././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.685713 pyparsing-3.3.2/.coveragerc0000644000000000000000000000017015134002420012567 0ustar00[run] # This line instructs only the code contained in the "pyparsing.py" to be measured for coverage. source=pyparsing ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6869822 pyparsing-3.3.2/.gitignore0000644000000000000000000000441215134002420012441 0ustar00# Created by https://www.gitignore.io/api/python,pycharm working/* ### PyCharm ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff: .idea # CMake cmake-build-debug/ # Mongo Explorer plugin: .idea/**/mongoSettings.xml ## File-based project format: *.iws ## Plugin-specific files: # IntelliJ /out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml # Ruby plugin and RubyMine /.rakeTasks # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties ### PyCharm Patch ### # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 *.iml # modules.xml .idea/misc.xml *.ipr # Sonarlint plugin .idea/sonarlint ### Python ### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Environments .env .venv .venv-perf* env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ # End of https://www.gitignore.io/api/python,pycharm # For developers on OSX .DS_Store examples/verilog/ /perf_pyparsing.csv ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6869822 pyparsing-3.3.2/.pre-commit-config.yaml0000644000000000000000000000017615134002420014735 0ustar00repos: - repo: https://github.com/python/black rev: stable hooks: - id: black language_version: python3.9 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6869822 pyparsing-3.3.2/BUILDING.md0000644000000000000000000000142015134002420012164 0ustar00# BUILDING pyparsing uses the [flit](https://flit.readthedocs.io/) build system that is compliant with [PEP 517](https://www.python.org/dev/peps/pep-0517/). Therefore, any PEP 517-compliant tools can be used to build it. ## Building using flit To build the distribution files using flit, type: ``` $ flit build ``` The generated sdist and wheel will be placed in `dist/` directory. ## Building using build [build](https://github.com/pypa/build) is a generic builder for PEP 517 projects. To build the distribution files using build, type: ``` $ pyproject-build ``` The generated sdist and wheel will be placed in `dist/` directory. ## Testing pyparsing uses [tox](https://tox.wiki/en/latest/) to run tests. In order to run the complete test suite, type: ``` $ tox ``` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6869822 pyparsing-3.3.2/CHANGES0000644000000000000000000060110615134002420011447 0ustar00========== Change Log ========== RELEASE PLANNING NOTES: In the pyparsing release 3.3.0, use of many of the pre-PEP8 methods (such as `ParserElement.parseString`) will start to raise `DeprecationWarnings`. I plan to completely drop the pre-PEP8 methods in pyparsing 4.0, though we won't see that release until some time later in 2026. So there is plenty of time to convert existing parsers to the new function names before the legacy functions are completely removed. Required Python versions by pyparsing version --------------------------------------------- +--------------------------------------------------+-------------------+ | pyparsing version | Required Python | +==================================================+===================+ | 3.3.0 and later | 3.9 or later | | 3.2.0 - 3.2.4 | 3.9 or later | | 3.0.8 - 3.1.4 | 3.6.8 or later | | 3.0.0 - 3.0.7 (these versions are discouraged) | 3.6 or later | | 2.4.7 | 2.7 or later | | 1.5.7 | 2.6 - 2.7 | +--------------------------------------------------+-------------------+ Version 3.3.2 - January, 2026 ----------------------------- - Defined pyparsing-specific warning classes so that they can be selectively enabled or disabled without affecting warnings raised by other libraries in the same Python app: - `PyparsingWarning` - base warning for all pyparsing-specific warnings (inherits from `UserWarning`) - `PyparsingDeprecationWarning` - warning for using deprecated features (inherits from `PyparsingWarning` and `DeprecationWarning`) - `PyparsingDiagnosticWarning` - warning raised when pyparsing diagnostics are enabled and a diagnostic feature is used (inherits from `PyparsingWarning`) - Added `as_datetime` parse action to `pyparsing.common` - a more generalized version of the `convert_to_datetime` parse action (supports any expression that extracts date/time fields into "year", "month", "day", etc. results names), and validates that the parsed fields represent a valid date and time. - Added `iso8601_date_validated` and `iso8601_datetime_validated` expressions to `pyparsing.common`, which return a Python `datetime.datetime` - Various performance improvements in `ParseResults` class and core functions, with 10-20% performance overall. - Added `regex_inverter` web page (using PyScript) to demonstrate using the `inv_regex.py` example. - Expanded regex forms handled by the `examples/inv_regex.py` example: - named capturing groups (`?P`) - partial repetition (`{m,}` and `{,n}`) - negated character classes (`[^...]`) - Added `SPy` (Simplified Python) parser to examples. Version 3.3.1 - December, 2025 ------------------------------ - Added license info to metadata, following PEP-639. Thanks to Gedalia Pasternak and Marc Mueller for submitted issue and PR. Fixes #626. Version 3.3.0 - December, 2025 ------------------------------ =========================================================================================== The version 3.3.0 release will begin emitting `DeprecationWarnings` for pyparsing methods that have been renamed to PEP8-compliant names (introduced in pyparsing 3.0.0, in August, 2021, with legacy names retained as aliases). In preparation, I added in pyparsing 3.2.2 a utility for finding and replacing the legacy method names with the new names. This utility is located at `pyparsing/tools/cvt_pep8_names.py`. This script will scan all Python files specified on the command line, and if the `-u` option is selected, will replace all occurrences of the old method names with the new PEP8-compliant names, updating the files in place. Here is an example that converts all the files in the pyparsing `/examples` directory: python -m pyparsing.tools.cvt_pyparsing_pep8_names -u examples/*.py The new names are compatible with pyparsing versions 3.0.0 and later. =========================================================================================== - Deprecated `indentedBlock`, when converted using the `cvt_pyparsing_pep8_names` utility, will emit `UserWarnings` that additional code changes will be required. This is because the new `IndentedBlock` class no longer requires the calling code to supply an indent stack, while adding support for nested indentation levels and grouping. - Deprecated `locatedExpr`, when converted using the `cvt_pyparsing_pep8_names` utility, will emit `UserWarnings` that additional code changes may be required. The new `Located` class removes the extra grouping level of the parsed values. (If the original `locatedExpr` parser was defined with a results name, then the extra grouping is retained, so that the results name nesting works properly; in this case, no code changes would be required.) - Updated all examples and test cases to use PEP8 names (unless the test case is specifically designed to test behavior of a legacy method). Added railroad diagrams for some examples. - Added exception handling when calling `formatted_message()`, so that `str(exception)` always returns at least _something_. - All unit tests pass with Python 3.14, including 3.14t. This does _not_ necessarily mean that pyparsing is now thread-safe, just that when run in the free-threaded interpreter, there were no errors. None of the unit tests try to do any parsing with multiple threads - they test the basic functionality of the library, under various versions of packrat and left-recursive parsing. - Added AI instructions so that AI agents can be prompted with best practices for generating parsers using pyparsing code. These instructions are in the `ai/best_practices.md` file, and can be accessed programmatically by calling `pyparsing.show_best_practices()` or running `python -m pyparsing.ai.show_best_practices` from the command line, after installing the `pyparsing` package. - Implemented a TINY language parser/interpreter using pyparsing, in the `examples/tiny` directory. This is a little tutorial language that I used to demonstrate how to use pyparsing to build a simple interpreter, following a recommended parser+AST+engine+run structure. The `docs` sub-directory also includes transcripts of the AI session used to create the parser and the interpreter. The `samples` sub-directory includes a few sample TINY programs. - Fixed minor formatting bugs in `pyparsing.testing.with_line_numbers`, found during development of the TINY language example. - Added test in `DelimitedList` and `nested_expr` which auto-suppress delimiting commas to avoid wrapping in a `Suppress` if delimiter is already a `Suppress`. - Added performance benchmarking tools and documentation: - `tests/perf_pyparsing.py` runs a series of benchmark parsing tests, exercising different aspects of the pyparsing package. For cross-version analysis, this script can export results as CSV and append to a consolidated data file. - Runner scripts `run_perf_all_tags.bat` (Windows) and `run_perf_all_tags.sh` (Ubuntu/bash) execute the benchmark across multiple Python versions (3.9–3.14) and pyparsing versions (3.1.1 through 3.3.0), aggregating results into `perf_pyparsing.csv` at the repo root. - See `tests/README.md` for usage instructions. - Used performance benchmarking to identify and revert an inefficient utility method used in `transform_string` (introduced in pyparsing 3.2.0b2). Version 3.2.5 - September, 2025 ------------------------------- - JINX! Well, 3.2.4 had a bug for `Word` expressions that include a space character, if that expression was then copied, either directly with .copy() or by adding a results name, or included in another construct (like `DelimitedList`) that makes a copy internally. Issue #618, reported by mstinberg, among others - thanks, and sorry for the inconvenience. Version 3.2.4 - September, 2025 ------------------------------- - Barring any catastrophic bugs in this release, this will be the last release in the 3.2.x line. The next release, 3.3.0, will begin emitting `DeprecationWarnings` when the pre-PEP8 methods are used (see header notes above for more information, including available automation for converting any existing code using pyparsing with the old names). - Fixed bug when using a copy of a `Word` expression (either by using the explicit `copy()` method, or attaching a results name), and setting a new expression name, a raised `ParseException` still used the original expression name. Also affected `Regex` expressions with `as_match` or `as_group_list` = True. Reported by Waqas Ilyas, in Issue #612 - good catch! - Fixed type annotation for `replace_with`, to accept `Any` type. Fixes Issue #602, reported by esquonk. - Added locking around potential race condition in `ParserElement.reset_cache`, as well as other cache-related methods. Fixes Issue #604, reported by CarlosDescalziIM. - Substantial update to docstrings and doc generation in preparation for 3.3.0, great effort by FeRD, thanks! - Notable addition by FeRD to convert docstring examples to work with doctest! This was long overdue, thanks so much! Version 3.2.3 - March, 2025 --------------------------- - Fixed bug released in 3.2.2 in which `nested_expr` could overwrite parse actions for defined content, and could truncate list of items within a nested list. Fixes Issue #600, reported by hoxbro and luisglft, with helpful diag logs and repro code. Version 3.2.2 - March, 2025 --------------------------- - Released `cvt_pyparsing_pep8_names.py` conversion utility to upgrade pyparsing-based programs and libraries that use legacy camelCase names to use the new PEP8-compliant snake_case method names. The converter can also be imported into other scripts as from pyparsing.tools.cvt_pyparsing_pep8_names import pep8_converter - Fixed bug in `nested_expr` where nested contents were stripped of whitespace when the default whitespace characters were cleared (raised in this StackOverflow question https://stackoverflow.com/questions/79327649 by Ben Alan). Also addressed bug in resolving PEP8 compliant argument name and legacy argument name. - Fixed bug in `rest_of_line` and the underlying `Regex` class, in which matching a pattern that could match an empty string (such as `".*"` or `"[A-Z]*"` would not raise a `ParseException` at or beyond the end of the input string. This could cause an infinite parsing loop when parsing `rest_of_line` at the end of the input string. Reported by user Kylotan, thanks! (Issue #593) - Enhancements and extra input validation for `pyparsing.util.make_compressed_re` - see usage in `examples/complex_chemical_formulas.py` and result in the generated railroad diagram `examples/complex_chemical_formulas_diagram.html`. Properly escapes characters like "." and "*" that have special meaning in regular expressions. - Fixed bug in `one_of()` to properly escape characters that are regular expression markers (such as '*', '+', '?', etc.) before building the internal regex. - Better exception message for `MatchFirst` and `Or` expressions, showing all alternatives rather than just the first one. Fixes Issue #592, reported by Focke, thanks! - Added return type annotation of "-> None" for all `__init__()` methods, to satisfy `mypy --strict` type checking. PR submitted by FeRD, thank you! - Added optional argument `show_hidden` to `create_diagram` to show elements that are used internally by pyparsing, but are not part of the actual parser grammar. For instance, the `Tag` class can insert values into the parsed results but it does not actually parse any input, so by default it is not included in a railroad diagram. By calling `create_diagram` with `show_hidden = True`, these internal elements will be included. (You can see this in the tag_metadata.py script in the examples directory.) - Fixed bug in `number_words.py` example. Also added `ebnf_number_words.py` to demonstrate using the `ebnf.py` EBNF parser generator to build a similar parser directly from EBNF. - Fixed syntax warning raised in `bigquery_view_parser.py`, invalid escape sequence "\s". Reported by sameer-google, nice catch! (Issue #598) - Added support for Python 3.14. Version 3.2.1 - December, 2024 ------------------------------ - Updated generated railroad diagrams to make non-terminal elements links to their related sub-diagrams. This _greatly_ improves navigation of the diagram, especially for large, complex parsers. - Simplified railroad diagrams emitted for parsers using `infix_notation`, by hiding lookahead terms. Renamed internally generated expressions for clarity, and improved diagramming. - Improved performance of `cpp_style_comment`, `c_style_comment`, `common.fnumber` and `common.ieee_float` `Regex` expressions. PRs submitted by Gabriel Gerlero, nice work, thanks! - Add missing type annotations to `match_only_at_col`, `replace_with`, `remove_quotes`, `with_attribute`, and `with_class`. Issue #585 reported by rafrafrek. - Added generated diagrams for many of the examples. - Replaced old `examples/0README.html` file with `examples/README.md` file. Version 3.2.0 - October, 2024 ------------------------------- - Discontinued support for Python 3.6, 3.7, and 3.8. Adopted new Python features from Python versions 3.7-3.9: - Updated type annotations to use built-in container types instead of names imported from the `typing` module (e.g., `list[str]` vs `List[str]`). - Reworked portions of the packrat cache to leverage insertion-preserving ordering in dicts (including removal of uses of `OrderedDict`). - Changed `pdb.set_trace()` call in `ParserElement.set_break()` to `breakpoint()`. - Converted `typing.NamedTuple` to `dataclasses.dataclass` in railroad diagramming code. - Added `from __future__ import annotations` to clean up some type annotations. (with assistance from ISyncWithFoo, issue #535, thanks for the help!) - POSSIBLE BREAKING CHANGES The following bugfixes may result in subtle changes in the results returned or exceptions raised by pyparsing. - Fixed code in `ParseElementEnhance` subclasses that replaced detailed exception messages raised in contained expressions with a less-specific and less-informative generic exception message and location. If your code has conditional logic based on the message content in raised `ParseExceptions`, this bugfix may require changes in your code. - Fixed bug in `transform_string()` where whitespace in the input string was not properly preserved in the output string. If your code uses `transform_string`, this bugfix may require changes in your code. - Fixed bug where an `IndexError` raised in a parse action was incorrectly handled as an `IndexError` raised as part of the `ParserElement` parsing methods, and reraised as a `ParseException`. Now an `IndexError` that raises inside a parse action will properly propagate out as an `IndexError`. (Issue #573, reported by August Karlstedt, thanks!) If your code raises `IndexError`s in parse actions, this bugfix may require changes in your code. - FIXES AND NEW FEATURES - Added type annotations to remainder of `pyparsing` package, and added `mypy` run to `tox.ini`, so that type annotations are now run as part of pyparsing's CI. Addresses Issue #373, raised by Iwan Aucamp, thanks! - Exception message format can now be customized, by overriding `ParseBaseException.format_message`: def custom_exception_message(exc) -> str: found_phrase = f", found {exc.found}" if exc.found else "" return f"{exc.lineno}:{exc.column} {exc.msg}{found_phrase}" ParseBaseException.formatted_message = custom_exception_message (PR #571 submitted by Odysseyas Krystalakos, nice work!) - `run_tests` now detects if an exception is raised in a parse action, and will report it with an enhanced error message, with the exception type, string, and parse action name. - `QuotedString` now handles translation of escaped integer, hex, octal, and Unicode sequences to their corresponding characters. - Fixed the displayed output of `Regex` terms to deduplicate repeated backslashes, for easier reading in debugging, printing, and railroad diagrams. - Fixed (or at least reduced) elusive bug when generating railroad diagrams, where some diagram elements were just empty blocks. Fix submitted by RoDuth, thanks a ton! - Fixed railroad diagrams that get generated with a parser containing a `Regex` element defined using a verbose pattern - the pattern gets flattened and comments removed before creating the corresponding diagram element. - Defined a more performant regular expression used internally by `common_html_entity`. - `Regex` instances can now be created using a callable that takes no arguments and just returns a string or a compiled regular expression, so that creating complex regular expression patterns can be deferred until they are actually used for the first time in the parser. - Added optional `flatten` Boolean argument to `ParseResults.as_list()`, to return the parsed values in a flattened list. - Added `indent` and `base_1` arguments to `pyparsing.testing.with_line_numbers`. When using `with_line_numbers` inside a parse action, set `base_1`=False, since the reported `loc` value is 0-based. `indent` can be a leading string (typically of spaces or tabs) to indent the numbered string passed to `with_line_numbers`. Added while working on #557, reported by Bernd Wechner. - NEW/ENHANCED EXAMPLES - Added query syntax to `mongodb_query_expression.py` with: - better support for array fields ("contains all", "contains any", and "contains none") - "like" and "not like" operators to support SQL "%" wildcard matching and "=~" operator to support regex matching - text search using "search for" - dates and datetimes as query values - `a[0]` style array referencing - Added `lox_parser.py` example, a parser for the Lox language used as a tutorial in Robert Nystrom's "Crafting Interpreters" (http://craftinginterpreters.com/). With helpful corrections from RoDuth. - Added `complex_chemical_formulas.py` example, to add parsing capability for formulas such as "3(C₆H₅OH)₂". - Updated `tag_emitter.py` to use new `Tag` class, introduced in pyparsing 3.1.3. Version 3.1.4 - August, 2024 ---------------------------- - Fixed a regression introduced in pyparsing 3.1.3, addition of a type annotation that referenced `re.Pattern`. Since this type was introduced in Python 3.7, using this type definition broke Python 3.6 installs of pyparsing 3.1.3. PR submitted by Felix Fontein, nice work! Version 3.1.3 - August, 2024 ---------------------------- - Added new `Tag` ParserElement, for inserting metadata into the parsed results. This allows a parser to add metadata or annotations to the parsed tokens. The `Tag` element also accepts an optional `value` parameter, defaulting to `True`. See the new `tag_metadata.py` example in the `examples` directory. Example: # add tag indicating mood end_punc = "." | ("!" + Tag("enthusiastic")) greeting = "Hello" + Word(alphas) + end_punc result = greeting.parse_string("Hello World.") print(result.dump()) result = greeting.parse_string("Hello World!") print(result.dump()) prints: ['Hello', 'World', '.'] ['Hello', 'World', '!'] - enthusiastic: True - Added example `mongodb_query_expression.py`, to convert human-readable infix query expressions (such as `a==100 and b>=200`) and transform them into the equivalent query argument for the pymongo package (`{'$and': [{'a': 100}, {'b': {'$gte': 200}}]}`). Supports many equality and inequality operators - see the docstring for the `transform_query` function for more examples. - Fixed issue where PEP8 compatibility names for `ParserElement` static methods were not themselves defined as `staticmethods`. When called using a `ParserElement` instance, this resulted in a `TypeError` exception. Reported by eylenburg (#548). - To address a compatibility issue in RDFLib, added a property setter for the `ParserElement.name` property, to call `ParserElement.set_name`. - Modified `ParserElement.set_name()` to accept a None value, to clear the defined name and corresponding error message for a `ParserElement`. - Updated railroad diagram generation for `ZeroOrMore` and `OneOrMore` expressions with `stop_on` expressions, while investigating #558, reported by user Gu_f. - Added `` tag to HTML generated for railroad diagrams to force UTF-8 encoding with older browsers, to better display Unicode parser characters. - Fixed some cosmetics/bugs in railroad diagrams: - fixed groups being shown even when `show_groups`=False - show results names as quoted strings when `show_results_names`=True - only use integer loop counter if repetition > 2 - Some type annotations added for parse action related methods, thanks August Karlstedt (#551). - Added exception type to `trace_parse_action` exception output, while investigating SO question posted by medihack. - Added `set_name` calls to internal expressions generated in `infix_notation`, for improved railroad diagramming. - `delta_time`, `lua_parser`, `decaf_parser`, and `roman_numerals` examples cleaned up to use latest PEP8 names and add minor enhancements. - Fixed bug (and corresponding test code) in `delta_time` example that did not handle weekday references in time expressions (like "Monday at 4pm") when the weekday was the same as the current weekday. - Minor performance speedup in `trim_arity`, to benefit any parsers using parse actions. - Added early testing support for Python 3.13 with JIT enabled. Version 3.1.2 - March, 2024 --------------------------- - Added `ieee_float` expression to `pyparsing.common`, which parses float values, plus "NaN", "Inf", "Infinity". PR submitted by Bob Peterson (#538). - Updated pep8 synonym wrappers for better type checking compatibility. PR submitted by Ricardo Coccioli (#507). - Fixed empty error message bug, PR submitted by InSync (#534). This _should_ return pyparsing's exception messages to a former, more helpful form. If you have code that parses the exception messages returned by pyparsing, this may require some code changes. - Added unit tests to test for exception message contents, with enhancement to `pyparsing.testing.assertRaisesParseException` to accept an expected exception message. - Updated example `select_parser.py` to use PEP8 names and added Groups for better retrieval of parsed values from multiple SELECT clauses. - Added example `email_address_parser.py`, as suggested by John Byrd (#539). - Added example `directx_x_file_parser.py` to parse DirectX template definitions, and generate a Pyparsing parser from a template to parse .x files. - Some code refactoring to reduce code nesting, PRs submitted by InSync. - All internal string expressions using '%' string interpolation and `str.format()` converted to f-strings. Version 3.1.1 - July, 2023 -------------------------- - Fixed regression in Word(min), reported by Ricardo Coccioli, good catch! (Issue #502) - Fixed bug in bad exception messages raised by Forward expressions. PR submitted by Kyle Sunden, thanks for your patience and collaboration on this (#493). - Fixed regression in SkipTo, where ignored expressions were not checked when looking for the target expression. Reported by catcombo, Issue #500. - Fixed type annotation for enable_packrat, PR submitted by Mike Urbach, thanks! (Issue #498) - Some general internal code cleanup. (Instigated by Michal Čihař, Issue #488) Version 3.1.0 - June, 2023 -------------------------- - Added `tag_emitter.py` to examples. This example demonstrates how to insert tags into your parsed results that are not part of the original parsed text. Version 3.1.0b2 - May, 2023 --------------------------- - Updated `create_diagram()` code to be compatible with railroad-diagrams package version 3.0. Fixes Issue #477 (railroad diagrams generated with black bars), reported by Sam Morley-Short. - Fixed bug in `NotAny`, where parse actions on the negated expr were not being run. This could cause `NotAny` to incorrectly fail if the expr would normally match, but would fail to match if a condition used as a parse action returned False. Fixes Issue #482, raised by byaka, thank you! - Fixed `create_diagram()` to accept keyword args, to be passed through to the `template.render()` method to generate the output HTML (PR submitted by Aussie Schnore, good catch!) - Fixed bug in `python_quoted_string` regex. - Added `examples/bf.py` Brainf*ck parser/executor example. Illustrates using a pyparsing grammar to parse language syntax, and attach executable AST nodes to the parsed results. Version 3.1.0b1 - April, 2023 ----------------------------- - Added support for Python 3.12. - API CHANGE: A slight change has been implemented when unquoting a quoted string parsed using the `QuotedString` class. Formerly, when unquoting and processing whitespace markers such as \t and \n, these substitutions would occur first, and then any additional '\' escaping would be done on the resulting string. This would parse "\\n" as "\". Now escapes and whitespace markers are all processed in a single pass working left to right, so the quoted string "\\n" would get unquoted to "\n" (a backslash followed by "n"). Fixes issue #474 raised by jakeanq, thanks! - Added named field "url" to `pyparsing.common.url`, returning the entire parsed URL string. - Fixed bug when parse actions returned an empty string for an expression that had a results name, that the results name was not saved. That is: expr = Literal("X").add_parse_action(lambda tokens: "")("value") result = expr.parse_string("X") print(result["value"]) would raise a `KeyError`. Now empty strings will be saved with the associated results name. Raised in Issue #470 by Nicco Kunzmann, thank you. - Fixed bug in `SkipTo` where ignore expressions were not properly handled while scanning for the target expression. Issue #475, reported by elkniwt, thanks (this bug has been there for a looooong time!). - Updated `ci.yml` permissions to limit default access to source - submitted by Joyce Brum of Google. Thanks so much! - Updated the `lucene_grammar.py` example (better support for '*' and '?' wildcards) and corrected the test cases - brought to my attention by Elijah Nicol, good catch! Version 3.1.0a1 - March, 2023 ----------------------------- - API ENHANCEMENT: `Optional(expr)` may now be written as `expr | ""` This will make this code: "{" + Optional(Literal("A") | Literal("a")) + "}" writable as: "{" + (Literal("A") | Literal("a") | "") + "}" Some related changes implemented as part of this work: - `Literal("")` now internally generates an `Empty()` (and no longer raises an exception) - `Empty` is now a subclass of `Literal` Suggested by Antony Lee (issue #412), PR (#413) by Devin J. Pohly. - Added new class property `identifier` to all Unicode set classes in `pyparsing.unicode`, using the class's values for `cls.identchars` and `cls.identbodychars`. Now Unicode-aware parsers that formerly wrote: ppu = pyparsing.unicode ident = Word(ppu.Greek.identchars, ppu.Greek.identbodychars) can now write: ident = ppu.Greek.identifier # or # ident = ppu.Ελληνικά.identifier - `ParseResults` now has a new method `deepcopy()`, in addition to the current `copy()` method. `copy()` only makes a shallow copy - any contained `ParseResults` are copied as references - changes in the copy will be seen as changes in the original. In many cases, a shallow copy is sufficient, but some applications require a deep copy. `deepcopy()` makes a deeper copy: any contained `ParseResults` or other mappings or containers are built with copies from the original, and do not get changed if the original is later changed. Addresses issue #463, reported by Bryn Pickering. - Reworked `delimited_list` function into the new `DelimitedList` class. `DelimitedList` has the same constructor interface as `delimited_list`, and in this release, `delimited_list` changes from a function to a synonym for `DelimitedList`. `delimited_list` and the older `delimitedList` method will be deprecated in a future release, in favor of `DelimitedList`. - Error messages from `MatchFirst` and `Or` expressions will try to give more details if one of the alternatives matches better than the others, but still fails. Question raised in Issue #464 by msdemlei, thanks! - Added new class method `ParserElement.using_each`, to simplify code that creates a sequence of `Literals`, `Keywords`, or other `ParserElement` subclasses. For instance, to define suppressible punctuation, you would previously write: LPAR, RPAR, LBRACE, RBRACE, SEMI = map(Suppress, "(){};") You can now write: LPAR, RPAR, LBRACE, RBRACE, SEMI = Suppress.using_each("(){};") `using_each` will also accept optional keyword args, which it will pass through to the class initializer. Here is an expression for single-letter variable names that might be used in an algebraic expression: algebra_var = MatchFirst( Char.using_each(string.ascii_lowercase, as_keyword=True) ) - Added new builtin `python_quoted_string`, which will match any form of single-line or multiline quoted strings defined in Python. (Inspired by discussion with Andreas Schörgenhumer in Issue #421.) - Extended `expr[]` notation for repetition of `expr` to accept a slice, where the slice's stop value indicates a `stop_on` expression: test = "BEGIN aaa bbb ccc END" BEGIN, END = Keyword.using_each("BEGIN END".split()) body_word = Word(alphas) expr = BEGIN + Group(body_word[...:END]) + END # equivalent to # expr = BEGIN + Group(ZeroOrMore(body_word, stop_on=END)) + END print(expr.parse_string(test)) Prints: ['BEGIN', ['aaa', 'bbb', 'ccc'], 'END'] - `ParserElement.validate()` is deprecated. It predates the support for left-recursive parsers, and was prone to false positives (warning that a grammar was invalid when it was in fact valid). It will be removed in a future pyparsing release. In its place, developers should use debugging and analytical tools, such as `ParserElement.set_debug()` and `ParserElement.create_diagram()`. (Raised in Issue #444, thanks Andrea Micheli!) - Added bool `embed` argument to `ParserElement.create_diagram()`. When passed as True, the resulting diagram will omit the ``, ``, and `` tags so that it can be embedded in other HTML source. (Useful when embedding a call to `create_diagram()` in a PyScript HTML page.) - Added `recurse` argument to `ParserElement.set_debug` to set the debug flag on an expression and all of its sub-expressions. Requested by multimeric in Issue #399. - Added '·' (Unicode MIDDLE DOT) to the set of Latin1.identbodychars. - Fixed bug in `Word` when `max=2`. Also added performance enhancement when specifying `exact` argument. Reported in issue #409 by panda-34, nice catch! - `Word` arguments are now validated if `min` and `max` are both given, that `min` <= `max`; raises `ValueError` if values are invalid. - Fixed bug in srange, when parsing escaped '/' and '\' inside a range set. - Fixed exception messages for some `ParserElements` with custom names, which instead showed their contained expression names. - Fixed bug in pyparsing.common.url, when input URL is not alone on an input line. Fixes Issue #459, reported by David Kennedy. - Multiple added and corrected type annotations. With much help from Stephen Rosen, thanks! - Some documentation and error message clarifications on pyparsing's keyword logic, cited by Basil Peace. - General docstring cleanup for Sphinx doc generation, PRs submitted by Devin J. Pohly. A dirty job, but someone has to do it - much appreciated! - `invRegex.py` example renamed to `inv_regex.py` and updated to PEP-8 variable and method naming. PR submitted by Ross J. Duff, thanks! - Removed examples `sparser.py` and `pymicko.py`, since each included its own GPL license in the header. Since this conflicts with pyparsing's MIT license, they were removed from the distribution to avoid confusion among those making use of them in their own projects. Version 3.0.9 - May, 2022 ------------------------- - Added Unicode set `BasicMultilingualPlane` (may also be referenced as `BMP`) representing the Basic Multilingual Plane (Unicode characters up to code point 65535). Can be used to parse most language characters, but omits emojis, wingdings, etc. Raised in discussion with Dave Tapley (issue #392). - To address mypy confusion of `pyparsing.Optional` and `typing.Optional` resulting in `error: "_SpecialForm" not callable` message reported in issue #365, fixed the import in `exceptions.py`. Nice sleuthing by Iwan Aucamp and Dominic Davis-Foster, thank you! (Removed definitions of `OptionalType`, `DictType`, and `IterableType` and replaced them with `typing.Optional`, `typing.Dict`, and `typing.Iterable` throughout.) - Fixed typo in jinja2 template for railroad diagrams, thanks for the catch Nioub (issue #388). - Removed use of deprecated `pkg_resources` package in railroad diagramming code (issue #391). - Updated `bigquery_view_parser.py` example to parse examples at https://cloud.google.com/bigquery/docs/reference/legacy-sql Version 3.0.8 - April, 2022 --------------------------- - API CHANGE: modified `pyproject.toml` to require Python version 3.6.8 or later for pyparsing 3.x. Earlier minor versions of 3.6 fail in evaluating the `version_info` class (implemented using `typing.NamedTuple`). If you are using an earlier version of Python 3.6, you will need to use pyparsing 2.4.7. - Improved pyparsing import time by deferring regex pattern compiles. PR submitted by Anthony Sottile to fix issue #362, thanks! - Updated build to use flit, PR by Michał Górny, added `BUILDING.md` doc and removed old Windows build scripts - nice cleanup work! - More type-hinting added for all arithmetic and logical operator methods in `ParserElement`. PR from Kazantcev Andrey, thank you. - Fixed `infix_notation`'s definitions of `lpar` and `rpar`, to accept parse expressions such that they do not get suppressed in the parsed results. PR submitted by Philippe Prados, nice work. - Fixed bug in railroad diagramming with expressions containing `Combine` elements. Reported by Jeremy White, thanks! - Added `show_groups` argument to `create_diagram` to highlight grouped elements with an unlabeled bounding box. - Added `unicode_denormalizer.py` to the examples as a demonstration of how Python's interpreter will accept Unicode characters in identifiers, but normalizes them back to ASCII so that identifiers `print` and `𝕡𝓻ᵢ𝓃𝘁` and `𝖕𝒓𝗂𝑛ᵗ` are all equivalent. - Removed imports of deprecated `sre_constants` module for catching exceptions when compiling regular expressions. PR submitted by Serhiy Storchaka, thank you. Version 3.0.7 - January, 2022 ----------------------------- - Fixed bug #345, in which delimitedList changed expressions in place using `expr.streamline()`. Reported by Kim Gräsman, thanks! - Fixed bug #346, when a string of word characters was passed to WordStart or `WordEnd` instead of just taking the default value. Originally posted as a question by Parag on StackOverflow, good catch! - Fixed bug #350, in which `White` expressions could fail to match due to unintended whitespace-skipping. Reported by Fu Hanxi, thank you! - Fixed bug #355, when a `QuotedString` is defined with characters in its quoteChar string containing regex-significant characters such as ., *, ?, [, ], etc. - Fixed bug in `ParserElement.run_tests` where comments would be displayed using `with_line_numbers`. - Added optional "min" and "max" arguments to `delimited_list`. PR submitted by Marius, thanks! - Added new API change note in `whats_new_in_pyparsing_3_0_0`, regarding a bug fix in the `bool()` behavior of `ParseResults`. Prior to pyparsing 3.0.x, the `ParseResults` class implementation of `__bool__` would return `False` if the `ParseResults` item list was empty, even if it contained named results. In 3.0.0 and later, `ParseResults` will return `True` if either the item list is not empty *or* if the named results dict is not empty. # generate an empty ParseResults by parsing a blank string with # a ZeroOrMore result = Word(alphas)[...].parse_string("") print(result.as_list()) print(result.as_dict()) print(bool(result)) # add a results name to the result result["name"] = "empty result" print(result.as_list()) print(result.as_dict()) print(bool(result)) Prints: [] {} False [] {'name': 'empty result'} True In previous versions, the second call to `bool()` would return `False`. - Minor enhancement to Word generation of internal regular expression, to emit consecutive characters in range, such as "ab", as "ab", not "a-b". - Fixed character ranges for search terms using non-Western characters in booleansearchparser, PR submitted by tc-yu, nice work! - Additional type annotations on public methods. Version 3.0.6 - November, 2021 ------------------------------ - Added `suppress_warning()` method to individually suppress a warning on a specific ParserElement. Used to refactor `original_text_for` to preserve internal results names, which, while undocumented, had been adopted by some projects. - Fix bug when `delimited_list` was called with a str literal instead of a parse expression. Version 3.0.5 - November, 2021 ------------------------------ - Added return type annotations for `col`, `line`, and `lineno`. - Fixed bug when `warn_ungrouped_named_tokens_in_collection` warning was raised when assigning a results name to an `original_text_for` expression. (Issue #110, would raise warning in packaging.) - Fixed internal bug where `ParserElement.streamline()` would not return self if already streamlined. - Changed `run_tests()` output to default to not showing line and column numbers. If line numbering is desired, call with `with_line_numbers=True`. Also fixed minor bug where separating line was not included after a test failure. Version 3.0.4 - October, 2021 ----------------------------- - Fixed bug in which `Dict` classes did not correctly return tokens as nested `ParseResults`, reported by and fix identified by Bu Sun Kim, many thanks!!! - Documented API-changing side-effect of converting `ParseResults` to use `__slots__` to pre-define instance attributes. This means that code written like this (which was allowed in pyparsing 2.4.7): result = Word(alphas).parseString("abc") result.xyz = 100 now raises this Python exception: AttributeError: 'ParseResults' object has no attribute 'xyz' To add new attribute values to ParseResults object in 3.0.0 and later, you must assign them using indexed notation: result["xyz"] = 100 You will still be able to access this new value as an attribute or as an indexed item. - Fixed bug in railroad diagramming where the vertical limit would count all expressions in a group, not just those that would create visible railroad elements. Version 3.0.3 - October, 2021 ----------------------------- - Fixed regex typo in `one_of` fix for `as_keyword=True`. - Fixed a whitespace-skipping bug, Issue #319, introduced as part of the revert of the `LineStart` changes. Reported by Marc-Alexandre Côté, thanks! - Added header column labeling > 100 in `with_line_numbers` - some input lines are longer than others. Version 3.0.2 - October, 2021 ----------------------------- - Reverted change in behavior with `LineStart` and `StringStart`, which changed the interpretation of when and how `LineStart` and `StringStart` should match when a line starts with spaces. In 3.0.0, the `xxxStart` expressions were not really treated like expressions in their own right, but as modifiers to the following expression when used like `LineStart() + expr`, so that if there were whitespace on the line before `expr` (which would match in versions prior to 3.0.0), the match would fail. 3.0.0 implemented this by automatically promoting `LineStart() + expr` to `AtLineStart(expr)`, which broke existing parsers that did not expect `expr` to necessarily be right at the start of the line, but only be the first token found on the line. This was reported as a regression in Issue #317. In 3.0.2, pyparsing reverts to the previous behavior, but will retain the new `AtLineStart` and `AtStringStart` expression classes, so that parsers can chose whichever behavior applies in their specific instance. Specifically: # matches expr if it is the first token on the line # (allows for leading whitespace) LineStart() + expr # matches only if expr is found in column 1 AtLineStart(expr) - Performance enhancement to `one_of` to always generate an internal `Regex`, even if `caseless` or `as_keyword` args are given as `True` (unless explicitly disabled by passing `use_regex=False`). - `IndentedBlock` class now works with `recursive` flag. By default, the results parsed by an `IndentedBlock` are grouped. This can be disabled by constructing the `IndentedBlock` with `grouped=False`. Version 3.0.1 - October, 2021 ----------------------------- - Fixed bug where `Word(max=n)` did not match word groups less than length 'n'. Thanks to Joachim Metz for catching this! - Fixed bug where `ParseResults` accidentally created recursive contents. Joachim Metz on this one also! - Fixed bug where `warn_on_multiple_string_args_to_oneof` warning is raised even when not enabled. Version 3.0.0 - October, 2021 ----------------------------- - A consolidated list of all the changes in the 3.0.0 release can be found in `docs/whats_new_in_3_0_0.rst`. (https://github.com/pyparsing/pyparsing/blob/master/docs/whats_new_in_3_0_0.rst) Version 3.0.0.final - October, 2021 ----------------------------------- - Added support for python `-W` warning option to call `enable_all_warnings`() at startup. Also detects setting of `PYPARSINGENABLEALLWARNINGS` environment variable to any non-blank value. (If using `-Wd` for testing, but wishing to disable pyparsing warnings, add `-Wi:::pyparsing`.) - Fixed named results returned by `url` to match fields as they would be parsed using `urllib.parse.urlparse`. - Early response to `with_line_numbers` was positive, with some requested enhancements: . added a trailing "|" at the end of each line (to show presence of trailing spaces); can be customized using `eol_mark` argument . added expand_tabs argument, to control calling str.expandtabs (defaults to True to match `parseString`) . added mark_spaces argument to support display of a printing character in place of spaces, or Unicode symbols for space and tab characters . added mark_control argument to support highlighting of control characters using '.' or Unicode symbols, such as "␍" and "␊". - Modified helpers `common_html_entity` and `replace_html_entity()` to use the HTML entity definitions from `html.entities.html5`. - Updated the class diagram in the pyparsing docs directory, along with the supporting .puml file (PlantUML markup) used to create the diagram. - Added global method `autoname_elements()` to call `set_name()` on all locally defined `ParserElements` that haven't been explicitly named using `set_name()`, using their local variable name. Useful for setting names on multiple elements when creating a railroad diagram. a = pp.Literal("a") b = pp.Literal("b").set_name("bbb") pp.autoname_elements() `a` will get named "a", while `b` will keep its name "bbb". Version 3.0.0rc2 - October, 2021 -------------------------------- - Added `url` expression to `pyparsing_common`. (Sample code posted by Wolfgang Fahl, very nice!) This new expression has been added to the `urlExtractorNew.py` example, to show how it extracts URL fields into separate results names. - Added method to `pyparsing_test` to help debugging, `with_line_numbers`. Returns a string with line and column numbers corresponding to values shown when parsing with expr.set_debug(): data = """\ A 100""" expr = pp.Word(pp.alphanums).set_name("word").set_debug() print(ppt.with_line_numbers(data)) expr[...].parseString(data) prints: 1 1234567890 1: A 2: 100 Match word at loc 3(1,4) A ^ Matched word -> ['A'] Match word at loc 11(2,7) 100 ^ Matched word -> ['100'] - Added new example `cuneiform_python.py` to demonstrate creating a new Unicode range, and writing a Cuneiform->Python transformer (inspired by zhpy). - Fixed issue #272, reported by PhasecoreX, when `LineStart`() expressions would match input text that was not necessarily at the beginning of a line. As part of this fix, two new classes have been added: AtLineStart and AtStringStart. The following expressions are equivalent: LineStart() + expr and AtLineStart(expr) StringStart() + expr and AtStringStart(expr) [`LineStart` and `StringStart` changes reverted in 3.0.2.] - Fixed `ParseFatalExceptions` failing to override normal exceptions or expression matches in `MatchFirst` expressions. Addresses issue #251, reported by zyp-rgb. - Fixed bug in which `ParseResults` replaces a collection type value with an invalid type annotation (as a result of changed behavior in Python 3.9). Addresses issue #276, reported by Rob Shuler, thanks. - Fixed bug in `ParseResults` when calling `__getattr__` for special double-underscored methods. Now raises `AttributeError` for non-existent results when accessing a name starting with '__'. Addresses issue #208, reported by Joachim Metz. - Modified debug fail messages to include the expression name to make it easier to sync up match vs success/fail debug messages. Version 3.0.0rc1 - September, 2021 ---------------------------------- - Railroad diagrams have been reformatted: . creating diagrams is easier - call expr.create_diagram("diagram_output.html") create_diagram() takes 3 arguments: . the filename to write the diagram HTML . optional 'vertical' argument, to specify the minimum number of items in a path to be shown vertically; default=3 . optional 'show_results_names' argument, to specify whether results name annotations should be shown; default=False . every expression that gets a name using `setName()` gets separated out as a separate subdiagram . results names can be shown as annotations to diagram items . `Each`, `FollowedBy`, and `PrecededBy` elements get [ALL], [LOOKAHEAD], and [LOOKBEHIND] annotations . removed annotations for Suppress elements . some diagram cleanup when a grammar contains Forward elements . check out the examples make_diagram.py and railroad_diagram_demo.py - Type annotations have been added to most public API methods and classes. - Better exception messages to show full word where an exception occurred. Word(alphas, alphanums)[...].parseString("ab1 123", parseAll=True) Was: pyparsing.ParseException: Expected end of text, found '1' (at char 4), (line:1, col:5) Now: pyparsing.exceptions.ParseException: Expected end of text, found '123' (at char 4), (line:1, col:5) - Suppress can be used to suppress text skipped using "...". source = "lead in START relevant text END trailing text" start_marker = Keyword("START") end_marker = Keyword("END") find_body = Suppress(...) + start_marker + ... + end_marker print(find_body.parseString(source).dump()) Prints: ['START', 'relevant text ', 'END'] - _skipped: ['relevant text '] - New string constants `identchars` and `identbodychars` to help in defining identifier Word expressions Two new module-level strings have been added to help when defining identifiers, `identchars` and `identbodychars`. Instead of writing:: import pyparsing as pp identifier = pp.Word(pp.alphas + "_", pp.alphanums + "_") you will be able to write:: identifier = pp.Word(pp.identchars, pp.identbodychars) Those constants have also been added to all the Unicode string classes:: import pyparsing as pp ppu = pp.pyparsing_unicode cjk_identifier = pp.Word(ppu.CJK.identchars, ppu.CJK.identbodychars) greek_identifier = pp.Word(ppu.Greek.identchars, ppu.Greek.identbodychars) - Added a caseless parameter to the `CloseMatch` class to allow for casing to be ignored when checking for close matches. (Issue #281) (PR by Adrian Edwards, thanks!) - Fixed bug in Located class when used with a results name. (Issue #294) - Fixed bug in `QuotedString` class when the escaped quote string is not a repeated character. (Issue #263) - `parseFile()` and `create_diagram()` methods now will accept `pathlib.Path` arguments. Version 3.0.0b3 - August, 2021 ------------------------------ - PEP-8 compatible names are being introduced in pyparsing version 3.0! All methods such as `parseString` have been replaced with the PEP-8 compliant name `parse_string`. In addition, arguments such as `parseAll` have been renamed to `parse_all`. For backward-compatibility, synonyms for all renamed methods and arguments have been added, so that existing pyparsing parsers will not break. These synonyms will be removed in a future release. In addition, the Optional class has been renamed to Opt, since it clashes with the common typing.Optional type specifier that is used in the Python type annotations. A compatibility synonym is defined for now, but will be removed in a future release. - HUGE NEW FEATURE - Support for left-recursive parsers! Following the method used in Python's PEG parser, pyparsing now supports left-recursive parsers when left recursion is enabled. import pyparsing as pp pp.ParserElement.enable_left_recursion() # a common left-recursion definition # define a list of items as 'list + item | item' # BNF: # item_list := item_list item | item # item := word of alphas item_list = pp.Forward() item = pp.Word(pp.alphas) item_list <<= item_list + item | item item_list.run_tests("""\ To parse or not to parse that is the question """) Prints: ['To', 'parse', 'or', 'not', 'to', 'parse', 'that', 'is', 'the', 'question'] Great work contributed by Max Fischer! - `delimited_list` now supports an additional flag `allow_trailing_delim`, to optionally parse an additional delimiter at the end of the list. Contributed by Kazantcev Andrey, thanks! - Removed internal comparison of results values against b"", which raised a `BytesWarning` when run with `python -bb`. Fixes issue #271 reported by Florian Bruhin, thank you! - Fixed STUDENTS table in sql2dot.py example, fixes issue #261 reported by legrandlegrand - much better. - Python 3.5 will not be supported in the pyparsing 3 releases. This will allow for future pyparsing releases to add parameter type annotations, and to take advantage of dict key ordering in internal results name tracking. Version 3.0.0b2 - December, 2020 -------------------------------- - API CHANGE `locatedExpr` is being replaced by the class `Located`. `Located` has the same constructor interface as `locatedExpr`, but fixes bugs in the returned `ParseResults` when the searched expression contains multiple tokens, or has internal results names. `locatedExpr` is deprecated, and will be removed in a future release. Version 3.0.0b1 - November, 2020 -------------------------------- - API CHANGE Diagnostic flags have been moved to an enum, `pyparsing.Diagnostics`, and they are enabled through module-level methods: - `pyparsing.enable_diag()` - `pyparsing.disable_diag()` - `pyparsing.enable_all_warnings()` - API CHANGE Most previous `SyntaxWarnings` that were warned when using pyparsing classes incorrectly have been converted to `TypeError` and `ValueError` exceptions, consistent with Python calling conventions. All warnings warned by diagnostic flags have been converted from `SyntaxWarnings` to `UserWarnings`. - To support parsers that are intended to generate native Python collection types such as lists and dicts, the `Group` and `Dict` classes now accept an additional boolean keyword argument `aslist` and `asdict` respectively. See the `jsonParser.py` example in the `pyparsing/examples` source directory for how to return types as `ParseResults` and as Python collection types, and the distinctions in working with the different types. In addition parse actions that must return a value of list type (which would normally be converted internally to a `ParseResults`) can override this default behavior by returning their list wrapped in the new `ParseResults.List` class: # this parse action tries to return a list, but pyparsing # will convert to a ParseResults def return_as_list_but_still_get_parse_results(tokens): return tokens.asList() # this parse action returns the tokens as a list, and pyparsing will # maintain its list type in the final parsing results def return_as_list(tokens): return ParseResults.List(tokens.asList()) This is the mechanism used internally by the `Group` class when defined using `aslist=True`. - A new `IndentedBlock` class is introduced, to eventually replace the current `indentedBlock` helper method. The interface is largely the same, however, the new class manages its own internal indentation stack, so it is no longer necessary to maintain an external `indentStack` variable. - API CHANGE Added `cache_hit` keyword argument to debug actions. Previously, if packrat parsing was enabled, the debug methods were not called in the event of cache hits. Now these methods will be called, with an added argument `cache_hit=True`. If you are using packrat parsing and enable debug on expressions using a custom debug method, you can add the `cache_hit=False` keyword argument, and your method will be called on packrat cache hits. If you choose not to add this keyword argument, the debug methods will fail silently, behaving as they did previously. - When using `setDebug` with packrat parsing enabled, packrat cache hits will now be included in the output, shown with a leading '*'. (Previously, cache hits and responses were not included in debug output.) For those using custom debug actions, see the previous item regarding an optional API change for those methods. - `setDebug` output will also show more details about what expression is about to be parsed (the current line of text being parsed, and the current parse position): Match integer at loc 0(1,1) 1 2 3 ^ Matched integer -> ['1'] The current debug location will also be indicated after whitespace has been skipped (was previously inconsistent, reported in Issue #244, by Frank Goyens, thanks!). - Modified the repr() output for `ParseResults` to include the class name as part of the output. This is to clarify for new pyparsing users who misread the repr output as a tuple of a list and a dict. pyparsing results will now read like: ParseResults(['abc', 'def'], {'qty': 100}] instead of just: (['abc', 'def'], {'qty': 100}] - Fixed bugs in Each when passed `OneOrMore` or `ZeroOrMore` expressions: . first expression match could be enclosed in an extra nesting level . out-of-order expressions now handled correctly if mixed with required expressions . results names are maintained correctly for these expressions - Fixed traceback trimming, and added `ParserElement.verbose_traceback` save/restore to `reset_pyparsing_context()`. - Default string for `Word` expressions now also include indications of `min` and `max` length specification, if applicable, similar to regex length specifications: Word(alphas) -> "W:(A-Za-z)" Word(nums) -> "W:(0-9)" Word(nums, exact=3) -> "W:(0-9){3}" Word(nums, min=2) -> "W:(0-9){2,...}" Word(nums, max=3) -> "W:(0-9){1,3}" Word(nums, min=2, max=3) -> "W:(0-9){2,3}" For expressions of the `Char` class (similar to `Word(..., exact=1)`, the expression is simply the character range in parentheses: Char(nums) -> "(0-9)" Char(alphas) -> "(A-Za-z)" - Removed `copy()` override in `Keyword` class which did not preserve definition of ident chars from the original expression. PR #233 submitted by jgrey4296, thanks! - In addition to `pyparsing.__version__`, there is now also a `pyparsing.__version_info__`, following the same structure and field names as in `sys.version_info`. Version 3.0.0a2 - June, 2020 ---------------------------- - Summary of changes for 3.0.0 can be found in "What's New in Pyparsing 3.0.0" documentation. - API CHANGE Changed result returned when parsing using `countedArray`, the array items are no longer returned in a doubly-nested list. - An excellent new enhancement is the new railroad diagram generator for documenting pyparsing parsers: import pyparsing as pp from pyparsing.diagram import to_railroad, railroad_to_html from pathlib import Path # define a simple grammar for parsing street addresses such # as "123 Main Street" # number word... number = pp.Word(pp.nums).setName("number") name = pp.Word(pp.alphas).setName("word")[1, ...] parser = number("house_number") + name("street") parser.setName("street address") # construct railroad track diagram for this parser and # save as HTML rr = to_railroad(parser) Path('parser_rr_diag.html').write_text(railroad_to_html(rr)) Very nice work provided by Michael Milton, thanks a ton! - Enhanced default strings created for Word expressions, now showing string ranges if possible. `Word(alphas)` would formerly print as `W:(ABCD...)`, now prints as `W:(A-Za-z)`. - Added `ignoreWhitespace(recurse:bool = True)`` and added a recurse argument to `leaveWhitespace`, both added to provide finer control over pyparsing's whitespace skipping. Also contributed by Michael Milton. - The unicode range definitions for the various languages were recalculated by interrogating the unicodedata module by character name, selecting characters that contained that language in their Unicode name. (Issue #227) Also, pyparsing_unicode.Korean was renamed to Hangul (Korean is also defined as a synonym for compatibility). - Enhanced `ParseResults` dump() to show both results names and list subitems. Fixes bug where adding a results name would hide lower-level structures in the `ParseResults`. - Added new __diag__ warnings: "warn_on_parse_using_empty_Forward" - warns that a Forward has been included in a grammar, but no expression was attached to it using '<<=' or '<<' "warn_on_assignment_to_Forward" - warns that a Forward has been created, but was probably later overwritten by erroneously using '=' instead of '<<=' (this is a common mistake when using Forwards) (**currently not working on PyPy**) - Added `ParserElement`.recurse() method to make it simpler for grammar utilities to navigate through the tree of expressions in a pyparsing grammar. - Fixed bug in `ParseResults` repr() which showed all matching entries for a results name, even if `listAllMatches` was set to False when creating the `ParseResults` originally. Reported by Nicholas42 on GitHub, good catch! (Issue #205) - Modified refactored modules to use relative imports, as pointed out by setuptools project member jaraco, thank you! - Off-by-one bug found in the roman_numerals.py example, a bug that has been there for about 14 years! PR submitted by Jay Pedersen, nice catch! - A simplified Lua parser has been added to the examples (lua_parser.py). - Added make_diagram.py to the examples directory to demonstrate creation of railroad diagrams for selected pyparsing examples. Also restructured some examples to make their parsers importable without running their embedded tests. Version 3.0.0a1 - April, 2020 ----------------------------- - Removed Py2.x support and other deprecated features. Pyparsing now requires Python 3.5 or later. If you are using an earlier version of Python, you must use a Pyparsing 2.4.x version Deprecated features removed: . `ParseResults.asXML()` - if used for debugging, switch to using `ParseResults.dump()`; if used for data transfer, use `ParseResults.asDict()` to convert to a nested Python dict, which can then be converted to XML or JSON or other transfer format . `operatorPrecedence` synonym for `infixNotation` - convert to calling `infixNotation` . `commaSeparatedList` - convert to using pyparsing_common.comma_separated_list . `upcaseTokens` and `downcaseTokens` - convert to using `pyparsing_common.upcaseTokens` and `downcaseTokens` . __compat__.collect_all_And_tokens will not be settable to False to revert to pre-2.3.1 results name behavior - review use of names for `MatchFirst` and Or expressions containing And expressions, as they will return the complete list of parsed tokens, not just the first one. Use `__diag__.warn_multiple_tokens_in_named_alternation` to help identify those expressions in your parsers that will have changed as a result. - Removed support for running `python setup.py test`. The setuptools maintainers consider the test command deprecated (see ). To run the Pyparsing test, use the command `tox`. - API CHANGE: The staticmethod `ParseException.explain` has been moved to `ParseBaseException.explain_exception`, and a new `explain` instance method added to `ParseBaseException`. This will make calls to `explain` much more natural: try: expr.parseString("...") except ParseException as pe: print(pe.explain()) - POTENTIAL API CHANGE: `ZeroOrMore` expressions that have results names will now include empty lists for their name if no matches are found. Previously, no named result would be present. Code that tested for the presence of any expressions using "if name in results:" will now always return True. This code will need to change to "if name in results and results[name]:" or just "if results[name]:". Also, any parser unit tests that check the `asDict()` contents will now see additional entries for parsers having named `ZeroOrMore` expressions, whose values will be `[]`. - POTENTIAL API CHANGE: Fixed a bug in which calls to `ParserElement.setDefaultWhitespaceChars` did not change whitespace definitions on any pyparsing built-in expressions defined at import time (such as `quotedString`, or those defined in pyparsing_common). This would lead to confusion when built-in expressions would not use updated default whitespace characters. Now a call to `ParserElement.setDefaultWhitespaceChars` will also go and update all pyparsing built-ins to use the new default whitespace characters. (Note that this will only modify expressions defined within the pyparsing module.) Prompted by work on a StackOverflow question posted by jtiai. - Expanded __diag__ and __compat__ to actual classes instead of just namespaces, to add some helpful behavior: - enable() and .disable() methods to give extra help when setting or clearing flags (detects invalid flag names, detects when trying to set a __compat__ flag that is no longer settable). Use these methods now to set or clear flags, instead of directly setting to True or False. import pyparsing as pp pp.__diag__.enable("warn_multiple_tokens_in_named_alternation") - __diag__.enable_all_warnings() is another helper that sets all "warn*" diagnostics to True. pp.__diag__.enable_all_warnings() - added new warning, "warn_on_match_first_with_lshift_operator" to warn when using '<<' with a '|' `MatchFirst` operator, which will create an unintended expression due to precedence of operations. Example: This statement will erroneously define the `fwd` expression as just `expr_a`, even though `expr_a | expr_b` was intended, since '<<' operator has precedence over '|': fwd << expr_a | expr_b To correct this, use the '<<=' operator (preferred) or parentheses to override operator precedence: fwd <<= expr_a | expr_b or fwd << (expr_a | expr_b) - Cleaned up default tracebacks when getting a `ParseException` when calling `parseString`. Exception traces should now stop at the call in `parseString`, and not include the internal traceback frames. (If the full traceback is desired, then set `ParserElement`.verbose_traceback to True.) - Fixed `FutureWarnings` that sometimes are raised when '[' passed as a character to Word. - New namespace, assert methods and classes added to support writing unit tests. - `assertParseResultsEquals` - `assertParseAndCheckList` - `assertParseAndCheckDict` - `assertRunTestResults` - `assertRaisesParseException` - `reset_pyparsing_context` context manager, to restore pyparsing config settings - Enhanced error messages and error locations when parsing fails on the Keyword or `CaselessKeyword` classes due to the presence of a preceding or trailing keyword character. Surfaced while working with metaperl on issue #201. - Enhanced the `Regex` class to be compatible with re's compiled with the re-equivalent regex module. Individual expressions can be built with regex compiled expressions using: import pyparsing as pp import regex # would use regex for this expression integer_parser = pp.Regex(regex.compile(r'\d+')) Inspired by PR submitted by bjrnfrdnnd on GitHub, very nice! - Fixed handling of `ParseSyntaxExceptions` raised as part of Each expressions, when sub-expressions contain '-' backtrack suppression. As part of resolution to a question posted by John Greene on StackOverflow. - Potentially *huge* performance enhancement when parsing Word expressions built from pyparsing_unicode character sets. Word now internally converts ranges of consecutive characters to regex character ranges (converting "0123456789" to "0-9" for instance), resulting in as much as 50X improvement in performance! Work inspired by a question posted by Midnighter on StackOverflow. - Improvements in select_parser.py, to include new SQL syntax from SQLite. PR submitted by Robert Coup, nice work! - Fixed bug in `PrecededBy` which caused infinite recursion, issue #127 submitted by EdwardJB. - Fixed bug in `CloseMatch` where end location was incorrectly computed; and updated partial_gene_match.py example. - Fixed bug in `indentedBlock` with a parser using two different types of nested indented blocks with different indent values, but sharing the same indent stack, submitted by renzbagaporo. - Fixed bug in `Each` when using `Regex`, when `Regex` expression would get parsed twice; issue #183 submitted by scauligi, thanks! - `BigQueryViewParser.py` added to examples directory, PR submitted by Michael Smedberg, nice work! - booleansearchparser.py added to examples directory, PR submitted by xecgr. Builds on searchparser.py, adding support for '*' wildcards and non-Western alphabets. - Fixed bug in delta_time.py example, when using a quantity of seconds/minutes/hours/days > 999. - Fixed bug in regex definitions for real and sci_real expressions in pyparsing_common. Issue #194, reported by Michael Wayne Goodman, thanks! - Fixed `FutureWarning` raised beginning in Python 3.7 for `Regex` expressions containing '[' within a regex set. - Minor reformatting of output from `runTests` to make embedded comments more visible. - And finally, many thanks to those who helped in the restructuring of the pyparsing code base as part of this release. Pyparsing now has more standard package structure, more standard unit tests, and more standard code formatting (using black). Special thanks to jdufresne, klahnakoski, mattcarmody, and ckeygusuz, to name just a few. Version 2.4.7 - April, 2020 --------------------------- - Backport of selected fixes from 3.0.0 work: . Each bug with `Regex` expressions . And expressions not properly constructing with generator . Traceback abbreviation . Bug in delta_time example . Fix regexen in pyparsing_common.real and .sci_real . Avoid FutureWarning on Python 3.7 or later . Cleanup output in runTests if comments are embedded in test string Version 2.4.6 - December, 2019 ------------------------------ - Fixed typos in White mapping of whitespace characters, to use correct "\u" prefix instead of "u\". - Fix bug in left-associative ternary operators defined using infixNotation. First reported on StackOverflow by user Jeronimo. - Backport of pyparsing_test namespace from 3.0.0, including TestParseResultsAsserts mixin class defining unittest-helper methods: . def assertParseResultsEquals( self, result, expected_list=None, expected_dict=None, msg=None) . def assertParseAndCheckList( self, expr, test_string, expected_list, msg=None, verbose=True) . def assertParseAndCheckDict( self, expr, test_string, expected_dict, msg=None, verbose=True) . def assertRunTestResults( self, run_tests_report, expected_parse_results=None, msg=None) . def assertRaisesParseException(self, exc_type=ParseException, msg=None) To use the methods in this mixin class, declare your unittest classes as: from pyparsing import pyparsing_test as ppt class MyParserTest(ppt.TestParseResultsAsserts, unittest.TestCase): ... Version 2.4.5 - November, 2019 ------------------------------ - NOTE: final release compatible with Python 2.x. - Fixed issue with reading README.rst as part of setup.py's initialization of the project's long_description, with a non-ASCII space character causing errors when installing from source on platforms where UTF-8 is not the default encoding. Version 2.4.4 - November, 2019 -------------------------------- - Unresolved symbol reference in 2.4.3 release was masked by stdout buffering in unit tests, thanks for the prompt heads-up, Ned Batchelder! Version 2.4.3 - November, 2019 ------------------------------ - Fixed a bug in ParserElement.__eq__ that would for some parsers create a recursion error at parser definition time. Thanks to Michael Clerx for the assist. (Addresses issue #123) - Fixed bug in indentedBlock where a block that ended at the end of the input string could cause pyparsing to loop forever. Raised as part of discussion on StackOverflow with geckos. - Backports from pyparsing 3.0.0: . __diag__.enable_all_warnings() . Fixed bug in PrecededBy which caused infinite recursion, issue #127 . support for using regex-compiled RE to construct `Regex` expressions Version 2.4.2 - July, 2019 -------------------------- - Updated the shorthand notation that has been added for repetition expressions: expr[min, max], with '...' valid as a min or max value: - expr[...] and expr[0, ...] are equivalent to ZeroOrMore(expr) - expr[1, ...] is equivalent to OneOrMore(expr) - expr[n, ...] or expr[n,] is equivalent to expr*n + ZeroOrMore(expr) (read as "n or more instances of expr") - expr[..., n] is equivalent to expr*(0, n) - expr[m, n] is equivalent to expr*(m, n) Note that expr[..., n] and expr[m, n] do not raise an exception if more than n exprs exist in the input stream. If this behavior is desired, then write expr[..., n] + ~expr. Better interpretation of [...] as ZeroOrMore raised by crowsonkb, thanks for keeping me in line! If upgrading from 2.4.1 or 2.4.1.1 and you have used `expr[...]` for `OneOrMore(expr)`, it must be updated to `expr[1, ...]`. - The defaults on all the `__diag__` switches have been set to False, to avoid getting alarming warnings. To use these diagnostics, set them to True after importing pyparsing. Example: import pyparsing as pp pp.__diag__.warn_multiple_tokens_in_named_alternation = True - Fixed bug introduced by the use of __getitem__ for repetition, overlooking Python's legacy implementation of iteration by sequentially calling __getitem__ with increasing numbers until getting an IndexError. Found during investigation of problem reported by murlock, merci! Version 2.4.2a1 - July, 2019 ---------------------------- It turns out I got the meaning of `[...]` absolutely backwards, so I've deleted 2.4.1 and am repushing this release as 2.4.2a1 for people to give it a try before I can call it ready to go. The `expr[...]` notation was pushed out to be synonymous with `OneOrMore(expr)`, but this is really counter to most Python notations (and even other internal pyparsing notations as well). It should have been defined to be equivalent to ZeroOrMore(expr). - Changed [...] to emit ZeroOrMore instead of OneOrMore. - Removed code that treats ParserElements like iterables. - Change all __diag__ switches to False. Version 2.4.1.1 - July 24, 2019 ------------------------------- This is a re-release of version 2.4.1 to restore the release history in PyPI, since the 2.4.1 release was deleted. There are 3 known issues in this release, which are fixed in the upcoming 2.4.2: - API change adding support for `expr[...]` - the original code in 2.4.1 incorrectly implemented this as OneOrMore. Code using this feature under this release should explicitly use `expr[0, ...]` for ZeroOrMore and `expr[1, ...]` for OneOrMore. In 2.4.2 you will be able to write `expr[...]` equivalent to `ZeroOrMore(expr)`. - Bug if composing And, Or, MatchFirst, or Each expressions using an expression. This only affects code which uses explicit expression construction using the And, Or, etc. classes instead of using overloaded operators '+', '^', and so on. If constructing an And using a single expression, you may get an error that "cannot multiply ParserElement by 0 or (0, 0)" or a Python `IndexError`. Change code like cmd = Or(Word(alphas)) to cmd = Or([Word(alphas)]) (Note that this is not the recommended style for constructing Or expressions.) - Some newly-added `__diag__` switches are enabled by default, which may give rise to noisy user warnings for existing parsers. You can disable them using: import pyparsing as pp pp.__diag__.warn_multiple_tokens_in_named_alternation = False pp.__diag__.warn_ungrouped_named_tokens_in_collection = False pp.__diag__.warn_name_set_on_empty_Forward = False pp.__diag__.warn_on_multiple_string_args_to_oneof = False pp.__diag__.enable_debug_on_named_expressions = False In 2.4.2 these will all be set to False by default. Version 2.4.1 - July, 2019 -------------------------- - NOTE: Deprecated functions and features that will be dropped in pyparsing 2.5.0 (planned next release): . support for Python 2 - ongoing users running with Python 2 can continue to use pyparsing 2.4.1 . ParseResults.asXML() - if used for debugging, switch to using ParseResults.dump(); if used for data transfer, use ParseResults.asDict() to convert to a nested Python dict, which can then be converted to XML or JSON or other transfer format . operatorPrecedence synonym for infixNotation - convert to calling infixNotation . commaSeparatedList - convert to using pyparsing_common.comma_separated_list . upcaseTokens and downcaseTokens - convert to using pyparsing_common.upcaseTokens and downcaseTokens . __compat__.collect_all_And_tokens will not be settable to False to revert to pre-2.3.1 results name behavior - review use of names for MatchFirst and Or expressions containing And expressions, as they will return the complete list of parsed tokens, not just the first one. Use __diag__.warn_multiple_tokens_in_named_alternation (described below) to help identify those expressions in your parsers that will have changed as a result. - A new shorthand notation has been added for repetition expressions: expr[min, max], with '...' valid as a min or max value: - expr[...] is equivalent to OneOrMore(expr) - expr[0, ...] is equivalent to ZeroOrMore(expr) - expr[1, ...] is equivalent to OneOrMore(expr) - expr[n, ...] or expr[n,] is equivalent to expr*n + ZeroOrMore(expr) (read as "n or more instances of expr") - expr[..., n] is equivalent to expr*(0, n) - expr[m, n] is equivalent to expr*(m, n) Note that expr[..., n] and expr[m, n] do not raise an exception if more than n exprs exist in the input stream. If this behavior is desired, then write expr[..., n] + ~expr. - '...' can also be used as short hand for SkipTo when used in adding parse expressions to compose an And expression. Literal('start') + ... + Literal('end') And(['start', ..., 'end']) are both equivalent to: Literal('start') + SkipTo('end')("_skipped*") + Literal('end') The '...' form has the added benefit of not requiring repeating the skip target expression. Note that the skipped text is returned with '_skipped' as a results name, and that the contents of `_skipped` will contain a list of text from all `...`s in the expression. - '...' can also be used as a "skip forward in case of error" expression: expr = "start" + (Word(nums).setName("int") | ...) + "end" expr.parseString("start 456 end") ['start', '456', 'end'] expr.parseString("start 456 foo 789 end") ['start', '456', 'foo 789 ', 'end'] - _skipped: ['foo 789 '] expr.parseString("start foo end") ['start', 'foo ', 'end'] - _skipped: ['foo '] expr.parseString("start end") ['start', '', 'end'] - _skipped: ['missing '] Note that in all the error cases, the '_skipped' results name is present, showing a list of the extra or missing items. This form is only valid when used with the '|' operator. - Improved exception messages to show what was actually found, not just what was expected. word = pp.Word(pp.alphas) pp.OneOrMore(word).parseString("aaa bbb 123", parseAll=True) Former exception message: pyparsing.ParseException: Expected end of text (at char 8), (line:1, col:9) New exception message: pyparsing.ParseException: Expected end of text, found '1' (at char 8), (line:1, col:9) - Added diagnostic switches to help detect and warn about common parser construction mistakes, or enable additional parse debugging. Switches are attached to the pyparsing.__diag__ namespace object: - warn_multiple_tokens_in_named_alternation - flag to enable warnings when a results name is defined on a MatchFirst or Or expression with one or more And subexpressions (default=True) - warn_ungrouped_named_tokens_in_collection - flag to enable warnings when a results name is defined on a containing expression with ungrouped subexpressions that also have results names (default=True) - warn_name_set_on_empty_Forward - flag to enable warnings when a Forward is defined with a results name, but has no contents defined (default=False) - warn_on_multiple_string_args_to_oneof - flag to enable warnings when oneOf is incorrectly called with multiple str arguments (default=True) - enable_debug_on_named_expressions - flag to auto-enable debug on all subsequent calls to ParserElement.setName() (default=False) warn_multiple_tokens_in_named_alternation is intended to help those who currently have set __compat__.collect_all_And_tokens to False as a workaround for using the pre-2.3.1 code with named MatchFirst or Or expressions containing an And expression. - Added ParseResults.from_dict classmethod, to simplify creation of a ParseResults with results names using a dict, which may be nested. This makes it easy to add a sub-level of named items to the parsed tokens in a parse action. - Added asKeyword argument (default=False) to oneOf, to force keyword-style matching on the generated expressions. - ParserElement.runTests now accepts an optional 'file' argument to redirect test output to a file-like object (such as a StringIO, or opened file). Default is to write to sys.stdout. - conditionAsParseAction is a helper method for constructing a parse action method from a predicate function that simply returns a boolean result. Useful for those places where a predicate cannot be added using addCondition, but must be converted to a parse action (such as in infixNotation). May be used as a decorator if default message and exception types can be used. See ParserElement.addCondition for more details about the expected signature and behavior for predicate condition methods. - While investigating issue #93, I found that Or and addCondition could interact to select an alternative that is not the longest match. This is because Or first checks all alternatives for matches without running attached parse actions or conditions, orders by longest match, and then rechecks for matches with conditions and parse actions. Some expressions, when checking with conditions, may end up matching on a shorter token list than originally matched, but would be selected because of its original priority. This matching code has been expanded to do more extensive searching for matches when a second-pass check matches a smaller list than in the first pass. - Fixed issue #87, a regression in indented block. Reported by Renz Bagaporo, who submitted a very nice repro example, which makes the bug-fixing process a lot easier, thanks! - Fixed MemoryError issue #85 and #91 with str generation for Forwards. Thanks decalage2 and Harmon758 for your patience. - Modified setParseAction to accept None as an argument, indicating that all previously-defined parse actions for the expression should be cleared. - Modified pyparsing_common.real and sci_real to parse reals without leading integer digits before the decimal point, consistent with Python real number formats. Original PR #98 submitted by ansobolev. - Modified runTests to call postParse function before dumping out the parsed results - allows for postParse to add further results, such as indications of additional validation success/failure. - Updated statemachine example: refactored state transitions to use overridden classmethods; added Mixin class to simplify definition of application classes that "own" the state object and delegate to it to model state-specific properties and behavior. - Added example nested_markup.py, showing a simple wiki markup with nested markup directives, and illustrating the use of '...' for skipping over input to match the next expression. (This example uses syntax that is not valid under Python 2.) - Rewrote delta_time.py example (renamed from deltaTime.py) to fix some omitted formats and upgrade to latest pyparsing idioms, beginning with writing an actual BNF. - With the help and encouragement from several contributors, including Matěj Cepl and Cengiz Kaygusuz, I've started cleaning up the internal coding styles in core pyparsing, bringing it up to modern coding practices from pyparsing's early development days dating back to 2003. Whitespace has been largely standardized along PEP8 guidelines, removing extra spaces around parentheses, and adding them around arithmetic operators and after colons and commas. I was going to hold off on doing this work until after 2.4.1, but after cleaning up a few trial classes, the difference was so significant that I continued on to the rest of the core code base. This should facilitate future work and submitted PRs, allowing them to focus on substantive code changes, and not get sidetracked by whitespace issues. Version 2.4.0 - April, 2019 --------------------------- - Well, it looks like the API change that was introduced in 2.3.1 was more drastic than expected, so for a friendlier forward upgrade path, this release: . Bumps the current version number to 2.4.0, to reflect this incompatible change. . Adds a pyparsing.__compat__ object for specifying compatibility with future breaking changes. . Conditionalizes the API-breaking behavior, based on the value pyparsing.__compat__.collect_all_And_tokens. By default, this value will be set to True, reflecting the new bugfixed behavior. To set this value to False, add to your code: import pyparsing pyparsing.__compat__.collect_all_And_tokens = False . User code that is dependent on the pre-bugfix behavior can restore it by setting this value to False. In 2.5 and later versions, the conditional code will be removed and setting the flag to True or False in these later versions will have no effect. - Updated unitTests.py and simple_unit_tests.py to be compatible with "python setup.py test". To run tests using setup, do: python setup.py test python setup.py test -s unitTests.suite python setup.py test -s simple_unit_tests.suite Prompted by issue #83 and PR submitted by bdragon28, thanks. - Fixed bug in runTests handling '\n' literals in quoted strings. - Added tag_body attribute to the start tag expressions generated by makeHTMLTags, so that you can avoid using SkipTo to roll your own tag body expression: a, aEnd = pp.makeHTMLTags('a') link = a + a.tag_body("displayed_text") + aEnd for t in s.searchString(html_page): print(t.displayed_text, '->', t.startA.href) - indentedBlock failure handling was improved; PR submitted by TMiguelT, thanks! - Address Py2 incompatibility in simpleUnitTests, plus explain() and Forward str() cleanup; PRs graciously provided by eswald. - Fixed docstring with embedded '\w', which creates SyntaxWarnings in Py3.8, issue #80. - Examples: - Added example parser for rosettacode.org tutorial compiler. - Added example to show how an HTML table can be parsed into a collection of Python lists or dicts, one per row. - Updated SimpleSQL.py example to handle nested selects, reworked 'where' expression to use infixNotation. - Added include_preprocessor.py, similar to macroExpander.py. - Examples using makeHTMLTags use new tag_body expression when retrieving a tag's body text. - Updated examples that are runnable as unit tests: python setup.py test -s examples.antlr_grammar_tests python setup.py test -s examples.test_bibparse Version 2.3.1 - January, 2019 ----------------------------- - POSSIBLE API CHANGE: this release fixes a bug when results names were attached to a MatchFirst or Or object containing an And object. Previously, a results name on an And object within an enclosing MatchFirst or Or could return just the first token in the And. Now, all the tokens matched by the And are correctly returned. This may result in subtle changes in the tokens returned if you have this condition in your pyparsing scripts. - New staticmethod ParseException.explain() to help diagnose parse exceptions by showing the failing input line and the trace of ParserElements in the parser leading up to the exception. explain() returns a multiline string listing each element by name. (This is still an experimental method, and the method signature and format of the returned string may evolve over the next few releases.) Example: # define a parser to parse an integer followed by an # alphabetic word expr = pp.Word(pp.nums).setName("int") + pp.Word(pp.alphas).setName("word") try: # parse a string with a numeric second value instead of alpha expr.parseString("123 355") except pp.ParseException as pe: print(pp.ParseException.explain(pe)) Prints: 123 355 ^ ParseException: Expected word (at char 4), (line:1, col:5) __main__.ExplainExceptionTest pyparsing.And - {int word} pyparsing.Word - word explain() will accept any exception type and will list the function names and parse expressions in the stack trace. This is especially useful when an exception is raised in a parse action. Note: explain() is only supported under Python 3. - Fix bug in dictOf which could match an empty sequence, making it infinitely loop if wrapped in a OneOrMore. - Added unicode sets to pyparsing_unicode for Latin-A and Latin-B ranges. - Added ability to define custom unicode sets as combinations of other sets using multiple inheritance. class Turkish_set(pp.pyparsing_unicode.Latin1, pp.pyparsing_unicode.LatinA): pass turkish_word = pp.Word(Turkish_set.alphas) - Updated state machine import examples, with state machine demos for: . traffic light . library book checkin/checkout . document review/approval In the traffic light example, you can use the custom 'statemachine' keyword to define the states for a traffic light, and have the state classes auto-generated for you: statemachine TrafficLightState: Red -> Green Green -> Yellow Yellow -> Red Similar for state machines with named transitions, like the library book state example: statemachine LibraryBookState: New -(shelve)-> Available Available -(reserve)-> OnHold OnHold -(release)-> Available Available -(checkout)-> CheckedOut CheckedOut -(checkin)-> Available Once the classes are defined, then additional Python code can reference those classes to add class attributes, instance methods, etc. See the examples in examples/statemachine - Added an example parser for the decaf language. This language is used in CS compiler classes in many colleges and universities. - Fixup of docstrings to Sphinx format, inclusion of test files in the source package, and convert markdown to rst throughout the distribution, great job by Matěj Cepl! - Expanded the whitespace characters recognized by the White class to include all unicode defined spaces. Suggested in Issue #51 by rtkjbillo. - Added optional postParse argument to ParserElement.runTests() to add a custom callback to be called for test strings that parse successfully. Useful for running tests that do additional validation or processing on the parsed results. See updated chemicalFormulas.py example. - Removed distutils fallback in setup.py. If installing the package fails, please update to the latest version of setuptools. Plus overall project code cleanup (CRLFs, whitespace, imports, etc.), thanks Jon Dufresne! - Fix bug in CaselessKeyword, to make its behavior consistent with Keyword(caseless=True). Fixes Issue #65 reported by telesphore. Version 2.3.0 - October, 2018 ----------------------------- - NEW SUPPORT FOR UNICODE CHARACTER RANGES This release introduces the pyparsing_unicode namespace class, defining a series of language character sets to simplify the definition of alphas, nums, alphanums, and printables in the following language sets: . Arabic . Chinese . Cyrillic . Devanagari . Greek . Hebrew . Japanese (including Kanji, Katakana, and Hirigana subsets) . Korean . Latin1 (includes 7 and 8-bit Latin characters) . Thai . CJK (combination of Chinese, Japanese, and Korean sets) For example, your code can define words using: korean_word = Word(pyparsing_unicode.Korean.alphas) See their use in the updated examples greetingInGreek.py and greetingInKorean.py. This namespace class also offers access to these sets using their unicode identifiers. - POSSIBLE API CHANGE: Fixed bug where a parse action that explicitly returned the input ParseResults could add another nesting level in the results if the current expression had a results name. vals = pp.OneOrMore(pp.pyparsing_common.integer)("int_values") def add_total(tokens): tokens['total'] = sum(tokens) return tokens # this line can be removed vals.addParseAction(add_total) print(vals.parseString("244 23 13 2343").dump()) Before the fix, this code would print (note the extra nesting level): [244, 23, 13, 2343] - int_values: [244, 23, 13, 2343] - int_values: [244, 23, 13, 2343] - total: 2623 - total: 2623 With the fix, this code now prints: [244, 23, 13, 2343] - int_values: [244, 23, 13, 2343] - total: 2623 This fix will change the structure of ParseResults returned if a program defines a parse action that returns the tokens that were sent in. This is not necessary, and statements like "return tokens" in the example above can be safely deleted prior to upgrading to this release, in order to avoid the bug and get the new behavior. Reported by seron in Issue #22, nice catch! - POSSIBLE API CHANGE: Fixed a related bug where a results name erroneously created a second level of hierarchy in the returned ParseResults. The intent for accumulating results names into ParseResults is that, in the absence of Group'ing, all names get merged into a common namespace. This allows us to write: key_value_expr = (Word(alphas)("key") + '=' + Word(nums)("value")) result = key_value_expr.parseString("a = 100") and have result structured as {"key": "a", "value": "100"} instead of [{"key": "a"}, {"value": "100"}]. However, if a named expression is used in a higher-level non-Group expression that *also* has a name, a false sub-level would be created in the namespace: num = pp.Word(pp.nums) num_pair = ("[" + (num("A") + num("B"))("values") + "]") U = num_pair.parseString("[ 10 20 ]") print(U.dump()) Since there is no grouping, "A", "B", and "values" should all appear at the same level in the results, as: ['[', '10', '20', ']'] - A: '10' - B: '20' - values: ['10', '20'] Instead, an extra level of "A" and "B" show up under "values": ['[', '10', '20', ']'] - A: '10' - B: '20' - values: ['10', '20'] - A: '10' - B: '20' This bug has been fixed. Now, if this hierarchy is desired, then a Group should be added: num_pair = ("[" + pp.Group(num("A") + num("B"))("values") + "]") Giving: ['[', ['10', '20'], ']'] - values: ['10', '20'] - A: '10' - B: '20' But in no case should "A" and "B" appear in multiple levels. This bug-fix fixes that. If you have current code which relies on this behavior, then add or remove Groups as necessary to get your intended results structure. Reported by Athanasios Anastasiou. - IndexError's raised in parse actions will get explicitly reraised as ParseExceptions that wrap the original IndexError. Since IndexError sometimes occurs as part of pyparsing's normal parsing logic, IndexErrors that are raised during a parse action may have gotten silently reinterpreted as parsing errors. To retain the information from the IndexError, these exceptions will now be raised as ParseExceptions that reference the original IndexError. This wrapping will only be visible when run under Python3, since it emulates "raise ... from ..." syntax. Addresses Issue #4, reported by guswns0528. - Added Char class to simplify defining expressions of a single character. (Char("abc") is equivalent to Word("abc", exact=1)) - Added class PrecededBy to perform lookbehind tests. PrecededBy is used in the same way as FollowedBy, passing in an expression that must occur just prior to the current parse location. For fixed-length expressions like a Literal, Keyword, Char, or a Word with an `exact` or `maxLen` length given, `PrecededBy(expr)` is sufficient. For varying length expressions like a Word with no given maximum length, `PrecededBy` must be constructed with an integer `retreat` argument, as in `PrecededBy(Word(alphas, nums), retreat=10)`, to specify the maximum number of characters pyparsing must look backward to make a match. pyparsing will check all the values from 1 up to retreat characters back from the current parse location. When stepping backwards through the input string, PrecededBy does *not* skip over whitespace. PrecededBy can be created with a results name so that, even though it always returns an empty parse result, the result *can* include named results. Idea first suggested in Issue #30 by Freakwill. - Updated FollowedBy to accept expressions that contain named results, so that results names defined in the lookahead expression will be returned, even though FollowedBy always returns an empty list. Inspired by the same feature implemented in PrecededBy. Version 2.2.2 - September, 2018 ------------------------------- - Fixed bug in SkipTo, if a SkipTo expression that was skipping to an expression that returned a list (such as an And), and the SkipTo was saved as a named result, the named result could be saved as a ParseResults - should always be saved as a string. Issue #28, reported by seron. - Added simple_unit_tests.py, as a collection of easy-to-follow unit tests for various classes and features of the pyparsing library. Primary intent is more to be instructional than actually rigorous testing. Complex tests can still be added in the unitTests.py file. - New features added to the `Regex` class: - optional asGroupList parameter, returns all the capture groups as a list - optional asMatch parameter, returns the raw re.match result - new sub(repl) method, which adds a parse action calling re.sub(pattern, repl, parsed_result). Simplifies creating `Regex` expressions to be used with transformString. Like re.sub, repl may be an ordinary string (similar to using pyparsing's replaceWith), or may contain references to capture groups by group number, or may be a callable that takes an re match group and returns a string. For instance: expr = pp.Regex(r"([Hh]\d):\s*(.*)").sub(r"<\1>\2") expr.transformString("h1: This is the title") will return

This is the title

- Fixed omission of LICENSE file in source tarball, also added CODE_OF_CONDUCT.md per GitHub community standards. Version 2.2.1 - September, 2018 ------------------------------- - Applied changes necessary to migrate hosting of pyparsing source over to GitHub. Many thanks for help and contributions from hugovk, jdufresne, and cngkaygusuz among others through this transition, sorry it took me so long! - Fixed import of collections.abc to address DeprecationWarnings in Python 3.7. - Updated oc.py example to support function calls in arithmetic expressions; fixed regex for '==' operator; and added packrat parsing. Raised on the pyparsing wiki by Boris Marin, thanks! - Fixed bug in select_parser.py example, group_by_terms was not reported. Reported on SF bugs by Adam Groszer, thanks Adam! - Added "Getting Started" section to the module docstring, to guide new users to the most common starting points in pyparsing's API. - Fixed bug in Literal and Keyword classes, which erroneously raised IndexError instead of ParseException. Version 2.2.0 - March, 2017 --------------------------- - Bumped minor version number to reflect compatibility issues with OneOrMore and ZeroOrMore bugfixes in 2.1.10. (2.1.10 fixed a bug that was introduced in 2.1.4, but the fix could break code written against 2.1.4 - 2.1.9.) - Updated setup.py to address recursive import problems now that pyparsing is part of 'packaging' (used by setuptools). Patch submitted by Joshua Root, much thanks! - Fixed KeyError issue reported by Yann Bizeul when using packrat parsing in the Graphite time series database, thanks Yann! - Fixed incorrect usages of '\' in literals, as described in https://docs.python.org/3/whatsnew/3.6.html#deprecated-python-behavior Patch submitted by Ville Skyttä - thanks! - Minor internal change when using '-' operator, to be compatible with ParserElement.streamline() method. - Expanded infixNotation to accept a list or tuple of parse actions to attach to an operation. - New unit test added for dill support for storing pyparsing parsers. Ordinary Python pickle can be used to pickle pyparsing parsers as long as they do not use any parse actions. The 'dill' module is an extension to pickle which *does* support pickling of attached parse actions. Version 2.1.10 - October, 2016 ------------------------------- - Fixed bug in reporting named parse results for ZeroOrMore expressions, thanks Ethan Nash for reporting this! - Fixed behavior of LineStart to be much more predictable. LineStart can now be used to detect if the next parse position is col 1, factoring in potential leading whitespace (which would cause LineStart to fail). Also fixed a bug in col, which is used in LineStart, where '\n's were erroneously considered to be column 1. - Added support for multiline test strings in runTests. - Fixed bug in ParseResults.dump when keys were not strings. Also changed display of string values to show them in quotes, to help distinguish parsed numeric strings from parsed integers that have been converted to Python ints. Version 2.1.9 - September, 2016 ------------------------------- - Added class CloseMatch, a variation on Literal which matches "close" matches, that is, strings with at most 'n' mismatching characters. - Fixed bug in Keyword.setDefaultKeywordChars(), reported by Kobayashi Shinji - nice catch, thanks! - Minor API change in pyparsing_common. Renamed some of the common expressions to PEP8 format (to be consistent with the other pyparsing_common expressions): . signedInteger -> signed_integer . sciReal -> sci_real Also, in trying to stem the API bloat of pyparsing, I've copied some of the global expressions and helper parse actions into pyparsing_common, with the originals to be deprecated and removed in a future release: . commaSeparatedList -> pyparsing_common.comma_separated_list . upcaseTokens -> pyparsing_common.upcaseTokens . downcaseTokens -> pyparsing_common.downcaseTokens (I don't expect any other expressions, like the comment expressions, quotedString, or the Word-helping strings like alphas, nums, etc. to migrate to pyparsing_common - they are just too pervasive. As for the PEP8 vs camelCase naming, all the expressions are PEP8, while the parse actions in pyparsing_common are still camelCase. It's a small step - when pyparsing 3.0 comes around, everything will change to PEP8 snake case.) - Fixed Python3 compatibility bug when using dict keys() and values() in ParseResults.getName(). - After some prodding, I've reworked the unitTests.py file for pyparsing over the past few releases. It uses some variations on unittest to handle my testing style. The test now: . auto-discovers its test classes (while maintining their order of definition) . suppresses voluminous 'print' output for tests that pass Version 2.1.8 - August, 2016 ---------------------------- - Fixed issue in the optimization to _trim_arity, when the full stacktrace is retrieved to determine if a TypeError is raised in pyparsing or in the caller's parse action. Code was traversing the full stacktrace, and potentially encountering UnicodeDecodeError. - Fixed bug in ParserElement.inlineLiteralsUsing, causing infinite loop with Suppress. - Fixed bug in Each, when merging named results from multiple expressions in a ZeroOrMore or OneOrMore. Also fixed bug when ZeroOrMore expressions were erroneously treated as required expressions in an Each expression. - Added a few more inline doc examples. - Improved use of runTests in several example scripts. Version 2.1.7 - August, 2016 ---------------------------- - Fixed regression reported by Andrea Censi (surfaced in PyContracts tests) when using ParseSyntaxExceptions (raised when using operator '-') with packrat parsing. - Minor fix to oneOf, to accept all iterables, not just space-delimited strings and lists. (If you have a list or set of strings, it is not necessary to concat them using ' '.join to pass them to oneOf, oneOf will accept the list or set or generator directly.) Version 2.1.6 - August, 2016 ---------------------------- - *Major packrat upgrade*, inspired by patch provided by Tal Einat - many, many, thanks to Tal for working on this! Tal's tests show faster parsing performance (2X in some tests), *and* memory reduction from 3GB down to ~100MB! Requires no changes to existing code using packratting. (Uses OrderedDict, available in Python 2.7 and later. For Python 2.6 users, will attempt to import from ordereddict backport. If not present, will implement pure-Python Fifo dict.) - Minor API change - to better distinguish between the flexible numeric types defined in pyparsing_common, I've changed "numeric" (which parsed numbers of different types and returned int for ints, float for floats, etc.) and "number" (which parsed numbers of int or float type, and returned all floats) to "number" and "fnumber" respectively. I hope the "f" prefix of "fnumber" will be a better indicator of its internal conversion of parsed values to floats, while the generic "number" is similar to the flexible number syntax in other languages. Also fixed a bug in pyparsing_common.numeric (now renamed to pyparsing_common.number), integers were parsed and returned as floats instead of being retained as ints. - Fixed bug in upcaseTokens and downcaseTokens introduced in 2.1.5, when the parse action was used in conjunction with results names. Reported by Steven Arcangeli from the dql project, thanks for your patience, Steven! - Major change to docs! After seeing some comments on reddit about general issue with docs of Python modules, and thinking that I'm a little overdue in doing some doc tuneup on pyparsing, I decided to following the suggestions of the redditor and add more inline examples to the pyparsing reference documentation. I hope this addition will clarify some of the more common questions people have, especially when first starting with pyparsing/Python. - Deprecated ParseResults.asXML. I've never been too happy with this method, and it usually forces some unnatural code in the parsers in order to get decent tag names. The amount of guesswork that asXML has to do to try to match names with values should have been a red flag from day one. If you are using asXML, you will need to implement your own ParseResults->XML serialization. Or consider migrating to a more current format such as JSON (which is very easy to do: results_as_json = json.dumps(parse_result.asDict()) Hopefully, when I remove this code in a future version, I'll also be able to simplify some of the craziness in ParseResults, which IIRC was only there to try to make asXML work. - Updated traceParseAction parse action decorator to show the repr of the input and output tokens, instead of the str format, since str has been simplified to just show the token list content. (The change to ParseResults.__str__ occurred in pyparsing 2.0.4, but it seems that didn't make it into the release notes - sorry! Too many users, especially beginners, were confused by the "([token_list], {names_dict})" str format for ParseResults, thinking they were getting a tuple containing a list and a dict. The full form can be seen if using repr().) For tracing tokens in and out of parse actions, the more complete repr form provides important information when debugging parse actions. Version 2.1.5 - June, 2016 ------------------------------ - Added ParserElement.split() generator method, similar to re.split(). Includes optional arguments maxsplit (to limit the number of splits), and includeSeparators (to include the separating matched text in the returned output, default=False). - Added a new parse action construction helper tokenMap, which will apply a function and optional arguments to each element in a ParseResults. So this parse action: def lowercase_all(tokens): return [str(t).lower() for t in tokens] OneOrMore(Word(alphas)).setParseAction(lowercase_all) can now be written: OneOrMore(Word(alphas)).setParseAction(tokenMap(str.lower)) Also simplifies writing conversion parse actions like: integer = Word(nums).setParseAction(lambda t: int(t[0])) to just: integer = Word(nums).setParseAction(tokenMap(int)) If additional arguments are necessary, they can be included in the call to tokenMap, as in: hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16)) - Added more expressions to pyparsing_common: . IPv4 and IPv6 addresses (including long, short, and mixed forms of IPv6) . MAC address . ISO8601 date and date time strings (with named fields for year, month, etc.) . UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) . hex integer (returned as int) . fraction (integer '/' integer, returned as float) . mixed integer (integer '-' fraction, or just fraction, returned as float) . stripHTMLTags (parse action to remove tags from HTML source) . parse action helpers convertToDate and convertToDatetime to do custom parse time conversions of parsed ISO8601 strings - runTests now returns a two-tuple: success if all tests succeed, and an output list of each test and its output lines. - Added failureTests argument (default=False) to runTests, so that tests can be run that are expected failures, and runTests' success value will return True only if all tests *fail* as expected. Also, parseAll now defaults to True. - New example numerics.py, shows samples of parsing integer and real numbers using locale-dependent formats: 4.294.967.295,000 4 294 967 295,000 4,294,967,295.000 Version 2.1.4 - May, 2016 ------------------------------ - Split out the '==' behavior in ParserElement, now implemented as the ParserElement.matches() method. Using '==' for string test purposes will be removed in a future release. - Expanded capabilities of runTests(). Will now accept embedded comments (default is Python style, leading '#' character, but customizable). Comments will be emitted along with the tests and test output. Useful during test development, to create a test string consisting only of test case description comments separated by blank lines, and then fill in the test cases. Will also highlight ParseFatalExceptions with "(FATAL)". - Added a 'pyparsing_common' class containing common/helpful little expressions such as integer, float, identifier, etc. I used this class as a sort of embedded namespace, to contain these helpers without further adding to pyparsing's namespace bloat. - Minor enhancement to traceParseAction decorator, to retain the parse action's name for the trace output. - Added optional 'fatal' keyword arg to addCondition, to indicate that a condition failure should halt parsing immediately. Version 2.1.3 - May, 2016 ------------------------------ - _trim_arity fix in 2.1.2 was very version-dependent on Py 3.5.0. Now works for Python 2.x, 3.3, 3.4, 3.5.0, and 3.5.1 (and hopefully beyond). Version 2.1.2 - May, 2016 ------------------------------ - Fixed bug in _trim_arity when pyparsing code is included in a PyInstaller, reported by maluwa. - Fixed catastrophic regex backtracking in implementation of the quoted string expressions (dblQuotedString, sglQuotedString, and quotedString). Reported on the pyparsing wiki by webpentest, good catch! (Also tuned up some other expressions susceptible to the same backtracking problem, such as cStyleComment, cppStyleComment, etc.) Version 2.1.1 - March, 2016 --------------------------- - Added support for assigning to ParseResults using slices. - Fixed bug in ParseResults.toDict(), in which dict values were always converted to dicts, even if they were just unkeyed lists of tokens. Reported on SO by Gerald Thibault, thanks Gerald! - Fixed bug in SkipTo when using failOn, reported by robyschek, thanks! - Fixed bug in Each introduced in 2.1.0, reported by AND patch and unit test submitted by robyschek, well done! - Removed use of functools.partial in replaceWith, as this creates an ambiguous signature for the generated parse action, which fails in PyPy. Reported by Evan Hubinger, thanks Evan! - Added default behavior to QuotedString to convert embedded '\t', '\n', etc. characters to their whitespace counterparts. Found during Q&A exchange on SO with Maxim. Version 2.1.0 - February, 2016 ------------------------------ - Modified the internal _trim_arity method to distinguish between TypeError's raised while trying to determine parse action arity and those raised within the parse action itself. This will clear up those confusing "() takes exactly 1 argument (0 given)" error messages when there is an actual TypeError in the body of the parse action. Thanks to all who have raised this issue in the past, and most recently to Michael Cohen, who sent in a proposed patch, and got me to finally tackle this problem. - Added compatibility for pickle protocols 2-4 when pickling ParseResults. In Python 2.x, protocol 0 was the default, and protocol 2 did not work. In Python 3.x, protocol 3 is the default, so explicitly naming protocol 0 or 1 was required to pickle ParseResults. With this release, all protocols 0-4 are supported. Thanks for reporting this on StackOverflow, Arne Wolframm, and for providing a nice simple test case! - Added optional 'stopOn' argument to ZeroOrMore and OneOrMore, to simplify breaking on stop tokens that would match the repetition expression. It is a common problem to fail to look ahead when matching repetitive tokens if the sentinel at the end also matches the repetition expression, as when parsing "BEGIN aaa bbb ccc END" with: "BEGIN" + OneOrMore(Word(alphas)) + "END" Since "END" matches the repetition expression "Word(alphas)", it will never get parsed as the terminating sentinel. Up until now, this has to be resolved by the user inserting their own negative lookahead: "BEGIN" + OneOrMore(~Literal("END") + Word(alphas)) + "END" Using stopOn, they can more easily write: "BEGIN" + OneOrMore(Word(alphas), stopOn="END") + "END" The stopOn argument can be a literal string or a pyparsing expression. Inspired by a question by Lamakaha on StackOverflow (and many previous questions with the same negative-lookahead resolution). - Added expression names for many internal and builtin expressions, to reduce name and error message overhead during parsing. - Converted helper lambdas to functions to refactor and add docstring support. - Fixed ParseResults.asDict() to correctly convert nested ParseResults values to dicts. - Cleaned up some examples, fixed typo in fourFn.py identified by aristotle2600 on reddit. - Removed keepOriginalText helper method, which was deprecated ages ago. Superceded by originalTextFor. - Same for the Upcase class, which was long ago deprecated and replaced with the upcaseTokens method. Version 2.0.7 - December, 2015 ------------------------------ - Simplified string representation of Forward class, to avoid memory and performance errors while building ParseException messages. Thanks, Will McGugan, Andrea Censi, and Martijn Vermaat for the bug reports and test code. - Cleaned up additional issues from enhancing the error messages for Or and MatchFirst, handling Unicode values in expressions. Fixes Unicode encoding issues in Python 2, thanks to Evan Hubinger for the bug report. - Fixed implementation of dir() for ParseResults - was leaving out all the defined methods and just adding the custom results names. - Fixed bug in ignore() that was introduced in pyparsing 1.5.3, that would not accept a string literal as the ignore expression. - Added new example parseTabularData.py to illustrate parsing of data formatted in columns, with detection of empty cells. - Updated a number of examples to more current Python and pyparsing forms. Version 2.0.6 - November, 2015 ------------------------------ - Fixed a bug in Each when multiple Optional elements are present. Thanks for reporting this, whereswalden on SO. - Fixed another bug in Each, when Optional elements have results names or parse actions, reported by Max Rothman - thank you, Max! - Added optional parseAll argument to runTests, whether tests should require the entire input string to be parsed or not (similar to parseAll argument to parseString). Plus a little neaten-up of the output on Python 2 (no stray ()'s). - Modified exception messages from MatchFirst and Or expressions. These were formerly misleading as they would only give the first or longest exception mismatch error message. Now the error message includes all the alternatives that were possible matches. Originally proposed by a pyparsing user, but I've lost the email thread - finally figured out a fairly clean way to do this. - Fixed a bug in Or, when a parse action on an alternative raises an exception, other potentially matching alternatives were not always tried. Reported by TheVeryOmni on the pyparsing wiki, thanks! - Fixed a bug to dump() introduced in 2.0.4, where list values were shown in duplicate. Version 2.0.5 - October, 2015 ----------------------------- - (&$(@#&$(@!!!! Some "print" statements snuck into pyparsing v2.0.4, breaking Python 3 compatibility! Fixed. Reported by jenshn, thanks! Version 2.0.4 - October, 2015 ----------------------------- - Added ParserElement.addCondition, to simplify adding parse actions that act primarily as filters. If the given condition evaluates False, pyparsing will raise a ParseException. The condition should be a method with the same method signature as a parse action, but should return a boolean. Suggested by Victor Porton, nice idea Victor, thanks! - Slight mod to srange to accept unicode literals for the input string, such as "[а-яА-Я]" instead of "[\u0430-\u044f\u0410-\u042f]". Thanks to Alexandr Suchkov for the patch! - Enhanced implementation of replaceWith. - Fixed enhanced ParseResults.dump() method when the results consists only of an unnamed array of sub-structure results. Reported by Robin Siebler, thanks for your patience and persistence, Robin! - Fixed bug in fourFn.py example code, where pi and e were defined using CaselessLiteral instead of CaselessKeyword. This was not a problem until adding a new function 'exp', and the leading 'e' of 'exp' was accidentally parsed as the mathematical constant 'e'. Nice catch, Tom Grydeland - thanks! - Adopt new-fangled Python features, like decorators and ternary expressions, per suggestions from Williamzjc - thanks William! (Oh yeah, I'm not supporting Python 2.3 with this code any more...) Plus, some additional code fixes/cleanup - thanks again! - Added ParserElement.runTests, a little test bench for quickly running an expression against a list of sample input strings. Basically, I got tired of writing the same test code over and over, and finally added it as a test point method on ParserElement. - Added withClass helper method, a simplified version of withAttribute for the common but annoying case when defining a filter on a div's class - made difficult because 'class' is a Python reserved word. Version 2.0.3 - October, 2014 ----------------------------- - Fixed escaping behavior in QuotedString. Formerly, only quotation marks (or characters designated as quotation marks in the QuotedString constructor) would be escaped. Now all escaped characters will be escaped, and the escaping backslashes will be removed. - Fixed regression in ParseResults.pop() - pop() was pretty much broken after I added *improvements* in 2.0.2. Reported by Iain Shelvington, thanks Iain! - Fixed bug in And class when initializing using a generator. - Enhanced ParseResults.dump() method to list out nested ParseResults that are unnamed arrays of sub-structures. - Fixed UnboundLocalError under Python 3.4 in oneOf method, reported on Sourceforge by aldanor, thanks! - Fixed bug in ParseResults __init__ method, when returning non-ParseResults types from parse actions that implement __eq__. Raised during discussion on the pyparsing wiki with cyrfer. Version 2.0.2 - April, 2014 --------------------------- - Extended "expr(name)" shortcut (same as "expr.setResultsName(name)") to accept "expr()" as a shortcut for "expr.copy()". - Added "locatedExpr(expr)" helper, to decorate any returned tokens with their location within the input string. Adds the results names locn_start and locn_end to the output parse results. - Added "pprint()" method to ParseResults, to simplify troubleshooting and prettified output. Now instead of importing the pprint module and then writing "pprint.pprint(result)", you can just write "result.pprint()". This method also accepts additional positional and keyword arguments (such as indent, width, etc.), which get passed through directly to the pprint method (see https://docs.python.org/2/library/pprint.html#pprint.pprint). - Removed deprecation warnings when using '<<' for Forward expression assignment. '<<=' is still preferred, but '<<' will be retained for cases where '<<=' operator is not suitable (such as in defining lambda expressions). - Expanded argument compatibility for classes and functions that take list arguments, to now accept generators as well. - Extended list-like behavior of ParseResults, adding support for append and extend. NOTE: if you have existing applications using these names as results names, you will have to access them using dict-style syntax: res["append"] and res["extend"] - ParseResults emulates the change in list vs. iterator semantics for methods like keys(), values(), and items(). Under Python 2.x, these methods will return lists, under Python 3.x, these methods will return iterators. - ParseResults now has a method haskeys() which returns True or False depending on whether any results names have been defined. This simplifies testing for the existence of results names under Python 3.x, which returns keys() as an iterator, not a list. - ParseResults now supports both list and dict semantics for pop(). If passed no argument or an integer argument, it will use list semantics and pop tokens from the list of parsed tokens. If passed a non-integer argument (most likely a string), it will use dict semantics and pop the corresponding value from any defined results names. A second default return value argument is supported, just as in dict.pop(). - Fixed bug in markInputline, thanks for reporting this, Matt Grant! - Cleaned up my unit test environment, now runs with Python 2.6 and 3.3. Version 2.0.1 - July, 2013 -------------------------- - Removed use of "nonlocal" that prevented using this version of pyparsing with Python 2.6 and 2.7. This will make it easier to install for packages that depend on pyparsing, under Python versions 2.6 and later. Those using older versions of Python will have to manually install pyparsing 1.5.7. - Fixed implementation of <<= operator to return self; reported by Luc J. Bourhis, with patch fix by Mathias Mamsch - thanks, Luc and Mathias! Version 2.0.0 - November, 2012 ------------------------------ - Rather than release another combined Python 2.x/3.x release I've decided to start a new major version that is only compatible with Python 3.x (and consequently Python 2.7 as well due to backporting of key features). This version will be the main development path from now on, with little follow-on development on the 1.5.x path. - Operator '<<' is now deprecated, in favor of operator '<<=' for attaching parsing expressions to Forward() expressions. This is being done to address precedence of operations problems with '<<'. Operator '<<' will be removed in a future version of pyparsing. Version 1.5.7 - November, 2012 ----------------------------- - NOTE: This is the last release of pyparsing that will try to maintain compatibility with Python versions < 2.6. The next release of pyparsing will be version 2.0.0, using new Python syntax that will not be compatible for Python version 2.5 or older. - An awesome new example is included in this release, submitted by Luca DellOlio, for parsing ANTLR grammar definitions, nice work Luca! - Fixed implementation of ParseResults.__str__ to use Pythonic ''.join() instead of repeated string concatenation. This purportedly has been a performance issue under PyPy. - Fixed bug in ParseResults.__dir__ under Python 3, reported by Thomas Kluyver, thank you Thomas! - Added ParserElement.inlineLiteralsUsing static method, to override pyparsing's default behavior of converting string literals to Literal instances, to use other classes (such as Suppress or CaselessLiteral). - Added new operator '<<=', which will eventually replace '<<' for storing the contents of a Forward(). '<<=' does not have the same operator precedence problems that '<<' does. - 'operatorPrecedence' is being renamed 'infixNotation' as a better description of what this helper function creates. 'operatorPrecedence' is deprecated, and will be dropped entirely in a future release. - Added optional arguments lpar and rpar to operatorPrecedence, so that expressions that use it can override the default suppression of the grouping characters. - Added support for using single argument builtin functions as parse actions. Now you can write 'expr.setParseAction(len)' and get back the length of the list of matched tokens. Supported builtins are: sum, len, sorted, reversed, list, tuple, set, any, all, min, and max. A script demonstrating this feature is included in the examples directory. - Improved linking in generated docs, proposed on the pyparsing wiki by techtonik, thanks! - Fixed a bug in the definition of 'alphas', which was based on the string.uppercase and string.lowercase "constants", which in fact *aren't* constant, but vary with locale settings. This could make parsers locale-sensitive in a subtle way. Thanks to Kef Schecter for his diligence in following through on reporting and monitoring this bugfix! - Fixed a bug in the Py3 version of pyparsing, during exception handling with packrat parsing enabled, reported by Catherine Devlin - thanks Catherine! - Fixed typo in ParseBaseException.__dir__, reported anonymously on the SourceForge bug tracker, thank you Pyparsing User With No Name. - Fixed bug in srange when using '\x###' hex character codes. - Added optional 'intExpr' argument to countedArray, so that you can define your own expression that will evaluate to an integer, to be used as the count for the following elements. Allows you to define a countedArray with the count given in hex, for example, by defining intExpr as "Word(hexnums).setParseAction(int(t[0],16))". Version 1.5.6 - June, 2011 ---------------------------- - Cleanup of parse action normalizing code, to be more version-tolerant, and robust in the face of future Python versions - much thanks to Raymond Hettinger for this rewrite! - Removal of exception cacheing, addressing a memory leak condition in Python 3. Thanks to Michael Droettboom and the Cape Town PUG for their analysis and work on this problem! - Fixed bug when using packrat parsing, where a previously parsed expression would duplicate subsequent tokens - reported by Frankie Ribery on stackoverflow, thanks! - Added 'ungroup' helper method, to address token grouping done implicitly by And expressions, even if only one expression in the And actually returns any text - also inspired by stackoverflow discussion with Frankie Ribery! - Fixed bug in srange, which accepted escaped hex characters of the form '\0x##', but should be '\x##'. Both forms will be supported for backwards compatibility. - Enhancement to countedArray, accepting an optional expression to be used for matching the leading integer count - proposed by Mathias on the pyparsing mailing list, good idea! - Added the Verilog parser to the provided set of examples, under the MIT license. While this frees up this parser for any use, if you find yourself using it in a commercial purpose, please consider making a charitable donation as described in the parser's header. - Added the excludeChars argument to the Word class, to simplify defining a word composed of all characters in a large range except for one or two. Suggested by JesterEE on the pyparsing wiki. - Added optional overlap parameter to scanString, to return overlapping matches found in the source text. - Updated oneOf internal regular expression generation, with improved parse time performance. - Slight performance improvement in transformString, removing empty strings from the list of string fragments built while scanning the source text, before calling ''.join. Especially useful when using transformString to strip out selected text. - Enhanced form of using the "expr('name')" style of results naming, in lieu of calling setResultsName. If name ends with an '*', then this is equivalent to expr.setResultsName('name',listAllMatches=True). - Fixed up internal list flattener to use iteration instead of recursion, to avoid stack overflow when transforming large files. - Added other new examples: . protobuf parser - parses Google's protobuf language . btpyparse - a BibTex parser contributed by Matthew Brett, with test suite test_bibparse.py (thanks, Matthew!) . groupUsingListAllMatches.py - demo using trailing '*' for results names Version 1.5.5 - August, 2010 ---------------------------- - Typo in Python3 version of pyparsing, "builtin" should be "builtins". (sigh) Version 1.5.4 - August, 2010 ---------------------------- - Fixed __builtins__ and file references in Python 3 code, thanks to Greg Watson, saulspatz, sminos, and Mark Summerfield for reporting their Python 3 experiences. - Added new example, apicheck.py, as a sample of scanning a Tcl-like language for functions with incorrect number of arguments (difficult to track down in Tcl languages). This example uses some interesting methods for capturing exceptions while scanning through source code. - Added new example deltaTime.py, that takes everyday time references like "an hour from now", "2 days ago", "next Sunday at 2pm". Version 1.5.3 - June, 2010 -------------------------- - ======= NOTE: API CHANGE!!!!!!! =============== With this release, and henceforward, the pyparsing module is imported as "pyparsing" on both Python 2.x and Python 3.x versions. - Fixed up setup.py to auto-detect Python version and install the correct version of pyparsing - suggested by Alex Martelli, thanks, Alex! (and my apologies to all those who struggled with those spurious installation errors caused by my earlier fumblings!) - Fixed bug on Python3 when using parseFile, getting bytes instead of a str from the input file. - Fixed subtle bug in originalTextFor, if followed by significant whitespace (like a newline) - discovered by Francis Vidal, thanks! - Fixed very sneaky bug in Each, in which Optional elements were not completely recognized as optional - found by Tal Weiss, thanks for your patience. - Fixed off-by-1 bug in line() method when the first line of the input text was an empty line. Thanks to John Krukoff for submitting a patch! - Fixed bug in transformString if grammar contains Group expressions, thanks to patch submitted by barnabas79, nice work! - Fixed bug in originalTextFor in which trailing comments or otherwised ignored text got slurped in with the matched expression. Thanks to michael_ramirez44 on the pyparsing wiki for reporting this just in time to get into this release! - Added better support for summing ParseResults, see the new example, parseResultsSumExample.py. - Added support for composing a `Regex` using a compiled RE object; thanks to my new colleague, Mike Thornton! - In version 1.5.2, I changed the way exceptions are raised in order to simplify the stacktraces reported during parsing. An anonymous user posted a bug report on SF that this behavior makes it difficult to debug some complex parsers, or parsers nested within parsers. In this release I've added a class attribute ParserElement.verbose_stacktrace, with a default value of False. If you set this to True, pyparsing will report stacktraces using the pre-1.5.2 behavior. - New examples: . pymicko.py, a MicroC compiler submitted by Zarko Zivanov. (Note: this example is separately licensed under the GPLv3, and requires Python 2.6 or higher.) Thank you, Zarko! . oc.py, a subset C parser, using the BNF from the 1996 Obfuscated C Contest. . stateMachine2.py, a modified version of stateMachine.py submitted by Matt Anderson, that is compatible with Python versions 2.7 and above - thanks so much, Matt! . select_parser.py, a parser for reading SQLite SELECT statements, as specified at https://www.sqlite.org/lang_select.html this goes into much more detail than the simple SQL parser included in pyparsing's source code . excelExpr.py, a *simplistic* first-cut at a parser for Excel expressions, which I originally posted on comp.lang.python in January, 2010; beware, this parser omits many common Excel cases (addition of numbers represented as strings, references to named ranges) . cpp_enum_parser.py, a nice little parser posted my Mark Tolonen on comp.lang.python in August, 2009 (redistributed here with Mark's permission). Thanks a bunch, Mark! . partial_gene_match.py, a sample I posted to Stackoverflow.com, implementing a special variation on Literal that does "close" matching, up to a given number of allowed mismatches. The application was to find matching gene sequences, with allowance for one or two mismatches. . tagCapture.py, a sample showing how to use a Forward placeholder to enforce matching of text parsed in a previous expression. . matchPreviousDemo.py, simple demo showing how the matchPreviousLiteral helper method is used to match a previously parsed token. Version 1.5.2 - April, 2009 ------------------------------ - Added pyparsing_py3.py module, so that Python 3 users can use pyparsing by changing their pyparsing import statement to: import pyparsing_py3 Thanks for help from Patrick Laban and his friend Geremy Condra on the pyparsing wiki. - Removed __slots__ declaration on ParseBaseException, for compatibility with IronPython 2.0.1. Raised by David Lawler on the pyparsing wiki, thanks David! - Fixed bug in SkipTo/failOn handling - caught by eagle eye cpennington on the pyparsing wiki! - Fixed second bug in SkipTo when using the ignore constructor argument, reported by Catherine Devlin, thanks! - Fixed obscure bug reported by Eike Welk when using a class as a ParseAction with an errant __getitem__ method. - Simplified exception stack traces when reporting parse exceptions back to caller of parseString or parseFile - thanks to a tip from Peter Otten on comp.lang.python. - Changed behavior of scanString to avoid infinitely looping on expressions that match zero-length strings. Prompted by a question posted by ellisonbg on the wiki. - Enhanced classes that take a list of expressions (And, Or, MatchFirst, and Each) to accept generator expressions also. This can be useful when generating lists of alternative expressions, as in this case, where the user wanted to match any repetitions of '+', '*', '#', or '.', but not mixtures of them (that is, match '+++', but not '+-+'): codes = "+*#." format = MatchFirst(Word(c) for c in codes) Based on a problem posed by Denis Spir on the Python tutor list. - Added new example eval_arith.py, which extends the example simpleArith.py to actually evaluate the parsed expressions. Version 1.5.1 - October, 2008 ------------------------------- - Added new helper method originalTextFor, to replace the use of the current keepOriginalText parse action. Now instead of using the parse action, as in: fullName = Word(alphas) + Word(alphas) fullName.setParseAction(keepOriginalText) (in this example, we used keepOriginalText to restore any white space that may have been skipped between the first and last names) You can now write: fullName = originalTextFor(Word(alphas) + Word(alphas)) The implementation of originalTextFor is simpler and faster than keepOriginalText, and does not depend on using the inspect or imp modules. - Added optional parseAll argument to parseFile, to be consistent with parseAll argument to parseString. Posted by pboucher on the pyparsing wiki, thanks! - Added failOn argument to SkipTo, so that grammars can define literal strings or pyparsing expressions which, if found in the skipped text, will cause SkipTo to fail. Useful to prevent SkipTo from reading past terminating expression. Instigated by question posed by Aki Niimura on the pyparsing wiki. - Fixed bug in nestedExpr if multi-character expressions are given for nesting delimiters. Patch provided by new pyparsing user, Hans-Martin Gaudecker - thanks, H-M! - Removed dependency on xml.sax.saxutils.escape, and included internal implementation instead - proposed by Mike Droettboom on the pyparsing mailing list, thanks Mike! Also fixed erroneous mapping in replaceHTMLEntity of " to ', now correctly maps to ". (Also added support for mapping ' to '.) - Fixed typo in ParseResults.insert, found by Alejandro Dubrovsky, good catch! - Added __dir__() methods to ParseBaseException and ParseResults, to support new dir() behavior in Py2.6 and Py3.0. If dir() is called on a ParseResults object, the returned list will include the base set of attribute names, plus any results names that are defined. - Fixed bug in ParseResults.asXML(), in which the first named item within a ParseResults gets reported with an tag instead of with the correct results name. - Fixed bug in '-' error stop, when '-' operator is used inside a Combine expression. - Reverted generator expression to use list comprehension, for better compatibility with old versions of Python. Reported by jester/artixdesign on the SourceForge pyparsing discussion list. - Fixed bug in parseString(parseAll=True), when the input string ends with a comment or whitespace. - Fixed bug in LineStart and LineEnd that did not recognize any special whitespace chars defined using ParserElement.setDefault- WhitespaceChars, found while debugging an issue for Marek Kubica, thanks for the new test case, Marek! - Made Forward class more tolerant of subclassing. Version 1.5.0 - June, 2008 -------------------------- This version of pyparsing includes work on two long-standing FAQ's: support for forcing parsing of the complete input string (without having to explicitly append StringEnd() to the grammar), and a method to improve the mechanism of detecting where syntax errors occur in an input string with various optional and alternative paths. This release also includes a helper method to simplify definition of indentation-based grammars. With these changes (and the past few minor updates), I thought it was finally time to bump the minor rev number on pyparsing - so 1.5.0 is now available! Read on... - AT LAST!!! You can now call parseString and have it raise an exception if the expression does not parse the entire input string. This has been an FAQ for a LONG time. The parseString method now includes an optional parseAll argument (default=False). If parseAll is set to True, then the given parse expression must parse the entire input string. (This is equivalent to adding StringEnd() to the end of the expression.) The default value is False to retain backward compatibility. Inspired by MANY requests over the years, most recently by ecir-hana on the pyparsing wiki! - Added new operator '-' for composing grammar sequences. '-' behaves just like '+' in creating And expressions, but '-' is used to mark grammar structures that should stop parsing immediately and report a syntax error, rather than just backtracking to the last successful parse and trying another alternative. For instance, running the following code: port_definition = Keyword("port") + '=' + Word(nums) entity_definition = Keyword("entity") + "{" + Optional(port_definition) + "}" entity_definition.parseString("entity { port 100 }") pyparsing fails to detect the missing '=' in the port definition. But, since this expression is optional, pyparsing then proceeds to try to match the closing '}' of the entity_definition. Not finding it, pyparsing reports that there was no '}' after the '{' character. Instead, we would like pyparsing to parse the 'port' keyword, and if not followed by an equals sign and an integer, to signal this as a syntax error. This can now be done simply by changing the port_definition to: port_definition = Keyword("port") - '=' + Word(nums) Now after successfully parsing 'port', pyparsing must also find an equals sign and an integer, or it will raise a fatal syntax exception. By judicious insertion of '-' operators, a pyparsing developer can have their grammar report much more informative syntax error messages. Patches and suggestions proposed by several contributors on the pyparsing mailing list and wiki - special thanks to Eike Welk and Thomas/Poldy on the pyparsing wiki! - Added indentedBlock helper method, to encapsulate the parse actions and indentation stack management needed to keep track of indentation levels. Use indentedBlock to define grammars for indentation-based grouping grammars, like Python's. indentedBlock takes up to 3 parameters: - blockStatementExpr - expression defining syntax of statement that is repeated within the indented block - indentStack - list created by caller to manage indentation stack (multiple indentedBlock expressions within a single grammar should share a common indentStack) - indent - boolean indicating whether block must be indented beyond the current level; set to False for block of left-most statements (default=True) A valid block must contain at least one indented statement. - Fixed bug in nestedExpr in which ignored expressions needed to be set off with whitespace. Reported by Stefaan Himpe, nice catch! - Expanded multiplication of an expression by a tuple, to accept tuple values of None: . expr*(n,None) or expr*(n,) is equivalent to expr*n + ZeroOrMore(expr) (read as "at least n instances of expr") . expr*(None,n) is equivalent to expr*(0,n) (read as "0 to n instances of expr") . expr*(None,None) is equivalent to ZeroOrMore(expr) . expr*(1,None) is equivalent to OneOrMore(expr) Note that expr*(None,n) does not raise an exception if more than n exprs exist in the input stream; that is, expr*(None,n) does not enforce a maximum number of expr occurrences. If this behavior is desired, then write expr*(None,n) + ~expr - Added None as a possible operator for operatorPrecedence. None signifies "no operator", as in multiplying m times x in "y=mx+b". - Fixed bug in Each, reported by Michael Ramirez, in which the order of terms in the Each affected the parsing of the results. Problem was due to premature grouping of the expressions in the overall Each during grammar construction, before the complete Each was defined. Thanks, Michael! - Also fixed bug in Each in which Optional's with default values were not getting the defaults added to the results of the overall Each expression. - Fixed a bug in Optional in which results names were not assigned if a default value was supplied. - Cleaned up Py3K compatibility statements, including exception construction statements, and better equivalence between _ustr and basestring, and __nonzero__ and __bool__. Version 1.4.11 - February, 2008 ------------------------------- - With help from Robert A. Clark, this version of pyparsing is compatible with Python 3.0a3. Thanks for the help, Robert! - Added WordStart and WordEnd positional classes, to support expressions that must occur at the start or end of a word. Proposed by piranha on the pyparsing wiki, good idea! - Added matchOnlyAtCol helper parser action, to simplify parsing log or data files that have optional fields that are column dependent. Inspired by a discussion thread with hubritic on comp.lang.python. - Added withAttribute.ANY_VALUE as a match-all value when using withAttribute. Used to ensure that an attribute is present, without having to match on the actual attribute value. - Added get() method to ParseResults, similar to dict.get(). Suggested by new pyparsing user, Alejandro Dubrovksy, thanks! - Added '==' short-cut to see if a given string matches a pyparsing expression. For instance, you can now write: integer = Word(nums) if "123" == integer: # do something print [ x for x in "123 234 asld".split() if x==integer ] # prints ['123', '234'] - Simplified the use of nestedExpr when using an expression for the opening or closing delimiters. Now the content expression will not have to explicitly negate closing delimiters. Found while working with dfinnie on GHOP Task #277, thanks! - Fixed bug when defining ignorable expressions that are later enclosed in a wrapper expression (such as ZeroOrMore, OneOrMore, etc.) - found while working with Prabhu Gurumurthy, thanks Prahbu! - Fixed bug in withAttribute in which keys were automatically converted to lowercase, making it impossible to match XML attributes with uppercase characters in them. Using with- Attribute requires that you reference attributes in all lowercase if parsing HTML, and in correct case when parsing XML. - Changed '<<' operator on Forward to return None, since this is really used as a pseudo-assignment operator, not as a left-shift operator. By returning None, it is easier to catch faulty statements such as a << b | c, where precedence of operations causes the '|' operation to be performed *after* inserting b into a, so no alternation is actually implemented. The correct form is a << (b | c). With this change, an error will be reported instead of silently clipping the alternative term. (Note: this may break some existing code, but if it does, the code had a silent bug in it anyway.) Proposed by wcbarksdale on the pyparsing wiki, thanks! - Several unit tests were added to pyparsing's regression suite, courtesy of the Google Highly-Open Participation Contest. Thanks to all who administered and took part in this event! Version 1.4.10 - December 9, 2007 --------------------------------- - Fixed bug introduced in v1.4.8, parse actions were called for intermediate operator levels, not just the deepest matching operation level. Again, big thanks to Torsten Marek for helping isolate this problem! Version 1.4.9 - December 8, 2007 -------------------------------- - Added '*' multiplication operator support when creating grammars, accepting either an integer, or a two-integer tuple multiplier, as in: ipAddress = Word(nums) + ('.'+Word(nums))*3 usPhoneNumber = Word(nums) + ('-'+Word(nums))*(1,2) If multiplying by a tuple, the two integer values represent min and max multiples. Suggested by Vincent of eToy.com, great idea, Vincent! - Fixed bug in nestedExpr, original version was overly greedy! Thanks to Michael Ramirez for raising this issue. - Fixed internal bug in ParseResults - when an item was deleted, the key indices were not updated. Thanks to Tim Mitchell for posting a bugfix patch to the SF bug tracking system! - Fixed internal bug in operatorPrecedence - when the results of a right-associative term were sent to a parse action, the wrong tokens were sent. Reported by Torsten Marek, nice job! - Added pop() method to ParseResults. If pop is called with an integer or with no arguments, it will use list semantics and update the ParseResults' list of tokens. If pop is called with a non-integer (a string, for instance), then it will use dict semantics and update the ParseResults' internal dict. Suggested by Donn Ingle, thanks Donn! - Fixed quoted string built-ins to accept '\xHH' hex characters within the string. Version 1.4.8 - October, 2007 ----------------------------- - Added new helper method nestedExpr to easily create expressions that parse lists of data in nested parentheses, braces, brackets, etc. - Added withAttribute parse action helper, to simplify creating filtering parse actions to attach to expressions returned by makeHTMLTags and makeXMLTags. Use withAttribute to qualify a starting tag with one or more required attribute values, to avoid false matches on common tags such as or
. - Added new examples nested.py and withAttribute.py to demonstrate the new features. - Added performance speedup to grammars using operatorPrecedence, instigated by Stefan Reichör - thanks for the feedback, Stefan! - Fixed bug/typo when deleting an element from a ParseResults by using the element's results name. - Fixed whitespace-skipping bug in wrapper classes (such as Group, Suppress, Combine, etc.) and when using setDebug(), reported by new pyparsing user dazzawazza on SourceForge, nice job! - Added restriction to prevent defining Word or CharsNotIn expressions with minimum length of 0 (should use Optional if this is desired), and enhanced docstrings to reflect this limitation. Issue was raised by Joey Tallieu, who submitted a patch with a slightly different solution. Thanks for taking the initiative, Joey, and please keep submitting your ideas! - Fixed bug in makeHTMLTags that did not detect HTML tag attributes with no '= value' portion (such as ""), reported by hamidh on the pyparsing wiki - thanks! - Fixed minor bug in makeHTMLTags and makeXMLTags, which did not accept whitespace in closing tags. Version 1.4.7 - July, 2007 -------------------------- - NEW NOTATION SHORTCUT: ParserElement now accepts results names using a notational shortcut, following the expression with the results name in parentheses. So this: stats = "AVE:" + realNum.setResultsName("average") + \ "MIN:" + realNum.setResultsName("min") + \ "MAX:" + realNum.setResultsName("max") can now be written as this: stats = "AVE:" + realNum("average") + \ "MIN:" + realNum("min") + \ "MAX:" + realNum("max") The intent behind this change is to make it simpler to define results names for significant fields within the expression, while keeping the grammar syntax clean and uncluttered. - Fixed bug when packrat parsing is enabled, with cached ParseResults being updated by subsequent parsing. Reported on the pyparsing wiki by Kambiz, thanks! - Fixed bug in operatorPrecedence for unary operators with left associativity, if multiple operators were given for the same term. - Fixed bug in example simpleBool.py, corrected precedence of "and" vs. "or" operations. - Fixed bug in Dict class, in which keys were converted to strings whether they needed to be or not. Have narrowed this logic to convert keys to strings only if the keys are ints (which would confuse __getitem__ behavior for list indexing vs. key lookup). - Added ParserElement method setBreak(), which will invoke the pdb module's set_trace() function when this expression is about to be parsed. - Fixed bug in StringEnd in which reading off the end of the input string raises an exception - should match. Resolved while answering a question for Shawn on the pyparsing wiki. Version 1.4.6 - April, 2007 --------------------------- - Simplified constructor for ParseFatalException, to support common exception construction idiom: raise ParseFatalException, "unexpected text: 'Spanish Inquisition'" - Added method getTokensEndLoc(), to be called from within a parse action, for those parse actions that need both the starting *and* ending location of the parsed tokens within the input text. - Enhanced behavior of keepOriginalText so that named parse fields are preserved, even though tokens are replaced with the original input text matched by the current expression. Also, cleaned up the stack traversal to be more robust. Suggested by Tim Arnold - thanks, Tim! - Fixed subtle bug in which countedArray (and similar dynamic expressions configured in parse actions) failed to match within Or, Each, FollowedBy, or NotAny. Reported by Ralf Vosseler, thanks for your patience, Ralf! - Fixed Unicode bug in upcaseTokens and downcaseTokens parse actions, scanString, and default debugging actions; reported (and patch submitted) by Nikolai Zamkovoi, spasibo! - Fixed bug when saving a tuple as a named result. The returned token list gave the proper tuple value, but accessing the result by name only gave the first element of the tuple. Reported by Poromenos, nice catch! - Fixed bug in makeHTMLTags/makeXMLTags, which failed to match tag attributes with namespaces. - Fixed bug in SkipTo when setting include=True, to have the skipped-to tokens correctly included in the returned data. Reported by gunars on the pyparsing wiki, thanks! - Fixed typobug in OnceOnly.reset method, omitted self argument. Submitted by eike welk, thanks for the lint-picking! - Added performance enhancement to Forward class, suggested by akkartik on the pyparsing Wiki discussion, nice work! - Added optional asKeyword to Word constructor, to indicate that the given word pattern should be matched only as a keyword, that is, it should only match if it is within word boundaries. - Added S-expression parser to examples directory. - Added macro substitution example to examples directory. - Added holaMundo.py example, excerpted from Marco Alfonso's blog - muchas gracias, Marco! - Modified internal cyclic references in ParseResults to use weakrefs; this should help reduce the memory footprint of large parsing programs, at some cost to performance (3-5%). Suggested by bca48150 on the pyparsing wiki, thanks! - Enhanced the documentation describing the vagaries and idiosyncrasies of parsing strings with embedded tabs, and the impact on: . parse actions . scanString . col and line helper functions (Suggested by eike welk in response to some unexplained inconsistencies between parsed location and offsets in the input string.) - Cleaned up internal decorators to preserve function names, docstrings, etc. Version 1.4.5 - December, 2006 ------------------------------ - Removed debugging print statement from QuotedString class. Sorry for not stripping this out before the 1.4.4 release! - A significant performance improvement, the first one in a while! For my Verilog parser, this version of pyparsing is about double the speed - YMMV. - Added support for pickling of ParseResults objects. (Reported by Jeff Poole, thanks Jeff!) - Fixed minor bug in makeHTMLTags that did not recognize tag attributes with embedded '-' or '_' characters. Also, added support for passing expressions to makeHTMLTags and makeXMLTags, and used this feature to define the globals anyOpenTag and anyCloseTag. - Fixed error in alphas8bit, I had omitted the y-with-umlaut character. - Added punc8bit string to complement alphas8bit - it contains all the non-alphabetic, non-blank 8-bit characters. - Added commonHTMLEntity expression, to match common HTML "ampersand" codes, such as "<", ">", "&", " ", and """. This expression also defines a results name 'entity', which can be used to extract the entity field (that is, "lt", "gt", etc.). Also added built-in parse action replaceHTMLEntity, which can be attached to commonHTMLEntity to translate "<", ">", "&", " ", and """ to "<", ">", "&", " ", and "'". - Added example, htmlStripper.py, that strips HTML tags and scripts from HTML pages. It also translates common HTML entities to their respective characters. Version 1.4.4 - October, 2006 ------------------------------- - Fixed traceParseAction decorator to also trap and record exception returns from parse actions, and to handle parse actions with 0, 1, 2, or 3 arguments. - Enhanced parse action normalization to support using classes as parse actions; that is, the class constructor is called at parse time and the __init__ function is called with 0, 1, 2, or 3 arguments. If passing a class as a parse action, the __init__ method must use one of the valid parse action parameter list formats. (This technique is useful when using pyparsing to compile parsed text into a series of application objects - see the new example simpleBool.py.) - Fixed bug in ParseResults when setting an item using an integer index. (Reported by Christopher Lambacher, thanks!) - Fixed whitespace-skipping bug, patch submitted by Paolo Losi - grazie, Paolo! - Fixed bug when a Combine contained an embedded Forward expression, reported by cie on the pyparsing wiki - good catch! - Fixed listAllMatches bug, when a listAllMatches result was nested within another result. (Reported by don pasquale on comp.lang.python, well done!) - Fixed bug in ParseResults items() method, when returning an item marked as listAllMatches=True - Fixed bug in definition of cppStyleComment (and javaStyleComment) in which '//' line comments were not continued to the next line if the line ends with a '\'. (Reported by eagle-eyed Ralph Corderoy!) - Optimized re's for cppStyleComment and quotedString for better re performance - also provided by Ralph Corderoy, thanks! - Added new example, indentedGrammarExample.py, showing how to define a grammar using indentation to show grouping (as Python does for defining statement nesting). Instigated by an e-mail discussion with Andrew Dalke, thanks Andrew! - Added new helper operatorPrecedence (based on e-mail list discussion with Ralph Corderoy and Paolo Losi), to facilitate definition of grammars for expressions with unary and binary operators. For instance, this grammar defines a 6-function arithmetic expression grammar, with unary plus and minus, proper operator precedence,and right- and left-associativity: expr = operatorPrecedence( operand, [("!", 1, opAssoc.LEFT), ("^", 2, opAssoc.RIGHT), (oneOf("+ -"), 1, opAssoc.RIGHT), (oneOf("* /"), 2, opAssoc.LEFT), (oneOf("+ -"), 2, opAssoc.LEFT),] ) Also added example simpleArith.py and simpleBool.py to provide more detailed code samples using this new helper method. - Added new helpers matchPreviousLiteral and matchPreviousExpr, for creating adaptive parsing expressions that match the same content as was parsed in a previous parse expression. For instance: first = Word(nums) matchExpr = first + ":" + matchPreviousLiteral(first) will match "1:1", but not "1:2". Since this matches at the literal level, this will also match the leading "1:1" in "1:10". In contrast: first = Word(nums) matchExpr = first + ":" + matchPreviousExpr(first) will *not* match the leading "1:1" in "1:10"; the expressions are evaluated first, and then compared, so "1" is compared with "10". - Added keepOriginalText parse action. Sometimes pyparsing's whitespace-skipping leaves out too much whitespace. Adding this parse action will restore any internal whitespace for a parse expression. This is especially useful when defining expressions for scanString or transformString applications. - Added __add__ method for ParseResults class, to better support using Python sum built-in for summing ParseResults objects returned from scanString. - Added reset method for the new OnlyOnce class wrapper for parse actions (to allow a grammar to be used multiple times). - Added optional maxMatches argument to scanString and searchString, to short-circuit scanning after 'n' expression matches are found. Version 1.4.3 - July, 2006 ------------------------------ - Fixed implementation of multiple parse actions for an expression (added in 1.4.2). . setParseAction() reverts to its previous behavior, setting one (or more) actions for an expression, overwriting any action or actions previously defined . new method addParseAction() appends one or more parse actions to the list of parse actions attached to an expression Now it is harder to accidentally append parse actions to an expression, when what you wanted to do was overwrite whatever had been defined before. (Thanks, Jean-Paul Calderone!) - Simplified interface to parse actions that do not require all 3 parse action arguments. Very rarely do parse actions require more than just the parsed tokens, yet parse actions still require all 3 arguments including the string being parsed and the location within the string where the parse expression was matched. With this release, parse actions may now be defined to be called as: . fn(string,locn,tokens) (the current form) . fn(locn,tokens) . fn(tokens) . fn() The setParseAction and addParseAction methods will internally decorate the provided parse actions with compatible wrappers to conform to the full (string,locn,tokens) argument sequence. - REMOVED SUPPORT FOR RETURNING PARSE LOCATION FROM A PARSE ACTION. I announced this in March, 2004, and gave a final warning in the last release. Now you can return a tuple from a parse action, and it will be treated like any other return value (i.e., the tuple will be substituted for the incoming tokens passed to the parse action, which is useful when trying to parse strings into tuples). - Added setFailAction method, taking a callable function fn that takes the arguments fn(s,loc,expr,err) where: . s - string being parsed . loc - location where expression match was attempted and failed . expr - the parse expression that failed . err - the exception thrown The function returns no values. It may throw ParseFatalException if it is desired to stop parsing immediately. (Suggested by peter21081944 on wikispaces.com) - Added class OnlyOnce as helper wrapper for parse actions. OnlyOnce only permits a parse action to be called one time, after which all subsequent calls throw a ParseException. - Added traceParseAction decorator to help debug parse actions. Simply insert "@traceParseAction" ahead of the definition of your parse action, and each invocation will be displayed, along with incoming arguments, and returned value. - Fixed bug when copying ParserElements using copy() or setResultsName(). (Reported by Dan Thill, great catch!) - Fixed bug in asXML() where token text contains <, >, and & characters - generated XML now escapes these as <, > and &. (Reported by Jacek Sieka, thanks!) - Fixed bug in SkipTo() when searching for a StringEnd(). (Reported by Pete McEvoy, thanks Pete!) - Fixed "except Exception" statements, the most critical added as part of the packrat parsing enhancement. (Thanks, Erick Tryzelaar!) - Fixed end-of-string infinite looping on LineEnd and StringEnd expressions. (Thanks again to Erick Tryzelaar.) - Modified setWhitespaceChars to return self, to be consistent with other ParserElement modifiers. (Suggested by Erick Tryzelaar.) - Fixed bug/typo in new ParseResults.dump() method. - Fixed bug in searchString() method, in which only the first token of an expression was returned. searchString() now returns a ParseResults collection of all search matches. - Added example program removeLineBreaks.py, a string transformer that converts text files with hard line-breaks into one with line breaks only between paragraphs. - Added example program listAllMatches.py, to illustrate using the listAllMatches option when specifying results names (also shows new support for passing lists to oneOf). - Added example program linenoExample.py, to illustrate using the helper methods lineno, line, and col, and returning objects from a parse action. - Added example program parseListString.py, to which can parse the string representation of a Python list back into a true list. Taken mostly from my PyCon presentation examples, but now with support for tuple elements, too! Version 1.4.2 - April 1, 2006 (No foolin'!) ------------------------------------------- - Significant speedup from memoizing nested expressions (a technique known as "packrat parsing"), thanks to Chris Lesniewski-Laas! Your mileage may vary, but my Verilog parser almost doubled in speed to over 600 lines/sec! This speedup may break existing programs that use parse actions that have side-effects. For this reason, packrat parsing is disabled when you first import pyparsing. To activate the packrat feature, your program must call the class method ParserElement.enablePackrat(). If your program uses psyco to "compile as you go", you must call enablePackrat before calling psyco.full(). If you do not do this, Python will crash. For best results, call enablePackrat() immediately after importing pyparsing. - Added new helper method countedArray(expr), for defining patterns that start with a leading integer to indicate the number of array elements, followed by that many elements, matching the given expr parse expression. For instance, this two-liner: wordArray = countedArray(Word(alphas)) print wordArray.parseString("3 Practicality beats purity")[0] returns the parsed array of words: ['Practicality', 'beats', 'purity'] The leading token '3' is suppressed, although it is easily obtained from the length of the returned array. (Inspired by e-mail discussion with Ralf Vosseler.) - Added support for attaching multiple parse actions to a single ParserElement. (Suggested by Dan "Dang" Griffith - nice idea, Dan!) - Added support for asymmetric quoting characters in the recently-added QuotedString class. Now you can define your own quoted string syntax like "<>". To define this custom form of QuotedString, your code would define: dblAngleQuotedString = QuotedString('<<',endQuoteChar='>>') QuotedString also supports escaped quotes, escape character other than '\', and multiline. - Changed the default value returned internally by Optional, so that None can be used as a default value. (Suggested by Steven Bethard - I finally saw the light!) - Added dump() method to ParseResults, to make it easier to list out and diagnose values returned from calling parseString. - A new example, a search query string parser, submitted by Steven Mooij and Rudolph Froger - a very interesting application, thanks! - Added an example that parses the BNF in Python's Grammar file, in support of generating Python grammar documentation. (Suggested by J H Stovall.) - A new example, submitted by Tim Cera, of a flexible parser module, using a simple config variable to adjust parsing for input formats that have slight variations - thanks, Tim! - Added an example for parsing Roman numerals, showing the capability of parse actions to "compile" Roman numerals into their integer values during parsing. - Added a new docs directory, for additional documentation or help. Currently, this includes the text and examples from my recent presentation at PyCon. - Fixed another typo in CaselessKeyword, thanks Stefan Behnel. - Expanded oneOf to also accept tuples, not just lists. This really should be sufficient... - Added deprecation warnings when tuple is returned from a parse action. Looking back, I see that I originally deprecated this feature in March, 2004, so I'm guessing people really shouldn't have been using this feature - I'll drop it altogether in the next release, which will allow users to return a tuple from a parse action (which is really handy when trying to reconstuct tuples from a tuple string representation!). Version 1.4.1 - February, 2006 ------------------------------ - Converted generator expression in QuotedString class to list comprehension, to retain compatibility with Python 2.3. (Thanks, Titus Brown for the heads-up!) - Added searchString() method to ParserElement, as an alternative to using "scanString(instring).next()[0][0]" to search through a string looking for a substring matching a given parse expression. (Inspired by e-mail conversation with Dave Feustel.) - Modified oneOf to accept lists of strings as well as a single string of space-delimited literals. (Suggested by Jacek Sieka - thanks!) - Removed deprecated use of Upcase in pyparsing test code. (Also caught by Titus Brown.) - Removed lstrip() call from Literal - too aggressive in stripping whitespace which may be valid for some grammars. (Point raised by Jacek Sieka). Also, made Literal more robust in the event of passing an empty string. - Fixed bug in replaceWith when returning None. - Added cautionary documentation for Forward class when assigning a MatchFirst expression, as in: fwdExpr << a | b | c Precedence of operators causes this to be evaluated as: (fwdExpr << a) | b | c thereby leaving b and c out as parseable alternatives. Users must explicitly group the values inserted into the Forward: fwdExpr << (a | b | c) (Suggested by Scot Wilcoxon - thanks, Scot!) Version 1.4 - January 18, 2006 ------------------------------ - Added `Regex` class, to permit definition of complex embedded expressions using regular expressions. (Enhancement provided by John Beisley, great job!) - Converted implementations of Word, oneOf, quoted string, and comment helpers to utilize regular expression matching. Performance improvements in the 20-40% range. - Added QuotedString class, to support definition of non-standard quoted strings (Suggested by Guillaume Proulx, thanks!) - Added CaselessKeyword class, to streamline grammars with, well, caseless keywords (Proposed by Stefan Behnel, thanks!) - Fixed bug in SkipTo, when using an ignoreable expression. (Patch provided by Anonymous, thanks, whoever-you-are!) - Fixed typo in NoMatch class. (Good catch, Stefan Behnel!) - Fixed minor bug in _makeTags(), using string.printables instead of pyparsing.printables. - Cleaned up some of the expressions created by makeXXXTags helpers, to suppress extraneous <> characters. - Added some grammar definition-time checking to verify that a grammar is being built using proper ParserElements. - Added examples: . LAparser.py - linear algebra C preprocessor (submitted by Mike Ellis, thanks Mike!) . wordsToNum.py - converts word description of a number back to the original number (such as 'one hundred and twenty three' -> 123) . updated fourFn.py to support unary minus, added BNF comments Version 1.3.3 - September 12, 2005 ---------------------------------- - Improved support for Unicode strings that would be returned using srange. Added greetingInKorean.py example, for a Korean version of "Hello, World!" using Unicode. (Thanks, June Kim!) - Added 'hexnums' string constant (nums+"ABCDEFabcdef") for defining hexadecimal value expressions. - NOTE: ===THIS CHANGE MAY BREAK EXISTING CODE=== Modified tag and results definitions returned by makeHTMLTags(), to better support the looseness of HTML parsing. Tags to be parsed are now caseless, and keys generated for tag attributes are now converted to lower case. Formerly, makeXMLTags("XYZ") would return a tag with results name of "startXYZ", this has been changed to "startXyz". If this tag is matched against '', the matched keys formerly would be "Abc", "DEF", and "ghi"; keys are now converted to lower case, giving keys of "abc", "def", and "ghi". These changes were made to try to address the lax case sensitivity agreement between start and end tags in many HTML pages. No changes were made to makeXMLTags(), which assumes more rigorous parsing rules. Also, cleaned up case-sensitivity bugs in closing tags, and switched to using Keyword instead of Literal class for tags. (Thanks, Steve Young, for getting me to look at these in more detail!) - Added two helper parse actions, upcaseTokens and downcaseTokens, which will convert matched text to all uppercase or lowercase, respectively. - Deprecated Upcase class, to be replaced by upcaseTokens parse action. - Converted messages sent to stderr to use warnings module, such as when constructing a Literal with an empty string, one should use the Empty() class or the empty helper instead. - Added ' ' (space) as an escapable character within a quoted string. - Added helper expressions for common comment types, in addition to the existing cStyleComment (/*...*/) and htmlStyleComment () . dblSlashComment = // ... (to end of line) . cppStyleComment = cStyleComment or dblSlashComment . javaStyleComment = cppStyleComment . pythonStyleComment = # ... (to end of line) Version 1.3.2 - July 24, 2005 ----------------------------- - Added Each class as an enhanced version of And. 'Each' requires that all given expressions be present, but may occur in any order. Special handling is provided to group ZeroOrMore and OneOrMore elements that occur out-of-order in the input string. You can also construct 'Each' objects by joining expressions with the '&' operator. When using the Each class, results names are strongly recommended for accessing the matched tokens. (Suggested by Pradam Amini - thanks, Pradam!) - Stricter interpretation of 'max' qualifier on Word elements. If the 'max' attribute is specified, matching will fail if an input field contains more than 'max' consecutive body characters. For example, previously, Word(nums,max=3) would match the first three characters of '0123456', returning '012' and continuing parsing at '3'. Now, when constructed using the max attribute, Word will raise an exception with this string. - Cleaner handling of nested dictionaries returned by Dict. No longer necessary to dereference sub-dictionaries as element [0] of their parents. === NOTE: THIS CHANGE MAY BREAK SOME EXISTING CODE, BUT ONLY IF PARSING NESTED DICTIONARIES USING THE LITTLE-USED DICT CLASS === (Prompted by discussion thread on the Python Tutor list, with contributions from Danny Yoo, Kent Johnson, and original post by Liam Clarke - thanks all!) Version 1.3.1 - June, 2005 ---------------------------------- - Added markInputline() method to ParseException, to display the input text line location of the parsing exception. (Thanks, Stefan Behnel!) - Added setDefaultKeywordChars(), so that Keyword definitions using a custom keyword character set do not all need to add the keywordChars constructor argument (similar to setDefaultWhitespaceChars()). (suggested by rzhanka on the SourceForge pyparsing forum.) - Simplified passing debug actions to setDebugAction(). You can now pass 'None' for a debug action if you want to take the default debug behavior. To suppress a particular debug action, you can pass the pyparsing method nullDebugAction. - Refactored parse exception classes, moved all behavior to ParseBaseException, and the former ParseException is now a subclass of ParseBaseException. Added a second subclass, ParseFatalException, as a subclass of ParseBaseException. User-defined parse actions can raise ParseFatalException if a data inconsistency is detected (such as a begin-tag/end-tag mismatch), and this will stop all parsing immediately. (Inspired by e-mail thread with Michele Petrazzo - thanks, Michelle!) - Added helper methods makeXMLTags and makeHTMLTags, that simplify the definition of XML or HTML tag parse expressions for a given tagname. Both functions return a pair of parse expressions, one for the opening tag (that is, '') and one for the closing tag (''). The opening tagame also recognizes any attribute definitions that have been included in the opening tag, as well as an empty tag (one with a trailing '/', as in '' which is equivalent to ''). makeXMLTags uses stricter XML syntax for attributes, requiring that they be enclosed in double quote characters - makeHTMLTags is more lenient, and accepts single-quoted strings or any contiguous string of characters up to the next whitespace character or '>' character. Attributes can be retrieved as dictionary or attribute values of the returned results from the opening tag. - Added example minimath2.py, a refinement on fourFn.py that adds an interactive session and support for variables. (Thanks, Steven Siew!) - Added performance improvement, up to 20% reduction! (Found while working with Wolfgang Borgert on performance tuning of his TTCN3 parser.) - And another performance improvement, up to 25%, when using scanString! (Found while working with Henrik Westlund on his C header file scanner.) - Updated UML diagrams to reflect latest class/method changes. Version 1.3 - March, 2005 ---------------------------------- - Added new Keyword class, as a special form of Literal. Keywords must be followed by whitespace or other non-keyword characters, to distinguish them from variables or other identifiers that just happen to start with the same characters as a keyword. For instance, the input string containing "ifOnlyIfOnly" will match a Literal("if") at the beginning and in the middle, but will fail to match a Keyword("if"). Keyword("if") will match only strings such as "if only" or "if(only)". (Proposed by Wolfgang Borgert, and Berteun Damman separately requested this on comp.lang.python - great idea!) - Added setWhitespaceChars() method to override the characters to be skipped as whitespace before matching a particular ParseElement. Also added the class-level method setDefaultWhitespaceChars(), to allow users to override the default set of whitespace characters (space, tab, newline, and return) for all subsequently defined ParseElements. (Inspired by Klaas Hofstra's inquiry on the Sourceforge pyparsing forum.) - Added helper parse actions to support some very common parse action use cases: . replaceWith(replStr) - replaces the matching tokens with the provided replStr replacement string; especially useful with transformString() . removeQuotes - removes first and last character from string enclosed in quotes (note - NOT the same as the string strip() method, as only a single character is removed at each end) - Added copy() method to ParseElement, to make it easier to define different parse actions for the same basic parse expression. (Note, copy is implicitly called when using setResultsName().) (The following changes were posted to CVS as Version 1.2.3 - October-December, 2004) - Added support for Unicode strings in creating grammar definitions. (Big thanks to Gavin Panella!) - Added constant alphas8bit to include the following 8-bit characters: ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ - Added srange() function to simplify definition of Word elements, using regexp-like '[A-Za-z0-9]' syntax. This also simplifies referencing common 8-bit characters. - Fixed bug in Dict when a single element Dict was embedded within another Dict. (Thanks Andy Yates for catching this one!) - Added 'formatted' argument to ParseResults.asXML(). If set to False, suppresses insertion of whitespace for pretty-print formatting. Default equals True for backward compatibility. - Added setDebugActions() function to ParserElement, to allow user-defined debugging actions. - Added support for escaped quotes (either in \', \", or doubled quote form) to the predefined expressions for quoted strings. (Thanks, Ero Carrera!) - Minor performance improvement (~5%) converting "char in string" tests to "char in dict". (Suggested by Gavin Panella, cool idea!) Version 1.2.2 - September 27, 2004 ---------------------------------- - Modified delimitedList to accept an expression as the delimiter, instead of only accepting strings. - Modified ParseResults, to convert integer field keys to strings (to avoid confusion with list access). - Modified Combine, to convert all embedded tokens to strings before combining. - Fixed bug in MatchFirst in which parse actions would be called for expressions that only partially match. (Thanks, John Hunter!) - Fixed bug in fourFn.py example that fixes right-associativity of ^ operator. (Thanks, Andrea Griffini!) - Added class FollowedBy(expression), to look ahead in the input string without consuming tokens. - Added class NoMatch that never matches any input. Can be useful in debugging, and in very specialized grammars. - Added example pgn.py, for parsing chess game files stored in Portable Game Notation. (Thanks, Alberto Santini!) Version 1.2.1 - August 19, 2004 ------------------------------- - Added SkipTo(expression) token type, simplifying grammars that only want to specify delimiting expressions, and want to match any characters between them. - Added helper method dictOf(key,value), making it easier to work with the Dict class. (Inspired by Pavel Volkovitskiy, thanks!). - Added optional argument listAllMatches (default=False) to setResultsName(). Setting listAllMatches to True overrides the default modal setting of tokens to results names; instead, the results name acts as an accumulator for all matching tokens within the local repetition group. (Suggested by Amaury Le Leyzour - thanks!) - Fixed bug in ParseResults, throwing exception when trying to extract slice, or make a copy using [:]. (Thanks, Wilson Fowlie!) - Fixed bug in transformString() when the input string contains 's (Thanks, Rick Walia!). - Fixed bug in returning tokens from un-Grouped And's, Or's and MatchFirst's, where too many tokens would be included in the results, confounding parse actions and returned results. - Fixed bug in naming ParseResults returned by And's, Or's, and Match First's. - Fixed bug in LineEnd() - matching this token now correctly consumes and returns the end of line "\n". - Added a beautiful example for parsing Mozilla calendar files (Thanks, Petri Savolainen!). - Added support for dynamically modifying Forward expressions during parsing. Version 1.2 - 20 June 2004 -------------------------- - Added definition for htmlComment to help support HTML scanning and parsing. - Fixed bug in generating XML for Dict classes, in which trailing item was duplicated in the output XML. - Fixed release bug in which scanExamples.py was omitted from release files. - Fixed bug in transformString() when parse actions are not defined on the outermost parser element. - Added example urlExtractor.py, as another example of using scanString and parse actions. Version 1.2beta3 - 4 June 2004 ------------------------------ - Added White() token type, analogous to Word, to match on whitespace characters. Use White in parsers with significant whitespace (such as configuration file parsers that use indentation to indicate grouping). Construct White with a string containing the whitespace characters to be matched. Similar to Word, White also takes optional min, max, and exact parameters. - As part of supporting whitespace-signficant parsing, added parseWithTabs() method to ParserElement, to override the default behavior in parseString of automatically expanding tabs to spaces. To retain tabs during parsing, call parseWithTabs() before calling parseString(), parseFile() or scanString(). (Thanks, Jean-Guillaume Paradis for catching this, and for your suggestions on whitespace-significant parsing.) - Added transformString() method to ParseElement, as a complement to scanString(). To use transformString, define a grammar and attach a parse action to the overall grammar that modifies the returned token list. Invoking transformString() on a target string will then scan for matches, and replace the matched text patterns according to the logic in the parse action. transformString() returns the resulting transformed string. (Note: transformString() does *not* automatically expand tabs to spaces.) Also added scanExamples.py to the examples directory to show sample uses of scanString() and transformString(). - Removed group() method that was introduced in beta2. This turns out NOT to be equivalent to nesting within a Group() object, and I'd prefer not to sow more seeds of confusion. - Fixed behavior of asXML() where tags for groups were incorrectly duplicated. (Thanks, Brad Clements!) - Changed beta version message to display to stderr instead of stdout, to make asXML() easier to use. (Thanks again, Brad.) Version 1.2beta2 - 19 May 2004 ------------------------------ - *** SIMPLIFIED API *** - Parse actions that do not modify the list of tokens no longer need to return a value. This simplifies those parse actions that use the list of tokens to update a counter or record or display some of the token content; these parse actions can simply end without having to specify 'return toks'. - *** POSSIBLE API INCOMPATIBILITY *** - Fixed CaselessLiteral bug, where the returned token text was not the original string (as stated in the docs), but the original string converted to upper case. (Thanks, Dang Griffith!) **NOTE: this may break some code that relied on this erroneous behavior. Users should scan their code for uses of CaselessLiteral.** - *** POSSIBLE CODE INCOMPATIBILITY *** - I have renamed the internal attributes on ParseResults from 'dict' and 'list' to '__tokdict' and '__toklist', to avoid collisions with user-defined data fields named 'dict' and 'list'. Any client code that accesses these attributes directly will need to be modified. Hopefully the implementation of methods such as keys(), items(), len(), etc. on ParseResults will make such direct attribute accessess unnecessary. - Added asXML() method to ParseResults. This greatly simplifies the process of parsing an input data file and generating XML-structured data. - Added getName() method to ParseResults. This method is helpful when a grammar specifies ZeroOrMore or OneOrMore of a MatchFirst or Or expression, and the parsing code needs to know which expression matched. (Thanks, Eric van der Vlist, for this idea!) - Added items() and values() methods to ParseResults, to better support using ParseResults as a Dictionary. - Added parseFile() as a convenience function to parse the contents of an entire text file. Accepts either a file name or a file object. (Thanks again, Dang!) - Added group() method to And, Or, and MatchFirst, as a short-cut alternative to enclosing a construct inside a Group object. - Extended fourFn.py to support exponentiation, and simple built-in functions. - Added EBNF parser to examples, including a demo where it parses its own EBNF! (Thanks to Seo Sanghyeon!) - Added Delphi Form parser to examples, dfmparse.py, plus a couple of sample Delphi forms as tests. (Well done, Dang!) - Another performance speedup, 5-10%, inspired by Dang! Plus about a 20% speedup, by pre-constructing and cacheing exception objects instead of constructing them on the fly. - Fixed minor bug when specifying oneOf() with 'caseless=True'. - Cleaned up and added a few more docstrings, to improve the generated docs. Version 1.1.2 - 21 Mar 2004 --------------------------- - Fixed minor bug in scanString(), so that start location is at the start of the matched tokens, not at the start of the whitespace before the matched tokens. - Inclusion of HTML documentation, generated using Epydoc. Reformatted some doc strings to better generate readable docs. (Beautiful work, Ed Loper, thanks for Epydoc!) - Minor performance speedup, 5-15% - And on a process note, I've used the unittest module to define a series of unit tests, to help avoid the embarrassment of the version 1.1 snafu. Version 1.1.1 - 6 Mar 2004 -------------------------- - Fixed critical bug introduced in 1.1, which broke MatchFirst(!) token matching. **THANK YOU, SEO SANGHYEON!!!** - Added "from future import __generators__" to permit running under pre-Python 2.3. - Added example getNTPservers.py, showing how to use pyparsing to extract a text pattern from the HTML of a web page. Version 1.1 - 3 Mar 2004 ------------------------- - ***Changed API*** - While testing out parse actions, I found that the value of loc passed in was not the starting location of the matched tokens, but the location of the next token in the list. With this version, the location passed to the parse action is now the starting location of the tokens that matched. A second part of this change is that the return value of parse actions no longer needs to return a tuple containing both the location and the parsed tokens (which may optionally be modified); parse actions only need to return the list of tokens. Parse actions that return a tuple are deprecated; they will still work properly for conversion/compatibility, but this behavior will be removed in a future version. - Added validate() method, to help diagnose infinite recursion in a grammar tree. validate() is not 100% fool-proof, but it can help track down nasty infinite looping due to recursively referencing the same grammar construct without some intervening characters. - Cleaned up default listing of some parse element types, to more closely match ordinary BNF. Instead of the form :[contents-list], some changes are: . And(token1,token2,token3) is "{ token1 token2 token3 }" . Or(token1,token2,token3) is "{ token1 ^ token2 ^ token3 }" . MatchFirst(token1,token2,token3) is "{ token1 | token2 | token3 }" . Optional(token) is "[ token ]" . OneOrMore(token) is "{ token }..." . ZeroOrMore(token) is "[ token ]..." - Fixed an infinite loop in oneOf if the input string contains a duplicated option. (Thanks Brad Clements) - Fixed a bug when specifying a results name on an Optional token. (Thanks again, Brad Clements) - Fixed a bug introduced in 1.0.6 when I converted quotedString to use CharsNotIn; I accidentally permitted quoted strings to span newlines. I have fixed this in this version to go back to the original behavior, in which quoted strings do *not* span newlines. - Fixed minor bug in HTTP server log parser. (Thanks Jim Richardson) Version 1.0.6 - 13 Feb 2004 ---------------------------- - Added CharsNotIn class (Thanks, Lee SangYeong). This is the opposite of Word, in that it is constructed with a set of characters *not* to be matched. (This enhancement also allowed me to clean up and simplify some of the definitions for quoted strings, cStyleComment, and restOfLine.) - **MINOR API CHANGE** - Added joinString argument to the __init__ method of Combine (Thanks, Thomas Kalka). joinString defaults to "", but some applications might choose some other string to use instead, such as a blank or newline. joinString was inserted as the second argument to __init__, so if you have code that specifies an adjacent value, without using 'adjacent=', this code will break. - Modified LineStart to recognize the start of an empty line. - Added optional caseless flag to oneOf(), to create a list of CaselessLiteral tokens instead of Literal tokens. - Added some enhancements to the SQL example: . Oracle-style comments (Thanks to Harald Armin Massa) . simple WHERE clause - Minor performance speedup - 5-15% Version 1.0.5 - 19 Jan 2004 ---------------------------- - Added scanString() generator method to ParseElement, to support regex-like pattern-searching - Added items() list to ParseResults, to return named results as a list of (key,value) pairs - Fixed memory overflow in asList() for deeply nested ParseResults (Thanks, Sverrir Valgeirsson) - Minor performance speedup - 10-15% Version 1.0.4 - 8 Jan 2004 --------------------------- - Added positional tokens StringStart, StringEnd, LineStart, and LineEnd - Added commaSeparatedList to pre-defined global token definitions; also added commasep.py to the examples directory, to demonstrate the differences between parsing comma-separated data and simple line-splitting at commas - Minor API change: delimitedList does not automatically enclose the list elements in a Group, but makes this the responsibility of the caller; also, if invoked using 'combine=True', the list delimiters are also included in the returned text (good for scoped variables, such as a.b.c or a::b::c, or for directory paths such as a/b/c) - Performance speed-up again, 30-40% - Added httpServerLogParser.py to examples directory, as this is a common parsing task Version 1.0.3 - 23 Dec 2003 --------------------------- - Performance speed-up again, 20-40% - Added Python distutils installation setup.py, etc. (thanks, Dave Kuhlman) Version 1.0.2 - 18 Dec 2003 --------------------------- - **NOTE: Changed API again!!!** (for the last time, I hope) + Renamed module from parsing to pyparsing, to better reflect Python linkage. - Also added dictExample.py to examples directory, to illustrate usage of the Dict class. Version 1.0.1 - 17 Dec 2003 --------------------------- - **NOTE: Changed API!** + Renamed 'len' argument on Word.__init__() to 'exact' - Performance speed-up, 10-30% Version 1.0.0 - 15 Dec 2003 --------------------------- - Initial public release Version 0.1.1 thru 0.1.17 - October-November, 2003 -------------------------------------------------- - initial development iterations: - added Dict, Group - added helper methods oneOf, delimitedList - added helpers quotedString (and double and single), restOfLine, cStyleComment - added MatchFirst as an alternative to the slower Or - added UML class diagram - fixed various logic bugs ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6869822 pyparsing-3.3.2/CODE_OF_CONDUCT.rst0000644000000000000000000000641515134002420013465 0ustar00Contributor Covenant Code of Conduct ==================================== Our Pledge ---------- In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. Our Standards ------------- Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others’ private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting Our Responsibilities -------------------- Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. Scope ----- This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. Enforcement ----------- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at pyparsing@mail.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership. Attribution ----------- This Code of Conduct is adapted from the `Contributor Covenant `__, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6869822 pyparsing-3.3.2/CONTRIBUTING.md0000644000000000000000000002106515134002420012705 0ustar00# Contributing to Pyparsing Thank you for your interest in working on pyparsing! Pyparsing has become a popular module for creating simple text parsing and data scraping applications. It has been incorporated in several widely-used packages, and is often used by beginners as part of their first Python project. ## Raising questions / asking for help If you have a question on using pyparsing, there are a number of resources available online. - [StackOverflow](https://stackoverflow.com/questions/tagged/pyparsing) - about 10 years of SO questions and answers can be searched on StackOverflow, tagged with the `pyparsing` tag. Note that some of the older posts will refer to features in Python 2, or to versions and coding practices for pyparsing that have been replaced by newer classes and coding idioms. - [pyparsing sub-reddit](https://www.reddit.com/r/pyparsing/) - still very lightly attended, but open to anyone wishing to post questions or links related to pyparsing. An alternative channel to StackOverflow for asking questions. - [online docs](https://pyparsing-docs.readthedocs.io/en/latest/index.html) and a separately maintained set of class library docs [here](https://pyparsing-doc.neocities.org/) - These docs are auto-generated from the docstrings embedded in the pyparsing classes, so they can also be viewed in the interactive Python console's and Jupyter Notebook's `help` commands. - [the pyparsing Wikispaces archive](https://github.com/pyparsing/wikispaces_archive) - Before hosting on GitHub, pyparsing had a separate wiki on the wikispaces.com website. In 2018 this page was discontinued. The discussion content archive has been reformatted into Markdown and can be viewed by year at the GitHub repository. Just as with some of the older questions on StackOverflow, some of these older posts may reflect out-of-date pyparsing and Python features. - [submit an issue](https://github.com/pyparsing/pyparsing/issues) - If you have a problem with pyparsing that looks like an actual bug, or have an idea for a feature to add to pyparsing please submit an issue on GitHub. Some pyparsing behavior may be counter-intuitive, so try to review some of the other resources first, or some of the other open and closed issues. Or post your question on SO or reddit. But don't wait until you are desperate and frustrated - just ask! :) ## Submitting examples If you have an example you wish to submit, please follow these guidelines. - **License - Submitted example code must be available for distribution with the rest of pyparsing under the MIT open source license.** - Please follow PEP8 name and coding guidelines, and use the black formatter to auto-format code. - Examples should import pyparsing and the common namespace classes as: ```python import pyparsing as pp # if necessary ppc = pp.pyparsing_common ppu = pp.pyparsing_unicode ``` - Submitted examples _must_ be Python 3.9 or later compatible. (It is acceptable if examples use Python features added after 3.6) - Where possible use operators to create composite parse expressions: ```python expr = expr_a + expr_b | expr_c ``` instead of: ```python expr = pp.MatchFirst([pp.And([expr_a, expr_b]), expr_c]) ``` Exception: if using a generator to create an expression: ```python import keyword python_keywords = keyword.kwlist any_keyword = pp.MatchFirst(pp.Keyword(kw) for kw in python_keywords)) ``` - Learn [Common Pitfalls When Writing Parsers][pitfalls] and how to avoid them when developing new examples. - See additional notes under [Some coding points](#some-coding-points). ## Submitting changes If you are considering proposing updates to pyparsing, please bear in mind the following guidelines. Please review [_The Zen of Pyparsing_ and _The Zen of Pyparsing Development_](https://github.com/pyparsing/pyparsing/wiki/Zen) article on the pyparsing wiki, to get a general feel for the historical and future approaches to pyparsing's design, and intended developer experience as an embedded DSL. If you are using new Python features or changing usage of the Python stdlib, please check that they work as intended on prior versions of Python (currently back to Python 3.6.8). ## Some design points - Minimize additions to the module namespace. Over time, pyparsing's namespace has acquired a _lot_ of names. New features have been encapsulated into namespace classes to try to hold back the name flooding when importing pyparsing. - New operator overloads for ParserElement will need to show broad applicability, and should be related to parser construction. - Performance tuning should focus on parse time performance. Optimizing parser definition performance is secondary. - New external dependencies will require substantial justification, and if included, will need to be guarded for `ImportError`s raised if the external module is not installed. ## Some coding points These coding styles are encouraged whether submitting code for core pyparsing or for submitting an example. - PEP8 - pyparsing has historically been very non-compliant with many PEP8 guidelines, especially those regarding name casing. I had just finished several years of Java and Smalltalk development, and camel case seemed to be the future trend in coding styles. As of version 3.0.0, pyparsing is moving over to PEP8 naming, while maintaining compatibility with existing parser code by defining synonyms using the legacy names. These names will be retained until a future release (probably 4.0), to provide a migration path for current pyparsing-dependent applications - DO NOT MODIFY OR REMOVE THESE NAMES. See more information at the [PEP8 wiki page](https://github.com/pyparsing/pyparsing/wiki/PEP-8-planning). - No backslashes for line continuations. Continuation lines for expressions in `()`'s should start with the continuing operator: ```python really_long_line = ( something + some_other_long_thing + even_another_long_thing ) ``` - Maximum line length is 120 characters. (Black will override this.) - Changes to core pyparsing must be compatible back to Py3.6 without conditionalizing. Later Py3 features may be used in examples by way of illustration. - `str.format()` statements should use named format arguments (unless this proves to be a slowdown at parse time). - List, tuple, and dict literals should include a trailing comma after the last element, which reduces changeset clutter when another element gets added to the end. - New features should be accompanied by updates to `unitTests.py` and a bullet in the CHANGES file. - Do not modify `pyparsing_archive.py`. This file is kept as a reference artifact from when pyparsing was distributed as a single source file. ## Some documentation points - The docstrings in pyparsing (which are generated into the package's API documentation by Sphinx) make heavy use of doctests for their example code. This allows examples to be tested and verified as working, and ensures that any changes to the code which affect output are accompanied by corresponding changes in the examples. - The codebase's docstring tests can be verified by running the command `make doctest` from the `docs/` directory. The output should ideally look something like this: ```console $ make doctest [...documentation build...] running tests... Document: pyparsing ------------------- 1 item passed all tests: 204 tests in default 204 tests in 1 item. 204 passed. Test passed. Document: whats_new_in_3_1 -------------------------- 1 item passed all tests: 15 tests in default 15 tests in 1 item. 15 passed. Test passed. Doctest summary =============== 219 tests 0 failures in tests 0 failures in setup code 0 failures in cleanup code ``` Any failed tests will be displayed in detail. - Much more information about doctests can be found in the [Pyparsing documentation][pyparsing-docs], in the chapter titled "Writing doctest examples". Even if you have never worked with them before, it should guide you through everything you need to know in order to write Pyparsing doctest examples. If you are already familiar with doctests and with `sphinx.ext.doctest` in general, you may wish to skip over the introductory content and go straight to the section on "Doctests in Pyparsing" which covers some issues specific to the project. [pitfalls]: https://github.com/pyparsing/pyparsing/wiki/Common-Pitfalls-When-Writing-Parsers [pyparsing-docs]: https://pyparsing-docs.readthedocs.io/en/latest/ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6869822 pyparsing-3.3.2/LICENSE0000644000000000000000000000204615134002420011457 0ustar00Copyright (c) 2003-2025 Paul McGuire 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. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6869822 pyparsing-3.3.2/README.rst0000644000000000000000000001022015134002420012132 0ustar00PyParsing -- A Python Parsing Module ==================================== |Version| |Build Status| |Coverage| |License| |Python Versions| |Snyk Score| Introduction ============ The pyparsing module is an alternative approach to creating and executing simple grammars, vs. the traditional lex/yacc approach, or the use of regular expressions. The pyparsing module provides a library of classes that client code uses to construct the grammar directly in Python code. *[Since first writing this description of pyparsing in late 2003, this technique for developing parsers has become more widespread, under the name Parsing Expression Grammars - PEGs. See more information on PEGs* `here `__ *.]* Here is a program to parse ``"Hello, World!"`` (or any greeting of the form ``"salutation, addressee!"``): .. code:: python from pyparsing import Word, alphas greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" print(hello, "->", greet.parse_string(hello)) The program outputs the following:: Hello, World! -> ['Hello', ',', 'World', '!'] The Python representation of the grammar is quite readable, owing to the self-explanatory class names, and the use of '+', '|' and '^' operator definitions. The parsed results returned from ``parse_string()`` is a collection of type ``ParseResults``, which can be accessed as a nested list, a dictionary, or an object with named attributes. The pyparsing module handles some of the problems that are typically vexing when writing text parsers: - extra or missing whitespace (the above program will also handle ``"Hello,World!"``, ``"Hello , World !"``, etc.) - quoted strings - embedded comments The examples directory includes a simple SQL parser, simple CORBA IDL parser, a config file parser, a chemical formula parser, and a four- function algebraic notation parser, among many others. Documentation ============= There are many examples in the online docstrings of the classes and methods in pyparsing. You can find them compiled into `online docs `__. Additional documentation resources and project info are listed in the online `GitHub wiki `__. An entire directory of examples can be found `here `__. AI Instructions =============== There are also instructions for AI agents to use when helping you to create your parser. They can be pulled from the GitHub project repository, at pyparsing/ai/best_practices.md. You can also tell the AI to access them programmatically after installing pyparsing, either from the CLI with ``python -m pyparsing.ai.show_best_practices`` or within python with ``import pyparsing; pyparsing.show_best_practices()``. License ======= MIT License. See header of the `pyparsing __init__.py `__ file. History ======= See `CHANGES `__ file. Performance benchmarks ====================== For usage instructions and details on the performance benchmark suite, see ``tests/README.md`` in this repository. .. |Build Status| image:: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml/badge.svg :target: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml .. |Coverage| image:: https://codecov.io/gh/pyparsing/pyparsing/branch/master/graph/badge.svg :target: https://codecov.io/gh/pyparsing/pyparsing .. |Version| image:: https://img.shields.io/pypi/v/pyparsing?style=flat-square :target: https://pypi.org/project/pyparsing/ :alt: Version .. |License| image:: https://img.shields.io/pypi/l/pyparsing.svg?style=flat-square :target: https://pypi.org/project/pyparsing/ :alt: License .. |Python Versions| image:: https://img.shields.io/pypi/pyversions/pyparsing.svg?style=flat-square :target: https://pypi.org/project/python-liquid/ :alt: Python versions .. |Snyk Score| image:: https://snyk.io//advisor/python/pyparsing/badge.svg :target: https://snyk.io//advisor/python/pyparsing :alt: pyparsing ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768964922.7324464 pyparsing-3.3.2/dest/README.md0000644000000000000000000000443315134041473012705 0ustar00# Regex Inverter This directory contains a web-based Regex Inverter tool powered by [PyScript](https://pyscript.net/) and `pyparsing`. ## Overview The Regex Inverter allows you to enter a regular expression and generate all possible strings that match it. It is particularly useful for visualizing the expansion of character classes, repetitions, and alternatives. ### Key Features: - **Expansion of Regex Patterns:** Generates matching strings for patterns like `[A-Z]{3}\d{3}`. - **Client-Side Processing:** All computations happen in your browser using PyScript, so no data is sent to a server. - **Progress Tracking:** Shows the total count of possible matches, even if they exceed the display limit. ### Supported Syntax: - Character sets: `[a-z]`, `[0-9A-F]`, `[^0-9]` - Repetitions: `{n}`, `{min,max}`, `{,max}` - Alternatives: `apple|orange` - Groups: `(abc|def)` - Macros: `\d`, `\w`, `\s`, `\D`, `\W`, `\S` - Dot: `.` (matches printable characters) ### Constraints: - **Unbounded operators `+` and `*` are not supported.** You must use explicit range repetitions like `{1,10}` instead of `+` to prevent infinite or excessively large result sets that would crash the browser. ## Files - `index.html`: The web interface and PyScript configuration. - `inv_regex.py`: The core inversion logic using `pyparsing`. ## Run the Regex Inverter web page online To run the Regex Inverter from the Github Pages server, open your browser and go to [https://ptmcg.github.io/regex_inverter/](https://ptmcg.github.io/regex_inverter/). ## How to Run Locally To run the Regex Inverter on your own machine: 1. Open a terminal or command prompt. 2. Navigate to this directory: ```bash cd examples/regex_inverter ``` 3. Start a local Python web server: ```bash python -m http.server ``` 4. Open your web browser and go to: [http://localhost:8000](http://localhost:8000) ## Deployment To deploy this to a web server: 1. Upload both `index.html` and `inv_regex.py` to the same directory on your web server. 2. Ensure your server is configured to serve `.html` files (most are by default). 3. Access the `index.html` file through its URL. Since this is a static site (using PyScript to run Python in the browser), you can even host it on GitHub Pages or any other static site hosting service. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768964922.7344463 pyparsing-3.3.2/dest/index.html0000644000000000000000000003046315134041473013425 0ustar00 PyParsing Regex Inverter

Regex Inverter

by Paul McGuire, January 2026

Description

This page allows you to invert a regular expression, generating strings that match it.

Instructions: Enter a regular expression in the "Regex" field and specify the maximum number of results you want to see (up to 100,000,000). Click "Invert" or press Enter to generate the matching strings.

Constraints:

  • Unbounded repetition operators + and * are not supported.
  • Replace + or * with explicit {1,n} or {min,max} repetition operators (e.g., use an explicit repetition like [A-Z]{1,4} instead of [A-Z]+, or [A-Z]{,4} instead of [A-Z]*).
  • For brevity, all generated strings in this utility are limited to 7-bit ASCII characters. By default, Python's re methods will match the full Unicode set, so macros like \d could match numeric digits in other language character sets beyond just the ASCII digits '0' through '9'.

Note: Complex regular expressions or those with large repetition counts may take some time to process.

Regular Expressions Quick Reference
ConstructDescription
.Any character except newline
\dDigit [0-9]
\wWord (identifier) character [a-zA-Z0-9_]
\sWhitespace character
\DNon-digit
\WNon-word character
\SNon-whitespace character
?0 or 1 repetition
{n}Exactly n repetitions
{n,m}Between n and m repetitions
{,m}0 to m repetitions
[...]Character class (any of these characters)
[^...]Negated character class
|Alternation (OR)
(...)Grouping
(?:...)Grouping (non-capturing)
(?P<name>...)Grouping (named group)
Other common regex features not covered in this utility
^Start of a line
$End of a line
\AStart of string
\ZEnd of string
*0 or more repetitions (use {,m} to limit repetitions)
+1 or more repetitions (use {1,m} to limit repetitions)
\bWord boundary
(?=...)Positive lookahead
(?!...)Negative lookahead
(?<=...)Positive lookbehind
(?<!...)Negative lookbehind

Examples

Here are some example regular expressions to try:

DescriptionRegex
Match one uppercase letter followed by three digits [A-Z]-\d{3}
Time of day (HH:MM:SS) (2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])
8-bit binary numbers [01]{8}
Integer from 0 to 99 [1-9]?\d
Integer from 0 to 255 25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d
Roman Numerals to 50 (X{,3}|XL)(I{,3}|IV|VI{,3}|IX)|L
Chemical Symbol A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|S[bcegimnr]?|T[abcehilm]|U(u[bhopqst])?|V|W|Xe|Yb?|Z[nr]
IPv4 addresses in 192.168.0.0/16 192\.168(\.((25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d))){2}
MAC address [0-9A-Fa-f]{2}([:-][0-9A-Fa-f]{2}){5}
UUID [0-9A-F]{8}(-[0-9A-F]{4}){3}-[0-9A-F]{12}
Original US Area codes (leading and trailing digit 2-9, middle digit 1 or 0) [2-9][10][2-9]

Enter a regular expression to see its matching strings.

GitHub repo for this page regex-inverter

Powered by PyScript and pyparsing

packages = ["pyparsing"] [[fetch]] files = ["inv_regex.py"] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6880958 pyparsing-3.3.2/dest/inv_regex.py0000644000000000000000000002147415134002420013757 0ustar00# # original file: https://raw.githubusercontent.com/pyparsing/pyparsing/pyparsing_3.0.9/examples/invRegex.py # # Copyright 2008, Paul McGuire # # pyparsing script to expand a regular expression into all possible matching strings # Supports: # - {n} and {m,n} repetition, but not unbounded + or * repetition # - ? optional elements # - [] character ranges # - () grouping # - | alternation # __all__ = ["count", "invert"] from pyparsing import ( Literal, one_of, Empty, printables, ParserElement, Combine, Optional, SkipTo, infix_notation, ParseFatalException, Word, nums, OpAssoc, Suppress, ParseResults, srange, autoname_elements, Regex, ) ParserElement.enable_packrat() class CharacterRangeEmitter: def __init__(self, chars): # remove duplicate chars in character range, but preserve original order seen = set() self.charset = "".join(seen.add(c) or c for c in chars if c not in seen) def __str__(self): return "[" + self.charset + "]" def __repr__(self): return "[" + self.charset + "]" def make_generator(self): def gen_chars(): yield from self.charset return gen_chars class OptionalEmitter: def __init__(self, expr): self.expr = expr def make_generator(self): def optional_gen(): yield "" yield from self.expr.make_generator()() return optional_gen class DotEmitter: def make_generator(self): def dot_gen(): yield from printables return dot_gen class GroupEmitter: def __init__(self, exprs): self.exprs = ParseResults(exprs) def make_generator(self): def group_gen(): def recurse_list(elist): if len(elist) == 1: yield from elist[0].make_generator()() else: for s in elist[0].make_generator()(): for s2 in recurse_list(elist[1:]): yield s + s2 if self.exprs: yield from recurse_list(self.exprs) return group_gen class AlternativeEmitter: def __init__(self, exprs): self.exprs = exprs def make_generator(self): def alt_gen(): for e in self.exprs: yield from e.make_generator()() return alt_gen class LiteralEmitter: def __init__(self, lit): self.lit = lit def __str__(self): return "Lit:" + self.lit def __repr__(self): return "Lit:" + self.lit def make_generator(self): def lit_gen(): yield self.lit return lit_gen def handle_range(toks): inner = toks[0][1:-1] if inner.startswith("^"): range_chars = set(printables) - set(srange(f"[{inner[1:]}]")) return CharacterRangeEmitter(sorted(range_chars)) return CharacterRangeEmitter(srange(toks[0])) def handle_repetition(toks): toks = toks[0] if toks[1] in "*+": raise ParseFatalException("", 0, "unbounded repetition operators not supported") if toks[1] == "?": return OptionalEmitter(toks[0]) if "count" in toks: return GroupEmitter([toks[0]] * int(toks.count)) if "minCount" in toks: mincount = int(toks.minCount) maxcount = int(toks.maxCount) optcount = maxcount - mincount if optcount: opt = OptionalEmitter(toks[0]) for i in range(1, optcount): opt = OptionalEmitter(GroupEmitter([toks[0], opt])) return GroupEmitter([toks[0]] * mincount + [opt]) else: return [toks[0]] * mincount def handle_literal(toks): lit = "" for t in toks: if t[0] == "\\": if t[1] == "t": lit += "\t" else: lit += t[1] else: lit += t return LiteralEmitter(lit) def handle_macro(toks): macro_char = toks[0][1] if macro_char == "d": return CharacterRangeEmitter("0123456789") elif macro_char == "w": return CharacterRangeEmitter(srange("[A-Za-z0-9_]")) elif macro_char == "s": return LiteralEmitter(" ") elif macro_char == "D": return CharacterRangeEmitter(sorted(set(printables + " ") - set("0123456789"))) elif macro_char == "W": return CharacterRangeEmitter( sorted(set(printables + " ") - set(srange("[A-Za-z0-9_]"))) ) elif macro_char == "S": return CharacterRangeEmitter(printables) else: raise ParseFatalException( "", 0, "unsupported macro character (" + macro_char + ")" ) def handle_sequence(toks): return GroupEmitter(toks[0]) def handle_dot(): return CharacterRangeEmitter(printables) def handle_alternative(toks): return AlternativeEmitter(toks[0]) _parser = None def parser(): global _parser if _parser is None: ParserElement.set_default_whitespace_chars("") lbrack, rbrack, lbrace, rbrace, lparen, rparen, colon, qmark = ( Literal.using_each("[]{}():?") ) re_macro = Combine("\\" + one_of("d w s D W S")) escaped_char = ~re_macro + Combine("\\" + one_of(list(printables))) re_literal_char = ( "".join(c for c in printables if c not in r"\[]{}().*?+|") + " \t" ) re_range = Combine(lbrack + SkipTo(rbrack, ignore=escaped_char) + rbrack) # type: ignore re_literal = escaped_char | one_of(list(re_literal_char)) re_non_capture_group = Suppress("?:") re_named_group = Suppress(Regex(r"\?P<\w+>")) re_dot = Literal(".") repetition = ( (lbrace + Word(nums)("count") + rbrace) | ( lbrace + Optional(Word(nums), default=0)("minCount") + "," + Word(nums)("maxCount") + rbrace ) | one_of(list("*+?")) ) re_range.add_parse_action(handle_range) re_literal.add_parse_action(handle_literal) re_macro.add_parse_action(handle_macro) re_dot.add_parse_action(handle_dot) re_term = ( re_literal | re_range | re_macro | re_dot | re_non_capture_group | re_named_group ) re_term.set_name("re_term") alt_op = Suppress("|") seq_op = Empty() autoname_elements() re_expr = infix_notation( re_term, [ (repetition, 1, OpAssoc.LEFT, handle_repetition), (seq_op, 2, OpAssoc.LEFT, handle_sequence), (alt_op.set_name("re"), 2, OpAssoc.LEFT, handle_alternative), ], ) _parser = re_expr return _parser def count(gen): """Simple function to count the number of elements returned by a generator.""" return sum(1 for _ in gen) def invert(regex): r""" Call this routine as a generator to return all the strings that match the input regular expression. for s in invert(r"[A-Z]{3}\d{3}"): print s """ invre = GroupEmitter(parser().parse_string(regex, parse_all=True)).make_generator() return invre() def main(): tests = r""" abc|def [A-EA] [A-D]* [A-D]{3} X[A-C]{3}Y X[A-C]{3}\( X\d foobar\d\d foobar{2} foobar{2,9} fooba[rz]{2} (foobar){2} ([01]\d)|(2[0-5]) (?:[01]\d)|(2[0-5]) ([01]\d\d)|(2[0-4]\d)|(25[0-5]) [A-C]{1,2} [A-C]{0,3} [A-C]\s[A-C]\s[A-C] [A-C]\s?[A-C][A-C] [A-C]\s([A-C][A-C]) [A-C]\s([A-C][A-C])? [A-C]{2}\d{2} @|TH[12] @(@|TH[12])? @(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9]))? @(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9])|OH(1[0-9]?|2[0-9]?|30?|[4-9]))? (([ECMP]|HA|AK)[SD]|HS)T [A-CV]{,2} A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|S[bcegimnr]?|T[abcehilm]|Uu[bhopqst]|U|V|W|Xe|Yb?|Z[nr] (a|b)|(x|y) (a|b) (x|y) [ABCDEFG](?:#|##|b|bb)?(?:maj|min|m|sus|aug|dim)?[0-9]?(?:/[ABCDEFG](?:#|##|b|bb)?)? (Fri|Mon|S(atur|un)|T(hur|ue)s|Wednes)day A(pril|ugust)|((Dec|Nov|Sept)em|Octo)ber|(Febr|Jan)uary|Ju(ly|ne)|Ma(rch|y) \S-\d{2} \D{2}-\W [^A-Z]-\d{3} """.splitlines() for t in tests: t = t.strip() if not t: continue print("-" * 50) print(t) try: num = count(invert(t)) print(num) maxprint = 30 for s in invert(t): print(s) maxprint -= 1 if not maxprint: break except ParseFatalException as pfe: print(pfe.msg) print("") continue print("") if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6880958 pyparsing-3.3.2/docs/CODE_OF_CONDUCT.rst0000644000000000000000000000004415134002420014405 0ustar00.. include:: ../CODE_OF_CONDUCT.rst ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6880958 pyparsing-3.3.2/docs/CONTRIBUTING.md0000755000000000000000000000000015134002420016266 2../CONTRIBUTING.mdustar00././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.688279 pyparsing-3.3.2/docs/HowToUsePyparsing.rst0000644000000000000000000020140515134002420015546 0ustar00========================== Using the pyparsing module ========================== :author: Paul McGuire :address: ptmcg.pm+pyparsing@gmail.com :revision: 3.2.0 :date: October, 2024 :copyright: Copyright |copy| 2003-2024 Paul McGuire. .. |copy| unicode:: 0xA9 :abstract: This document provides how-to instructions for the pyparsing library, an easy-to-use Python module for constructing and executing basic text parsers. The pyparsing module is useful for evaluating user-definable expressions, processing custom application language commands, or extracting data from formatted reports. .. contents:: :depth: 4 Note: While this content is still valid, there are more detailed descriptions and extensive examples at the `online doc server `_, and in the online help for the various pyparsing classes and methods (viewable using the Python interpreter's built-in ``help()`` function). You will also find many example scripts in the `examples `_ directory of the pyparsing GitHub repo. ----------- **Note**: *In pyparsing 3.0, many method and function names which were originally written using camelCase have been converted to PEP8-compatible snake_case. So ``parseString()`` is being renamed to ``parse_string()``, ``delimitedList`` to DelimitedList_, and so on. You may see the old names in legacy parsers, and they will be supported for a time with synonyms, but the synonyms will be removed in a future release.* *If you are using this documentation, but working with a 2.4.x version of pyparsing, you'll need to convert methods and arguments from the documented snake_case names to the legacy camelCase names. In pyparsing 3.x, both forms are supported, but the legacy forms are deprecated; they will be dropped in a future 4.0 release.* ----------- Steps to follow =============== To parse an incoming data string, the client code must follow these steps: 1. First define the tokens and patterns to be matched, and assign this to a program variable. Optional results names or parse actions can also be defined at this time. 2. Call ``parse_string()``, ``scan_string()``, or ``search_string()`` on this variable, passing in the string to be parsed. During the matching process, whitespace between tokens is skipped by default (although this can be changed). When token matches occur, any defined parse action methods are called. 3. Process the parsed results, returned as a ParseResults_ object. The ParseResults_ object can be accessed as if it were a list of strings. Matching results may also be accessed as named attributes of the returned results, if names are defined in the definition of the token pattern, using ``set_results_name()``. Hello, World! ------------- The following complete Python program will parse the greeting ``"Hello, World!"``, or any other greeting of the form ", !":: import pyparsing as pp greet = pp.Word(pp.alphas) + "," + pp.Word(pp.alphas) + "!" for greeting_str in [ "Hello, World!", "Bonjour, Monde!", "Hola, Mundo!", "Hallo, Welt!", ]: greeting = greet.parse_string(greeting_str) print(greeting) The parsed tokens are returned in the following form:: ['Hello', ',', 'World', '!'] ['Bonjour', ',', 'Monde', '!'] ['Hola', ',', 'Mundo', '!'] ['Hallo', ',', 'Welt', '!'] Usage notes ----------- - The pyparsing module can be used to interpret simple command strings or algebraic expressions, or can be used to extract data from text reports with complicated format and structure ("screen or report scraping"). However, it is possible that your defined matching patterns may accept invalid inputs. Use pyparsing to extract data from strings assumed to be well-formatted. - To keep up the readability of your code, use operators_ such as ``+``, ``|``, ``^``, and ``~`` to combine expressions. You can also combine string literals with ``ParseExpressions`` - they will be automatically converted to Literal_ objects. For example:: integer = Word(nums) # simple unsigned integer variable = Char(alphas) # single letter variable, such as x, z, m, etc. arith_op = one_of("+ - * /") # arithmetic operators equation = variable + "=" + integer + arith_op + integer # will match "x=2+2", etc. In the definition of ``equation``, the string ``"="`` will get added as a ``Literal("=")``, but in a more readable way. - The pyparsing module's default behavior is to ignore whitespace. This is the case for 99% of all parsers ever written. This allows you to write simple, clean, grammars, such as the above ``equation``, without having to clutter it up with extraneous ``ws`` markers. The ``equation`` grammar will successfully parse all of the following statements:: x=2+2 x = 2+2 a = 10 * 4 r= 1234/ 100000 Of course, it is quite simple to extend this example to support more elaborate expressions, with nesting with parentheses, floating point numbers, scientific notation, and named constants (such as ``e`` or ``pi``). See `fourFn.py `_, and `simpleArith.py `_ included in the examples directory. - To modify pyparsing's default whitespace skipping, you can use one or more of the following methods: - use the static method ``ParserElement.set_default_whitespace_chars`` to override the normal set of whitespace chars (``' \t\n'``). For instance when defining a grammar in which newlines are significant, you should call ``ParserElement.set_default_whitespace_chars(' \t')`` to remove newline from the set of skippable whitespace characters. Calling this method will affect all pyparsing expressions defined afterward. - call ``leave_whitespace()`` on individual expressions, to suppress the skipping of whitespace before trying to match the expression - use ``Combine`` to require that successive expressions must be adjacent in the input string. For instance, this expression:: real = Word(nums) + '.' + Word(nums) will match "3.14159", but will also match "3 . 12". It will also return the matched results as ['3', '.', '14159']. By changing this expression to:: real = Combine(Word(nums) + '.' + Word(nums)) it will not match numbers with embedded spaces, and it will return a single concatenated string '3.14159' as the parsed token. - Repetition of expressions can be indicated using ``*`` or ``[]`` notation. An expression may be multiplied by an integer value (to indicate an exact repetition count), or indexed with a tuple, representing min and max repetitions (with ``...`` representing no min or no max, depending whether it is the first or second tuple element). See the following examples, where n is used to indicate an integer value: - ``expr*3`` is equivalent to ``expr + expr + expr`` - ``expr[2, 3]`` is equivalent to ``expr + expr + Opt(expr)`` - ``expr[n, ...]`` or ``expr[n,]`` is equivalent to ``expr*n + ZeroOrMore(expr)`` (read as "at least n instances of expr") - ``expr[... ,n]`` is equivalent to ``expr*(0, n)`` (read as "0 to n instances of expr") - ``expr[...]``, ``expr[0, ...]`` and ``expr * ...`` are equivalent to ``ZeroOrMore(expr)`` - ``expr[1, ...]`` is equivalent to ``OneOrMore(expr)`` Note that ``expr[..., n]`` does not raise an exception if more than n exprs exist in the input stream; that is, ``expr[..., n]`` does not enforce a maximum number of expr occurrences. If this behavior is desired, then write ``expr[..., n] + ~expr``. - ``[]`` notation will also accept a stop expression using ':' slice notation: - ``expr[...:end_expr]`` is equivalent to ``ZeroOrMore(expr, stop_on=end_expr)`` - MatchFirst_ expressions are matched left-to-right, and the first match found will skip all later expressions within, so be sure to define less-specific patterns after more-specific patterns. If you are not sure which expressions are most specific, use Or_ expressions (defined using the ``^`` operator) - they will always match the longest expression, although they are more compute-intensive. - Or_ expressions will evaluate all of the specified subexpressions to determine which is the "best" match, that is, which matches the longest string in the input data. In case of a tie, the left-most expression in the Or_ list will win. - If parsing the contents of an entire file, pass it to the ``parse_file`` method using:: expr.parse_file(source_file) - ``ParseExceptions`` will report the location where an expected token or expression failed to match. For example, if we tried to use our "Hello, World!" parser to parse "Hello World!" (leaving out the separating comma), we would get an exception, with the message:: pyparsing.ParseException: Expected "," (6), (1,7) In the case of complex expressions, the reported location may not be exactly where you would expect. See more information under ParseException_ . - Use the ``Group`` class to enclose logical groups of tokens within a sublist. This will help organize your results into more hierarchical form (the default behavior is to return matching tokens as a flat list of matching input strings). - Punctuation may be significant for matching, but is rarely of much interest in the parsed results. Use the ``suppress()`` method to keep these tokens from cluttering up your returned lists of tokens. For example, DelimitedList_ matches a succession of one or more expressions, separated by delimiters (commas by default), but only returns a list of the actual expressions - the delimiters are used for parsing, but are suppressed from the returned output. - Parse actions can be used to convert values from strings to other data types (ints, floats, booleans, etc.). - Results names are recommended for retrieving tokens from complex expressions. It is much easier to access a token using its field name than using a positional index, especially if the expression contains optional elements. You can also shortcut the ``set_results_name`` call:: stats = ("AVE:" + real_num.set_results_name("average") + "MIN:" + real_num.set_results_name("min") + "MAX:" + real_num.set_results_name("max")) can more simply and cleanly be written as this:: stats = ("AVE:" + real_num("average") + "MIN:" + real_num("min") + "MAX:" + real_num("max")) - Be careful when defining parse actions that modify global variables or data structures (as in fourFn.py_), especially for low level tokens or expressions that may occur within an And_ expression; an early element of an And_ may match, but the overall expression may fail. Classes ======= All the pyparsing classes can be found in this `UML class diagram <_static/pyparsingClassDiagram_3.0.9.jpg>`_. Classes in the pyparsing module ------------------------------- ``ParserElement`` - abstract base class for all pyparsing classes; methods for code to use are: - ``parse_string(source_string, parse_all=False)`` - only called once, on the overall matching pattern; returns a ParseResults_ object that makes the matched tokens available as a list, and optionally as a dictionary, or as an object with named attributes; if ``parse_all`` is set to True, then ``parse_string`` will raise a ParseException_ if the grammar does not process the complete input string. - ``parse_file(source_file)`` - a convenience function, that accepts an input file object or filename. The file contents are passed as a string to ``parse_string()``. ``parse_file`` also supports the ``parse_all`` argument. - ``scan_string(source_string)`` - generator function, used to find and extract matching text in the given source string; for each matched text, returns a tuple of: - matched tokens (packaged as a ParseResults_ object) - start location of the matched text in the given source string - end location in the given source string ``scan_string`` allows you to scan through the input source string for random matches, instead of exhaustively defining the grammar for the entire source text (as would be required with ``parse_string``). - ``transform_string(source_string)`` - convenience wrapper function for ``scan_string``, to process the input source string, and replace matching text with the tokens returned from parse actions defined in the grammar (see set_parse_action_). - ``search_string(source_string)`` - another convenience wrapper function for ``scan_string``, returns a list of the matching tokens returned from each call to ``scan_string``. - ``set_name(name)`` - associate a short descriptive name for this element, useful in displaying exceptions and trace information - ``run_tests(tests_string)`` - useful development and testing method on expressions, to pass a multiline string of sample strings to test against the expression. Comment lines (beginning with ``#``) can be inserted and they will be included in the test output:: digits = Word(nums).set_name("numeric digits") real_num = Combine(digits + '.' + digits) real_num.run_tests("""\ # valid number 3.14159 # no integer part .00001 # no decimal 101 # no decimal value 101. """) will print:: # valid number 3.14159 ['3.14159'] # no integer part .00001 ^ FAIL: Expected numeric digits, found '.' (at char 0), (line:1, col:1) # no decimal 101 ^ FAIL: Expected ".", found end of text (at char 3), (line:1, col:4) # no decimal value 101. ^ FAIL: Expected numeric digits, found end of text (at char 4), (line:1, col:5) .. _set_results_name: - ``set_results_name(string, list_all_matches=False)`` - name to be given to tokens matching the element; if multiple tokens within a repetition group (such as ZeroOrMore_ or DelimitedList_) the default is to return only the last matching token - if ``list_all_matches`` is set to True, then a list of all the matching tokens is returned. ``expr.set_results_name("key")`` can also be written ``expr("key")`` (a results name with a trailing '*' character will be interpreted as setting ``list_all_matches`` to ``True``). Note: ``set_results_name`` returns a *copy* of the element so that a single basic element can be referenced multiple times and given different names within a complex grammar. .. _using_each: - ``using_each(list_of_symbols)`` a short-cut for defining a number of symbols of a particular ``ParserElement`` subclass:: LBRACK, RBRACK, LBRACE, RBRACE, LPAR, RPAR = Suppress.using_each("[]{}()") AND, OR, NOT = Keyword.using_each("and or not".split()) .. _set_parse_action: - ``set_parse_action(*fn)`` - specify one or more functions to call after successful matching of the element; each function is defined as ``fn(s, loc, toks)``, where: - ``s`` is the original parse string - ``loc`` is the location in the string where matching started - ``toks`` is the list of the matched tokens, packaged as a ParseResults_ object Parse actions can have any of the following signatures:: fn(s: str, loc: int, tokens: ParseResults) fn(loc: int, tokens: ParseResults) fn(tokens: ParseResults) fn() Multiple functions can be attached to a ``ParserElement`` by specifying multiple arguments to ``set_parse_action``, or by calling ``add_parse_action``. Calls to ``set_parse_action`` will replace any previously defined parse actions. ``set_parse_action(None)`` will clear all previously defined parse actions. Each parse action function can return a modified ``toks`` list, to perform conversion, or string modifications. For brevity, ``fn`` may also be a lambda - here is an example of using a parse action to convert matched integer tokens from strings to integers:: int_number = Word(nums).set_parse_action(lambda s, l, t: [int(t[0])]) If ``fn`` modifies the ``toks`` list in-place, it does not need to return and pyparsing will use the modified ``toks`` list. If ``set_parse_action`` is called with an argument of ``None``, then this clears all parse actions attached to that expression. A nice short-cut for calling ``set_parse_action`` is to use it as a decorator:: identifier = Word(alphas, alphanums + "_") @identifier.set_parse_action def resolve_identifier(results: ParseResults): return variable_values.get(results[0]) (Posted by @MisterMiyagi in this SO answer: https://stackoverflow.com/a/63031959/165216) - ``add_parse_action`` - similar to ``set_parse_action``, but instead of replacing any previously defined parse actions, will append the given action or actions to the existing defined parse actions. - ``add_condition`` - a simplified form of ``add_parse_action`` if the purpose of the parse action is to simply do some validation, and raise an exception if the validation fails. Takes a method that takes the same arguments, but simply returns ``True`` or ``False``. If ``False`` is returned, an exception will be raised. - ``set_break(break_flag=True)`` - if ``break_flag`` is ``True``, calls ``pdb.set_break()`` as this expression is about to be parsed - ``copy()`` - returns a copy of a ``ParserElement``; can be used to use the same parse expression in different places in a grammar, with different parse actions attached to each; a short-form ``expr()`` is equivalent to ``expr.copy()`` - ``leave_whitespace()`` - change default behavior of skipping whitespace before starting matching (mostly used internally to the pyparsing module, rarely used by client code) - ``set_whitespace_chars(chars)`` - define the set of chars to be ignored as whitespace before trying to match a specific ``ParserElement``, in place of the default set of whitespace (space, tab, newline, and return) - ``set_default_whitespace_chars(chars)`` - class-level method to override the default set of whitespace chars for all subsequently created ParserElements (including copies); useful when defining grammars that treat one or more of the default whitespace characters as significant (such as a line-sensitive grammar, to omit newline from the list of ignorable whitespace) - ``suppress()`` - convenience function to suppress the output of the given element, instead of wrapping it with a ``Suppress`` object. - ``ignore(expr)`` - function to specify parse expression to be ignored while matching defined patterns; can be called repeatedly to specify multiple expressions; useful to specify patterns of comment syntax, for example - ``set_debug(flag=True)`` - function to enable/disable tracing output when trying to match this element - ``validate()`` - function to verify that the defined grammar does not contain infinitely recursive constructs. *(``validate()`` is deprecated, and will be removed in a future pyparsing release. Pyparsing now supports left-recursive parsers, which this function attempted to catch.)* .. _parse_with_tabs: - ``parse_with_tabs()`` - function to override default behavior of converting tabs to spaces before parsing the input string; rarely used, except when specifying whitespace-significant grammars using the White_ class. - ``enable_packrat()`` - a class-level static method to enable a memoizing performance enhancement, known as "packrat parsing". packrat parsing is disabled by default, since it may conflict with some user programs that use parse actions. To activate the packrat feature, your program must call the class method ``ParserElement.enable_packrat()``. For best results, call ``enable_packrat()`` immediately after importing pyparsing. - ``enable_left_recursion()`` - a class-level static method to enable pyparsing with left-recursive (LR) parsers. Similar to ``ParserElement.enable_packrat()``, your program must call the class method ``ParserElement.enable_left_recursion()`` to enable this feature. ``enable_left_recursion()`` uses a separate packrat cache, and so is incompatible with ``enable_packrat()``. Basic ParserElement subclasses ------------------------------ .. _Literal: - ``Literal`` - construct with a string to be matched exactly .. _CaselessLiteral: - ``CaselessLiteral`` - construct with a string to be matched, but without case checking; results are always returned as the defining literal, NOT as they are found in the input string .. _Keyword: - ``Keyword`` - similar to Literal_, but must be immediately followed by whitespace, punctuation, or other non-keyword characters; prevents accidental matching of a non-keyword that happens to begin with a defined keyword - ``CaselessKeyword`` - similar to Keyword_, but with caseless matching behavior as described in CaselessLiteral_. .. _Word: - ``Word`` - one or more contiguous characters; construct with a string containing the set of allowed initial characters, and an optional second string of allowed body characters; for instance, a common ``Word`` construct is to match a code identifier - in C, a valid identifier must start with an alphabetic character or an underscore ('_'), followed by a body that can also include numeric digits. That is, ``a``, ``i``, ``MAX_LENGTH``, ``_a1``, ``b_109_``, and ``plan9FromOuterSpace`` are all valid identifiers; ``9b7z``, ``$a``, ``.section``, and ``0debug`` are not. To define an identifier using a ``Word``, use either of the following:: Word(alphas+"_", alphanums+"_") Word(srange("[a-zA-Z_]"), srange("[a-zA-Z0-9_]")) Pyparsing also provides pre-defined strings ``identchars`` and ``identbodychars`` so that you can also write:: Word(identchars, identbodychars) If only one string given, it specifies that the same character set defined for the initial character is used for the word body; for instance, to define an identifier that can only be composed of capital letters and underscores, use one of:: ``Word("ABCDEFGHIJKLMNOPQRSTUVWXYZ_")`` ``Word(srange("[A-Z_]"))`` A ``Word`` may also be constructed with any of the following optional parameters: - ``min`` - indicating a minimum length of matching characters - ``max`` - indicating a maximum length of matching characters - ``exact`` - indicating an exact length of matching characters; if ``exact`` is specified, it will override any values for ``min`` or ``max`` - ``as_keyword`` - indicating that preceding and following characters must be whitespace or non-keyword characters - ``exclude_chars`` - a string of characters that should be excluded from init_chars and body_chars Sometimes you want to define a word using all characters in a range except for one or two of them; you can do this with the ``exclude_chars`` argument. This is helpful if you want to define a word with all ``printables`` except for a single delimiter character, such as '.'. Previously, you would have to create a custom string to pass to Word. With this change, you can just create ``Word(printables, exclude_chars='.')``. - ``Char`` - a convenience form of ``Word`` that will match just a single character from a string of matching characters:: single_digit = Char(nums) - ``CharsNotIn`` - similar to Word_, but matches characters not in the given constructor string (accepts only one string for both initial and body characters); also supports ``min``, ``max``, and ``exact`` optional parameters. - ``Regex`` - a powerful construct, that accepts a regular expression to be matched at the current parse position; accepts an optional ``flags`` parameter, corresponding to the flags parameter in the ``re.compile`` method; if the expression includes named sub-fields, they will be represented in the returned ParseResults_. - ``QuotedString`` - supports the definition of custom quoted string formats, in addition to pyparsing's built-in ``dbl_quoted_string`` and ``sgl_quoted_string``. ``QuotedString`` allows you to specify the following parameters: - ``quote_char`` - string of one or more characters defining the quote delimiting string - ``esc_char`` - character to escape quotes, typically backslash (default=None) - ``esc_quote`` - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None) - ``multiline`` - boolean indicating whether quotes can span multiple lines (default=False) - ``unquote_results`` - boolean indicating whether the matched text should be unquoted (default=True) - ``end_quote_char`` - string of one or more characters defining the end of the quote delimited string (default=None => same as ``quote_char``) .. _SkipTo: - ``SkipTo`` - skips ahead in the input string, accepting any characters up to the specified pattern; may be constructed with the following optional parameters: - ``include`` - if set to true, also consumes the match expression (default is false) - ``ignore`` - allows the user to specify patterns to not be matched, to prevent false matches - ``fail_on`` - if a literal string or expression is given for this argument, it defines an expression that should cause the SkipTo_ expression to fail, and not skip over that expression ``SkipTo`` can also be written using ``...``:: LBRACE, RBRACE = Literal.using_each("{}") brace_expr = LBRACE + SkipTo(RBRACE) + RBRACE # can also be written as brace_expr = LBRACE + ... + RBRACE .. _White: - ``White`` - also similar to Word_, but matches whitespace characters. Not usually needed, as whitespace is implicitly ignored by pyparsing. However, some grammars are whitespace-sensitive, such as those that use leading tabs or spaces to indicating grouping or hierarchy. (If matching on tab characters, be sure to call parse_with_tabs_ on the top-level parse element.) - ``Empty`` - a null expression, requiring no characters - will always match; useful for debugging and for specialized grammars - ``NoMatch`` - opposite of ``Empty``, will never match; useful for debugging and for specialized grammars Expression subclasses --------------------- .. _And: - ``And`` - construct with a list of ``ParserElements``, all of which must match for ``And`` to match; can also be created using the '+' operator; multiple expressions can be ``Anded`` together using the '*' operator as in:: ip_address = Word(nums) + ('.' + Word(nums)) * 3 A tuple can be used as the multiplier, indicating a min/max:: us_phone_number = Word(nums) + ('-' + Word(nums)) * (1,2) A special form of ``And`` is created if the '-' operator is used instead of the '+' operator. In the ``ip_address`` example above, if no trailing '.' and ``Word(nums)`` are found after matching the initial ``Word(nums)``, then pyparsing will back up in the grammar and try other alternatives to ``ip_address``. However, if ``ip_address`` is defined as:: strict_ip_address = Word(nums) - ('.'+Word(nums))*3 then no backing up is done. If the first ``Word(nums)`` of ``strict_ip_address`` is matched, then any mismatch after that will raise a ``ParseSyntaxException``, which will halt the parsing process immediately. By careful use of the '-' operator, grammars can provide meaningful error messages close to the location where the incoming text does not match the specified grammar. .. _Or: - ``Or`` - construct with a list of ``ParserElements``, any of which must match for ``Or`` to match; if more than one expression matches, the expression that makes the longest match will be used; can also be created using the '^' operator .. _MatchFirst: - ``MatchFirst`` - construct with a list of ``ParserElements``, any of which must match for ``MatchFirst`` to match; matching is done left-to-right, taking the first expression that matches; can also be created using the '|' operator .. _Each: - ``Each`` - similar to And_, in that all of the provided expressions must match; however, ``Each`` permits matching to be done in any order; can also be created using the '&' operator - ``Opt`` - construct with a ``ParserElement``, but this element is not required to match; can be constructed with an optional ``default`` argument, containing a default string or object to be supplied if the given optional parse element is not found in the input string; parse action will only be called if a match is found, or if a default is specified. An optional element ``expr`` can also be expressed using ``expr | ""``. (``Opt`` was formerly named ``Optional``, but since the standard Python library module ``typing`` now defines ``Optional``, the pyparsing class has been renamed to ``Opt``. A compatibility synonym ``Optional`` is defined, but will be removed in a future release.) .. _ZeroOrMore: - ``ZeroOrMore`` - similar to ``Opt``, but can be repeated; ``ZeroOrMore(expr)`` can also be written as ``expr[...]``. .. _OneOrMore: - ``OneOrMore`` - similar to ZeroOrMore_, but at least one match must be present; ``OneOrMore(expr)`` can also be written as ``expr[1, ...]``. .. _DelimitedList: - ``DelimitedList`` - used for matching one or more occurrences of ``expr``, separated by ``delim``. By default, the delimiters are suppressed, so the returned results contain only the separate list elements. Can optionally specify ``combine=True``, indicating that the expressions and delimiters should be returned as one combined value (useful for scoped variables, such as ``"a.b.c"``, or ``"a::b::c"``, or paths such as ``"a/b/c"``). Can also optionally specify ``min` and ``max`` restrictions on the length of the list, and ``allow_trailing_delim`` to accept a trailing delimiter at the end of the list. .. _FollowedBy: - ``FollowedBy`` - a lookahead expression, requires matching of the given expressions, but does not advance the parsing position within the input string .. _NotAny: - ``NotAny`` - a negative lookahead expression, prevents matching of named expressions, does not advance the parsing position within the input string; can also be created using the unary '~' operator .. _operators: Expression operators -------------------- - ``+`` - creates And_ using the expressions before and after the operator - ``|`` - creates MatchFirst_ (first left-to-right match) using the expressions before and after the operator - ``^`` - creates Or_ (longest match) using the expressions before and after the operator - ``&`` - creates Each_ using the expressions before and after the operator - ``*`` - creates And_ by multiplying the expression by the integer operand; if expression is multiplied by a 2-tuple, creates an And_ of ``(min,max)`` expressions (similar to ``{min,max}`` form in regular expressions); if ``min`` is ``None``, interpret as ``(0,max)``; if ``max`` is ``None``, interpret as ``expr*min + ZeroOrMore(expr)`` - ``-`` - like ``+`` but with no backup and retry of alternatives - ``~`` - creates NotAny_ using the expression after the operator - ``==`` - matching expression to string; returns ``True`` if the string matches the given expression - ``<<=`` - inserts the expression following the operator as the body of the ``Forward`` expression before the operator (``<<`` can also be used, but ``<<=`` is preferred to avoid operator precedence misinterpretation of the pyparsing expression) - ``...`` - inserts a SkipTo_ expression leading to the next expression, as in ``Keyword("start") + ... + Keyword("end")``. - ``[min, max]`` - specifies repetition similar to ``*`` with ``min`` and ``max`` specified as the minimum and maximum number of repetitions. ``...`` can be used in place of ``None``. For example ``expr[...]`` is equivalent to ``ZeroOrMore(expr)``, ``expr[1, ...]`` is equivalent to ``OneOrMore(expr)``, and ``expr[..., 3]`` is equivalent to "up to 3 instances of ``expr``". - ``[:stop_on]`` - specifies a stopping expression for the current repetition (may be combined with ``...`` or ``min, max``), as in ``Keyword("start") + Word(alphas)[...:Keyword("end")] + Keyword("end")`` Positional subclasses --------------------- - ``StringStart`` - matches beginning of the text - ``StringEnd`` - matches the end of the text - ``LineStart`` - matches beginning of a line (lines delimited by ``\n`` characters) - ``LineEnd`` - matches the end of a line - ``WordStart`` - matches a leading word boundary - ``WordEnd`` - matches a trailing word boundary Converter subclasses -------------------- - ``Combine`` - joins all matched tokens into a single string, using specified ``join_string`` (default ``join_string=""``); expects all matching tokens to be adjacent, with no intervening whitespace (can be overridden by specifying ``adjacent=False`` in constructor) - ``Suppress`` - clears matched tokens; useful to keep returned results from being cluttered with required but uninteresting tokens (such as list delimiters) Special subclasses ------------------ - ``Group`` - causes the matched tokens to be enclosed in a list; useful in repeated elements like ZeroOrMore_ and OneOrMore_ to break up matched tokens into groups for each repeated pattern - ``Dict`` - like ``Group``, but also constructs a dictionary, using the ``[0]``'th elements of all enclosed token lists as the keys, and each token list as the value - ``Forward`` - placeholder token used to define recursive token patterns; when defining the actual expression later in the program, insert it into the ``Forward`` object using the ``<<=`` operator (see fourFn.py_ for an example). - ``Tag`` - a non-parsing token that always matches, and inserts a tag and value into the current parsed tokens; useful for adding metadata or annotations to parsed results (see `examples/tag_example.py <../examples/tag_example.py>`_). Other classes ------------- .. _ParseResults: - ``ParseResults`` - class used to contain and manage the lists of tokens created from parsing the input using the user-defined parse expression. ``ParseResults`` can be accessed in a number of ways: - as a list - total list of elements can be found using ``len()`` - individual elements can be found using ``[0], [1], [-1],`` etc., or retrieved using slices - elements can be deleted using ``del`` - the last element can be extracted and removed in a single operation using ``pop()``, or any element can be extracted and removed using ``pop(n)`` - a nested ParseResults_ can be created by using the pyparsing ``Group`` class around elements in an expression:: Word(alphas) + Group(Word(nums)[...]) + Word(alphas) will parse the string "abc 100 200 300 end" as:: ['abc', ['100', '200', '300'], 'end'] If the ``Group`` is constructed using ``aslist=True``, the resulting tokens will be a Python list instead of a ParseResults_. In this case, the returned value will no longer support the extended features or methods of a ParseResults_. - as a dictionary - if ``set_results_name()`` is used to name elements within the overall parse expression, then these fields can be referenced as dictionary elements or as attributes - the ``Dict`` class generates dictionary entries using the data of the input text - in addition to ParseResults_ listed as ``[ [ a1, b1, c1, ...], [ a2, b2, c2, ...] ]`` it also acts as a dictionary with entries defined as ``{ a1 : [ b1, c1, ... ] }, { a2 : [ b2, c2, ... ] }``; this is especially useful when processing tabular data where the first column contains a key value for that line of data; when constructed with ``asdict=True``, will return an actual Python ``dict`` instead of a ParseResults_. In this case, the returned value will no longer support the extended features or methods of a ParseResults_. - list elements that are deleted using ``del`` will still be accessible by their dictionary keys - supports ``get()``, ``items()`` and ``keys()`` methods, similar to a dictionary - a keyed item can be extracted and removed using ``pop(key)``. Here ``key`` must be non-numeric (such as a string), in order to use dict extraction instead of list extraction. - new named elements can be added (in a parse action, for instance), using the same syntax as adding an item to a dict (``parse_results["X"] = "new item"``); named elements can be removed using ``del parse_results["X"]`` - as a nested list - results returned from the Group class are encapsulated within their own list structure, so that the tokens can be handled as a hierarchical tree - as an object - named elements can be accessed as if they were attributes of an object: if an element is referenced that does not exist, it will return ``""``. ParseResults_ can also be converted to an ordinary list of strings by calling ``as_list()``. Note that this will strip the results of any field names that have been defined for any embedded parse elements. (The ``pprint`` module is especially good at printing out the nested contents given by ``as_list()``.) If a ParseResults_ is built with expressions that use results names (see _set_results_name) or using the ``Dict`` class, then those names and values can be extracted as a Python dict using ``as_dict()``. Finally, ParseResults_ can be viewed by calling ``dump()``. ``dump()`` will first show the ``as_list()`` output, followed by an indented structure listing parsed tokens that have been assigned results names. Here is sample code illustrating some of these methods:: >>> number = Word(nums) >>> name = Combine(Word(alphas)[...], adjacent=False, join_string=" ") >>> parser = number("house_number") + name("street_name") >>> result = parser.parse_string("123 Main St") >>> print(result) ['123', 'Main St'] >>> print(type(result)) >>> print(repr(result)) (['123', 'Main St'], {'house_number': ['123'], 'street_name': ['Main St']}) >>> result.house_number '123' >>> result["street_name"] 'Main St' >>> result.as_list() ['123', 'Main St'] >>> result.as_dict() {'house_number': '123', 'street_name': 'Main St'} >>> print(result.dump()) ['123', 'Main St'] - house_number: '123' - street_name: 'Main St' Exception classes and Troubleshooting ------------------------------------- .. _ParseException: - ``ParseException`` - exception returned when a grammar parse fails; ``ParseExceptions`` have attributes ``loc``, ``msg``, ``line``, ``lineno``, and ``column``; to view the text line and location where the reported ParseException occurs, use:: except ParseException as err: print(err.line) print(" " * (err.column - 1) + "^") print(err) ``ParseExceptions`` also have an ``explain()`` method that gives this same information:: except ParseException as err: print(err.explain()) - ``RecursiveGrammarException`` - exception returned by ``validate()`` if the grammar contains a recursive infinite loop, such as:: bad_grammar = Forward() good_token = Literal("A") bad_grammar <<= Opt(good_token) + bad_grammar - ``ParseFatalException`` - exception that parse actions can raise to stop parsing immediately. Should be used when a semantic error is found in the input text, such as a mismatched XML tag. - ``ParseSyntaxException`` - subclass of ``ParseFatalException`` raised when a syntax error is found, based on the use of the '-' operator when defining a sequence of expressions in an And_ expression. - You can also get some insights into the parsing logic using diagnostic parse actions, and ``set_debug()``, or test the matching of expression fragments by testing them using ``search_string()`` or ``scan_string()``. - Use ``with_line_numbers`` from ``pyparsing_testing`` to display the input string being parsed, with line and column numbers that correspond to the values reported in set_debug() output:: import pyparsing as pp ppt = pp.testing data = """\ A 100""" expr = pp.Word(pp.alphanums).set_name("word").set_debug() print(ppt.with_line_numbers(data)) expr[...].parse_string(data) prints:: . 1 1234567890 1: A| 2: 100| Match word at loc 3(1,4) A ^ Matched word -> ['A'] Match word at loc 11(2,7) 100 ^ Matched word -> ['100'] `with_line_numbers` has several options for displaying control characters, end-of-line and space markers, Unicode symbols for control characters - these are documented in the function's docstring. - Diagnostics can be enabled using ``pyparsing.enable_diag`` and passing one of the following enum values defined in ``pyparsing.Diagnostics`` - ``warn_multiple_tokens_in_named_alternation`` - flag to enable warnings when a results name is defined on a MatchFirst_ or Or_ expression with one or more And_ subexpressions - ``warn_ungrouped_named_tokens_in_collection`` - flag to enable warnings when a results name is defined on a containing expression with ungrouped subexpressions that also have results names - ``warn_name_set_on_empty_Forward`` - flag to enable warnings when a ``Forward`` is defined with a results name, but has no contents defined - ``warn_on_parse_using_empty_Forward`` - flag to enable warnings when a ``Forward`` is defined in a grammar but has never had an expression attached to it - ``warn_on_assignment_to_Forward`` - flag to enable warnings when a ``Forward`` is defined but is overwritten by assigning using ``'='`` instead of ``'<<='`` or ``'<<'`` - ``warn_on_multiple_string_args_to_oneof`` - flag to enable warnings when ``one_of`` is incorrectly called with multiple str arguments - ``enable_debug_on_named_expressions`` - flag to auto-enable debug on all subsequent calls to ``ParserElement.set_name`` All warnings can be enabled by calling ``pyparsing.enable_all_warnings()``. Sample:: import pyparsing as pp pp.enable_all_warnings() fwd = pp.Forward().set_results_name("recursive_expr") >>> UserWarning: warn_name_set_on_empty_Forward: setting results name 'recursive_expr' on Forward expression that has no contained expression Warnings can also be enabled using the Python ``-W`` switch (using ``-Wd`` or ``-Wd:::pyparsing``) or setting a non-empty value to the environment variable ``PYPARSINGENABLEALLWARNINGS``. (If using ``-Wd`` for testing, but wishing to disable pyparsing warnings, add ``-Wi:::pyparsing``.) Miscellaneous attributes and methods ==================================== Helper methods -------------- - ``counted_array(expr)`` - convenience function for a pattern where an list of instances of the given expression are preceded by an integer giving the count of elements in the list. Returns an expression that parses the leading integer, reads exactly that many expressions, and returns the array of expressions in the parse results - the leading integer is suppressed from the results (although it is easily reconstructed by using len on the returned array). - ``one_of(choices, caseless=False, as_keyword=False)`` - convenience function for quickly declaring an alternative set of Literal_ expressions. ``choices`` can be passed as a list of strings or as a single string of values separated by spaces. The values are sorted so that longer matches are attempted first; this ensures that a short value does not mask a longer one that starts with the same characters. If ``caseless=True``, will create an alternative set of CaselessLiteral_ tokens. If ``as_keyword=True``, ``one_of`` will declare Keyword_ expressions instead of Literal_ expressions. - ``dict_of(key, value)`` - convenience function for quickly declaring a dictionary pattern of ``Dict(ZeroOrMore(Group(key + value)))``. - ``make_html_tags(tag_str)`` and ``make_xml_tags(tag_str)`` - convenience functions to create definitions of opening and closing tag expressions. Returns a pair of expressions, for the corresponding ```` and ```` strings. Includes support for attributes in the opening tag, such as ```` - attributes are returned as named results in the returned ParseResults_. ``make_html_tags`` is less restrictive than ``make_xml_tags``, especially with respect to case sensitivity. - ``infix_notation(base_operand, operator_list)`` - convenience function to define a grammar for parsing infix notation expressions with a hierarchical precedence of operators. To use the ``infix_notation`` helper: 1. Define the base "atom" operand term of the grammar. For this simple grammar, the smallest operand is either an integer or a variable. This will be the first argument to the ``infix_notation`` method. 2. Define a list of tuples for each level of operator precedence. Each tuple is of the form ``(operand_expr, num_operands, right_left_assoc, parse_action)``, where: - ``operand_expr`` - the pyparsing expression for the operator; may also be a string, which will be converted to a Literal_; if ``None``, indicates an empty operator, such as the implied multiplication operation between 'm' and 'x' in "y = mx + b". - ``num_operands`` - the number of terms for this operator (must be 1, 2, or 3) - ``right_left_assoc`` is the indicator whether the operator is right or left associative, using the pyparsing-defined constants ``OpAssoc.RIGHT`` and ``OpAssoc.LEFT``. - ``parse_action`` is the parse action to be associated with expressions matching this operator expression (the ``parse_action`` tuple member may be omitted) 3. Call ``infix_notation`` passing the operand expression and the operator precedence list, and save the returned value as the generated pyparsing expression. You can then use this expression to parse input strings, or incorporate it into a larger, more complex grammar. Here is an ``infix_notation`` definition for 4-function arithmetic, taking numbers or variables as operands. The order of definition of the operators follows the standard precedence of operations for arithmetic:: number = pp.common.number() variable = pp.common.identifier() arithmetic_expression = pp.infix_notation( integer | variable, [ ("-", 1, pp.OpAssoc.RIGHT), (pp.one_of("* /"), 2, pp.OpAssoc.LEFT), (pp.one_of("+ -"), 2, pp.OpAssoc.LEFT), ] ) ``infix_notation`` also supports optional arguments ``lpar`` and ``rpar``, to parse groups with symbols other than "(" and ")". They may be passed as strings (in which case they will be converted to ``Suppress`` objects, and suppressed from the parsed results), or passed as pyparsing expressions, in which case they will be kept as-is, and grouped with their contents. For instance, to use "<" and ">" for grouping symbols, you could write:: expr = infix_notation(int_expr, [ (one_of("+ -"), 2, OpAssoc.LEFT), ], lpar="<", rpar=">" ) expr.parse_string("3 - <2 + 11>") returning:: [3, '-', [2, '+', 11]] If the grouping symbols are to be retained, then pass them as pyparsing ``Literals``:: expr = infix_notation(int_expr, [ (one_of("+ -"), 2, OpAssoc.LEFT), ], lpar=Literal("<"), rpar=Literal(">") ) expr.parse_string("3 - <2 + 11>") returning:: [3, '-', ['<', [2, '+', 11], '>']] - ``match_previous_literal`` and ``match_previous_expr`` - function to define an expression that matches the same content as was parsed in a previous parse expression. For instance:: first = Word(nums) match_expr = first + ":" + match_previous_literal(first) will match "1:1", but not "1:2". Since this matches at the literal level, this will also match the leading "1:1" in "1:10". In contrast:: first = Word(nums) match_expr = first + ":" + match_previous_expr(first) will *not* match the leading "1:1" in "1:10"; the expressions are evaluated first, and then compared, so "1" is compared with "10". - ``nested_expr(opener, closer, content=None, ignore_expr=quoted_string)`` - method for defining nested lists enclosed in opening and closing delimiters. - ``opener`` - opening character for a nested list (default="("); can also be a pyparsing expression - ``closer`` - closing character for a nested list (default=")"); can also be a pyparsing expression - ``content`` - expression for items within the nested lists (default=None) - ``ignore_expr`` - expression for ignoring opening and closing delimiters (default=``quoted_string``) If an expression is not provided for the content argument, the nested expression will capture all whitespace-delimited content between delimiters as a list of separate values. Use the ``ignore_expr`` argument to define expressions that may contain opening or closing characters that should not be treated as opening or closing characters for nesting, such as ``quoted_string`` or a comment expression. Specify multiple expressions using an Or_ or MatchFirst_. The default is ``quoted_string``, but if no expressions are to be ignored, then pass ``None`` for this argument. - ``IndentedBlock(statement_expr, recursive=False, grouped=True)`` - function to define an indented block of statements, similar to indentation-based blocking in Python source code: - ``statement_expr`` - the expression defining a statement that will be found in the indented block; a valid ``IndentedBlock`` must contain at least 1 matching ``statement_expr`` - ``recursive`` - flag indicating whether the IndentedBlock can itself contain nested sub-blocks of the same type of expression (default=False) - ``grouped`` - flag indicating whether the tokens returned from parsing the IndentedBlock should be grouped (default=True) .. _originalTextFor: - ``original_text_for(expr)`` - helper function to preserve the originally parsed text, regardless of any token processing or conversion done by the contained expression. For instance, the following expression:: full_name = Word(alphas) + Word(alphas) will return the parse of "John Smith" as ['John', 'Smith']. In some applications, the actual name as it was given in the input string is what is desired. To do this, use ``original_text_for``:: full_name = original_text_for(Word(alphas) + Word(alphas)) - ``ungroup(expr)`` - function to "ungroup" returned tokens; useful to undo the default behavior of And_ to always group the returned tokens, even if there is only one in the list. - ``lineno(loc, string)`` - function to give the line number of the location within the string; the first line is line 1, newlines start new rows - ``col(loc, string)`` - function to give the column number of the location within the string; the first column is column 1, newlines reset the column number to 1 - ``line(loc, string)`` - function to retrieve the line of text representing ``lineno(loc, string)``; useful when printing out diagnostic messages for exceptions - ``srange(range_spec)`` - function to define a string of characters, given a string of the form used by regexp string ranges, such as ``"[0-9]"`` for all numeric digits, ``"[A-Z_]"`` for uppercase characters plus underscore, and so on (note that ``range_spec`` does not include support for generic regular expressions, just string range specs) - ``trace_parse_action(fn)`` - decorator function to debug parse actions. Lists each call, called arguments, and return value or exception Helper parse actions -------------------- - ``remove_quotes`` - removes the first and last characters of a quoted string; useful to remove the delimiting quotes from quoted strings - ``replace_with(repl_string)`` - returns a parse action that simply returns the ``repl_string``; useful when using ``transform_string``, or converting HTML entities, as in:: nbsp = Literal(" ").set_parse_action(replace_with("")) - ``original_text_for``- restores any internal whitespace or suppressed text within the tokens for a matched parse expression. This is especially useful when defining expressions for ``scan_string`` or ``transform_string`` applications. - ``with_attribute(*args, **kwargs)`` - helper to create a validating parse action to be used with start tags created with ``make_xml_tags`` or ``make_html_tags``. Use ``with_attribute`` to qualify a starting tag with a required attribute value, to avoid false matches on common tags such as ```` or ``
``. ``with_attribute`` can be called with: - keyword arguments, as in ``(class="Customer", align="right")``, or - a list of name-value tuples, as in ``(("ns1:class", "Customer"), ("ns2:align", "right"))`` An attribute can be specified to have the special value ``with_attribute.ANY_VALUE``, which will match any value - use this to ensure that an attribute is present but any attribute value is acceptable. - ``match_only_at_col(column_number)`` - a parse action that verifies that an expression was matched at a particular column, raising a ``ParseException`` if matching at a different column number; useful when parsing tabular data - ``common.convert_to_integer()`` - converts all matched tokens to int - ``common.convert_to_float()`` - converts all matched tokens to float - ``common.convert_to_date()`` - converts matched token to a datetime.date - ``common.convert_to_datetime()`` - converts matched token to a datetime.datetime - ``common.strip_html_tags()`` - removes HTML tags from matched token - ``common.downcase_tokens()`` - converts all matched tokens to lowercase - ``common.upcase_tokens()`` - converts all matched tokens to uppercase Common string and token constants --------------------------------- - ``alphas`` - same as ``string.ascii_letters`` - ``nums`` - same as ``string.digits`` - ``alphanums`` - a string containing ``alphas + nums`` - ``alphas8bit`` - a string containing alphabetic 8-bit characters:: ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ .. _identchars: - ``identchars`` - a string containing characters that are valid as initial identifier characters:: ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyzª µºÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ - ``identbodychars`` - a string containing characters that are valid as identifier body characters (those following a valid leading identifier character as given in identchars_):: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyzª µ·ºÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ - ``printables`` - same as ``string.printable``, minus the space (``' '``) character - ``empty`` - a global ``Empty()``; will always match - ``sgl_quoted_string`` - a string of characters enclosed in 's; may include whitespace, but not newlines - ``dbl_quoted_string`` - a string of characters enclosed in "s; may include whitespace, but not newlines - ``quoted_string`` - ``sgl_quoted_string | dbl_quoted_string`` - ``python_quoted_string`` - ``quoted_string | multiline quoted string`` - ``c_style_comment`` - a comment block delimited by ``'/*'`` and ``'*/'`` sequences; can span multiple lines, but does not support nesting of comments - ``html_comment`` - a comment block delimited by ``''`` sequences; can span multiple lines, but does not support nesting of comments - ``comma_separated_list`` - similar to DelimitedList_, except that the list expressions can be any text value, or a quoted string; quoted strings can safely include commas without incorrectly breaking the string into two tokens - ``rest_of_line`` - all remaining printable characters up to but not including the next newline - ``common.integer`` - an integer with no leading sign; parsed token is converted to int - ``common.hex_integer`` - a hexadecimal integer; parsed token is converted to int - ``common.signed_integer`` - an integer with optional leading sign; parsed token is converted to int - ``common.fraction`` - signed_integer '/' signed_integer; parsed tokens are converted to float - ``common.mixed_integer`` - signed_integer '-' fraction; parsed tokens are converted to float - ``common.real`` - real number; parsed tokens are converted to float - ``common.sci_real`` - real number with optional scientific notation; parsed tokens are convert to float - ``common.number`` - any numeric expression; parsed tokens are returned as converted by the matched expression - ``common.fnumber`` - any numeric expression; parsed tokens are converted to float - ``common.ieee_float`` - any floating-point literal (int, real number, infinity, or NaN), returned as float - ``common.identifier`` - a programming identifier (follows Python's syntax convention of leading alpha or "_", followed by 0 or more alpha, num, or "_") - ``common.ipv4_address`` - IPv4 address - ``common.ipv6_address`` - IPv6 address - ``common.mac_address`` - MAC address (with ":", "-", or "." delimiters) - ``common.iso8601_date`` - date in ``YYYY-MM-DD`` format - ``common.iso8601_datetime`` - datetime in ``YYYY-MM-DDThh:mm:ss.s(Z|+-00:00)`` format; trailing seconds, milliseconds, and timezone optional; accepts separating ``'T'`` or ``' '`` - ``common.url`` - matches URL strings and returns a ParseResults with named fields like those returned by ``urllib.parse.urlparse()`` Unicode character sets for international parsing ------------------------------------------------ Pyparsing includes the ``unicode`` namespace that contains definitions for ``alphas``, ``nums``, ``alphanums``, ``identchars``, ``identbodychars``, and ``printables`` for character ranges besides 7- or 8-bit ASCII. You can access them using code like the following:: import pyparsing as pp ppu = pp.unicode greek_word = pp.Word(ppu.Greek.alphas) greek_word[...].parse_string("Καλημέρα κόσμε") The following language ranges are defined. ========================== ================= ======================================================== Unicode set Alternate names Description -------------------------- ----------------- -------------------------------------------------------- ``Arabic`` العربية ``Chinese`` 中文 ``CJK`` Union of Chinese, Japanese, and Korean sets ``Cyrillic`` кириллица ``Devanagari`` देवनागरी ``Greek`` Ελληνικά ``Hangul`` Korean, 한국어 ``Hebrew`` עִברִית ``Japanese`` 日本語 Union of Kanji, Katakana, and Hiragana sets ``Japanese.Hiragana`` ひらがな ``Japanese.Kanji`` 漢字 ``Japanese.Katakana`` カタカナ ``Latin1`` All Unicode characters up to code point 0x7f (255) ``LatinA`` Unicode characters for code points 0x100-0x17f (256-383) ``LatinB`` Unicode characters for code points 0x180-0x24f (384-591) ``Thai`` ไทย ``BasicMultilingualPlane`` BMP All Unicode characters up to code point 0xffff (65535) ========================== ================= ======================================================== The base ``unicode`` class also includes definitions based on all Unicode code points up to ``sys.maxunicode``. This set will include emojis, wingdings, and many other specialized and typographical variant characters. Generating Railroad Diagrams ============================ Grammars are conventionally represented in what are called "railroad diagrams", which allow you to visually follow the sequence of tokens in a grammar along lines which are a bit like train tracks. You might want to generate a railroad diagram for your grammar in order to better understand it yourself, or maybe to communicate it to others. Usage ----- To generate a railroad diagram in pyparsing, you first have to install pyparsing with the ``diagrams`` extra. To do this, just run ``pip install pyparsing[diagrams]``, and make sure you add ``pyparsing[diagrams]`` to any ``setup.py`` or ``requirements.txt`` that specifies pyparsing as a dependency. Create your parser as you normally would. Then call ``create_diagram()``, passing the name of an output HTML file.:: street_address = Word(nums).set_name("house_number") + Word(alphas)[1, ...].set_name("street_name") street_address.set_name("street_address") street_address.create_diagram("street_address_diagram.html") This will result in the railroad diagram being written to ``street_address_diagram.html``. `create_diagram` takes the following arguments: - ``output_html`` (str or file-like object) - output target for generated diagram HTML - ``vertical`` (int) - threshold for formatting multiple alternatives vertically instead of horizontally (default=3) - ``show_results_names`` - bool flag whether diagram should show annotations for defined results names - ``show_groups`` - bool flag whether groups should be highlighted with an unlabeled surrounding box - ``show_hidden`` - bool flag whether internal pyparsing elements that are normally omitted in diagrams should be shown (default=False) - ``embed`` - bool flag whether generated HTML should omit , , and tags to embed the resulting HTML in an enclosing HTML source (such as PyScript HTML) - ``head`` - str containing additional HTML to insert into the section of the generated code; can be used to insert custom CSS styling - ``body`` - str containing additional HTML to insert at the beginning of the section of the generated code Example ------- You can view an example railroad diagram generated from `a pyparsing grammar for SQL SELECT statements <_static/sql_railroad.html>`_ (generated from `examples/select_parser.py `_). Naming tip ---------- Parser elements that are separately named will be broken out as their own sub-diagrams. As a short-cut alternative to going through and adding ``.set_name()`` calls on all your sub-expressions, you can use ``autoname_elements()`` after defining your complete grammar. For example:: a = pp.Literal("a") b = pp.Literal("b").set_name("bbb") pp.autoname_elements() `a` will get named "a", while `b` will keep its name "bbb". Customization ------------- You can customize the resulting diagram in a few ways. To do so, run ``pyparsing.diagrams.to_railroad`` to convert your grammar into a form understood by the `railroad-diagrams `_ module, and then ``pyparsing.diagrams.railroad_to_html`` to convert that into an HTML document. For example:: from pyparsing.diagram import to_railroad, railroad_to_html with open('output.html', 'w') as fp: railroad = to_railroad(my_grammar) fp.write(railroad_to_html(railroad)) This will result in the railroad diagram being written to ``output.html`` You can then pass in additional keyword arguments to ``pyparsing.diagrams.to_railroad``, which will be passed into the ``Diagram()`` constructor of the underlying library, `as explained here `_. In addition, you can edit global options in the underlying library, by editing constants:: from pyparsing.diagram import to_railroad, railroad_to_html import railroad railroad.DIAGRAM_CLASS = "my-custom-class" my_railroad = to_railroad(my_grammar) These options `are documented here `_. Finally, you can edit the HTML produced by ``pyparsing.diagrams.railroad_to_html`` by passing in certain keyword arguments that will be used in the HTML template. Currently, these are: - ``head``: A string containing HTML to use in the ```` tag. This might be a stylesheet or other metadata - ``body``: A string containing HTML to use in the ```` tag, above the actual diagram. This might consist of a heading, description, or JavaScript. If you want to provide a custom stylesheet using the ``head`` keyword, you can make use of the following CSS classes: - ``railroad-group``: A group containing everything relating to a given element group (ie something with a heading) - ``railroad-heading``: The title for each group - ``railroad-svg``: A div containing only the diagram SVG for each group - ``railroad-description``: A div containing the group description (unused) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.688279 pyparsing-3.3.2/docs/Makefile0000644000000000000000000000113615134002420013041 0ustar00# Minimal makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build SPHINXPROJ = PyParsing SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.688279 pyparsing-3.3.2/docs/Writing_Doctests.rst0000644000000000000000000004030715134002420015431 0ustar00======================== Writing doctest examples ======================== Doctest support is provided in Sphinx by the extension `sphinx.ext.doctest`_, and its documentation is one useful resurce for working with the pyparsing doctests. .. _sphinx.ext.doctest: https://www.sphinx-doc.org/en/master/usage/extensions/doctest.html Types of doctests ================= There are two basic forms of doctest, and both are used extensively in the Pyparsing documentation. Which one to use for a given example is a decision that needs to be made when writing it, but there are some factors that usually make the correct choice an obvious one. Doctest type 1: ``testcode`` / ``testoutput`` blocks ---------------------------------------------------- The first form involves one or potentially two separate code blocks. The ``testcode`` block contains all of the input code in the form of a standard Python script. This can optionally be paired with a second ``testoutput`` block, which if present will contain the output for the preceding ``testcode`` block. An example of a ``testcode`` / ``testoutput`` pair, from the docstring for ``ParserElement.__add__``: .. code-block:: rst Example: .. testcode:: greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" print(hello, "->", greet.parse_string(hello)) prints: .. testoutput:: Hello, World! -> ['Hello', ',', 'World', '!'] Examples written like this will be formatted in the rendered HTML/Latex/etc. documentation **exactly** as if they'd been written as normal code blocks. There is no visible difference between the code above and this code without doctest support: .. code-block:: rst Example:: greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" print(hello, "->", greet.parse_string(hello)) prints:: Hello, World! -> ['Hello', ',', 'World', '!'] However, the advantage to writing doctests is that when ``make doctest`` is run from the ``docs/`` directory, the doctest extension will execute each ``testcode`` block, and verify that its output exactly matches the ``testoutput`` block (if present). Any deviations will be displayed in "ndiff" format. This enhancement to the standard unified diff will (sometimes) indicate where in each line the differences occur. (The character-difference highlighting is frustratingly inconsistent. But at worst ndiff is equivalent to unified diff, so it's still worth using.) Testing examples with doctest allows the code used to demonstrate the pyparsing API to be verified against the *actual* API as it's currently implemented, and ensures that examples stay current and relevant. Not all ``testcode`` blocks need a corresponding ``testoutput`` — if a ``testcode`` block is included on its own, the code inside the block will still be executed, but its output won't be verified. This can be useful when displaying code that doesn't require demonstration of its output (or doesn't output anything), as the extension will still verify that the code can be run without error. It's also possible to include a *hidden* ``testoutput`` block, which will beverified against the preceding ``testcode`` but won't be displayed in the documentation. To hide a ``testoutput`` block (or a ``testcode`` block, for that matter), add the ``:hide:`` option as an argument to the directive, i.e.: .. code-block:: rst .. testoutput:: :hide: """Output that won't be shown, but will be verified against the preceding testcode block.""" Doctest type 2: ``doctest`` interactive blocks ---------------------------------------------- The second type of doctest is a ``doctest`` block, which takes the form of an interactive Python REPL session in standard format (using ``>>>`` and ``...`` markers for input lines). With these tests, output is interleaved with the code, which can be much easier to follow when there are multiple lines producing output. If an example would contains multiple ``print()`` calls, rather than first displaying all of the code in a ``testcode`` block, then all of the output in a ``testoutput`` block, consider using a ``doctest`` session so that the reader can follow along each step as it occurs. A typical ``doctest`` example can be found in the ``ParserElement.ignore`` docstring: .. code-block:: rst Example: .. doctest:: >>> patt = Word(alphas)[...] >>> print(patt.parse_string('ablaj /* comment */ lskjd')) ['ablaj'] >>> patt = Word(alphas)[...].ignore(c_style_comment) >>> print(patt.parse_string('ablaj /* comment */ lskjd')) ['ablaj', 'lskjd'] Setup code for doctest blocks ============================= The doctest extension is configured with extensive setup code which is run before each test block. It can be viewed in the :download:`docs/conf.py <../docs/conf.py>` file — look for the ``doctest_global_setup`` variable near the end of the file. The setup code is intended to make any useful symbols available to the tests without them having to be included in each and every doctest block. If additional modules are needed, feel free to add them to the global setup. When writing doctests, Pyparsing classes can be invoked directly, or as members of the ``pp`` alias namespace. Either way, the definition of those symbols can be assumed without explicitly importing/defining them. When using symbols from other aliased namespaces, however, it's a good idea to establish the alias for the reader at the start of the example code. Even though these are both defined in the global setup, showing the establishing lines before referencing ``ppc`` or ``ppu`` in an example makes that example clearer: .. code-block: py ppc = pp.pyparsing_common ppu = pp.pyparsing_unicode However, because those symbols *are* provided by default, they don't need to be explicitly established for **every** example. Feel free to omit them after the first use, when writing multiple examples for a given class or function. Documenting exceptions ====================== Code that will trigger an exception can be both demonstrated and verified using doctests (of either type), although when a ``testoutput`` block will demonstrate an exception it should be the only output in that block — doctest does not support mixing regular output and exceptions. Both the ``IGNORE_EXCEPTION_DETAIL`` and ``ELLIPSIS`` doctest options are enabled by default, which make demonstrating exceptions far more convenient. Ignoring exception detail means that the full traceback for an exception can be omitted, as well as the fully-qualified name of the exception class. As long as the ``Traceback...`` line and the exception class name match, the doctest will pass. (The exception message is also verified by default, but read on for more about that.) This example code, from the ``ParserElement.set_name`` docstring, will actually output a long traceback, followed by an exception of type ``pyparsing.exceptions.ParseException``. But because the ignore-detail option is enabled, the doctest will pass with this abbreviated form: .. code-block:: rst .. doctest:: >>> integer = Word(nums) >>> integer.parse_string("ABC") Traceback (most recent call last): ParseException: Expected W:(0-9) (at char 0), (line:1, col:1) Relaxing doctest output validation ================================== For even more flexibility in demonstrating output, the ``ELLIPSIS`` option (enabled by default) means that parts of the output can be replaced with an ellipsis (three periods, ``...``) which will validate against any output. This is an extremely useful tool when the exact output of the code is unpredictable (for example, when messages include line and column numbers, or variable data like the current date or a directory path). The code above could also be written like this, and it would still pass the doctest: .. code-block:: rst .. doctest:: >>> integer = Word(nums) >>> integer.parse_string("ABC") Traceback (most recent call last): ParseException: Expected W:(0-9) ... While this is necessary in some situations, it shouldn't be overused. The more precisely a doctest validates the output of its example, the more useful it is, so think twice before employing an ellipsis in doctest output. Normalizing whitespace checks ============================= Another method of relaxing doctest checks that doesn't impact the test's ability to validate output is the ``NORMALIZE_WHITESPACE`` option. This option isn't enabled by default, but can be turned on for any doctest block with a directive argument: .. code-block:: rst .. testoutput:: :options: +NORMALIZE_WHITESPACE (Note the preceding ``+`` sign, which adds the option to the default set instead of replacing the default options.) With normalization activated, any combination of spaces, tabs, and newlines will compare equal to any other combination. One advantage this has is permitting long messages to be wrapped over several lines in the example output. In this example from the ``Keyword`` class docstring, the exception message at the end would normally be printed as one long line. To make the example readable without excessive horizontal scrolling, ``NORMALIZE_WHITESPACE`` allows the example output to be broken into multiple lines: .. code-block:: rst .. doctest:: :options: +NORMALIZE_WHITESPACE >>> Keyword("start").parse_string("start") ParseResults(['start'], {}) >>> Keyword("start").parse_string("starting") Traceback (most recent call last): ParseException: Expected Keyword 'start', keyword was immediately followed by keyword character, found 'ing' (at char 5), (line:1, col:6) Doctests in the Pyparsing codebase ================================== While the preceding is generally applicable to doctests in any codebase, there are some issues specific to Pyparsing doctests that you should be aware of. ``run_tests()`` output ---------------------- There is one scenario in the pyparsing documentation where the ``NORMALIZE_WHITESPACE`` option *must* be used. When the example code uses the ``ParserElement.run_tests()`` method, the output will consist of test strings and matches potentially separated by two blank lines each. (Unless each test is preceded by a comment, then there will be only one blank line.) Since ReStructuredText will collapse multiple blank lines in embedded code, the only way to get the ``run_tests`` output to validate against the example is to enable ``NORMALIZE_WHITESPACE`` and collapse the multiple blank lines in the expected output, as well. Also, "any whitespace compares equal" doesn't mean that *no* whitespace will be accepted, so the beginning of the ``testoutput`` block MUST include an extra blank line at the start, in order to match the leading 2 (or 1) blank lines in the output. So, a valid ``run_tests`` output block consists of the ``testoutput`` directive, the ``:options: +NORMALIZE_WHITESPACE`` argument, then **TWO blank lines** followed by the output to be verified. This example, from the ``ParserElement.run_tests`` docstring itself, demonstrates the required format: .. code-block:: rst :linenos: :emphasize-lines: 17,21,22,26,27 Failing example: .. testcode:: number_expr = pyparsing_common.number.copy() result = number_expr.run_tests(''' 100Z 3.14.159 ''', failure_tests=True) print("Success" if result[0] else "Failed!") prints: .. testoutput:: :options: +NORMALIZE_WHITESPACE 100Z 100Z ^ ParseException: Expected end of text, found 'Z' ... 3.14.159 3.14.159 ^ ParseException: Expected end of text, found '.' ... FAIL: Expected end of text, found '.' ... Success Note in particular: - The extra blank line (line 17) before the first line of output, which is required to match the *two* blank lines in the actual output. - Only one blank line (line 22) separating the two tests' output. The real output will again contain two blank lines. - The use of ellipses to abbreviate the expected output (lines 21, 26, 27). - Exception messages mixed with normal output. In this case that presents no problems, because ``run_tests()`` catches any exceptions generated and prints their messages as normal output. Doctest has no restrictions on normal output, only when the exception is raised and a traceback is triggered. By the same token, ``IGNORE_EXCEPTION_DETAIL`` is not applicable here (there are no exceptions in the expected string, only regular output), so the normal string-matching rules apply when comparing expected output to actual output. Two final notes about failing doctests -------------------------------------- There are two things to watch out for, when attempting to address doctest failures during a ``make doctest`` run. Code location references are not useful ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Due to the uncommon structure of the pyparsing namespace (with the symbols from all of the package's files imported into the top-level ``pyparsing`` namespace, and documented there rather than at their "home" locations where they're defined), the doctest output for failing test will not display the correct source location for the code. Every failing test will be preceded by a reference similar to: .. code-block:: File "../pyparsing/core.py", line ?, in default However, this will be followed by a listing of the code that produced the failing test. So as long as we write examples which are not too generic and are sufficiently distinct from each other (which is good practice anyway), it should be easy enough to find the failing code. Diffs on failing tests will include *ALL* differences ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When ``doctest`` displays the NDIFF-format differences between the expected output and the actual output, it will indicate **EVERY** difference between them — even the differences that would otherwise be ignored. The ``IGNORE_TRACEBACK_DETAILS``, ``ELLIPSIS``, and ``NORMALIZE_WHITESPACE`` options do not apply when NDIFF is generating the comparison ouput for a failed test. What this means is that, even though the NDIFF flags an ellipsized section of text as a difference from the actual output, or marks a difference where an output line has been split into two when the ``NORMALIZE_WHITESPACE`` option is enabled, those differences WILL be ignored when the doctest is in a passing state. It's important to focus on the differences that *wouldn't* otherwise be ignored, and just trust that correcting those differences will result in a passing test. For example, consider this failing test: .. code-block:: shell-session :linenos: :emphasize-lines: 20-23 $ make doctest ... File "../pyparsing/core.py", line ?, in default Failed example: data_word = Word(alphas) label = data_word + FollowedBy(':') attr_expr = ( label + Suppress(':') + OneOrMore(data_word, stop_on=label ).set_parse_action(' '.join)) print(attr_expr.parse_string("color: RED")) text = "shape: SQUARE posn: upper left color: light blue texture: burlap" # print attributes as plain groups print(attr_expr[1, ...].parse_string(text)) Differences (ndiff with -expected +actual): - ['color', "RED"] ? ^ ^ + ['color', 'RED'] ? ^ ^ + ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] - ['shape', 'SQUARE', - ... 'texture', 'burlap'] ********************************************************************** 1 item had failures: 1 of 208 in default 208 tests in 1 item. 207 passed and 1 failed. ***Test Failed*** 1 failure. The **only** significant difference is the highlighted one: The wrong quotes used around the word ``"RED"`` in the expected output. Once that's changed to ``'RED'``, the doctest will pass. The remaining diff line(s), where the expected output uses an ellipsis and is split over two lines (with ``NORMALIZE_WHITESPACE`` enabled), will not fail despite being shown as differing from the actual output. (Technically it *does* differ, after all. The configuration simply ignores that difference.) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.688279 pyparsing-3.3.2/docs/_static/pyparsing.css0000644000000000000000000000264515134002420015563 0ustar00/* Deprecated get a red border spanning the entire length of the doc * (class, function, etc.), and the message itself has a faint red * background shading, but no border. */ dl.py:where(.class,.exception,.method,.function):has(> dd > div.deprecated) { margin-inline-start: -0.6rem; border-inline-start: 0.4rem solid #f00; padding: 0 0.6rem 0 0.2rem; } span.deprecated { background-color: #fee; font-weight: bold; text-decoration: #f00 underline; padding: 0 0.5rem; } /* Added and changed get a blue or orange (respectively) border next to * the message only, plus a light background shade of the same color * (again, only on the message, not the rest of the doc). */ div.versionadded, div.versionchanged { border-inline-start: 0.4rem solid transparent; } div.versionchanged p, div.versionadded p, span.versionmodified { line-height: initial; padding-bottom: 0.2rem; padding-top: 0.2rem; } span.versionmodified { padding-inline-start: 0.5rem; padding-inline-end: 0.2rem; margin-inline-end: 0.5rem; line-height: 130%; } div.versionchanged p, div.versionadded p { padding-inline-start: 0.5rem; } span.versionmodified { margin-inline-start: -0.5rem; /* Make up for padding above */ } div.versionadded { border-color: #2d67f3; } div.versionadded span.added { background-color: #d1e5ff; } div.versionchanged { border-color: #ff9800; } div.versionchanged span.changed { background-color: #ffddac; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/_static/pyparsingClassDiagram_1.5.2.jpg0000644000000000000000000071556215134002420020562 0ustar00JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222{" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Aloou;ޱwKQ@T(T :U|-@$چ"W.' 8viaeVm|sPhM n OS[U>NBa<8Qn?Zoqvuro G"UgcAa$YSN4K}'ɎjV860WLkVw!_k=ֹ=Y8ռbz=v`y[CNXt+ =~[t^G[!}|j.ya?Ǿ,x眚Mֹ=G!_k=6)7閡ƬLHcjw@#RT>-A5?]y-] ui+ni %`z~'un?ZoW}\gXytf`2c jxv^$;I~Q6ҩ66U2 -mu@z!_k=Տ? YX ;qn-!E3<D%cc#u(t.uȎ 7;1 wn2\64rR!LFI2A Dn?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAEsQn?ZotP?n?ZoWAE|K>#N=r'ˋRwۺc9'O&%{]'w>$O[ +Jj'2lD 9#Jg?oEWA@@%{]'>6^I㢀>o+lW?WR٫((((((((((((((((((((((((KMxWW-6k@JD,+*E5CZ <kC<[TV<ӕ_?5oJ?UE9QZ <kC<[TQÕ_?5oJ?UE9QZ <kC<[TQÕ_?5oJ?UE9QZ <kC<[TQÕ_?5oJ?UE9QZ <kC{ v.)bO ΋Z\P̕!Cs@@/G4?Ty~0ևy**1|kC@%{]'>6^I㢀>o+lW?WR٫((j(ItѾ>A'woVnCŵFv*Pڮ/7=VI}oo5{UO>Ě*MiѴ,({ O5Ο0$BLC"4_$$1_ đ$a"9Ö{WD[IJ4 HiPw_9|Ҹvg8YX%HWC ׃ &l%p~pa:~QDVVv{2p=k*I $9$,@KZ^e;$'NUpڒMoIi5K$E\ i9' úcBc+Xm㶅a[rYZL'n8jSnVHa-=̖acTK둃].$߽^_f] #6ڶ>} 9QQ}Qu1H.cbR1Gl_\j$s,ڪL+XKpElQQRG Hδ4 =E) S2v9ٜOj:UΗu#ٽe*VC?'7> }N3I|J#n fwN4_^By6tmEn-+`_Roe+PVkqHPXUOc[_[/yL[ιtNݼcORѵ+Bk=Nt{FL)|08s[g8Ry&tXfbi5Lwq0A.\! uK$Ce= V.VYjKjf[‘m ?&rpH țzՄ֚UbNqj'tFǒ- e8IIqJV`uB7˭iѯ` `A^i:e<]jKyG-+"A<G>NUF$bYč*ףnS+jr8gc$l{"77a^>ةk߿F3Eq M $R(dt`UGQOm~yHv1­V.aER(((((((((OzL]owjL4G{ƨV&g#TaϮ;5Eޢ0?[ 3}u, >iQ`2JY^}d(FLw2s~- ޡ`:Zl>t;bPG0tiQ >;t sN:PI-FBgc|1r6VmÍZDӬ`w1 0|l|T)OL]owjL4G{ƩޢI-WPssuj Ρqqlb,JʻULVuGNi-DE"2:qoL4G{ƨL]owj #c-Ž!2·gYUB\ oy1֟nm2YiA{L&a 򍨋bH溏L4G{ƨL]owjX}nq_9B'n'iRXe o䳂I$ֿ|>Y]m&+4 |Ĕ36w`1laϮ;5G&g#Ts;²oQX?iQ >MoQX?iQ >zL]owjL4G{ƨV&g#TaϮ;5Eޢ0?[ 3}u, >iQ`7L4G{ƨL]owjE`aϮ;5G&g#TX J? Ewuƚ+:,çqҽ [Š( (/]]hnyol3"sl@p˝z[x@0SNh/=[-o=zZzܢ?=[-o=zZzܢ0oea9krտr͗#ߛ/G(V[6_GC~l( ?=[-o=zZzܢ0oea9krտr͗#ߛ/G(V[6_GC~l( ?=[-o=zZzܢ0oea9krտr͗#ߛ/G(_Wa4vS\FAfT!`-Gohz^X_pq&K6@%{]'>6^I㢀>o+lW?WR٫((o]ꩬs$i$M4Z%Z0 7c=9WSPj H1P}%Gե)O¢=ZoC֗G-h˾#6's""ּc{"z#?47Sϔf qѾjQ/c\EI6 #pǮiBҬE럳VOAWBA4 zWЛ;Y3okEeq qnJːwیTsx Ih-}V*ŽOs[9]M#߉/ngDd!ыƀީNxcX-U4Mf3u\5Z1`k_ izrZsZ[3xڴN`&؝/1/G9qӣOz(FWQo|Os I,bm>)N2l [qG{h$f)q08ꆑ Iu!Z}Sb 0;f,P\7D͞>oƅ:]cuNֹ$٤M5: D|a۪sӁ]=St9#K>b #X!T`q>r(/%- ((((((((((((((Oa;B͞*<86qt&%A*N:t..GuEq_5MJ8O iFƍcɝG9qbAl-c rcRn}уckEq뷧WMAmnƙm+HPd)kzxHѦTݢs5 UwHwiQA:GsEq#?,,TwoCRb5ˌ1>ˎ4ډp&&wA8ƕ\:Z+MJPPFѤ t< J1sn_j<\Rs0HZEce A܏AMŧa)~'WEq:!85-6TvpǻRp2i%8'&g"O6Hny a#hS]էH#6Iqۼй22mCu[+[mIZpm<ϒ`>NHRuirM3VIt!a,Qۈ;1l/zV\zic=Ν V'Da; TX%5΢Ov$6\q7/C#9a&QEHŠ(((((((((CA/A]pA u(b ( i ?)l5=OaM;KauI5t*[Ky M4B.*I9'wF_ZIot-fLӼLYxFQ~lb=WβE.[{ A78sIE j b'2GbOy8"F,;xYkXs@(!u?< %,;Cd AГ8gLYn-˅d~Vg.RHJdU It=l.mG_M>}D%ꌶI`X3t'tUј&E4 "trwwR旫 aЎq"$BȊd^O?[9I6^fh0@qK_kvN6y%Xah[͑C?zEtWv[_=m-*O$~|Uc=#@wAc*$KXK{ZX"(W{,lKm.\l # >P 4[ky}"!-w32*F.J<`0[: }_AmLLo(@>^v#9:׉-4=-Nx]Ānչ89: 6^I㢏Wwx ; _[5t7@w?Կj(((]~ ,c$X#SIֵoTmٿF~mvsqҗ7:WԴ]~YL$s2szwbumKJ?&>|w3D_<a|_e%,~ȱHHC$OGS<7qM-YY AМ\kWIFYnfǧxCZinxA(Xf_0y>}M"}FS0 |KCWn;ZO=.;f/Wۻofs9Y;mR.- 'P@RHn=3 j~ptGm͌fF>.>kŕ-~cY#'!'y'+Nӵ{|ɥI"ŔEpJ'jfF%bkvj槖=:x^ &WiL"9Ä߂]3U`ڒMOe Flmǘ逤qtՙeMi-aYF#HG_j>0Ƌ^$q낳*(%<m=jg++moīkzEw*z<{췑N<ͻ)`NGo○SVNxkj"yAȶ+zfUGIEfkV1B&7&N0'j95f7rܕ)'lضi*sz6ETQEQEQEQEQEQEQEQEQEQEQEQEQEW?'%Uj+*E5iI"CI#"c֝Y֏OAC3ǃx%AFbIMskrZ+?ZQ5BYX1"9@`J1@zW3ǙBbl')O^<Zi'&W;ju}mdg’vz!k:uuuebt#s8g%C&nG~4yn-&ivX?^KgPFGJ̽4M*6sLN@,QH_JH,t%XZF<Ty=: 籣uد˩'ĩܰrw`\d^N7[($k"0d` 9.)}7M+e+FVye6M}ܚO]$dAcw=ٶbʂ$ JsEryܐI95˘t7ftMd̀==HtpyPU6+*(9zaV NTbS\λ)jt |[R:xb"vģQAڥ5)~|Nڏn#Yvg}9<> #1ىcc#$#;msJ{]G$#V ?pN? O\T^ Qw3GZM71F?-CxmOX"[n(̠)uYiKQof8Wjg<Ēy&((((((((((((x PWw\&%_"lf (( i[ t5x@0SNh>^,QZϹ-4DZ,78<꾽D$ѭ:4P2(%ƫVIO24Sza!z8)Z0."ICwK1d"E ֎mYeDhc8sۜl3$Wֲ$k#K*\FV-wLdehP~$wvqjoUn-:}Cz Mu,O,5#1ˉV.p>xɩc|Cq j3N]9Fx8.1Z2@ %`F"س3<2\ZоN6E*p1׭GiM"Pk op|>\nۙH5upq"myB3%h0Eei+g/crتέH%t|\uw'մP4B%,[z6 A˭鱩@<)`:*?35}cJ+[QKxdxc(geRRNJ[k޷qwoikm<piraF8UBHqI *C) zѳl k[A F*gҬ\Eik5Ͷ(Pd+8^83 NĎ{$ mH F-(tx\Zěuerr*&qǭv:fy +4r6V8`AU{Č-!u39tn맮oN.FII-(EPEPEPEPEPEPkG+E0\(GUI[c 1 Z`d۷~vnv܌--1BGDog'`sbT FPT#T DIx[qn pqkivB >Aq=6 bힼSEh^qYz^k$I݅Vp,e9IUW𕃇['F5Ӫqkz^Wax'Mڅ{tLv@8rrt&VԯQxcY1 I8/sE?k>05֣w7ni0KC*+}sV:Eiz,涷#2Dk45}Š(QEQEQEQEQEQEQEQEQEQEQEQEQEIu w$Ŀ M@ֵ]=yp^Lrvs\.xĊ2mG)FFȊXdW9(kb0ܫA!GԐ+-g}B,IjmzyqǠ`?O?lx&7̄I&!zkNTkbh;Bv}W?bǠ1@dU._L(V1e@##T>#P<gQ*#Xfˠ)K3Jʓ1Ce[J+[֐!E -7.䏼1io#; 'K˜ґ568дLӆZ9!ÂF8I.vXK)hh5vuےr 0y9&i$в$~[ 2b0y#H=ANz=C7m,x X%ٶBܷb~r0*_j3-Eg\Mpp~r:rZw+<1Y?q4jk%-pY͞E#Z+XbmqJ:l$*0\hڏxn//c)ǘfR yq;ӧdUk-HbH!Iyc1׍J( ];J`w]%szw kv6JB ( ( ( ( ( ( (>@%{]'>6^I㢀>o+lW?WR٫((((((((((((((((((((((((sӉ33VA.%! X#HEIN,gw$P p7mBxM.9mR93 `͜. pp;qi-Kn'UP=W<~8ﰚW}KSd 4N*2U2 lw:ZvW1Gk*$*!fEqN:0h[_;;V!wȻ"*)_sb3\hmc ~9R2ݬ@#]ֶȱ]jLcYO<*6vpp'ۥG7dYduVKeeYsk`>lO8۾H.|Is ~so4ΤlV!C E'Ԯq;${uϔS\8=JTVB4em)/&iJ`p0ݧ=Ĭx|u,pp0H>X]glbX! r9!մ 1jnyn&_1\4A$\YiniEQEQEQEQEQEQEQEQErA x PWw[ESQEW=OaM;KacC#ii1~y!YA# AV A#:cC*UrpS@>NDoo㾺짼mKmѤQβOk{<wlŦ iN6"nP7 dG{bi$0]+ŪE~,/ !T0Gq=sM uik}:0Ҵ 2rHCxbѴ !Ml'"A{wɒF;aϠZZzݽ&>UL wP|< Y.B$'ˍ/?h`s`8#`QwaԴ[ mNnFCp͸cto}z[ >V1 }v\·Gi}=M~C>F/1zsj> .O ۴"#Cm?'dݴt>(,63MAe~%t{"FyjI_ޛio;xDPc%C̀>\1.ybxZEP #ʯY7m#XwO}Ev 鏩i6h6}]78l?E-6?%eQCC#8<`z?+hn$k# ;!߸nB9@OqcURd.Z[dGonbH 6Nԥ]sMGPPJKفYnV3c'>/hsD:>j3zT}5ͥƬ#y#W*aHָ)4ˡG;p 8B~V7y<ۥm/{"?g)}}.#NMuF[++i$!A>OӢYڤ 0D@Bp)c\#>+m ;xoZ2 4`29@r1f,>Ǥ0KsnX1A(gzuߵb\[߸O\U7YDZtuHQBZ7z %Ym.g(2HVx$t&,5[i%W QYE DU @r>QOgo':MG=*sɷDˎp:[آI ,7`=wrH\N@] Jͼ"-D#:C 2Tr9tbO[Mqm|.s7D_ FHANُ҅þX&cѴ +f֎:$9KW(\)Ӏp}?>tJ;-ZAH,w6G\Rx&w7&k";',L@ `u7;*(w kv6J(?mt ( ( ( ( ( ( (>@%{]'>6^I㢀>o+lW?WR٫(((((((((((((((((((((((( >[.Q5+%[ "UT1}0kP֡C$o'n8d@%RuԂk{Vɽ#H.@ &v{'Mr$j-8XP#Oآzޝ,hCF7'ctN#G|T6!nu'K`X=G+͒8N:I<#lc/V56cr\-ē*У:Mnh$tbF,!R' ׽ Ucu$Rj(f,dfU@3+qzpiL̻A'\[>) 36dOR91Yx6ndV/݄bά@A] n? ē*>%[lO'4?K:iLZgۻhnۜkV5E∦[]+r.c+<'$ "F$FeP 2 E ((((((((ӿk_ ѷuW7@ֿan뤤HQEQEQEQEQEQEQE+]jr*T;(beB9J% -Kk0$J̞V2Pq=˷'}ѿo݆r!a#hr73{f Es*r޸e*Os?$9gJ{ҢX+lYںúĂdGÎ[AY:}w0Ikm,s6n#hՄs{M!kmhm&8gܕi㎆Rx!Ido-ȁF߻ 1S5gkuPm39N˿`Ro[_tZnjikkco"bL`v,u(o![L6&d#[ sntd{E>m܍>ǒ8Mucm鳬ڥ7,s"1WEo'vv871ʸu6Qciye@r ҕ9I=;J}鐉m"-yv:מ$ƎU+0Odd/Uy'F3pcM)p1S[h/#xgQO|}Kg4[Bc*J ( ( ( ( ( ( ( ( (9 J? Ewuh?P] #wGOUw6xs#UҤʯ0P)q"ɒ[Hn9sYTc,0JF:QEx@0SNk{Ɵšw@QE2(((((((((((( ];J`w]%szw kv6JDQ@Q@Q@Q@Q@Q@Q@ |mۿEk@O7@w?Կj+o+lPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\xW_)OPn*Dlu ؊H]lixF żRVwmnb8hӃxSԮ-fOKh#d|-Թ }ђHp'ev$HbydpfcM.eإkor"%B3.i0~P37c5];hVKpL2H'5;X3/e%?ʿWUU* $FiC HnHݠqZ)ܓs̰$uHXk:.׷R:rʠ{?[k{]9 PHZKȮ$rO}deq嫗>c)xF6Ws,,ƈIS&7bV(5]3iepʛg#[\EspxA\r~a(_ZuMj[;GUHP=vb`uw]{6߼n{m..u{ mJ}_xT s rY|fpɥHen*63CsOG\ͭi.USex$ 4'ڴUֱ.aN,#ha"nQ\9-SmlfXd8 ^c>U;^Qnl2Cqn,G@rïR=ҳrIբ) (((((((4(  @H[Š( (((((((((((((((((((((((Wwxow:(º]s u/- ((((((((((((((((((((((((+*E5tIu4&ц #Nz RK4 'Hu}:ۢQR}Gk/l0LӪao?Sl3,4AT/̫a=E3ij[%$F#anT>sP2>b$v&rj-|7Z2qN 2K.ݧ*8ӥ/#Yf EEk hMTg'理K8ƣ^_:Mʒ Hb1+_{AmNѺl9(zM7fJqt>x; XnFqp8hZr +B%+ 6B->czds0h%9,LdVq{zE(e41!$1h3ҡݍO',rn.%XdrVڵݮlͨLkt[=أ79<'#Oʶa𱈝xȀQk{k[7t &q`C;x3}+ˉ;XF^LB'$+Ix1%jgLIx )xֽ4Y14"<(dYxz=W!a1 mh@ˆkmqŷ{}PuOާ\M(l@|ÿ~r;`s/}im{e!y)T;Pgk|2MJ-= )5Բ$X]0N P]vC F G5V  u}+kd#NZKq n!v] [ -Kf`R~cFwMy^d{ILar~\tEaʻ1-n rKLd XH9ϽIi]Os$W;sc8ErERQEQEQEQEQEQEQEh?P)WZoݧ8m ~Pӗ.sٱִF2P: Tl<7lz۝]+)X ٌA.Ӛσj6mpjDX0޻ c5CUuxl^w\!@l+H6O9s*ishĜ}tëe FӌR}HGwMI"TYuI"z`W9GZ'RG鯮Eu)YQ `=rzvlǩZWkήdC6FsB'F/;hI5:%ZW ebv3Nj̾f1沤6G$d3Z tH=LOk eRh2="3xЫE6FאOѪ7?TDڭPn￞cT!Piu)#iF䜡MGv+ǯIu /́yxn;;Dϱ&E4ɨ٤ iT*3U{]o2[N6M%IBd+еkkY`kipPz(WZ_ i_$P[Gyx+%rzdwYnһ4gE`L# 6[y~etUGÞNE[ԼyqkOG.aE"xR ĶbBʤS-?1N:Y Z/[km՟s;ʁB#r0TxAähmḗVH'ϕ#\Y0pvYxb;xF(-v )eCFGL;Olqu ̥yUpNz^WX}$3"(ʉ&ThЖ6xS*[J2yL\f<ٰ||-xMFE!oBxQ$rrjlGooppqpe?k 6%:m7VDhn0j&I${إ7A{Cꦷm<9ao{5Ɂ|ǖ{ΝM݋V0A{m!cʡvzơ}wH5[f@ElJʹk1N![x m ˜OڥAYL7L0o>ʅ$``:9qY[t{CH%L)l\de Ѿ{o6n}.? <[p ]_O@ݶp/ko&Ƅ~bs Dc^)cHC#`zGQY>#-IYHYیmGh^7%T`b;:cq,xPA6uYH'{O4ە6#zukhM8ϵE&mg_.đx|V$ZE'EZIn>o[@6ʹ>`>qVt ZCΣgk=6ƞd(Mĕlqvݪܛcqm#PıUG{8o{Tk'N0rwM;FB8=^*W6Qi32+yM)IY6"($ ϵT̈o -PJ(I`(c\ճj7Mq..@1Oz'g,-4Z'dvo/l("0}lZz]4{-Epm6oz5$Ɩ ţQ)œ<=|:'}|~_";sQim ¶KuT`3V[I"e!TL0PI۔N[uۼ>|4 ¸IF!4*t6qۏjJ[{\}kcT KƘ zQ۟OX1ʹ\I.P LpGV^yal-H5 e'1q'vZA"g`ێ6#W_ (O|ܠxo'>!彨2jx-7IK,ct=) ѨH$ -ți\¯m\U["]%V|+"8Y1ؚtxN_'%lc?Uk_ ǣr,Z#':'Ir>l:Lۢh±}e*Xc8oJߕI 34WWSħu8xgR΃n<+tv@AS ZTqEmᴎ$]M{=օV'[h,\[bC, #ݎI<8\Q7mdiH ه85)_BdwmۜvN+"zm~odi|)K( |йny{i5,v2@vKX֒̄%ߘZ%fO+l (8bOCgms) #WP1ʊH xEbpUۆ/*0Rp9ϰ8iZQ15_=@d1-E*7J4HbY)98zu^L K]de7ny{7j>*Ů`{d*7[j *'+a^ͼw0ۼӶ-lsN0:W=wg s[2G6Wo!#fNB3玁~,P,HF8?l>m}?,I%/x cWC+[WVZy ]AfwJ ޸Q bW#9}{MJAd#U,Oe9K}ȃ|c>\Q8:D>I0}c( <;`\mm0yѲȇ(pWZtTx}g>nluznZw̟ؒ_`U&gpBVp"xri+C(hD1J4w9^'@.\˹ER([VJ'i At ( ( ( ( ( ( ( ( ( (9 J? Ewuh?Pz`?O~3_XYDNEh&@V wqU}$` Haweq;ԙ"=:Nxk @?}zH*Y6%9}\N*ދ̯x gc >`09z^=tqlۖ "W$H'pc(~ߠ^:/SItIg &GUq ǜhZE8Qvs\_rZGpd`iDqzEBd uTmҏ6լ1'uۆRBpw>6\]G(HfV]%9ڣ\o[fk1E2L(=ANKy与@"J8 @+~R:rxzY-ۿwN]:'r4YI8un* QEQEQEQEQEQEQEQEQEQEh?PQHzӤ^Ěvw3 ke.Gl;Fyvɝ!e32PFۻG"I>ڳN"v0|EcAB-:ⴕٌINwL~s]K4Wx~jo(pK>].uY^Ӛى$򋎪$۰Gj ?Hlm+%ϔnǟvyc'WGmgZX'FBIl-T-#;)|;d$I95?oHLY(JB63Y/0Icv~tգӝe #Bd 8,9=sk's6ևS4I* 0O>ƒxmfjY-Vr][ZE d1,T{vo4̇E*As\$]0ۼ Ǯ6WZخgus##JH,t%XZF<Ty=: 籥}u8KG 's"g`1 9kI;!ڹ$n`d/ʅ'nzx{8$. c?W)g{a(-t2w]1ʮ>P|S~c:Olu Uκ.v[N˹*R}(,(((((((((4(  @H[Š( (((((((((((((((((((((((Wwxow:(º]s u/- ((((((((((((((((((((((((+*E5tIukh{K ,0>犹o:][d chVS&ц #NsMnPlxm^E pk&6)yqgu#4 n aAs5yg[1V$d e :?cVP#=,OcM[dm8V By_iUC/7o3f}kmm_RGfbO^ID%E;ytM"ݼvi98!9s7 rvAHdWpdJrĞ8I9'='Š8#7V$mmx/1G2O`k0ŵϙ]E,Is&"D̻r@9kƑ 59ؓjٲ*i]!ȺYP9d9p2~POC^YH⌢줒?3N2`RyW=[[uiMŢ.*ni@띹;\85 =]9'-ɏ|;W^3~leG?ߥ8 Q궊ii'?\7 n ԒpqU%m泗UtndhdD,Tdc>WlqyQOn8nEF%S!q!R"opqq;HlAw,  0pOyTs, kuGgPGLwPiVrN{ܙcL[a$7=9gWjɫ,.z|`f#kyQIF Vث5jҋo"TIEGG?ߥIdT~p~yPT~p~yPT~p~yPT~p~yPT~p~yPT~p~yPT~p~yPT~p~yPT~p~yPT~p~yPT~p~yPT~p~yPT~p~yPT~p~yߥrA x PWw[ESQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE+Bvl"Ύ?'N?$Q >Bvl"::+Q;\_G$ .s}GsE?'k( 3IeOН/H,Ύ?'N?$Q >Bvl"::+5KSӖV)^F`왈ݺ5eu # -Q@Q@Q@Q@s;y_]覮H~y#P#&3p0Q(ONݣ׮FBygh\L dda8W]7Yp ~[5Rpyl.Ƌ\"Asa;т`,pU[^ V.)켞b#bpqǧ\NM "6 ȃhU2pBQNG O,34xc&yYcrc)Re70,BGqyziH~+B/n$o5]OcS$#E,M6}KK 9|,fR1k[oҝiGEI7T/+=6X7m$YRI2HN#!mYnKg+%/>qR#PQIuipVTXفUV|(:)b 4I* S5X6,r$@3ŭb ˟-eQ9$GoҀ#GoҀ#GoҀ#GoҀ#GoҀ#GoҀ#GoҀ#o~/?ߥH#7@%_"4( c7QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE|JnO|mۿE}?WR٫WA@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s5ӿk բ+((OǺ4Z冗g&+p WVw <9g]ͶOv5r=Q 8nFcclrq5g`NER Q[$BI.+urO+XlD,QEdQ@Q@Q@s;y_]覮KͬWW5kxBBt* '>+kZNC /%$i?Jghc 8#!GZJG%$i?>X?tO@F]8=T)_ִ5I&m5BxrI<9nz? G?OGJCRcV_Ӈöf4q 6A!Iʞ=XJmGQ"$G3 b c;<` G?OGJM)!8Cy˹.5bv yg Fڸ``1Vl|!0kaS"FDFv}ixW z?('4I{ְ!{CPM#Fɍ 2'XIsmxgHlnIiIV[8Ab[yl t4QEQ!EPEPEPEPEP\޶%EoQ_l{eȤ$ezJuz֥RH|טC-vU Z`HWnц e-}@n( ZjІ$01'9B]^O[ޯ5+{sm}%v].|I0)(((((.+}2d(.E'#* 74i2m൫(hHv-bNs1fuz֥RH|טC-vU Z`HWnц k2x|9[[k.f+7$Jjn YY%78T /,)ee9nQ#ԼsizHKH,g杞iaPAp)W+921ƺB8v/֥_IW ɑEkG+p}9*7~,Ai8VvmK{hc8*p+;7vp,dI:L))#p%@ zY+[\;}Vm$p6nx ڟ6[ͨG2Dfhe #%)=|%[8Ăyr@E%P)IVF8a fCa3U|qUYw&_&/X^{M:8Ryg 䴃$N3ZqzTjVx̒9wƸ,#TggQ"%UURr@s׽f뛋۩n5%eL%l 9 )@BF^%΍5&[vSNT;f  9 Ty@Zʲg$`rx =XZ4 S`6#!Cݎ*+O^i3Ar_&-!(%DN34x,zޕ`A}B &Bn~KbmM6f zcg5ol2)`Ĝ9'4e%ii͍Jg<Us 4wv&W%{XGD%K;q}5>e5cdPCP@ r2zGgndI}B/#3[\:6^I㢏Wwx ; _[5t7@w?Կj(((((((((((((oH\K{4w"ȤnV_5Ep>-Uv?fɪ߻3]vp>-Uv?fɪ߻3]Y`MW񚩪YxH/u;k$V%8O\ j~!پcm#h=B/#0?d0+#M3"dgZ~jvYc5D!") ;޺ɪ߻3Ro|E5XK, #iq&EWmIYwG 5_cho 5N.ſ2j5_ck L;tnok sop96+/~? \ \/~(/~? \ \/~(/~? \ \/~(/~? \1隈It4*zbVPEPEPU:O.'gNPKN=*s;y_]覠I}oWjMtE{ƫV˜S+]'}^?5[Z(S+]'}^?5[Z(S+]'}^gu?vzܗWZ}0%1`dֺ(S+]'}^?5[Z(S+]'}^?5[Z(S+]'}^?5[Z(S+]'}^?5[Z(S+]'}^?5[Z(R;Z7K5#͜ HH%+Jak%QLG?'%Uj+/ĺlυu}.ݣYl$(gBqj%;y4GNacv@@(r(<RA\FѬt}Fh,㷍,U(' gPYEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%PAEsct?MT}M7%P'%UjԮ?Ɩ*_5HrdHQ| nHqk+2(((((((/֥_I]mr^K,#+R>6^I㢏Wwx ; _[5t7@w?Կj(((((.6]_TX{+)#Y*YdzԢ >& >& >& >& >& >& nГ<j[ /PyO vg1Oɩ)mF{QDrL۱`0TץJg;}OVmWK)̵R%vg|xWEE7pJERJak_*ׅop)*9[{ PȡԌA8IEs7O*m2[߃6q4Ygc$Ï29 m (F? dӧٟcՏ1Ѕmc0eR@`!6]i?o1|k3@,GzonS:ӓz \ʷe.m "nۺ#vSw$z._D?{{hKNsv'4Ơgdۏ9y{c-mDc8yIxO(Gvqr]ӿ\-;5ځyh vs8Eg( Bp k,/D?{{k&[^0RHl.̱^j(YdHna]q(D}w -(LŠ((( k>vg6 p Obox$1S^LdM'ӱQOi_6ğҿm'#}E.D('4IQOi_6뾢D('4IQOi_6뾢D('4IQOi_6뾢D('4IQOi_6뾢D('4IQOi_6뾢D('4IQOi_6뾢D('4IROkj^t\wE?yrC&&X5?ZEz׺z"H`VcMB8bbdxW z6\ '[H\;Hb8+xn⸷9$l]H #ԕI%l(b>@%{]'>6^I㢀>o+lW?WR٫((ֵFX4:kyoE\ $Ga?^-i(oKſ?s/"h9is :Jw$Ŀ MQixZ'eZGujzO>ۭ%mЮ}g2(AfvW7h9hoOȴs :J+oOȴixZ'eZ9Y%ixZ'eZMi n&dRH Cd,>dgWE67YcYXu1殞!IҴ"%x?<(u/ D̿J(oKſ?s/"h9is :Je ;o [ Gh9k?Y-c"wmsZVϓ2Kfvc=zQ̂(oKſ?s/"h9hAftW7h9hoOȴs :J+oOȵ'-}7\Ӭli9RSAOCN酙QEs u/-  ; _[5tQ\T:TzψH=pĐj0"'m#W;"Zwk=.iΦӿ\-;5\9Y\"Zwk=%;G:Vu5Iu%;Q"[{ I+ .#Q΃m%;G"Zwk=sgSEri?o9Y\"Zwk=%;G:Vu4WoMC\yõ6*pe7_ڴW&_)((((+*E5tIu*ַ;G!gk<㵽Es?LovCy{kz.!gk<ַ;[Qp0?[3~^ޢ~?Z/\ Cy{h?Lov`ַ;G!gk<㵽E3~^??[(?~?Z/oQE4[tv.Mܷ :p38u5%Bo5VQE1Q@Q@Q@"?ng$_ Zvr|RpX8pXo^i?'lGVlG~14̤AEG[qo,sA*H2AG9sD)[U5 whi79C ܜ,'bmW3O∵$zvrRA,,Z[y/T)cJ屹{ڛ*y<{R^>DĿG[@M5b˹4~O /섳|v=󎵛?m oѮ&c(AR @aA$j[@M5ko4OKެ gX6]_DUJJLrcKk1ʿiW|;I(@@aVh8_ _Fb"ZU5jkTGy :g:s~hcH=30Ky2ykc[ko4OK}ſ?q/#Qw{Ag:YxXsKVbAhKu'&_:u[\_Aut%s t$]PĂrz:_ko4OK}ſ?q/#Rolt7WW[&Y%e&S+)v`~EQNiumcs,G+2<<q8kW~-&'%j5.\$913b5+;KБך/,X/o/#ў7p76 |'9h8_ _FVEXAG@8Le29KzWQX?ko4OK}ſ?q/#PoWOZ_ _FsVWZO4/췏>[g;LvOLr㸥QElfQEQEQEQEQEQEQEQEQEQEQEcu<-äb {g\=W6ғI; ȯ4ii+Cg?ن `lmo/q:( (Wwxow:(º]s u/- ((/(/mlV>%E]{G`*FWxMYw5֝m=Hn!`26ȩϬAwX>֨FكAbG$c=Z\=R[HQ I `/ݸ+:Յ~׍f-\[&(< IwR¸>FZe\o?r?{-h-(WA\sa]KKf9C+Em[uHn`*FGV Ѵ{p4bH`uAԎ2>zGIhEr4H^`R+;quhMkVO6\1pϽ26I,#ԌZ-bB'Bsұu^݆aud^͑q66֑˳yji֚mPLJ.%lXMȢ}p8dcgA L H4f%A֭_j,fX (u9R>t*o%^[z+S\34̒fݛbHgh%} Z(aEP?w_)K+7OI`եI]O6"FQVHQEQEQEQEW?'%Uj+*E5jQEjQEQEQEQEQEQEQEQEqP,?uw%Bo5VQE1Q@Q@Q@Q@s'WaHںz4O‘L*;tQEbXQEQEQEQEQEQEQEWOZ쫍GZ'eT7;(3 (8χWWC\y_36H3U/O7%T~襭Ǚr?Ty~0ևy**1|kCg伎A溉JG;^B]L N<%CN?8 :' "z@`q/tOEW?_zmkNu&v$`e!I8䀹 Q;uIXIX*\4ozccV^_ڮ-8Fq DŽi?aRG%WU[Gc Ӣ/*N<%CNޢf'D_UxKUE`q/tOEQ DŽi?a[P'D_UxKUE`q/tOEW9kF-'+T3 .m'z q(D}}EVg?WR٫WA@-^'Rvse`c*ch8_ _F,k2dA+ʄ@H#_ _F~-&4aԺYA#4_ _F~-& 7x:mevU$)vϨ+7OI`եI]O6"FQVHQEQEQEQEV !ILHK3I'VǷDb`pAѯ2CMyƫGF1,NƛϿ>QȊg= Q WCϿ>G&>9yj&TȾ zd/r(fBSH 2UA"G&>>D<5_^?<5_^4hӿo39O4?MWןjO4?MWןjM;}?4hA{U5U5N}ƏM;}9s3a Miض-!-%.X"8=kz=R,H`w~5z+QE0 ( ( ( ( 4O‘th_#+jTw6袊İ(((((((79hіWOZn)lwQElfQEr襭>oMF1np = L4G{ƫM+ 3}u?0?[`7L4G{ƨL]owjE`aϮ;5G&g#TXxKQ{ç]Ѣ3*8in]?Ku5Ԯcy =´lT9߼L]owjL4G{ƪOĴMo 㿼]X\Zhy7 h.};Z+ akhV$r+LpAPXIFp_ >iQv$8'SJbt;y٦_R>nw ,o P;N9L]owjL4G{ƨm7L4G{ƨL]owj7L4G{ƨL]owjE`aϮ;5G&g#TX |Q#`kZiW9kڷE|VyV3[2[twtq+QKch(ow:(%{]'WA\sa]KKf ( (9KJ`iCjk4Frm6ono 7mw95/(/mlVRJ+ծugֶo#ӆfpKzꪅjs B=Hzd)َIdgI+xiJ,{ #ߒ.3\j%ENɎfcuA!#~b s9 ;x#n]ӍTg΁DES?s^j]oa}i$EoJHvYCG< 6I,w4ݹ*}~[:5ۢDiUV26K`׿0t Y Hڥ,G&]*K 7vzUEDT@T`T[RNחkGZ'evUG-2֜7;(39º]s u/- `[]h TQGQmRMޛ=jvSwOZ%% -Kk0$J̞V2Pq=me*Os?$9gJ{һj*y\5il$5 ij36S8O覭/ :O?'SV'u?V؉QEY!EcLng'ukM klTp@T?5oeHi\cV[6_G&C~l=bj9kտr͗#΃=bj9kտr͗#΃=bj9kտr͗#΃=bj9kտr͗#΃=bj9kտr͗#΃QixK5]V&%K|@r|?]NII&qX⾈$Q `@ؚZz~7lu3 ]~"Bg=$#hNG:jt'R-lu Fe5K,BaFC#<5uy>%$;d*cr'-dl2Wey[Iiu'R߼ vX\s9.O_[zueI4/8<:Պ[@-2-^-dgIEs^-/ D̿G2 3/ D̿G_EQ\_EKſ?s/"̂(oKſ?s/"h9hAftW7h9hoOȴs :J+oOȴixZ'eZ9Y%ixZ'eZ?[@-2-,Β[@-2-^-dgIEs^-/ D̿G2 3cD)[S[@-2-`.xVMk@["fXמnTr:¬GG'se¬GG* /Jtt{0:+Y_.U^auW'  ҿ]<7@+Ø(Og:?VxozW ه1WOZg:eIf3X[Z˰hWʚs* (9_?Rr{h a S\ *jK)^[lV֏-U1tPTr݇'*>ViL[(c9Vc72Z0C$3Ac!y<1 IE]uK{S-Q̸'q1 dMNF^OuzxHбU2 Or:#;+ cP_&?,Ds3.XFIw#u9mUyv1u=z=xPot*IflBev #|3ȌBrpKm78'͔u$-yPJK*09GQ\& WRV?,,H C$s=NΘǣtKd.5 VdA7øQ_ V^ 4ѭXDD^H\vy{+Zk"I"w kwb ;Km*mv)M7duW.o@%{]'>6^I㢀>o+lW?WR٫((oR.FVU׼9xbԴ;>S۬<=+Y_.)X(Og:?VxozW uW'  ҿ]<7@+Ø(Og:?VxozW ه1Q\* /Jtt¬GGcS7aFKOU^k_%\Yv #.FpHf'#urO*G^EQgv c8*9 ѷuXonu6tZXb dC#)lA̍Ў++ſ2jrnY}`MW?|[C&~.FCſ2j5_cha̎?|[C&~>-Uv?fFCſ2j5_cha̎>FZ|[C&~1<+{,0 BBrvsN0i(9º]s u/- m|G'UiS6w7I AAև'D_Uo__.a=#vCJFo'D_UxKUݟG#v.@38 :' "_40/F ?C(c7 Ӣ/*N<%CNVqh\nEIHdDA󟳺`[VU t2n1T )|ixYKi~۰#Nn2dҍ+[ EVӇnn|.1S_^x6VP\OiVkwf>`ɶp9%ĥ{y_j(Š(( J? Euh?Pщag.-"*nGW?`=_YH6 wLv$c^-:f]>r{}j&vUKcU#zwEYXm(b ( ( ( ( ( (9_?R`IkG5W *"FԔPEPQp.]>IEQEQEQEQEGVј]YNKIܚ((79hіWOZn)lwQElfQE|JnO|mۿE}?WR٫WA@Q@Q@Q@Q@Q@Q@WWڗKC\ 5,p%䞔ҹW-?oi򳩢oD?{{hKNsvth[-;5?ӿ\+:+KNsvD?{{hAΦӿ\-;59roD?{{hKNsvth[-;5?ӿ\+:+KNsvD?{{hAΦӿ\-;59rσsa]KKf(|[!H&bBS[PY%XOrI?ӿ\+:+KNsvD?{{hAΦӿ\-;59r o xMK"2y\\ek#GwI\MX>7L6t,,R8erd6:LHU5/;YtgQ:1Ƀ(&F2 1Y hhvY,"RUV/B;Euo4MIkj1\Tq)(p5(Q@Q@Q@Q@xW_)$ 䊵'%UjԬ\LH5?eAП/H+2H5?eAП/H( OoYEj'+zS?[_G$ ޢ0 O$Q B~" H5?eAП/H( OoYEq iH"fB>SӂG55_ eGV&GE\-=*:fԣu#bc8<?? GV3ب3 Ӣ/*N<%CNޢ,_40 Ӣ/* N<%CN?8 :' "z_40 Ӣ/* N<%CN?8 :' "z_40 Ӣ/* N<%CN?8 :' "z_40 Ӣ/* N<%CN?8 :' "z_40 Ӣ/* N<%CNMr i5h$8 »j4( pܙlwtQEj@QEQEu+;KU7=nɀoA%B_ "ºM[z-A%B? ' jψG+Ky%AVr`;Tg$`Nl^ROkqu%ūH[i"H '#@$ _A%B? ' j1=(3V8]L#Fтe%LV*,/v]n@X 5@I?V?_G [D|_MS?Wشm-<2ڬ{lqiYNW="($(ow:(%{]'WA\sa]KKf ( ( ( ( ( ( |$ K]Ur襬z( ( ( ( (0iE-hbܨW ۗ,2G'qxGA1H.3' Cb=G^mMypꭻ<`K'9\-i{k[U*=2Xc8|+oqso>E=oZG̼QNѵ=zK-O$rTH*q}+xaP$i|5C ( ( ( (8>FZ}\?r?{-k9ºo]s2t- Q@Q@Q@Q@Q@xW_)u5K.Tn"Xe!iMY𮯥۴k=񴄅 TN2} sxİ$M%jc ׵Dvլ:umndI()>I#5K\{IFKȆ?M, u+ğҿm'# G?OG}0koO\buX ;"

ki!Vuh:Vn :} 2Wty8OJWCs־02h+ưyh \K<3@U@=s[&i+mC#wxK0999Tji w-I;um Vs^0M=\̑JN\g*&OS2U&="&2IHkg9ﶵ4i){tc|Y%1xF9a' RRC/>l'{e-͐s#93Q7ilNYE9d C~az[_%mvEcI.c< 䄢RT \R-6IZ"#`? PZڥlYHIc@*zDh?PuMH# 9GW3qKZQ ]E<\m zV<[AMdoO4-6^NRr$Ũ²C"vO>1X!5N$K{/坷*!}` cw& 'h'7_I CR mɘ۔e%y; 9߆:UOơ=K<[sm *A' 7b> 'h'7_Iw ǂ']fƕ7G$B0rcjH (Gsް 'h'7_I{\%_"~ 'k‰w5ſ F7&$?pc YPR*( (uoźkC*HKWR2",Gz]'}^']Zެ25[]'}^բ8r_?Q >jG8r_?Q >jG8r_?Q >jG8r_?Q >jG8r_?Q >jG8r_?Q >jG8r_?Q >jG8r_?Q >jG8r_?V}i|CyZUXmiyv8Q]-q(D}Sl($(ow:(%{]'WA\sa]KKf ( ( ( ( ( ( ]x|-mo&*3/%EN=Mz-r襨Q'%j>h8z$o e< ̳~-&'%j7M97)'#TDĿG[@M5m3UI uKd.=0}~-&'%j2Ƴ,FD,O$ d2?1O '%j>h8zPc[@M5ko4OKն%Љʪ?0 =iDĿG[@M5oS"9Iadet9 B(~-&'%jVW#5%GDfp%N8 4DĿG[@M5nR7 d 4̱Jಡ<1b}ſ?q/#QDĿ["GN3dEt`e9z_ _F~-&[@M5ko4OKսEy6/[\i_o}߼wD뜞kGZ'ewմv3?/WMk_AT (((((/:.o-f8ĥ"V zV_E@SNkVRh^-/ D̿[TsQh9hoOȵE9Qh9hoOȵE9Qh9hoOȵE9Qh9hoOȵE9Qh9hoOȵE9Qh9k'᷈eP垹 $r$1U vu_ eGUM%chButx55ԓRF4ATCz+Р}s~lQɍU1A&4fm/ i__ ?>g>߱SȇCiVO?G&Эv~YϤQ ?9s3_ +kݧ}} bD?6mom/ iA~`H?أ39M[[?KB}g>߱G,(ACiVO?G&Эv~YϤQ ?9s3_ +kݧ}} bD?6mom/ iA~`H?أ39M[[?KB}g>߱G,(ACiVO?G&Эv~YϤQ ?9s3_o ϊ;짳[6(hG}n}} b8xFP)&MEU((% ?Y5nͽvԢy08nqI >-Uv?fpw-I}`MW?|[C&~.FCſ2j5_cha̎?|[C&~>-Uv?fFCſ2j5_cha̎ J? E>-Uv?fs×^5R\fy[yK5Q"QLM(B(WO7`_X>襭fEPEPEP ڶ;_jF)9r~߅<sFDV3_j]=ۿHmk g-&F-F}6[F"xAb2:4fcXom˛d:9>մu9ԚH ^+!YLr59##sɠi677 ukp%Hz-2R3]Ҵl-L_8rd۷vq*4;$-4m:81C'ڜZ[O#;=ގbx9FA](lx]uvw' eILǸ?/Z#Jӗl-F x'׽vi4e,;hV5-dgϵ-tQE ( ( |Q#`k]q(D}}EVaEPkG+hCw-mbH+ ~W+']Z΢.=voiqw%ԑS#j푟ZQ7mͰ8iceSq* 8c/.pDr5`9{U{}+W&MV2Ћ6!vBQqaF+"]4oϦjkkeY{$sn#o_ۆOӵ; ^H&mdC6m ~g<֊j%% -Kk0$J̞V2Pq=me*Os?$9gJ{һj)s1+m.,rvx+V"2BZk"#e N37rSH3^ Eo%c7ͻ #:`dkK-u 'Dݔ,_54S\^_%y"h9UڅcyA9}Ar #V{kin&P[Z zLc;QK|Y2i5h^eY<*d;2`tn=ao5Ri.ɯw>W*;AE/C-/4EnngiD`$`rᕋcc75mJOT\'ӳa9{s[TQ}nh^M{kgQ=̅!]T62x+[@ 4[rF4c2ĠJ֕^J);)QEq(D}>FZ}[Cc9ns2t- e ;o [ tB ( ( ( ( (9 i[ j7' qq*C ZI#TQy $w8 :' "9z_40 Ӣ/*F DŽi?aG'D_Uz_Y7fqdb)o0lEbO cO ֻKyRhe$l]HG޴2=v( l9hрM R m998?7tM+ X2ʁo`?bsGW3~^??[xM+Cq#G$E?pXqWܳm!@#5o!gk<ַ;[RCy{kմ{m'ZO٥7O1-yzxA^\o?r?{-j;(3 (>@%{]'>6^I㢀>o+lW?WR٫((((((_?RU\m/ \\D*.JFNMEr<7@+  ҿ]O+(Og:?VxozW ه1Q\* /Jtt¬GGc?U^Y_.fYEr<7@+  ҿ]9VxozW g:=se¬GG* /Jtt{0:+Y_.U^auW'  ҿ]<7@+Ø(:}IYt1u{KP   ҿ]9VxozW g:=se¬GG* /Jtt{0!GZ'ewY|=tٌV/##򮾭++_A\ma]7Ka((((({ƿšwZ_AaM;Kak,[LeDfrcu99㷭g=ZE'd٭E5+(Hc#^}S*R];]u2m720voemp:!8l  oc&42 S0>'5\OReEpJ rڇu M&&o.=$e|24HFߏ7}YЬEӠvG*904I3sa4R衵z-c66R|8F2Cuj[-߇ :+\1q4gBpO WUuiWMeq*Mn$eRHO@*;w6qkTu` (# 0OAF SZC<ddc?3vCXj<޳Gm#2nlO86oM:fvC1h#·''֚^aj_0B8\qM:[6OqYG#ha/+<5G0$qVosuVCd3[DҬr NM73wt0EIR "%UEfڊ v`S*c񞄎_AY_hQ@Q@rA x PUreEEPEP-/]WQɫv% ?Y5nsUv8'8|MM*{=@h".~*\c 7\RE,ku AJ_Uu#ibXdn_P{h[zUGg+:wxzLxr<p |==G{/ i2)f5)7y Otm{52//O޶1o Zd 1TF!;;iVϞ X$o*|ѱݖ<`}Zk="/wu!v"qXgT 1f4αugG-ԆK&@D*Luy 9!ktny%aȐȇ Kp:tZzY\o|GmX$[Z&U!I]rt5i5Xot{i P3†##N@h?P6^I㢏Wwx ; _[5t7@w?Կj(((((((ס* |$ KS)Xi\ ߃kcG'~C?UjQS 2; z a51J(ew?Q ߃kcZQ51ס*() ߃kcG'~C?UjQGS/ס*NC^Ԣh_'~C?U?0UE9LNC^?; z aR=r?0Tw?V{@8 ¶=O]':{kO-Щ[?0UE9LNC^?; z aR=r?0Tw?V{@+%u6uBJrHRN2@ϸJ/Uxkc???F fa b>ZGwgkc???F 9o'D_UxKUݟG#v.@38 :' "_40/F ?C(c7 Ӣ/*N<%CNnzO}???Ž@38 :' "⫌U<7Z.-IWeu AGz_F >:|*MOQP }=* }QT AmS=?[3~^ڹJeOx "_`9}A*{?~?Z/+뗊 PK!Fm{pWʨ3Ul V->:'B.T_j^Cr [n8Qz{fqZ?[3~^ڲ͵el.7\rF9cFr/Cy{h?LovnW62*Y??,m NѦ0gs8.tڹ J? ET7&[QZQEQEyE%Xj\U6G>$?&XNZ'7_I.+dջX7'7_I-މy&q?doO4}ſ?O/$\ xz' > 'kz.<[AMdoO5E-މy&(q\[j|BbC01G]rA nL;( (|$ K[i1,-4{;6;xmbYUTo羗y"e#7?K<GH̎Š}/Eo羗y"F(?O?$Q{'(a̎Š}/Eo羗y"F(?O?$Q{'(a̎Š}/Eo羗y"F(?O?$Q{'(a̎Š}/Eo羗y"F(?O?$Q{'(a̎¸>FZӼ}/EdN!񦘺fuZ ̶ݝ>1Ŧ&GEEPkG+Xĥ؏ 7?0G皥=.4{k H.h׵Eߛ/GN~_xlt#;ɅM[-o=ؚZzӼ̱F]c ٘*$ MBK/e2JKmP2NI(adfbj9kտr͗#՝W^TkטMgQɭC"]6@''D_UxKTF+a0GTQfm>eh̃aW-Ǔ =G݉/n<J DŽi?aG'D_U{Q>ҭ1t*@ V5qG-кIenҸ$!M*~R B*'D_UxKTF+cOLk:(H2N ,lV Ӣ/*N<%CNƬ4(  DŽi?aXԼi]]Aum&6Mѱg8aUCqKcШԀ((ʹ^NuxS?sZB/&-3<ہ{ſ2j߃sa]KKfſ2j5_ck 8Oɪ߻3Gdݏ,?|[C&~>-Uv?f( o 4`MW.ſ2jտxrKfK9qo)cF1Qһ (Š(EPEro&6U[ϧ3`RK ucMZ 䪗$ftW3Z <kC6^I㢏Wwx ; _[5t7@w?Կj(((((((:vM}DV >nqZ@c_n}IEO,YtbOZΣ*;S[6_G#zۆd9mȡdTWiaa=܈deLn dƣRS[6_G#z km6mY\<2یۜ摵k$w1bp xTѨ]8kS[6_VGFMVѼ:*8JZ@_ClqGʇއ~$ ԥC~lG?5eΗ>f\(xΠʧQ{.g@˲F jFG#z?p͗#3O o=8kz.#z?p͗#\ G?5e?ߛ/G(?8kS[6_[Qp0p͗#C~l`?ߛ/GO o=oQE[ObQߧmRB^$Ɲs=1}6>FZ}[Gc9ns2t- e ;o [ tB ( ( ( ( (9_Ÿ#zĶ9$]U*ג:zG$ {+ OoYEj'*,QoZtڿ=6ݑfi qϥr moVkveV.vRrAO< OoYEj')8hjc|d쉵m)w$ yWlpK ЗZzźAG5ݽBI/qQd@ /J O$Q B~"z_<& ]4j{ZM%/L`8##9=x}^uH")u+̰NT$ֶ O$Q B~"m[:[|bo`y2lrcL~Z'%ۀ~^Mn7EӴmc!G#rOIS?[_G$ .o:ޢ O$Q B~"7̾/ OoYEq iH"fB>SӂG5 QEh@W'i<֑vjVW?x±XnzO}???¶( F ?C+bnzO}???¶( F ?C+bnzO}???¶( F ?C+bnzO}???¶( F ?C+bnzO}???¶( F ?C+bnzO}tKkK7#EQEQEQEp^ +`.gj +R0,䞾V&C~l/]WQɫvrw4IXտr͗#ߛ/G+m2K|xOr*xJ[mbٔqyd G3,&C~lM[-o=mkBKX%S!IKc y fغ2W^Z2JnȪ21{s$ Pe%eA*sBW _3(;lzް&m.&2C*cDWo])QEQEWOZ쫍GZ'eT7;(3 (>@%{]'>6^I㢀>o+lW?WR٫(((((( Zj |=k{m%@>Rf:|$ KYبzngXgcp@='Ԭ]Y3і+ޭQPn줒VG3s?.-7ӣ%F0Fl:G<2s}b/$X.$q=/n+'ǡ˯Vd:;ɗ`$ی*c 'xn]?H%xLe] otR{ʯn.w_aw1cjצ|;6t϶s{֭"8U%_BpGM{fA0zzRʯp)QEQEQEQEQEQEq(D}>FZ}[Cc9ns2t- e ;o [ tB ( ( ( ( (9_Ÿ#z?)aW;MJ[U+5c۳z"tk)RvFW7Ap5?Q жAx(RS~r*ŷesKi_oWwi+ 瘁#")Hwuր73ɨq-##"F//9v+ivWhwWe#:n,R&_1oR =Emks$w~P]3%Gm?۰SrZUܹF~9z?E%y|Qc%_ eGUrdzQZsC乓JH$d6omfw{SwJ ' h_+h/uo.CLm!K+ʹm*F7.O! ڟ%%R㑡|ZTH# v@Olk%f7 Э/&A%B U[7SC/$c Fz՞_+h/ Э/&p0 ' h_+h/(?Km4/O\ A%Bӭ-4z=6-,V$j͹ >»j7xX뚸nL;( ((% ?Y5nb|7^F#Lx295 B~"kSEV/~nne "lA[؟8 eF@3tq B~"H5?e ͤ0DEs %0w\A;5TZè-\:B!1uPN$ ? O$S_!Y_-X?WCWS47AFXqI$Dl7llcL{ ~|S B~"H5?e~97Iߧ숻]`C?+ W$ ? O$Soq$\|T& sZ_j'+{߉\iZ{;\Ly09\xN[EVQ@-gP\Cm\.>l9hр6^I㢏Wwx ; _[5t7@w?Կj(((((((WO7`_Wi'֑aɣVUdPP g*&بQOi_6ğҿm'#r2Q\o%$i?JKcN= Q WCϿ>G&>.D>fsh~ ?h~ ?t?ؚw4biȃ'k5G'k5]&>ؚw4r g= S[2&YNT ~?M;}?4hA{U5o(Cbp+ӿoN}ƎD<5_^?<5_^4hӿo39O4?MWןj_fu ֿ{4&X2x9r8 ȯKӿo_֑isNbE5 ҚBnUEU+?? GV k/Tf[Cdyط <3بuV<[AMdoO5fOoD[3}7m3R}ſ?O/$OoDS 'h'7_I}@Oh44&,E$BEX?doO4}ſ?O/$zE`ſ?O/$OoD\ckmt8m/ < .Lg.HtwbGF0;]}{YXn¬PB}F'ooQCj A^$ux"m8M%ɋRT Ȯ+:|^Žtim v>bJgQo*L]\ ʜ | QEAQEWOZ쫍GZ'eT7;(3 (>@%{]'>6^I㢀>o+lW?WR٫_5l1C tojulnS 髖.+d2vCJ?'k(Q;\_ZTsQ >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9Q >Bvl"IeE9QOOϑoesnfZGc6y:Q;\_ZQÕ?'k(Q;\_ZQÕ?'k(Q;\_ZQÕ?'k)~+Yx"KX$'{rȬW\o?r?{-im/WMk_AZQEQEQEQEQEr!a-Vay3%d In?oK@m+bw.+C -;5?ӿ\*nʲ0ӿ\-;5ݢ0ӿ\-;5ڗV5M>-.PIQ-LCjPę񎙩ئ.T4v7W,' w>REadi?oIxGu9M鰴6̊x?\U NUm71A*GT{KNsvD?{{kv.da%;G"Zwk=㵻Eada%;\nGdG+ Is,IJ/?2K*2GE\Ɖ!R?"}Ck-SQGF?14O%cKY/I|){dz\^bMH-%L, BU{S8%NˢimBm eF$3`t9c؜Qd>g/k=5XRV8Fj ~} -k, g@U8>`餍pI I^U$c Wj$M떕 @IAz2#,.in\< }-+"I s'\G_jXrOĦ ᣍ۰ Yk妇OyݛYE9[{)ڤ ( vp]<аIRIPr=~u ]Mح`hV(JŪYaԱclԚׅ5e{s,J8Q0HI! 6)K; +[ƍ#*vn#+1j-y|RcH ۃ.$e{\|彎[] 9QyF=A4nCm%7HbDe miqenv>Kݙ.~' ezH9o:*((>_*ׅ¸M^:[QZQ@Q@/ 5=E~R1ZIuV^nzO}???¨~0ևy*/O7%Q΃C(nzO}>_?5oJ?TseF ?C* h'aAU9Y{???F Z <kCFZCqKc+c0(Wwxow:(º]s u/- +.+d-/]WQɪ'Qݢ+"Š((((((/zV:՞-g孼ۅ۲3*J!wws_%G%mΡIpau$Ă~c$28b&.T {SM=-K8&8OIZavw|1D< 綷fG6wbpn~iUqs\#m4[iZ9,mD=<[z8Vr0Z={]oM{g}bl/.ɡW-XʤK848#МZ/k=Z}OHZ,UOʸry=Z[LlA&H_a/^n5"[㻞J" fzU42HQDff$31,ĒNI&(@QEQEQEQEQEG-2ֻ*|Q#`kU -ºo]s2t- (((((/(/mlW795qkks7mdh/ie9y㙾h8)\v7'%j>h8,QE`ſ?q/#QDĿEE^nik;L=MSE5Z;AK;[Y!Z7 ͷiŒ8|c+[~-&'%jiks"sisjЋ9}LŤ-h8 6z9=J4I<C"I^so]m.ms!;K!Ŵfr< t:?p{_{-bn&|dI{oRK׶W:<L`sOּ1k:mnHMo4I&d$`C K`]mK:-oM{?-f]êr0xjԮB}wR&ks玠کEM愿@z6z4\4G*lc`YN w;Tx+MYἷ侸#a+y . 8#<W%/ԿP+K_Urdw4QEj@QEu϶]iZk7ɥINb2p+/g:(g:?VxozW VxozW g:(g:?VxozW VxozW g:(g:?VxozW VxozW g:(g:?VxozW VxozW g:(g:?VxozW VxozW ^:bᴴsoj-_ɯH~J`i@Q@Q@ |mۿEk@O7@w?Կj+o+lP^ wR45]C|ؼ <? 5:[h8j"8?& ?@*'Q [D|_MKm5sE"֭xk #HzӥhK '!^+6ܨ[Km4/O"uxMٲ0Hw X=ʽsnO[H,Q"FH=iًoX?V?_G [D|_MG7"aS0NwFG9넲񕎣6Vy>H ܲ?ϵ{;/O?V?_T'-. i-ĥOp퓕&3@|_HQ{C> 2DѲxR1OYd/ [D|_MKm5NJ3\ZCi%ݴ"Ļ`M|n,hÿ ' h_+h/1dldϘF۳l,Vz7q+s uW`ij42 ' h_+h/TSHt~";d#`L&VC1CA!]y6pq\ Э/&A%B1,`/DYxTGF*K|<:Sq+~3֓WiKm4/OU2 V3C4 J$ :sgn2q'Y%ŴҮ%IU .8n22)۰sGA%B? ' j+oi7w6;B8)$NdErEm5 UC9$wߝBbĿKm4/Oֵ_w+2!*5߼*$xKR ' h_+h/O+!]ᡂH ȼy88{İyLydyQ-6'қMh.h [D|_Msh27O>noĖ3igzw0:儒<> ?\׊?r?{-iڃi{_A\ma]7Ka (((((/(/mlV>%E]jCV/ŷ{񟽜e/ }dVROp'_WVՓS]Y $ݧNYY '1jRJU2FA FYYW$ űGVamm Q9xmMB.xb].#a-Yا pWr9cd ?RԊtr2Du T9>+[ +vų#Y#/O=ǭkmْI+ұSNvQ|,v9┑+z%s>KfX^Nܤw-Ąsa:jRV] (Š(( /?2K*2=f(H =!V?"bO/@Ե:le{pm>dszcZs}GsE?'k)]s}GsE?'k( 3IeOН/H,Ύ?'N?$Q >Bvl"::+Q;\_G$ .s}GsE?'k( 3IeOН/H,Ύ?'N?$Q >Bvl"::+Q;\_G$ .s}GsE?'k( 3Ie>hJNӯ4˸#_.&ES1AEЬnQE((h5F5]C& *d9SױZiRKA_jݬc 3}u?0?[) L]owjL4G{ƫzL]owjL4G{ƫzL]owjL4G{ƫzL]owj>̷ }: %6FyV ޻ZY%idw4QEh@QEICap-Τ𳱆9r`p%cOoOȴC+Em[uLcKſ?s/"h9kbv>TcixZ'eZ?[@-2-lQG;TcixZ'eZ?[@-2-lQG;TcixZ'eZ?[@-2-lQG;TcixZ'eZ?[@-2-lQG;TcixZ'eZ?[@-2-lQG;TcixZ'eZ?[@-2-lQG;TcixZ'eZ?[@-2-lQG;TcixZ'eZ?[@-2-lQG;TcixZ'eZ>,liw{k$z瞘笮79hіQlM$( (>@%{]'>6^I㢀>o+lW?WR٫o "ºM]MrEu,{͸Hdh' 02NONȳ/ hj }ё- Bn?.1a$mkY)ʄb@#i[S,{cgfF$QynKe9lGJC<ۈX޸WGC|_r8  jErDZҝbUh8Aa :+a =OYGޤ,&$8\(U(Uأa 818o{4{w,$2,qƪ$ ˕*+S2-ȞY (CJtM9XQc 7ݐr (TbZ-ǘ$i?y|z1рzbvô/˟/bszU(^Qp ܬgn_ "2H| ؓEaʎs[ 쁄a;Üuѷ/5ē'3$p\h\)~Ee{2tu+3۝[-WgF14E7"/|ۏVRsw[Fh.Hscn ~Gb+jM>f2O $gVU{?gvܓyqݍwo3R47"*'Uœ kV.dӦP6OXXb͖FI8(ӅNeݿR7mݎ3}kNW*R]$k #Z7 F^{v>f$K6Rq$YS pr8 )݅gain`Y۷wj8<;#"C)Rc Iq#.;TсJբc,wNc>Vd |7]jRZh6NL+渒V-Iv$ (Uحmc~5*rwr}S>.A!w 0ql7yo JP #h')վ6|Mm|mG2j,'կJwGQ\o h6ג~ƁĬ@yizl.-n~τa4[Dsda[va̭4z%&vj6pi_*ׅ¸M^:[QZQ@Q@ua]GK&4hz֛=zIlGr/&<0>UU^7 uW'  ҿ]<7@+uW'  ҿ]<7@+Ø(Og:?VxozW ه1Q\* /Jtt¬GGcK_R¬G[-%8 0#UuUMڢ* (9C+Em[uCO}OZӬmJ7Xn6+;aϱN<%CNKSEE`q/tOEQ DŽi?aSaV'D_UxKTX + Ӣ/*N<%CN,`xk@%{]'>6^I㢀>o+lW?WR٫o "ºM]Mrx>KJa4I%$jd4o\* /Jtt¬GS:+Y_.U^auW'  ҿ]<7@+Ø(Og:?VxozW ه1Q\* /Jtt¬GGc?U^Y_.fYEr<7@+  ҿ]9VxozW g:=se¬GG* /Jtt{0:+Y_.U^auW'  ҿ]<7@+Ø(Og:?VxozW ه1Q\* /Jtt¬GGc?U^Y_.fYEr<7@+  ҿ]97,%MQN׺q[?<7@+Ø(Og:?VxozW ه1Q\* /Jtt¬GGc79hі7* /Jtuffax,5 ;ºo]s2t- B(((KMxWW-6k@JD,+*E5CZ <kC<[TV<ӕ_?5oJ?UE9QZ <kC<[TQÕ_?5oJ?UlzHՆuK!tBy7}=:Ut6FTE:haʌ/O7%QZ ՆH'V$CЊi*1|kCSaʌ_/O7%QzRU滴ֶlY܃#a[Uh?PU=sQ_.=Rk8gtǴpA'x^=zMN֊nIs\AIy/0&TA|ݺ~T׮PyL+U S<0'o8'9_>u{-]xʀi&[yf#mZ8XUtkײ_yq鱋c0I%Y)͑iYޢt=N?m1v q3 syvL(C ( |Q#`k]q(D}}EVaEPkG+˻kҶ|]0Ҵ?[@-2-lQG;TcixZ'eZ?[@-2-lQG;TcixZ'eZ?[@-2-lQG;Ts׾%7:\$YV=M#u0O+,M=W t:'F"Jma]7Kaºo]P(((iQ`7L4G{ƨL]owjYʗÿLYCx5:?+oo#n2͊:GL3 JvH8BL]owjL4G{ƪs#I"ŇMhe-@Y<ьJ #dz%ʩu`| 68ɮ 3}u?0?[OVGyxP׷Y]Ckwcy[=6-;Ev=kђ$aT|V/&g#TaϮ;5S?+ 3}u?0?[`7L4G{ƨL]owj^eF_uiWe|I: ']D0ʰO QEh@W/0]wŬs!dǕj+?? GVبMj]GQnf .zu޵iFX*ḿ)՛JN^O=sۙz\HG*cէ: :ݗ+lD\ dIgc5tSe-ywBIq%2MW,,I"ViWo,IjwDEeE*ijcDr{yßqUm`֦czXm} zU} ķZ^*79TcV&g#TaϮ;5BZm{ޓ6I1G#j? XRZyĤ%(q#9L]owjL4G{Ʃ_o/8׈ Ɵy&{:tIg6Ҽ  r ms^"jvfV/&0Y čwc׵L]owjL4G{Ʃ;²>g5v-cy"n %$c:L]owjL4G{ƪ]݇\%_"0?[ ^EMrc}@`OpQaӸU ɖǡQEEP1Hn4O‘m2lJ KML8]rrd*FRh\lnָRaM|OJHtm>ګj#X r=~zwb+^:";{%Aj9tm.{so6g$ )S2qWh;"Tkw&d(VfK08]Et{"@fG*jѢعWbFsn3E$*HA>->V(lBv@p8VXԧ,¨Y$f`3ؓ?8 :' "_40}O{V'D_UxKU6z_40 Ӣ/*E`q/tOEQ DŽi?aEޢ8 :' "_40A,?tOЍp/Wu- ;K KP .' O»@#Zb%/WMk_AVHQEQEQEW?'%Uj+*E5jQY+6Mp*GqWvF8#H.1W=_[YCYe?1>dGq.,xF,JYvnA8?6x˥οtW'K-&KٴZq,,*ۤ%gj^"V9>y(LupNhw{Dw4W4R\ ຎ4[2pGOy$GQR))2K t8['R۝xR-\ldY 3ə^uRTt+kHl.&y`YQ:F=[~^c;MPyhu:8H4gIyCZ+׾!͸k+ChH,|4;qv }᳻mSV;|Ę;y $9ٽ59KkhԞ%.l]Bd5ݴZz- y210hgE(if_SWjW2$K$"BqЖ~A#fqUM\:| _Opc6)vd0y*"U )5hOEQC0۴@-Uv?fFCſ2j5_cha̎?|[C&~>-Uv?fFCſ2j5_cha̎?|[C&~>-Uv?fFCſ2j5_cha̎?|[C&~>-Uv?fFGZ'e?ſ2j[LNh]Imyhr: ;QEh@QE+(l/qep27eqa)+^ZD2 e`dӶ2lYyxR3OK$`(>G888n'hDPU( >T>mgwmsKɧ8R(乜@(Hnɤ Ԡc5Q+c|EO ~+jieƠ+k5P\$]a-+2 8=~;?|!cf4c>xq)E#An%nu$>Bp=9Ey*}}F p J G+ttU-^鬴[ݺy$!IF~ gn@š|-l'0Hr-ٍ9ϵ!CCЬn5wW$g*.Y ۿs!nIrOZ|ek5_]^]BxXaVK1|{ CWQFhK)+)+[M4'DVV)?wy?wyÜq.pIZur_OA]Sw]OA]Sw]>FhK)+)+[Er_OA]Sw]OA]Sw]uW%?wy?wySqwVA2E*2Qy_!] SWTUl7Q!K3<#E'dM\ca7shBx;G?R kϾ+5G&O"T\5[]'}^.CEs?Q >MtE{ƨI}oWj\&O"TkϾ+5Eh{]'}^?5[t4W= >?Qp:+I}oWjMtE{ƨ sPo_JOMtE{ƫ>Z>!e<*wڬge<];ggp;( (>@%{]'>6^I㢀>o+lW?WR٫(((((( ѷuW3=_V?6{;TQEbhTK/K#S"}6b0A =Պ( u)[]B+m6p9<4;;+kd@B1* ?JEDYCٗo!s*E42RB"_7gs\ E;*i,$K>@1T 9j$($[t7} qWpi2!mn%2"_`s]gӊȽ{[_k}#Dor%K( |kPi5f@vm% 0m='zw٠|q}*Z) iX6@ PbQ4gj7b8? 1~gSEOt.%01k1 TdV gjgC#Hv~SؒG5-\,WZUFaʈx8EDT@T`R@X((y"] x?_{ǟ+X\5-ºo]s2t- B(((|_\v] Φ7ndEÀZ6VSD?{{j\W:+KNsvD?{{is򳩢oD?{{hKNsvth[-;5?ӿ\+:+KNsvD?{{hAΦӿ\-;59roD?{{hKNsvth[-;5?ӿ\+:+KNsvD?{{hAΦºUӿ\^l Y MnAfbxbI=&thMMW]֒ɲk+2;q!\Vԣ.i%ޫwGV?u+[7\1=Io "ºMJnȨGbj9kտr͗#3*տr͗#ߛ/G(adbbj9kտr͗#s01?5oebj9kn9YؚZz?5oe>-/A򿴮Z/43 UmQ8=jնiy5Vyj9SPt`xZ|,M[-o=ؚZzׂttu 0X7nOci=+(xg@ 䃑EYbj9kտr͗#YؚZz?5oeE,OM[-o=ؚZzۢfF'&C~lM[-o=mG3 #V[6_TKQ|awjWZ-ki4OrD$PFzZ돗JajbV;( ((% ?Y5nua]GK&j ȏT_sXErsI"Nq Zy:UMNQvk[V,pdGu0W i+yv9;8'H>"OX&จ;IaMvmj h%ˉbzQ۶)xoL s+}Uݙhlf==-_Ah^8B}sV}V-w-s0#V&v]'R:0 ߻ϙ.,lghpXbߵ5[I\^Y* qbº=O5eđpX!_ rC/O_MR40B}$U>Jӭ,mGn-GAI?Y}+x PW_\%_"-(H (9C+Em[uHn`*FQEQEW u^6+5܏٢KtXwyrDˑ˴r >#Z\Csgcr{B|\AM&o_ 3Z&jo!W >Sv:6oov&Kyb&w2,(h6*IFЕ]G÷1ZQt%ʤ1qrAdAOŤMl!m\ˉǼf>0d K0S)QEQEWOZ쫍GZ'eT7;(3 (>@%{]'>6^I㢀>o+lW?WR٫((((((OUBM)t.\\ƌgPwtޠ$sRjN) Q WCϿ>G&>O"39O4?MWןjO4?MWןjM;}?4hA{U5U5N}ƏM;}9s3CMyƨCMyƫӿoN}ƎD<5_^?<5_^4hӿo39O4?MWןjO4?MWןjM;}?4hA{U5U5N}ƏM;}9s3CMyƨCMyƫӿoN}ƎD<5_^?<5_^4hӿo393BS2dE G>>0|ذ۩=obiȃ'k5G'k5]&>ؚw4r g= Q WCϿ>G&>9vcc}f>sK݉f(TOjOЍؚw5r#bvϽRVw0e ;o [ t@v)(((}z[/d i5([[kQ%7@`?`xl7E /,%L6H"'tNr^IqW$vR6'b_7&V%JovQ"y>*-CWK}m>m-!)ˈ̌r_,W$n&z$R4I,NFCЃS4TE 0)jXטQEQE%Bo5W/ G\y[c7W-/]WQɫ?}kg} >/#]WPIj&<[Ӛ8vV$ ? O$VV,ޢ O$Q B~"E`AП/H OoYEzS?[_G$ ,REORw&kY݀rl8U~$伂6(0J uX2k_ OoYEj')kjRjIc-=5.<,6ϙR29z}O—בkAE`[yYsƉRl=cZj'(S?[_M]}H{idbbVlА>Qm$ ? O$Rzޢ O$Q B~"oQX?j'(S?[_Eޢ O$Q B~"\|T& sZ_j'+{߉\iZ{;\Ly09\xW ɖǤQEEPEPGjqb#( ^Ik?ߛ/G.+dջX7S[6_G#zޢ`?ߛ/GO o=oQES[6_G#zޢC~lG?5eEO o=cR[_ky=䋨 8@"Ӏ:z]rA nL;( (4O‘m#k'Tj(F[jW돱V7PO=q??[eޢ?[3~^ڑV!gk<ַ;@V!gk<ַ;@'FΨ5Cٝ@ k11Z͹_4:]m4S?-1pIsK~?Z/ZM{9_M0ZA$ ٷzӓKӦl-^+hTe>n ?LovCy{hg@MM{[f--iH9%WROXΨ5O?6!|1oq:w!gk<ַ;@V!gk<ַ;H +3~^??[ +3~^??[ |Q#`kZ9hOK|nyW\c[t񞂪;[EVaEPkG+gI.K yYHMtE{ƫV9ÔI}oWjMtE{ƫV9ÔI}oWjMtE{ƫV9ÔxL5aoM2֟qob \?r?{-k-Yma]7Kaºo]1Q@Q@Q@; 5Or5V,?}ſ?q/#T'?*GsZ.;?ko4OK}ſ?q/#VS/giggg'Xc2FzԕDĿG[@M5n#*r7V'\68lg ch~-&'%jޢ?ko4OK}ſ?q/#VVZxPɑ€QXz~I[]BA4s/~-&'%jֻ5/49>ƒQ3^[Di ULך2h8_ _F) _ _F~-&kF0U$lG VyR "c~-&'%jޢ'%j>h8zx$G*91 08{95~$\6kkm7BN|K4hAxaQEphWL`h3>bn(^>^vRA %DN ]@FZŵ߈ń2M$͸DQ 69l oOv ]B,Jv-[&wqQ:t;+,_g\}r$ort#cS hֱE46kn|1$ cߏQ{K& +t@kQP<$T+E"IlNє"gQӧnvO477Zxby pAmC+EmZ[JѮ+9l ^V$~[}=ⳏkyf ?9H1+' ^ePʖ2#m,@)! ft{tK#tDlK8L2I<֠i13P YP mF#TgS f(m.G?xHswwYVO2fbm );GCs-?4yTK<ȆY 1S8g=1w6f JrR]u`12cMRȌA>x.Ş&Db6ɶ@R<'?/9Go_D㲳Tk fvU`ݹI\`7O]Ŭ\y,Q#ޤp@#oӬ/oe+y.ʬ$B9koq4ƯH[ٖEe>w`"oi*@O!1Ck,uO':xSr`2˸_y`;KÜU&TrM2"G8S;FB; bO0߭[A$۟12F{禄W~6.;g&I5;2,>Uh#}+T.7VeVyBcW%UN+:KiّoX2v6=1Qj>DO# ǎ)05] ru^1MԱ'$%_F!wa~RH H^)[ĚbHwȶs3ӂY@vQmK[UM?tۗU 2zlU=Sf"1a(wm 2q6ggޗq^>!EnRFB7i;y94iZj,D-^`*H' 0@#/p5$z5[v@ ҡtv!4V-hv9O֢*K |Q#`k]q(D}}EVaEPkG+FZ}[Cc9ns2t- e ;o [ tB ( ( (9_Ÿ#ԴVZ(">nK S¯w5YMٔՂ6X (㷑Z[q$BVx ܶsmiEyWyل;pPŻgrַ;Zv)c >iGOT6ED/eK|0mrka#Ldyk9LF@YHW~GI89?Yѵ,Og/LyU!F#x2=w+`G&;/xA$7D#;h rx`K3OޅɉFm;syD9h/f8f7qYBIk5巛OVo㰩5}7]Kd"Ovq$u#^4x):wCn੤sH9..u2%(>V%%VF8fsTմpe%FTQ31ffWqE\6NiL &a'Ao-٠ӄw),cnr dq!p:9ȿ[|T& s]prP,?uwv%xKA_jk~xwT{BZVk٤rI,N9'_*ׅ?VxozW 'np%ᴵ˫8X9t19\(B((((((((((cD)[Vbh_#+j۬e(Q@Q@Q@Q@Q@Q@Q@Q@q(D}ʸ>FZCqKc+c0(Wwxow:(º]s u/- ((((((+?;뙧Gu 5[Pba$GN߭zr^@h=SRgF >7$D*;?LovCy{jiݳOC:#o.Eb982= ouRU33Y+=OCy{h?Lov J3x:K y|8Y?8#M]9w+$rD$كd.HCv?LovCy{joI,[Kky8Kidi @EU%gOS6HK'vbPX?<-C=~?Z/KlKV) `i|< #6RK#.#AA+ƢCA< vsG!gk<ַ;Vlyf3˳lr[ . htr(u##"1??[3~^ޢ`ַ;G!gk<㵽E3~^??[(?~?Z/oQE?LovCy{kz.!gk<ַ;[Qp0?[3~^ޢڶmI4}51%O1o^+kGZ'ewմv3?/WMk_AT (((dԶI9v n*[Fqުyj&Uȋ,mzT4j\Sv9O4?MWןjO4?MWןjM;}?4ir!3CMyƨCMyƫӿoN}ƎD<5_^?<5_^4hӿo39O4?MWןjO4?MWןjM;}?4hA{U5U5N}ƏM;}9s3CMyƨCMyƫӿoN}ƎD<5_^?<5_^4hӿo39O4?MWןjO4?MWןjM;}?4hA{U5U5N}ƏM;}9s3a Miض-!-%.X"8=kz=R,H`w~5z+QE0 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (8KL=C\ }6I&Xbe=;[O?$WyE.T;|s=y9_ (ʂ}/Eo羗y"(Avp~o羗y"7?K<]r8?7?K<GH9P]HO?$WyE.O?$Q{'+Tg{'(|s=QG* |s=y9_ (9_ <}/EwQʂ}/EUm3wͶ2X#OKHǔ=:j) ((>6^I㢏Wwx ; _[5t7@w?Կj((((((([_WS\ua]GK&Gsf xbBP-Uv?f( o 4`MW.ſ2j5_ck 8Oɪ߻3Gdݏ,?|[C&~>-Uv?f( o 4`MW.ſ2j5_ck </K;0Soiopvdy8?jo 5g%YU 8Oɪ߻3Gdݏ,?|[C&~>-Uv?f( O m}^ 2CꨮP\ݯ\}Es2t- e ;o [ tQEQEQEQEQEh_#+j۬MC+Em[u4[QR0(((((]ʶtwh6P⎶^mx ֋i\Cd+[t.D/\S.w{'.oΧ%jrlA)"@0w28 pFsM=YIA-gKziw @;ņl;2]/(M&IhX|ms(2uOMov}H`ZT6Ӄ^*G5_6]:Wm]DBA]DCZEy|z%]N\I b*az A7:nl1KBI`ʊDà?r>oVo;(aEPEPEPEPEPEP5,?tOЍs<\BJᮇD</ְ؉nhQEdQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ |mۿEk@O7@w?Կj+o+lPEPEPEPEPEPEP^_j^/ rK&hԱzWW+']Zӿ\-;5ݢ.KNsvD?{{kv.KNsvD?{{kv.KNsvD?{{kv.KNsvD?{{kv[Ŗ_o+{#f;Xad\'"Zwk=㵻Eada%;G"Zwk=㵻Eada%;G"Zwk=㵻EadqŘީ M[XuKt6Ӷ <TwV4ְtV8+ Q[$Br+l5W?/WMkQEQEQEQEQECO}OZӬmJ7Xn6+;aϱN<%CN~!R?"$ݱնCXsE DŽi?aG'D_UoTmYv38 :' "_40( DŽi?aG'D_Umy T\djJ4 LN<%CN?8 :' "niIpƥݏ@4<Wj<8u8E01?8 :' "_40}Z=܅#PHBK'4M#+ Ӣ/*N<%CNа5)8>В RHP$U${FN_40 Ӣ/*.i76hդ#f\,IOC @'*q/tOEQ DŽi?a[QN<%CN?8 :' "VP9-f,iʬM;3 Ӣ/*N<%CNޢN<%CN?8 :' "z_40 Ӣ/* N<%CN?8 :' "z_40 Ӣ/* N<%CN?8 :' "z_40 Ӣ/**GiawW2j;!7vDAWqkW t:'FKsB($((((_r^_ik7<4\X2HXNC^?; z aNC^?; z aNC^?; z aNC^?; z aNC^?; z aNC^?; z aNC^?; z aNC^?; z a|YN;;iWwRgd0^#' N'(((((((((((ow:(%{]'WA\sa]KKf ( ( ( ( ( ( |$ K]Uy׃PGi7U\܀q'eDh'%j>h8+oQX?ko4OK}ſ?q/#Q`7'%j>h8V[@M5ko4OKX .| ֯mz^Aun1(#h+9}+G~-&'%jjY|0Mlſ?q/#QDĿNZ_xDҮu;n/I\laEc9[uDĿG[@M5!V[@M5ko4OKԬDĿG[@M5z_ _F~-&E`ſ?q/#QDĿEo%uIyg%zvm{k}キ 1sqa oV؉nc@v++l5UQEQEQEQEQEr:'kĞɊb5S!9D2H;O͹saȨeơ-f1Hdf( p)prkI%ZJGx1K}N9mELm֌f=ڱFyx6omjK$ c2!;g#Vgc*$Vq,rl0OE`z0AH% X׌u<a5KC9Ms1sח1db&r]Vxr8̜xaazgy2Fќ` g]=Q~v&Ii[i(ˡmP09 ǎEI7ep|"B( AQEcuםm"LϱX.T6H 'J]]3ɺX.F]`+hI^#m"z)r*J< >wa(OY<-$Rq̾;0{Z4 a ڮrƺj(Cu>zei!@3ʒwMP@5o^²&IW`D>YPpyctP`yKsgMZiJ,-mV)2E9 Rð-#8"H]`$¦MJEPdQEQEQEQEQEQEs^<\BJᮇD</=,?tOЍk QVHQEQEQEW=_AaM;Ka i[ Z(juKeh@JU$d?6Ji1FRE;um5`eԃ*~BGZOz,z^/^XњktT1˴=62FqO~gErD_%?jY|Hwٿ>m x]Ֆnme{6kAUeK,2dPwWm#MK->iMAo%%7,=.5xI9,B6ӈÙ$`r9PAsea³p)<ȱƀ;=voiqw%ԑS#j푟Znm5恨[[.tI,ACI;-v\@co\gI\V}͵K;uYdxˁH#-ZuX#&n'#0c IJe\MF9;J+ZU b fȇto9bvryf͸Rn%~PF6n>N/oH/gy { #q1xdefX%pYPHd~b\^d$i-d+2yX`aA8'5_=@d1-E*7J,{F:P (QkpOR㎝k=a %9&KU޹y:^$ )].WyI%?LovCy{kW.-b N *aq p{jv%#3~^??[*nQ~?Z/\ Cy{h?Lov`ַ;G!gk<㵽E3~^??[(?~?Z/oQE?LovCy{kz.!gk<ַ;[Qp0?[3~^ޢ~?Z/\ Cy{h?Lov`ַ;G!gk<㵽E3~^??[(7caGs HsuBqֻ@#\?WҸk? B56"[QEY!EPEPEP\4-yMᄍ&x]-=VX–Bo!FG^A٪څ\X^Fb7ܤ`++O o=8k,Wϛ6q$.BɂsR]4iشѥ99 ?ߛ/GO o=0,2 Ihf~]!"snZ z {h:cx "j#z?p͗#ѭfxi+$2fıq{z Y-]]\[tz+xK|8vu%C=ʶlKYظnj麝c ;`⥺KجQU,~I>ÓO8b]ơg8`UMb6H`s"l1". ~Cjr# 9d ͬ';wR_JiZtr3do-qs=\j%<1(GGc6}7oy2x2;֯~ vxeV* w$uSHUm]f\KsGı&yfXU~@A:CڲI "rttɑهHuNPY eX =hyHFhXxݏ=+?ֲF [!f}|޾RH.P[xbȲβ́6n?GL*1`8">ךa/)*ބ9AzJ+7c ZV6s-Zys~x늜piv(Bvgc== sZ?u<5E!Y$eFF $^jVn<-[+.,If#,:< rr>A8$ïKaeI|yR;9?FȾH043d)bg#8 +{0C6'Rv(hityIGVjvSZ ]CB!U1.I=r9Q궭qA+3NӎAC\ɳ`٠x9BF2gY?2XlsҷOd27^&*I㎝ $%&ّo%uIr6_ 7\W_a oUas_A\ma]7Ka(((((?? GVկSn1?8}UuDGح֗+F]>lN0>Q88&{"`r"Mze&aymI (^8r灒j̚4WqC?Vx DTO1ٓd3E]H%X /S~srskWMmVMa;`Hs =jyqt ǜcc2 <閷TQ3*NX a)g.C~}+]PKOѭ7[!|)Y YUdU0xpp WZ'ԝ(6) qkmp01ܱhv8څQHaEPEPEPEPEPEPEPEPEPEPEPEP5,?tOЍs<\BJᮇD</ְ؉nhQEdQ@Q@Q@s5ӿk MjYeZ[N* 36OUQKr<7n8=:ѻwKC'_meY$WZ( n^`e^6⋋"7kydL>zogq{3Co-r׸;k68±ҟ4)* BcKMl}սNCL?t}2 k+'fbdvRGN}c^Ҭj#Cq:)v*0]-sc ֺ*^7)ǪjoZXmyMscӽn[mlr@|9<UCu V戦t/P̄U$Erwr=f#}+9%"QP; p5tkɮu^)ʝ6B 4HO\Ð (EJw( ((S7aFK?m\ NsC#)^ 4gdݏv×VQVǦ}m q(bIF 'dݏſ2jwE;!]'dݏſ2jօ|E[ Kkh-dGo*WQnd8SixZ'eZ^2?|[C&~>-Uv?f[@-2-^->-Uv?fɪ߻3Z^-/ D̿E>-Uv?fɪ߻3Z^-/ D̿E>-Uv?fɪ߻3Z^-/ D̿E>-Uv?fɪ߻3Z^-/ D̿E>-Uv?fɪ߻3Z^-/ D̿E>-Uv?fɪ߻3Z^-/ D̿Eo]z{WP[ILE0UQ'dj~z7eTB`ixZ'eZ?[@-2->h̓_A\^<[mEw&dn>:{g</ D̿G2 3/ D̿Q}B]u:n-)o^%*A144YEQLAEPEPEP/HRjp:+jFծ)KX%ح+Ds8;Tz'WaHڶ.H+Zǥ4#dia=s31]EgF/;"|2f\?%n} z.}9bJWeV0@Uq;?kv *"*2@zXˣxnY6M.q/FLWWjX;q:tQ/9iZǶtfx{{8.$D,K7$ =q]I/ ^2ch\޷um.ȣT+urarǾP~o$NlYY.##x\ݏZfutL+·~wu?$R$`n< Gnd|zC"6d9',pxN/?yt61?ۭB-R5%+jfxCeKKkH1G.Uzu[:tIͽ*SJX61NjoIE0.T{s5SRMU;'&dHFPpw }F9%u=jQXk diWp%ѷ&1/|Ac=|VrEPHQEQEx(Iq]}!\o:'6"[(B((((((((((>6^I㢏Wwx ; _[5t7@w?Կj(((((((((-Eu;2Q6/$;6ZF]'(K?u"T  T߾GF<\LW9}:˯G$Xpg8\sşHkAp)xKA_jݬ/ "ºM[lQE ( +m--5 O4K]w!.P P ot_Zv]JXaK2|ڶm8P ,(^]{xKshyKF`rqFONoEN3s5N'c2܈ۧC[N}SŰ_x}ݧ&umim"%U0}EW.|Iu/M>[d0$8M5/O+$ӭo˝dG_617\gWA-@I7*K hn~H]lM_}C0hs\KqΥN p3g5ycY0M1op>_'vQIبQHaEPEPEPEPEPEPEP5,?tOЍs<\BJᮇD</ְ؉nhQEdQ@Q@Q@s5ӿk xLoEm03:udV*YT%/9j䁀OҹѻVKR) ISsd䍬U>3}j:5obX.8XPuWwo H]` $ ǂW6W :34i%|$ǘ~IiYWzd_+#ݵ*K%Wg!pv2Gpyt92_זC2ڼ9j_=mtɺ-_[ sۛS^ H8*,j z{.KoaÝ|Tڿ`:sj7è%:068݁s]E4LN9tIwī02qW(op(QEQEx(Iq]}!\o:'6"[(B((((((((((>6^I㢏Wwx ; _[5t7@w?Կj((((((((((FZGqKc+c0(((?? GVկP42}p|[ډN?btkjiiok."1N1G^}r1beQoZݢ(.aY>qN;q[7oRKeu"E3P0HKy %~&gGmp.%2');6tU zU8im <+k&R6H->e{F;)(休Ȕsq9$q)}C%9]>KVb/#=9iߵRVYIpʒKrywlh1ӷ[[[[xuUP}sHP19mtlNa}GFK&ei dFV}n;Od⛴ybC4ybQ#ff.o&m)Üqڷ.4}2:m31qY47H#mh)]qcZIǷo!i멀'b[h&I$W1yr0?4@d?tǴlSϒ WKuo/ zw:JT2EdO֬}E9,pGI#ҋZ] |Mz[[kª;gN3_sZOwj2>Up~_~U}ꮵk lg/X4$[ozӷIBŦ`N{=KyX*K ( |Q#`k]q(D}}EVaEPEPEP1He$I ubs~Eb]j88?mާt(4{ ]K(Q1czXƭdXiv%KRY$€~c+Z ]f&"~џF%z#n=z-:y㶈+mA$4Pmhpek`7Ă%A rXÏCC u[cuZgG9,pr ❕r{Dr,YC̅NACێQQap Gd}v\[Kl/ BEݱz0rJx綾e n%7F9B /e95{#zqq ahh) 8'?".^O*1Q6 g{~6?]]4G`AGR*Ke?//mfhCCО:uz}r%Hɴ/icsdcۻ$5E:H/av`n^f;ID$YyF1ZWI6D6噥AX[_^wb'sIh\Ciw؅0pOGNhB8e HRAW1ImWB?%-"O*W}C9A@sHbt yᇆ˕u2X S]{QPXQEQEQEQEQEQEQEQExEqa +@#\?WҸk? B56"[QEY!EPEPEP\4-y7^K{heԴ92A# + Э/&A%B57A%B? ' hzg/(c,3]x4Џ h&UP̟ap 68?CE`/O?V?_H +Ox2W)4`ʭ$9K<2Z b$AS ' j8ə/hH~_c訬A%Bo!>.Sp#gϱgfRxkAu TAw  [D|_MR Q[$Bľ{i.e3jL%F~ppJq8VIk (((((((((((Wwxow:(º]s u/- (((((((((=!V?"sşHk(?|IcAycCp5+0Uӫ#J2 zO4?MWןj{:A$o`6?Pbi8"yj&Tyj&UbiϿ>G"fsh~ ?h~ ?t?ؚw4biȃ'k5G'k5]&>ؚw4r g= Q WCϿ>G&>9yj&Tyj&UbiϿ>G"fsh~ ?h~ ?t?ؚw4biȃ'k5G'k5]&>ؚw4r g= Q WCϿ>G&>9yj&Tyj&UbiϿ>G"fsh~ ?a:Ů2kLV7I+c4 ܨ̈'ctN}ƏM;}j ; ((((ј.92۵Oj]GQnf .zuޡ?? GVղe"v}O{W9/R]n[* xfɠ鲕S+|ӹ3=)!C6vW+Y\ҘIYd(ݽ=G%1Kw1we9`֕ihP˫\]1RFӂ{*&,-TgV9ݱYC ]Eoq?_ٷ?gvn= c4+u)t5l/dbhJN<`0m~AkiڕH]cƠoe,}w6v iifIB{I-on`q+4$2 y kyOpחƵS]Y@cq+2]T(䓒sryMJ Wͱ%s0BaUOZ4koyw?m${~)o4K[-yLVPl2<6IK MqK)ne Hwb˞d%Ԯ^zVᥤqq\2p wcŽK`qZ 64 B# F hvW%'fk?Xďmks342‡-$*FؓG ͸f pN7i)-[6jI̙'̒Y%v㎼qQ1ªݣn,eKV>0pI /-D&mdk$RB1#MʬORǚ-KO#w(ޯ*EY,వKku+g$I$I$rjzNХ{jQE!Q@Q@Q@Q@Q@Q@׏?WҸk? B5xEqa +@#Zb%EUQEQEQEx@SNk{ƿšwC5&Tf,QcXl09F8ZQTr>S{cKks3V[8[Čg'h]ݎaKkPi23C]>ȡx# ))CuWr&7 ]PWz ۧ\}QلiVxbU!lH`ۀ*#1|M+U՞Vj KQwvpXORO?tXz-&kKV?/ mIE+f?CRL!=BUk( bGFvK˒>`F3cBvl"IeE9QiZcCY)z!E1a:Q;\_ZQÕ?'k(Q;\_ZQÕ?'k(Q;\_ZQÕ?'k(Q;\_ZQÕ?'k(Q;\_ZQÕ?'k(Q;\_ZQÕ?'k(Q;\_ZQÕ?'k(Q;\_ZQÕ?'k(Q;\_ZQÕ?'k(Q;\_ZQÕcizrJ=ÈL1X۷\WFdx"I.+urO*j̱EU(((((m]nj& ڥѭg:ݼ񴹈E'x5!R?"x"Xq6EbeWruyV;88V,L|PpJ~H=e(؋c-U dx=qIVjqBksl|ОY8j>`0vg= [Fcwzfe!m9;vBvGVmp~a yǮj״Mi:c@֌ ri(kK4.fPЅ69r3]28E;J|8`p3ia|8x?M߆jX Օư9U\HTO=t**+ZE#Aa(.M” # /~-xIdH4ci ptcV."uY$Ivx񎻨66N&K^;weHL?C#$qOW5O-ƥir[`ܱ&efo<@|Š(0(( Q[$BI.+urO+XlD,QEdQ@Q@Q@Q@Q@Ue:#VkKKq.aonX (qzUtbW]i XQSmRڵޥ=\iwkhxc<1ŻY\׮D!H9#x3+(ml[m ]\(ese#yFVoaNi+ ("ҥ%٭#d<0O=ㅳ5 !Ys+C*YBvwm)XnbmokcG.ëuQבZռRtɮgW`~@.7a*}z-~lZZH ŗ%\q~;}g-ݙǓ)׾qך˟wHMko6\,L'n ```el 5e<7RV9`F=яCNqqkYc!n!kU +m$?b`|k^Kd+iiQXG<3VhSC 5y;VYYr }G,sKVu:Z*us{X]kq4*#lHϠU~Vv);QH((((((((((((kǟ+X\5y"] x?_aТ* ( ( ( ( ( ( ( ּ>uoe fB+,n7 ;l@%> |Umkv-5FCnAɕ1ǯgak:y$^uM $5x±tZQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE|JnO|mۿE}?WR٫WA@Q@Q@Q@Q@Q@Q@qWCԿt+Jn̷YqWk\PXۺl8G?V?_G [D|_MXu9 WA%ydtխYjZi`/O?V?_RV{WaE:1y0c6kgY$,1E2Z{'+|QiztB%OڌX)&4`2Q >KHwf'Hx)⸇B; 2IB1}t?Q >]V) V q*4aA(VǟdwB,M<;BیIkI}oWjMtE{Ʃ俱|Bl#f@FF6'f<>I& ɣ͓ 8ɮ]'}^?5[-cd`H?OݱbMvW`LTOC\r G)e܅,A2I'5kϾ+5G&O"T[G8 _h!\-eQ.1֦|s= >?Qdf'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Ef'HO?$V&O"TkϾ+5Eg3W{/ gq*9Y f`2Pw:t SSsYEtP? Bf"HuO5eQ@$: ?!?L?$WAEs&k(T3\_]CЙ/HSsYEtP? Bf"i: :(d0!))ulW?g%YU((((((((((>6^I㢏Wwx ; _[5t7@w?Կj(((((((f?(zmt%WUÎF"`0:d&EswhdgbLt/;\XTk5$D[g>[ن-o2֢عV2SÚlMDQy2o9|0I2xw}RĻl0$IqZtQv/tW7IpTq(8jdѴ%d2fTv*)WcZEaʻgC;;Y"2H8ݘ]N=A9(xMXdhdDUIUeCmLJ4cKw V9eb )?r=V.Õv2dH$RgghRk B:Ɓt<"dICLA-Uv?fɪ߻3G#duW!5_cho 4r0G_Er>-Uv?fɪ߻3G#duW!5_cho 4r0G_Er>-Uv?fɪ߻3G#duW!5_cho 4r0G_Er>-Uv?fɪ߻3G#duW!5_cho 4r0G_Er>-Uv?fɪ߻3G#duW!5_cho 4r0G_Er>-Uv?fɪ߻3G#dIo%uIp]z{WP[ILE0UQ'dj~z7eTB\U-ݓQEB ( ( ( ( (9 ѷu\m|CԾ-yZU߲MouuӾq:~?Z/c-#E`ַ;G!gk<#7Cy{h?Lov7Cy{h?Lov7Cy{h?Lov7Cy{h?Lov7Cy{h?Lov7Cy{h?Lov7Cy{h?LovLqGys4QƮc'pI2q*yU"n49hò犥~?Z/f]O{pZ F8xJjxsCK#t{{-.ク|~?Z/@hPSeU.@18W3~^??[ +3~^??[~?Z/~?Z/~?Z/~?Z/~?Z/~?Z/~?Z/<\BJᮇD</ hQ>&c>u2D9G{D</ְ؉nQֵFX4:kyoE\ $Ga?^-KJ`i[&M^-/ D̿[TKſ?s/"h9kb9rKſ?s/"~<[}cgݵiOen~矻EsF?_EKſ?s/"sF?_EKſ?s/"sF?_EKſ?s/"sG7>{xGhl丑c%,U6gֺkn2@q$ğ MZ^t!ZEL(oWCKy{+ w"Ơne_\4- >Bvl"IeEeFG$ ?'N?$VsFG$ ?'N?$VsFG$ ˃UV75"Mg4o;1?%\sG;TdOН/H}GsEkG;TdOН/H}GsEkG;TdOН/H}GsEkG;TdOН/HGW:uΝy]Rw 2,JpyOZЮ>_*ׅbqQEdQ@Q@Q@Q@Q@ |mۿEk@O7@w?Կj+o+lPEPEPEPEPEPEPEp>\ 5,p%䞕?zo\":w=#޹;@Xc;~?ӿ\,tW1?zo:z+GNsvDt?{{h =#޹;G":w=?ӿ\;~OEs?zocDt?{{hGNsv\":w=#޹;@Xc;~?ӿ\,tW1?zo:z+GNsvDt?{{h =#޹;G":w=?ӿ\;~OEs?zocDt?{{hGNsv\=m?[#h_nupynhpN kٮ]2AIQPeQEQE%WUXqWR^Zb|ݔLwjlPXۺIy[2Fqz*Q%rrj:ƷGO߲EhFayX?69{gUS C?mۻj띹+9._O㴻VLIo @g+%0rAz%yI$Dqn-U,$wA'b\.qsoI$QK",23@=RZkew f]$e@9=-[JrN{H:p]_[f쏴y @>qjڬ1޽[d%wo"RjH״w5ki<U5z9U-%ISpGA)NU,'◆PkPevJMv((cu*wrr`AY6j$H?9w#9w ٧<#tEgB۸7͑Hm.%Z5Ԗ:Nv2Fd`}V9:ZMn&70[[+Pl ܨ:o?nװ&/Jy{8ϵ_HdцUi[NOfֲ6F3}(,~{z#.} "Mߐ ]~PG]UF`5 +azWi/Gg[[Z)Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@׏?WҸk? B5xEqa +@#Zb%@m+bvSY.fXԷhp 3x57'D_UL֣ܠ\Tטc·^,pinK7r3ZYuې s]'D_UxKU*ʺ96wgm5ΧlY[}&Kty16+}KZGs~o;1n7Y*x Ӣ/*N<%CNoHoƹhskuPٺ'*C@ #W<֚}ZDÐ 3]GeiF]"F88_40 Ӣ/*1A ѣl:x4y9=ż=OF"y&UcVDeHi | w DŽi?aQO"Lj ]]VKXS1ׁ{hM.pL6$ں :Oآ* k ?)l5=_AaM;Ka\:>34vV2 ^b$$`6g(Xcq wlAcw$ۄ9v r+֞=Ě~oa[)a/;1!E,xQiyq$ nm\<ݱ%<Cc;GoMk_Csky7srG (.Sí2׈4>5Ĉe]$BI?tWG5Iq6pGnks~^9wLE&ӿ]Dx/^h]sMɧ4%Lj/\KIj ﵲ:8Mk4&i/~9n]r\FH*)vXi!k iq츂@]!vdbBg&#2 ^uuӄè~ʒ1.A pEzVtcog+ػOvbM}|cy?48_VRMLasI]%0E6ZO>fh†\5SW \|T& s]qP,?u8n((((((ow:(%{]'WA\sa]KKf ( ( ( ( ( (9o?Rq.4ViIHci HѢڠ&xPK ay_K-Qde1]Ldp)gmŬrZYC /~r7Һ071[z{iw eou;󰸺0(E*FeԎWyY-%er(p7[:Ͷ]s2P0!)nvFįox%g- ^c.3 2P+Bq[V!y|1>ua5vyTSk!'{W''5n}#Mtj [g<2e=엣c{(eQ0Gc{R5/u7H-Go;\[GY 1$(ÉP:d &qv-#x* w@)]ܢKEr-A-k=>;ƍdX avrO,O&~&T5FgkK.w~Sb{ѻ=/GE`Y^^e6TqycL} 5~{&{۸""(H'M&OͤډD/hVY\"balHWݣl+O~OEh#`xr}AؑOtvW%u m&GW p iLţ'q†4,@`{h16guÝ*y<'Q\Z-=#Cvv]c*p ߒG]hp (Q@Q@Q@*ԼZG\O ) ѰQ䎵]>ynOaxRVVA𖹩_yk66)IYB_1`0O\ޝ%Z]!EP3=_V?6aͨZJ0G ) gPG%WUXwzՔMռ0+4 qa?ޟ7+6+ \IEQJK$$x'rq]sx$z_؉G1-ʗ?>8M߻[tRv춢fI@is<;ʆ#p 10ϼ3;%u[;ipL \xʏL[x$YbA(˓hV].r q9ZUy6;}WqDgd, L8Nr `V^7vqk(9EpA*Z$*(QEQEQEQEQEQEQEQEQEQEQEQExEqa +@#\?WҸk? B56"[z w6Ҷ+R.FVD*;QR0(((((OI`եI]O'$]j #b($+xa-"IRHPo!x =_AaM;Ka[ Э/&A%Bޢj`/O?V?_[Qp0 ' h_+h/(?Km4/O\ A%B? ' kz. [D|_MKm5E Э/&A%Bޢ?V?_X6zVH,-lk;hXԷp2B39W/ G\reQEEPEPEPEPEPkG+->D6}>5ͳe 9=?{+ ܴV63y(DFۓx$i.S[Ծy&QtMrKB0۾fq]QtzL.e$l=z)Wj:FDjzuhۑ.`YBP=46ݲ|-Y8Dܠn䏔,$hqa6ь 'y#4;Yn.c4褟&yVɜq=NsWKybegPcߌ~sEZRۻf7O;snv-rQ&MH,a$XaILӲòuqJ?SÚͬ6|B7 7Vl >VV6֜(]q<5:jE$Lh͟b]`,v )'q&fH} mij[jkv\A*\5Ĝ>0Ϗ7mN/p1h|qAE@#qR6PjOad5х|Ӂ~3tjXu}LX[4Y[tB;x`rMa=(]Ms "iLnjG݆ x 8l{i^,/WRKFe. o8 w2 `?KzK([ +؀3#_nq+NS}>K~Lo0q9u S-q%n; }c~{ A.-Vs:OBt/aI[X0Vg#0 qjQ-?bYtذ:7n#y 4҅smg3ʳNۢ`y}j[hwvPY\t֖`8R0? 㮴 SN:H#H0+ss2JIn.7wIe#B (Ivv:.ۛK2yX_pF3׮)dд]*ա;B Y84M.6Ow%"y9vpr21Zz ktza3uT.[88N_\ڇIm}P,fB2rWci=U(aEPEPEPEPEP.%Z];J`w]%"B(f?(zmmV,PXۺuwi]^˫]\C0Pȱz3?\3`Sڇu[\y ܶ3Uk=bMB ZgaG~#XB`hS`|FW-hz/DFmնuywiҢF%'$iZ+Es׾,v̀#jGwo]+RIieV!6G E(y?SӬm6mCyh&H#r$2;0[Pb @I?.M;Zژ~21 0b '<(͎,ޯZGK"3=[}c';N31BOK\eӬgk;y.E3ĥ2=7M1eirp88qpG hO~^L٣TYt`8y=|=LӼ7lp(/ v#尪H $ xkj5p0>S3oHgʮ Zji,3QbS3)i q;r{ݎ̰JYP@H#\H kƯfd6M0[(3ʒ).}gyIi3- 2ecI/khf!EPEPEPEPEPEPEPEPEPEPEP5,?tOЍs<\BJᮇD</ְ؉ne_P4_Jج}KJ`i[ܨQEHŠ((((( ?'SV'u?Vo?w_)K+XlD({ƿšw] s5ӿQEsQ@Q@Q@Q@Q@Q@qP,?uv%Bo5pR((((((ow:(%{]'WA\sa]KKf ( ( ( ( ( (8=VESح Ӎ>1}/j՗m 9V^8犞Pqሦg 3 g(ïl<#d2,Fˏ"ahv(zNK4/R$6˫ *0$7t#\i YOk0hfe_d`8xᴹ0B鼸`;l1*TsjՏVwu+ȶwˉvn:s_Z.|kͥ9e#m,B1c9 UnVVoiFBNwb-M;H 0xw*sibfa^hQ)ԯ4գm<ʭ:ȱePъp>'P D0o0Bӂi/ g'g S~]'$ bTE,/<k[Mwr 2yk+`Qщs׽1|-'oL4ofm=GD>mt>R+gyI@j,q12*K閫I|C E@w۵'P}j0n}/S༗X\$$J$„Up0~dQ9%ot=Z{ǀز}|WD""Oy)[mݷ۳v9ۜT6r[]2R7T yDϾTBi5 v"w3}|ݸwnyot [Y."EV_ICJLJW2ؠlӇ<^7kZʬx+Xg3[KlukXDi)p@E1a-9> 0<d1 q!cS9g4Nj4b[lDsD0]YQ9 о1ZMrJ p5)#U4UAmq:(KćaTT|皳mXa)'ԯghtrmA%:W;|r3E24dRF'-Nq9<QEQEQE@ֿan뤮oN.FIH(J`wSHu Yh\s9#*FֲAO$ʸ@q3an]I+&VV2O["R|eg۸&w.s֬\\"z䷷cRw0w4-⍧%KIf-eѼPd`62qӜZzKIb@*@y"NGy8?GÂDjܱmˈCG \nԚllr\]8XpEê,W`=h_sGry|G`q*HUFǪ],͔vv5rV-O^FM.5*$TܹUlx|m]ôar6B}K)'涢jɋ'4I.$Q fr*1u۔ q#8oikp3!c$c0#۸= qm€hip yO0dc;zzΞ'^ȭ4ah畑y3 l1IMIpEfc5 ߅4=, PuGǗRz=^,n-Uv?fFCſ2j&(;+OIuF2I1 I$Xc,F .2Wr0GQ\dݏſ2jÙ}`MW?|[C&~9\dݏſ2jÙ}qP,?u/dݏ4 궺ԯ類CIp`c5QFMTbފ($(((((ow:(%{]'WA\sa]KKf ( ( ( ( ( (&[:X[)7p7s16t[Y-&- Qv;# H]WhK4y⺶eH<#q>m,ehЅ -؅.si 4N :gF,KzI ;[9$9aLKan_crш4BsRp8sVhz/5]f;My&$[r2n-@x+TZe4(esz褹LJ0y dԴt;fүGl-Tmݴ.wg?]-.1F)҅l ֻJBuH~C-|W^]m ?̼P1ܿ(AΡ5Z_[vFIhO%r9qJfHc 4X:wd֍ED'ygh&V] b9ېjM?wj5ji16/6n ˅bxN1ZBfF pO$:{R~!cfw4jAcC1c0 ޳6]cLK;ˉb_,+*VPeVێw*H'g4pU 'z%+ p~˦i=%,r$s`20rV_j>!2]YKHQerO^9\0")f8Zl}d<Tc]Fp:U7y/]Kikb/#I"IPacW¶;t-:V}z7K8VG!,#rU}tkx|o3;Ե=WKm5 s`F,1摸wuRTӭ"$LGdL$޻-hft̐ќ ?5->:ώu}+K2}b Y2t ă =j'VMoIF5di[.wIQx]}ilEn]>ơ Ȑܡ8NI +9+Nj7[wTJ5Kؖɛ0FssTf4kiYn#.>XR0p 0${Lhi\$qwc2MS4UV_q̿a.L.Ip\V>"]·#5dGu]k1չ#ЊRǠ5->䪐8[_]ܴXE ;Z$5w8IN{ S7u֯j#i@ߨc ؓ 2g' 'nO[k:- 属$e:9MU|68L^7[ZpF]sHCwA.r*o}W첛'oG$S ?x }@18<K*}XH}{xA lI9o"l,%'w$ e@9[E'21~:OjlF#?y'j mH(QEŠ((((((((((((kǟ+X\5y"] x?_aТ* ( ( ( ( ( ( ( ( ( ( ( ( ,--F5W6pw"+IIT^:;]I7XrWxl-K4MSD,!S~IrKq^O|fIՎ·%ͽ}ܛ@O R1th}_6&mf*ȫ#Jcy`$T (((((((((Wwxow:(º]s u/- ((((((?K>v!6/nA , ƞ6C>iW#n3 ;7 .E-om,Q?oaN4[ѐ[S$cgׇ<1Vppa2̙˷19Ǔ޺*+}3Rkŷ42H%8yLqjl ɂ WUuIY 4QeUq yE%(m,s~'Цզ43SHڌĊB?0G@y H.JI5^O:O42y5s| Zm+z1!B*]Kdg&< pm0N֕#`v8AX [Ri ?Gy.fӥwul#7V-F[IdYͼ.9GcJ>BӴ$:WJp_j9q$in>q93Z3$ebPcYPG-7UI-&RlmÍ۱QM_0Zlpڏ bkY 1MXB>T`A)WwH˕y1,00G$gkyAhr^gKm="H #PJNy^-[Kp Wo;o8ۛ,ȃ~NyvQՌKmGG6Am(#kV0%q\ymEeC9#Ȼ_(|6Tu:)[[]nVR>$?s6l##*hX?2Bpc.KJ q[+J:Mſ˷ K #?nQ0VĊDL&B##M~y#85h=JZtݯ#pv[:%y@7`t)hF2T̟_C9M67F[y9Bvl"ҼM\:uwqK<$ȲU*c68==h(Q@Q@Q@Q@Q@ |mۿEk@O7@w?Կj+o+lPEPEPEPEPEPEP ˽oG𾑦\x?Xi졷̩d@JտM$WMEnj&(տM$WMEsտM$QЛ/H3Л/HsV7[_]5gsV7[_GBn"j( Bn"[oYEtP9[oYEۚ 騠.s?ۚ ?5oueQ@\5ouenj&+nj&(տM$WMEsտM$QЛ/H3Л/HsV7[_]5gsV7[_GBn"j( Bn"[oYEtP9[oYEۚ 騠.s?ۚ ?5oueQ@\5ouenj&+nj&(տM$WMEsSQFZtZ[ķ2B3H JH]5P (J`w[4WgN:f*FӬmo/-d`ZGn{&F;ϵc? تZ;1xCn A}sxJ\ص.&8&(aXPJ`91+[x{OmDޯy4 0=1Ѭ!0dc1e' zqҹ9uҬwڄKVlC1f)mɟr1c'p4]Vis"m7qŴnPʧc{f/_ےM_ikq,DkWy T$vU4Y٣m/Y]ٳ ^lm'WlG0) /iK{X`XK5Y.YOéA@V<i' 7w/gEc˶MՋ'y ,Ic 2SDK3"I5of @aa؆x7g~(6ɰ d:(\I2O4K&a mc 8૚BTԵ3M0;%ȓVBKIe7xXpܗ;( (((((ow:(%{]'WA\sa]KKf ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9 ѷu dU=_V?6aͨZJ0G ) gX5u4l?-~~/g;s}^v>ke9sT;*<ܞU%2 *" "G=j3"iw׎:|<'{N=*>V;N9|jvH% X=d] P$+h=1ѤK/t96J[[%YI >psK]sM2w a]q{ZƟC-AbYě;9QrV򩇆.m促8Ei$y M؜i[G_CfT#i//V4ʀ1z*+f[$g.9#@8T{;3\u-,U*`F.~ɑ֞Itu..V-"HF q'$c1cPm4,̗SEiI )9>C:,Ua2pp{y.mD7C|w?ܬ_p0N27<_p'%xR&ww=ޢQeƗjVi=u = ڭ"Juu*r2"al1dXܾqozڌ8S2dc<>)GB\nś\Yȃil@(_guA 8٧LBOg9ž5Fo-_D-ܬF2 O7}ߘml㊣?;;X.(cDsrLwjiM'}י>kqOi줄U u3Z+u QDFݰ8ʶ38sLW[i%ߐ2_qzMF_ƶfyx߻{nsޞ(ӽ?\\. RHmȗV/8A4homYDMЌH?@2H xxIafrW# #q&[FݚgA 7E71'<-5%K5+miN35%e@g1_2 }2Zo O*I5IRVa{n;s[6bpیa=)+"J fY)Q@Q@Q@Q@Q@Q@Q@Q@׏?WҸk? B5xEqa +@#Zb%EUQEQEQEQEQEQEQEQEx@SNkkǐCuᄷ&]KOI#C+A;P٢ ' h_+h/sSz_+h/ Э/&7iiw}mt#9!s FO$ ' h_+h/?V?_G [D|_M 7A%B? ' hz\6ž[9 661VBx<ßZ_+h/ Э/&V [D|_MKm4ޮ>_*ׅ/A%BҴEžake YػGm ƥ끒ϰc(Ԁ(((((Wwxow:(º]s u/- ((((((((((((((((((((((((((c*FӬu{j]&BFsl8=_V?6FiG`GTh _cYͿofcwgڶ?wfv7}qjʋJW1$i4Ao*g H88p{vz#!&+p0#bisIf8bEnIg#6#&)#V =rpOӚv_cю4WNHpHe*;z UmSXOm-^+r8zWᷲ-8'ʹ!@Oj9-4۝I&[d ȭ,JA}phw{nZw,biAB !U\ʜ= zeݜ:n@*cAj7y ݴ0\Z#u5NQ\Jèִ/El?hmmܑ,e**tw=I5&Љʪ0Cfs3}QAEPEPEPEPEPEPEPEPEPEPEPEPEP5,?tOЍs<\BJᮇD</ְ؉nhQEdQ@Q@Q@Q@Q@Q@Q@Q@s5ӿk բ+((((((+Jak>_*ׅyEVaEPEPEPEPEPkG+e岼Z 9D LadcINГSsn`x.4/F&I .\Mooɮml0呷099>?ZQQ,bhVPFˀ2xG:[I4ΥIԪq?YRZӾmZHY =h%:mp_Z+7[~+mہWz`-UcukIVdP @-$X_im,ҩ]EVv+ 0ВS{'EW:)8٨>3/p;s]A(;֫i5Id,/`pӡreVnVMY!ES2 ( ( ( ( ( ( ( ( ( ( ( (9Ȯ?!apCkW t:'FKsB($((((((((+ C\4-Q\EPEPEPEPEPEP\|T& s]qP,?u\7;(3 ( ( ( ( (>@%{]'>6^I㢀>o+lW?WR٫((((((((((((((((((((((((((f?(zmk$L$9?d%WUXkrkWQ^Yb| kzqXhLu n/'h^s2Z_/81wgkf$ o/,!2@c%:0zdzHzٙmnX i-|dd7o6Isirf(&푓~qo m/5 h%iI/Z?%Y3mmr6acI{۫h!T ;e[.<_HchF!Hw Ǡ%tw:M6RQ+Fo&5$;إu}{:wmm6u<ƞhLgQ0?$4+}KSG fۣEH*\t `-u}FM~k!襄 ?NJZdӴmI9$w29|zb{=u~F|^M[ d-MԠ5orrp >A!*v`0{wl-Uv?f( o 4`MW.ſ2j5_ck 8Oɪ߻3Gdݏ,?|[C&~>-Uv?f( o 5&V\:ci. lqF:݉ފ,p)QEQEQEQEQE+6MI\ny Yibd1x^HOS3Pݍ)Iٻ|GoJ#Kk::eA<kNk`ͼYC%G*P 9N08i]*pV5{q[mP۝8Ta*$ۃ3W*/L_,K!bEeFv1j΅sM56{'% |dv*7u\!}UUپ  YY7.v(2nc ;8F*܂E{#JnP1V%P!@=*S!aEP (((((((((((((W t:'FȮ?!apCkXlD4(B+gFYZt2]J۪#1+t ?5oebj9k9\cV[6_G&C~ltcV[6_G&C~ltcV[6_G&C~ltcV[6_G&C~ltcV[6_G&C~ltcV[6_G&C~ltcV[6_G&C~ltcV[6_G&C~ltcV[6_G&C~ltcV[6_G&C~ltcV[6_G&C~ltcV[6_G&C~ltcV[6_G&C~ltG:Z}y>kW3hj ( ( ( ( ( ( (>@%{]'>6^I㢀>o+lW?WR٫((((((((((((((((((((((((((f?(zmKej|p^#%~f@N9E=_V?6hC70tc?ua?-1<[f}rAkv? A| Ey!fid o<k7~>'̌fʦıI%IeHb8#jZq].x^E{H&FLYp r16K+ w*u8*Ų ݷ30?[ 3}u]cLi ]JlNQ԰>#{a@Y)?wg]_iQ >hG5/,?P3~CA=‹'dTr(@`9R~4X.L4G{ƨL]owjı  >Syh6‰87gBPC@7miQ >]:=+*\Fwߦ .9m}JdP!AOB?0X.iQ >oQHf&g#TaϮ;5[P&g#TaϮ;5[P&g#TaϮ;5[P&g#TaϮ;5[P&g#TaϮ;5[P&g#TaϮ;5[P&g#TaϮ;5[P&g#TaϮ;5[P&g#TaϮ;5[P&g#TaϮ;5[P&g#TaϮ;5[P&g#TaϮ;5[P&g#TaϮ;5[PXQC>c>u ]Dyw(uD</=,?tOЍk QVHW;qojt1[4Jy18\8]sz w6Ҕ܇ OoYEj'*5hZ^rnqt:;j㹃 B~"H5?ev\/Ŕ8eM ]*XoM.7WT3[Hi4]ϳ+AП/H OoYEY_ g0,O+nW$x9, \$Sk- ht t̊"$ ? O$S!\aV C)p_d9N*I|OO-Ĩ$VmMȪp(FKFqwWkAП/H OoYEYM95Ğ_,2`ci<0-0B2sp<|sE{9eoH5?eAП/HIw~}.{v f)l=^mvؼ7(T*Ax V)oH5?eAП/H/=2;h2N.*ZλN܀ `1NuYBuud:n$Eн{2$ ? O$V@%{]'>6^I㢀>o+lW?WR٫((((((((((((((((((((((((((f?(zmMi&TQ`BG\@Ny 5UB%di&?Y{9&[dGە`!+Ԓ k? K2c ;R5ҭ[H՝WBΒwCiIY!jahG $9'ixuW J⮗D</ְ؉nhQEdsz w6ҺJ/(/mL#7"oB s~%V&=Ɔz2N,a+]?>T35M<\\<ӆVbl]%Uf9隍<]maGN<7tA8[N͠Y=ɼ9D[z}s] (f+ QJs$EI*D1қ g+RxZN{$H HsvƊ5Ej0 i 1)6xYPO*ſ->Ύ6B*q\*QyEBWؐ7{6c%r%_wMt}F+y{<a{me*AZPՁTwoH,/,[Ǚn`s Y@3 1<h]X쌋 &{?1r q}wؼ_eHDXC.r'1] 5ubc9GfT> iNc-ot"O#UM2 +&%HBXNN~cԞrbsVBZmRiivRٿ'-zR^x;MYnIB eC\.1l}v+KZi0t |fa"r9Fxd&.OdkȰWnAX2Okzvso[mQFɝ2xX2hة] ]GH)$'9iVWSA:[xnq5qEqr.O9FHǷ =*(I%an핬=:&8C(9ǹ9&E2oVrA x PWw[ESQEQEQEQEQEQE+rsI\7/ܾy<]imǦ],WmdG w#7۞&z.-پN(8  9nn_Qѹ}GX^3V5iSM]ۙBO:ga]R}Ph{`Pr﵆}:E>V%8[n_Qѹ}GXzR?e8mX3f3ۏz|>*o,e(#}pF.V&~u.ሳx&2 rV!KktҮKʳˆ\8s8Sr΍?:nt׺|SHed :lV2[r΍?:EVܾrά@/ܾ4Pm?:7/[r΍?:EVܾrά@/ܾ4Pm?:7/[r΍?:Er6 dqWMkW t:'FKsB($+Կh ѶW7@m*eQXQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@%_"4( c7QEQEQEQEQEQEQE|JnO|mۿE}?WR٫WA@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@PXۺPfL<PXۺuԷwXn2Nx[ӲFe^xsJ.kwx0 0d`sZofeUwVB,@ ~Q֥n9Zڛ+t{o7v6߿# OXGPbMr6W:i4Z\HV<2'BIg8yD_lR+D󉏖+ч\|͜繫>Ո6d!c6iBMeXe\yxwLܴ2@ߴ67ϽgEY.Qox=Ȇ  Nk Ėˤ3[ɗlāmtty&L%(Z;KO&(lJqpG=):!f đ60N`y/f]FYڼ gcJݺԍ^ tPy2atWSN/KHZݠ+ĝ 2sŝ?Mi/( 23dn<0]kZGsw6m.[1v27ޡsD.}?uU>bx8 |5V$ixFe{c#_#ݍn83K'٤F$$o<5ېϽsxE -Fݠwd u-n5 {WHٱrc|^JOEprQmYZ2FF,qw,IN ګ20dF @qڹ[^+Z[t1pO ll3%Jn-@YМxj_as-,FpY##cd)8EKegqōIAױ'#▼ı#ˌ{qr MӕXPpF3)YV۶NYI?Y]پnceUNE)XU#pǧkEc":Aqu}n쏴1ZKܝB3(S6؜۷6vjoE%Q@Q@Q@Q@׏?WҸk? B5xEqa +@#Zb%EU k"FH&kr cav/=mQ@7 SWTG SWT] ?wy?wysE  ;  ;빢?uOt?uOuE???hpOA]Sw]OA]Sw]w4Q`8o@.@.(7 SWTG SWT]X)+)+, ?wy?wysE  ;  ;빢?uOt?uOuE???hpOA]Sw]OA]Sw]w4Q`9}‡CiBdY[f`@KHI<*uQL(((((((>6^I㢏Wwx ; _[5t7@w?Կj(((((((((((((((((((((((((((J`wZqIe+:qd%WU<;j6}WRHQHbbEU_[ e֦D&?esu#J }+k6H]c eu=Nme .!X(l&n%Z,MnmI cqZC-&u!vm${cұχZЬ6^I㢏Wwx ; _[5t7@w?Կj(((((((((((((((((((((((((((J`wN˫t!Td'qSc*Fc-i] @_ m] t5Q} 3gv13Io|4α].qWrqNw#MiL*J '!q<'Dfy4'%nz魦hZŽv'4﹇?5*Xt& }ϙVF?tv: ͭi5ṵ{#nS[{g[1E$ֱGg U 8 ;/xNm>y7[k#ۦLJqAOIoPm$6L;ZK0JQKwqxڂ)>TBoOV',2Vju( Ӈ^0?#(]Ugr+)ogb}2X4/^__?*ie<|''Gr$7{ ɿyV²ymO=Qѐ=W#(7/xs n,4Iې9)Ѽo8±Ȭ@+0qmhf# VʖfyS7.9j4! $(qRw}i5PdyHQNi'3jut7fB\(/Gҵ屴r%^0Sӌ w;w5FX@օmF|76\GutO9^30J*89 Տmmtm`71&Hg {֝agqZAndD%PAF}zN,Z}xaT/ߒ4] ҺԹETQEQEQEQEQEQEQEQEQEQEs^<\BJᮇD</=,?tOЍk QVHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE+ӕ8lo.IeLӚ7Җ31dR,bn:oJ~Шo!Up.' xO6iV?},AڪH^603ﱛ7t^ g M K#;tA+hGJugL^\|+"gNj&O^\D<]ccbv=>2d@Lk {y޾D:D,Akk(!&Hq!|E[kny6]ZRG^qސxL*Ud{y2v;s6g "I+͸mٳ8pG3^<6kl5[,/.uS 4>b>݉< kx _ǧ]K6l4{cBa0@ZkV7']1Hvܫ#NH'k2wٮ1:@d۵IC96bTcAa "Q'l}3wQ)ɢQ fcap 208TtwiLeXok{*6DyI+-ڪąf;pH8-{Q$pRr+e{fF  ,X8\jzT/_a$l>\غMY\YfOYy䁑zb|] Xp]5;Bbz($!]]9RPxfSPm$4lPRF^Ea̻C ( (9Ȯ?!apCkW t:'FKsB($(((((((((((((((((((((((ow:(%{]'WA\sa]KKf ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9 ѷu%ēYO gLPXۺuƶWvvتp1F8[ӲFQ\f&rnq cLίW96a-vm# w`D^f#o+}&.|ausi4Dj! )3f@bI\IHYs'̄cw pa]L2ӤM4XsaHd'Cc]>Z3 <\I|ӱm9l&12nb%9bI'П5ue²3 *=JWڮ|;u,W׏ő&>rsߦ#ҭ( 0}HTri\EsGE <_\\]#o0{SՏZ<5d-p8eyqVg$AEA9E8Q7s\ZV|eE_ū_XJ'pml׶sҪ/4tTx$}Χl`V~<86qt&%A*N:t查TԣQ{lh=lsq*zf[7_ê>֚۬+baSo|-gA"_O5̒GfYR&9Oz:q\Ğ<QE&/~ۧ8Y/."[[[O! cct'<8+G c𭍝٤R8\x돮hռ)k;A"96xY;M]nl$[K; V#:X'c${ڼ1Go.I(܊w#܍;_4VݷGa(D *QNpQ`A;o\r2I`n~ezrY\\ʓ9F1ݪUB`QӌW>im-ıKXKeN=j+ĚQͧ 1}*J|{~vTW9jw۫ai-H;8fc@y㞎'p) (y"] x?_{ǟ+X\5- ((((((((((((((((((((((((Wwxow:(º]s u/- ((((((((((((((((((((((((((c*FF:P (P;ps'G!vmt>gK-SL]O *@M|H+g#ߩ'4Yw|.UEyGI%-Y*ks`cIky <>nFB#F&ԮkzhIC# r=_sRmA`-ܒT<Tk.s!whB˾h8L)5;zk6zlCqUfDr@N#S\!zl&ymT#E8cy#jO @m/P̻HCIn oAO_qsɭPˉbDѰV$CG*xUj>5 Y@xgn g6a+dP[L]GlddLbW!A8J._%SI .態'3ԕ x$NKHEC),)9>xK1E%V]A,13m` :c.+Q΅p꤂?E{%r' #ILH7H`4[6Y[E?8+v#s'g,]ʱ`ʞbmnn\+7RQnHI,lQd ؈?y˹.5bv yg Fڸ``1EZvWWPZMup! ' OTfF|^Dț,f@ރ<ӧz]lJp2x*R$ 1mdH#3[{rPmN3MF=_qsI:+^jD9STGqxX#cJnk8-m\\nH f-XO56CRn5W(LFҞ ;Wq_ ŵxxL|eg f.d/2h9"R8EUBF@6TFGJ*mHDf MY՞E]QHg5,?tOЍs<\BJᮇD</ְ؉nhQEdQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ |mۿEk@O7@w?Կj+o+lPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP3=_V?6u9 WA%ydtPXۺPfL2ݖeaՔi~²y&߽یfk=KMO8Q&9Mr߃qIRy"[s$`s]rٱs w*qi vꥂ7q jN6b8Lj 2,9'$I'O<܉P20oo̠qSN7W2%3kXn%ѩiDE*C2G>x9'P`'|6ݟ3f0GgڭNh#oX d ܁*i({[yF7˷:0Pi]ұ=똶X.-\8i?3Oob,E#2 \cQ2iG|"-19c;xUɬei!0ugcr=vR_f(^m&$ c P'm6sK<CBN$fx=~Vtm8ۉ3w@46縉 RZ2[dbw?# O` L:jiki'#_6P(?z|i6d/s3r#BF(ZB)I؋#ŀqf%U1]AtfQRXQEQEQEQEQEQEQEQEQEQExEqa +@#\?WҸk? B56"[QEY!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPkG+Yg- i_8]ጒ' 硋YҖx-<~R\d0T@ Ec;yD2 z|Ñ;oWב\1vb>Csoz5=ֹrWdhEij,M0c9k9kX}_iҞXo3MXI,vȐ8[vXI]>/sZn'KNv;]܃y{%EKpbFc#}gCkBj]Lr_K 2*ʛ.̸Wq֋vg%^ yγ@lq 0Dśxi;1kvE s&P44¤BCCbxl.$ñ;?)Wt>+?6n?=wD=Xg:ѶWwR9B#X ;Fcԑ(t^y}3Km?P%$/;HcCҵgycP2"LfNAps>?iK} Ϫr+ۜӡR0B]7!a,Wrgө&it$AŜ nsW\ntKYV)EEȮs4;ZW4hRk:\-˩YJ :s9>k +o9+ p$#] *dwEPXӨp;s*M>SEd•u{h(((y"] x?_{ǟ+X\5- ((((((((((((((((((((((((Wwxow:(º]s u/- ((((((((((((((((((((((((((c*F֞luIm>+F (u yX eX?d-$ҹ=`~{l/A&Ϳ7coV%5s4kdȞh e!^ӷ_Ix[8 @ޙnx'?s|BO"1_|<,ߌ&Dp}8 GпJBEj2!s$Oz,LO,DRB]0:gzwk^-߅}LO@02 oiȎDo{̖67kf8 ~K1''96'L}?¶Io>ͼC j,C.KyQ3xZk[MB-KN݇{+{s|B |HPe,r$Y3ͤ"|&ZOio<1cw)nQ!J@_a\xZi-5,nURSey%8$qc肺 7?)1{(>gקI`Z_4eUFO0cq5!Z)w[>r$"3q WI!F.g"f~+y"utH>OI'Nzc޳%cdQ!FFpl<`G2(Q!OūXʟâ[6nBYǜU>;뻛"J+$[nRQWSҗWDRM1={-C0am-S) #?s|BqOs__ ( E]v݌E,d$jw?(?qFܽ t%%-GI=][Ҭk9I~bFP0 =ޥ?s|B=OEA!FOEA!FOEA!F`Eqa +@#\׍ُ'?0Ҹ? B56"[QEY!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPkG+P?| ȶ\k+$2$J\</`0HʹCVcL. Ds $1[k<8뎼g-uV`G򂁵O'8CZEƯ,?gڪtBq~[O֒r[Y\aU|UwrK |8>$_)JizbC,"FKO=O,Jktf צ53̼\'ɍs]Woc24'$s`D=8.g^o o [w'9[_E1ܼ6i'XRԄ6qor玚]G[<")&"X$d 9Vs5қg|r9?)^6,Ot&kt+*ĕ8R1~|K^IyP` p7e=2vEecKr΍?:g՝CBV6;r歏[\MifG9vU8=QlH_r΍?:/iP[YM"[ȋ 풢Lрlg2xY GovES9ѭ}GFe?bX<_<| TyK[HA2WiA}GFdAhm]̲"bS%L݊/me[W)q,A\G*~ys"m?:7/1NjP Tl"49c)Tl H+=wv-~ 䓱}GF,KsmmqnΡmr 3ֲ5Ŧ]m$pZʯ'K#HE5/ܾB&/\>wiQfʌ?2pGaHd>*Xw27t[pw\ܾrΛ_jfMWh9 :HVܾrά@/ܾ4Pm?:7/[r΍?:EVܾrά@/ܾ4Pm?:7/؃ᓃ/]6 x?_{ǟ+X\5- ((((((((((((((((((((((((Wwxow:(º]s u/- ((((((((((((((((((((((((((c*FF"`0:d&*FӬ.ŕ|KvS] 2vLVRݖ6+>EGWT-)3nHa1qZ^#\m%фHb.T%fĂJtԭ I][*i6i͒?;re${桺y)A䘮$ |jb5na.0KnF G nu>Eyuy n31L*Ly 91UqC}Oikd/4">͙ȅāFeqGSkUuvk|g[Afi6|7g*֘n$[cx]d"?(brhvx7kh-`8m[~WGduҷ@V@qFJHM4_<>N?^C8?ei YI.%7®7gF:U ynnZCM{: z3BOS`I6}RV]k5XryB'$$sUw{W41ڨrVC{ҳ-l-'[>fw9{_IY8,ggF7L?xܓI(wՖJ(@QEQEQEQEQEQEs^<\BJᮇD</=,?tOЍk QVHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE+ 8sެVׅܐ*?$\Iw}FKBiAYFEh}^E<95a<_{ MBϐ n$3$6^I㢏Wwx ; _[5t7@w?Կj(((((((((((((((((((((((((((*G]֮dXmŕL/@e!Qde(v ]=#.0(r1ؒ==?s|B3ۖ4K+m$ې?n] t)-bA\L<,A bQׯ7?(?Txv2+e{vqϑtN/]$vil)mٍ>>tQOD.u ~r}?tqƂPuSɏ=w 1X ][T}8<woF4u?s|B`e=w/۟nSw/ܾnQ!Mܾr΀!F7r΍?:v?:7/۟nSw/ܾnQ!Mܾr΀!F7r΍?:v?:7/۟nSw/ܾnQ!Mܾr΀!F7r΍?:v?:7/۟nSw/ܾnQ!Mܾr΀!F7r΍?:n|0A9]. x?_g *OЍk QVHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE+UA;MnQ|xܻP6 r:9R;⣗ZmY]=YchxɗcZxgK !X]U We rYm#"ƙ$B9ngKJ{g:qUͪљz5KSڥM2tڊ̻XHAMo{ =`h?&7ISrogoonN̤ĖI-Z8b nnӕsҒkgљxJ $Y'0rZ@G*ԗ6$aQ4y_,I# iё1y_~^O*]r FV@zϭAi3uo=Wo UmFvӖ FHO+$ы+[D)d9fi=K8,2] .3F@,E9.ys*ɸ L ;@{&tvX񄰽2dU@ `\541os$ǀw$*a&$܄$RNzd2H)ʴ$=qѽ-.QRXQEQEQEQEQEQEQEQEQEQEQEQExEqa +@#\?WҸk? B56"[QEY!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPkG+@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!Vn>@tCI[o?J  ?%o+]a+7G.߈0䕿诐?vC$~!VnWwx?[ڵ/KSv 8P?././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/_static/pyparsingClassDiagram_3.0.9.jpg0000644000000000000000000106234115134002420020555 0ustar00JFIFCompressed by jpeg-recompress      +""+2*(*2<66caɿ!09@G9n {duol`eSFM2tr`s@||pհ2f"rw kd.SjZ;3c{? 5`"On#?S0հ2FS`5:,$M&?I]:u_&l4 UDQh2RkLjYj{88?IXNkw$lVhdU"^u`fߐ{S_un΀=ɀ Djzé1I\ߡ@հ3m-egwr`sT1khRw[- [#":oCcm/;L*5*lݫX {A~rb1@հ3Tcj)wT" eJ&?HZ1v lFT !:'P3tͿ+StmKWd?IXZ]f`"NX`eCNz{ёR5KKw? l\F׭bw_Gv⊵hm߬Y+5 =n勽s=Iyk׽{0$r`sTl^~-Xsyv*.1*h [#9Oյ+ Rdܘ9@U%kNJ/~ *">mho`f^؝2!'4"{? l\voZVƞlhhJdm| [#( ȻƥZEt&?IZ5&2ZgLV5i } [#"6P-giTUDsFfc=jL**ՖA_k5ywHVr`sMN܄"`"E]_4Vʥ'k.5j~f:e{? <ڌЗЊ~ [#*Oysx'f09@sknB*"+*Pp=}-] m\0tհ3ܘ9@U%kuovʒX} smB:8jL)qXmEAkO; =,_ =PߣVȈ81ߞߡt:톕1uܘ9@U%u᥵=ӞlEZE_4ޣ .پ[#){.Xz730[u/+EvkkyZf`d2C|j_}-Gz'ĎL6Y#>7ԸثXr {ٚ#VK㛑cV{'}8c牬mHL*^W gtI}xKT,܀V6O3Eͯ? l^ǹ½''EZG1Hitiەn[OAiX\~MkojK5lӮaé%c_·̙1inɂ>@9@Sblո* keBk-{UXNǶܘ9}zg6Ll2!ODl+Zy)=!kk/a3 gjI~X?.VWY-Z:-sMҀix-=b*" }KGIiߊߑհ2Xމ߈y(TJ3`&) +-)ZԖUDWttj۫ [h [#+kWfW JS4=ɃR+`sMեbҳQVMӌֲT&r z>vq`dDNm:톅Č& NgG`sO+7%[sK.?S9b1[;ޓOsF_JZ/-Zeհ2봫/30[u:} {zkkݏ@ M9@'XْZ9ĕ*k-cnGU[޺[V \mIYDD{5IC݀56.cI'+j^=˕\*}X)r3 ?v "`#|I@InKljFy7}#Z.Z[$n+򉭃SsCwǯOjm_ܭݳkO3P=vPs{7אܴZkZ$B"~V qz˫?& N5aң'!6EH':84e 7~Z3*"!qeFU1}6?k1N{~r܌w'm_ +ׯ}4e"߻}*")?Φoj>ڜLr`0]*4o8 ʯq @svrްk8>X@հ2 y-zbr^h٫0jrkLn›1.BC^PhO[c|eG1+D>oc`d &se!Y7=i& Nc[c&6|)9@s:ۦl&ի|kZ~Hհ2&/*C O\M٠`sTŖ"ɧ_wv"`#B#ަ_>`:5lҮ ^=ɃSJSl*<?I؊nn;0U?bmհ2?w_׍R7{ =ɃSμ-S3Wc69@U*] J6zj0gV€2 ["Vѩen{Wq_69xN5ຯf9@U?=k٥**"9<߄oR෽t,᫇ݠo&#gjjx? TUD}5I}M5ls]^[\gb^{lJ P9@sq=s*"(4).Fe\,d{ͬqjCdd$ܘ#VZ>*:ڛ Xґ"rVTLfmK+r'qm+}vc׮FWEkކB{J/wJkr7و)-~dojHjW,`##l*""b4u5$5үZw@հ2#}r`d+0sTV }X"`"[&)XЯY+=kp4Zum/$ܘcșpGB`}+bs6*罘Y; V=o:{p$cdlLW[*"&~N ~Xb5l1zJ֙7&` sQR,Uޙ*"9zC׌w`f֛).r` sT[2"`#G}kE%FۜX+}31Lc\*|v0x?֌@ܘbg9@U9ݬ4."*"!S(kkq!MiuWBl=ɀ|Rc߸k-ݚ{= [# KTP QBBvAVve5}:vRj5?Udc:7v 9@#dGxWW,eBLϢ"_"]?QA~Y1ӱ?H~ ݐ$2A8ys 3?1mkl`eӱ?U3Y@WXsV?6;}GLvV9@@j ݐTa's l6kv 9@0>EՉ|S?@gb 9@N7aӖX4*ӱ?qJ!5>vLHK&Z\h?k{#/Wc6M݆9@,y _v?Y-a+_qgHL*֠VZ@s*,4I|=6']5+OnHˀ=L>?ܥrC-=hYx%>*9@DzD}f!4-?`alRaamR)p<R Ŝ8s /Q,`?VZL5CNlłήX՟t&܁%0|_04?y&{cI[ۙ[+Y&Ԉ[pl *֐s׀zgϦ R՟FŤ ̀W%c&"cY]ZtG@ *DK}9@u_)f1Nލ5`õk?+c܀VB3^ ݑ[Az!ɃnF`p#| ͘ 9@~DsLݦ]6Sׂ*ZzЊr9@k|zNjP+3KX:YU0(:Ԍ+7fDUm@9@HYN3b|kÞ>K7ae|sm̀AkYQ֕8J͘"RRB'BKxwNgU![ 7s0EYޛGkMKX*? J4lA[cٶ95v[goI+?,@Ѳ:,0YU0"KT~'sV+ 5rT퀎8<?[؜+oUK$ǰXך U9`j6Yʝ8 0Y=Ip!bVle1Nk<-@Tʴ̈?nT1+YSOw ͙@+"e&R*p(05G^e?o+QkKr7+VWX a 'c}iY9@ B#0hhknFZBgCח߮؊ݐPsfiyd 7ݏSlif!!g,_chaƆΜ,TTBfcCgd`YZZhҭi{b $ ͧI?F W_j)/SCC%wDnȇ屩gU), .A;]ϥCSoY-̜tk@"?;VU Z' ŗެjbuaWsh[:YrZ,­i+vB#2?Z~"kۯb&Hηz[L>EK_.XHX{AY9@/E |[r+0U0@ ]IPf1 ݐ :0+7?@u 0WlBf1*ǹ@pkCX? Ք0VXd \@W,a\UW,`[ ՔDEe-T!))`D`*M? ݐ{@VY@dj{Cv8b( b%l+}_Eo}U9@W,`0+v@Y\r[ 1jH Y ?ە:4>W|\o=f|Bd{]r  Gm +'? ݐk`Z=UX J͐ 5[W`Z ߕ.)(v +0W,`Xb ݑ?dvg Ք b*֣z Xi¬>W|fJɳkr0+VPW,`Xc ŝ?b0ڀ(V쀮؀1,;@ZBgFՐٓR]r Ք+0ـI? +0ڀW,`؀Ud&Ԗ@N!"#@rTm?b; X[d U? +0%\ \2X]SXo!5l+_ ?c( ǐ W,`G>pWs+6`XfWl@fb װ**6뇠fkpiVlß<cdUަ_͝Vc Ŝ]n|@ U V]`v]W (, jŜY@ ߠD}sXr\/͝Ve9@iVƘ*6C{W7} k7= o0)S Z4O4vahdҵeV?*hVH81*}U-g7"o[o`5l 3f!ұ{p (H"@`>WH!?!`[d"4>51KoJ;`вĈ{gұ@CFon!gўXfBG{R;}csdVy3o"}V쁇@m6'$DP 7v>'YU{A?1Fm(Тt?DG9K˳SRu$ Ze""Xfs[( ,2+vS+6`K1Lݘ ݐeTv?\""\XUp4rٺiAs6Xdr'͜sn|\o1y@fՙŽlCosـ+pk@Iʩ  xjuP"dsـkI>W}#a?F{"r9@hdj'׃+v@WgB ?Y3>m0n+ )؁9@+pWsVIRp? *6WlA>s&:P9@XkOvp9@8Wz q[x*9@X" T-@?'<3X4 @9@XBb+s{@rN^=X ZsrS%vďҝ?V,@ d2Lۛ+KbbTsd8yz> 6e 1IZh?d 13:`ikhb)xY&|zrF6=yXMf/ypjhjMB[BOKo L+@JZ-p?:1zb4m5#dn(KBK<Ʃ'98ytM-٩{` ބKz#A9AEfޓsLHCKS-Z:FqWL/liʀ T(TAw?c4ͯ@9@ӫ誖ZW3#l<ɀc` #}"DK4%s9@e ) O > PT?n@"R)_KpYy^7[_s >##`"{^CFt*6o5*׏v'V{NlW(;8Y{$ XIՙPܳ@~>V2|ǛG[.eVBifaK[viHoRn`ibkբ,0hY2X`pyyJKЋԃ^ȭYT֮Zu`ڕL]?NFhDhyov`Z+زy5`~GFOO=OR]:ݛsRś CFZ,A2NToqՕ0MʟlȪOkHyx /9_[[R>KZ^*4q] Oat&t}Ţ*Og6b76qPjL5jM [47nԏ55"BFZEiU5,!TU%A`g*֑Z# f`?9=AֱjUZ$;aKz,ƗWm)j7/gjM"pu.M]k?H9F];#%c}FNQR=p,NӟgI bd|+:*q61`ùGkCwfVhKYڶi>#vr:zmVޱ䖼\5UhP {+f/GfhұjͫD9@k` r|(0k#VcӴyD}Ռĵ{fpQO~pْFFr*s+r>S.>nŃ\_tc=N}KĀsT-*6jTc8m5!:d T+pU /0so  Xgrs|U9@j*{@ V@\9@:`& ݐbh^nsFjXPV,rd++vC?7R‡L͜V*V,+#?&$tCf Ŝj ՔjsF#:5aW<&kw `*X7 1W,g?m^3BҞگҗen&g#vv@Y@V6d9@s#k{9`9@(Y@Vl+v@V,MeQR‡L W,`+v@ +v@ IdcedKaCn+ 5qoX[V?o>=Z~}R‡L!jr<+ ǥgC4 K 0sWl?@rr| ݐc9@s#hx:5K:`bcXYW,g?lZx3{{CG`jXPg nrsFܱS ~k=aC + +01iIV?l'ʼ̒ K 0sV,]\؀0XڕJz3Z'rl,0=#ljXP9؀XV؀\9]k9@A v ͘vsFBaC+v@+VP+ 9?m.#R‡L+ Wl@Vl+ Vl81 i5,(tcnrbvZ g[P_ K 0s 5( n9@s#q@9@W,`^c]W sF\}4}}:d=UkhI5lI׻sK6WN绾#l8<@zg9V=(9ڿ=?6l:}6]:`֮Je:jtzrٍ,Ex}:ލo/q4kF7־/l\>tv+%?l>kgkr`:`ǀs amJN-y=y{ݳoQPb T@>Y9@s#h8Ŗ>뷃R‡L9h *rK3eR=>AZϠ԰?`E;58&,?o;KhvNqg~'l9@z|Ymd5,(t輠D&Zv/&oaC+>. ,?6W94~V,mt[:9ҽ`BIi]OZţ_5,(tڅrTW,cQ``a؊3~jXPU 툮cfsF#6uq3j:R‡L39LZieXjhYS: XݹIjXPiX`la mrU߲s6?39@j yгb?6sMxfImgzpZ Vvf CchR>Rj5,(td +vJ+VPVkg?Z:$:`h V{@ גƧ[mU{aaC*WlAYx+VP+0?mnע#,;R‡L Ք"e=U brѭNb_i,x74~N:`br ͛_B\ i?m?Y 䤑?N/洮‡L2ha'A\ !'9@s"$VpIa̓ߒ9@jc+VV(y{@j;:` Ք ͘ ݐ~d0s Փ0/ʽkHdϺ0s ri#`+6`r@7chnep&X9@skHrd*vj+  0 ݐ1֭  g ݐ?>{FMY^RTDԮ4qVI}>Fݐ|9@m (Za5lwp|ϗb:cN_؎-ri36op92F۷MMh[v;8i:_+rQ<`tmFUB{@ br7>=г7B& г7p?y}$F9AX P g@@V6;v'sp "IFrgQ+5[ECfm-{eag]o@ȥmCT{MkZ)9ںv]`݂o-'6{NMw seBG+5BvTKݾǪ%hoq}8DiwN ij$MnhC qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8Bmz_~6=PwGW߻T+Ǫh qq}8we*ت\04*??*??OʳOS#7|?uj`ÏAÏAÏAÏAÏAÏA:gar#s=[:ߧ-y9n;ηquN[rwoӖ~[:ߧ-y9n;ηquN[rwoӖ~[:ߧ-y9n;ηquN[rwoӖ&1ll>Ku!l[?pUm5j;F:-^4U>*0y !dhPgHZ5$Lb`h=W8Lϩ$'B3NIzn:f9UIZ?$Mk&BHg u8DZ+O0U8,Qݥ(1mrIE|6|{nЏ?OʳC3U+R0>;C 8>;C 8>;C 8>;C 8>;C 8>;CU|مfr?,g=ʟνrqܩw*:ʟνrqܩw*:ʟνrqܩw*:ʟνrqܩw*:ʟνrqܩw*:ʟνrqܩw*:ʟνrqg~8}7|>OFXs)g>r(vg :/tڜZ=Qgmq7 j; /_ Rڝ oj~#ESJjlr#5vDPuNmӓoCdYZ+PgiJ HSSXZ%,PHW[]1jG(^vl^RvUݴ_hG|Y}5fQ9)n%eP&{2SщIese{LߚFT]fv^l:MIښ-sՆU}ܮlW Xz]uH`h딢(b ":g'js.}9:ϧ#Syxo>Mӑ㩼rMӑ㩼rMӑ㩼r<'y[zi~ЗwfլF<@91saz*̲Y`0T,yɈ8a=> _-j1Fh*,E' o:[Ӥӌ$m:L[YD+|r|/Ӏ-1.\ ܵFBѓW '(rad|X"[=zX(z6(-5,b9[mB? |t +??*6ӫ! >װ}-;^8{KCװ}-;^8{KCװ}-;^8{KCװ}-;^8jኑDd/=Ѩa༬X2rda{`̩aRcdS6ݡ 7)]Y#3uY]Y=5bODZN%mm$2Z"e bH\Q{jߤ^ ؘ60f]awz3F(9)2=ډ,"Jnn`MHWG`qIQ*FOGʯ?m/mrzU ohZOd؛%=aAj -vgRVrƧlR[xSw\@.LL`M5ynzZ kl/KXx΂.^ˎ=шT.u,TT ukCɮO* RvdD;K{< -u'òlMKY; UJ*7֝+Vц3Dm!VZڣ+h] =F`,smB? |t +??*7EWԁtU6,p>5fη&e%[v9g'5Ulu}_mY-pRsgRWAb/ c9> K2ԱYa\8v8+Rh1FZ9o+fUa9܏XP:l2TG[´$ezZ CصYw\.E;_޷S#n `YL%uM*ew*N{= ή*ͧ*EyR7nVfgT[jS* %kPm A2W2ضk +%$5.@@ݕn,XlcР)5: XjUACf\ tD-QTe:KhZpKH!õlV&<}ܪY*f0caf=m^;nWۿfٵx=m^;nW6W^est̳[*KUuTBCnWۿfٵx=m^;nWۿfٵx=m^;nWۿfٵx=m^;nWۿfٵx=m^;nWۿfT#%l~WUn:.d{1*Tzr\G\Gז% WX!bq9adwXM46zf:lMa:xܪ6,Z-޾wRZVT/8eE/ -5 bnt(j%CXl!ÑZn,cP~ h1/QքbUmB\4ڨ.V`@2 DK(f0y*KRs0N5}֟eM{^ΫܶT+ReZ-W:@s+EЌ׽mY-jR?Mze\%谅(z raH4a7Ӭu,k: ;K`328BZ:U]6 xUAp05{mo_)Vy{TV3`cߴNOߴNOߴNOߴNOߴNOߴNOߴNOqqXz! JrL}yG?mʚ"&j۫i5R{gk6V:}YPx㮑Cj뜞fMa4v|cb*v}))^`jIhJUwc;7i…(=n gl+&q9qG9jʶHKxSн.rxjՄW=(+JaPinvD55ӎqď4:b>UCi~ЗXHe0䂝n OlP-v=x,P(m{9oTc7Gr&W5=wQ`p[P^k}O {k%*YTD!%9p% ̓L</;+S({nЏ?OʳO6s@9эVl^Bx~km_K뫚@*[ΞJ 4S몍UerP#ii뮮\iO,2ȯ%.nxNY\lʫR[NKm0+&|p~z{QOӓTe}d( ]JHfL ]A<3ũ v[mC(,  ĂpҺpnL^i޵c#囷Uf8!ђcv}үV5o͚/U`ak6]b(0dbVݭYlF&y3‖jkEl۷Y/,_eV; ӂ\}ܪ.9LA@ XۉfMgO [x v.sf᫖İݫ+;-e}Hݪֈ_6WMv$vW: 6D^ɵ RX;/w+^EN wʁ[iA8FA4uzf &63iLZOt7 qP_NH͆7YZ^=ehg|VRZmf2r޶5hʫ)j-OA`` {TZN5\lY8əlk &:O3kUu{W{mo_)Vy/p꾤+z/^K2zT8&4}dUedB25U@9&cĬ\jȗVVK>cEOAh-Y #}õyG?5Uw k4l=,K~aNGzJ*QRK+=G.WsKd4A(tH*t" aVrĦ kfvnCS$z}"RR0B&eY:@3Z;uiamRuYzD:3 *5S,$9 CYv!hLx&&tKNuj=2W|X67=WMhTͮ 6nN`z:iff:\X][osp*6.^kRNضEi=ZZq |`kmi{4[(qٶ b6x4(qMiѮ Kl΃UyJWܵ2Sg9˭] WٜHn)TP}kPͽx.̕-B!bHV&1G>$m0O";_޷S{+zTYMyWm<3dE4Rk=Ӽzx+Mp6aUeZt53YCqe|ꓸre $ws!lOҸ }-Z&Wf7M ` tCIؾPHit*֫j\K2){R1+pvhy (u@M3XO:6l+ q5@5Pv/T],hHDU-\ZG\aPۮU $|UmB\m:UIx{Ix&/yb6{]#bdwf!Y׹ɥ(%f N8N˓ +klPp܆tyO'sM]0`l PK F7] T;HtqrUTMb>J>:^9lr;Uv,3qA{w=H< 5/`H(4;ѮNkg Y%жwimĹNͦ@&8ز@SYO.qga?^e.9=q; p\-s` #FAJhNBɵLgcN_hG|Ydx뵹\pp:1fuE|R["ƙmnt0,X \5@15[5*kCqi|jߌa(x-S9cmӬM!2Nl3Ս N6_pŘ\YX%ΡNc8\%{ԏ[tj?U*KeVqO { & а*nrISJ)6N5{&ej,.ٶHktN,A:XH {:4TV +"[fwoAlg59Pۃh@M'ZV{ViN5*9 m+gHHy}H3l|}ܪ.6 &۱Ty T VC|ZUQ= ̛kfkMc>avοvUaF,X|WQYWtaՕżkOy|)(g)B F@ :zu[.}=[U5"ˁ=1|^ JgbwL⢩j:V{3e\dݬ:p0;삞i*`#Jz*[XLVn_oJ@3QF`40Af3ٔpu#G e Vȡ{:dvQGvotdPVWu0j+5r =vVva lMLi[)\fiNܘZ}3n!0Hg3%|t +??*7EWԁ໹K_b#τҺOaXds`y:{UHdIZ\k>r*9A`5uLڪb8wd>YbBoM`\r$(]-BM/-iB@嫄j/V("wΧjEVZI{ԏ[tj?ة-sS}I%2Aayok6e1=aUɭv$R{&n m5fs6줭]Zu(.òCdrbh&5emեU7kFlm z1JjzQ*ulljkf|ծܚLk ~yζYy@ `] qWU7[>mAFm%Yi]‡(Q\?gOSum,Ma2@f6'Tکʹ hYdL4dRֵ% _lQT5ݚMZŒ%!s]͒GKhu\ժQG= 9 ZF'Ű^U'q~=PTl 5^yϨW6~Y8)g^k#~.|`9NNG=Cvpw3;ac4\3>UX!i2ۨo+b0GvVк ),N]%rs!AQrJU fI'ule\WDUM:L8MD !G'DLA7]eWH,9휣)b$Yl(ѲܯAs|m +G21.;2;cel:g1f[iTŢ!*%jA qfA1r>Knji ;櫆ʧoLN3MY"Bk XqԚt:qEK5SKe[=^,xr=fWޞe/xʜM(%FPLhMAdsmu4!l,뻶LLjfDRV5W4c)뀬g:5#h#YrxAX"İ6ekD[y@n xb\}ܪ.Bq+́q};f,c l0E9a]TV1mn;,u\e-5MZ5kCX Cӄ"P7QH^]ujVqp+#NVsJ4eT% *j1VwTɫj2iR l,F;ċ%Y%ª@(bQı3lⲂ%UJ)侹<ν_hG|YYmZ !C^1k>adDnPV63 1f?3Ol?29fK'k\]l{4o(͵ 'kS59@4.g%Հ_+_6[ t;m9ȭT. mAMZ tfUPڴzKXJXjmIӹ yt,܅UWQBjqdLp;x|F&ڇyvũbq$\ 7 !0îumB? |t +??*7EWԁxdjݫ_Lur=|O{CuUUTMACj Υ[WV*IcNYXɫrͥM)̼ P(WTQuj5ytLEɐY,r!pq>"I. bY;_޷SŢ*ye '+ .6L zIH#LP1)QtթBSf`<Ҟ0UK4!b9 zIH#j\L eG_a_%õ6RޮUCϊǠ8[Xg+k;Tms.J4qC0QDlMⶱ*9䲕~* ~~q(//*;_޷SE+dO!iYZd) JeW2& QE.MhJU@ݧA( Ȁ2v. W(%$e%/D3U\e䂹 r\̓_9n8%"%]9Dͨ&óoP:܎S9S[yjTݴ 6'FH҅9tysm۲A*;_޷S*ڒe|I\/46ȅrԵӃt$Ť!Y樺ˮV:jTQeOmS5N&g:\V0ǝ']zFj<>_tZN ZC& p8A #W+MS(ϘG%r>Kiت5^B.|@{,X/"Xv˥lnT9Wceز@E4́ڷr%ɲ}O_!ނa >~O;3b+h6J4tvPaLg93gyr>Kܪ+ հѪ"U.sWNhn[BzӕAU8laZ#R.n<0U#r,7Zvv$W7T N}m3U|¸g#m Rm@v3fؠdYW I"Gqc8G5lӴdl:?dALl%.mجVűtmb]ר)p,(Q8M(vcG8-cE\UU6V]GQŇv|cb˕7Zu5j>piJl QTcVgݹ1l5$`Zi@8 6'#iV[:@)ZsSo9|I8H' MT;sAzރ1~3nyٮ‹Yqc u:tydnr%o1JJ9ֵ:mpgޠq5JCS1 pK`n5W##kx]+",=X*9MYL[&zyֲeR%!mB١8M$/]W6ぱ9Jf t'C]34pռv ~WUn:GjAާ{_O:x+q[4g9&h=]QJH }U@6]&([Up||uu5 Lc\nIi*jDi\6ld{= z|dmº/}õyG?X]&U WmUz0q ..E^D0G }v)!]3ec9 Hl5+!c!v{VS0.>ncܮ2Ѹ\@gڲ^.сuO>UCi~ЗέW&aCcp$!3Qp(qġ> 8$2kV,'X@9k!2 vcPδO 6X&,n]qkY|îEjLT2H%EDAPYeA`I˚K$^2fm@Z8!&Vxƹ PF;b3ɪ*7HNX׵Tmdnģj*6kXz=OQb뫬xta1kȞъHȽ,@ë5BD|qY[ "5*ΚkǢE'b UXAXb`s^yX7Lۇ7Adܻ :Mcc,PQ7{MJ%YTʯ?m/ӰXNcbԫA^5뗜(⺚ejju闄z:2 N~WY3]Vya}RJԵ\$T1AW nⲶ!TEl ikd˘X6f9G\%&MRBDJu9Ř5,9͎~nn~;"vqv뤊Sg-MPCkEk$z}[aZvn´HD q5LRaC pukz+5&'9ir&: 3X'\ 0^ۯ#b1ҝ9 \#1B6 b1:g0Вdp(xW=vIW g9u\iu'#@kjUB18zPB}5KC&6YRӉYsSNUe(E" ˋʽGƸvL n;H4~GRIH{V-պd0˪7+:ʺFJ.{c5s-wسT@ZP~ gLgwxavl!LNq=61n/'>8j;%CZ^Z]VR@libU%YUWk=H [n0F QEcO1{mZrmFNܳUܵQgtU(Qv*9D*j $nV3{V]T2:{ R,DW>݌4ٶ}>nDݮVq$UY=[ ; A5<¶*=&75ɿ[9 9y7d Kx`tٓ61$TsbCű3A{mY^O)}ʢeS 5n_mXd7z-W^M;ǭ'өujWڜvPTF VIΙ5w-/mڬ*:g@mש YqruלkuhQ6S烋X5źVh,:imgWT ˦K]~l0B)sڲ2v6( %"q uzm)#>AZ.+ǁy5DG5l7W"‘iWY]5G7'T/v k'feU:=SW[+t'ߝA94* ߳NmM IQbvIe`ͣ]L|%I}R+$B[`nS2-?x~U,Zt |5I - -B!bHV&1G>$m0O3w*hKB p AشN{\Z}6#'OH=nK搡/\XQՃ``P֯$̱kІePU@gw[0DH!N+j ƳXiZ\u=z6vA!|c1cNUB'ecX0PhZrp,z3{mܢKfx| $Jֹ" ƭlbگs&N '@f4aw,tQZө\̊6C(š*\p{w\Q& 3ZYF)E6)E*$v݃ |)>qc;峡}+YiϠ7knO5ai^$ƙ^7꟮u"=N*[HvJP0F u˰lQ {qL=|t +??*7VR[@\+(k{- SaXp8gZl[]Ti >UWGr~t6Hz [+%]ZrsZ&m"anq]] k* at!d>CN,/[+̬!]1K lXՊk,.he20ijno,UˋNMneVGvH^.I^zΪX~# ++"g#,˺Uefl)5Y u@06ʧ-SWwE{=i ] @_ v"^֖ $ P[ nZ^3G"]r\V_hGˤ7n늊jlf}`]GP5,_ 1'B3(e)??M>:gidh\)z}^j URX N/&VnVtnr q^tvO]ֆ]a"ɬm, CTP! 5]mI+k{EU*ks+~SsM !FYSU׆aꇠ~({c ▹m;%!h^k#~6*Ks\RILX^`جŪ`is*u.LstHlրfk{c#ڵyθP]t;گ1eY@&9Vԑ *竭궛 iN-No* z{Hm%: րNzY(ҴͯZbP,wNm[hR~:,U[%zLq]cuW~㪻Uߦ81Uw:Lq]cuW~㪻Uߦ81Uw)w[5[`l暏 g@\D1̧:+V["z2[*2c\ilV(G9&4*lب±tɮ/s^eW;:Ѳef8אSٵٌ$X_QTϫEYc.;&sIbs[ /ty! (L#2.TFd*\@yG?{EEfDF5Bښp%KC6LU}Xtꢛv5e| ^CHbz(WTF;&qq[Pi?9H`&w[|9~_܈QAoɓs@{Qk $ pETlLqc9V9J:ygoהXtDklN)Ṟ-6FѾVקa/i Eo ).BwEf!}^q]g5UDQ& .!i2`+v' dH ]'Cp7A S1kthN ̲a]Kt9VGzsbyw%G­,eS$q(Rh|t 5Ïٝ (ijW 1.c{9\r_Cb` s$":. EP-&fMQ,q=,h}uWSB#!)/DEKEVl9ġ9 ozϦFlW|֞GgNs@-g7TEi 1|̏Oɂbc}7_`3;"mGl⨅onSt^}HPܳZMŅ U]j {(0֓ zuZ93A PewPfcկ]g 1js4tl\d')]`Z:pߓe]J@qF#U* hDCVWjKM[Qzg|*ؙRLED2葔gejk /fyG?.7j"&C#:Ե]%' ]-jdu\-hqa֞F:Ki]vRYBvz{ ޡŸPzv.wEtE2K#nL 2Qj;N+on eGQ6]r;Ui%ck `jښIn-X]k_Cӳ\#%Z|ð$h6E뻶[&53")+Q{UsH*[u#*Ӌ1z`Bqq.YY(5n4p-_OZQ 4p\n{Ea(N9>UCi~Зt]–qk3>@)YB0AˋKT=dxBQbksT YvVVŬPG.=u qc8>3i"b}R!%XαV,iMQwL )tVudrg|Kߤ5׍lem;j,J8t֖pjMN" ,nuetJm`8QMDU}x.A {nЏK@v'HU'=souqoUAs;C  k3s-u:UW4"i&i,)S,(:U,E5m k"]m4'O1`lmgP\R0qNniuZzSU)!Ԇ[}e9dp9Ohv+QyW0.:Vuce8ZUiѹߵYÆ`ٺ^ 392[GN[Fp,aԳ홶ՙfqPn#[\ g㴭㴭㴭㴭2@'c{?ܧYz D \(K>#R.iň֤!N( ^-߮pN'\F>>MR1X T7~՜lX3(մTdsC8_UK't}>۰xqvR?} jur~?~U1[STm*iy'*e0jef{ $yb0 YWNcWs XB( \JBSEP_X f K꾧_]s,slB] z]QrYfmWAᠬ, "G&}c\Yζ5 xXdHP25WgI@!.8&1(C2XkI W6ٕ&7xC;#>R{$z^4T + Jc_NjIc:RJVHhyo &ѼLsx)UַEi??MRڽ M%aOOy {R?tٚ~ JCQ:As)YI.tұwoBg׵+φK5fne!JY4{Ӻ}lYȠctXs!l'^˙ !ciO-+Nuɘ:"D0\L *. 1ρ͎ a=#3ydSabL3+Eϵ۷ȨV/EiXmO+^ۯ#hCzo2Pv7/OMi[:{\6%\jY.vȶMD͡VE,U%_Lwu όtzE-i:;&G[:??M>:_5miR"HMŃHu& ,SPbb5UhKIkuTUn9ݫC_yT0aIV]Qۭ$HF8Fr~+|8d7\CCin O;a^n8dgmyJbo[؏(JRT;L@d;wЩF̠ h;)N,"rjٷvӨNLvF#c0ꣵXѿOʳՈ ':F&f{Y,߆a<D`F`%*o& FFsvq~~gK %Ƶ_YOP ֲp)ZSؾ f1 G!T)$ssUq};Ι{Dy V AȿMu]qbw*hKޡ*ԡ{ *aWXM.c>*wu40nA|.6߫կ_M(#BNzНf5`Vl.يε;Yi;n fx[Od~ѹ iM%}^QeOM1B jTl)0¤.+vMX bd‖jkEl۷Y5خdAl\hl67yөy+z^0c]7-=P4 럳Gb6zv9i޹ukm,hM?Z~]vXonӸOj4c3Oʳs͌"+6@T\0@\_+` *DG `mA][X)@BVMEͥx+dtu",}ۣ=YP(ieW>tWr!s^k#~6WͱQkË8њʹd8; 4vl5;LE(Ƥ}ϽYYC*ccwv^3Hdqd5MK]vB~J+\9A'?w*hK K8̄-:@:֦]AEQzڔTC0熳L jzDtUإaqPe5LU1T9kjRf9e.A\r`:޺suZ382]'kdۖ\l9Q] !n؝nܸ_d,?n#tjkb~qVd=E [&vE5%bT4&t6;;.UJK-WTjʼ=6ucy6ܵڶrθ6-Rkի$i}7),/ lS]5=dgT@ Hq'ORS:h bo6FRe&1csl{";l4FTpNouF HrVr94㒐5>#N,CJv&g{{dDOW?g g@m UQY 36J'*G&xs!6dli[ɾ cZfҵ#Y$s'<\6) thlC].;'@pUvR?o=Ѩ^X)@ \QA2R5+Y0C܊Nƾ\F0^Llu@gF/ E'xkY@.dtNUvEabROʯ?m/k%-d'\<9+%1+EŃ\uݝ<%Sݴ|b=h, /5U# TNxbf"έWd7W _ԨS6-a-pt;CUOޭ}Q =KgfBLxW*){E sf 6sSW5;^r9Uj4>*.[,S[yjTݴ }s!bw;χ! D#食VIh'׽t&⧓ hlң9aBlPp:z,#b0Ki 1lgºU>Ol{:ze&onnͯF 4mj. 1(66,t}baFHX4S8l $MO_5{KgˌGo͋ Hx *Z߅WZ0J36 QqccIo17>MkMJh=be9c,I\k6,Rզ/4f)5XqI9rhjR4\kC^K]5h1Z9#)]BUeWb5 [5dekz[ˊ3VI]W[eV6ֳR,5 R.l%bSa|8s)Vy/p꾤+RNضEj͜\0~ڲUBmhd8+UM,"&-\;ؖGYe9;PyťN~e5QNUl}sSPg,^G^t'o^Af0mSUYVh2\'m]ylKdoDH,tqhdRJj-jT-&gl '6Vz{ҶifnQ( ZF\K0J_1{mЮYj9Xq(Xq(Xq(Xq(Xq(Xq(Xq(Xq(0a f]>\c>_O_8?'yDm& d<풖'}FcZmױSao&smH*Y?NHguj͉pk.TZ-ň'V [{bz2ԫ`K۶j"\$nQ,D跂d&Fx׫AYTT8@~q_/Un:D;[*Oko 4mB~<ڱP^-V_mf +MU-]Ze}!i}r-խ=N46 sX|p~z{QOʵQWdCrL*t6]ٱ 6͌@AV|NҮɖE2ޖ^ ɫ\5ٸ[k 3NST_nE.qaYyG(,{殩UT,XZB[YSS`@{]Rv=I,WwT΃ Y83[gx }*jecNuJ%miy0mj[u;&V1-i.D{,#ˏ_a_%v*5|ǪJ`:ŭRbjYVNn,ȿbw fUX_6^4n/5zdjt)_1;e|My Da:u3Sa E!rx8಍}rlݗcY#sM A|E 7;gUoض/1, Y^EL* 15^xC朳ON/1M u|OOpFJ۰ִ\.q-bq=kq^tW\3J\jVٳƆ!m{c~GLkZK_kYۘpRu{f[qXlBU$6T- tR;n/ꭻ6༨Y,\$¾`#gQHة0m} >έuf652j5wj[m5{&M.Q__oA,Eg0r?+o2[.\ #Xw+cOܬzi;M?rV=4ǦXw+cOܬzi;M?rV=4ǦT{k2sfO02.[|<,"J Kؒx_NK +IokY-rXkV<ī㾔дЪesIn-UCԮ@wp#7S_i>H+p~z{QOKpkL& + 6RGeY?|PbIhͺk.rriyӲs+ Յ:L@9lܝZm@BO6 4uNUکaO0 tK{D6:i(?e5CUYPj4|l5V氱 چWcвyuq2χ:톩e5e-Jƥc@.OWA9R22؟\}ܪ.-k(L g; huҷw A% 38nֱc-En2eg\ aQ<cM{nЏInjYΰ<Ɓ -hQ,4g ilf}`lLfGu-au0457MU9i؞#vSu;?XBEqKK|˗#O^P9&?Oʳ{U q]F5jцeJO*כּx*H!iQm11"#wKg&l4/i.IΫ88ѭ0l7&f UXҰUq:Dy+ukFC!Rᮨs/}õyG?Ekn-ܵW,? 9CkƮ~.KwrD15 SʢkB4 ] јk -7~u Gl[m whmvn\^ѱr>K+ ɪ"Tv&j0+˜ӨA3Z1[&};{zniS\bQF5 *+mM ={m??M'S=eolv̴6m19 0[-/(: m6kwE隈DxYTj;oݎ: /aA5#k֨l !2VPkIvN2}[޶QX3)??M>:gĥA[K,c+ rsH`BX4Nj*˴bm]qY2Mޅc%ZiiR1"ld7iکڹOW1׳H3tp+hڎ1r~K 6-rᵹCR#gdc o;fb:60p~z{QOʍo۴P#G ˧lr".wZL[p!b&=3jpRV UvcLugӭ˲*,$=_a Jmr~ڍAv E1i}UaGJS}9=w*hK[V 1gҊ .aK8̆pv5Qkz#nMLa>Ln,KVR aH3(N8emB>]'ǭa ̳ I,ӣØ~ƑY(:eSnW>O*fQ@CH@YXN5>5:4'y[Y 7lvW+c2,8Zx`Ygr.Q4WjvbgYq,c83׷)ߩ5Af lˬ$+ӈgB+1Ԗ>n$N'2hohW!Rh|t +??*7EWԁm~js-0q`,Ԛ|u eg97 mj1YhKc33^k# !BH$ǭAUeRM~ 09:qZ@9قrqR;4ģϚ_a_%=K2|l.F޿}.-(*mnyNe bEfَuR"RB]>{֯+Ei-p\'Ŏ.oh:X5*X#ltX^2 ݊; R\5Zq;ߜr}YCS.pY5&Жm=#XYgB&<_hGˤ77fqgN4'鰀!+k>Pho Ѻ&`CaXc!~yOSrh0.N{MV1z2uqoUAs;C :{)6Mǚemzm}qK@W&֑QzXqBoSPa)uQѹ<&;ư}S}=n52_([!PAOZxs&?Oʳ{U pZvoa)["+0PM[[SYsYUZYrN "JcZSMIbOt13Cq/}õyG?b6a`טAr@)]KOd7 W匚:M*(VWm*u[LA \P4YҎJ:${I8*T;~Qٵej m{ w|UU|r|B!m`p2\Շ&uH{W?} p5S MA`ck2~$tod1# #L|R1)FimyԞJFy"*Y*U JclQ1z&ns!]dm"1{mglXr0߉|w_4?~%Okkqx8}f;_޷S^Քv |h[k}|O)תt99-Z \b12F"((S8P6~e"r/]p(W\q8pfζ$Xw*hKzd ;wb'vpC,jJ'DtϲmlV#9 4觀,]U?3e}| z-qWŚr0J}ֿbRϴlH52孾ŪUHݮY3z9۝CΞLcpԌnnj.Yu=nRk\<5F[ ڵz$ 7م_ã}my`P ٯyO,Yeg=;#k7V:q^]71:g@㒻4Kd_TAR"`F/ss5- ҸWh6Tϒ-om9t]9LCє>b;_޷S}X"z/eBsVob\Tt7ſnB#f9P*uqCb^kcJ4vݳFoU9p풵u5 ='/*,ݽ݁W^vMݥƆV^o'٫p Ynhk&:,[Wh9Jn%f22)\_+` *DG `y.d!qPs*>UCi~ЗQV. >5瞅tstw\׬OS ,%j&X\(#gKMv( ֱ7G t!z,F ZeE<11K@:OױWHS`'6hhYje<*, ?}K -N>fίSIʙ\9o.jZL$5{[(}Z[JLT"˕J:UU)LeV2,5mB>r:ZD+E&u*M+(tlZ˷eW/!RՉ1Q^JoU 8k:b@P(~:g@jb5&AO4˺Y 8p 7^^QX< 3 va-7HF*i *`Q|[<-}b> A\1c%Ha ZhH9 (ouz$!cu|n,Q\[iZِEQ2fZrJsyhj[iee i;U~bE%A0JzUf"\v/d`#/ؐrh֤VSvMחV4L4&uAl=5UmB\nwԀP޷].3ʍUj*Vo_i#ڬ뙭rG[f|OrWUu4Y;]Ք(c9'& ,ZPn2#aSt[T33T+G:Le=cִhf{\"&8ęzoZddӾ޿k .V(]lzµy3dYӶ3洮Aa 0U}obq^< Sɪ$?5{m H,źG)6;tdUPY^jQ-uG/+% *.a3/QP jD\8;7|<6 1z9ݬ׍2+!WoBGl ԷMS͈/Koͦ^/wtq\Z) h,.J:UڤwsgNҹ(UEx1O&p~z{QOu~QMzv8s$(]uǵmj-]sׇV6SH:s{£5d{vZ;pˁN3Z7uF6 ۓc)jTZ \o2[_W4gpuiwmj)^*Wп}l.ɍSZuFpӅU6Mġh;i붳RЏHYokN3=mb,^7mFU$rtϫ$4[q ˏ_a_%@ ׉z ] \O>/shM3gdAA֢H07LSv 3 FD3+֬*+b6F?iqeYbl׊vqAX9T/dS|*֦Zj@6+sCvxJ.OR\v1>NiW\˶'";OL]S-YpvH4]ָXW)3 '۴d$jdGku||!C5H<OSt^}HVu[ ,XGcS GZZ+6XT^,9V<4 yN$NZv;r`dQtZV1a_ؤ(n҂ѐu.;_޷S*ڒeKUʮFkz/WZ}n+;53˻v6'V423!)Rlwv]L+'wVр]ji.l+\SՏ, huijdU ŕT80Yv&uNk[וS,0ھ)PmSZNy/mB+Ƒ:˦,j!CV`֩aѣW 3ˏ_a_%ݴcWQ$v*+w{l3'w󮼦6N\칥7?K?S'5K?\[5AN{5)ǮV5zP*Ik5Re-%Şf)5mtcaW%A]frj1 :r_hGXڟ멊E7xߠ+gt +??*7EWԁƗߪźk͸Ug*,´~{hpZ6MS 1Kg}$g(;bg]&7 X;QHfHZ_\t5kxb4 on#&;_޷S}BU|ur|,)r] a>iEsY*XYwc5v5Iy08UQ.g%:t(X'O'cƗߪźk.RX RPgƽ{ OJJ%[9uxuke.RrVS5]3lS"sfe>WYgr#fE%._2U0w J9l7]հ|UmB\^gbC^˧L#mM|NKFUXeP#{Vks[ [I 9ZUŴj-49ڃ35Ʃ\6٘ӼJl乑fc]Kmk24+˓:7ZZ4#쬌 {nЏqg961Ɓ}Bc.٣٭5uOt +??*7EWԁzeS#+VZ.mɥfXVè][ժNxayFڳEaL:Gɬ+`f\(5 c u {ښI /(KMGboWg\}<$Wy7HF:VٵQX v%56/5Rvl [6n]| )*UءCeM xXҬCU(RK_kP\mkZ%r3c0q.HSxƞhTՖy=lGdwe; >#J7"tN4UuM9QhS{Ik_*[ !Rֵ% hTy=lCfwe;1]cMO5x!#Y32-@5D=kOq9uNw*hKŁm_]_+&$O^3,'γmp8$18⫔zf#ttGTMed}x7v*d,xGp,cZgU/8=RS5 cۍT Fkl8Xg|_hGnοRh^ \WI(ezTc>o_)Vy/p꾤5ڂiWçvQQ~X犎ls۪ӌ:.]0A֙οwYg7HF:axa3|m̠~sSAr@Uqٯf JbQ8Fx1qUeSϦ'{mknI+xcvM]:vYCQy FH=5[mXrIX?ՖŞAPkdnKasnj=Ij.nD cW?} q$5.@Ljۃ]mh"R .)+Y@N VfISbE8bR Zj\:'l,*. 걫k ưvg4PelVY5ï{ RYjոD}`HI8:kqTW,ȝxL{nЏy[[_aˤ'xVLi{G홫fCV ڠf(Ly|Yê8԰KKMB6 ;6ݫ{.vw-ll8{w(5R8ASF62M"3{u=dj;_޷SoV[fC]8? Z}CK}PY`x}wtLjs46caC,1.P\r sg0sV&׍^ЛXfҁm Vdά(+[qJ S|}ܪ/ eL6n5=5ZBK˅5ړ22Hc1Jt}3/ΫZO6\ u3jJbeYl}9smԓq`BPƕLO=7|<u_RuhҠ ,gŋl8_j|4MesuMibG#hk##ͦjW gvVi b3!(.)ӴLd t֖pjdaJi:CfjmjUmB\r *ahb'AFZUV;SAV=[oTdyryfgܻ)-g{\mkdqP3b8աVGqhL@|\k<\ 崞;My.ܬQTOҭ+ l{>eOu|{?J'E3J~m:goCŮCsR-\bbٲګǸ@ʕu8NO{+5{ԏ[tj?ܪPܴ Gg4uՠ,9Uu5 iwB/֩G]W@~MNU}ƻM]YbkOЗC͞t0_5vHOהeU"%VS@LPdaE!@ ,ja)ѷ7BRw:jAoww<K=ǎ6vޝP_\5vPB|>P;4?whptzMð׽[m>n:yZ.7qC|t +??*7EWԁz/'s;J˜r:ؒB˫qb+>b;_޷S^Քvx9s] IWf'd^ , VQf*ʝz銬𒆢 ln6)NSG.Yln%@.p##xIR֘SrNPQr>KmZۉ ߿ejnRL֮/p\o5@%V"J#-]?v܆4jIwDk\)4/m]>6 A7@szds{i9QwJ۴(ޡ*ԡ{ *dGWU W^(j(.F kHӖՍYpSLaH\V우+6lgZɝ,״ٝn<&u;P r˭av^!.sڲ O!2!'Kku|'sFfǟS^֪|!S T >{o_)Vy/p꾤(^US4TBR\]4}\W濘@4Uɭ*_jl`EkcF&n1mG51VO``S&Α`k H ryYi6wVmzDr+]kv ,0~UaT/Ns5%1 9Htglzi]zI{vp%QV94rfAPD)n,5*+,Q f[s!dCQ- yUmB\nwH(t DGeP Ja'lگ\0g|hef -d>!f}s!ba3e4_:v7;{0q[N5[g}XS+6Յ:jؕ\*sr ATB>N9`&n!y{nЏ޿-R^@_i~2?Oʳ{U q]K uFŲ,3t_dUKh&v ͥ*U@X|8J RfBcnΞEa;],ܗ`5FݝXP33,c{EW-lpJh򑱐d$zjI{o +Uh ^} 1Rڸe05MB@] 2P}cH^RoLWVbUp:mYVi ߁w`@ &ٶӯ`O5,[6vdݪyz<^I3.iQ[+^ۭ TvkU W-mg>zKM=Aj9j/_a_%ŽY(' _Sژ.]Z] Yr ^])Zާ}e[3+X l+w Y٬9]m}%mk&hV*իȪ+ĕLslZg,L2%2t@akThѫrYKmB>n>ըfqcݣU7[g>wo_)Vyso_)Vy/p߫:},`SO~:|f%G^5mn) &'QmbV NaiWȶ"Q٤m&it.Pu-&ol@8q>3g}õyG?;}UoLMD64JB-؛u@qSQZBTU|X SVʋ4r&5N)[ )6Fj`ιq%O-[}ɺlcqqٲ  MѶUU w-"YUԕ,X>,H [n9nDVyQUF0q]4YiO5w*hK,UkYyt)8-P+Uq;uZسbPN8Y[`Ş45xӭıI f[l,V =9ivjghWQMmV*1 pڮ߃EUrY]VFlՙ:zx_dLcnSnhE+0VSG촚_xt :2rga6$ ]i#tHW8o3{mz;X,?.XO'4>~*OSt(+a,sHYƻҏN7V+R.^N멛1NiG36mZ&Pv̤ N.kdBQlr{{emC X* 6zx'NnF"8F4cc}õyG?m׆jX,7&ݙ/X%zK*PV945umVWGw uR Mm"x5c3vN i*bYʋh$CTa9'a,#ykKWgj @\ڿm޼J }y*u50k+e:ZBpG;bԁBK^f>UCi~ЗwfլFbVIq3ӱl-O@y#pϕA$6㯮DlC꭫Ӄ`{K cԋlU`>H;O?X{UUM:L8MFmLs8!Œ n 8=o4%=`]0Cp Agu|މ>x_aXso_)Vy/p꾤D{) ~}k{\-(+fk4Ũ]SpNIgl*P],,nk!^k#~Q v1gkS/c_d,:D_}S7V3ծEJn17ӏC7 z(" ^!.Soqu6ݮK|05m]]d!ɖi+kq nn 9,Nr>K/-@^46d1S=UɖZ*{#j*+jRWԕ+(5mᶴ )XJjb>!T;s9֝+Vц3Dm!VZڣ+hXjpK YPKqѳX#S+-wk["#ԓeMw K>(+[qJ S|_hGmVo,#`RUG֊cS jwo_)VylJT2%܅UWQBjqd⢻ZCtl)U|]d 1ܶj%mNR"Cvm! e9qI )^s/}õyG?kNp96C݂p+Vi"]5 ة3"μkfl%,h;Cyt9kiYnՈHn;ݓZz83NPͥ.Yd$%ܐǜ_a_%U,Eȋɶ56=t, cYaJzBoH>VX\rrpǙ2AB6w s+[[f2 >{^ۯ#rх{/Y瑮owo_)Vy/p꾤%tdJ~VN4lJ}ZUlx<|vR?o=ѨDU}x.Aqc81g4=SZASO2O#^xmfρNʶQ$wMpړexw*hKRZU~,-LC~$ GTuxDmVik5ɆNjΛ$`Cx"PUjp@0]  nRZU~,-LC~$c{,iS 픙+)*3A%T  o6aZ&& !,*:vbt0*+xlh9E3qWe{nЏع5D[ic8[[ г;7|<7O+zn`GNQk.ozzowow ]!xӝođDdvﵧ`xUSVbY \{IlNG5rFa)[#cWUY0/kq cM2nrbvɜ\xuG]I{wR+%wbWaQ&ܚp1]oض5΍6pwuQ <^v[Yнr~?~U1[STmAnr '&L`iܣrg'Ҏ Ai cg pt: veGf;<>ťM)̼ P(W m֝vyOIge?ا1r>KDY-O5}߱o* 61θ =p [D5z) MIɌeR3d$3s $ig8s{nЏ3\<޲1Ǚ?!~ڞwo_)Vy/p꾤 E*z+Loqczv1 `1Xg^2/g"5uCM1N9e#^k#$e y:+wa_%h*cvԮ}; u2ĔalM%TP*tL>Kc#RE\$UmS3Ujx*8dXf6;wdN@{n[l5QٮV,k\͝;+*Ց63CQNj1iCI"kDك.1D#eUb %q'{^0.sYjkF97=juR'%7mx*[9 #;>$U}X9$Iۈ`g^ۯ#v]ˆ0lq@))y"7Kl =V)T]Eml֏mT @jJUAކmMSߌ+ڮt^-5;6rV;(]vR?o=Ѩt-hOX5ʞ'ضk+*kID'Uq0 F˶j@ƋE׆cul9JbV!XځVW{V)Y?]B+J3Lr>K[`P+adl:*Zo0B9UFktVpn$d0:Wݠlaw.tF+ncb6("ƴ*R+2`Oױ/LcÁ5,)j.q PaSb{ ykBAyK0rWm 2`AUOKS58&-Ju@h#+l.ܢQc-DK v%ag^ۯ#wza?ƨD3Iώ|Yê8Ҵ-4Tkuvwpʥ[eZ>>~ί;NÆ4bf̶\SU߿iuXp)h5bq?3S}õyG?Z3ݕ~GcK۶j"\$nQ彾cƉbkں8.1p+=qBlV5cw],&+ZkvmKe*vQ9}{m;'AgOoo_)Vyq ^.Ӗ9/-AYBR y6aZc hP ƇCF`ةpx)3 kx\M ivel̮KQf6Xͷ&ϝaZ2w~Fm~kKW 6`1 ɨ e\3ԗyĽkzr]Um_v]@hs9ß`nI<۶P+bhrgnVUS`j3 Ri\ L t_$D 6XbbYڈ}3yFY(g{G(_[OS>~-kh)#S9"=V870X1՞ϼkZבXvi,Fؤx WX(Sh2Y\cr̿":N?@1sfAskE_+rVi0`R=M;4pr`]d1hruJw[E2k6zȽ1d›+Ybjlvc4ſK`mxVt36i!Gol&W־\%J9w*hKYyT.Yqf~ĪOQ _WG_J0h,cՙ{Xz3z iN~(\XֵZ.ݛ @u;6Vئ^es4ց[fsYm-nlYAY|ꭐǔ0KRY'5mB>gCϲm9?Oʳtj?mꌬ+ a]b[Ck=^.:;WMOuv2 9CTB2bk3+e}0Pnw[TN#R7\e|v\Ѝ\zECAmBUu*BGng q+Um&ua5)p#I;8_hPTZ٬ݣ,붆/){"1'X BR:J=~8ծɨn5OZZنluY*sPDBO(h'`O/2um? }ܪ/"\ׯӠEWKMF SXArԕCГMu٥, %}{m⢊Y0'?~*5ZZqKK! X UQg".ʦ'zK-Z)ihGzh,c_W*JWNȕgWR.\ܗ 6pc"0HsqfӣC073-X`ɦ%RǴ{^ۯ#7kEK7OIWU/$#rP1,~ Da/%t V:اR\ pC3$f4?5{mzAZy͝ Xk79N=7{mca "K{:P?77|?,3$hj*UpBJV X0Yk$m*rb9EI`ERLMoh:xk@Uo]qѾ-y19r$#ּRuj839j 0TV" QSU}ZsƦv̞$uC5El'fY]w_DEePHaq5I y=ARkVS U(vxĤg?5N91xϗEh}h01Ϝ?_77|? sG Xnhjرj,X0 \ mWE24RN^.CuCNjqt8w_:x<].CuCNjqt8w_:x<].CuCNjqt8w_:x<]8CsF^jv/Z<6oce657|?6݃UcK g 9s Z+)tUPTNU:\'8/rn?OʳYAY@$Cl7Š-?κtN}~cuq߻Wnj&1͝)ko_)V ":sj',j\ڟpWcqC续J<{r Ի3x3 `5 w4ن,G {޷a`ǝ߿ң7:gdR*[ga^{C(}`"qȹm7 j5n 9& :OH VtbI(k۝3w$ gZ+7`댾kov];zư|ܕt9gN?gN?gN?gNN,۸H UXbYڐ"K#[cs>v(,%S\@р¸O1eN+,ֵJlqN ]TG%F+ŬrCy"]eS]|ӄI BX猱g'_0537|t |kp2U]ŧ,[UtVL;7+(Yhu;&maZ3_q{ʽ}|wVϮ,ˬk TObF^mW-rmbhSS9Jsd𬷬5l89Oʳ5f]^YJN=| ZMB4u v.heOǞ3m=b|Pyz]b\j ʳQP\ `jg?,57|t Фfk9Gxo9^V[DjVw>黠ot[ѥI] XqkLw6Wh 0/"Thr|]b)k=?c[Z1:܊lIT8juEE,˥J T~S kkz3X?b&݉OG!]]PT+/`~nS rVui"$ռiSt!/;9ԬUDzB1cǟ!|O5h/+ƸzƥIw,Y}?Wew_/~;_OkZo*TjuwAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAjw,wAkP[JlL<9Oʳ&icv8=ճ>˙O?uZİq{6}<-qN+^Rұ; ǟ=]ܭY@ǝڿjh|M?x) D57|t ??*)VUUYZ~q ڶ^ѮK?uutkZĸ){N+~^w=),k%\#wڱ{1JOozE:Y??*[MX䙜&9ĞW/Jh(#)ty[vK\z~gB"i*ؿp }~(!xl{칐:Y??*;]"f.3ԩrfTPcR31=U"CVtVs I BX猱g#^ K>sH6L|:@7eKjko)Vx9OʳH_X+v_9GH??*)V|kyO%laˢ8vbi}FSLBLsw5UX?T lصPvtshre<_9oVǯ/I{ESFʹT:EWԁ$E.esȩ˺Վ Dg55M}'^!#լ Woqh>2sxX_Կ"9s%ƫ!~ZPtȻ>)a,WktƉTPҵT&A0FIW']\jV" '[493YPT"(Ju']'Y??*ϓlMa1Lq}㯿u@Cp{plx\ҚhvM2|sVSՌLbu+FmhכtlU)F̊W@'Ku{F{z5>;ѩ^Oj|ln&eQY[c+a G{F{z5>;ѩ^Oj|wףS6'ClL!QUcLr&x{F{z5>;ѩ^Oj|\hb 9bX{z5>;ѩ^Oj|wףSm&ʰ `8ko^}H)(g)B F@ 4OnV{niofXZ IFg56tQ!Aw5'HlVFOtsi_/XH;uzfnu{+՜jɳF߷&9&.a>I=ԣ>H??*)V|0;z|19U`{L`@,>@ģ{*w 1̡>%{—vxwh?uly*51"1CMbg$ ~ݦ[p168uvj\')8 Z"ט[rpI_+3UZ->QzKpO>OTidjK\k>'XpCWrZ^/ MN" *}_`%"ځ~28.N"8F]]w:Gz*~Aw'a\ (ѷ, Q"&6^Mai4n^`ɜ 4Pڻtw}{ v0p. @Y˶eX{IEZט9 yDR#|<Yso}S~ƛ⟍Lj{L31B;/^xg&^LR7ަlQ^9Slh7?[e[Ԧ\ݹySnBVksl$|)#ur063%Oc- ~o@6'hXS0Z{S*xu Xfx0ݢ=*ɯ(Z~LRSe<E٪,Uyo &SS̸" 8<3c=w)͠Q E;kW')݊¤h$׻NF#?|ĵZmA)X.,Cm{o]5};Anp m&,(Dļ?s{kvlUhW@xɦ#u~ȃyz V+7e:ȆL0!6l;Q VA-}.Mȥ x,fUbD׈f㓯˩/nJPEvUj0r2| ]!xӝ-Y<`mNj=nTK&Jl)_ɬ"xqU-*/ko^}HTYoB X+w:-u>DnPj_O5vwTWWWZY (aY7^-(lRʽkI aN{[׬.+(,VWZQK+B"LS#IG)Vx9Oʳ[:cqږږ7ОI4rood& 1O?mE/X vhyyɿEI X=il8ǞlgппппzJ¼sK/M+S8c93(ѣό>NXJe1zG)hij=rZ:N k:U+/8zG)sz9N 8 8~Jܕc!nT 8‰?1UcugХdnnsS5N;ѪqSjw5?T㹩O8jFLXբ&p"F+k[ H4y.jw5?T㹩O8jF+jJG8>3bCO8jFsS5N;ѪqSjw5?T㹩O8jFsS5N;Ѫp xb {o=u_R 6-$mash6Fz`Dj0emV'1}Ze"|Yf1^YY{Iu]NuY »&PMK8tZs'\ocאc9q^TK*pPXdRAփ7mQ5hHd(:nHsd"8 > IG)Vx9Oʳ wЍF=u+1T9R5\L繞AY:#_7A؛h6ST)9VsG0l?D=e$8k`c<6<\kYlP {2cjLsazU LPjRK7{ 1.`@ZQM;{`;fVED4{oV@RBA意N|ۥ LU'7sPqw>淮1vZ:!~9lzJxO`%f9qc?#f83cq͜jI^Of3K>^?%?ۚhRfI`KX (sO57z/p꾤(۲WD~,G9gg_j.-mwTiD osdEXF5(-$.,U+&-8JZbؑhةOJS8lgJyƛ#d -ss20[SX(JP2Veya 2*mt 6`r^ˬ\;e`یR#|<YѭOTFA Xc s=SX<,MzחO@$ɼzaXǬo6/r?cW>WN6:hձc1ʑ 1怙&Wc/mvL孰g lڒ?jxd-Ȑ0R2ZV#ٌ*kNp1B\vٯzmxڪlϔsa)f58g2R(O9vqݻu#`YIe ~̭Mj_4mIuR'g"!ضuSFag lv}Xg畱O>Su7kO֊DO57z/p꾤!UTh!Xo?H"V\:MS&漚DAZjIbSSRL,Ⱥk`yTSNf`W azEc8R X@rdBB,bgCGwb֩z#j'@*.K 1 zII+TUƲC s@~{G|USs2qc7Z @@QZcҚ>KU>l9W~;mK=_gu7 @Z϶UI0,q895iw+oxn8±챎nz>|PV?Z( w??|Oߑê8GMZMeo*MIIFl=uUj{كKO&[N [m3X; ]k3eȡCPڥOV=OA~U_#gQRpؼ+ `6+S5N"zFt0͢I)ZP0 F1g gcϰ8wZnW8qX.Umw]ʼnE;o)&0ڈxqG|, @WJ:b`QJi2Z}q%Nb<~M}>r:]~a_`XE2,ڋQ]KJo&}[u2Ā8`QOc(2LVYҭSK̪V:3 !cGi&fIgko>}HONdaB INRVC5aT5eg,cu׵]@31ؚrRR:Բ$ٔU|MֻǃuuJ*FdrzM!ڳRS jB I7j.tj ,VkL=W՗n[BTeB4PT;pc3hȕWx3m%Lɱ %G8A՚34Y½|<YscKrY]y29fL{q >55Qs>=pÉq[M9(06>x+WV-kR]@clUf[Xl%=y,ln ٍ`B#GcaVqαIlŖlL"9Kbd3튽.y&YKX He? eBF cŊ,U~bNj_ckڍT/ew}B ☰^t,^qfמ~ZjŻ-a`\q{V;މJkgJrae FQKҁ4jEyPG*'8g>Buٝ(gʳζ|3\>=S淙B`OX.ǑJ](N3[ǟ+ե&a85QۇL ?|Oߓ7*/*uV}e%>O??*)V{jMZKagpu[0 UB!0#JQs)g1Ϝw)$ a3p|g1fmnN W5L+.y.rqD<ˋ]gF2B^͍>UGxL߰&KKذ"K$6䱍!ϯQR2_#d~gICz-$xulRiE,a7IZiܼg+zEkuhv݀ИdKm?"֞NfK;izw{<UmVMvs_ӵ2+7ܻefy 6<{ e]_뮭{,^S^%YC<Ǽϊ$l}r -[K[/ ͊f2C?;hx<~:-o7oMlp)<%rmtҟF6:6i6Z,׭ORu<60Evמ=v%j8+paǪ<ĕZ<i8aF>/rO9 8B#@[=~873/)Vx9OʳޏllFqHVْ5Ŏl}UUĪB(#qtN_2#=B4)a4,8rlb R)g"Dgc݆#Կ7Y7E<;<\zn̷@r%m+}YaK{ƴVX BgXʶ*m?*ުldY>%g%1#WصXs?kgOs9۝Nyе1{ OIrsu 8S,c1بpSk οsg՞~Fea)S"8s% y{=qAXO57[VIi꧌Q Kicv5zppU\gt͍%ڋXl=?PfTOs]_̰FCϣֈڲx~N1ҍz\swш+OP+(?%ф bp^MEMdDlg \ڱ1u,r `zI`;K3-٭kͩ)sbƖ\7V,gSMm µ6sgB7_{g_TIJԽ;UufUۖj^;i$ ßdsJe1ͽ֕}1S8/n6j,eGqgq8k:^cxν^:lM|cwܿmEȨ;ȷ\{֩_6!w^yyrg|=iz%-WvFNIzs;c5ſSO!ϰf{L @+b#ylK0Q̈X^lׇϳkMAYGhNl8 6ڼZx͇*jk(1sJ\\ࠇ9y8\<9D\69uѱǘiGǯA8qc8>3?]s&[ɿg0X WP0 6 f4[O˴O*Y&AqSzwxj{269yeXqsg*Yӱ,YܩypmENGvI71ar+v `T [- ECwaEļ938U^~Ț@rZsd(J8eOkoM`sʞ9U~6a(J9(Osa!_bB%Tmsݭ>y 'OJ^^x'?B~ʌr`c{'-cs=R@16}|c ^ly8XJ92Gac9 K9.l7TXu|dz`j  &9_*Ξjmc8%+n_e=X?D;f/UV?㺋gڦʦyUcϞ??*)V{hݕ m,$) |y󓡨 g}{y= 3*ckrz\`V3y˦|쟿xtȠt,,*ФD)$ #NjP5bQTqY-5TbGX$xF>jGb4!BGqcjG>iPStב&|𭦂յ&$R?eWʭ׸ 8dW -ʶi8C;>ҽ*cBi}1!c/xZװ, }ʹSgK=AFЗ\|"-ڻE=Lu5E:9q;` vuT"Qcф<ضJRy[O;Vv=ZIc3T_m_T[z gbB*@Y=o (~hn}{$ )5nMT;aj5jK7Nb;fXtL?~OoYUR%k9|PՑ &6e nTuEda)'maxkm+9MK vQcyE[v k*o[u |tޡU_g_pp,~|É$]BsZ=Rڦq~C *pt䊠rx9jgCճm}y8gi \+Z7U _cMvA3ώUS{UU[9@x+\FuU1gqV䝂Y;3Ji+t#s6{OATҫ 8`z. 𲇮9gqVS`7SM:`@b4Uٖek&[&e6P?u uؕبsEgZ ,|bC֭mZ{pL$Ɵb]f:͝^1_g׍*V!ͳS9juҐT_]PWCMCF1dɍl,)UvN`&6[^ϰt՛X=yB8cc;L^)oZW֡NRAxqc. Ԛau ia ~MGT~r2"x\=WEnXI(nu9_J3$2FcAugWbgDlrvHն27\{H:u& xlems)3(hVkGeo0V(W^dK(̽u׎eEMDVUWR'Z3Yct)T@ 4,UP 1s[lԾz;ޭv,u[bfݯtf?p*+75ՖG:nƞI'dYsϲzo1!YV<+ہ%J,jZ lxqC d-mGVJ0#@b+]`Pvc^5?_w9}wX7>:tLH p<-/˫+طw.m ["O ct[ȹuZQt_ ٸ FYÌXmW)2Tj6럱?,ccc_<Ę9jj*UP 1ٴU.@ijByNv:y'^fѕYtG?#,AGNkze9v ,j+^T`8Hr< &¹4ED!@vm"#+AY4[fITҙ9GjN*Ő(Keo]$K3Mz=x/j1gJHnOR̳nKun*%g'2FX3׽g-SSs,V$ _#|<Ymn*V,`QCjrHuUKWHA\<<)E@T\_R@& #9]حv3Gy#91s3)+bףBF ~zyB@C ,Fe,P b69Lyw?ugLJwLk/XSul$MgH' 9y{ .BUeVZ`[e`+mUʶ*g8CvZ ѽԎ=ϫk,Zyd,y[`a7n="bhEڸ?U-qSȢ@r2@ ک$Ax/wRY&D\f7I%٪%yHB&4JuS'cur(/y|t _?|, &B8S$oo3Pt X5zq(1cǃbvLxCjh낊ceRP:ȀG2aأB`FYJV>]1vNjK%Φ*:W"dzգߏ;cZMՍX,K8+ZH Zcc<y4/16x7W\c˿wT2:lwYNK%Xqsgՙ\̧_S0XYz+y0^¶q ])m~hcILŵeUR4,矡zm"MW\,Za>%ԖL C??*)Vyvfh՚#`w*Y͋#q7|;Y$զgeYqa1r Q`Ddy45!dhęo˜(H#9ob!#8##stNE)ZgA%Qp@"i1yYG10<c'? y𶬭HX|LW9ygXģg>3\c;]17q:|yY K,y&aYY[XfOyt _?|՞5Z]RӰeiqm >[-AXŃcLjr1'6UDxC<Ŋl,yJSVb,Zl0f; lcEJ5(1p~B>OfjO͏+k=_>zĭۮn9Xa.5kfΣ5֓糭.k>U3/MK\xl+.SV* q6ǩ{!81sXqY". % Q6謍)W(D_FrBS;l ;l ;l ;a-Ũ*Q:&A>6x?Cg6x?Cg6x?Cg6x?Cg6x^dm/O0 ܼ}u.-v}n r$$zP/hA21֯j}xF5YI?#e/]Kاk}]z[WT12 \L8QN3B~m ZstZueq4ûk [Y'8^ұ5XV}b+:ZT0 Ejε*\hZ%h^q^vozDdaOZ/?]w>9B6Vſbsl!ōe:?7[ I؀q,|0+*ּvQeg03+9 1"E8s% W[dϴCߩwjqvʞT!zH2Brɔhp+"h9(|p7* Y#Z6j}.UB0Aˋ3wSKaWȖi(0/VFyq 0X 0 HEI 'uV O+Xx_R.׶'4$3/ZeVS6_4d9"Y\,XEH2y?mZyJqsz ]jjW״9a.ҭ\/TY@ bFs)οqmۂuKlϟ0[:ɑ)q5 9' koogԜwoId" g^2<1ق@ r23l*)CXlW QX$㹌7֣zcg0S:jU90Fs3eŻ.0 ^ `8fs қ;v 9Y-3U9/혪ffŽzk)OzdX: ,D .C:rg֫9<2~b6C?kxFɖM`Y/U$9`9 |noAs{<6u둧 s̵TCjpq4೴F"<ǘbSW?6bb9)FɼF D 1-hn a< C t0ѣFٿ=aA%'>S[Ufvx}^Rgı83|eDU}*x.AMz^6RfNҝ;p&љf^Srgd>6uw ]k՚~btҩ& ͅ1YֲgpmٺL;/Wɦ g+ە*y/x\lC/)bRzMYV9s8th-.3jSl\>`7oe}8W*x۩,nkMINR X%$zVxv_rԸ1D.U0uiZhaYiG6mI]v;$sIlr1!v/,3GZG*O7{rif&YfCK9Jb)Z0J16<V}Iv|V{T++_Ii|X s,ؙfk2m6h0ߛ 7qm#FC_ܬkx cg*6T~x*wXdzz$[ڧ̨z֛8v= \ܐ5pf@qVkQ+f U`wSw {zzuv?;O?˭]ʻ$^`ak6]b(0d,Wm>4-uVȝ+FZyǼܞmݦC-C e#EŊ5d[M)ݐ#OA} 7aDEsV{{TG'LmgOW5xVs:c/ffp5faSw1؟ͥ]PEs׮)#i6FpfKsuC]mzJʩ+.!uőK^f#tF6+9 竊ɨ]bɨh%iiӡ+ckzljJJXc8= J2IfK DY:"$׵ڔYM*T6%ׇd‹p_[i$H6f$(S`ڼF0*"zX^UsoYT"$f)*86sld8u~͖m:^FG>W:j&9tG1O^W#0G<7Vf,qlٺ\,$ƻu1!d,r kllЗGQAt~ík5K\62nmvM| g}H uJ*45z BX9[k!!19[yabQU\Yh0@vpMueI\0=AFzf9!bQ`Bdž%5P @zr(e;Pԣk, ?庝*iTllnRـ8把T=VE$<HeMuOˈ]qdR?|O"8^sTr8+Mq:εNfg>]k\;etԵdHf(Tv`9'0T DzζAAJbmMQXʃ.9l1Z*>^f}mOf*/Sg9Hhc[\Yf"ndܻ :Mcc,k-Cy6&[2WTbuA^82Zʎ#bny[X*P@b*BXYk_ iPVK0«fIj5P!R :3E;.竷[e??*)Vx !sGqeuBWqeQV"۬WD+, %eˁηJ&Lz&qt;{M(jqھ9Ǒ8@'J2q(zuBWqηJer 5޻ a*j ϋ:ߡ+g[%w "U\@??CjU kI4n mq|uBWqηJ:CI຦g[%w,~ŝoЕx=Z!#8#l%XhE2O:2SRsڏWP:ƫ91n:ߡ+g[%w,~ŝoЕG_ׁ8Bq3ye<ѯɮl V|VY-eyηJy蒗F;M7Oak۠^#(s>|fdWTCR@2 m)^-|U4"Bq*Tl lCYMώkoWK~|y85&abF<'=4mڮz]o^bxv}؉ v1e!bqByU~;gɏSrg}bbw7zbzPcy/w7jYϴ,}iLp{c89MlfmON>9S?uJ޴V1]ggѡ}T끚% DU0  ^?NoV*P ń jomW@Pȷlcc.aI;K&bjy蜟}z,s5_qvG[dفnNOrѵ0M~wnߍ\[s6 nyaʼ#bqY R9Nђ q:딈8'}TİV?U\T+sonm7 `<}j$'Sm|+֟wmy~hOwj4vyR٣8x-b矯Tjkz3;u:VOFLUQSRzy$^Nl^& -a&вfAU&ies7ӝoj30uWZ􊥈 -lTǭp g`AN8'2C$#8Kً&)L%y\?@gW^1ϒG}q LU<Wd02E SO57νM7Ik?bWY5[LԕZ7SXtko9V`↿4uUHz4W;}jN>.}{ Z V~hx6}5mAFftl72if/ sj"K9RڗiY.J>l+g3#W)fp#ؙy|Smxlxs]޴!em_]fNխ ׹J -FiG]%bɩa q[\6f"(8}xq]7lXv1mUɃi6Ny…KĔTpe{$h9F}b(_=O~6Bc&1c1QXc 9sF=v|g@ظfqh3tWz~<<Y??*'F1N~M8,)<0=Z8DZVkHz>x"(@q4ccwxYH=?f^5n/{X5e[ .lgw&ðK`wԐBA\V??rz4aX\,*GTx))|{5 ͚yφ֢I'dzTۊ˄{C8sZR]8Yׄ[Vsʋbp1ǰ|Qcj`uNH{`=~xZb?4죌f cZ= Q; kls6m>!jω˓C^@OAc^?|h 'MW֩袦?Y:zԯC*}z[X_n&$<@ qģ,sg5޲GArV1Gx7cٍ6Ou1'>:t(5?Tmz/i~On <* tyw^x_Aj 1CUStYc,?>M3y~65_ζjM<1.ejX23lK7ۏ!͏Lz8gjԐǯ?kB9ǽ-v:9bgtX?[3:s#]UWLPKs"RcK81|Zv mfz+  -BN3j Yynv,κ8;5L& 1;Vׯ1cLJ|<Y?F?"3kyݪ-X-pBsb^kmԣoaEEii,sDlc[&QY,3Y ?<~#dL9_ ! B8 p#yV&cLk/>uGX,Kշi+QsQ~pʞ~ap,"A^jTQgZrVm]C[.%LYbw]ky[zk.z}ef?}+BL ,q!C:en.FQģg>3ŵ:wuWE{gU6zWf0c>GO57أxUcQ"=lWZsL~N^gaժfsBHJϘY+>ccf^l/^ a.n[402.OͻNѭ,G.@O nϏ7}iX|)n:"baʖJgm?1&P #ީ/k Tqg] E>3gxd'VS:F3,c89T8My/P6'Ϙ3v $؟Mgq0,3{QOYSb] @7NmNPW>)ée=} l)T m-2td[9G`XقlB5WMQ K6+`JjKZ%3g`ֱY5pz0ڴǝ۳׷#c&|S<|U=b5c*.0??*)Vx QS)I̧884Q}7iwuk.pfexEpOEUFY(RqU< ˣEqEqǍ_M4Q}7xEqEqu[gV uϙBGfq7c#9b13;%3ۡ՟(6Ƭ28-s#>4Q}7xEpu'FvJg06sƊ/(gՒ>4Q}7xEqEqǍ_M4Q}7,'X(? -,dvM4Q}7Kfs8JluQ㮼 uQY ??!ѭ$'hƊ/(.ՙ BYrixEqEq7U.]ȹsy T(yg!G(T=kڼ1"RJ<L5ь+ӌqc ǘ~#hsu1Zq^NyG4 ?3,!^APrQpga^cc\x<=fjpVS_h=(e%8/%.3?8="RJ<L5ь+ӌqc Ǖ={|(ϱBb^ e$ikoPF1ϕZ8z Gf26l%(ό3]½80yZ߬DZ͏ 5XY-Y@c8JMLk4 X5!CbْF?X lN-DO`pȥn UEe&AVJ_oPmlM<5RX*5́TmE f<¹1~E !.o)Y~>>ly6xקi^k6(X.%Z?USlqmv-z쬜M#UJajV@;]k\Vꤿ3uW@6*;z#/I<@>Z,14MRsZ݋ukcsjĕWc5Y,NP{5.l߬uuTP;f72F0(9F=;q,ѱ<#Vmƭy乜dBCr h٬ e&CqaZI6"uqVETMA5ۍafaجg:Ѫylqn =O$on췝u0 y.FX##ݶ*kE l`lfbjܟŢHEdHᕙ67{4WS.IesW'̾ƣYeoTyѯr-sG# UwīGQn'hٮwfUdsskUGSx_RټCX%zWrֵ5xPVu;f5-l5.qnJl7}Mgazi> g1UOcc/[ &c': 2aɷrNpZwn>ȸqe9m6oArJq{;V/~޻" =)\u"rӴYC[hG$. fzkFtjsRlew1Y׬*ݍ]..VUp)3dh,ܿnhg![E<)=v߂mRn{S͐0NK 3(ƨveHb{ő\ŭ[Wd,gZtϺl`E C4h9{Ru\~rPuF\.[7v싇SϠv)j]XlK; mfWfa9<[`䭃tl@hgHį]Xט=}/cK؛ySWHW"U;lpŻ_\MJ.K;svƷ+T5El=F'ݘԩ*3`7r\{4WD@K7% QriO9Bg8ba_%x+ ΤW[+G]A<* Zl]*1j);cn9R%ZzyEhmT++쬵ák7BmVTvkeր-+=B -E>! /s8qܟ& úfu ePO&1i7=juR'%My5lJn:Skx+e|aW\€(D܌{zPJ$zNNj˰Xdž8٨O>=YICGO57!\o2 o^nlj^ u'l+a9=| ҹ-+>* ƮZ[nUܙP* /nbjwbާNN/%Z鍶%ݶȄY 8ԝۃ46\.EBY% kUt_ap9OʳU ܼ}u./5DV 㐆5dF͕DZ5UdKbv2NsTp{iJ u,0b|65uzeb|iDiY7!DERs4us`pcBgLPY٪N$O ipB JKM<)ZW RV1`G:)zS(\ 3t`ݹhk&WW,cqj (M ge4t`SXLiiKҘ1BHUFiV;ej:暲nq*F3Q)S)P0/bl!hË{N]r}Uς춱u`.,]41[Sh-s\0 t eA8iv9_ X"/s8֐ثdr0T dҀc?sl32jW8ӽlMIk $4'riE r uzl\`06Vc13>YZ@טl6+դA鴤YYY>UW}q*,즢ByECԶ[r$loͥ_2cMRs= {'n _a(mbguvuZNI[ 6Vz{Ҷin• \f< Q4@@حȅ\:XPVѝl5k5kie (*m˒? ޲ XG];'e,_uJޕPgH44 #t>٭"(f4,hk'oLe^3 fVRm}MK`uW-nf1OPbIF=+*, L^k!pMV|[Y)[3eSesW'n髂ĬR XtWejO>;&]G{*UQ˒H24E`U YJb)Yke={tT6Hj*&H 7'u*ZmTuW$g) PՉ cش#g,xV\.#`\.Ku2Շc3>i`qG߬`iLMFPIHP4dmk =tug._'ϏO57!Ο[܂ҹ'9@93N*4xUP Fq]jum z$u S|Ɵ}>M\XHlU29*FUi@js Hlt-mӔ#%֐] j]xU*Y=l%kĬv;rߩLSv IFu΂nܻɼ7SEWѯ1,9;_c=W[ԳwT9b&1ť-mVrX5p,8!1UGOgRG"?x6/R%KRs)ņgqcη0{Wn88soCH-aƴA1V !%0^ %vj jva,T:lj+BY::mE5Rcs]hY^. Fhb"PPFSWŨt!\+VIzj쓽yt6vM1i[-v0]oNX9cNj.Ӗc,c89k=T" P#xoNX9cNj.Ӗ=L1b}qf2/M<]7,xtޜzrǏM<]7,xtޜEZ d!'9/>s `'.Ӗ{oج}%Cރz⨬|t _?|ۋL203>ݏ7.Ӗu)f;ؔ鞱SYo{Y++S}g6b04o\$0+lWl4qc 5%d :g8w*{'d,un,nFrq&|ڷm6̓L: ᳪ0(D$^S>lg GMtv!bU.Ӗ a,8fsʬ Qj݉=8x~:'S/+7Dٵ-vxH=`M;U hpdž~,k+mʶH3g"tQ 8:ָYlc&kzj8NMz5eB $vqvSTH5 ׫(\EBs%1Ɉk\Y Z᱓uu֔s8/^Y-EuY1y6(gl<Ja)he*~Ⱥ9 sM~mqo|WƇ b(0#N:~VQji3 R1$D0=Z$?0¸-^4U>*0T _̴J m~EW##ٟ`2 Emv4iJ6Nɓ<Y??*;C_!EfAn?"D?:(Vv _34!ߛ0:y* -&dc^sl6֡Al??|O}h޵]UϝF⽊E.5GutUL'6#f(}8.V~8rNj<\nqgs`ch;-Vv폋<\nqgs+?[xYzV9ן!pBa,쓨A.Z{h%гAuB??*)Vyݓ=}g?$_ "C$akUep(G"q#yH޳d(;<-vΆ4^ofnP+49knN%)E]{F$>OO57ZW?c T3X^Bu5bBd,N|u.5($vzSjȖ^4QC(Bqģ/->m3>Srgة{ƻ&k*.BG^2 G>qm_ٯ oEY>ǯJ|~?6鮬?ߊ-lRs&D%͌p!sb>MTՀ1hk;dxW:Q }~?<郙 ]lz҄wS:􌾒x9m2|4Y|C CH^ mTlS"VEa^w2,Cd F!0>C??*)Vy{ly2L|A8D. :k@@SgyG` E9F!ٞwF3Ȗyخ; ;c8Λ&خ`J(̺uI׏fd%U{{ྷ°%ӫC:[frp,g/=g3όtwvWd+a=AAS-C[9=)|<Y綿c;=hdk?"*rDa%2O] . Y X>^mԫָW=}^Xn؇7Q>wn+gk#HT˰l{ 8F#vhSW^UWt _?} u\c)7 \VfC.1v桹;HbX'I߷LSsO b؎qZsUSrl~D}]JlqA0K ,VN ˿i<{0ٽծS[^멐蔨#n(a-RTԢkdjՆ& f XRi57|t ӟeIbU<d~w8)8ţq:+^s G??*)V{XtZk0\7׹DjѾ|*)vZ>YnX׫Kay\{7kgQcKߤF?,͗A1M.~~u+ЯV\xZu݋X1͎ϲz ʩ{/SuTr) {wo=P(=hKzoi?;Cyl vZ(cNqkǯX%vX##|<Y 98Qsx(Q3jR_ڵe(軫m;U\mϑ6b9ו1SA{Ggg1%r߲:͹{x5rT==^:+ c198&Kz٘"o*juEdgst _?}36>U3g}`&f2C0)Lm^Zۤ7?t3ۿ ea2z;Mb2J$g|<@8pܕ1;3rV|xJϘY+>cccNjTDŪOq'8jxINNjTDŪOq'8jxINNjTDŪOq'8jxINNjTDŪOq'8jxIN'Y{o}\~D:{s/*ރQK qramjҡs6`nZyM 2kg]h !ZgSȺιM wzUZۋrwMFv:(CIWءѧGlhMuEƧɑusV+sO`([\.5gAȃZLԾQ ĨSp4+te:.çY5=Z噆XvEInΧYב"M b5=mnYVLVɝtJmiU}qإR>1br/%vb=U+PnB(9 =;`U됝DɐveN/P.K'_eckz}Y8dAJ;8^L\{DmhL+=[cD1\D-6t =uNTN ku=>gSYٍOm.Xp4ڧh1C^u-6(2k\Я(]M'aV'W0vg5˵(AVLM5ly+o& [ܘČS^Ӭݚ@tK0&ጭ9Kb`''ueE"Dx#vuP#$ׇ@GD9#ᬷuZ&$Rp+s\)Ly%+Qƞ[5WmkY O#$W?kϳ᝗\M׵u\%̹V}}츆X&4e!^ۯ#_)Vx9Oʳ}<18>uQ㮼 uQ㮼 uQ㮼 uQ㮼 }__:au~:uGW>}__:au~:)'g}ǿi sad ї_:au~:uGW>}__:au~:uGW>}__:ʰe4/t/ko{r%ٵV@_` *`ak6]b(0e5 V/cfKuN Nbf!kZ8KmZy y1UuMxM} l^~:PBS\ {NS4zkܝYǰl6IUQPϗEj fY*/hornAާ80իȯ琯ד uƳZȇnkUՍy׽ X3b_4c/koqp3 NJ|UCX$.jZL$15|Q%:~9pjȳ*dg)KPPTV'&Q"EG:޺suj3834ki/.EuC)NLjj΂WMY@tbEt۸vb'2"ηj8Y3AYK:SKR_8ML)ذ7Uu P$J&ʸʵ]P t 8^%J$"2*j jz(yqlN} kzoŚZ1fRb=E&0da:!u׽r}OʳU xY \g_udk!Ny}[jU8YKc}Vhk; !uڶ67 {Fa= Z=DYSp%7s8-`lv+5uݶgq26Z{VQ']*LmLymIs̽TIŴ{2w%u=Eɧ캋5 䮯C gU,V=ӛu]3ʨ]Pt,ftjDLΥWTJ8SwYdT e6 IZV66uq٩uZj3 hG7wL^)[P Y*T0s{0B>Уzήҍ,5Lu3 o%ZNjҬ`$L5a VE꽜JҫbUpɝ*b$zUzD2}:+sYҵ,rzy ]s_YM'FX%ktяdxO%ź/-xnKNjt2^<[?̗dO]9@p!F116^;rq[eoWϫuByki Z[r!kXRjMw%lu u~ѮMG_BByxʀy *5D)g#*;;MMEX4DwrÔN b. c+["Pc3&S["Vp[tg'Y[Y@3xpf6>9Bʶy9af}V̫Fc]]n<[3u2YM${Z)J%H^11TOl;pƳ[qLr!RjКҥ]5h^UUglc,+7 ͻ $=_([4E`ri]޻~QFsG>2ӵ& j;l,*݁-B t- bm?tj/\,dfic]!תG^R)W@]6B2/+A9y:8t͈)ż]6uNbW6.,ڄWy&&'K4Go9= e3dVk+aI-*9׸f['c;<뵡gy@0uWWPlk5& )◰,*v Af_y|t _?}ekĉ$HǣO%ź/-xnKNjt2^<[?̗dxO%ź/-xnKNjt2^<[?̗dxO%JL˃c۵hXdnKNjt2^<[&aDc>qOʳU :b"H,}9w.2>;TϓSΎ$<1cY˪~̏?fGrꟳ#uOّܺ{Ųz8̜W^X+[G=˪~̏M)ZҊ#4q-?fGrꟳ#uOّܺ@ B1O4jl*Oqܺ]Sd|w.2>;Tԥl8]Sd|w.2>;T˪~̏?fGrꟳ#T׏`v筥CSzƮ(kQ2}zg(l5X (1B~%O k>@0 5ZB FV\Q8*ZF$c(mi,q8q߉|w_4?3ж㧜lJ< w_4?~%O߉|w_4?~%O߉|w_4?~%Ofձ^J0X(!NՕ:VMx9}Z*M)~%O߉|Tzb1_4?~%Ocl3o | pw_4?~%O߉|w_4?~%O߉|w_4?œW(yf pk(C\DҏʗE~j3]Vnqk߿?|׭Zq7b#crrgs-C!l`rafoʹpᪧ}qVk2e85===el Of.3 Ke](FwsKT,=g9|~b=y8 3ki*&+t=Go9OʳƹV5(fi(*}R~6n<'Xedœ2qxf)P&s^yaU5ό@n7GYz`X6*hאP[ҜSv⢮?j CV6{z`u`X6Vn|-(9~tlsqvm a :K DЊ7-1^Aw2zw`7tB3g,&^trp8sB~}Nñf{ AqWXT7^ MOmjc8K`Y+?D'IGte3}'8˃{U3t҂1`Uόg+8c–9Oxt +??*=믌M* $BN0qϙ{ա9#Y1g-Z$O}_wTWS;-q)yS}k-)Rş]修99#7srɞN&@~~n1hXJ8ܭpZ=cE]l]M(:T-*hXuYٱzĨD b/6N{v96daSp{pO[D;!i3yn_mW=vYt6*sY@e PG9cPR HjFέ7@g>\fu֥9\U ةry>o_)Vyݱ55I!k)SYeX (!F1VLR3&EN;ֽ<b~6-7` ?5 TwQz]nw-iIv 6/hIg({dHM*EdV Ᏸ>-)2T=~%^>5@+H-SSN:]q,åwkĹ6B%>1] 7e2n,ѱ+fkU4#cqWx.P`pŃdQZN.Nk?)*k[E\][kVاnϤ\sV[4XuzTf,Tlw%ytp* t,ۭꛞylRP7+c:gē8|46Ptw Hw4,̢ԭ Zqj%6PSSd@Y?OʳNp$BKqZ'hgvq,eF(9!sXuD%63ЕpIqoghьy͌c3k4HŲf90k %N 㞓\zwq?p(pC9?n)^[qJe xJSu+0qg|;HdԞbŹ.d! q " 1}ïTzw+۝Dv/>|aٚ2:Q蜡mQ'Z ؿyеIm =*hoޢ=u g֨}ə+B3͕y.Iy0LLtfsba1u8H㡭#ԭfҷUAXSXYcݷeb5{cҖu v+,@@Q$ڷ?j\ljV97;-*o1>'˦"V5bʾ!;^α1]S^ xNe}^:q삗bBeCx.=h Kl駎E[q kG Gm6YzBK_t +??*97 #9r9=8qc=guZ/B.WnQGun6%ƍd3?X1#4cŖAX̓Yam :ժA`Ғs 怲X#hgi*%j+as6n]1Gɣ.v kzeXHQr!gB8̉!6֏ Z<3ucgS<ݻm c=__鱌VT"7\y H8DzOqP݆3VVCNҴi-vո9+UW=4Qslw Xg֭PT GR01X[%50e?x-zP9q818sL~'ܿzqπ@ p1k.RLilǂO=#“bLAvKa..uʫުm Q`>S{{]v=h0QN3F|g9,5"q|Rڨa vg w6WÇO_?Oʳ͸⵩DH&=JZ&vP33 s~;9L/qov^S󧉯^_hTTS UA~-/h! پJ~ᝇa5< Vms7쪅m]*V=~ɶ+i5qeKysccbUTAq*8 Jv UruIV+X달?ȴg1&N3G)+gc-fд%-8,}!XqE<U1HA=N]k?l7gy>%^+]c;V6X?lZjSAf"9d96풢BP_37|<-_^"dqq(=anj}2xGq(=anj}2lV=b{?h{>2xGq(=anj}2ggDQ̌q"yZ`"@.ae8Pz>Ä_^9(3.lK0]} Ŧ`C&7H?PT?e;ŔyJ_6]OUxڈ|lkCk1nj}8, ,G22qcw$F72vn>kAd5sXÏAÏAÏAÏAÌ9t#9Bog!",Kfۜ?[yv>B.\0J6x c1c[luq${۰,PaLbYƎs0OAÏAڤ"vM؈ӡcgZV:C /Zٜ [ljMbp6 ާ!& ZlaW٥<y|YO_%voQd"yȷ@"Vb(ǩ'>SȭQzճsCKIUl|,W:@1H4 [b0##GcIU\ BK vWC\o%?o|'aC [r_W/w-Oh8֗|(K2'9l1c1c'_/j2`ϟO!-'P+Qqclzb yut,rBˤv<^}H^M`<\? Rsֽ]*%>UgO^ `8fsZV*弜X_raG )cq(O_?cWnWG x_ՊƴPocEu}j,o.RqEy $iDQcr+X93jn)g{ufrNe^ \nF{eqObCָ,1QmOt-nn(owZfJ\{&^q _N} uځ.ڷ|fͮ/f*T.6 dдXe>9 &sd3,<>xVoݶlK֑0$vꞚc\;jbs)m587?8޺ԹDF=.=l&(+2Ilٕ|ƭڹ*4ADܿ]ʾT5ustFZЯTu.P謝͆Q9 ZMftGI6gsֹ!ӱV/~/(֨)-X)h[z8;9FmM{fu:-|a,潲l@ԭűUz mV']ka5W۬MЭ9/ȰqjhY鷀rlcʝt"Ѷ`]wXJZcT3{5nߘJaݬ* YbSZ_J=1=`OXԫZ{6H3jhp؞n̲C#H4Vc[8 )ώI[W916;Fv_ɧ\XGɱz{kӉ)% FUzrVPMq)ň1eQZxbj=Flװ{ե}YSE5keg*5o/Yyİq g*f6pT*),*kTXυ=-9$C<$P)p;/OifqWֳMik2ۛ^F[7Fh?ZfWfeyK K;жCuffONzͩw;*^+߰0s1 6j ogԜYi79l[u^1 h(@Fظr ܳVo"Gj ("0C 9Y{y|T)IX c8[ms8z]jiiĺӬczR{ EAUґxVoOP ɢ5'j_$%b'Y&ñMo%ՌeuhO]^Y   |/8 pp̤b=9,|5\C sk}r|Y˹*%p(}f4Dam UQY 36JB+Ga]#YI4 9' iA0#$QVKEfc1zFg"kB3&%wDg w:ǫ=Elv%u YW["H+ (aFdt^6J*+PFY;״Mb4`LݭU: bXVZ<^5N9W₦2gsb8(RG+C-*+:@"!xvO|<\j:Pq'`>@Q 39B68thcjͯ{d?;.UZu8p)J'fW`-&[S(+\AFꯀpYظ,QX ŔC8~G 8R9*t(ҵ07KVv/d`#WU_ER9oXk2g,-eЮOĻ8.۽J^%M}A@L༞\IFp p%4}80dCk+:36\;TfC[-3](JnjļWkg9ruF2K[*Pv=bu.FVg1MR[bil*ʙ^[ßS[ . 4f5 sVQVT"`D81(^US4TTIFS~^ mH 7\EY)H1Gk! O{DK^ %5`6UaEβY9fV3!nKy&bI +c_5e-BaT:6рb ºS0nR0rW C_eրw/:` QWu wT$|gC} mܬZhڽÇug8{'qgg:uSBTcS32#๹J.gxCARNG6m<*ѹ ,'-YBINrqi,K'$!;`x 6(%bKZI/u!]bx=cbu(02UUN|q{b X l[O dB9`CliiE}R2&DLL.IwU0< K+o_)VxYln|XoqW{*[O[3c><&h31 Ŋ,U~bNj_{g5bc<`<3cOox&m8׹[Kh$?B\x~xRY\jeo˿prwo, LcĀpFyZAb hKE{q~vta89@9iA:cf\s4, g=A>;~kHRu.3Yz}x4=K^=UۡmǶQm㼵\{bl8&hZAV5 dhcՒ +RCr6zw8 c\a.xJ{ǏZxC]؏W(ؒ|n1$BG|}S{\g"hoU5Xa#fa-BĿP-6qO fz f\p{2ٞl]>lˌ/w<0O_OSqKGep~Mku}a;/y8rRר 3,k**թ`Ǔ7|?.l\x)o#RH #PliAt D!B>9q81|Xupo/?)F̥c>r3>v1T:QeF9'NJu 66N< T 95;P{Ng c11g Y[Xmڹ`!qqqqqqq␖ aۇkm+|? grh)%Y4+dG[=y<_ipw2q*;N'4/w2_w.E'g=>G??*J1e,9,cB30R]J:oZ MZIADK(P8UX9"1 窬{&^`WG/?)F1̥c>s:~~Uΰ\0H!I0؞ݬHm06Zcg5mjAC>8$ǩ%=I(}7qIC齣RJMzPohԒ{GgWX̘6[3OԚ[G>8&ǩ5=I}5qMC魣RjMmzPkhԚ[G>8&ǩ5=I}5qMC魣RjMmzPkhԚ[G/')Rk@쀚ug̓5\NS٧;jk8GڒB8ccZff&y)I x1zptb}Nv%yoĈ#8#;sܿYCYV{s@jw#Y$EGAީrg?V2^??* [j۲o9g.5JHYc`^۞e:lAD E>U ͓]p̥B@?hl< d$B9nݙg&>xcY٧h|v_=c834 )9 C|t oTRI.8 c8;+8Pz>ÏAÏAÏAÏA0m+V{(n3,[o D8nj\\SqÙa/ hYYllc11c ԮLv`` !KޜY5N3,XY 6Ϛ)L#G2#fhf'9lgxif'h:Z7ȃ>Oϊ]뻸Dze";.l,d|t oTRI;'!-'%q7̭gx2)V|yi^kG̔sZ2 qDq!b11yЦ.+V&`ի \ . @BF8TT8AxQՎpFe4r$@PZ!,>0@\6 ϑ7SJ'Ї7ȷ@V?2G>KޜYG2qcΗҎF.? ލOduLn6Q2%>y]J*xeCc1sc,6>GOߖO+? 3M12d裞;?{O^S׸Tu;?{O^S׸Tu;?{O^S׸Tu;?{O^S׸Tu;?{O^ẕF爧q[r_Wxw+X/zrg۴:ӆyڂȄ0qB8c&e"ϟqg961Ə2+}\g쎮O;tzF#>:\xv Ѕ96UhA>H.u&mrzk,)̼KϛV)1`'jDX-ֳu7PaN*!`y(Qw&ϴB *0>^厙'݇=nTQlbaj[VTy84){#0KU3~N6P˥dLF5S@/L(4kk%xo9VV3|t oTRI;'! 2Q[J2qj]]qG ʻoXZXn4|A/G SMF5LwYܫW=saOZgiWCP56ZL´$!Y52ju-9k^ˤjKO\^R#hJ9TTVpO^Gqi:֙`z p}YWZ#dHUAj׺Wa0V,Ծn?ru yg.?X{Ut7vɖ( K\R\B7̭gx2)V|R !I,Fe)i1.hbh'1,K6Y߽ lU) stUP@Ǽ/6}Zـ͑q JXlS8δ$iz&YLT0R?w7SJ'ЇݜsWMW5\6U;|bwi(1\VÔ&)% o}\~ +g4̭cdU.=9fY jk!0q1\W>跹Ng ,_WقIUu<1c1`\CީrgvOhClzZTOެɸsV&׍ͅƟsq\9ѯ3(Z{~/Wy?~[?ԮRN}|]-_K$;uMR!`Ǽ/^E9>M_/ej ^/_gaۧˏ>La(~?yoQ5*!|t oTRI;'!Ur6% xlØ׬Hb uWV9Gh1간֢[EЊ{;MFR[ ' й?yqtŗpl55!-)e=ME.8']#4 `..щvv\%NP--'%q7̭gx2)V|BIF6y̳ΎS|s#5CaxoߕN=ZM.ox6QId2SMDOl_?O}kg^!R?y?~[?ԮRN}|>>(',!*dB1OF&ʦ~}oGଳFO t0WPR6Xj$%[UA>~<[N+}Ko[?ekc%NSsIs1cKޜYɜ3Hg8p/.Plhp?5L;1*-\ >'ϯd;&=~Wc|t oTRI;'!eQUr /i^ĺX*j˜z±VwD[eUW5ZH+!e\EAɋ-ZL| V_/_vlZm`9=5gZ9C/ݳkU9]LD9M$z>B#VGQAvI:*Y@!9?!-'%q7̭gx2)V|}#|-W)?'d>9RTɬ° W9_V4VA5ĿPQl["5-ѱ6é`*Cdu09=ZZq |`kmi{4[(qٶ b6x>vM](b"yG"q[r_Wxw+X/zrg˚ћ1+<{›=n_7۵OޟRi|kº1uuQ y-1|t oTRI;'!qJ3,pr'HVv#d[&֨Z<Ѐ?Y^x3Z٪Z wgc,OיK %a`8BAkFTT`ReCf2Oo89/~elc;Ə}9Oʳx \ϯ',(L.S{?@- r^oS;.P`ayP_k"7SJ'Їױ\^kIһd#r|pMWu&:(fSZ+JIX9:{b뜨yni{3p% 8ws*̝]Y*7'cY+]Tfmz63LJV ~3wc]zg@(yxeujqaVij/*莓^zk(V9'(ѱ=*dfByc"q[r_Wxw+X/zrgme"3Ɛ%k?z~x _%=k%?( }~a}KPa_=|t oTRI;'!{GSh GWƪ"&!A I>M+Pe+jZ] 6;LB1h 9k)_*C $I>9gspƌYٖ :›XU+g) Slb9״[UH{5Uݝ)eo0<ȷ@V?2G>KޜYylf #?SjIӹ뿳=~P@/?ÛI9cSG Ny#9΅HIǚlOߖO+?{B_wfլF<@91saz2.ssL]n$8 ;@L?E侮??V2^??*ϖX79iϱ6_DxBځ??e {u<Ӷ۳\x )q>:\xj\A[76&OkfXqkEy\Y4k: mʪ"q[r_Wxw+X/zrg{yfϚm\(V'@#)s 5wvgGOߖO+?{B_-6\]U,-~BYxXTD`8fsvZ!`"bѳ5pFXbԍvkd ϛ o}\~ +g4̭cdU-쟔ش~Z2o?s[%s>3H{w~(L@?'ϟ3?yZ nTQt oTRI;'!( U\\ousOSV! <XLέ~d)+!q@AZB[wQG>%G84":U I,ȀJ K~/axP=\W3(uc?AyE;6ylloOOߖO+?{B_ȵy;NK;liQV=0ضEU,{>v:jce-c[/BKxi?Z_??e_?m?kϱ*Ayagؘ43u>L9OM鵫wnjL ikOKYX?kQ@>:\x:pQq%&5 Ak R d#L( Mhf ȴZ9GNH\˥ZֹZ&D-rb1##yȷ@V?2G>KޜY}~P>WrT0p< _s{`Cy{@V 9?^m$Ly??~[?ԮRN}|0ssީrgvOhC[%fXW8δM%?JpOKO"vV :T4ౚ)eYfee#agmc {e g 93\GU([[ ҸV1F?4sV3hZ{Ӕ|>[?{pvW1|,sg(uOC?3w= OC?Zp[Svبo=ZgOC?3w= OC?k F,)gyU@&?J%u_]\Fى>OOߖO+?{B_KFTc=}vοvUaF,X|WQYWtaM-fV9M0)+vfZLIqy卩=H[9l"1X:J|&.֕*cVַuvI ̿E侮??V2^??*ϖBl5KW岑&+ j/ژXf8?~^JRA]qc55dXI%4Uy nuD<rokȺN㜐9GKfy8bQϞQ`ki-Fh1a(JSWC * GީrgvOhCSv0ş'!eNq[qeeCx4c!ͰxG2IHє::+7jHFdYF9ї&3UC +sssc3j,'>;K.;K. ( cc8:6V1B=YqYqYpF8M n dj`9 O}yZg?=㰟ҖvRÎݽѐ9'a?,8'㰟Җ GU|s/<|pJk7#3{ )aa?,8'1 biF{ )aa?,8'ג3$<rozO=9Vaqv3ldn!saqe(:HԢ`be^kIB.E( 5u8uqf)kMuQUp\.E&ik6%)`UY{o}\|[(Wg!_V1#m)Rȑ+EFRDWʶ;&J&k8BL{=zN9qdWpխ'Akj.MKx!kvZ/ow[sf '3\++8T-_?N7=DPGR``ՌȘzC{;5 h)Up˳#}]0K5zWzMsjToigW,wH+m4Wr֝ fSu]z2C=M""Eb=-7Ш*@j]S(Aʴ5h*wXȚp%DICX)e`J,oa&-R,'JA oYhA76uP|a{qGW;QkpK0[E ]bL?>9CY{0THO۲޸j4YP7w1AEg>>:\x*޳췫2nsQkجNb܉POz-{Ō̒P%]PM@qͼ]6ŠmL{Mb$TjHkǮZz_M)ڪIv vMS٩k1l4i,xU!Ug,i\ez|RM=?E侮??V2^??*ϕ/ȇ8i,mӡfVٸsU3Ms3Uҹ-3cs" JODZ>j %.r5 :CkCMRWlJ[\P2JMdshfU6jm N1դq9{LKk*.N:]jՙV0,b\`&"s[٬cY]-{(+0IMʺX+*tlcZԌ,Ҋ [6-jlЩ5Ś'c6oS9%h-\(+t&HVSe:hUѓ', }gjTlO%g BM[fٜ-VM ;Q a fx4r4mWnAR2:ޥ(g&5lܩ{k& v2PSվXgf .-S*h}wg5oPˡuyC,!'בQ,FRy9n۹u<݌ yc*⮢ʶʭu%xY<gv :g-E %^dDGB1abKSSmi]_uEXJZnkBӉ$ Y3UWvo^M0dy ޹5ҕC&∺޶/q:_@[km}m^㭵 u{/qӊgT2EC-W)?'d>7EjZgKl*OrJXaVw{n"HlzjsO/EsO:X6 S7Cܒ-qΧ5jIm=sR㫵s9M[֔TR;4 l70ٶp[ f(D;5i)sV3hZ{Ӕ|>[oSʽ0uqQgd}x#)īc1V dNKҋVeRɲVTcK(H-s$tAN: bP2]rbNhJ Xfb(~-СQ: ǭvU)GgjHϸ ,b=)[ VVx]mi((ZUHD!Sa[ܢ({` kh18ͮrwxz=u߳Ψ>5N 81gqg?-W)?'d>h& 4FK{Slx̜YqWshn2Eh&D<[N+}Ko[?ekc%NSiLyfRKTkIt[s3uvK<Ӱ*,>PB=aj[, %JeOZ0aU.h̎,D'vթ::sVYtKʘJvW(l?*xj@8<\I2*Yu5f'#l@jъ!Q]38,%-'%q7̭gx2)V|oPSut"ˎQȞc Λ+X=S mMuҒJQdw:QWYۢ,wXŖ^Bvabw5zM+ylFJozO=YXl馾{\z-p Vm"y+a|՞# cUz)Uy|0`,׆(!tz{f9WU:z`iZ&. ޱeܤ8W0޳e%q!sV3hZ{Ӕ|>[k,6sֳnVz8{XpR >f~:\xYֺJm!бjF4*=Z7m!z.s~0a-ݡ`dT(@r>Ȓ^ʶA Z^<ݻ6υ+m%NdBse),,[ Ȯ(i0Zp,C]TPl *-UvXc؞:pMfZ65K]MsHDO##^'5-f8ZjHBݍSqx5"fQ>"hy%UAT@={FT:o$BErڵQ~, ~}4 э@Y_ێ@$ eX9dK[N+}Ko[?ekc%NSice]z^+?/l[i87<3]Eb!,Fe, tiY[oLA~xI(`L|7SJ'Ї>_v16ê.QUG\w4αGS۱"+uj(\LM/vCcܮI^${UhZ[ MXQnlܖdR賈>kLF+1e2.97u5vؘalcE˔WJ| 7\΅T @Y^xOxwKg[Y2'h qFH \1D&q:LuQعJVʌ̵4nSpa?E侮??V2^??*ϖvLPR;a1ŮTF4fNdb3-sCr|!~NLAiPPYFFǚ!4YT( .iZɧ)TozO=>N{GUl ioY_ggfr81[6ib'cE7y;q[V|26vT] Z0Lv2P{GkF5{h*eakjx/1N{H^2OZ #ngGmKu鐱Uر`; ­Zw4n0ɿCG:ǟ1٥s{O?y| i <-rADXd [N+}Ko[?ekc%NSeboH> &x]_Bcn9Cyاv^7$%j̺ȟ?~[?ԮRN}|<=hlfe8ogG68eΆPk[ᡍVctUVfu12&]n1g>y-'%q7̭gx2)V|K 2HYi$tYdžs9ysOx҃9d}kgeG:Ac\8\fɬcod韓3~ȟ?~[?ԮRN}|Ojl(z @ sE_"q[r_Wxw+X/zrg\{ъfC1yƋL+k:@5Cqqk1,>L׹ٶgad!/bb8?~[?ԮRN}|>.Jڮ.LKϿE侮??V2^??*ϖ5_?^ #z}>+1wZ?bzm 8 6L3aC;A+M>:\xpXZ {d'iRc\NE].-Z{y o}\~ +g4̭cdU+2>Fyf*ETU စ7tդWS&~K[-vv=`AWצ%a# 9MXozOɁ%sEg8i;?{O㾓i;?{O㾓i;?{O㾓i;?{O㾓i;?{"B#sB1o}\~ +g4̭cdU+>\{Z=ŋ,Qke_of]-ꑲ <>K.SaNx~KoԍX-'OߖO+?{B_j 0ǛNڦ9A,5#'&eg Dp.C6%b޽VK.G'%\%o}\~ +g4̭cdU+_[$G1u9Q3>1"_G.|;0u87aHΓ&,lY,e,ɟ#m_3} |7SJ'Ї+HTT~k8SETE.떖iQoշoL=\4=c-n,7e}~,MGcgjiYO?{+KV6)ε%y:j9OBnJ4ʂ.+vMX bdh1WoLLdkSwBmYl11$lrlͻH&`1\v*WG8+& N bLXMc!qCg 6O3̂HvchWsV3hZ{Ӕ|>V.vezͿ!O R /T01aU%[}q̝'jULk>Pc1cEp;xS ptX"#0bO+@QL-OߖO+?{B_.'&yH'iގMPe\ƠpNw 7B<>VlWZrLJ(pv5SѾFx&,w͹eBR:ؑHJes;@ij`#Ju;m+6+JZJpOY+B6(̥ 9,#^VlemTS= q]3VK&>ݝ |_ǁ-'%q7̭gx2)V|<4 R`\W$EjuǢV{cPT[=}?c T~Fˎqj;:If2_h6mوȽhsj[9׻>CީrgvOhCe|d$ebmػ'B;wzeRh_vb)u\VƒMŬ%:}PB!z"ŨlQ̓N 9 }SrtjM=j¹./e ثTV}rT^8lzч 'a3# U#F09cLJa>q ?X411r4lƽfMUu̜J.f ,Db9i*ڭqbøǓ~JpWs,|7SJ'ЇŽeRvɘ8aqסS;bQ-;fa$p&g[L/7uIn+B1CF5PrR,|Q1oY,H419›{%Ul9BCiܵ́Zf^JQD)ģ5Bk)52_h.O7(tQAi!4coY}9įS,Z7G%)i u] |tKdSmםro 9AmʭOU9í.W`<8?2G>KޜYՠ))޳4s(,O+KKFp޿)NI`q"l.AO)?Q2onqMb^js|EIX<`51c1lcɧ嵇g?-W)?'d>7:7{µx2jH/]Gl*"5gb-_PͻUJ QG'\]ziU&N…pŽtgh*kVe!OhZ9',`,KiSٯ:Dsνֻt^4KvO֣Q41i-uP"Du Mg]c]QD5z/g6Ҳɭv'W6GuA)Δe(ҝ]i)1TNh6 T,3֮OTkeĄ(yWvhA5:8ڡӆ/)7m+ tձ*Ve{o tj hsYU׵Vpvݶ^iW(aG>$m0Gȷ@V?2G>KޜY򅽚5N1ϑ x+ \Nm=/)eyCƈ kc/YOֿmpxZʝF!n5?piK#c1c[ 3ƈy3%\O/-W)?'aEt>/(\1NYr}Q^rv5&;Xtdy(KYMѶňi `6J~86J h 2枻Mٮi 44!QSU[}nP[ XXf &wVрܹ} Ytb OkFpv"y&X x3oĕLslZg,LHdS1ú@@5QB `볬bƪBT5f j5q.K 9)_o8BYzXq7̭gx2)V|{ [PG"fYfh5-t8PME֏D(\9AŅᴬNֵ! VѦ=}IZ, 2 |և, Xs|7SJ'䶢/5؇J3K]=yyyyyyyyX6%~_?~[?ԮR?2G>KޜY~9zKp~^یH=c}E9|1g3όN,&2G:H2p{skM r c`lDU:|~emc;Ə}9Oʳ\dϮy7u|ܟkX*'m3{[ Ɩhoo @vH$Z u*|([ml}U#^>髋:{]ݴcmXަ__________________________ Vb;[XACp!{ϔ|>NOHɔ$s5h(ѫ^YGg\38T7+#yaU=8B>%3e2bYhQbMf23SG(5M x o_)V|\bty(Vv3&lyu7o$ 8da8R2mak6'>)1or[noBWU&پEkMˢ3:-!M;Ζnlu?W0 |Ϳ2{߱Wy yVAt>l]=Fi2IV.L u2z-EFn,?hna8 Z8Ǵߋ!|t +??*ϒKG,sĞ2xGqX(Ƶ!`+Ԍq/!29hs@9}2xGqْ[\ ųq(=anj}bs#?!`Lc0N6K9)\JsxGqG22q<]3M1& l*πPz>ÏAÏA+pݟ86i@1at(=anj}2xGq(=aoHDM(=anj}2W٩c`8$&<sϢ8cYЅ2xGq(=ag;JFs0m+ÏAֽ]OS&~N6ABHߜVڍǩVVkUL:OuۘgVhڰʛMV\g:ڶIu™E ñ+$@vv4IwQӄRuUlVWxŒJxGbocJ :R-cvV[ 5-K=`$ouSV E]&m7]ΏTL>YYm5ʩBЛ,)M1]Hlc7]QT>J9/K]2_ XfMFN" 55u-Mu-Ս6v߼laEkt]mH Q!lMgSV6>PocEuwE*`' @/S9b+"Ԥ_z|~_k'>4ˣn@-_۱ݲBP=6!R C4 Y.CWm{E6{+3X -_O/Z;[j6.BP-}y˴bm 7eS77v;г.T '=tZL6_}t +??*ϒl#^1rp>LAF$8KHPS\ZK0KV4SiYdivYxw("`֞꺠숬"Z鞽YDp`W'0nusCal쭁DTň‘SWHR,<'ǥk4K2 6T`6K3͝3|ep'msu&Udڲ`]Ƅ 㔁,V=}YGTÄtrKWK=Ǒ3U2r[$ - L)vfx.6c,ETfɨjΧԻAR Elܼ}u.-t]n6;D64{5%*:> Mׇ^vV93qw%U1q+ڽZL *-GN+Ut|ys=S+W*UB@2Ѱ˜pgflmsjJv2XOZ&lvfN:ˣ}7|>JηM ta{bNj_"9^  !10A "@Qaq2PRbr#3B`sSct$d4DTCp5U? ,JG.f5}v뵿Wy$/SnHU"83DPN =@QDJA":]K?խ6'QY䰘pG?:_]ُR[ƶ5lkc[ƶ5lkc[ƶ5lkc[)FVLkz:0m'lpa:OW\5^^cnq;Y%9e}k F⢊9co5 +V7ln2^Oo&Ð*(a˙b#1i?ƉhqN4I\2Gj,&Qĩhvts#DbQF UZsm^/SGm$ٺt=Y^;C@# *q9!Hww^^NkjZڭmV[UkjZڭmV[UkjZڭmVHWߊ-NG<"έ6Q"dȭHNMs>Y׳$cj+WHuG>R+Sf%л+͐}ZeA@pO5YY X!$xMCl`Ci$8/W\/t.@+\sGW4}\sGW4}\sGW4}\sGW4}\sGW4}\sGTq4x7.^ZϪWS@iƌ8*k"b@PVl H2KHR>m 3Q6ZP̀iR eX<ƒiD<4!SwT6\(居*MEg 6BtrE!;> $2ʰpi5auJ@.Ĩ$o`WQ ar2i,\fgtP"NGPG|A럝~F<@f(&dc#|Шyd`2BGf8#|5Β8S!"]`xli%3͌S܉"(a"9s.!ݣ.eBβ 8)#ydB fcN/7,Eɦx` 3*`c3V;ϑ%f8h+.8|Gt-eFWwgՏ+b#+ ad5Z_"M:"K"FO,j)(`A# .-Z HfN`NWRcjO”1x˔5,nKQb"惠1Ճulw]$| CQ*"*P"`=v{ulw]`=v{ulw]`=v{W<-ڰ3~u}; fc*b'N̤i'䱊7-,*&mܤsY E[^ Ck{sn *d6 'n!k$bq.'tRY h_sKEcc\ɦkG)(bLSLM΂F 1Kq1wxn@r=@/E ۋ84h ډ>])25j`k=ET{˜ :I,"hQ r]_ t=+E6fCtX8jA9RqVN+Ϊ ӸRbб 5*'΍>\zcoP,&Jv|l6_?Mku$Ճ#%qV[LJLhn3Zax T8Bn"^dvsUlZT]0c[:r Zq?Cyj8:G2F`qW+leʠOdHLPW|1FeBC{DԶqē$F3$}5(R,QΎib +Dѩ\C38@&,ȖC qrҀITa+Wce(1K)iĄM,.Dr8U! W;][$\$.đ.NWInki Je$Ze;VqxG|A럝~GlBI)YH _Cfm.xɖ'늍v#VMM OtjR4m@0&8u1*$O p6-U=`$N(ìPF [,@"e=婢IM@5k\?.@8 s4]2Źz-hBE\Msu66kB\pǂu"Hp\[h`wc+W5kPD ,B .I 27l \OPe*gCo ##x οoN#"YFUjNZ>i%x b4U.*+v[<7gH]@* ~1nէRiE (n2QAt UqSA.$4lI5 DG]^V*ǔgD{9AQ&\84/f-7rxRϵe1hLJP*k$HgwM"tez;8KB!x\zCyiZ,lv )o-v8i7{VHhL,'+Kn meDaIS\). rE iF]$-l'(2:ĒoFW5O3[pKI,Y94*#*knwkLWou%6ݔ115/,$Fr/PRDaR, 91 { h;-̑2!SG0GHָZZy,&R lƭ{cv*݌x#PdTdsJ%{aʌ<;,eW\?@R\L &u2f *1)˨7{dRKxX.S̏9cQ4UIWŲtWDIwqo c$Dp>CJ XcV 8I>Ha@IY60L>; @bs Wqb&<29䁝y.7//[ *"TzĬT Y٦\pØ*H-^F,bi4#YSjSCm"ō@hV Q!p T{-.AecX 3FFUF\X?:BI8+`el쭂}O V>'[+`el쭂}O V>XPt*YmP dS!b8bdS6>uĒy/!@ctQȓhNRc+';(gLH!Bi}pmyWPN$PUБ̺-sMt}#SA$2'('mz&g,ANzUE*Ľ˕#Vb>Ji vR:Ʀ; S+>MK? zNC$;eFZEX;Cyjp(8R p[>Z͚Tpw𘶲rc0kBڻhek *.J[GUP8%KD8 6,JD_MC-EiYtB p#Âdc0z[#C [WPr]5Xbhw20Filf-tj02jo"s.b:jkiȹ >5JnHV ]$W*B:R>+% 7u|A럝~F]Cl E=!yyN2S,FQe6p:j9ʄGRDBt WTA#h̎IW1MES+6IҜAm0H|KH:C4Iތd9.S} uYPJ0WVV"8e og ,'Qgߨ^vݸ☍;(X'TYu3pNJI 5ӯY\(H#gQbED2etj]@qFj#A$F\W.tՀNYFj.:i% j]w ռ^W9v uaY\(H#gQ2a"05Df|VFA5$ntHP\{CyhD^hfLuH `[cF,xVD0 hW$\2/I"(Gh f#0dPs\ԑ)2FX#ԐڑȄ+TT% ) u F M~P @qάTjrYrIyɿQjIM=@j)#CGsXIl6BmhD,KJp*&H.˒ BK9qR[>XOJD12htw2|x οow(X"()w|?.̕mʌ]]iRAޒ(_bG.09QmnGOvPI_8QMepNRu*"-D >tوS9if$;lgC*7.$ػɒIs*qۿdUU$TLN5 NIU$-䫍LfN]gԢqBOXUK.ΈA t,$ֆ'qR4v%.I *5!l$%\o}x gN*bX.27J*$AscQM # l54hh\'\^Zqm3#>e!qɩM"X\ܺuh݇Rt$*72"XV*QhiYLꫮRWfA&x!~Tjה㺝'*-mCVqSJtBe xwHi&)``tҡ|چ}34G5jpQ >qCJ / ՟)E}"YI046<-1.Ϝl[mˡ4jה㺝'*-Kt#vh_g+FԊ^GٻjFY%4/#jE`FK m0@!#όTr'^ݗ#3Rܘ"T2q4n0Fk6>uP-ᡡL0!޹~"wg`f Wj5si΄cQXKc-Yq ƔB$ݦbCM\bI L1f l.ru驗DK 7# Q ďX dB9 Ɏ@g> U:E47: 9F0A]fB̲XqH]o[F [%5VsϴBLINgI!'H=5vSFdHÔt,z"h-uk}KIZ47.$̀4 )Wͱ5G.'NY> G<2r 1&2yF'H UIFd}j^3K$AEHaut~Os /  )z䇛P pC:LPr4'uJaOѷyQp$7@lNjx-.Pđb= Tk/"dȟwImioۿ::@ 0ZI2]dus43/ 9- T;;⬹MgxѢITDdbRW8eeItNT2#3Zme#VxZF eCASB)v0b<*73 ZC/3*夶7mߝN K3%HK⦥y\9ҀI8*i9*Y+d"y}tN +Mmdh9ߌS[M2Η@ޤW [מqPYEun"y Zey6mob2M럝~G#DUpaިcFlIȱvy5rk#p:MXACN@&=cQC$ЫHHh`#CӗDE44yR \3QicD7pT)Xn>[H}o d2o")nϠ|ФV$$qfK9WT"gO**ɏM-$y֛m=KUiN W@>DHW@K^THFt($HaGe#aWƮsKi#ЅL~QPO2+1'Y4aC,IDn+@%w\eP^Srb&C&vN:ڥR%@ъEW:)YBHW“Q[,qIQJ#y 6n#:WG}a:G8NlVЄ5,rjFrxbiD<4!SwTr1B|*";i\|$"Ӷ3>lp((Y:9݆8) u@Tw[98֫2e򊵷va %cHfJ6`߂= YA'HڄR\(wi8lV&%ʙ{yڢ C"()Kkk%K.s3=^/=s BrI$xe27XEv';!9Q`1".#"r xDf0Z;meƥ|4ӇЦb_́IJA^ a$riDJA)&T :~MObKwF^JT!-My &cZI(nd-44RkA*&:mHՐK זH T-S6&nd'kR~&P{iQ.G]K2hrԦĘReiEmX)S-FbEt :^XW{` hKE`S4QOAcW`V7O$ziu~Z5^ZC`_.7]_<\6Fӏ bҖ2:ݶ4b5s};F=usRFvBqtP4]ZȂQ+D"YkGz,IL a2daԍѢKqPz"g0+@Hu:W uAN9a.^ 2*nL7]:q1'YԢ2 Z1nvBXZ=ÉR\AcĎ.h"ڪ`AWI &QHLL(Xb>"-0\kB%<$wI ym2 n ZccZ=?JƘ.hoW\?@v-m9ƍrfum~/ZV^yƎz>+7i͕!뫘% $D(H@ &ȁ"2I#, "rp> gHN$Γ7r2Ǡ|Э,u@/ P=JrF921s,wyGZ1uFA7gG%|Ob- Y [58dlk;`Z=c+ #x婢IM@5k\?bpx|72c+W5kF.ꨐ"|z_z_d\("<jY  1.N,k|\SH ':W]8Xpt`pk΀*G @(} !Qwzѻ9v$䍔R#-6ܱ&L=O1xѬR+Ĝ"Ƣ0֫k721xʱCzpLZ!Uٹ)kl{(xhxJJ&xQiTn`HާuO1x,R+Dt_-K3pĉ-őGu "t#t:O糈 ס#:W^/=sX9%xVlsQx*DyJ"0)geΞoixය(w)>x}<(+,Fq4Ƌ#0T.+B%`T? Ta$blwfǖ$Xh Pj8=@b].c311'ݾ.bVC 2 x U)-!q]5s/VH.D ^O@MYܕ̬fC,/nl#Iv5`-vf2Pad-S 1:5b2!%ƨmj9%yxbCOQEl~r.RZFEDgo{hZ\Oʅa# gIو]HwVpM2\H"T/y:=ZJ =~u};Q VJdZ$9q5M ٵb.m&w,U1^u@ΈzUԱ\DZ > RŎ54]\8#*doV23Npw ٿ:|6ڵ;ckfMӺנ(t6[ceAwcM <vːA\$*@£T-K !i"Bl'-gTUD%iRB`7epi!ukd٤6Tp  DbUo;X8YٔXXBf7]$UD<[3Lf.6# ?:2"0tHURMgC LA5z-_B5MNIQŴoA4* lK*kg`@(:C! Pj6RJA#CܝfrJ08 <(྅Zb#"\kF>3,byTdFW!oq28DHeH)#Qpn"״6m&Q5ď AGYΰ*u ,2YFEZ"w슪$D͗|z!wY "gqh{8ɇ ]AcVq b˺ I(B-Xl)⸤ RVPGH6:-PGdӴ;IPWut/_z_ i+rY09(&Vy.VPdTKjcDvFPcmP |!O78n> U̍K F8tI U~àfGld PfzVFS Umob Cc% bM]Hk+N_žZ>2ԅDF6:l(byFXŪkTn]9"Ƹ$Cahu( < i!*YB 1M.I4KwZ? [X.OAK":xn4tBr-'iH1#}~c^_ x οo"* fc]Twi.)"-F!04'¬ s!ӧ lgԳQ33Z]>ZL{7ބBUȦچs'S} Hie`2BGfoP)ᨌ&CŌъM{}dɧRG*XX؍@F*%Gxm^Thɡ`Q} 4 qe(pt1<$)mƼjy<[ᑙW&XVlMY\1Ƶش5#>sVy^KXVxЫ!j$[euhD.duCz?EmR+EۼqYr$KxUE\Է7BCyTTrɠkc%Cd){1fhdm0YMv q8b3#x5ۋfa+ӊ$6S4TjI9>MQiZяd$UFy<`G&yصLᛩ/PB 7R]:ڌu q*hI7aBSIXaْ"7A|A럝~Gh]v[pK#xg*sm/2%tn \o_Kچu.BUibb8EƢ&+;#9:2 Z1nvBXZ6y*<,X cAA11­ DcLW4ݏ@/Hr5uS /}ͤu Esx)25j85@b(v&wr4I($깅&PƠ Z<5h8t{CyjWԙ%y{s4NT" ߤ2yA{VURIk2,. <[R5r:H/_DRufX.8!)EY54PmcrgU/o#'i)@d:=s؇;NiNqNζukC=ºo[=n*% i1I/ 2P9dHC$yJE# 3+)C&ܘhVv~ЎǠ|ТTC.둸"p,4WZ#"+ ΕlNbّX!%V4UFm4gN\> To)BA3Hn98"B6 Jh;4V6M uniC䖗յYfBFDX["UFȩ&e Ռ[:$I $ ~PRRr}5k`iĂF''mA!<1qn;$u&6<%Bw1l q5^x⣗\Y.>FBֻsrs2Vw/n JFI1I(@@:O3[pKI,Y95Ԑ2s]}(@l*r#I#uЖ~W~'5r[ɰ1*򂊈gz̰ڤywX%eltQFQ.D05f})h .koY%.E]Ie.\ru*]RɬAmhЙ:Rr5~W$_**{n\|3]ܒxMsk'\> 8O}pmsk'\> 8O}qJr=`?:bKhn,ŀID)1ц(H!RD[ 3^MlcXĪJmD8 :C/Vw*hD0 7i탅((w5K=lTp+.F`]T"E0!hqz~*kk#c`vBF,OW #U; h4MN@_)?'IC4ilLppsI>M=4+B0(DadS"jvNI7o@D"0F#PB 4cS-o*kf+v}Lcec?Rta*B&Ur.M[‘koh&9hs>hQ2N"q?yJY u# 0XUX6> Nk`el쭂}O V>'[+`el쭂}O V>'[+`el쭂}O V>'QƩ&yj|o3H$CQKk :KC2j7u $,$y2rK\f+t$ 0LB0f$%uF-݈) n䫆S EKm(x0uؙefMj&XCcj&2s{TP>cl1swf$-+31jް#*yM~2L6G^: #REYܽg3#DC6uE]u,B`HPaCvB?i}^.hLʀd_@/5i ]bw8aw`)`4x}pj+egcri//m+Vqol^]ypZ&My9H+nM]T$|PruܦPsAim3TGQpT\6Kf-ڄ7F(6D1``9/5ۂ4bY.[YL2H]U2A yByH%"]D9w3C1(OS6iriI^ Yt1 |,x լors:*8?:%Pu*š࠾MY$FRWFEvrkQ+܅YP+Oes;YǙ M>]F4⠶KiL@|(NT( b!s6:Nj.J[GUP`qqq]Y냛4=@/WHG61kyp#r76$!bB0i*S V}9l4A&rгH2;7M@.I] cCGSqEzRG,*JIqp*t\2##8aBic)Hf1| ;ь%wU:/Cyj ,2@t$AW2}'B_M|(TF5q,m.0UZɭ`Ldp@U\xh _ZCZ]Q`g ,'Qgߨd*V"OwiO\q({Nn"ʒ)+͌ѓ\ bڷ^w ƆWXQ6#H#* Ngd5E4T#]Z[FTM8Tr:2PֺqFHM/"|jDmA F2q$AV)E CG5~HY@:ZfEƮƜH2 kkZsF:0" h42Gd]tg 1.Z3-YR r=c V-Z2 Qю+PU9("Yr1j#Bu(s(B#J O[nNU%Ś6 6y ʓ\<O2,ů0pchq2MFA(bT&iq"2FHBl'-D3*N(ͽ1d,77䰩&G'KFNy[P*0@{Frݟ@/V5t"Uu*QsT0p$jdoJ4LhѕO ;*",z$RF9 i6P{U2[0Jʙ$%xFUQ"Z[KT63Z %4nolf0S!`мzJ;TdaIuuG#|籴K3cKi^YZgHMGu[48%cG:Ԍh }VkfHA8IS,JĐ 1 띍rĶ\+stnҹW7J\+stnҹW7Jh "מ6=!UTo$ %AOxNW/& RD$XP̒F4)#uGq>[*HrFї9 ʯJ.rG t#%i"J*KI_V wM2щvwG@D)bWǂ5bN!J͠G+iR#ѷ_ ʅ5˪I4;8 rp)-0:gӳ$c52T$F5gN /Į5| lx~& |@-K?l tykgm'BUЊZYcf 1$r&$DR~5$O +TErC jHNxΘ dLH*#v঒c/%IiSSlsV.ii4O2_"3`(Q8'Vʸ8=X wVm$Xy@&#HgbG) 2NpT`" [7{y8k.2<38/`ι̇M46t!$=Hp'}SF[e{us8߷~4iãFT'w\lRsxsU&@FBʶ\qTjL/'$8@%.vV8͠s8mU\䗵 97Ӹҍ*- xr<QS:W2Z֖Vq$ O r~ ߪ/n4va,:IBF8g5ŜF03!IsPGVOo5BHˬ2yA* 7-[tn|]1+i昩RTQsFp k"`s%3+SBeQK<)z &5E/ 5K`"J.sBQ!x#%f~!5ang $$2cd2UmV$yGZ']hXI-? TG'_Wvpмb ajce;OY*$3mUIsJΗ.2FƒkB0Ch#( T6:@/V+.BFI4qJBF+W XQ%*di"g:8F*$E8Ql<}$#s%"F.#2U8AUiHwrGaD.ApI]f-4ԑFf{}ZLe`XA-rü dBsH8ayf 9r!Fy 1l#p%>b"f((5pGAt-\LcK&ZlR7 1@*PJpCy9N븘IfLy MD G&7rCrAVAldž~PAo (6p*[MLIR)Cf$੦-4SFĂ@ 469aXlِrˆ՚aYWPᇌ6֪tz/Wy"y\9ҀĜ5M f;e;+}-D2󦔐 Ypn1"1M⡆LdStp&h/kZqB&JLBh& ԓQsKm\& ĄG1 ) ,x5K ]$D\Qc64F |EK3\\FiU[; 4J/k5V:rXKVm?C+omQ$%62 H;a+VuZmiUVuZmiUVuZmiUVuZmiUVuR9#U?!ABI [ h8sSI 5ʳ럝~G:InR3 W:LF%ڞ ym2 n ZKy$a(@U#H. ncE!1BDž]rX MF@]M(Bh.R(33R!5BO ƒElȧ7hM Rʫ%xNiA$2.IcIlw *bLre JBGTȸG+llK vhոr|ҽ?ن~#:bD2Өdta" *оs:|Ǹ} or;?sp9%zA:H"#yT& 'd~Th_g4YdDsxqԳvD8d c8],AHh°*ijNBvs\j+F_NHNFNM.QbŹ[{bOPbptmF?:{,EQ#؂ymsHY}FyJ0~dfBpI (BcAs?__s;2(de~NTZ (D76,b SI1nuž' -$72+I!fGl Vi~N)bȺ U͓ʂnN)E!jcSO 4}R|?Ʒ®UmkM Vay9 )s귩m۝!n׎$aƔiQlĬ滑^ZͪY2Uw-C.pʂ3; %Eif.&u*;`&0dd8 n tbpՂ4lQԆ >wLlw`1n~s\U 71*JQcF@,*P hM00(\O!ARRAGrW1n~sMhX{}#3z_pÆ2pd\C*rP{LOC;C^tNwgl,Fԉq9!HwvbXs)s9 )e. &GQ)FUFdȹ:T8=E~Y8#\"If4l:ɩyZ[XcvgP|j4X aer='繺wqV3W)t-,t4zxxjBvFS;~XHE'{'142m/!kxZ_'x_6w!đN?#伔B߆~CsE_ 2SO[(뉒S>ճL ڶqkXOaQ2+H$*2uW 2{ 8t>_B|Bˣh B%[E^S?`Tv|bhdmDcZEy2@G $:@gTqG,-#O׊{hR÷Hq+#^SOq,O"A[(-Ԝk"> _g$? 4-gDu@B3¢dVHTd#}uȮd$pP$^èԶ񼫎r AML AbWIt ^*)Լ$#!|vB2dyJ'ꭊi\q3FO4-I⇬T# ,o؟Ui3j'5͑'e$jS[Fdb2d"%d%"-RD8:p&B:`SLLGv=d]'Bb8<&&[DZ\SKXzhH;828sK$Vrjr %!9. Y}dHR\,QˤN1g GGE+S ` V̂]yG|8Һ8+0r]ZveI K#?GW\42|T VwI;<7/(#HgcuyElN-ɫ.`Sl&TYR;=btPs2/NeWY&'=(~rWpΒ YCuLiK| 3q( MHfF\q]Y,m؅kv\K0[i'{j9ݛvK7ihz?WQe!#"^iX hs/%efCg+`d Ici`򑨖=x?:@;1![ Q0Vpn#ysN nߔW,_F 3Qe'$'؋QmeXvmڲ /\ݦOa=྅]+[`u+8sNqĸm Ghhn@\ۋi6\Ǖ#FCGĩ4#G)\z#j05 =#iwP|> R<2SrnJ1|3GLN'+"@x05ŷuK彑?t~͡)C.r&.c;= 4hDQJ V4mUM֝k#A[D'WjB"Hyx>leI8$dVy ŒF3[-YÐC@5ĭ ;WY]2qӓSK|aK4G948bF3[-YÐC@4HK攇~\FLDcY,m DC6/&Mb0DK[GG>bd_xOu+_1n)$t޹gt 6}:k X.TE00Okq#u1:H#gLFu.ŭ`KA ^(nQ"(ђXhv@`0Iެۂ3ƌTm;x$#DOxxf[s3\en=`WȹKh/ff/il4; gPW##HP[2[z!Cr@d ѽ&FQ[':WXuFQ̀l@^'v$qNSC)K:S1$i\1w%I&[q^aIdq剹;dq9(dYrwX5U)*imbo#ȚG9 #2EP;PEO;Na@P]_CΙd\!Ktolv1km7T4@ Z)fW!əh* ;,Ӂ)!4ѕlj^Sgh .$_υ˟hKCz]'ɚqG&?: 6`U5m "#\DdPԶ֐!dS c`_IlYBFv cI`XOa^"G> REVV]U` hյ-%9DH$ X qX6ldBLdӬB̤M_g$? 5cYV5};BKSO[(뉒S>1[47"H8"+hΎ4VFm" /5Fg)&-_'d:?Cyj%!cĄb 4qCyvp-iqW)O\TɄC^¦$tnV TI=!gyhH4 +i QB(Coi/U5AE-8 H4"P:A)DTvͫ\ ־΄?]CH^H/u_n?:s9ϖ4ՆGP8T%:+ 5w,'Ř3iCuGl ~C59|ЭL4 Q\M rG9QO4Lc BG9sy"|f0evwnILjقs [JNKCl'rʽeT.MkmY+zZ4KuzYN#Jz]۬k)d7~u}*o"s.b:kg&{{f>#9wJty8y>X3fځc&& !0#Lάlj`ʙ1́*F^9LC} GD-X0TdPrEsc,΁MC%2N F 0 |MPۘ9VbDWqr |j V# Rbnuu]1NB&IL"1p|. wDiWQ$z(H,I=+ ,:?KDL+{m97"c59%5 VH=>"|@[:W aa"LG3ʔ!N)3p'揫N(ɠϧv?EjMj򸐄:HE[jB,Q#F7. ˩C$:pGV!y\ۿFtפppf G!%OI>t8k\N}=7~u})e܀$sFm. 7EZMR r=c VL6ɽbe$RpNpc&vbK 9*F1 N\2&te(\>ww)HE ځMo,b]gM}zHW {VW /yTv(c1l TJWb 1 .3$RK`8ԺA4ilg2?8ZsVPq"dEkx$ VC"l+jȫyc+ow mVehW$y1 :`>Ux5 :W[@ϪYHmrjnSH8q7.zZ7ab 2G((üa SyeW))f0\~Eԁ1%YWD3I]Ta9Y$˶t.Yfpj;=g' ٿj8},x*lX#*ÔRqdJGo7VhPb&.HJJ1*Ô'> *⌌RQʎ#u<@t^Gkٙ Z_4ӹΐYpeXPgNwT"r|$ kIې犚TߙT04U18#J#քivm &`~_B6zm4RsX|1FeL͌`J-3i2iaFiDcI:{1"KʒHoг,zdY|ؔHb˸=h߀.r3ƦHΜ$N4B! *^dBeTWyX.%>.P&4ˎ P ol9 )sk΢1,j K$<0Y B+ :S>P;cR ' j4Dё-C`!G|lŤh`̒\ɨm 1D#&6 ĉ듹)iDFf\c*璮@!_qHe6 jGwF߇Qk-Ԝ!ϛ 8,LHߍ` xeFnek廿#Z>j}s4:/P ~~Lc"`3b/_B*$mX{dS)FK][\iO^82T$F5gNchV};2F8VϽHo+Ď0\rdPibpbdz":L"IP5! L::Ien^ZfhO80YZc "I"U*yN6ۘ|V7Imqk$pfgz-] Dnȁ085sx׳30[&ruVAӔ"gEtlA[I fk`8)ﳦ'JZatneK11"DrMf\0OMt_9_@͸)\~#nai:8Z{yg0O2":79 T@jE-dAA10ps0:b>h8<'dLC(KZ L?),1"T2H1w:OAӼE jFj90J +մ`r}Zew-G9ӔT\ۉ<.C95g}m8qHWQtΐԺ ?etOӨm. 3ǹ}3V%Q*0 *2Ǫu3ؒ92J"pgb+.T2`T] C-/~u};T!U_cZto:Sx@/ZI!xKU2QA!(А^GPH_9 (8^Z-grB0O.QC)$(ظSPrfkDb4MqXV$0E,SK:7i$*!(hN 7.t()k;|wTb(' $F\dx;tKAbGl. |uT@e : ^IDۧx/% L:-;οo<3>y9:VsKsw>F|ke;fNLq͒7+)yx#}m&0ѫd*0(%[0 ch X yW'0svz+L4"Xgspu#xhy5۝4Hы,QSB H -<-h,'YMos6SdFqBCLQ 1V X"V2U *f*DPP%²a٭gFe4, "VHomQJx:WXcO8QŨ67ʰ-U3a$r_)pG%y[15ŜF03@.QKpX*CFH`*Kt^#}9??C[g&?: 9`)cY*,Mo # Yhw;uw>_CiY" <|(9S2jֲk=`0$|%\("Fs 7tx2$(b / ,OF D⍎ :cХIwTëyh]Ql VyZ[y^є"w`2HY3/hPQo^K tIcWlgInGI\˯^#:Fj墖lNY Mc#G-X򙰸d.1@PJxj "C>LbI:UOZRR(A1gCnD6Q)@@!+NrL,{vJo KdE-ݺQlcb"8 (Nbiśk1,p o=e ՃL2Lr KANQ!T `l< ţgApMi4iSH e]F(߈dUǔ2yb ;0,]C]rHeJ}྅,i$mBP˨2Im)SctЁK9"4cb("$IJ6TPdT1q&x $e1v'MMDT%)s."TSg SO+g(~nRK5L*+9̨M_Gmq $E )#ajjUswEd%p$2ظ%xĄ5iki->d .9³Ք6+<3ythThP(w 7j8mQ]Q{҃©$p`P˼QEj'\<hZB<1R{* YjXGhՔتv ߼Y[=7W, #$#c9э4 G1H\“>0X0ND`BכI$9]VJ@ `N$F5"&A(?$1)IK8 'y&kȕap6yS#&̡:̎z'x/\;a?t~.gi~C(ۂN_EEq41InE=Jau} :շ(;è 9$u4exjkt۽ݸVE$#ƤˬF0Os=yF)ߤ2¬z!w>_BGXDU4.fYf΢&$D'Y9C 8TS$77B$ Zn,%󒒣ώhd'9buuUܖ m.PIA8ݣ *inf<m5 yFtKYVHD"J,9L$rrc,iʼnx .8n 2*imd>#iQd`A>|s |\RM,r89/DL$ߝ&pNvԍM4<Ȭ;]To&$I^i!s! yiyV`G iuk[ R7E̹`t`魜iIV2,SH 5xN`5dս*9#ySp;T[S:ȭuĒxjroER)äjrJj[y7 C3iqP$FXMR>I&A,fB蒉9*2S;9\8 bet])cK1=dt^C W4 ו z_TI (6l\!`hц H,*[klL\2P MqjMYEDGr{e *l(h +A*k`1Ќӯ$b6f"UrPX^QZf h[z)]Ǖu ^L(PFɃ%pGl!˱%5{b;T(a**?ֳODKʲ QT2A4Ghhn@\ۋh2WĄ!Ӏ2+\\݌D2+Q|4s1N+W/ #ЊxP+hݼh2C!$ [ڤxpQ]HlC"$R+jy7QeΜMwn9<,1>N a#5$I9'xp,t~-vsȊ`4I.?)#JJ t?6^B^?:v,<@lp+M6{mM6{mM6{mM6bXjp|ШL! yB46\ [,H5 )W#$cv|dhZkf jc3iժWAL4qHѿ9w@"$Jy x)%`ˀ@ Woe#TKy|G XX dB9 Ɏ@It-\LcK&-3k܅;3 #WUltUѡP7x@ i-XֿXo-2m+*8i9R<}^.#h?t_Uԯ H$ \rqS[T;%<UeupX{i @# oaW#`~ V̑<Yd ! 5-ȍn#\9 {Uմ K6Р4g26Iޥ?]mSοoB8Ub$:79*nӒ7BqgK;óֈ>S*DXv9%ѡ <2i0i]g5^[ Rlem5k; WS6<ǡ#_-QKmdVm'xuBDa| xZp۪"IqqlȧT-S6'Nd'Jh^Bl'DЮ[VLp<"c":LdUԑ\^-@, fe&_H+OxngII럝~r}س:vM0 H$M4>35$qh* bV'{idu$ uE# It UAq=lֺ |2oEܭBIeFMesg8!)#7jkٙgyƭ/rxGMZoi^G|1fm !kO1cɆ=tZPM0nփ\o2sRO i( OXj* rWS$$ٶ;&JS4lf3p^^9jX8[BlcQ'\*jЊKHA4Fg :Gz]萵yQ=ֿzO\/VUb dѫrU…j!$5+Y6}g9^ZKL]H8 KXsMDWcSmݕ i I 33lз ԣ"ԈaBD5xUń_B\d "T=g滑x"'I:O'~uޯ/rɠe'},XEp wN(Fȑ.QTwX- IyVlmd$dt~A-?}87G럝~淫Q>?B{$6/6 \իƒ%۸M!ybnLA)e2!72oCpAw=6*LW<KAFq$ۑnx" %ơ0{XG,SQ 3.$菿H:*k׸Yĥ&'H$\D=Ȋ0:# 1 -t~>d!AF#Cr){oSx ;+u|՞~xNz_`?:cjE*T!j?( OK6sF`Q:Amw-&H$pVN'GFEkC\RYROvf_ ?6.!Ѻ7H5x/doOG럝~6NA@ƣSy2$R pkI:yղ:'POn0 4yֽDL/#^2N+2 $}=7mοoN k g9PGZpb_#7t@T&2tH۩(+DNDS!n=r?:r0yxmVJo ~MF@nϕ| G&_$~nƗ!$VŞ1ɏx!ې>+n:+u8U@;llll:h`o͟o>!?pV,]/𯒢@-Me"1:E-w>'T0ie#s#R0GQ,gAx-s>խκ0NT2G3v۫ .V6QgI]5clq*[a ,PmhmfL ~l1HH5:'iד̺ED|t^;k.P_Q펟4z( 6KGt^W"a:>f1̨F14^u*,؍ \4 1W tKEjI)`g|:=rZܛn툖2L Jm$yǷh.xNBwhRYplAku=7Ϲ8*+t^z1mq'Qwdqm2~u Tgo)?kv>f wRƺyubܟ>mŬ6:/\s{p_d)*">t/24Iyfo,K9"$QGT=7ז?)MbR=OE~o}o521G]4$wIE,k#g#=בz\sy6[H+J%~ _W+J%~ _T,d 8cAi|¤ -Ȼjf2L~|>zB~Ot[|h:\s@wSYX 'nNq ܠ'Q=wɍ,dq"ޑy'Ù%40c#+qn)>W#%ԏ|HVBGC|OʂD7 #B$/ù n1<۝Fǜiƽ:r-VkR ڼ>i7ոyP[`m2ӫr78|_3L*[DJKXC-&@Ɔ"cJUhq8 :qi~(n{o7y]{'W.fq~ P)˴>|Ig=t^;Lq>ۧ[tknmm}O>ڂkvpsL.(Tfbl>ۧ[tknmG"K{}ocTq,z;V^y1jx<~j>!\D1x- 2z9 2I'e# 8W.5.8doc^:u;{}oyX(x\ Wl$g`,K@Ğ;)}H3at5C_: ausEF9 (QS"!ѵ,3Z kgQ4r%Yo*6Vຓ#4!]oͲ6Pq\ˢ'OTm4ܡ;٫HVɤLdM"xb!2ѫ'FxfmL4(3IHH`i :@>@gե{GFD#] @ |M] .I&?Nȃ&̘mZC|O IhH$LBkzsZqÜgZΥLz73C,M.K7W9D.a$d4ET]!$ 9:z>)(Ն7r> bڻlYf$f.&  N7XZyBUʂWl.axե{3AKf<s\s5 *FI!ZEϽ+`0"UDQ#P ø0BW:V7$nvokvok;hکMXP~w5;s\s5;s\7\cy6h +w W;s\s5;sF"&/$W;s\s5;s\$DtbFB7v=sωVFƖn+oVz/T2 m಩RE\۴\gO-d?Vq=*luwd0Qiy4)*w1 k%}l$U;XɧN *BqunɮWtHkہ*|B4t.a1+Q#D.#$@XeN5e#nw"48 eTGyѻo].&)|2\Juuy5۝4G4{YH*:9qitCjD$L^%($PJLWHgpd5\hAhOCI)`3dxЃHIVomp g )Ѣk'R6+9~`&Uy9vN&^TL,3:z4V m˛|_$Qfĭ#'׊Üo?4I0?'ӍAp-|J n|O 8&jˌ iTjƜhDm . qf$WPF N`52F!1#x 8 2!"HP8` }5HCv)Y IBGwQ=t2|xB  Vl.5VJr "o3_Fcu}cVW9VZjVZjV +PBu.rKo ZDcsøc̎ |+PB +PB )N$ )NpzE6Hg!;i$Vg Q-0ug8Jn2aq;w4(Dȉ &,aѫFxf:yK#DG]FƘ9Sz{}o)K k*&,N q# ƚ! b(aR 8i~(M9ȶ22͹l$ |}:_,3c%y?),R+oxOt^?(rj[Y؇UdIA F>h x{y 6ŀp4+e%Bb 䱊7-,*&$IyH1m桵x'I@Ѹq\ c6B4TqRB$>2¯1.-&RI +QM6SZ9M1DmUug,"żj?ai~(ŎG4n3VW7jQ39XmmuDnT6ҬbRVɵcNn~j,>ʴAx#eOJ"Ĩd8f Yv%*x DG@}sωLダEw鲺cɫ݇!UUFI$28ZX_x63^:s=ǫKG&dee<* p~KykziInR#q3^]xד_ؕ_"4yb%+x$fRO:ɓy*.|'hH)s}C|RI"or[:kxkeƥp]~r)/GnWVZ޴O5kl4 }t˱1>^2*%~2@ƠGE)f3)TFؘtvP~Ri*h|jkq/cXi\'"OxOHb_4F?bB6_ۃqqC=r/C>fV#CPyg|o5:|N[W$:W$AX"$_U[g{|#m؏Qݛ2`OD(:# L_tk:S)r63:ο9 :VeӲUp](#` ?X[j7Z~]-"lbI?wdCn`֑075sMͬQUM S<1Π6`xԐ# 1$c@0gե{~k7X>'t"OJjL%>}#I! WR$-Gv߻Iavj5O`Ij;xZa$T౯@FF*/sRD9V+hȅ,D]Dd C?NqC~o~+RKo(#x0zUnPx4]:!#5cU̶CHۘ rmڳ~CƯOޑ>DE?ZVRlOwnft;+0>|O em%TD0I$_zƳF$mYM*R3(X GAo($T[6 / lS;%cFK.l U-VHi5(Bi7ُܾ٘+a p$#q Ȧ&Qddݽ02/,on"a?~X)  N\g $`>"jC3i:y3WvI^3z 72J x }o-էo. ͊<$Uޯl0~M xŪ5A)6k涿Nr k@R1$|xP7o _DIOH4;C qFbbqMx|)x28=׊hƸϴ|0G 7he?N2 Gt^?*+բT`9߾;bA+_#55;2fIqĐ`fPqinY.2 0{]u3^sR3`I vmI2"j)c_6&̀lvw$'!a8_%o'- Vެ82*èϼ}s+\>ϼy;3(\):%8"ϼ}s+\>ϼ}s*Yd(߄+l#ς jF 6+1}2i@UP8fgx͍`2ԕɀGirҷ2(!XOs g\V?ϝ?c5 2x)=gN#>y1pw<Dl8~II^ʰ7g݅itBF_ep8q+_=dL Xձ"L 9|P:V$Ob/YsrGi@E5tq?W̸ԬTyI @'jv2MJ0pO)K-ğ)Q ʐ?qKXX{>7#$Q~x'g*OԇGr뒬82*GQ&'Ay>iUx)8[3[\~\Y%ZT2(|N>CP^nHJ0(2EGfXd-$@@?t^l$EGu&ʓ rwDM0*#T6i*XBTh"ϱtHLoڧx9xX27qǺuΖO#*CQy>i∦֜VABGNtǥ5ʉe4H<ۭl@H*|GaMׂM <1" ~`::#;3 |K=q"m..aTZ!椎9U)j+kܐX?*VwҸ_$QS"9FgwB(T-2rHa0>yοi[ıj+{he {tp~eJhИVXYs² -m{cU-I(o[&P4W5'j(V/mה"R%~ɐ oOP[ߧHd>^r}'N} '%[O4EKfS9.쯵lrvt>=؝sH5 9bCƍf"4c{(̓I\o.l|^68QVOeo*&j5P#TVdpi5!,’Fi" &#o8?27g.Zx;EO3񤋨wʺq7X8sSq~EΖOGQ! CsO@|x)N8ʄfEX̆6| ҜX#t>0U\n789hdxѸuFLRcnR_*ҜVtZ&|O^g x|1{$>y%rff`~hXmb?>uwQZD b4PAxl~IK![D>sΗ!E^h'Sef7+ +O+c\Lw.`Wua<=b@~vuO{yQQ+;ѾKo!O J??va_6b5[IjTrl.ϛ35L<*S5XR/>67?kϱW쑉YL|v%Oi,+KW A?qVwVƉ?xRFp|G}o ˏ!^HI߫SpPm8(>:7({BԊTxGY'ps |@eswXԖj:#^&y]Yݎf;=|#[|J&R;0;?>mH<ΜenLrP~E OS+$;U(w@|x)N8ʄ5bBog5`v7x NUJ \t30NSTm!cߒq~UAy\iOcƢ #}s Uk\i- \zحĭ\b^ɳ;5M~3rm1Y1ayʕzviK|/>/zy%~,'Ny$q92ӐYo뮨\}GFAէO;yrz{Bч 3IJ`jXcL\fylaS\te'73\ `Q`|SA If{wG4CGBp|ws’85cw=A%rW*>V/o'V_㩭XǞ[c* U8wM=LCn>./e-ɳPĴOU_ $<N/y;cQq߻o+$$y'y/–W:R5CoE~ GW- ו?KHt9GNgˉ%6# G5^JʾT'Xa>8aAS%ϙ.Tz7dϐQnjRq7Z9 жq7Qpg&~pdG ۷3|:/\g`Q5Z܏Zq\|jIOWy˚2O'8oUi.gope"ˏ "57Ϩ('q[?5(D8Dm笞u@~b;g-G+MMǦǺ T.B`.SAa#ٹ>60)[$P 9\pcBP&>d!5lOrl'rwMѴcjE|<1g%e_Fֲ1&z?ofU6@{̿'qS:FU$nC4FABn1%{#xze;ZBk{"xH&E(XdJ3JpZ+rze9d#F8G0gsKVK3wŎܯžy_91Pu(.qʘdƴ9VVys<|ߨ5ac=Ip)?\Q{:8ne@|e9]q Jg1S6iwxhxT"!G+\tQ8qp#tclk0~ ?)`[ yPMB.u9uSRK#7[OD l72FX]Z-X475<\ ¢^.5H .g:>`N|~"2(qݨɌ*~)4'nrlFFB\7;Dr?" IG +L>99GUrrRz)\" )+C*pͷNQ0v Ci|>2xwg Ȃ#3'`*I>_'P9~WA!j<-OuhB4)(B>6d4u ã!agXʉNWD mE0>Xx%U9YGpy:;ov9Zbt21ۃ@$Nh Q7q%P#GQ2k%?r}c5by{KQtat=HI:Q2c-ݸ-zi>azJ*dZ=} F,h>f.|^yb8'WSw}&%Q1J(|o>y=m8,CȀvc8li ߒ)UQU eq"9#sHpmĎSJQDQqkv{-'?1*CM3Hʌ=u~7p/h?a?{w'g5 zE1^5q1!sN(h 'FjǥCG3\!. }Rj#㉏ȾT$x&[|;' Es&L ^T8a0dqc݆%>Ra39ʬq_7Z \BD?QJIEG[UA-7𯖮`F@FCݒ2,N^׬N,{;OC+ERj3qLy]6"wdZ»qsmLr19gsNX8k:{g< f;4DJ#OɈnۙwPcLryAw`d:|SHc< |xR`Ԡȣ|,|iSVlqky{(ocoPK1I8'sP{ pgQw/4s?X6s&oYp&(;ogڞ? ~*Uǝ:/\`x5Ĝ"zV܎8a'M#ґgbrpXPWV\@eM"n Tuu"v~L`m]5I"0@?(QLMo4?z :Ww}@nO'K|8GS0#xl?ߞ#;ՇX;CԣuO3CyId+y$}ȩgqC|L2as;;omҹW8J V5Ę'g$d|bP:ȱI2vW{39 3N(%sp^rGg#C IH9'~{Bd7 \+%ssu <'?/ _!YJw]Zl!db>eH^1nW8J Fu:Ź2(]` \(\%8+!*qAN ^ʐ ,I,@\+%<-G*7[U߁:7u7q8FI0Xq=}|W8J \(Wdg=IБ ~p= t6*@ sQ\M]zIW8J \)$ AʲE9Mi ǭ6%H%5i;A뤕cyxqpW8JI-a{?*傹?l?{}逢a) rs[E唸|WgIVqWAFEFYJeE7H=ci:u;^ǬkMtNwfE.FJrNAAcbҳ_25d;>5@z|`! K"L&0>AM"dUʄF D⍎ :if.&eF{N0c;LUīg pE27d EwJ=9 2I'!N R=n=sm1Ɗ0 ]K@ HFK3hr}::R1I22CQ!/gW{s2:s22 >bAҏ:k#Z {\Y9TcZR+ Au <{$0\#Rt`rw_&w r1} iI(e)9m=xaʺy9-:9k?*9{M[U؅C%7Э,u@/ ~vOGHŤcLݟo|~1XV&-ߠ=ѺA'e:p0-Ԏ-#uAw,y3FCj/IB?7qV؅OF >sԫi2kbO~@ PI$y)/&WamvŽ*k$HgwM"tezx:pDSҬ4@p{0#f5!= ark0rpmu-JLtLEO iN؋o,IcTFAߎlEo/ImMxӤ(/ 8GWų&hɑϣGf4C&{VW$mJFCx̼_ JfyzIblۂլ9'Nb?2{mpՀV }Ƿj:G&5i" >#+q$jMWhe5oDd?<Dz[5oDJg,cQ5=Lj $ʹs2PD.# ]xyu-ݠG/4)#DRI"Ĉ"jrLj $ʹs20zb-@'8k߆L`$( QSB4gP$RD`˩#21;Ul?guDq[%1ãbÎjKh8BZNFd0 27R[FXc 3*;h$d9  iMr7cOk Hǧ`I5qʙr 0!ƪ6|jmyW0J<Y:SUL5 PN7e XO' ljHv[gPV<WX\XyHDz0\cq4m&5S[FgpĄj9dcap"+T UCqE a֪9#\tnF5-2 !VC G6PȡR38 8l4lR(Fqljbέ:s"(ô 1nxօ $GATJ|aUUr3|[N{n#ލ<u"ɂx>;qȨ" GQ\ [FXckVAD Aob@zH{xf`!MƉ 4"P:A)DS[d3.5G$` q8 b$El3@`nR[Bw*춎,W @&3R*# PH5,Jn$b"fSJAm b(q6_qyAFj(4B"53#!#'A5r>  5F:s )WY T=ϖUJ ~q$J;T)b@h )*%)KtR`% TqfI5 .q]Ϸ RQeshAwpshʊF#ŕǎ9TJ\?eshͣ*4=x\?4%#.~5o~W6mQE~e/'$@׃\?eshͣ+GW60CKshͻc6m\?eshͣ+GW6줁ݰH=Dͣ+GW6m\?eM;\~ͣ+GW6쨡D8=YP;:y shͣ+GR@@:նaи ]$ĨW6m\?eshͣ+GW6m\?eshͣ+GW6쨡DbIqJEw,x )Qvܶӱ<"sO/†hθ_*DgRx~({ 9@mSýsΗ{ 7cRƼSe<ɝ#;10=?n^o|jь~l?dtFϷsZc$Αн24 p5#sҭp!pbLˑF\.*`! <[;#m7^vk(C lĊ{7Fr$#?PHIw4BHE5Ja4+OPԸ[Ka㹏tLD'Pm{ʀ c;džE/d{]?&f w_xMi7͹d'q_@7EsO"fAE?NRpE.Jx7U,SXgVCyIv\щ\f4[JRCOg5}efEս`PŸ˯j_mIso1v2qN ^CCƧ ;7Do7ۏ==)ތ8ެ:~zK!yr=u8/]71&/鼆"{>c}rNE^dJ)Grd8~Vo ]N ]~/1VVR;eI6'r800#hF#z*ƭ[D>I<>k*[^VJBXvd윟63\wi&OatO\ۮQ6gjF Gq4K'VKeӲT}{tw*[W7 r}7L`j?xˣ VUOa oVDogˆ#'/sh9Y" |$:έZRo ΋:_)zo4xnX2toyx!Fʣ>c}z^^SptF2+đ#M}|Bw|" ?9!"L1)w9 ZB$=g5!o.̸lNz}OoOL:ua#O8ϘM̏;{*_fOa؈$gؔE:a/6O*(?ػ躀ҤITh|WA4VwWEVJrԑGD[ʴ6 W<յI?k饳QiQVRod W4RXrJC~$eyKu2=3_Z$BHX9a#.s74(p 3d` sJS9ؒ{>;9(Ğp oVDo=='aXì㻒0](<ِG\| y5Xa+$M7;͢YV9u9t?P%9@AQdzLVjHDϚK(WiSB64iq\ Y/Ԍ$eW'HmI>6XL!CTa8΋:_<7F/^õt߮#׳30Ϸ?(OV:c)M+%|#?\'Ek[Ien n[6&ֿW_bj>(ǥu A*g7=H%A9PVB;8EЄ t#szKZM-cҟ(Y5_O(BDeK0ݟo>7sS^xY$iO3t~EORN4VNx8*dUV|SiK#jq8})CP ?Iuu*VPi]%XqGS:$ p rbx$ lIUSz:irѕK 2}uQK*C\F7n#jCOF7pYNc}zn^T)麶Vv>2e1XA.EqqS"1 x;ؗ&F:R4l@i#P{.!a$M0xNAuEp Hr{BN52M;wTO_{@Tt?='a@IFN>xdqц aX$o=* ہ\uOe}#Qdܱ;c?BD !9A3j6 X#^]x<Ɣ; pdCFTߋAd`Gst5.$5z;9[t( MJ&?[Gkhm31 A5?[Gkhm,hm$O=FM~)so;o>{{?tFpb}'8ns(阑oi pJ!ÉxGQqD>H(Y=d'NF$z F勁UqFS;G"WSk|v+8/VS鶼=ge/]L4o'qF8t$dz/hNt=ʞVLkJSFAǮt^Y yCt6V}=6gwCvewEEm)ijQĪXuι][a(tl*Fm,7BFd*jdV#sgSAV+CS-uYV# V(#wlQ eh0<TUV+Ce20<5:´?ZRO C?BXSqŽZV+Cea-Ϻ/jl Tn$rO h?ZQF9F#Sep`czw>ljn`gӇ<`w^BǦCٞMԒ}8zWy P :8 >z!q)zo=e*So-ijȘ`]i/eʶΗJ }Y7V)*1DYKW_3]:\-O-Mx@?+ql.PsiT :럳lA>6m?)l]q O&WVHsr"D4.T,}S27#&NwW[G}ȉf|ި=VgKU@!K别˦K|Su(Ebkfܼu~QLu8r%XˇׄpsW+#Is0\0FFPȷ #vQGM$iiFv%/ (agvI H!g$k-%Xnd.@|W*<ۉehfp_6s1"C?N$C36:%x!THWK}Y$t)g{l̜z r c2DHAQ兽Ο7&;DsЋ+P 4NZfcAiĆHI0VCBI&Ma)MQ29%_#Yܷk/ wTKk_mICv+Qβ%>C!xf&'ijWY=gU\)42,4d4uOg=j;\sk;=9 O Tܟy3= pJ8Ia׎a B9uղ4)4rŴPʾA^&[ Ҧ0C5n&tTߊXi\'y58P$AC1'*heFj"ehZ\ߤфOF˚e nBM-Y^@[0S{bjˀrKn%$HNxШ!7hϲ@Y)\H-mYv!YAwBz&6h.M6sYӳf!ڪhqΡ 'sۘ.@D1J 2o;PU:[uwX _0 EI\2< BMaw=:H s8 Oay?P$Y ҼgMijՍ 5TI Ut Ku:ihszAAyw%HD3et5%_4)ncS ąs(UxBECay;d&xu$&`)@4֗<!؇ %Xb{c!VI1Iv/SVMEW1IU q84ʦ<,u2rwi)YxdL0D jF[xnF HNtμ&B'n T0%i ON#X[̩F6tk};o=e*@ëFp§]T](OR8),N-ۈ#;SnŲl Z;P۴@[E.y\HB8"Wb p3 #ψI#cQIR@*G723Ȥ! ~/Q ʓb4 9mTW-D|XeeUۑhUEN@6CTbC($BqZ~IV#|F8[RX(qLE4(&8QeΜPN L2W8=VTdʒ. :8 WI8a&uT6i* )da.p bqFt8-ǝM7UFnPFb!u 7aWIbF5 X@P5s6NwR5`w5yV9bף7 tBca"8žo*Ve 'u[@g5hbAWHPXE n˭&.8#&B˷~鯯Ijmm]*q42~}lW$Fܶ#+x̒cQ$~%7Oqt~C"DIJB΢LE#Yj&CFr>mM#I 6nlЂ'{ JG9SHM[>x0AT֢Q' HT Qa{bLQ6N:NH(QEhI 1FcQʜts1lBtK0ǡ^}``Xl^:s5eheQuBuRw;Lj][,:qeW֌A0iNB&djhbᰥiz$UMC &S<@8C XjgBTHnR^I#NK*X/+wΚHG6&t0ԵnJ1|3GD8ܸ<31 wn$I!Q\D+gI$w c crF*g;!",C9YJ$'91p鑜0V4 #LpR D|e4@,Xd}j_|<#* HrcSzc)+)Ԭȭ6{mMJ!3p@'˽aEPK 8EiUVouZmiUVouZmiUVouZmJWQ + <p 8mM6{m] #T'46 G Iǔ֛ouZmiUVouZmiUT2rB'-b(?UӨƥÆ"{mM6{mM6ـI`"D6,\8F5VouZmiUVouZmKCcVjqx8mM6{mM6 Dze ,FVouZmiUVouZm9'q## 6{mM6{mmB #T Qq5VouZmiUVouNru39=VyP|ݟҟZg=sΌp5VouZmiUT065`FOCn{C`TpdyMiUVouR%]^P ҋsi+?k09QM9gw:Ш&6<%Bw1l e3.rXyn m4CM5T.$Imyeu^A #cp yЧ9rEVa|vü܊KcD#P=jwU+w,д/ clɢ$ Gq؉!}5/+Kka lFnS+FT)95,\D^Y`o&ZC;:q \lH8KWLud؀*`,Gȭ6{m]P+h8={&PrmZmiUVouZmiUVouXCT`NYNe>0FEiUVouZmiU6fK&N7}ǷumRef>Ş)e̿ce|CNY[ͩ; pTdM#p?F%P{\s½~aѺF:x(z$MEM*xT$upEF3 M%jLPՆ;-Y[W9{xgEhMuhNwJDθi&i +8i-W`zά1QƼDkeE  @DBgzKx4bI%TsQ@IbY&\ʲ'+1#Y䗋LI{}'2o$+<f pڢǤ~hLW '60d>zyBniB2XQ@:;~|A= XI4h8Q2d :$e{8`eh^XDB:*'EiB'Y= hͬЂYSMDYlM:GErj[\tIy,NMD@$ 8 J6!1/&u Oogr$;2*(8Vv=FP"V*aL6ɨk0L+j3;.w H4A&\Ҳ}ǷxU*kqnLRmOCID[hFqN,NY=gUFI>AN0YψKsxWg(Hw6>.}Ф&#eeAsIVՐ:&9&Tt`qH#eq%@쓍XF{Da :/o2h4~]FCx{~Ĉ2|ML@v7ƷTD\;=F>1[y#/uxWVsHNGX&_8H:eX+.>Q\=n>sۏ\=;^>!vsۏ\=n>sۏFҌP08aĞQ̭sn2Ƿ{YH@8=\͓~eMrtOxA12Er†hmZ1IKtTl}g6(s(n@zE/]63nuNL38{}oQF㓃R_:˱CHȞU~"$?ސ_݂XǛ\vPXۖ J0c'~w7G2';??wxWӊ9?{lL_N1|p#X]yșYeJ28R:Hrcgр{81"T?%)UFpOo224X/g o4RJWbOUrj)/[>,[Z'<بb?Y|>XNpH03O:/\eG6v1Kt= `|9.0r|g$>CK=ϳ FUFI$a'&B:|+_{Wy,6H_83qP-[Gy3.yCSD&jj 41Y-Qؼ |uZF&j.F\/s=uQ<&21G>ST~_S''MFUTp΋<+/L^o-`=5 HܸpANvcv'19c~(߀]1,r@G 8,"Oja+ cN=9{ ~Ra~6梷w BaOgX_ <|lz\xo٫2Kx`:/\Ϳ'U˟ǏRx}~S3Hi~G<1~)߀|)GOFY"^DcV8GWy.QXRsV d Wp@LI<ŚVoj…ѝTCۅ>'tH~ O˼y"C=^Hg#ǑxWф20A4' 2m=iQ1ª$N0a__ǷF* 8m?[Gkhmm.~:?[Gkhmm?[Gkhmmgg uoZwm%'&q%rIZoַk[mkZoַk[mkZoַk[]UÕ'p \䚷G$TJsI׍3<?2Ws݃ #@8 mkZoַk[mkZoַk[m;3.H`zUG^z~ 5CHS$H4KcG{uGw~cRnn.IrR[hMo<146r%ᎣN"rk OȪmc&"D15͂5U,qA4W.\݃WqƮ$iF\GOO' 2pͿV[okUV[ڔi$ yV2jok6Fd5ͶFePElF$:΀{jbѱ.cy] Q-(|LR3ć:B|wW9#RvТjξT sG- \XfFT HBkDBInJIM)O 7DMAC!9PU1mR sVcLC} CSY!K;3\tLI !5m3Cj }FU}4W ⠉c]DƂFMr:`L.'ɧļ `Ѯc*f@0[UA[kxc#H I5gAXtrR @I|5$Hm!> K!)Gj$$$$W@g'vp$CޖP lC0qNdP`٩l6r; V V2|+SӍ_8r:j(#Dq$*ObN%\9 ŊDY:1P6b \9P86M$q@pqU:h8dp xZ@ # ߎ[okUV[okUV#bӻEN!j֫{Zj֫{ZK pcgzD U,W1KJ0 2 B#iZ'@Hs'R 4E@8lArs_xܥ"a*M+WG s)N$@$Dn:4Jud_5LrH i,#2](܃42g I˴,] q銸bL Ĉf\ى`q'Zj1ƠG\xI5F+Ccf[NucNs՜=3z&MHvUp2k Z!M &:\V*˲ [ h3b, ~)Ufi!m޲ fҵu$@C'MD9:Q$g*DX|ucq82s#dbMruw5a$'DHܒ{L&rS,c_ lg\dC#kL`#ZޠFCn0mAԛWm4.pC,W-!`Z.C)I= {[1ΓN!լKA 56\>ѣ D]$P2ژ3&;Oq|_FrTE7EB, t9iEé󊵼I={tȠ͡)C$ᨳXdΞ8%nN"-8 hk5#8x/nۜ)*TuU2GpA]bErRhdt8p<:/\& *$xVQxB{%1$|@|uO"ĥۂ EFLaAؐ38e꭛ @ ƶnd}\{*IriV 9Hd522 z'&.cINxa <'2dL$S^$x+` kvokvokvokvokvokvokvokvC ƿT=1ScFlyƍ[VϢ%tPzv ČQpR<"0厞;4b\K"\'(c ̫OmRfnZҐ͵'mqC b̀cZ7KR*J{eeh\N-\ܼ,̮g?"㘜Hb3z&ԑā y'y'y'y'y'y'y'y'y'y'y'y'y'y'y'y'y'y'y'y'2kT.^6=&y'y'y'y'y'y'y'y'y'y'y'y'y'y'y'y'y'^F%?\sPe k25Y"5qҝBXCG7ShMDsД#2D@EOrNPAMrj MgK43"MRJp ġ=9vg$H`8=\ܼ,̮g?"ۘPc,"5`Q=h4¥imbY"dڢ:M@av56b:hM 3uQtumᕆA$]Nf#y>b ٩uUD\* $R$QtG"s s3]`} i$Ycm' R!)fԷ(<4#UI% YФQC[p涫~PΒG1B29梔JоFJG` QjVrP:tsBxG4 N\=!pfV &1!4'&MӭԓJ ɩH G(\&߆]]t'#yaYb'V9NEA09%#\CO$zcM\D|xpE?,-J'$wnADd?8ou oTjx 2㉛P [xô9`2Xj841s1;:MsoƠX I4H(Uext^N H b@)21BIb2pTF30#TbRfuj8%$U@$NèԖXэN >Pv4S|I$Qw+BF# ۪דinfMKxF,Fjkx}SSthƤ?3gƝxiT#@#:i#U@FEZA3o&HT2~j6c[D 8d x՞-c x+fޘfHB!N+.&I.jshAw:rsch#|fyHJ 4Ek XD# vXZo& +&&x%VDDОl =MJÊUᅸVq#q 'P(FV?V IFaKo3Ap*r6\&8, jT%b'_ҝtK>V5 ֯m%~WLLm1op5mHn~^`j{'2n2-rO,IIqW+jiH=c]Xe0bt`HI&60z% 4̠hR1BfENU'G:^ : U8YZb]5WܚcKq1wxn N IöYj-(#_jQEyHWCȂ+w`;dxK4շV_[y~mշV_[y~mշSM# PZGSrDBbomcIx:۵g#[c B7c܇j]L[eTE/& S]uMe2TC!fRRRR꭭.>VT$UսԿԿԿԿ?ԿԿԿԿԿԿl I_v%u*r < PPF5e"ܮet5$K dSZ\%bo%hqOap )cs+7?r%'tZA7W1n~s\W1n~s\W1n~sR$+aQL++ A [İƺI IԹ*Vs\W3|IMs\W1'HzB5n~s\W1n~s\W1n~sOo$(beUP?\s{}W.rON<8H'ƷQq"4 )%N/4~ 91qtCBsW'p"F/x qZTh7Ҷ4^r5wk *~N$ؼ#k*-p~ q\HW"$pji Oݣ{V&)aܬjVcꖯ)\?Qu#Gz_Y{*<=Rj'p|R}@ @ےz|omQWZ5T/̭`Ñg5 jh< !GT@GR0cil?}+\RigW\Hd~[ /;ȃj }F_MyvqV %'W*2٢rT- [Cۆvah PD/P(&(,, ސ˩<:f>sIscC8GP+'ge(cnuNL3`r;LS9SQ!QIi3j"A3y ~u-H27ÀGD'n>r,ղrGyI.+9A1~x~u}*|(-|yR* <`<'@Kʃf>Qul$q\lͪc3`^rk"3'yE]%P{f%~GA0\jdvG嚠sɇi"!c1IOX2z_ դ-QX 3얯2>ewGrEha͑I/OgFԽTfrjؤ*éBbܥteL6(-IPBTvdljcWOPyn\x?'W/\_^8Is iyypU)awsaSfX>0x;2(:Xpeb¹6Om~zy(>0r|fU=2*!5y'?/Hh&B X" j3;hr[|*GpcUğRnJ0T`$g1KOhWP[љ"fU?k*[ܟ58cXP;V |ڈ{c?T&(jKkDe^wzaVF_I*K+b@"`:Įx5~jt !@;8=AT,pȳD#2Wgpx#w*JK|L27E"No!P4 I>8B^I|σu1\Emccc7ʎES[ J!꼄 c"xU]䟩RxKoSz_ȱ1<ڨx*,z(8! a;LH+%{ R<@Ţ5@ m\r-xLQUQw!Z[lH -m0%fA|,@ y楉,M Ms-h:8`?85w}<*2~EglO&&7R-uh`'6&y6Ql y,pdv) ZzH弽s(n{]Ǎa~lvXd2 Ӝ2mIwHH"Dzv!c'yGPǃJrAGdc%w+xێgChF )W2۱KWοon 2M7 A)|| *&>4:b[TogZ{fso`#fcϤ˰!"qcdڧa~nMj5{eO//䯍 Vrxg/DjeϐQHQ)OM"?k\m5VZT?R5R޿aQI}\K^8 E ܌WMrtrQ[W(\$նyV^/jFnjF8.o:s=;\[E,?ğ:5G 0#HOtY|Kpv|lWR3!۸C!3w]Cl,m`s)I'x ⇬qSPdŞ2ُ拁9 e8](2:_Bt x1bnD:OE럝~f$glkc[ƶ4b 3{y+c[ƶ4*w"0GXѮ_3\L?JZiTdBհ#5lkc[؉n c6O#giiNI w0X!#8'p lkc[,I44*QBvR[2INEZ`+³fJW:9:H7c4<0-}Qԝa3FMLL(ѽ{&IN8:و5Eޑuj4rhP&AN/f_(]eR mē}7Q*1kэR)@J:9LVRG43:xu 5mo`0@3$q,h[e4Q1hycbUKrU'MFpr8[o :rP>O3\𹩢T":EsY\F$X05]JZ Qa"v-dyEJD%`(ÜL ]ǧ LI6q[> E#k,\]LYQPiJ0hIH;pSh >@gK"!p)X1f;YF̛¸Im*o<1 Th$sqF ev-lF.PYâD%IzF(d!sFr{>$j&Ka^(/>u=s캆VV!.g!4J쩸ngtb 3E 1R\,QˤNaكQwݎ"ri.bR%g.14"ӣSN$۷9`#N~٨cI3.|"-W T qԤb,c%9Ƞ[ @dhyseĸy&:j[ؤHĮSX<WHPAhʨ!|Uж6NѺM$(0DxsJc㡞BWi @ps_=!Z%Ӝq$[ѕΜy"|f0evwnn&1 bRsS\3i^Gf8Dⶎ6cZtB3w˼ݳ*k(gfSKr&gchЂ*7N :S1+{p@LeV V$y`''ע;LOPA KF#R^ܢG* oc1W7f 7#fr2GP\Ml"Y6d6Pixus8\+H`2kSf27q4XRvsRM$١fmNs嫋|Ȳǩ}ۊL ;j.jinh;9t$:)MK 2#'!~?8PMnw>2LlĬdOP{v(׌(z w1$FKq{s;Ž^7Fh34;8iRwj{?:KJɤ]$b[5Mypd1Ԅ iiDH&-:$)wD.3@=8jN` Q'QDX,ӧYdYDڵvLVsRHҾK1،jy[:rqv2WR A&W$قD/lN\*+$'sT*qƐ. hK,i2!ʬȌP{QTd|BaUuSOa~3Fu*U4"8p>i⧭Hsq,!p1>ϼ}s+\>ϼ}s+\>ϼ}s+\>򤻝ч1K$-*H}s+\>,O$Oq FAW>Ϯ}I#/ZB<; `+\>ϼ}s+\>ϼ}s*[]Jrq,!p1>ϼ}s*KxY sBA ce8sy\W>Ϯ}sy\W>Ϯ}Ks4NA#p{,#0]\p >q"VM[X30唃ՠ @H@G Tݷ]kr_?.gp`bW?Gz:x\]h6}600}0q餅)E=ml ?B5j v#:[?XpsmPu;)PE¿ørοo@;# x$,,NNFt8B5TUrQTdMH4wʟg pqc?#"826NK1!p?g <.^n>@K]<=C&R1|QPtC25 |02=]|k_]Wle/e_0x-HCJGF83=Q[SN-#y=i#s Ip_ Pu]BFf|K@`8<ƒ5-C|7tǁ^y# :22;4xۜFn>;-4^fÐ\tRI)D]ȫ}eq6d{rpIL4< (zrRI)D]ȧ tɓJ'q@,Ic\I5lkc[ƶ5lkc[ƶ5<JӜZR `u=oFD?ȷa\yŸR,5#tpQ$ʑ+:so>>;cz#ԯ{lpUlp?ǛyQA_ M \ƧG|gc# x̶9Ҕ?CzYc K*1Ǯ|w=Gc-__?FضCR<47('k*FpUA|!"OI <]+PdG!<,JώXG^~+ǀxT-K&-zt?|HT}C8:V$s?w߫IS<߮{q}~߮{q}~߮{q}~߮{q}~߮{qauGc-__>b%jx-9x.B@?t?5t6#@_qT,:QUI&G#2k2](I=G8\\Kd`W?f)]Dт*Y "C)h'3 B0Xe/)܉װe׌A; PH^t6)J$,wԌ)ؙDtĻ6 M, AcYk'HWTeż.ˏ8-Rܘ )Vb%')E-2nF o9"6+bZ[M OQ^R t)LV7#qqP]!qbTǐKWW=o1#k.iXx%qך* 65,k"IѺ,k '1{=sV=Ԩ8'Bh\mS#]& ыɳ E RA,"X׋eU(9 &ĩ ~Lj< gFvE!Tqz5ZR z8lJG=FIf_|OS|R6xUQ߫Pb0fZkWWp7 I"lnБ23[wfLq򨤸E[H!D%o}@bmLw24t!=HsZѯDv?ROo;NmLQݠ ?̵z]Ǯ|wǺi6b d$43$D'< ]$z~{A X mw=g%]_\cO>Ɩ\%N-:9jkXObI]2~hF:FKWW=<-,zo\6YGq^ O(_=sV=лk.ي95]]٦Q޴HFm1qF0+H!HŝƟ&y}π!_,$/N>;cOL0H)z;WQ,!"A&"Z]‘R.eSMKs2Hb@S%Ns}kԕr$2H!0$I]LT&t9U'#kԵ~|[[n7ў><|ó5bO'=sV=3%kPr{LAAM=#CGrXQI6f9f!иwV4[!6s"$ ⭥T"L IB 0"Xˌ g5!˜~z#ԯ{|._Gc3[(е}Ǯ|wǺYXiC R5F+BܘT()zk[ ZrW%Rt@6gqIu& OB@]_b9RjkRj,'?xTܭm;Q*6BTR ʾI䴆$m,dT7h'ZLJS2.vXkԵ~|ȃ5`Gq'O8wOqjײV]F3lž<{k}aPc?FWky1kc&P1Hr)dui[< [-;nw:i֑ɸht5)L AA-PrSN bq)AsIBG\̠x4$q5#IGc-__;!E"tޝ5/;(53=sV=ֆ}R%TN4fqPMp?p42ĬQz#ԯ{%O^_^澕|&!_H{F0;\Տu#_-V<%+ GI379Fv\p!UUFI$Zc/CM2H<rqP >{u =Gc-__;S/H.g4'OO%n>;cX6LWԄ1odPet^5T8۴;-h2)As434DMr}So4ǥ26xH]B:79 T@jC45#8WRz#ԯ{DZ:ҷ P`/s#pz|[ۈoiYMif+B8ѯDv?ROo+Mj:5RQ_Im)H{\Տuo!&G,-̒K srSQ@bLF#Cr){oRI1*.k .F&':)9f~SII#lW7MdV%SkԵ~|NtK8:8yv+m)AxHώXNHx01fU@7VѠhߊeOX PH @ _: rrjR8ή9UomJpj@^~+~y]?ӱ~G~V|0n|uIUV $yOuͤE}Fb%AF]$T!jw2pM %k#Wjf"tiG9QΈYrƯ6FLLAJ+67RXOz5ZR w?̅d?KM_y_)w^߫ݵ9$[=s[0kF\T)[P[CuL|)Ӎ9Z$$ Gaɐf7LBT dݼ݌t~z#ԯ{ x̻͙Ц!(t NV[okUVA\61-j֫{ZjԺp6qGyo=/mkDZ\ՏuiJDH'ejgU]rVr2 4[ OtmBG!ɫ @(̐F8Լ,o2ȑoނ{2UT{FvՇ(2G2"B&WF |^z#ԯ{ xk"{38p3` bjN;$ O ϡ|ȿ#=?h[O瓼~"{5 9sV=֍Z@F34m5ʎ ٳƚӜ4"ǡF05d=yኚvIuhĈ|5|R 6XUcu$GRPTс5hPEע;jJ'ʱ [oVJ[+omʤYPVJ[+om. Ժ h!I!bqr,ۑ`[jT0 )gի G6M:4i$*jk V%2Ou,$7`rc'HU2erc-so~s4- 2hIz=5Ć*t(/W7&^a\L6x /g$n&THТ8b;FKWW==f:~ShdinF } 1ke60A\!> Eܱª[yFrD#wE#TRC#|Pio.9i\p+RETp@mYPeb] d`Vb89Ƭwx!#}c|?e"gRG1Q4 ]1TפFܠmɄ]1ԝ5.ZY@8;;'0&FCvlA*) 4Fa_2ю/sTVO)Ve_)opjBW&TRS4<MđԐw*XjJU#ս9 L(kfk}jկwc>;cjLQ mv,WH4dU19c2iّ ( T@,p0YPOPr4LY'Kw/!sD oW&-iYE cp輻5cX°s&Xw VdRK\13"$6E`q5Y~R I].49vcaRtiE2] 1Pr("=Ө QU=J3I&O1]dёGkUp5FuΉt'hfNh (L_6 J/5!#bFխeu|p&&43܉dQ o/ޭzo/ޭzo/ޭzgg85X{О& IBs,S$ET>ex0c;x]K) <6v]!IFFF( V<%+;c[12>y!xk]99upWvqI pjd_IaDSKN8&L5Gbo'bu3'|wǺu EsxэNiщ>P,t bחI'Ix@LP~FeiJ{T#BxiB01[9c%j9MJ& |`85-n-nѪH8kԵ~|u[T8}9%/jqϕᢿO&ľ߫PfX?~HOm:]M 9,S3Xj \`wr_8rU )SzFzӔO'dݜNiYQTVc4[XG1㎌9$]#PhSFB@xF PI Bе$' Lc"CP=DLưڴ7&gQde%NkԵ~|qd(a]JF~+lkq--1b5%}sV=3$@ w ΝGԲv(c1VmlNPFXդud&bKV.۪$WF7uhFG3$sk]j[6v6@02j#Η2Gl!AvTEPU@ F,B\UlRw;k@ף^~+]Fy1%*y(3JW̿$uo@ =3~83'|wǺs =i%KnppRdähYq hZX<I!pk|ؼ PE+n\@ A0Yfք0`u%O>$ :w狀H 8Gv0 lTR8pC+{dXO ss )!W=ެ;pdg^1K| Lb`PQ WBBgY(YIF\8ǣ^~+?) c&Cw$͂l˛x"׈(# W~$ώXZ5k4qxVeI>xm(sp"%mGZǝi3dDXXEa9}DK.q*[qt[E0WRaӨűyRXHʼnIuЀ`5}ӢIKE6ʂ4FYTG8ʀ"F xQB:O9xfԮu-DaCP#e Yba=Mm!82P#>Ez5ZR sn%v|S=.5⏔"hO22E?z~{%]rnt\άT"ęGAe0 JU"¹PFIGc-__8<j$Gq^ǖ֎'|[H߳w>$ώXAT@ʅ]X|h?2X)%jii^vrpDNTsBo5s oV*!8zoFKWW=5W?Cgҍiy#PxĞ߫vxk\}Wrܮeq+\}Wrܮeq+\}Wrܮeq+\}Wrܮeq+\}WruY(Dv?ROo~u8;z ~"d/c@kƲ(a_̲q |I$p5 ' GeudoT$4ARUF)@iN:GvF@-pK Gc-__6eWbn&c$=,"ω&~lY)/_JO=_Ğ߫'ټq‡#]T,СD'r]5;KvQ6pUCRE$Vț6 !tAXQC$qV(aLNaCT\f+t$ mGiPBFw;GF @Lg'5f!XTHb}lS)炲UHf˹_A͸劾p5* b!] oCOo+6,M|ꮹ*H"35ZR j:}O?KqCըgc\_4+_N0~#ώXP>`23E;Ʒ0ʣH(Qi] į R… 4Aq&qNb}_LWѢeQ]լ.4_Wk 8|N`h]L6 Xč9 M NjYlJFOW5psgXM\WVMPO‹hu?\ՏtGBg9ҊI5 9Y@Ij9ì䮇]# ڭJH)ƺ$p6*:pu ` 8LkqRk"'FŗI&ia"'١pv̧B{`-ȸb9@T =b8(`0Vz#ԯ{xv4k>A^%Aw-Z@w2_ _Ϙ9oz&Ϸ17r: |G 4H "11bU#U-Ue)qk8PGQ&Y3mcߔCCd"0 k`H(q&[A'.C6wqT!13!FC!l8yc24@y*4s$ЪGi !yh}ԖzP#xN %.m"KU:JT6|a bdEl|s#*3v}Gc-__4k˕ !{,d?\U?G#MŌ#**4x/Ok |wǺ gsUUf=@TE) 9c )r@$lÈmJ3&("cw,7*#y ,k2gV"2ZA]PW<*x%qTaFs =3ɳ E O "6Uu\cI$hDI-MH~PȩmemʊcSΐexxf+t`WV1J"Y?"{p4L Ev@ 0U2< ((VSSA-S28AX<ތZ# Y;jJ'#TV;˹p;g{$T5.Gqr$?TzK?\Տtn'-8וO<:b23 qK8͐ѩwV8]?2*疥Gdvʢ NHT:yw$EBDKtX"' g-GP&h4JD"v&&&l~ˮ GsV=()k;|wTb(' $FͶyݯTs]}Zecr%zȮPD0#%aI_57q!# &t H&V(ƉsuVڋvƢXMrM6rz 6}:k d$k0?&(޽k{>z#ԯ{ɳ?Xdiw]a&9S<i"1JI '_!dU>~ҋ~{r$T*)O1mM5b B\n8zә[KlJx*^VLMNgDaISI-}ew%2 /"幹AX#x Tn0PK3(LZ4ЄTo MRu5U؈Cn0AB` )o-v8i7mC4xSrk$%xS+# Cm$/d/qע;jJ's[̙|1d+}!(~$m>1COv}yo>;cLDaV5yUt[‘koh&6!ʁ8c^ սq3"fgSu 5 ec@=lN1"]0 )c FwF;}#kvLr P0H"5b1Ɍ7=U Ji!~hnѯDv?ROo{t~r:~!g3B£ zNhn~X)_! $팁R?z~{o3H,r11 ơPE"C.P$lA `B| xc[]O`jkmV&Ƭ9 TyPI,"K<A:Ԩ2tXqR(*'!dCqr |j U:!i4 *dw#̵%_4)ncS ą}pmyWPNBiI:h"54]c擽U1tF'JkԵ~|q:Ft)ηȹ<(|3w2nRM[L|ϝ~"P97Ca |wǺ,2@tp$AE$[cTWU82HDj&xFNⲸPlFw=r%#qPnaB6\ɤ/ i$| :J&IifNC Vf2B$׳ `5,m  t$-F&dVB˷~鯯I„b6{U$]؂ÉB)󍥩;ZY y$^z#ԯ{|F~:c!kȃߍf}x샃A# *!y!H}=ԑO^߫9Essssssssssssssssss=ԥXxj;?jJ'y8QⶑnEq>evc薡炪GG:/qS/\Տ+-@p>q c[,GҀɃ QE+=-#^߫ KWW={6r t?c[:55;8F2Aj tOu5"9%/\#A(Mv+_]Wle/ev+_]Wle/ev+_]Wle/ev+_SlN} (UQOoW3P''G;O|KrEڏ7s._h#ޠ+Lz?~"οoytPyE )qK"w,2X`iuYXK6żg5z'ӇkK/\-҃'ZM9S lg*ܧ*r7ޤp4F#G/RO<(TAh1m5krdGXIDgƨB[0)B;.I}T0ƎrWSƌ:TEeFPh}1XH-kFPQ%ٮӿPpNWQ(&L@f#ai"ƒm1*iѤec J" 5-(KlBҊ PAs;4c*DvBrj]h8 g{֥Z;'Ȑ2Zr PB U/*>9IzjHG5Zm\c!I ר X |4mȄ*byv?3#ӎO[(뉒S>-`nO3¢tVd*2uSFk, UOI2 -qs;`LN H!pdkm,ВiKݖ~6k3#왆 &{݀dCA#$iP#U>5R: 5uHw#h&~"/762J ] G撻'#'UYO Yɨc9HY4 FI38UG{[4˼aSe6) Ş Q v)BP(ݥCTDyJG<435!܍( l+3h5r 2kfF沼CឹS$#tu yEMq4-=He 6W@ċ"oל˶H˒ti'} LPu(2k}0ggoifŜڳhOss9?Li$V UlqgR =|ied|I%gvn%R{섀C Aus5ܑ拾vul+RO$T&w.ǎFQb{Щ=&%~"=(LbbK2$Q+>тPj)扌qDa@H'"(&aكT3I&Atܢ6 T3\lШȌL}բ4ou1 V Tَh%HF&W+4]ヤI42+Fg }ka܇ ZtnⶲZd+BfdLFia(6`bF4ѸH4ܪR;%9 $AW7S:1I%vt#jkw10d̒;>*)}BвM&c0AB*Ii\<39[ 9'Z˦h wgB' Z3 b3LK Di1Itq;Oxg~uGwp\PϮ}sy\W>5ij$c*$f=WSD1>Ϯ}sy\W>Ϯ}Ks4NA#p{n%1"6PN3\W>%ϼ}s+\ʖi&!Ìq$Spղesy\W>Ϯ}sy\W>Ϯ}syN#Y$>Ϯ}sy\W>Ϯ}sy\W>Ϯ} οo>X7\u5/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wle/ev+_]Wlepn&Gp?+!R"13A`aQqB?5[M*}J}E +U]UWQTkcw9NX %\F1cVlu=rX %[hĀSԧ cr8 9GHT0?]r7;#$uD@#E f7vSÇDcK`+fozzO@V =Z+TjSƙ l1!0`?D"` vU}.Uz]}t././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/_static/sql_railroad.html0000644000000000000000000012321215134002420016371 0ustar00

Forward

'select' '*' column name ',' Suppress column name 'from' table name ',' Suppress table name 'where' 'or' term

column name

W:(A-Za-z, $0-9A-Z_a-z) identifier '.' W:(A-Za-z, $0-9A-Z_a-z) identifier

table name

W:(A-Za-z, $0-9A-Z_a-z) identifier '.' W:(A-Za-z, $0-9A-Z_a-z) identifier

'or' term

'and' term 'or' 'and' term _FB 'and' term 'or' 'and' term 'and' term

'and' term

'not' term 'and' 'not' term _FB 'not' term 'and' 'not' term 'not' term

'not' term

'not' 'not' term _FB 'not' 'not' term column name '=' '!=' '<=' '<' '>=' '>' 'EQ' 'NE' 'LT' 'LE' 'GT' 'GE' Unnamed 2 column name 'in' '(' Unnamed 2 ',' Suppress Unnamed 2 ')' column name 'in' '(' Forward ')' column name 'is' 'null' 'not' 'null' '(' Suppress 'or' term ')' Suppress

Unnamed 2

Re:('[+-]?(?:\d+\.\d*|\.\d+)') real number Re:('[+-]?\d+') signed integer Re:('"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') '"' Re:("'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") "'" quotedString using single or double quotes column name
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/conf.py0000644000000000000000000001530115134002420012677 0ustar00"""Configuration file for the Sphinx documentation builder.""" # This file does only contain a selection of the most common options. For a # full list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # pylint: disable=all import doctest import os import sys # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath("..")) from pyparsing import __version__ as pyparsing_version # -- Project information ----------------------------------------------------- project = "PyParsing" copyright = "2018-2024, Paul T. McGuire" author = "Paul T. McGuire" # The short X.Y version version = pyparsing_version # The full version, including alpha/beta/rc tags release = pyparsing_version # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ "sphinx.ext.autodoc", "sphinx.ext.doctest", "myst_parser", ] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffixes: source_suffix = { '.rst': 'restructuredtext', '.md': 'markdown', } # The master toctree document. master_doc = "index" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. pygments_style = "sphinx" # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = "alabaster" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = { 'github_user': 'pyparsing', 'github_repo': 'pyparsing', } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] html_css_files = { "pyparsing.css": "*", } # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # The default sidebars (for documents that don't match any pattern) are # defined by theme itself. Builtin themes are using these templates by # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # html_sidebars = { '**': [ 'about.html', 'searchfield.html', 'navigation.html', 'relations.html', 'donate.html', ], 'pyparsing': [ 'about.html', 'searchfield.html', 'localtoc.html', 'relations.html', 'donate.html', ], } # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = "PyParsingdoc" # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ( master_doc, "PyParsing.tex", "PyParsing Documentation", "Paul T. McGuire", "manual", ), ] # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [(master_doc, "pyparsing", "PyParsing Documentation", [author], 1)] # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ( master_doc, "PyParsing", "PyParsing Documentation", author, "PyParsing", "Python PEG parsing library.", "Miscellaneous", ), ] # -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project epub_author = author epub_publisher = author epub_copyright = copyright # The unique identifier of the text. This can be a ISBN number # or the project homepage. # # epub_identifier = '' # A unique identification for the text. # # epub_uid = '' # A list of files that should not be packed into the epub file. epub_exclude_files = ["search.html"] # -- Domain configuration ---------------------------------------------------- python_use_unqualified_type_names = True python_display_short_literal_types = True python_maximum_signature_line_length = 100 add_module_names = False toc_object_entries_show_parents = 'hide' # -- Extension configuration ------------------------------------------------- autodoc_class_signature = 'mixed' autodoc_mock_imports = ['railroad'] autodoc_preserve_defaults = True autodoc_default_options = { 'class-doc-from': 'both', 'undoc-members': True, 'show-inheritance': True, } doctest_global_setup = ''' import math import string import pprint import pyparsing import pyparsing.common ppc = pyparsing.common ppu = pyparsing.unicode import pyparsing.util import pyparsing as pp from pyparsing import * ''' doctest_default_flags = ( doctest.ELLIPSIS | doctest.IGNORE_EXCEPTION_DETAIL | doctest.DONT_ACCEPT_TRUE_FOR_1 | doctest.REPORT_NDIFF ) myst_heading_anchors = 3 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/index.rst0000644000000000000000000000117215134002420013242 0ustar00.. PyParsing documentation master file, created by sphinx-quickstart on Mon Nov 19 15:06:52 2018. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to PyParsing's documentation! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Release v\ |version| .. rubric:: Contents .. toctree:: :maxdepth: 2 HowToUsePyparsing whats_new_in_3_3 whats_new_in_3_2 whats_new_in_3_1 whats_new_in_3_0_0 pyparsing CONTRIBUTING Writing_Doctests CODE_OF_CONDUCT Indices and tables ~~~~~~~~~~~~~~~~~~ * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/make_sphinx_docs.bat0000644000000000000000000000004515134002420015405 0ustar00sphinx-build.exe -E -b html . _build ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/pyparsing.rst0000644000000000000000000000117715134002420014154 0ustar00************* pyparsing API ************* .. automodule:: pyparsing :members: :special-members: __add__,__sub__,__div__,__mul__,__and__,__or__,__xor__,__lshift__,__invert__,__call__,__getitem__,__str__ :exclude-members: __init__,__repl__,parseImpl,parseImpl_regex,parseImplAsGroupList,parseImplAsMatch,postParse,preParse,streamline,recurse,try_parse,can_parse_next,default_name,mayReturnEmpty Module ``pyparsing.diagram`` ---------------------------- .. automodule:: pyparsing.diagram :members: .. 'hidden' prevents the toctree from appearing at the bottom of the page .. toctree:: :maxdepth: 2 :hidden: self ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/pyparsing_class_diagram.puml0000644000000000000000000001362715134002420017175 0ustar00@startuml 'https://plantuml.com/class-diagram top to bottom direction hide circle hide empty members 'hide empty methods skinparam groupInheritance 3 note as N1 Class Diagram --- pyparsing 3.0.9 May, 2022 end note N1 <-[hidden]- unicode package core { class globals { quoted_string sgl_quoted_string dbl_quoted_string counted_array() match_previous_literal() match_previous_expr() one_of() dict_of() original_text_for() ungroup() nested_expr() make_html_tags() make_xml_tags() common_html_entity replace_html_entity() class OpAssoc infix_notation() class IndentedBlock c_style_comment html_comment rest_of_line dbl_slash_comment cpp_style_comment java_style_comment python_style_comment match_only_at_col() replace_with() remove_quotes() with_attribute() with_class() trace_parse_action() condition_as_parse_action() srange() token_map() autoname_elements() } class ParseResults { class List {static}from_dict() __getitem__() __setitem__() __contains__() __len__() __bool__() __iter__() __reversed__() __getattr__() __add__() __getstate__() __setstate__() __getnewargs__() __dir__() as_dict() as_list() dump() get_name() items() keys() values() haskeys() pop() get() insert() append() extend() clear() copy() get_name() pprint() } class ParseBaseException #ffffff { {static} explain_exception() explain() mark_input_line() line lineno column parser_element } class ParseException class ParseFatalException class ParseSyntaxException ParseBaseException <|-- ParseException ParseBaseException <|-- ParseFatalException ParseFatalException <|-- ParseSyntaxException class ParserElement { name: str results_name: str --- {classifier} enable_packrat() {classifier} enable_left_recursion() {classifier} disable_memoization() {classifier} set_default_whitespace_chars() {classifier} inline_literals_using() {classifier} reset_cache() {static} verbose_stacktrace suppress_warning() operator + () -> And operator - () -> And.ErrorStop operator | () -> MatchFirst operator ^ () -> Or operator & () -> Each operator ~ () -> NotAny operator [] () -> _MultipleMatch operator () () [set_results_name()] add_condition() add_parse_action() set_parse_action() copy() ignore(expr) leave_whitespace() parse_with_tabs() suppress() set_break() set_debug() set_debug_actions() set_name() set_results_name() parse_string() scan_string() search_string() transform_string() split() run_tests() recurse() create_diagram() } class Token #ffffff class ParseExpression #ffffff { exprs: list[ParserElement] } class ParseElementEnhance #ffffff { expr: ParserElement } class _PositionToken #ffffff class Char class White class Word { 'Word(init_chars: str, body_chars: str, min: int, \nmax: int, exact: int, as_keyword: bool, exclude_chars: str) } class Keyword { {static} set_default_keyword_chars(chars: str) } class CaselessKeyword class Empty class Literal class Regex class NoMatch class CharsNotIn class QuotedString class And class Or class MatchFirst class Each class OneOrMore class ZeroOrMore class DelimitedList class SkipTo class Group class Forward { operator <<= () } class LineStart class LineEnd class StringStart class StringEnd class WordStart class WordEnd class _MultipleMatch #ffffff class FollowedBy class PrecededBy class AtLineStart class AtStringStart class TokenConverter #ffffff class Located class Opt class Combine class Group class Dict class Suppress ParserElement <|-- Token ParserElement <|----- ParseExpression Token <|-- _PositionToken ParserElement <|----- ParseElementEnhance 'ParseElementEnhance ---> ParserElement 'ParseExpression ---> "*" ParserElement Token <|-- Empty Token <|-- CloseMatch Token <|-- NoMatch Token <|-- Literal Token <|-- Word Token <|---- Keyword Token <|--- Regex Token <|--- CharsNotIn Token <|-- White Token <|---- QuotedString Word <|-- Char Literal <|-- CaselessLiteral Keyword <|-- CaselessKeyword ParseExpression <|-- And ParseExpression <|-- Or ParseExpression <|-- MatchFirst ParseExpression <|-- Each ParseElementEnhance <|-- SkipTo ParseElementEnhance <|--- Forward ParseElementEnhance <|-- Located ParseElementEnhance <|--- _MultipleMatch _MultipleMatch <|-- OneOrMore _MultipleMatch <|-- ZeroOrMore ParseElementEnhance <|-- DelimitedList ParseElementEnhance <|--- NotAny ParseElementEnhance <|--- FollowedBy ParseElementEnhance <|--- PrecededBy ParseElementEnhance <|-- Opt ParseElementEnhance <|--- TokenConverter ParseElementEnhance <|-- AtStringStart ParseElementEnhance <|-- AtLineStart TokenConverter <|-- Group TokenConverter <|-- Dict TokenConverter <|-- Suppress TokenConverter <|-- Combine _PositionToken <|-- LineStart _PositionToken <|-- LineEnd _PositionToken <|-- WordStart _PositionToken <|-- WordEnd _PositionToken <|-- StringStart _PositionToken <|-- StringEnd } package common { class " " { comma_separated_list convert_to_integer() convert_to_float() integer hex_integer signed_integer fraction mixed_integer real sci_real number fnumber identifier ipv4_address ipv6_address mac_address convert_to_date() convert_to_datetime() iso8601_date iso8601_datetime uuid strip_html_tags() upcase_tokens() downcase_tokens() url } } package unicode { class unicode_set { printables: str alphas: str nums: str alphanums: str identchars: str identbodychars: str } class Latin1 class LatinA class LatinB class BasicMultilingualPlane class Chinese class Thai class Japanese { class Kanji class Hiragana class Katakana } class Greek class Hangul class Arabic class Devanagari class Hebrew class Cyrillic unicode_set <|-- Latin1 unicode_set <|--- LatinA unicode_set <|-- LatinB unicode_set <|---- BasicMultilingualPlane unicode_set <|-- Greek unicode_set <|--- Cyrillic unicode_set <|--- Chinese unicode_set <|--- Japanese unicode_set <|--- Hangul Chinese <|-- CJK Japanese <|-- CJK Hangul <|-- CJK unicode_set <|-- Thai unicode_set <|-- Arabic unicode_set <|-- Hebrew unicode_set <|--- Devanagari } ParserElement <-[hidden] ParseBaseException 'ParseBaseException <-[hidden] globals 'globals <-[hidden] ParserElement CJK <-[hidden]-- common @enduml././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/requirements.txt0000644000000000000000000000003215134002420014657 0ustar00sphinx < 8.2 myst-parser ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/whats_new_in_3_0_0.rst0000644000000000000000000007546415134002420015517 0ustar00============================= What's New in Pyparsing 3.0.0 ============================= :author: Paul McGuire :date: May, 2022 :abstract: This document summarizes the changes made in the 3.0.0 release of pyparsing. (Updated to reflect changes up to 3.0.10) .. contents:: :depth: 4 New Features ============ PEP-8 naming ------------ This release of pyparsing will (finally!) include PEP-8 compatible names and arguments. Backward-compatibility is maintained by defining synonyms using the old camelCase names pointing to the new snake_case names. This code written using non-PEP8 names:: wd = pp.Word(pp.printables, excludeChars="$") wd_list = pp.delimitedList(wd, delim="$") print(wd_list.parseString("dkls$134lkjk$lsd$$").asList()) can now be written as:: wd = pp.Word(pp.printables, exclude_chars="$") wd_list = pp.delimited_list(wd, delim="$") print(wd_list.parse_string("dkls$134lkjk$lsd$$").as_list()) Pyparsing 3.0 will run both versions of this example. New code should be written using the PEP-8 compatible names. The compatibility synonyms will be removed in a future version of pyparsing. Railroad diagramming -------------------- An excellent new enhancement is the new railroad diagram generator for documenting pyparsing parsers.:: import pyparsing as pp # define a simple grammar for parsing street addresses such # as "123 Main Street" # number word... number = pp.Word(pp.nums).set_name("number") name = pp.Word(pp.alphas).set_name("word")[1, ...] parser = number("house_number") + name("street") parser.set_name("street address") # construct railroad track diagram for this parser and # save as HTML parser.create_diagram('parser_rr_diag.html') ``create_diagram`` accepts these named arguments: - ``vertical`` (int) - threshold for formatting multiple alternatives vertically instead of horizontally (default=3) - ``show_results_names`` - bool flag whether diagram should show annotations for defined results names - ``show_groups`` - bool flag whether groups should be highlighted with an unlabeled surrounding box - ``embed`` - bool flag whether generated HTML should omit ````, ````, and ```` tags to embed the resulting HTML in an enclosing HTML source (new in 3.0.10) - ``head`` - str containing additional HTML to insert into the ```` section of the generated code; can be used to insert custom CSS styling - ``body`` - str containing additional HTML to insert at the beginning of the ```` section of the generated code To use this new feature, install the supporting diagramming packages using:: pip install pyparsing[diagrams] See more in the examples directory: ``make_diagram.py`` and ``railroad_diagram_demo.py``. (Railroad diagram enhancement contributed by Michael Milton) Support for left-recursive parsers ---------------------------------- Another significant enhancement in 3.0 is support for left-recursive (LR) parsers. Previously, given a left-recursive parser, pyparsing would recurse repeatedly until hitting the Python recursion limit. Following the methods of the Python PEG parser, pyparsing uses a variation of packrat parsing to detect and handle left-recursion during parsing.:: import pyparsing as pp pp.ParserElement.enable_left_recursion() # a common left-recursion definition # define a list of items as 'list + item | item' # BNF: # item_list := item_list item | item # item := word of alphas item_list = pp.Forward() item = pp.Word(pp.alphas) item_list <<= item_list + item | item item_list.run_tests("""\ To parse or not to parse that is the question """) Prints:: ['To', 'parse', 'or', 'not', 'to', 'parse', 'that', 'is', 'the', 'question'] See more examples in ``left_recursion.py`` in the pyparsing examples directory. (LR parsing support contributed by Max Fischer) Packrat/memoization enable and disable methods ---------------------------------------------- As part of the implementation of left-recursion support, new methods have been added to enable and disable packrat parsing. ====================== ======================================================= Name Description ---------------------- ------------------------------------------------------- enable_packrat Enable packrat parsing (with specified cache size) enable_left_recursion Enable left-recursion cache disable_memoization Disable all internal parsing caches ====================== ======================================================= Type annotations on all public methods -------------------------------------- Python 3.6 and upward compatible type annotations have been added to most of the public methods in pyparsing. This should facilitate developing pyparsing-based applications using IDEs for development-time type checking. New string constants ``identchars`` and ``identbodychars`` to help in defining identifier Word expressions ---------------------------------------------------------------------------------------------------------- Two new module-level strings have been added to help when defining identifiers, ``identchars`` and ``identbodychars``. Instead of writing:: import pyparsing as pp identifier = pp.Word(pp.alphas + "_", pp.alphanums + "_") you will be able to write:: identifier = pp.Word(pp.identchars, pp.identbodychars) Those constants have also been added to all the Unicode string classes:: import pyparsing as pp ppu = pp.pyparsing_unicode cjk_identifier = pp.Word(ppu.CJK.identchars, ppu.CJK.identbodychars) greek_identifier = pp.Word(ppu.Greek.identchars, ppu.Greek.identbodychars) Refactored/added diagnostic flags --------------------------------- Expanded ``__diag__`` and ``__compat__`` to actual classes instead of just namespaces, to add some helpful behavior: - ``pyparsing.enable_diag()`` and ``pyparsing.disable_diag()`` methods to give extra help when setting or clearing flags (detects invalid flag names, detects when trying to set a ``__compat__`` flag that is no longer settable). Use these methods now to set or clear flags, instead of directly setting to ``True`` or ``False``:: import pyparsing as pp pp.enable_diag(pp.Diagnostics.warn_multiple_tokens_in_named_alternation) - ``pyparsing.enable_all_warnings()`` is another helper that sets all "warn*" diagnostics to ``True``:: pp.enable_all_warnings() - added support for calling ``enable_all_warnings()`` if warnings are enabled using the Python ``-W`` switch, or setting a non-empty value to the environment variable ``PYPARSINGENABLEALLWARNINGS``. (If using ``-Wd`` for testing, but wishing to disable pyparsing warnings, add ``-Wi:::pyparsing``.) - added new warning, ``warn_on_match_first_with_lshift_operator`` to warn when using ``'<<'`` with a ``'|'`` ``MatchFirst`` operator, which will create an unintended expression due to precedence of operations. Example: This statement will erroneously define the ``fwd`` expression as just ``expr_a``, even though ``expr_a | expr_b`` was intended, since ``'<<'`` operator has precedence over ``'|'``:: fwd << expr_a | expr_b To correct this, use the ``'<<='`` operator (preferred) or parentheses to override operator precedence:: fwd <<= expr_a | expr_b or:: fwd << (expr_a | expr_b) - ``warn_on_parse_using_empty_Forward`` - warns that a ``Forward`` has been included in a grammar, but no expression was attached to it using ``'<<='`` or ``'<<'`` - ``warn_on_assignment_to_Forward`` - warns that a ``Forward`` has been created, but was probably later overwritten by erroneously using ``'='`` instead of ``'<<='`` (this is a common mistake when using Forwards) (**currently not working on PyPy**) Support for yielding native Python ``list`` and ``dict`` types in place of ``ParseResults`` ------------------------------------------------------------------------------------------- To support parsers that are intended to generate native Python collection types such as lists and dicts, the ``Group`` and ``Dict`` classes now accept an additional boolean keyword argument ``aslist`` and ``asdict`` respectively. See the ``jsonParser.py`` example in the ``pyparsing/examples`` source directory for how to return types as ``ParseResults`` and as Python collection types, and the distinctions in working with the different types. In addition parse actions that must return a value of list type (which would normally be converted internally to a ``ParseResults``) can override this default behavior by returning their list wrapped in the new ``ParseResults.List`` class:: # this parse action tries to return a list, but pyparsing # will convert to a ParseResults def return_as_list_but_still_get_parse_results(tokens): return tokens.asList() # this parse action returns the tokens as a list, and pyparsing will # maintain its list type in the final parsing results def return_as_list(tokens): return ParseResults.List(tokens.asList()) This is the mechanism used internally by the ``Group`` class when defined using ``aslist=True``. New Located class to replace ``locatedExpr`` helper method ---------------------------------------------------------- The new ``Located`` class will replace the current ``locatedExpr`` method for marking parsed results with the start and end locations of the parsed data in the input string. ``locatedExpr`` had several bugs, and returned its results in a hard-to-use format (location data and results names were mixed in with the located expression's parsed results, and wrapped in an unnecessary extra nesting level). For this code:: wd = Word(alphas) for match in locatedExpr(wd).search_string("ljsdf123lksdjjf123lkkjj1222"): print(match) the docs for ``locatedExpr`` show this output:: [[0, 'ljsdf', 5]] [[8, 'lksdjjf', 15]] [[18, 'lkkjj', 23]] The parsed values and the start and end locations are merged into a single nested ``ParseResults`` (and any results names in the parsed values are also merged in with the start and end location names). Using ``Located``, the output is:: [0, ['ljsdf'], 5] [8, ['lksdjjf'], 15] [18, ['lkkjj'], 23] With ``Located``, the parsed expression values and results names are kept separate in the second parsed value, and there is no extra grouping level on the whole result. The existing ``locatedExpr`` is retained for backward-compatibility, but will be deprecated in a future release. New ``AtLineStart`` and ``AtStringStart`` classes ------------------------------------------------- As part of fixing some matching behavior in ``LineStart`` and ``StringStart``, two new classes have been added: ``AtLineStart`` and ``AtStringStart``. ``LineStart`` and ``StringStart`` can be treated as separate elements, including whitespace skipping. ``AtLineStart`` and ``AtStringStart`` enforce that an expression starts exactly at column 1, with no leading whitespace.:: (LineStart() + Word(alphas)).parseString("ABC") # passes (LineStart() + Word(alphas)).parseString(" ABC") # passes AtLineStart(Word(alphas)).parseString(" ABC") # fails [This is a fix to behavior that was added in 3.0.0, but was actually a regression from 2.4.x.] New ``IndentedBlock`` class to replace ``indentedBlock`` helper method ---------------------------------------------------------------------- The new ``IndentedBlock`` class will replace the current ``indentedBlock`` method for defining indented blocks of text, similar to Python source code. Using ``IndentedBlock``, the expression instance itself keeps track of the indent stack, so a separate external ``indentStack`` variable is no longer required. Here is a simple example of an expression containing an alphabetic key, followed by an indented list of integers:: integer = pp.Word(pp.nums) group = pp.Group(pp.Char(pp.alphas) + pp.IndentedBlock(integer)) parses:: A 100 101 B 200 201 as:: [['A', [100, 101]], ['B', [200, 201]]] By default, the results returned from the ``IndentedBlock`` are grouped. ``IndentedBlock`` may also be used to define a recursive indented block (containing nested indented blocks). The existing ``indentedBlock`` is retained for backward-compatibility, but will be deprecated in a future release. Shortened tracebacks -------------------- Cleaned up default tracebacks when getting a ``ParseException`` when calling ``parse_string``. Exception traces should now stop at the call in ``parse_string``, and not include the internal pyparsing traceback frames. (If the full traceback is desired, then set ``ParserElement.verbose_traceback`` to ``True``.) Improved debug logging ---------------------- Debug logging has been improved by: - Including ``try/match/fail`` logging when getting results from the packrat cache (previously cache hits did not show debug logging). Values returned from the packrat cache are marked with an '*'. - Improved fail logging, showing the failed expression, text line, and marker where the failure occurred. - Adding ``with_line_numbers`` to ``pyparsing_testing``. Use ``with_line_numbers`` to visualize the data being parsed, with line and column numbers corresponding to the values output when enabling ``set_debug()`` on an expression:: data = """\ A 100""" expr = pp.Word(pp.alphanums).set_name("word").set_debug() print(ppt.with_line_numbers(data)) expr[...].parseString(data) prints:: . 1 1234567890 1: A 2: 100 Match word at loc 3(1,4) A ^ Matched word -> ['A'] Match word at loc 11(2,7) 100 ^ Matched word -> ['100'] New / improved examples ----------------------- - ``number_words.py`` includes a parser/evaluator to parse ``"forty-two"`` and return ``42``. Also includes example code to generate a railroad diagram for this parser. - ``BigQueryViewParser.py`` added to examples directory, submitted by Michael Smedberg. - ``booleansearchparser.py`` added to examples directory, submitted by xecgr. Builds on searchparser.py, adding support for '*' wildcards and non-Western alphabets. - Improvements in ``select_parser.py``, to include new SQL syntax from SQLite, submitted by Robert Coup. - Off-by-one bug found in the ``roman_numerals.py`` example, a bug that has been there for about 14 years! Submitted by Jay Pedersen. - A simplified Lua parser has been added to the examples (``lua_parser.py``). - Demonstration of defining a custom Unicode set for cuneiform symbols, as well as simple Cuneiform->Python conversion is included in ``cuneiform_python.py``. - Fixed bug in ``delta_time.py`` example, when using a quantity of seconds/minutes/hours/days > 999. Other new features ------------------ - ``url`` expression added to ``pyparsing_common``, with named fields for common fields in URLs. See the updated ``urlExtractorNew.py`` file in the ``examples`` directory. Submitted by Wolfgang Fahl. - ``DelimitedList`` now supports an additional flag ``allow_trailing_delim``, to optionally parse an additional delimiter at the end of the list. Submitted by Kazantcev Andrey. - Added global method ``autoname_elements()`` to call ``set_name()`` on all locally defined ``ParserElements`` that haven't been explicitly named using ``set_name()``, using their local variable name. Useful for setting names on multiple elements when creating a railroad diagram:: a = pp.Literal("a") b = pp.Literal("b").set_name("bbb") pp.autoname_elements() ``a`` will get named "a", while ``b`` will keep its name "bbb". - Enhanced default strings created for ``Word`` expressions, now showing string ranges if possible. ``Word(alphas)`` would formerly print as ``W:(ABCD...)``, now prints as ``W:(A-Za-z)``. - Better exception messages to show full word where an exception occurred.:: Word(alphas)[...].parse_string("abc 123", parse_all=True) Was:: pyparsing.ParseException: Expected end of text, found '1' (at char 4), (line:1, col:5) Now:: pyparsing.exceptions.ParseException: Expected end of text, found '123' (at char 4), (line:1, col:5) - Using ``...`` for ``SkipTo`` can now be wrapped in ``Suppress`` to suppress the skipped text from the returned parse results.:: source = "lead in START relevant text END trailing text" start_marker = Keyword("START") end_marker = Keyword("END") find_body = Suppress(...) + start_marker + ... + end_marker print(find_body.parse_string(source).dump()) Prints:: ['START', 'relevant text ', 'END'] - _skipped: ['relevant text '] - Added ``ignore_whitespace(recurse:bool = True)`` and added a ``recurse`` argument to ``leave_whitespace``, both added to provide finer control over pyparsing's whitespace skipping. Contributed by Michael Milton. - Added ``ParserElement.recurse()`` method to make it simpler for grammar utilities to navigate through the tree of expressions in a pyparsing grammar. - The ``repr()`` string for ``ParseResults`` is now of the form:: ParseResults([tokens], {named_results}) The previous form omitted the leading ``ParseResults`` class name, and was easily misinterpreted as a ``tuple`` containing a ``list`` and a ``dict``. - Minor reformatting of output from ``run_tests`` to make embedded comments more visible. - New ``pyparsing_test`` namespace, assert methods and classes added to support writing unit tests. - ``assertParseResultsEquals`` - ``assertParseAndCheckList`` - ``assertParseAndCheckDict`` - ``assertRunTestResults`` - ``assertRaisesParseException`` - ``reset_pyparsing_context`` context manager, to restore pyparsing config settings - Enhanced error messages and error locations when parsing fails on the ``Keyword`` or ``CaselessKeyword`` classes due to the presence of a preceding or trailing keyword character. - Enhanced the ``Regex`` class to be compatible with re's compiled with the re-equivalent ``regex`` module. Individual expressions can be built with regex compiled expressions using:: import pyparsing as pp import regex # would use regex for this expression integer_parser = pp.Regex(regex.compile(r'\d+')) - Fixed handling of ``ParseSyntaxExceptions`` raised as part of ``Each`` expressions, when sub-expressions contain ``'-'`` backtrack suppression. - Potential performance enhancement when parsing ``Word`` expressions built from ``pyparsing_unicode`` character sets. ``Word`` now internally converts ranges of consecutive characters to regex character ranges (converting ``"0123456789"`` to ``"0-9"`` for instance). - Added a caseless parameter to the ``CloseMatch`` class to allow for casing to be ignored when checking for close matches. Contributed by Adrian Edwards. API Changes =========== - [Note added in pyparsing 3.0.7, reflecting a change in 3.0.0] Fixed a bug in the ``ParseResults`` class implementation of ``__bool__``, which would formerly return ``False`` if the ``ParseResults`` item list was empty, even if it contained named results. Now ``ParseResults`` will return ``True`` if either the item list is not empty *or* if the named results list is not empty:: # generate an empty ParseResults by parsing a blank string with a ZeroOrMore result = Word(alphas)[...].parse_string("") print(result.as_list()) print(result.as_dict()) print(bool(result)) # add a results name to the result result["name"] = "empty result" print(result.as_list()) print(result.as_dict()) print(bool(result)) Prints:: [] {} False [] {'name': 'empty result'} True In previous versions, the second call to ``bool()`` would return ``False``. - [Note added in pyparsing 3.0.4, reflecting a change in 3.0.0] The ``ParseResults`` class now uses ``__slots__`` to pre-define instance attributes. This means that code written like this (which was allowed in pyparsing 2.4.7):: result = Word(alphas).parseString("abc") result.xyz = 100 now raises this Python exception:: AttributeError: 'ParseResults' object has no attribute 'xyz' To add new attribute values to ParseResults object in 3.0.0 and later, you must assign them using indexed notation:: result["xyz"] = 100 You will still be able to access this new value as an attribute or as an indexed item. - ``enable_diag()`` and ``disable_diag()`` methods to enable specific diagnostic values (instead of setting them to ``True`` or ``False``). ``enable_all_warnings()`` has also been added. - ``counted_array`` formerly returned its list of items nested within another list, so that accessing the items required indexing the 0'th element to get the actual list. This extra nesting has been removed. In addition, if there are other metadata fields parsed between the count and the list items, they can be preserved in the resulting list if given results names. - ``ParseException.explain()`` is now an instance method of ``ParseException``:: expr = pp.Word(pp.nums) * 3 try: expr.parse_string("123 456 A789") except pp.ParseException as pe: print(pe.explain(depth=0)) prints:: 123 456 A789 ^ ParseException: Expected W:(0-9), found 'A789' (at char 8), (line:1, col:9) To run explain against other exceptions, use ``ParseException.explain_exception()``. - Debug actions now take an added keyword argument ``cache_hit``. Now that debug actions are called for expressions matched in the packrat parsing cache, debug actions are now called with this extra flag, set to ``True``. For custom debug actions, it is necessary to add support for this new argument. - ``ZeroOrMore`` expressions that have results names will now include empty lists for their name if no matches are found. Previously, no named result would be present. Code that tested for the presence of any expressions using ``"if name in results:"`` will now always return ``True``. This code will need to change to ``"if name in results and results[name]:"`` or just ``"if results[name]:"``. Also, any parser unit tests that check the ``as_dict()`` contents will now see additional entries for parsers having named ``ZeroOrMore`` expressions, whose values will be ``[]``. - ``ParserElement.set_default_whitespace_chars`` will now update whitespace characters on all built-in expressions defined in the pyparsing module. - ``camelCase`` names have been converted to PEP-8 ``snake_case`` names. Method names and arguments that were camel case (such as ``parseString``) have been replaced with PEP-8 snake case versions (``parse_string``). Backward-compatibility synonyms for all names and arguments have been included, to allow parsers written using the old names to run without change. The synonyms will be removed in a future release. New parser code should be written using the new PEP-8 snake case names. ============================== ================================ Name Previous name ------------------------------ -------------------------------- ParserElement - parse_string parseString - scan_string scanString - search_string searchString - transform_string transformString - add_condition addCondition - add_parse_action addParseAction - can_parse_next canParseNext - default_name defaultName - enable_left_recursion enableLeftRecursion - enable_packrat enablePackrat - ignore_whitespace ignoreWhitespace - inline_literals_using inlineLiteralsUsing - parse_file parseFile - leave_whitespace leaveWhitespace - parse_string parseString - parse_with_tabs parseWithTabs - reset_cache resetCache - run_tests runTests - scan_string scanString - search_string searchString - set_break setBreak - set_debug setDebug - set_debug_actions setDebugActions - set_default_whitespace_chars setDefaultWhitespaceChars - set_fail_action setFailAction - set_name setName - set_parse_action setParseAction - set_results_name setResultsName - set_whitespace_chars setWhitespaceChars - transform_string transformString - try_parse tryParse ParseResults - as_list asList - as_dict asDict - get_name getName ParseBaseException - parser_element parserElement any_open_tag anyOpenTag any_close_tag anyCloseTag c_style_comment cStyleComment common_html_entity commonHTMLEntity condition_as_parse_action conditionAsParseAction counted_array countedArray cpp_style_comment cppStyleComment dbl_quoted_string dblQuotedString dbl_slash_comment dblSlashComment DelimitedList delimitedList DelimitedList delimited_list dict_of dictOf html_comment htmlComment infix_notation infixNotation java_style_comment javaStyleComment line_end lineEnd line_start lineStart make_html_tags makeHTMLTags make_xml_tags makeXMLTags match_only_at_col matchOnlyAtCol match_previous_expr matchPreviousExpr match_previous_literal matchPreviousLiteral nested_expr nestedExpr null_debug_action nullDebugAction one_of oneOf OpAssoc opAssoc original_text_for originalTextFor python_style_comment pythonStyleComment quoted_string quotedString remove_quotes removeQuotes replace_html_entity replaceHTMLEntity replace_with replaceWith rest_of_line restOfLine sgl_quoted_string sglQuotedString string_end stringEnd string_start stringStart token_map tokenMap trace_parse_action traceParseAction unicode_string unicodeString with_attribute withAttribute with_class withClass ============================== ================================ Discontinued Features ===================== Python 2.x no longer supported ------------------------------ Removed Py2.x support and other deprecated features. Pyparsing now requires Python 3.6.8 or later. If you are using an earlier version of Python, you must use a Pyparsing 2.4.x version. Other discontinued features --------------------------- - ``ParseResults.asXML()`` - if used for debugging, switch to using ``ParseResults.dump()``; if used for data transfer, use ``ParseResults.as_dict()`` to convert to a nested Python dict, which can then be converted to XML or JSON or other transfer format - ``operatorPrecedence`` synonym for ``infixNotation`` - convert to calling ``infix_notation`` - ``commaSeparatedList`` - convert to using ``pyparsing_common.comma_separated_list`` - ``upcaseTokens`` and ``downcaseTokens`` - convert to using ``pyparsing_common.upcase_tokens`` and ``downcase_tokens`` - ``__compat__.collect_all_And_tokens`` will not be settable to ``False`` to revert to pre-2.3.1 results name behavior - review use of names for ``MatchFirst`` and Or expressions containing ``And`` expressions, as they will return the complete list of parsed tokens, not just the first one. Use ``pyparsing.enable_diag(pyparsing.Diagnostics.warn_multiple_tokens_in_named_alternation)`` to help identify those expressions in your parsers that will have changed as a result. - Removed support for running ``python setup.py test``. The setuptools maintainers consider the ``test`` command deprecated (see ). To run the Pyparsing tests, use the command ``tox``. Fixed Bugs ========== - [Reverted in 3.0.2]Fixed issue when ``LineStart()`` expressions would match input text that was not necessarily at the beginning of a line. [The previous behavior was the correct behavior, since it represents the ``LineStart`` as its own matching expression. ``ParserElements`` that must start in column 1 can be wrapped in the new ``AtLineStart`` class.] - Fixed bug in regex definitions for ``real`` and ``sci_real`` expressions in ``pyparsing_common``. - Fixed ``FutureWarning`` raised beginning in Python 3.7 for ``Regex`` expressions containing '[' within a regex set. - Fixed bug in ``PrecededBy`` which caused infinite recursion. - Fixed bug in ``CloseMatch`` where end location was incorrectly computed; and updated ``partial_gene_match.py`` example. - Fixed bug in ``indentedBlock`` with a parser using two different types of nested indented blocks with different indent values, but sharing the same indent stack. - Fixed bug in ``Each`` when using ``Regex``, when ``Regex`` expression would get parsed twice. - Fixed bugs in ``Each`` when passed ``OneOrMore`` or ``ZeroOrMore`` expressions: . first expression match could be enclosed in an extra nesting level . out-of-order expressions now handled correctly if mixed with required expressions . results names are maintained correctly for these expression - Fixed ``FutureWarning`` that sometimes is raised when ``'['`` passed as a character to ``Word``. - Fixed debug logging to show failure location after whitespace skipping. - Fixed ``ParseFatalExceptions`` failing to override normal exceptions or expression matches in ``MatchFirst`` expressions. - Fixed bug in which ``ParseResults`` replaces a collection type value with an invalid type annotation (as a result of changed behavior in Python 3.9). - Fixed bug in ``ParseResults`` when calling ``__getattr__`` for special double-underscored methods. Now raises ``AttributeError`` for non-existent results when accessing a name starting with '__'. - Fixed bug in ``Located`` class when used with a results name. - Fixed bug in ``QuotedString`` class when the escaped quote string is not a repeated character. Acknowledgments =============== And finally, many thanks to those who helped in the restructuring of the pyparsing code base as part of this release. Pyparsing now has more standard package structure, more standard unit tests, and more standard code formatting (using black). Special thanks to jdufresne, klahnakoski, mattcarmody, ckeygusuz, tmiguelt, and toonarmycaptain to name just a few. Thanks also to Michael Milton and Max Fischer, who added some significant new features to pyparsing. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/whats_new_in_3_1.rst0000644000000000000000000002667515134002420015301 0ustar00============================= What's New in Pyparsing 3.1.0 ============================= :author: Paul McGuire :date: October, 2024 :abstract: This document summarizes the changes made in the 3.1.x releases of pyparsing. .. contents:: :depth: 4 Supported Python versions ========================= - Added support for Python 3.12. - All internal string expressions using '%' string interpolation and ``str.format()`` converted to f-strings. New Features ============ - Added new ``Tag`` ParserElement, for inserting metadata into the parsed results. This allows a parser to add metadata or annotations to the parsed tokens. The ``Tag`` element also accepts an optional ``value`` parameter, defaulting to ``True``. See the new ``tag_metadata.py`` example in the ``examples`` directory. Example: .. doctest:: >>> # add tag indicating mood >>> end_punc = "." | ("!" + Tag("enthusiastic")) >>> greeting = "Hello" + Word(alphas) + end_punc >>> result = greeting.parse_string("Hello World.") >>> print(result.dump()) ['Hello', 'World', '.'] >>> result = greeting.parse_string("Hello World!") >>> print(result.dump()) ['Hello', 'World', '!'] - enthusiastic: True - Extended ``expr[]`` notation for repetition of ``expr`` to accept a slice, where the slice's stop value indicates a ``stop_on`` expression: .. testcode:: test = "BEGIN aaa bbb ccc END" BEGIN, END = Keyword.using_each("BEGIN END".split()) body_word = Word(alphas) # new slice syntax support expr = BEGIN + Group(body_word[...:END]) + END # equivalent to # BEGIN + Group(ZeroOrMore(body_word, stop_on=END)) + END print(expr.parse_string(test)) Prints: .. testoutput:: ['BEGIN', ['aaa', 'bbb', 'ccc'], 'END'] - Added new class method ``ParserElement.using_each``, to simplify code that creates a sequence of ``Literals``, ``Keywords``, or other ``ParserElement`` subclasses. For instance, to define suppressible punctuation, you would previously write:: LPAR, RPAR, LBRACE, RBRACE, SEMI = map(Suppress, "(){};") You can now write:: LPAR, RPAR, LBRACE, RBRACE, SEMI = Suppress.using_each("(){};") ``using_each`` will also accept optional keyword args, which it will pass through to the class initializer. Here is an expression for single-letter variable names that might be used in an algebraic expression: .. testcode:: algebra_var = MatchFirst( Char.using_each(string.ascii_lowercase, as_keyword=True) ) - Added new builtin ``python_quoted_string``, which will match any form of single-line or multiline quoted strings defined in Python. - ``Word`` arguments are now validated if ``min`` and ``max`` are both given, that ``min`` <= ``max``; raises ``ValueError`` if values are invalid. - Added '·' (Unicode MIDDLE DOT) to the set of ``Latin1.identbodychars``. - Added ``ieee_float`` expression to ``pyparsing.common``, which parses float values, plus "NaN", "Inf", "Infinity". - Minor performance speedup in ``trim_arity``, to benefit any parsers using parse actions. API Changes =========== - ``Optional(expr)`` may now be written as ``expr | ""`` This will make this code: .. testcode:: "{" + Optional(Literal("A") | Literal("a")) + "}" writable as: .. testcode:: "{" + (Literal("A") | Literal("a") | "") + "}" Some related changes implemented as part of this work: - ``Literal("")`` now internally generates an ``Empty()`` (and no longer raises an exception) - ``Empty`` is now a subclass of ``Literal`` - Added new class property ``identifier`` to all Unicode set classes in ``pyparsing.unicode``, using the class's values for ``cls.identchars`` and ``cls.identbodychars``. Now Unicode-aware parsers that formerly wrote: .. testcode:: ppu = pyparsing.unicode ident = Word(ppu.Greek.identchars, ppu.Greek.identbodychars) can now write: .. testcode:: ident = ppu.Greek.identifier # or ident = ppu.Ελληνικά.identifier - Added bool ``embed`` argument to ``ParserElement.create_diagram()``. When passed as True, the resulting diagram will omit the ````, ````, and ```` tags so that it can be embedded in other HTML source. (Useful when embedding a call to ``create_diagram()`` in a PyScript HTML page.) - Added ``recurse`` argument to ``ParserElement.set_debug`` to set the debug flag on an expression and all of its sub-expressions. - Reworked ``delimited_list`` function into the new ``DelimitedList`` class. ``DelimitedList`` has the same constructor interface as ``delimited_list``, and in this release, ``delimited_list`` changes from a function to a synonym for ``DelimitedList``. ``delimited_list`` and the older ``delimitedList`` method will be deprecated in a future release, in favor of ``DelimitedList``. - ``ParseResults`` now has a new method ``deepcopy()``, in addition to the current ``copy()`` method. ``copy()`` only makes a shallow copy - any contained ``ParseResults`` are copied as references - changes in the copy will be seen as changes in the original. In many cases, a shallow copy is sufficient, but some applications require a deep copy. ``deepcopy()`` makes a deeper copy: any contained ``ParseResults`` or other mappings or containers are built with copies from the original, and do not get changed if the original is later changed. - Added named field "url" to ``pyparsing.common.url``, returning the entire parsed URL string. - Added exception type to ``trace_parse_action`` exception output. - Added ```` tag to HTML generated for railroad diagrams to force UTF-8 encoding with older browsers, to better display Unicode parser characters. - To address a compatibility issue in RDFLib, added a property setter for the ``ParserElement.name`` property, to call ``ParserElement.set_name``. - Modified ``ParserElement.set_name()`` to accept a None value, to clear the defined name and corresponding error message for a ``ParserElement``. - Updated railroad diagram generation for ``ZeroOrMore`` and ``OneOrMore`` expressions with ``stop_on`` expressions. Discontinued Features ===================== Python 2.x no longer supported ------------------------------ Removed Py2.x support and other deprecated features. Pyparsing now requires Python 3.6.8 or later. If you are using an earlier version of Python, you must use a Pyparsing 2.4.x version. Other discontinued / deprecated features ---------------------------------------- - ``ParserElement.validate()`` is deprecated. It predates the support for left-recursive parsers, and was prone to false positives (warning that a grammar was invalid when it was in fact valid). It will be removed in a future pyparsing release. In its place, developers should use debugging and analytical tools, such as ``ParserElement.set_debug()`` and ``ParserElement.create_diagram()``. Fixed Bugs ========== - Updated ``ci.yml`` permissions to limit default access to source. - Updated ``create_diagram()`` code to be compatible with railroad-diagrams package version 3.0. - Fixed bug in ``pyparsing.common.url``, when input URL is not alone on an input line. - Fixed bug in srange, when parsing escaped '/' and '\' inside a range set. - Fixed exception messages for some ``ParserElements`` with custom names, which instead showed their contained expression names. - Fixed bug in ``Word`` when ``max=2``. Also added performance enhancement when specifying ``exact`` argument. - Fixed bug when parse actions returned an empty string for an expression that had a results name, that the results name was not saved. That is: .. doctest:: >>> expr = Literal("X").add_parse_action(lambda tokens: "")("value") >>> result = expr.parse_string("X") >>> result["value"] '' would raise a ``KeyError``. Now empty strings will be saved with the associated results name. - Fixed bug in ``SkipTo`` where ignore expressions were not properly handled while scanning for the target expression. - Fixed bug in ``NotAny``, where parse actions on the negated expr were not being run. This could cause ``NotAny`` to incorrectly fail if the expr would normally match, but would fail to match if a condition used as a parse action returned False. - Fixed ``create_diagram()`` to accept keyword args, to be passed through to the ``template.render()`` method to generate the output HTML. - Fixed bug in ``python_quoted_string`` regex. - Fixed regression in Word(min). - Fixed bug in bad exception messages raised by Forward expressions. - Fixed regression in SkipTo, where ignored expressions were not checked when looking for the target expression. - Updated pep8 synonym wrappers for better type checking compatibility. - Fixed empty error message bug. This _should_ return pyparsing's exception messages to a former, more helpful form. If you have code that parses the exception messages returned by pyparsing, this may require some code changes. - Fixed issue where PEP8 compatibility names for ``ParserElement`` static methods were not themselves defined as ``staticmethods``. When called using a ``ParserElement`` instance, this resulted in a ``TypeError`` exception. - Fixed some cosmetics/bugs in railroad diagrams: - fixed groups being shown even when ``show_groups`` = False - show results names as quoted strings when ``show_results_names`` = True - only use integer loop counter if repetition > 2 New / Enhanced Examples ======================= - Added example ``mongodb_query_expression.py``, to convert human-readable infix query expressions, such as:: a==100 and b>=200 and transform them into an equivalent query argument for the pymongo package:: {'$and': [{'a': 100}, {'b': {'$gte': 200}}]} Supports many equality and inequality operators - see the docstring for the ``transform_query`` function for many more examples. - ``invRegex.py`` example renamed to ``inv_regex.py`` and updated to PEP-8 variable and method naming. - Removed examples ``sparser.py`` and ``pymicko.py``, since each included its own GPL license in the header. Since this conflicts with pyparsing's MIT license, they were removed from the distribution to avoid confusion among those making use of them in their own projects. - Updated the ``lucene_grammar.py`` example (better support for '*' and '?' wildcards) and corrected the test cases! - Added ``bf.py`` Brainf*ck parser/executor example. Illustrates using a pyparsing grammar to parse language syntax, and attach executable AST nodes to the parsed results. - Added ``tag_emitter.py`` to examples. This example demonstrates how to insert tags into your parsed results that are not part of the original parsed text. - Updated example ``select_parser.py`` to use PEP8 names and added Groups for better retrieval of parsed values from multiple SELECT clauses. - Added example ``email_address_parser.py``. - Added example ``directx_x_file_parser.py`` to parse DirectX template definitions, and generate a Pyparsing parser from a template to parse .x files. - ``delta_time``, ``lua_parser``, ``decaf_parser``, and ``roman_numerals`` examples cleaned up to use latest PEP8 names and add minor enhancements. - Fixed bug (and corresponding test code) in ``delta_time`` example that did not handle weekday references in time expressions (like "Monday at 4pm") when the weekday was the same as the current weekday. Acknowledgments =============== Again, thanks to the many contributors who submitted issues, questions, suggestions, and PRs. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/whats_new_in_3_2.rst0000644000000000000000000001350715134002420015270 0ustar00============================= What's New in Pyparsing 3.2.x ============================= :author: Paul McGuire :date: September, 2025 :abstract: This document summarizes the changes made in the 3.2.x releases of pyparsing. .. contents:: :depth: 4 Supported Python versions ========================= - Added support for Python 3.13 and 3.14. - Python versions before 3.9 are no longer supported. Removed legacy Py2.x support and other deprecated features. Pyparsing now requires Python 3.9 or later. If you are using an earlier 3.x version of Python, use pyparsing 3.1; for Python 2.x, use Pyparsing 2.4.7. New Features ============ - Added type annotations to remainder of ``pyparsing`` package, and added ``mypy`` run to ``tox.ini``, so that type annotations are now run as part of pyparsing's CI. - Exception message format can now be customized, by overriding ``ParseBaseException.format_message``:: def custom_exception_message(exc) -> str: found_phrase = f", found {exc.found}" if exc.found else "" return f"{exc.lineno}:{exc.column} {exc.msg}{found_phrase}" ParseBaseException.formatted_message = custom_exception_message - ``run_tests`` now detects if an exception is raised in a parse action, and will report it with an enhanced error message, with the exception type, string, and parse action name. - ``QuotedString`` now handles translation of escaped integer, hex, octal, and Unicode sequences to their corresponding characters. - Defined a more performant regular expression used internally by ``common_html_entity``. - ``Regex`` instances can now be created using a callable that takes no arguments and just returns a string or a compiled regular expression, so that creating complex regular expression patterns can be deferred until they are actually used for the first time in the parser. - Fixed the displayed output of ``Regex`` terms to deduplicate repeated backslashes, for easier reading in debugging, printing, and railroad diagrams. - Railroad diagramming improvements - Updated generated railroad diagrams to make non-terminal elements links to their related sub-diagrams. This *greatly* improves navigation of the diagram, especially for large, complex parsers. - Fixed railroad diagrams that get generated with a parser containing a `Regex` element defined using a verbose pattern - the pattern gets flattened and comments removed before creating the corresponding diagram element. - Added optional argument `show_hidden` to `ParserElement.create_diagram()` to show elements that are used internally by pyparsing, but are not part of the actual parser grammar. For instance, the `Tag` class can insert values into the parsed results but it does not actually parse any input, so by default it is not included in a railroad diagram. By calling `create_diagram()` with `show_hidden = True`, these internal elements will be included. (You can see this in the tag_metadata.py script in the examples directory.) - Fixed the displayed output of `Regex` terms to deduplicate repeated backslashes, for easier reading in debugging, printing, and railroad diagrams. - Simplified railroad diagrams emitted for parsers using `infix_notation()`, by hiding lookahead terms. Renamed internally generated expressions for clarity, and improved diagramming. API Changes =========== Possible breaking changes ------------------------- - Fixed code in ``ParseElementEnhance`` subclasses that replaced detailed exception messages raised in contained expressions with a less-specific and less-informative generic exception message and location. If your code has conditional logic based on the message content in raised ``ParseExceptions``, this bugfix may require changes in your code. - Fixed bug in ``transform_string()`` where whitespace in the input string was not properly preserved in the output string. If your code uses ``transform_string``, this bugfix may require changes in your code. - Fixed bug where an ``IndexError`` raised in a parse action was incorrectly handled as an ``IndexError`` raised as part of the ``ParserElement`` parsing methods, and reraised as a ``ParseException``. Now an ``IndexError`` that raises inside a parse action will properly propagate out as an ``IndexError``. If your code raises ``IndexError`` in parse actions, this bugfix may require changes in your code. Additional API changes ---------------------- - Added optional ``flatten`` Boolean argument to ``ParseResults.as_list()``, to return the parsed values in a flattened list. - Added ``indent`` and ``base_1`` arguments to ``pyparsing.testing.with_line_numbers``. When using ``with_line_numbers`` inside a parse action, set ``base_1`` =False, since the reported ``loc`` value is 0-based. ``indent`` can be a leading string (typically of spaces or tabs) to indent the numbered string passed to ``with_line_numbers``. New / Enhanced Examples ======================= - Added query syntax to ``mongodb_query_expression.py`` with: - better support for array fields ("contains all", "contains any", and "contains none") - "like" and "not like" operators to support SQL "%" wildcard matching and "=~" operator to support regex matching - text search using "search for" - dates and datetimes as query values - ``a[0]`` style array referencing - Added ``lox_parser.py`` example, a parser for the Lox language used as a tutorial in Robert Nystrom's "Crafting Interpreters" (http://craftinginterpreters.com/). - Added ``complex_chemical_formulas.py`` example, to add parsing capability for formulas such as "Ba(BrO₃)₂·H₂O". - Updated ``tag_emitter.py`` to use new ``Tag`` class, introduced in pyparsing 3.1.3. Acknowledgments =============== Again, thanks to the many contributors who submitted issues, questions, suggestions, and PRs. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/whats_new_in_3_3.rst0000644000000000000000000001132015134002420015260 0ustar00============================= What's New in Pyparsing 3.3.x ============================= :author: Paul McGuire :date: December, 2025 :abstract: This document summarizes the changes made in the 3.3.x releases of pyparsing. .. contents:: :depth: 4 Supported Python versions ========================= - Python 3.9 or later is required. - All unit tests pass with Python 3.14, including the free-threaded build ("3.14t"). Note: this does not imply that pyparsing is thread-safe; the tests simply validate that the library runs without errors under the free-threaded interpreter. The test suite does not exercise parsing across multiple threads. New Features ============ - Added AI best-practices guidance for using pyparsing to implement parsers. The guidance is stored in ``pyparsing/ai/best_practices.md`` and can be accessed programmatically via ``pyparsing.show_best_practices()`` or from the command line using ``python -m pyparsing.ai.show_best_practices`` (after installing the ``pyparsing`` package). - Added performance benchmarking tools and documentation: - ``tests/perf_pyparsing.py`` runs a suite of benchmarks that exercise different parts of the pyparsing library. The script can export results as CSV and append to a consolidated data file for cross-version analysis. - Runner scripts ``run_perf_all_tags.bat`` (Windows) and ``run_perf_all_tags.sh`` (Ubuntu/bash) execute the benchmarks across multiple Python versions (3.9–3.14) and pyparsing versions (3.1.1 through 3.3.0), aggregating results into ``perf_pyparsing.csv`` at the repo root. See ``tests/README.md`` for usage. - Improved exception formatting robustness: added exception handling around ``formatted_message()`` to ensure ``str(exception)`` always returns at least some message content, even if formatting fails. API Changes =========== Planned deprecations and guidance for migration ----------------------------------------------- - Beginning with 3.3.0, pyparsing emits ``DeprecationWarning`` for many pre-PEP8 method names (for example, ``ParserElement.parseString``). The PEP8-compliant names were introduced in 3.0.0 (August 2021); the legacy names remain as aliases but are planned to be removed in pyparsing 4.0 (no earlier than 2026). - The warnings raised in pyparsing all inherit from ``PyparsingWarning``, and deprecation warnings are of type ``PyparsingDeprecationWarning``, so these types can be selectively enabled or disabled separately from warnings from other packages in an application. Since these classes inherit from ``UserWarning`` and ``DeprecationWarning``, they can also be handled as those standard types. - A utility script was added in 3.2.2 to help migrate code to PEP8-compliant names: ``pyparsing/tools/cvt_pyparsing_pep8_names.py``. Run it on one or more files; use ``-u`` to update files in place. Example:: python -m pyparsing.tools.cvt_pyparsing_pep8_names -u examples/*.py - Specific deprecations with behavior notes: - ``indentedBlock``: When converted using the migration utility, a ``UserWarning`` is emitted indicating that additional code changes are required. The replacement class ``IndentedBlock`` no longer requires passing an external indent stack, and it adds support for nested indentation levels and grouping. - ``locatedExpr``: When converted using the migration utility, a ``UserWarning`` is emitted indicating that code changes may be required. The PEP8 replacement ``Located`` removes an extra grouping layer from parsed values. If the original ``locatedExpr`` was given a results name, the grouping is retained so that the results-name nesting remains consistent; in that case, no code changes should be required. Discontinued Features ===================== - No removals in 3.3.x; however, pre-PEP8 names are now formally deprecated and scheduled for removal in 4.0. Fixed Bugs ========== - Fixed minor formatting issues in ``pyparsing.testing.with_line_numbers`` discovered while developing the TINY language example. - ``DelimitedList`` and ``nested_expr`` now auto-suppress delimiting commas when the delimiter is already a ``Suppress``; this avoids the need for extra wrapping. New / Enhanced Examples ======================= - Implemented a TINY language parser and interpreter under ``examples/tiny``. The example demonstrates a recommended structure (parser + AST + engine + run) for building a small interpreter with pyparsing. The ``docs`` subdirectory includes transcripts of the AI session used to create the parser and interpreter. - Added railroad diagrams for selected examples. Acknowledgments =============== Again, thanks to the many contributors who submitted issues, questions, suggestions, and PRs. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/docs/whats_new_in_x_x_template.rst.txt0000644000000000000000000000123115134002420020203 0ustar00============================= What's New in Pyparsing 3.x.0 ============================= :author: Paul McGuire :date: month, year :abstract: This document summarizes the changes made in the 3.x.x releases of pyparsing. .. contents:: :depth: 4 Supported Python versions ========================= New Features ============ API Changes =========== Discontinued Features ===================== Other discontinued features --------------------------- Fixed Bugs ========== New / Enhanced Examples ======================= Acknowledgments =============== Again, thanks to the many contributors who submitted issues, questions, suggestions, and PRs. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6886954 pyparsing-3.3.2/examples/AcManForm.dfm0000644000000000000000000011434215134002420014566 0ustar00object Form1: TForm1 Left = 193 Top = 105 Width = 696 Height = 480 Caption = 'AcManTest' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object RichEdit1: TRichEdit Left = 0 Top = 107 Width = 688 Height = 346 Align = alClient Lines.Strings = ( 'RichEdit1') TabOrder = 0 end object ActionToolBar1: TActionToolBar Left = 0 Top = 25 Width = 688 Height = 28 ActionManager = ActionManager1 Caption = 'ActionToolBar1' ColorMap.HighlightColor = 14410210 ColorMap.BtnSelectedColor = clBtnFace ColorMap.UnusedColor = 14410210 EdgeBorders = [ebTop, ebBottom] Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] ParentFont = False ParentShowHint = False ShowHint = True Spacing = 0 end object ActionMainMenuBar1: TActionMainMenuBar Left = 0 Top = 0 Width = 688 Height = 25 UseSystemFont = False ActionManager = ActionManager1 AnimationStyle = asSlide Caption = 'ActionMainMenuBar1' ColorMap.HighlightColor = 14410210 ColorMap.BtnSelectedColor = clBtnFace ColorMap.UnusedColor = 14410210 EdgeBorders = [ebTop, ebBottom] EdgeOuter = esNone Font.Charset = ANSI_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] ParentShowHint = False ShowHint = True Spacing = 0 end object ActionToolBar2: TActionToolBar Left = 0 Top = 53 Width = 688 Height = 28 ActionManager = ActionManager1 Caption = 'ActionToolBar2' ColorMap.HighlightColor = 14410210 ColorMap.BtnSelectedColor = clBtnFace ColorMap.UnusedColor = 14410210 EdgeBorders = [ebTop, ebBottom] Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] ParentFont = False ParentShowHint = False ShowHint = True Spacing = 0 end object ActionToolBar3: TActionToolBar Left = 0 Top = 81 Width = 688 Height = 26 ActionManager = ActionManager1 Caption = 'ActionToolBar3' ColorMap.HighlightColor = 14410210 ColorMap.BtnSelectedColor = clBtnFace ColorMap.UnusedColor = 14410210 Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] ParentFont = False Spacing = 0 end object ActionManager1: TActionManager FileName = 'settings' ActionBars.SessionCount = 4 ActionBars = < item Items = < item Action = EditUndo1 ImageIndex = 3 ShortCut = 16474 end item Action = EditCut1 ImageIndex = 0 ShortCut = 16472 end item Action = EditCopy1 ImageIndex = 1 ShortCut = 16451 end item Action = EditPaste1 ImageIndex = 2 ShortCut = 16470 end item Action = SearchFind1 ImageIndex = 15 ShortCut = 16454 end item Action = SearchReplace1 ImageIndex = 17 end> ActionBar = ActionToolBar1 AutoSize = False end item Items = < item Items = < item Action = FileOpen1 ImageIndex = 12 ShortCut = 16463 end item Action = FileSaveAs1 ImageIndex = 13 end item Action = FilePrintSetup1 end item Action = FileRun1 end item Action = FileExit1 ImageIndex = 14 LastSession = -1 UsageCount = -1 end> Caption = '&File' end item Items = < item Action = EditCut1 ImageIndex = 0 ShortCut = 16472 end item Action = EditCopy1 ImageIndex = 1 ShortCut = 16451 end item Action = EditPaste1 ImageIndex = 2 ShortCut = 16470 end item Action = EditSelectAll1 ShortCut = 16449 end item Action = EditUndo1 ImageIndex = 3 ShortCut = 16474 end item Action = EditDelete1 ImageIndex = 4 ShortCut = 46 end> Caption = '&Edit' end item Items = < item Action = RichEditBold1 ImageIndex = 5 ShortCut = 16450 end item Action = RichEditItalic1 ImageIndex = 6 ShortCut = 16457 end item Action = RichEditUnderline1 ImageIndex = 7 ShortCut = 16469 end item Action = RichEditStrikeOut1 end item Action = RichEditBullets1 ImageIndex = 8 end item Action = RichEditAlignLeft1 ImageIndex = 9 end item Action = RichEditAlignRight1 ImageIndex = 10 end item Action = RichEditAlignCenter1 ImageIndex = 11 end> Caption = 'F&ormat' end item Items = < item Action = SearchFind1 ImageIndex = 15 ShortCut = 16454 end item Action = SearchFindNext1 ImageIndex = 16 ShortCut = 114 end item Action = SearchReplace1 ImageIndex = 17 end item Action = SearchFindFirst1 end> Caption = '&Search' end item Items = < item Action = CustomizeActionBars1 end> Caption = '&Tools' end item Items = < item Action = HelpContents1 ImageIndex = 18 end> Caption = '&Help' end> ActionBar = ActionMainMenuBar1 AutoSize = False end item Items = < item Action = RichEditBold1 ImageIndex = 5 ShortCut = 16450 end item Action = RichEditItalic1 ImageIndex = 6 ShortCut = 16457 end item Action = RichEditUnderline1 ImageIndex = 7 ShortCut = 16469 end item Action = RichEditBullets1 Caption = 'Bull&ets' ImageIndex = 8 end item Action = RichEditAlignLeft1 ImageIndex = 9 end item Action = RichEditAlignRight1 ImageIndex = 10 end item Action = RichEditAlignCenter1 ImageIndex = 11 end> ActionBar = ActionToolBar2 AutoSize = False end item AutoSize = False end item AutoSize = False end item Items = < item Action = FileSaveAs1 ImageIndex = 13 LastSession = 2 end item Action = CustomizeActionBars1 end item Action = FileExit1 ImageIndex = 14 end item Action = HelpContents1 Caption = 'C&ontents' ImageIndex = 18 end item Action = ActionShowStatus Caption = '&ShowStatus' end> ActionBar = ActionToolBar3 AutoSize = False end> Images = ImageList1 Left = 88 Top = 136 StyleName = 'XP Style' object EditCut1: TEditCut Category = 'Edit' Caption = 'Cu&t' Hint = 'Cut|Cuts the selection and puts it on the Clipboard' ImageIndex = 0 ShortCut = 16472 end object EditCopy1: TEditCopy Category = 'Edit' Caption = '&Copy' Hint = 'Copy|Copies the selection and puts it on the Clipboard' ImageIndex = 1 ShortCut = 16451 end object EditPaste1: TEditPaste Category = 'Edit' Caption = '&Paste' Hint = 'Paste|Inserts Clipboard contents' ImageIndex = 2 ShortCut = 16470 end object EditSelectAll1: TEditSelectAll Category = 'Edit' Caption = 'Select &All' Hint = 'Select All|Selects the entire document' ShortCut = 16449 end object EditUndo1: TEditUndo Category = 'Edit' Caption = '&Undo' Hint = 'Undo|Reverts the last action' ImageIndex = 3 ShortCut = 16474 end object EditDelete1: TEditDelete Category = 'Edit' Caption = '&Delete' Hint = 'Delete|Erases the selection' ImageIndex = 4 ShortCut = 46 end object RichEditBold1: TRichEditBold Category = 'Format' AutoCheck = True Caption = '&Bold' Hint = 'Bold' ImageIndex = 5 ShortCut = 16450 end object RichEditItalic1: TRichEditItalic Category = 'Format' AutoCheck = True Caption = '&Italic' Hint = 'Italic' ImageIndex = 6 ShortCut = 16457 end object RichEditUnderline1: TRichEditUnderline Category = 'Format' AutoCheck = True Caption = '&Underline' Hint = 'Underline' ImageIndex = 7 ShortCut = 16469 end object RichEditStrikeOut1: TRichEditStrikeOut Category = 'Format' AutoCheck = True Caption = '&Strikeout' Hint = 'Strikeout' end object RichEditBullets1: TRichEditBullets Category = 'Format' AutoCheck = True Caption = '&Bullets' Hint = 'Bullets|Inserts a bullet on the current line' ImageIndex = 8 end object RichEditAlignLeft1: TRichEditAlignLeft Category = 'Format' AutoCheck = True Caption = 'Align &Left' Hint = 'Align Left|Aligns text at the left indent' ImageIndex = 9 end object RichEditAlignRight1: TRichEditAlignRight Category = 'Format' AutoCheck = True Caption = 'Align &Right' Hint = 'Align Right|Aligns text at the right indent' ImageIndex = 10 end object RichEditAlignCenter1: TRichEditAlignCenter Category = 'Format' AutoCheck = True Caption = '&Center' Hint = 'Center|Centers text between margins' ImageIndex = 11 end object FileOpen1: TFileOpen Category = 'File' Caption = '&Open...' Hint = 'Open|Opens an existing file' ImageIndex = 12 ShortCut = 16463 end object FileSaveAs1: TFileSaveAs Category = 'File' Caption = 'Save &As...' Hint = 'Save As|Saves the active file with a new name' ImageIndex = 13 end object FilePrintSetup1: TFilePrintSetup Category = 'File' Caption = 'Print Set&up...' Hint = 'Print Setup' end object FileRun1: TFileRun Category = 'File' Browse = False BrowseDlg.Title = 'Run' Caption = '&Run...' Hint = 'Run|Runs an application' Operation = 'open' ShowCmd = scShowNormal end object FileExit1: TFileExit Category = 'File' Caption = 'E&xit' Hint = 'Exit|Quits the application' ImageIndex = 14 end object SearchFind1: TSearchFind Category = 'Search' Caption = '&Find...' Hint = 'Find|Finds the specified text' ImageIndex = 15 ShortCut = 16454 end object SearchFindNext1: TSearchFindNext Category = 'Search' Caption = 'Find &Next' Enabled = False Hint = 'Find Next|Repeats the last find' ImageIndex = 16 ShortCut = 114 end object SearchReplace1: TSearchReplace Category = 'Search' Caption = '&Replace' Hint = 'Replace|Replaces specific text with different text' ImageIndex = 17 end object SearchFindFirst1: TSearchFindFirst Category = 'Search' Caption = 'F&ind First' Hint = 'Find First|Finds the first occurrence of specified text' end object CustomizeActionBars1: TCustomizeActionBars Category = 'Tools' Caption = '&Customize' CustomizeDlg.StayOnTop = False end object HelpContents1: THelpContents Category = 'Help' Caption = '&Contents' Enabled = False Hint = 'Help Contents' ImageIndex = 18 end object ActionShowStatus: TAction Category = 'Tools' Caption = 'ShowStatus' OnExecute = ActionShowStatusExecute end end object ImageList1: TImageList Left = 168 Top = 136 Bitmap = { 494C010113001400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000400000005000000001001000000000000028 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 1040104010420000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000010401040 FF7FFF7F18631042000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000010401040FF7FFF7F 0000000018631863104200000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000104210401040FF7FFF7F00000000 1040104000001863186310420000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000001863000000000000 0000000000000000186300000000000000000000000000000000000000000000 00000000000000000000000000000000000010421040FF7F0000000010401040 1040104010400000186318631042000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000010420000 0000000010420000000000000000000000000000000000001863000000000000 0000000000000000186300000000000000001042000000001040104010400042 E07F104010401040000018631863104200000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000010420000 0000000010420000000000000000000000001042104010401040104010401040 0042104010401040104000001863000000000000000000000000000000000000 0000000000000000000000000000000000000000000000001863000000000000 0000186300000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000001040FF7F1040104010401040 1040E07FE07F1040104010400000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000001863000000000000 0000186300000000000000000000000000000000000000001863000000000000 000018630000000000000000000000000000000000001040FF7F104010401040 104010400042E07FE07F10401040000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000001863000000000000 0000186300000000000000000000000000000000000000001040FF7F10401040 104000421040E07FE07F10401040104000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 1042000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000001040FF7F1040 1040E07FE07FE07F104010401040000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 104200000000000000000000000000000000000000000000000000001040FF7F 1040104010401040104000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000001040 FF7F104010400000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 1040104000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000001042104210421042104210421042 104210421042FF7F186310421863FF7F18630000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000001042104210421042104210421042 1042104210421042FF7F1042FF7F104210420000000000000000000000000000 0000000000000000000000000000000000000000000000420042000000000000 0000000000000000000000000042000000000000000000000000000000000000 0000000000000000000000000000000000001000100010001000000000001042 10421042FF7FFF7FFF7F10001000100010000000000000000000000000000000 0000000000000000000000000000000000000000000000420042000000000000 0000000000000000000000000042000000000000000000000000004200420000 00000000000018630000004200000000000000000000000010001F0010000000 00001042FF7FFF7FFF7F10000000000000000000FF7F00000000000000000000 0000000000000000FF7F00000000000000000000000000420042000000000000 0000000000000000000000000042000000000000000000000000004200420000 000000000000186300000042000000000000000000000000100010001F001000 0000FF7FFF7FFF7FFF7F10000000000000000000FF7F00000000000000000000 0000000000000000FF7F00000000000000000000000000420042000000000000 0000000000000000000000000042000000000000000000000000004200420000 00000000000000000000004200000000000000000000000010001F0010001F00 0000FF7FFF7FFF7FFF7F10000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000420042004200420042 0042004200420042004200420042000000000000000000000000004200420042 004200420042004200420042000000000000000000000000100010001F001000 0000FF7FFF03FF7FFF03100000000000000000000000FF7F0000000000000000 00000000FF7F0000000000000000000000000000000000420042000000000000 0000000000000000000000420042000000000000000000000000004200420000 00000000000000000042004200000000000000000000000010001F0010001F00 0000FF03FF7FFF03FF7F100000000000000000000000FF7F0000000000001863 00000000FF7F0000000000000000000000000000000000420000000000000000 0000000000000000000000000042000000000000000000000000004200001863 186318631863186300000042000000000000000000000000100010001F001000 0000FF7FFF03FF7FFF03100000000000000000000000FF7F0000000000001863 00000000FF7F0000000000000000000000000000000000420000000000000000 0000000000000000000000000042000000000000000000000000004200001863 18631863186318630000004200000000000000000000000010001F0010001F00 0000FF03FF7FFF03FF7F10000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000420000000000000000 0000000000000000000000000042000000000000000000000000004200001863 1863186318631863000000000000000000000000000000001000100010001000 100010001000100010001000000000000000000000000000FF7F000000000000 00000000FF7F0000000000000000000000000000000000420000000000000000 0000000000000000000000000042000000000000000000000000004200001863 1863186318631863000018630000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000420000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000420000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000002 0002000200020000000000000000000000000000000000000000FF7F00000000 000000000000FF7F000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000100010001000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000100010001000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000100010001000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000100010001000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000100010001000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000100010001000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000100010001000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000100010001000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000100010001000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000010001000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000001000 1000100010001000100010001000100010000000000000000000000000000000 0000000000000000000000000000000000000000000000000000100000000000 1000000000001000100000000000000000000000000000000000000000000000 1000100010001000100010001000100010000000000000000000000000001000 FF7FFF7FFF7FFF7FFF7FFF7FFF7FFF7F10000000000000000000000000000000 0000000000000000000000000000000000000000000000000000100000000000 1000000010000000000010000000000000000000000000000000000000000000 1000FF7FFF7FFF7FFF7FFF7FFF7FFF7F10000000104200421042004210421000 FF7F000000000000000000000000FF7F10000000000000000000000000000000 0000000000000000000000000000000000000000000000000000100000000000 1000000010000000000010000000000000000000000000000000000000000000 1000FF7F00000000000000000000FF7F10000000004210420042104200421000 FF7FFF7FFF7FFF7FFF7FFF7FFF7FFF7F10000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000010001000 1000000010000000000010000000000000000000000000000000000000000000 1000FF7FFF7FFF7FFF7FFF7FFF7FFF7F10000000104200421042004210421000 FF7F000000000000FF7F10001000100010000000000000000000000000000000 0000000000000000000010000000000000000000000000000000000000000000 10000000100010001000000000000000000000000000FF7FFF7FFF7FFF7FFF7F 1000FF7F00000000000000000000FF7F10000000004210420042104200421000 FF7FFF7FFF7FFF7FFF7F1000FF7F100000000000000010001000100010001000 0000000000000000000010000000000000000000000000000000000000000000 10000000100000000000000000000000000000000000FF7F0000000000000000 1000FF7FFF7FFF7FFF7FFF7FFF7FFF7F10000000104200421042004210421000 FF7FFF7FFF7FFF7FFF7F10001000000000000000000010001000100010000000 0000000000000000000000001000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FF7FFF7FFF7FFF7FFF7F 1000FF7F00000000FF7F10001000100010000000004210420042104200421000 1000100010001000100010000000000000000000000010001000100000000000 0000000000000000000000001000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FF7F0000000000000000 1000FF7FFF7FFF7FFF7F1000FF7F100000000000104200421042004210420042 1042004210420042104200420000000000000000000010001000000010000000 0000000000000000000000001000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FF7FFF7FFF7FFF7FFF7F 1000FF7FFF7FFF7FFF7F10001000000000000000004210420000000000000000 0000000000000000104210420000000000000000000010000000000000001000 1000000000000000000010000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FF7F00000000FF7F0000 1000100010001000100010000000000000000000104210420000000000000000 0000000000000000104200420000000000000000000000000000000000000000 0000100010001000100000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FF7FFF7FFF7FFF7F0000 FF7F0000000000000000000000000000000000000042104200420000E07F0000 0000E07F00001042004210420000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FF7FFF7FFF7FFF7F0000 000000000000000000000000000000000000000000000000000000000000E07F E07F000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000424D3E000000000000003E000000 2800000040000000500000000100010000000000800200000000000000000000 000000000000000000000000FFFFFF00FFFFB6E7FFFF0000FE49B76BFE3F0000 FE498427F81F0000FFFFB76BE00F0000FFFFCEE780070000C7C7FFFF00030000 C7C7C7C700010000C387C7C700000000C007C38700010000C007C00780010000 C007C007C0010000C007C007E0000000C007C007F0000000F39FC007F8030000 F39FF39FFC0F0000F39FF39FFE3F0000FFFFFF7E0000FFFFC001BFFF0000FFFF 8031F003000007C18031E003E00707C18031E003E00707C18001E003E0070101 8001E003E007000180012003E00700018FF1E002E00700018FF1E003E0078003 8FF1E003E007C1078FF1E003FFFFC1078FF1E003F81FE38F8FF5FFFFF81FE38F 8001BF7DF81FE38FFFFF7F7EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 8FFFFFFFFFFFFFFF8C03C007C007C0078FFFFFFFFFFFFFFFFFFFC03FF807F83F FFFFFFFFFFFFFFFF8FFFC007C007C0078C03FFFFFFFFFFFF8FFFC03FF807F01F FFFFFFFFFFFFFFFFFFFFC007C007C0078FFFFFFFFFFFFFFF8C03C03FF807F83F 8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF EFFDFFFFFFFFE00FC7FFFFFFFFFFFFFFC3FBF00F81FFF83FE3F7F8C7E3FFF39F F1E7F8C7F1FFF39FF8CFF8C7F8FFF39FFC1FF80FFC7FF39FFE3FF8C7FE3FF39F FC1FF8C7FF1FF39FF8CFF8C7FF8FF39FE1E7F00FFF03E10FC3F3FFFFFFFFFFFF C7FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFC00FFFF F6CFFE008000FFFFF6B7FE000000FFFFF6B7FE000000FFFFF8B780000000FFF7 FE8F80000001C1F7FE3F80000003C3FBFF7F80000003C7FBFE3F80010003CBFB FEBF80030003DCF7FC9F80070FC3FF0FFDDF807F0003FFFFFDDF80FF8007FFFF FDDF81FFF87FFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000 000000000000} end end ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6915874 pyparsing-3.3.2/examples/LAparser.py0000644000000000000000000005120515134002420014354 0ustar00""" Purpose: Linear Algebra Parser Based on: SimpleCalc.py example (author Paul McGuire) in pyparsing-1.3.3 Author: Mike Ellis Copyright: Ellis & Grant, Inc. 2005 License: You may freely use, modify, and distribute this software. Warranty: THIS SOFTWARE HAS NO WARRANTY WHATSOEVER. USE AT YOUR OWN RISK. Notes: Parses infix linear algebra (LA) notation for vectors, matrices, and scalars. Output is C code function calls. The parser can be run as an interactive interpreter or included as module to use for in-place substitution into C files containing LA equations. Supported operations are: OPERATION: INPUT OUTPUT Scalar addition: "a = b+c" "a=(b+c)" Scalar subtraction: "a = b-c" "a=(b-c)" Scalar multiplication: "a = b*c" "a=b*c" Scalar division: "a = b/c" "a=b/c" Scalar exponentiation: "a = b^c" "a=pow(b,c)" Vector scaling: "V3_a = V3_b * c" "vCopy(a,vScale(b,c))" Vector addition: "V3_a = V3_b + V3_c" "vCopy(a,vAdd(b,c))" Vector subtraction: "V3_a = V3_b - V3_c" "vCopy(a,vSubtract(b,c))" Vector dot product: "a = V3_b * V3_c" "a=vDot(b,c)" Vector outer product: "M3_a = V3_b @ V3_c" "a=vOuterProduct(b,c)" Vector magn. squared: "a = V3_b^Mag2" "a=vMagnitude2(b)" Vector magnitude: "a = V3_b^Mag" "a=sqrt(vMagnitude2(b))" Matrix scaling: "M3_a = M3_b * c" "mCopy(a,mScale(b,c))" Matrix addition: "M3_a = M3_b + M3_c" "mCopy(a,mAdd(b,c))" Matrix subtraction: "M3_a = M3_b - M3_c" "mCopy(a,mSubtract(b,c))" Matrix multiplication: "M3_a = M3_b * M3_c" "mCopy(a,mMultiply(b,c))" Matrix by vector mult.: "V3_a = M3_b * V3_c" "vCopy(a,mvMultiply(b,c))" Matrix inversion: "M3_a = M3_b^-1" "mCopy(a,mInverse(b))" Matrix transpose: "M3_a = M3_b^T" "mCopy(a,mTranspose(b))" Matrix determinant: "a = M3_b^Det" "a=mDeterminant(b)" The parser requires the expression to be an equation. Each non-scalar variable must be prefixed with a type tag, 'M3_' for 3x3 matrices and 'V3_' for 3-vectors. For proper compilation of the C code, the variables need to be declared without the prefix as float[3] for vectors and float[3][3] for matrices. The operations do not modify any variables on the right-hand side of the equation. Equations may include nested expressions within parentheses. The allowed binary operators are '+-*/^' for scalars, and '+-*^@' for vectors and matrices with the meanings defined in the table above. Specifying an improper combination of operands, e.g. adding a vector to a matrix, is detected by the parser and results in a Python TypeError Exception. The usual cause of this is omitting one or more tag prefixes. The parser knows nothing about a a variable's C declaration and relies entirely on the type tags. Errors in C declarations are not caught until compile time. Usage: To process LA equations embedded in source files, import this module and pass input and output file objects to the fprocess() function. You can can also invoke the parser from the command line, e.g. 'python LAparser.py', to run a small test suite and enter an interactive loop where you can enter LA equations and see the resulting C code. """ import re, sys from pyparsing import ( Word, alphas, ParseException, Literal, CaselessLiteral, Combine, Optional, nums, Forward, ZeroOrMore, StringEnd, alphanums, ) # Debugging flag can be set to either "debug_flag=True" or "debug_flag=False" debug_flag = False # ---------------------------------------------------------------------------- # Variables that hold intermediate parsing results and a couple of # helper functions. exprStack = [] # Holds operators and operands parsed from input. targetvar = None # Holds variable name to left of '=' sign in LA equation. def _pushFirst(str, loc, toks): if debug_flag: print("pushing ", toks[0], "str is ", str) exprStack.append(toks[0]) def _assignVar(str, loc, toks): global targetvar targetvar = toks[0] # ----------------------------------------------------------------------------- # The following statements define the grammar for the parser. point = Literal(".") e = CaselessLiteral("E") plusorminus = Literal("+") | Literal("-") number = Word(nums) integer = Combine(Optional(plusorminus) + number) floatnumber = Combine( integer + Optional(point + Optional(number)) + Optional(e + integer) ) lbracket = Literal("[") rbracket = Literal("]") ident = Forward() ## The definition below treats array accesses as identifiers. This means your expressions ## can include references to array elements, rows and columns, e.g., a = b[i] + 5. ## Expressions within []'s are not presently supported, so a = b[i+1] will raise ## a ParseException. ident = Combine( Word(alphas + "-", alphanums + "_") + ZeroOrMore(lbracket + (Word(alphas + "-", alphanums + "_") | integer) + rbracket) ) plus = Literal("+") minus = Literal("-") mult = Literal("*") div = Literal("/") outer = Literal("@") lpar = Literal("(").suppress() rpar = Literal(")").suppress() addop = plus | minus multop = mult | div | outer expop = Literal("^") assignop = Literal("=") expr = Forward() atom = (e | floatnumber | integer | ident).set_parse_action(_pushFirst) | ( lpar + expr.suppress() + rpar ) factor = Forward() factor << atom + ZeroOrMore((expop + factor).set_parse_action(_pushFirst)) term = factor + ZeroOrMore((multop + factor).set_parse_action(_pushFirst)) expr << term + ZeroOrMore((addop + term).set_parse_action(_pushFirst)) equation = (ident + assignop).set_parse_action(_assignVar) + expr + StringEnd() # End of grammar definition # ----------------------------------------------------------------------------- ## The following are helper variables and functions used by the Binary Infix Operator ## Functions described below. vprefix = "V3_" vplen = len(vprefix) mprefix = "M3_" mplen = len(mprefix) ## We don't support unary negation for vectors and matrices class UnaryUnsupportedError(Exception): pass def _isvec(ident): if ident[0] == "-" and ident[1 : vplen + 1] == vprefix: raise UnaryUnsupportedError else: return ident[0:vplen] == vprefix def _ismat(ident): if ident[0] == "-" and ident[1 : mplen + 1] == mprefix: raise UnaryUnsupportedError else: return ident[0:mplen] == mprefix def _isscalar(ident): return not (_isvec(ident) or _ismat(ident)) ## Binary infix operator (BIO) functions. These are called when the stack evaluator ## pops a binary operator like '+' or '*". The stack evaluator pops the two operand, a and b, ## and calls the function that is mapped to the operator with a and b as arguments. Thus, ## 'x + y' yields a call to addfunc(x,y). Each of the BIO functions checks the prefixes of its ## arguments to determine whether the operand is scalar, vector, or matrix. This information ## is used to generate appropriate C code. For scalars, this is essentially the input string, e.g. ## 'a + b*5' as input yields 'a + b*5' as output. For vectors and matrices, the input is translated to ## nested function calls, e.g. "V3_a + V3_b*5" yields "V3_vAdd(a,vScale(b,5)". Note that prefixes are ## stripped from operands and function names within the argument list to the outer function and ## the appropriate prefix is placed on the outer function for removal later as the stack evaluation ## recurses toward the final assignment statement. def _addfunc(a, b): if _isscalar(a) and _isscalar(b): return "(%s+%s)" % (a, b) if _isvec(a) and _isvec(b): return "%svAdd(%s,%s)" % (vprefix, a[vplen:], b[vplen:]) if _ismat(a) and _ismat(b): return "%smAdd(%s,%s)" % (mprefix, a[mplen:], b[mplen:]) else: raise TypeError def _subfunc(a, b): if _isscalar(a) and _isscalar(b): return "(%s-%s)" % (a, b) if _isvec(a) and _isvec(b): return "%svSubtract(%s,%s)" % (vprefix, a[vplen:], b[vplen:]) if _ismat(a) and _ismat(b): return "%smSubtract(%s,%s)" % (mprefix, a[mplen:], b[mplen:]) else: raise TypeError def _mulfunc(a, b): if _isscalar(a) and _isscalar(b): return "%s*%s" % (a, b) if _isvec(a) and _isvec(b): return "vDot(%s,%s)" % (a[vplen:], b[vplen:]) if _ismat(a) and _ismat(b): return "%smMultiply(%s,%s)" % (mprefix, a[mplen:], b[mplen:]) if _ismat(a) and _isvec(b): return "%smvMultiply(%s,%s)" % (vprefix, a[mplen:], b[vplen:]) if _ismat(a) and _isscalar(b): return "%smScale(%s,%s)" % (mprefix, a[mplen:], b) if _isvec(a) and _isscalar(b): return "%svScale(%s,%s)" % (vprefix, a[mplen:], b) else: raise TypeError def _outermulfunc(a, b): ## The '@' operator is used for the vector outer product. if _isvec(a) and _isvec(b): return "%svOuterProduct(%s,%s)" % (mprefix, a[vplen:], b[vplen:]) else: raise TypeError def _divfunc(a, b): ## The '/' operator is used only for scalar division if _isscalar(a) and _isscalar(b): return "%s/%s" % (a, b) else: raise TypeError def _expfunc(a, b): ## The '^' operator is used for exponentiation on scalars and ## as a marker for unary operations on vectors and matrices. if _isscalar(a) and _isscalar(b): return "pow(%s,%s)" % (str(a), str(b)) if _ismat(a) and b == "-1": return "%smInverse(%s)" % (mprefix, a[mplen:]) if _ismat(a) and b == "T": return "%smTranspose(%s)" % (mprefix, a[mplen:]) if _ismat(a) and b == "Det": return "mDeterminant(%s)" % (a[mplen:]) if _isvec(a) and b == "Mag": return "sqrt(vMagnitude2(%s))" % (a[vplen:]) if _isvec(a) and b == "Mag2": return "vMagnitude2(%s)" % (a[vplen:]) else: raise TypeError def _assignfunc(a, b): ## The '=' operator is used for assignment if _isscalar(a) and _isscalar(b): return "%s=%s" % (a, b) if _isvec(a) and _isvec(b): return "vCopy(%s,%s)" % (a[vplen:], b[vplen:]) if _ismat(a) and _ismat(b): return "mCopy(%s,%s)" % (a[mplen:], b[mplen:]) else: raise TypeError ## End of BIO func definitions ##---------------------------------------------------------------------------- # Map operator symbols to corresponding BIO funcs opn = { "+": (_addfunc), "-": (_subfunc), "*": (_mulfunc), "@": (_outermulfunc), "/": (_divfunc), "^": (_expfunc), } ##---------------------------------------------------------------------------- # Recursive function that evaluates the expression stack def _evaluateStack(s): op = s.pop() if op in "+-*/@^": op2 = _evaluateStack(s) op1 = _evaluateStack(s) result = opn[op](op1, op2) if debug_flag: print(result) return result else: return op ##---------------------------------------------------------------------------- # The parse function that invokes all of the above. def parse(input_string): """ Accepts an input string containing an LA equation, e.g., "M3_mymatrix = M3_anothermatrix^-1" returns C code function calls that implement the expression. """ global exprStack global targetvar # Start with a blank exprStack and a blank targetvar exprStack = [] targetvar = None if input_string != "": # try parsing the input string try: L = equation.parse_string(input_string) except ParseException as err: print("Parse Failure", file=sys.stderr) print(err.line, file=sys.stderr) print(" " * (err.column - 1) + "^", file=sys.stderr) print(err, file=sys.stderr) raise # show result of parsing the input string if debug_flag: print(input_string, "->", L) print("exprStack=", exprStack) # Evaluate the stack of parsed operands, emitting C code. try: result = _evaluateStack(exprStack) except TypeError: print( "Unsupported operation on right side of '%s'.\nCheck for missing or incorrect tags on non-scalar operands." % input_string, file=sys.stderr, ) raise except UnaryUnsupportedError: print( "Unary negation is not supported for vectors and matrices: '%s'" % input_string, file=sys.stderr, ) raise # Create final assignment and print it. if debug_flag: print("var=", targetvar) if targetvar != None: try: result = _assignfunc(targetvar, result) except TypeError: print( "Left side tag does not match right side of '%s'" % input_string, file=sys.stderr, ) raise except UnaryUnsupportedError: print( "Unary negation is not supported for vectors and matrices: '%s'" % input_string, file=sys.stderr, ) raise return result else: print("Empty left side in '%s'" % input_string, file=sys.stderr) raise TypeError ##----------------------------------------------------------------------------------- def fprocess(infilep, outfilep): """ Scans an input file for LA equations between double square brackets, e.g. [[ M3_mymatrix = M3_anothermatrix^-1 ]], and replaces the expression with a comment containing the equation followed by nested function calls that implement the equation as C code. A trailing semi-colon is appended. The equation within [[ ]] should NOT end with a semicolon as that will raise a ParseException. However, it is ok to have a semicolon after the right brackets. Other text in the file is unaltered. The arguments are file objects (NOT file names) opened for reading and writing, respectively. """ pattern = r"\[\[\s*(.*?)\s*\]\]" eqn = re.compile(pattern, re.DOTALL) s = infilep.read() def parser(mo): ccode = parse(mo.group(1)) return "/* %s */\n%s;\nLAParserBufferReset();\n" % (mo.group(1), ccode) content = eqn.sub(parser, s) outfilep.write(content) ##----------------------------------------------------------------------------------- def test(): """ Tests the parsing of various supported expressions. Raises an AssertError if the output is not what is expected. Prints the input, expected output, and actual output for all tests. """ print("Testing LAParser") testcases = [ ("Scalar addition", "a = b+c", "a=(b+c)"), ("Vector addition", "V3_a = V3_b + V3_c", "vCopy(a,vAdd(b,c))"), ("Vector addition", "V3_a=V3_b+V3_c", "vCopy(a,vAdd(b,c))"), ("Matrix addition", "M3_a = M3_b + M3_c", "mCopy(a,mAdd(b,c))"), ("Matrix addition", "M3_a=M3_b+M3_c", "mCopy(a,mAdd(b,c))"), ("Scalar subtraction", "a = b-c", "a=(b-c)"), ("Vector subtraction", "V3_a = V3_b - V3_c", "vCopy(a,vSubtract(b,c))"), ("Matrix subtraction", "M3_a = M3_b - M3_c", "mCopy(a,mSubtract(b,c))"), ("Scalar multiplication", "a = b*c", "a=b*c"), ("Scalar division", "a = b/c", "a=b/c"), ("Vector multiplication (dot product)", "a = V3_b * V3_c", "a=vDot(b,c)"), ( "Vector multiplication (outer product)", "M3_a = V3_b @ V3_c", "mCopy(a,vOuterProduct(b,c))", ), ("Matrix multiplication", "M3_a = M3_b * M3_c", "mCopy(a,mMultiply(b,c))"), ("Vector scaling", "V3_a = V3_b * c", "vCopy(a,vScale(b,c))"), ("Matrix scaling", "M3_a = M3_b * c", "mCopy(a,mScale(b,c))"), ( "Matrix by vector multiplication", "V3_a = M3_b * V3_c", "vCopy(a,mvMultiply(b,c))", ), ("Scalar exponentiation", "a = b^c", "a=pow(b,c)"), ("Matrix inversion", "M3_a = M3_b^-1", "mCopy(a,mInverse(b))"), ("Matrix transpose", "M3_a = M3_b^T", "mCopy(a,mTranspose(b))"), ("Matrix determinant", "a = M3_b^Det", "a=mDeterminant(b)"), ("Vector magnitude squared", "a = V3_b^Mag2", "a=vMagnitude2(b)"), ("Vector magnitude", "a = V3_b^Mag", "a=sqrt(vMagnitude2(b))"), ( "Complicated expression", "myscalar = (M3_amatrix * V3_bvector)^Mag + 5*(-xyz[i] + 2.03^2)", "myscalar=(sqrt(vMagnitude2(mvMultiply(amatrix,bvector)))+5*(-xyz[i]+pow(2.03,2)))", ), ( "Complicated Multiline", "myscalar = \n(M3_amatrix * V3_bvector)^Mag +\n 5*(xyz + 2.03^2)", "myscalar=(sqrt(vMagnitude2(mvMultiply(amatrix,bvector)))+5*(xyz+pow(2.03,2)))", ), ] all_passed = [True] def post_test(test, parsed): # copy exprStack to evaluate and clear before running next test parsed_stack = exprStack[:] exprStack.clear() name, testcase, expected = next(tc for tc in testcases if tc[1] == test) this_test_passed = False try: try: result = _evaluateStack(parsed_stack) except TypeError: print( "Unsupported operation on right side of '%s'.\nCheck for missing or incorrect tags on non-scalar operands." % input_string, file=sys.stderr, ) raise except UnaryUnsupportedError: print( "Unary negation is not supported for vectors and matrices: '%s'" % input_string, file=sys.stderr, ) raise # Create final assignment and print it. if debug_flag: print("var=", targetvar) if targetvar != None: try: result = _assignfunc(targetvar, result) except TypeError: print( "Left side tag does not match right side of '%s'" % input_string, file=sys.stderr, ) raise except UnaryUnsupportedError: print( "Unary negation is not supported for vectors and matrices: '%s'" % input_string, file=sys.stderr, ) raise else: print("Empty left side in '%s'" % input_string, file=sys.stderr) raise TypeError parsed["result"] = result parsed["passed"] = this_test_passed = result == expected finally: all_passed[0] = all_passed[0] and this_test_passed print("\n" + name) equation.run_tests((t[1] for t in testcases), post_parse=post_test) ##TODO: Write testcases with invalid expressions and test that the expected ## exceptions are raised. print("Tests completed!") print("PASSED" if all_passed[0] else "FAILED") assert all_passed[0] ##---------------------------------------------------------------------------- ## The following is executed only when this module is executed as ## command line script. It runs a small test suite (see above) ## and then enters an interactive loop where you ## can enter expressions and see the resulting C code as output. if __name__ == "__main__": import sys if not sys.flags.interactive: # run testcases test() sys.exit(0) # input_string input_string = "" # Display instructions on how to use the program interactively interactiveusage = """ Entering interactive mode: Type in an equation to be parsed or 'quit' to exit the program. Type 'debug on' to print parsing details as each string is processed. Type 'debug off' to stop printing parsing details """ print(interactiveusage) input_string = input("> ") while input_string != "quit": if input_string == "debug on": debug_flag = True elif input_string == "debug off": debug_flag = False else: try: print(parse(input_string)) except Exception: pass # obtain new input string input_string = input("> ") # if user types 'quit' then say goodbye print("Good bye!") import os os._exit(0) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6915874 pyparsing-3.3.2/examples/README.md0000644000000000000000000001452515134002420013554 0ustar00# Pyparsing Examples This directory contains a number of examples of parsers created using pyparsing. They fall into a few general categories (several examples include supporting railroad diagrams): * [Pyparsing Examples](#pyparsing-examples) * [Pyparsing tutorial and language feature demonstrations](#pyparsing-tutorial-and-language-feature-demonstrations) * [Language parsers](#language-parsers) * [Domain Specific Language parsers](#domain-specific-language-parsers) * [Search and query language parsers](#search-and-query-language-parsers) * [Data format parsers](#data-format-parsers) * [Logical and arithmetic infix notation parsers and examples](#logical-and-arithmetic-infix-notation-parsers-and-examples) * [Helpful utilities](#helpful-utilities) ## Pyparsing tutorial and language feature demonstrations * Hello World! * [greeting.py](./greeting.py) [(PNG)](./greet.png) * [greetingInGreek.py](./greetingInGreek.py) * [greetingInKorean.py](./greetingInKorean.py) * [hola_mundo.py](./hola_mundo.py) * left recursion * [left_recursion.py](./left_recursion.py) * macro expansion * [macro_expander.py](./macro_expander.py) * Roman numerals * [roman_numerals.py](./roman_numerals.py) [(PNG)](./roman_numerals_diagram.png) * Unicode text handling * [tag_metadata.py](./tag_metadata.py) [(diagram)](./tag_metadata_diagram.html) [(PNG)](./tag_metadata_diagram.png) * chemical formulas * [chemical_formulas.py](./chemical_formulas.py) [(PNG)](./chemical_formulas.png) * [complex_chemical_formulas.py](./complex_chemical_formulas.py) [(PNG)](./complex_chemical_formulas_diagram.png) * API checker * [apicheck.py](./apicheck.py) [(diagram)](./apicheck_diagram.html) [(PNG)](./apicheck_diagram.png) * scan_string examples * [scanExamples.py](./scanExamples.py) * transform_string examples * [include_preprocessor.py](./include_preprocessor.py) * [macro_expander.py](./macro_expander.py) * [nested_markup.py](./nested_markup.py) * parse actions and conditions * [shapes.py](./shapes.py) * [number_words.py](./number_words.py) [(diagram)](./number_words_diagram.html) [(PNG)](./number_words_diagram.png) * [wordsToNum.py](./wordsToNum.py) * [range_check.py](./range_check.py) [(PNG)](./range_check.png) * [one_to_ninety_nine.py](./one_to_ninety_nine.py) [(PNG)](./one_to_99_diagram.png) * railroad diagrams * [railroad_diagram_demo.py](./railroad_diagram_demo.py) [(diagram)](./railroad_diagram_demo.html) [(PNG)](./railroad_diagram_demo.png) * web page scraping * [getNTPserversNew.py](./getNTPserversNew.py) * [html_stripper.py](./html_stripper.py) * [html_table_parser.py](./html_table_parser.py) * [urlExtractorNew.py](./urlExtractorNew.py) ## Language parsers * C * [oc.py](./oc.py) * lua * [lua_parser.py](./lua_parser.py) [(diagram)](./lua_parser_diagram.html) [(PNG)](./lua_parser_diagram.png) * lox * [lox_parser.py](./lox_parser.py) [(diagram)](./lox_parser_diagram.html) [(PNG)](./lox_parser_diagram.png) * verilog * [verilog_parse.py](./verilog_parse.py) * brainf*ck * [bf.py](./bf.py) [(diagram)](./bf_diagram.html) [(PNG)](./bf_diagram.png) * decaf * [decaf_parser.py](./decaf_parser.py) [(diagram)](./decaf_parser_diagram.html) [(PNG)](./decaf_parser_diagram.png) * S-expression * [sexpParser.py](./sexpParser.py) * rosetta code * [rosettacode.py](./rosettacode.py) [(diagram)](./rosettacode_diagram.html) [(PNG)](./rosettacode_diagram.png) * SPy - simplified Python * [spy_parser.py](./spy_parser.py) [(diagram)](./spy_parser_diagram.html) [(PNG)](./spy_parser_diagram.png) * TINY - parser, interpreter, and REPL * [README.md](./tiny/README.md) * [tiny_parser.py](./tiny/tiny_parser.py) [(diagram)](./tiny/tiny_parser_diagram.html) [(PNG)](./tiny/tiny_parser_diagram.png) ## Domain Specific Language parsers * adventureEngine - interactive fiction parser and game runner * [adventureEngine.py](./adventureEngine.py) [(diagram)](./adventure_game_parser_diagram.html) [(PNG)](./adventure_game_parser_diagram.png) * pgn - Chess notation parser * [pgn.py](./pgn.py) * TAP - Test results parser * [TAP.py](./TAP.py) [(diagram)](./TAP_diagram.html) [(PNG)](./TAP_diagram.png) * EBNF - Extended Backus-Naur Format parser (and compiler to a running pyparsing parser) * [ebnf.py](./ebnf.py) [(diagram)](./ebnf_diagram.html) [(PNG)](./ebnf_diagram.png) * [ebnf_number_words.py](./ebnf_number_words.py) [(diagram)](./ebnf_number_parser_diagram.html) [(PNG)](./ebnf_number_parser_diagram.png) ## Search and query language parsers * basic search * [searchparser.py](./searchparser.py) [demo](./searchParserAppDemo.py) * lucene * [lucene_grammar.py](./lucene_grammar.py) [(diagram)](./lucene_grammar_diagram.html) [(PNG)](./lucene_grammar_diagram.png) * mongodb query * [mongodb_query_expression.py](./mongodb_query_expression.py) [(diagram)](./mongodb_query_expression.html) [(PNG)](./mongodb_query_expression.png) * SQL * [select_parser.py](./select_parser.py) (SELECT statements) * [sql2dot.py](./sql2dot.py) (TABLE DML statements) * BigQuery view * [bigquery_view_parser.py](./bigquery_view_parser.py) ## Data format parsers * JSON * [jsonParser.py](./jsonParser.py) * protobuf * [protobuf_parser.py](./protobuf_parser.py) * stackish * [stackish.py](./stackish.py) * CORBA IDL * [idlparse.py](./idlparse.py) ## Logical and arithmetic infix notation parsers and examples * [fourFn.py](./fourFn.py) * [simpleArith.py](./simpleArith.py) * [eval_arith.py](./eval_arith.py) * [simpleCalc.py](./simpleCalc.py) * [LAparser.py](./LAparser.py) (linear algebra) * [simpleBool.py](./simpleBool.py) ## Helpful utilities * parse time expressions ("2pm the day after tomorrow") * [delta_time.py](./delta_time.py) [(diagram)](./delta_time_diagram.html) [(PNG)](./delta_time_diagram.png) * invert regex (generate sample strings matching a regex) * [inv_regex.py](./inv_regex.py) * [PyScript demo page](./regex_inverter/index.html) * email addresses * [email_address_parser.py](./email_address_parser.py) * Excel cell formula * [excel_expr.py](./excel_expr.py) * ctypes interfaces code generator from C include.h file * [gen_ctypes.py](./gen_ctypes.py) * log file parsing * [httpServerLogPaser.py](./httpServerLogPaser.py) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6915874 pyparsing-3.3.2/examples/Setup.ini0000644000000000000000000000264315134002420014074 0ustar00[Startup] AppName=M3i.comm stname = Utility modemid=125D&DEV_1999 audioid=125D&DEV_1998 win98path= winmepath= win2kpath= winxppath= win95path= winnt4path= stupgrade =Install/Upgrade Drivers stuninstall =Uninstall Drivers stchoose =Choose One Function to Process stchoosez3 =Choose Devices to Process copycompl =Copying files completed RemString1=Set up has finished remove ESS device driver and cleaned your system. Click Finish to exit. RemString2=ESS devices is removed completely.No need to reboot. If you want to reinstall, run the setup again with driver package. stshowmsg1=Setup will clean the installed files and update registry. stshowmsg2=Setup is updating system's registry .... stshowmsg3=Setup is starting sysdriver=es56cvmp.sys mdmzn=mdmm3com.inf mdmznp=esmdm_98.inf mdmzna=mdmessa.inf spkname=essspk.exe remvess=remvess.exe slmcat=allem3m.cat audiocat=allem3.cat audioinf=M3i sysaudio=es198xdl.sys audiovxd=es198x.vxd [Languages] Default=0x0009 count=30 key0=0x002d key1=0x0003 key2=0x0804 key3=0x0404 key4=0x001a key5=0x0005 key6=0x0006 key7=0x0013 key8=0x0009 key9=0x000b key10=0x0c0c key11=0x040c key12=0x0007 key13=0x0008 key14=0x000e key15=0x0021 key16=0x0010 key17=0x0011 key18=0x0012 key19=0x0014 key20=0x0015 key21=0x0416 key22=0x0816 key23=0x0019 key24=0x001b key25=0x0024 key26=0x000a key27=0x001d key28=0x001e key29=0x001f [test] foo=bar ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6915874 pyparsing-3.3.2/examples/SimpleCalc.py0000644000000000000000000000713015134002420014655 0ustar00# SimpleCalc.py # # Demonstration of the parsing module, # Sample usage # # $ python SimpleCalc.py # Type in the string to be parse or 'quit' to exit the program # > g=67.89 + 7/5 # 69.29 # > g # 69.29 # > h=(6*g+8.8)-g # 355.25 # > h + 1 # 356.25 # > 87.89 + 7/5 # 89.29 # > ans+10 # 99.29 # > quit # Good bye! # # # Uncomment the line below for readline support on interactive terminal # import readline from pyparsing import ParseException, Word, alphas, alphanums # Debugging flag can be set to either "debug_flag=True" or "debug_flag=False" debug_flag = False variables = {} from fourFn import BNF, exprStack, evaluate_stack # from fourFn import BNF, exprStack, fn, opn # def evaluateStack( s ): # op = s.pop() # if op == 'unary -': # return -evaluateStack( s ) # if op in "+-*/^": # op2 = evaluateStack( s ) # op1 = evaluateStack( s ) # return opn[op]( op1, op2 ) # elif op == "PI": # return math.pi # 3.1415926535 # elif op == "E": # return math.e # 2.718281828 # elif op in fn: # return fn[op]( evaluateStack( s ) ) # elif op[0].isalpha(): # if op in variables: # return variables[op] # raise Exception(f"invalid identifier {op!r}") # else: # return float( op ) arithExpr = BNF() ident = Word(alphas, alphanums).set_name("identifier") assignment = ident("varname") + "=" + arithExpr pattern = assignment | arithExpr if __name__ == "__main__": # input_string input_string = "" # Display instructions on how to quit the program print("Type in the string to be parsed or 'quit' to exit the program") input_string = input("> ") while input_string.strip().lower() != "quit": if input_string.strip().lower() == "debug": debug_flag = True input_string = input("> ") continue # Reset to an empty exprStack del exprStack[:] if input_string != "": # try parsing the input string try: L = pattern.parse_string(input_string, parse_all=True) except ParseException as err: L = ["Parse Failure", input_string, (str(err), err.line, err.column)] # show result of parsing the input string if debug_flag: print(input_string, "->", L) if len(L) == 0 or L[0] != "Parse Failure": if debug_flag: print("exprStack=", exprStack) for i, ob in enumerate(exprStack): if isinstance(ob, str) and ob in variables: exprStack[i] = str(variables[ob]) # calculate result , store a copy in ans , display the result to user try: result = evaluate_stack(exprStack) except Exception as e: print(str(e)) else: variables["ans"] = result print(result) # Assign result to a variable if required if L.varname: variables[L.varname] = result if debug_flag: print("variables=", variables) else: print("Parse Failure") err_str, err_line, err_col = L[-1] print(err_line) print(" " * (err_col - 1) + "^") print(err_str) # obtain new input string input_string = input("> ") # if user type 'quit' then say goodbye print("Good bye!") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6915874 pyparsing-3.3.2/examples/SingleForm.dfm0000644000000000000000000012531415134002420015031 0ustar00object Form1: TForm1 Left = 161 Top = 149 Width = 696 Height = 342 Caption = 'DbxSingle' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object ActionToolBar2: TActionToolBar Left = 0 Top = 0 Width = 688 Height = 26 ActionManager = ActionManager1 AllowHiding = False Caption = 'ActionToolBar2' ColorMap.HighlightColor = 14410210 ColorMap.BtnSelectedColor = clBtnFace ColorMap.UnusedColor = 14410210 Spacing = 0 end object PageControl1: TPageControl Left = 0 Top = 26 Width = 688 Height = 289 ActivePage = TabSheet1 Align = alClient TabOrder = 1 object TabSheet1: TTabSheet Caption = 'Data' object DBGrid1: TDBGrid Left = 0 Top = 0 Width = 680 Height = 261 Align = alClient DataSource = DataSource1 TabOrder = 0 TitleFont.Charset = DEFAULT_CHARSET TitleFont.Color = clWindowText TitleFont.Height = -11 TitleFont.Name = 'MS Sans Serif' TitleFont.Style = [] end end object TabSheet2: TTabSheet Caption = 'Log' ImageIndex = 1 object Memo1: TMemo Left = 0 Top = 0 Width = 680 Height = 399 Align = alClient TabOrder = 0 end end end object SimpleDataSet1: TSimpleDataSet Aggregates = <> Connection.ConnectionName = 'IBLocal' Connection.DriverName = 'Interbase' Connection.GetDriverFunc = 'getSQLDriverINTERBASE' Connection.LibraryName = 'dbexpint.dll' Connection.LoginPrompt = False Connection.Params.Strings = ( 'BlobSize=-1' 'CommitRetain=False' 'Database=C:\Program Files\Common Files\Borland Shared\Data\emplo' + 'yee.gdb' 'DriverName=Interbase' 'Password=masterkey' 'RoleName=RoleName' 'ServerCharSet=ASCII' 'SQLDialect=1' 'Interbase TransIsolation=ReadCommited' 'User_Name=sysdba' 'WaitOnLocks=True') Connection.VendorLib = 'GDS32.DLL' DataSet.CommandText = 'EMPLOYEE' DataSet.CommandType = ctTable DataSet.MaxBlobSize = -1 DataSet.Params = <> Params = <> AfterPost = DoUpdate BeforeDelete = DoUpdate Left = 104 Top = 56 end object ActionManager1: TActionManager ActionBars = < item Items.CaptionOptions = coAll Items = < item Action = DataSetFirst1 ImageIndex = 0 end item Action = DataSetPrior1 ImageIndex = 1 end item Action = DataSetNext1 ImageIndex = 2 end item Action = DataSetLast1 ImageIndex = 3 end item Action = DataSetInsert1 ImageIndex = 4 end item Action = DataSetDelete1 ImageIndex = 5 end item Action = DataSetEdit1 ImageIndex = 6 end item Action = DataSetPost1 ImageIndex = 7 end item Action = DataSetCancel1 ImageIndex = 8 end item Action = DataSetRefresh1 ImageIndex = 9 end> ActionBar = ActionToolBar2 end> Images = ImageList1 Left = 112 Top = 184 StyleName = 'XP Style' object DataSetFirst1: TDataSetFirst Category = 'Dataset' Caption = 'First' ImageIndex = 0 end object DataSetPrior1: TDataSetPrior Category = 'Dataset' Caption = 'Prior' ImageIndex = 1 end object DataSetNext1: TDataSetNext Category = 'Dataset' Caption = 'Next' ImageIndex = 2 end object DataSetLast1: TDataSetLast Category = 'Dataset' Caption = 'Last' ImageIndex = 3 end object DataSetInsert1: TDataSetInsert Category = 'Dataset' Caption = 'Insert' ImageIndex = 4 end object DataSetDelete1: TDataSetDelete Category = 'Dataset' Caption = 'Delete' ImageIndex = 5 end object DataSetEdit1: TDataSetEdit Category = 'Dataset' Caption = 'Edit' ImageIndex = 6 end object DataSetPost1: TDataSetPost Category = 'Dataset' Caption = 'Post' ImageIndex = 7 end object DataSetCancel1: TDataSetCancel Category = 'Dataset' Caption = 'Cancel' ImageIndex = 8 end object DataSetRefresh1: TDataSetRefresh Category = 'Dataset' Caption = 'Refresh' ImageIndex = 9 end end object ImageList1: TImageList Left = 112 Top = 120 Bitmap = { 494C01010C000F00040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000400000004000000001002000000000000040 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000084848400848484008484840084848400848484008484 8400848484000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000848484000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000008484000084 8400000000000000000000000000000000000000000000000000000000000000 0000000000000084840000000000000000000000000000000000000000000000 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 0000848484000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000084848400000000008484840000000000000000000000 0000000000000000000000000000000000000000000000000000008484000084 8400000000000000000000000000000000000000000000000000000000000000 0000000000000084840000000000000000000000000000000000000000000000 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 0000848484000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000848484000000000000000000848484000000000000000000000000000000 0000000000000000000000000000000000000000000000000000008484000084 8400000000000000000000000000000000000000000000000000000000000000 0000000000000084840000000000000000000000000000000000000000000000 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 0000848484000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000084848400000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000008484000084 8400000000000000000000000000000000000000000000000000000000000000 0000000000000084840000000000000000000000000000000000000000000000 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 0000848484000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000008484 8400000000008484840000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000008484000084 8400008484000084840000848400008484000084840000848400008484000084 8400008484000084840000000000000000000000000000000000000000000000 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 0000848484000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000008484000084 8400000000000000000000000000000000000000000000000000000000000000 0000008484000084840000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000008484000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000084840000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000008484840000000000000000000000000084848400000000000000 0000000000000000000000000000000000000000000000000000008484000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000084840000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000008484 8400000000000000000084848400000000008484840000000000000000000000 0000000000000000000000000000000000000000000000000000008484000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000084840000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000008484 8400000000000000000000000000000000000000000000000000008484000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000084840000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000008484840000000000000000000000000084848400000000000000 0000000000000000000000000000000000000000000000000000008484000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000008484000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000848484000000000000000000000000000000000000000000000000008484 8400000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000084848400000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000084848400000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000848484000000000000000000000000000000000000000000000000008484 8400000000000000000000000000000000000000000000000000000000000000 0000848484000000000000000000000000000000000084848400000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000848484000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008484840000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000084848400000000000000000000000000000000008484 8400000000000000000000000000000000000000000000000000000000000000 0000848484000000000000000000848484000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000008484840000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000848484000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008484840000000000000000008484 8400000000000000000000000000000000000000000000000000000000000000 0000848484008484840000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000848484008484 8400000000000000000000000000000000000000000000000000000000000000 0000848484000000000000000000848484000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000008484840000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000848484000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008484840000000000000000008484 8400000000000000000000000000000000000000000000000000000000000000 0000848484000000000000000000000000000000000084848400000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000848484000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008484840000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000084848400000000000000000000000000000000008484 8400000000000000000000000000000000000000000000000000000000000000 0000848484000000000000000000000000000000000000000000000000008484 8400000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000084848400000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000084848400000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000848484000000000000000000000000000000000000000000000000008484 8400000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000424D3E000000000000003E000000 2800000040000000400000000100010000000000000200000000000000000000 000000000000000000000000FFFFFF0000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000FFFFFFFFFFFFFC07FFFFFFFFC001F807 FFFFFFFF8031F807FFFFFC7F8031F807F3E7F0FF8031F807F1C7F1FF8001F807 F88FE3FF8001F807FC1FE7FF8001F80FFE3FE7078FF1FF7FFC1FE3878FF1FE3F F88FE1078FF1FC1FF1C7F0078FF1FFFFF3E7F8378FF1FEFFFFFFFFFF8FF5FFFF FFFFFFFF8001FDFFFFFFFFFFFFFF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7FFFFFFFFFFBFFFC7FFFFFFFFFF1FF FC7FFFFFE007E0FFE00FE007F00FC47FE00FE007F81FCE3FE00FE007FC3FFF1F FC7FFFFFFE7FFF8FFC7FFFFFFFFFFFC7FC7FFFFFFFFFFFE7FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7FF9FF9FFE7E7 E787FE1FF87FE1E7E607F81FF81FE067E007F01FF80FE007E607F81FF81FE067 E787FE1FF87FE1E7E7E7FF9FF9FFE7E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000 000000000000} end object DataSource1: TDataSource DataSet = SimpleDataSet1 Left = 108 Top = 250 end object SQLMonitor1: TSQLMonitor OnTrace = SQLMonitor1Trace Left = 228 Top = 122 end end ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.6915874 pyparsing-3.3.2/examples/TAP.py0000644000000000000000000001720015134002420013264 0ustar00# # TAP.py - TAP parser # # A pyparsing parser to process the output of the Perl # "Test Anything Protocol" # (https://metacpan.org/pod/release/PETDANCE/TAP-1.00/TAP.pm) # # TAP output lines are preceded or followed by a test number range: # 1..n # with 'n' TAP output lines. # # The general format of a TAP output line is: # ok/not ok (required) # Test number (recommended) # Description (recommended) # Directive (only when necessary) # # A TAP output line may also indicate abort of the test suit with the line: # Bail out! # optionally followed by a reason for bailing # # Copyright 2008, by Paul McGuire # from pyparsing import ( ParserElement, LineEnd, Optional, Word, nums, Regex, Literal, CaselessLiteral, Group, OneOrMore, Suppress, rest_of_line, FollowedBy, empty, autoname_elements, ) __all__ = ["tapOutputParser", "TAPTest", "TAPSummary"] # newlines are significant whitespace, so set default skippable # whitespace to just spaces and tabs ParserElement.set_default_whitespace_chars(" \t") NL = LineEnd().suppress() integer = Word(nums) plan = "1.." + integer("ubound") OK, NOT_OK = map(Literal, ["ok", "not ok"]) testStatus = OK | NOT_OK description = Regex(r"[^#\n]+") description.set_parse_action(lambda t: t[0].lstrip("- ")) TODO, SKIP = map(CaselessLiteral, "TODO SKIP".split()) directive = Group( Suppress("#") + ( TODO + rest_of_line | FollowedBy(SKIP) + rest_of_line.copy().set_parse_action(lambda t: ["SKIP", t[0]]) ) ) commentLine = Suppress("#") + empty + rest_of_line testLine = Group( Optional(OneOrMore(commentLine + NL))("comments") + testStatus("passed") + Optional(integer)("testNumber") + Optional(description)("description") + Optional(directive)("directive") ) bailLine = Group(Literal("Bail out!")("BAIL") + empty + Optional(rest_of_line)("reason")) tapOutputParser = Optional(Group(plan)("plan") + NL) & Group( OneOrMore((testLine | bailLine) + NL) )("tests") autoname_elements() class TAPTest: def __init__(self, results): self.num = results.testNumber self.passed = results.passed == "ok" self.skipped = self.todo = False if results.directive: self.skipped = results.directive[0][0] == "SKIP" self.todo = results.directive[0][0] == "TODO" @classmethod def bailedTest(cls, num): ret = TAPTest(empty.parse_string("")) ret.num = num ret.skipped = True return ret class TAPSummary: def __init__(self, results): self.passedTests = [] self.failedTests = [] self.skippedTests = [] self.todoTests = [] self.bonusTests = [] self.bail = False if results.plan: expected = list(range(1, int(results.plan.ubound) + 1)) else: expected = list(range(1, len(results.tests) + 1)) for i, res in enumerate(results.tests): # test for bail out if res.BAIL: # ~ print "Test suite aborted: " + res.reason # ~ self.failedTests += expected[i:] self.bail = True self.skippedTests += [TAPTest.bailedTest(ii) for ii in expected[i:]] self.bailReason = res.reason break # ~ print res.dump() testnum = i + 1 if res.testNumber != "": if testnum != int(res.testNumber): print("ERROR! test %(testNumber)s out of sequence" % res) testnum = int(res.testNumber) res["testNumber"] = testnum test = TAPTest(res) if test.passed: self.passedTests.append(test) else: self.failedTests.append(test) if test.skipped: self.skippedTests.append(test) if test.todo: self.todoTests.append(test) if test.todo and test.passed: self.bonusTests.append(test) self.passedSuite = not self.bail and ( set(self.failedTests) - set(self.todoTests) == set() ) def summary(self, showPassed=False, showAll=False): testListStr = lambda tl: "[" + ",".join(str(t.num) for t in tl) + "]" summaryText = [] if showPassed or showAll: summaryText.append(f"PASSED: {testListStr(self.passedTests)}") if self.failedTests or showAll: summaryText.append(f"FAILED: {testListStr(self.failedTests)}") if self.skippedTests or showAll: summaryText.append(f"SKIPPED: {testListStr(self.skippedTests)}") if self.todoTests or showAll: summaryText.append(f"TODO: {testListStr(self.todoTests)}") if self.bonusTests or showAll: summaryText.append(f"BONUS: {testListStr(self.bonusTests)}") if self.passedSuite: summaryText.append("PASSED") else: summaryText.append("FAILED") return "\n".join(summaryText) # create TAPSummary objects from tapOutput parsed results, by setting # class as parse action tapOutputParser.set_parse_action(TAPSummary) def main(): import contextlib with contextlib.suppress(Exception): tapOutputParser.create_diagram("TAP_diagram.html", vertical=3) test1 = """\ 1..4 ok 1 - Input file opened not ok 2 - First line of the input valid ok 3 - Read the rest of the file not ok 4 - Summarized correctly # TODO Not written yet """ test2 = """\ ok 1 not ok 2 some description # TODO with a directive ok 3 a description only, no directive ok 4 # TODO directive only ok a description only, no directive ok # Skipped only a directive, no description ok """ test3 = """\ ok - created Board ok ok not ok ok ok ok ok # +------+------+------+------+ # | |16G | |05C | # | |G N C | |C C G | # | | G | | C +| # +------+------+------+------+ # |10C |01G | |03C | # |R N G |G A G | |C C C | # | R | G | | C +| # +------+------+------+------+ # | |01G |17C |00C | # | |G A G |G N R |R N R | # | | G | R | G | # +------+------+------+------+ ok - board has 7 tiles + starter tile 1..9 """ test4 = """\ 1..4 ok 1 - Creating test program ok 2 - Test program runs, no error not ok 3 - infinite loop # TODO halting problem unsolved not ok 4 - infinite loop 2 # TODO halting problem unsolved """ test5 = """\ 1..20 ok - database handle not ok - failed database login Bail out! Couldn't connect to database. """ test6 = """\ ok 1 - retrieving servers from the database # need to ping 6 servers ok 2 - pinged diamond ok 3 - pinged ruby not ok 4 - pinged sapphire ok 5 - pinged onyx not ok 6 - pinged quartz ok 7 - pinged gold 1..7 """ for test in (test1, test2, test3, test4, test5, test6): print(test) tapResult = tapOutputParser.parse_string(test)[0] print(tapResult.summary(showAll=True)) print() if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/TAP_diagram.html0000644000000000000000000007114615134002420015275 0ustar00

tapOutputParser

planplan plan NLNL testLinetestLine bailLinebailLine NLNL tests [ALL]

plan

'1..' W:(0-9)

testLine

'#' [suppress] emptyempty rest of linerest of line NLNL 'ok' 'not ok' integerinteger descriptiondescription directivedirective

integer

W:(0-9)

description

[^#\n]+

directive

'#' [suppress] TODOTODO rest of linerest of line SKIPSKIP [LOOKAHEAD] rest of linerest of line

TODO

'TODO'

SKIP

'SKIP'

bailLine

'Bail out!' emptyempty rest of linerest of line

empty

Empty

rest of line

.*

NL

end of lineend of line [suppress]

end of line

LineEnd
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/TAP_diagram.png0000644000000000000000000023167315134002420015120 0ustar00PNG  IHDRIDATx \5AM2LZkbZb7ѴSI;2yyIQQ5 `*@ `*@ `*@ `*@ `*@ ,!-饄&$!OjˢOg_TBhpy1'=w@x\%a6s]dVRƩ2n$3K[f-inWs )zklf!q9ldMjZs&l 2"o&*<&E.(NY6]zV]ȑ6ı^{^y$ZqrWX-8)L߽LYK5S^H h܌U\4 Y%FhK,C{5;iua1e,Sf =Ɋ ָwYS*!G%H.%_62kZvѱ ަz]YE_hLU ,ZD\ܴ!q xGxdMIM iW+jVk"w+DEkծPAPX8+үېpnnqbaᵳ;zV 7s4j;ޛsgh91aoe˅&i.ApeQهyn6a]56 'ܤTCpBm>Z+mq&7nGʊsig .%˼g6_&$~gvk b3VZ)wBn,駓{ܺ8ȟJ?#c\ 7xq0' yVO1i24$u~zA[E/-8igyL%MPlNK4qJMM԰RpxC-WYrϩt\."/TZ&ėy-EIRyYY]\ [[7XssSiȍb߬2}nBCj6}s] =. NTFk K8CdRiJ9JI к)E)'.U+!LgHnn o;[6#"TIC^ƚȧ"}5QWڌHakaD)i<+LtyKִC])/.,l\p 1;h<+z,s'ܺ9 +KT&o񱌘 mqNkuV|=0cKdw@hDB^%aKG5B\VgQKch$5/F4ƸcxIJKyYqfg axXF\gFԞc CE%WjxB8:.Dg?bba~|MK_ 2H2ݺx{?/XZfB[@dL跩|L{j/Cd$&]r glW7<\cԒSQQ.%xVg͑^F_*D<Ӭ`9&;ĄRgy[ǤI1e/#5Gvny-L/9%k*"geYIR3]a6ƖZ+08_PN P0@U T P0@U T P0@U T P0@U T P0@U T P0@U T PFA_ۭE+7&m,OndGҢU&\BeSQQQ3.ɛQf)~#3:d/]3MKVE9L ɢK+5}^Yb]QOOWw+ʩK~dGيR<9J $/w]G]b@k.M&_a~hs6g*f/dݪ‰Ҳ(_8ƥgfcZ ?r` e>JM>}Rf{Ie\54\*9uy+]ҝ&[G s Ur HPAv[hVv܆ ٰ8 l[5twޤ={*/76WUZK2L岕O*9ygnNmOtNG,X0BXsyԇ'&۵gm7DFucM:}R}ɚ Xs}B7WGO[[ڦͭ"IDATP?NO. [.<0J$vʾݻukߟyy=/ݻ3p0a{N9(8vٻ7iR;Ν: Cv.,,SU{ Omqyk=Jɩ5e~˗/LI)**^ Ɲv?qK)4G۷k׳g=8VVxuV,0S6]KjrBebg0t޾?X^pe^>6wX=u>/p7 }~N{V2fIo{{\rE*`O-.\P -Z1G5۾'ڸvIoVn޲e1Q?&` `֕+W^} Věvv])׮]":yTpqq(:Q#>TvCzbVlڴT>v,kmp\d֦[wQhSʦpH4 ؞Tзo_;ԯo/$Ro%)whN*~}ء~ G.rs㲧 tߕB__;rrrڹ@UnR~ѰcOį 8K{__ætx`ޅt`U`ԻmSZrMl&KU1YtP,lb׆i|ZMd\40z7tՅ b .K{qKg$J7뛅yq}~2TҔ%/L[h?wHK4vx&{s`/--(q>K=2 *\ oGwr޶&ӽ㙢ùUr^GXRbjZ2]EJѰ`4ςz/S:3g'H,|W%GL=U+6'\4T`?w[=j|t#wgJ=.ۭ8CO:j*>w$>*EF19Mz0ғpnUXψkH0C@)OxhV7Jm=yrޤ={*=~ UO^̞pYaaC7]ga~y-nQstF=/?\ɉ {Тyw>z4TTTTጋ#h.˫~co}1ǻis7 >t; >I?KD? RxS O^n'_?4sq,{ + ˞|SX:"`ݴžϼラxzxt)<{ '~UIڧ|{{U zb_~":`k=]#Ա?4D7֭/Ũ͛5 玟 `8un#2dʌմiS/)\֝aZ5ԥsgp*`hj&7Õ` Bq`iJ]&:V6UVJ%Q fVD[;sFݹӻw.`l:vZ9fMر/^0M6JN#qq0j{UalRHKK"rssc׮Ucx@nmxb׮V8"{=!Ck_!yyR٫kWn :V{$#?2%a&'''8{jоr_g^K$/uFƍ/^R޵{s ն?9w~?Xܝ6h>X`YDXA^7L})%¿qnm o3QQ[|P{-pfdf*S}|}{k]Mh>r_k*DM/ kXf^>JYz<4ab{K2HƝv?qK)TCǏ/?}oRRVnf`D= jQs5Q9iTvxxIЊrZM]Mu:fUʪlfUS$j+'ʩǧ k0~%>^?qϠA?=ھ]={8ƞZc׭WnON+V~oӧO 47ةk";`pomXUƁ{]m2M}Wv(l]& }{vKeI, @6dͧ JyFh趯5iW*]%~>n_FnTZI?s*G~RT uܺ[A \~}RcGÇ6nXCd _)h/*I;U+6ںm6r*mlRi;(`=V?<^Ԁ:9}}7L2mW^^Ç}&ߍ0,55U)Wj{٪7hπn6,U `~ Grsmօ XU/\(Μ9s뭷VV4D yRa n[gOגEkn H:nyY@\\\]Qۜ9{V*ۙPJ48׷`[]tG2mѢEɹ{MׯKkVTEݺcַ".|9^8^rE*j{mͳnrNNN;D)׬la?d͐{`O]k{EY49p(gW^ݵ{OCnZ.; n0`ԇ!-Zۧ~˻M؏I%Pz>K<<: z`''eoaaѫ*sA;aV۵KFhԈw4_eU~듓Nv$vvum5{<0 Z04iҹS?$Y~nYZE\/HWjSep ΢H`aZ2ʥYTW@nWK[ ;D 0@U T jĞp5Bh*OIDAT@=uBÌ{ '~Uj0 4@ 񥓗eZ6e619MFOP/5V4Vn-[oSS4]?EMT;>-ӕV_iʝ?Wj~2 W/GѡmI[!;iʙ6(ys'NLPƍ?8_*K;g\j)٢E Q6|q]iiO8}@U4G۷k׳g5iӦVZ٭ۡT|,+kv\S9EԥӞ @u۷+Vv)Õz{Av挨_6; 4 t.]\/_>~kOچ\a_-UtP)Q炂#F>oE)Pk7~ݻwW\`ɓ'|a5iKƬZ\ ر۶ GjH6oQ #GqGGzy M1Vb׭W [$Tзos[r(¹j׷_n )\-l2P[+{aOy'~Uԍ\ЯokpX!77;"a571~inxuWwAwW|5jt3g\rn]Mޮ]1~~7mWiJ]#˟@bN5<:[~;sڵkq/Xl[6*}̤Bzzz?fVgwbz Xp!j4yUM6J!-=]u ޽zzPϫ*>>J!-d ^=Ʈ]fB=/v{EhUaCvj~'B c΢H&` _g^KDh3+G9vX)lOƍ/zW)ڽ;|k׮ k5OZq'_)-~:ִe>f/Ι+`T''o+fuWNγ,_>bI7+=K}f(/rПVnRQFXƤEVݎmaB`:^`ېJ~ޏR{`vE#?<価D)?UتWt05~*$m}ozp8 g$>5&P> >tD,|W/# yh$'``j0WjHٹkW<==;oΝ ,c%MJ2R\rmc- Eȅ('(D3]Q'ۇHG)4E]TeViqWRS݊Bc<5oPUAr*)L*{4Hjm߮]Ϟ=|`ȦM U!ׯ~+ݦ==_v5n{X(XSN+~_J)5a 6!qQ[9QVNRȯي(s+ThK|t,y^iUzS +Aʑ[V(bR3|SLlgߨ\ (cZiV٠%;V(s*+5o-W]$NSNRb֯)?p։jۅUT:ujXD>}z 7R С>)FWgNM3&:꧟7ۘSMibh{Q{ͳ_&TZQv[ѐv}O4'S>G.MR`ѻĭ&5Js3\xA2gzgȯJ7g_{K)ii{%۷τUj8R IvJ!K%^6UutMK|m:Q~\^xέ#F uUz_dR]ti^^G{-h֬Yʍ7n3BCWG٪m*n-Ⅎ븶K/~vQoPbT\U>’U[.QQӧGŊD-|^|&;[EurA4+|@{~8Ʈ[yk0Mոnu# *g51(aMS(sWt5꒶}{vK_?9y'UWr>h8qY4>̾tmo/En]ΟRT# Se.5baC ZM4d5OO7\Dj{+Fl5m+)VUdoJ2Tj -̠YyJr_8Q^£2ԤT!%gk׮ lr+>𰨾qE׈952kUMt/ XB+%EqMo2wގz 7q;(NC v`5n_?*i-~vŒ-]l+W}IY%6V';` .;v<|`ƍE5m>+\ ?* JQ9N_...EG[+ ]YRұcY[mo Q8im-Ja;(KC=/zy M> Q# P'*}zPϋ*3#)Vgs\ЯoQyQ~ "77gxnmJ[ԣzx^=iԨϜ9sʕnAߌ|+56JQ| Pb[fU/ٯ.)(znC=/[~;sڵk:^zIDATwÇӔgGE)HQyjW `M6J!MX4Ch;@%hڄƋPs$^*?H)KT[̞pC ا1ǟHص랟f=umJnnnڵJyVSp` D,3lnZЏDȔ"k~cOKe]^<#kܸE*]wϝWϣ9/ٳwR%NNNy`8AmR^!QڟܻOP OAnR~+J\iu.Hڷ?|ࡾ~;!8Q2R{oRҾ={LJq˞ ZwNʕfWYM6UhEaa᧱mӥ᝻v Ta>(F8#G2B֭+΢HhXv͞ Pڴit͒_炑#'?9pks^ })(lmV iiͯ_ڑ=(PMR鎔~E/h {9ŕfKƍcmFhU -ŕfT\[e4✹W\lTl%4~TCR?9YS (R X[ǫ\{^%fdf 8p_/M C^x? 8:pդze\Yl_2eK|ta4 ؂  7iRΰ%мY3{Fڽ-o[n,*7oq?ۦ\駦?իד']]]=  wYXQF̘>%dRum=C,hԽ - 3{ ڷ@j 29D յ= 4@ R5n *R֮_/G{u͏~I/6ǏkVgO8vzpa5jRʕ+7p6WV:'cYٽ}{B իW=yį?~ĂK8\jƍ ={ S3s[rogHݻ:0|Ro ݵ[):zz0Tc6lPT^]*Ƒ#JuVa8iF):gЄ7o\phzF5QONKS @ss}|{#thS3gŋJqNf@e*S6+hѢU˖MMu{%P*q|1,T v OHpޟݝ+77Wyy6}~4o*t6th7V*'BT]~'Bյ}+P'7nxwݻ_3ʕ+lk={*wtI.&,Tn8X2ٿPGE ?t(E؟,횖B;+lf??z8`)^{*7#3snȈ_z4mT@*,, ]BRjKq%rrr W>G3j, FSd29/fQ5/!;pyv벨8766Ą8~~RÍk#XEE>},Vpd\T;8$@#-!-}XFLpX@/,!CR^F\g7:=DŽ OߌDeb47XSQQQsV>}xtbBqD؀&~%`}`ΓiIu7'BkU”p`ksMbQ )3{;&z gNq>c'4-kS/XE-^ey EAP9Z'aYڈT A P0@U T P0@U T P0@U T P0@U T P0@U T||`Լ`h `*@ `*@ `*@ `*@ v7|q]iiO8}hP-[mN:Mu#G?zS/aoڶm۾]={8SQQQ3.mrB>zTؤƍ?YXOAA~ׯ GѹSW#lXt7IDAT=~~caRxinxuZEUm>95᫓'OJgk6jd/~`OTW5)/n74GmX=M({FӮS;Qh}}|%z )\8''Sʏ~\ԑyN'm%ME3W%ѱ[GJ^SNM5ԽnObe CcYݝ.|(%ETSҾJERD)yr![sn;/?l'>{-]{fO-Æ/w6oބyEw}Jysϊ {90з}$rX.Om^*^~=p%zuz} *{jܵ+`(\f 9[rn/>55_77W| jaZl)Ξ>K.\xY8t}4Ya3k~<;kV 9t(ts`Ϟzsv$l- (ROPL7Lagy 04rᎳ2w3gu,ӡXPA6/5&<[bLȨVB"㢂,<'&@_%prm`~QY Zt''4xwHLFe''_J iݜZ>X8'6Hs䷾:[h{xn41K뿷#~ճN_/rma-N?}lË/=zr7t%58k|a>5ӆ%Հ^#/2G |lcEͲ91&~+=&m.vDf @ZNMTE!対{į2LфDZ@ܱY}8 pᡲ g~[-󖒎Ef5eaDݹ̜ϧwpf-OoνZ V sQn! 9N>lpT#DI;,?CTB[~~p?s[&6@Ex9%glajV|)ᰤxzF$d.O)+} 77gaWBBCCC4O?RSfTdbKyQa:){xV7K9anrݐәr 7/8!<sωZ|L^L T] RIDAT)9qc斛/%z.6xי{ul^)^'\1tA)hCsNo_6iWQ{4gYT٘~%Z]U<':Ϝ ӯ34Ͻ&lX#E%oK lr-lOWN:ea 0@U T P0@U T P0@U T P0@U T P0@U T P0@U T PJP/tcT P0@U T P0@U @ `*@ `*xgwڕ~ĉ.;szԲe۶ԩ_ݴZTTTTጋ=۟<П5M/a qm+_vvv5o*P s9sX ڵk-w_ ;Gk.((>bnn3}G;vU@?6'$(ѫF Һ<4a':Z+?\>%8Tvvvޖ߻w/G5m_œ~؎ONٱ6* Lvu8-W\ɓ'ר mݺmryG-q"b|WJuqq(: 6 6+M(#︣[ܳS ))OSSSB߾}ذYfJPJ@p#5jԨ_?@p|ߕB__[)9sF^4z^&P/U TVe۔ZMاe>vJU!¹UC}r.q} P5peMU99(5NyU6<~ۋ}ҞpW[?~}~/'WX^ | l9i%/<׹bs+׏aHN4 ;Y6;vx c%r5i) <5NWz̐BCQJˆv2TH9ݕWG/*hҧKF63ַ{\"'[LعmM<=JLM+Ki|s^DJ$ P;pllCfoN3ңςJ$>~16g/'ޮ Y+yM$R}giiQJr]q'G<39= ]->b[=jԔīR2K /XUj{yUK`44Bd=pH||BҾG=y_%Y˖-oo۶SN~tj쓃}2A~>z}v={8Q#6m*@aa[vڕ~ĉ.;sUNI25Poep$NEEEθx>_ؕܔ…syص(U'E'mo~޻/'[=gx] >O-18T9i$\Ro>ڵIw⍅o. 憿47\BAA~ׯ GԸqg6/;;; dViJMw;w^|UONT*{^X]+O[ 1QN붯,;~vOY:o z- [_}z&MrXp\׮]{oɿ7oQLt_Y]RF|}3{V N7p˗/+YUYcH] !SRÑ&w|8|McXI1b]tf߇8O? BfnUc69ɩV,GdVիW"KKK_tv޳e͚5 1RJM]i|=wرwEouuSO .Х$lݖJiӦ4{nvȑK ?<~РjС͛7;bIpURy[B|o:0|2_={*wODH?0QaB>WGKWuwJXu ]A*&}4jd Z=đ#zxijժ7D]tV&f?!|=1yM6wpLSc7mnU2u'٬k׮Y-ڵKزiO+w7oٲvdͧ;#4ͤdŝ2Vdݿ280p1Ѱ sNn 7y`T}W\ևMZֵKW?=*I1?R'Z7n[ w}7#O7[oߣXkğuY =fY}z;kcn30`>XRx>Æ }dD| OfHI5fJ2-Rٺ&:yTpqq(:PSOWNS] kC|wJys xٿ)ӧO ~2E0|R޴y>ӣF㎎ ;%dH$К~{쬬laU;zzto߾:״*N?k_Xns}W#^ꔛUYYe:|Fftۼe˂W_{o3^rmN0iԨQ~۞(𛨝2ۿJdY~Zi;@CN?S˿2867*l1?˗t~9n %m߾ DI+[PpIѸ HcԻW8xФ)SL#4k׮ߛ7o(&gz=KyJY6}m2=T~qNvqNޓ~/\`Wۻwe՞h٭ V/6ݝ_yE)|?DT_6L7ÒO&Lƌ6\]4R̨ӝ9jfePׯ_쉐<^]w߽^7|_\bZuk[+EMXQs)whݖ~qΞ{.qrr">>ACru#E $u&K #oR{}6jٺ+;k:NxnK@Ə{@ L&M~2'LVĉG`L{'Pyhwkxzz bըQ#Z΢5qnUrAmVBDuU)Jl'OJG|2IjNjF7.ȫ\{^yFf ݐO_3*#or%߉ d~t'ك3f+ӴiSܢ[ Jjvn`c):Knܸqv,X ǫ:meH IWd?U0ko_dŋeĢ-Snu>V ?H`-5nU&΍JW,ox%^5*~++bw*T|{.7Q١v&l(}HDݲD/)e_(ĎT}hR*X7II[㥛TpuuptVv엲aCJ|)|?E|E?|'VQVgox:{b%>-U֮ʝdʼe%Dgz#*Vni3ݼU+v8ejڵk5>37XTϻdsnG2٤/EKE(;F\p] %6}F.;YI{;uM߂^\/ =vr^Ӯ?dE(,ңW@yo({JK.uq mVbI#_iw/w!Y96E7Onc4lHƝʪЙDMhYқ}.7؏mD5M%LݤE,+RND)nfTP]ӫ9rzKN(Ť qWQʞ01ْClʂ~{y~;F!-Sju~1n ?lkI=w˸ה, DC+]mw al*k&ӁAE_ЏG6J1XQvp.DSW ֵ#FlbɁqGCŬP=;{T_|i-[TT佼ot,e~q憋x\5O-QN2tӒ[8W݋2徍l䌸jb*ߩ7~5_Y_HG%crfөz7^jlQV0~$j\}+9msBj%v\K"?9eru8O?lڪ?=:H7­S-zaV^eLW]Je:{KIDATUoUǀesrG-jTd2M_(5*ekwҵ|wJA>7 HC;Y*j.**z|dSп^ývVR1GQ3˶`2S2Ɩ..jt⇤xrFi)I[ rG޶~0rMJ}_Ucfmyڷo?ׯ}of͚ }Ӟ2pS6;ՅzdmLԚE^?Su-)Xw\Jw\RĒݪ2f 5AC>ˍ/TP/8s`ɄEk>%СB+͛/]Izj~aDhJ2u+LLM jL7**hq%>!_jя*GVqZE"(-˙o ¢*(_OòFA~#Pmulk>YqfFh[o6jd G?<¥ePm~H[tVLcz%ltW7oPSaJS݊ gttWj-g(ħ^i|HCr%i%26*'Ϳu`ƁX CG6!1RO/*nY\YRQ"ex-1UUlL /8K!+}s6Q!1wwuoil_)Ϙ2ieEj%>9Q̙)SL6jG}©S hV˧jt2dJ_G^4+a4f_zYkr ^*;p6<{ q;.ה(oGo`A̶W_d f" '+']KG ܵKQ*ɼ{~(q1ʰ]7 Xz-X<](%=c%J *i&ҷNkڰ4"1'noi*hrXjPGoCJ6h*^鏁J+y,JzU~݉Ӝg(|7tc4(1VHZo$.IN\N_Eh67lWy *&/sr!=ߤ%R>Ibʟ.x>_Ԉ깯•+W}I΢H-ܹs<:JNNNK.w5{A[oϸ_YӦM;\Ad{ȃ1֦cS<ԂSԭ[Rz??_u))r')xc%K,폤B>}ZelWE?ug>a #.suG ԩ|+=euv^6O-]RүGѵoiժIB߳/坭S朝\>lU2Z?i~ m%pXEXxuԋP X1?LXaÞی},xW-]oh?A>wՍJ-ik~0M6S:/ؘFB&߾byT#׮^{z^IOJO6/ʦ+?X^뭲Ul{V(jM_~~ 0ux%wZ:wT8|uX7j~M=''9EQMRZE-"HI-SJT;shg&>ŋ~ct o5ջwoeEr2Òc H:26,gl~|3quP~[lsBA{K/gdfzqםw.|" oꌋRzh ;^-[DC 3z+ҹ./d:Oflj :6(6,skvp,+[ȰaC&[.v܃cE]zҳOS+1[nEpt]tYf;~jյ^G hӦMOݵ~T,M))ej3BC-ҔFSn8_6$ajpV;rDp\vfǟ(I=ڦ%ґ-''SWR-ZXO~~~J2kv6Ƹp=XvM7G ~%;:wD`w4a(wHLo>_C"?P Я_߁;a=ע]w X-Q}`+[ Z{`ة8P*MdzO$--}Rd嬨!AcF ZpF5r%7'O_J᜜\a3履&l_~F#Ա˗/+& Xժ(#,,,NH+ aY2H-gFFFWޛ/77ɓҭ܎ 2ر ?lQ6REw 9Zn-`U~Q}Ljz-^aC`@Xĉ޳gK|T6M_r806m(8-=U:ceCd۝i݀-r2uQ#6/^fgZtoO>wN4jhZZg|MFN y_>RCMnn%:99+,a+h6O^R[1OR[}w9b@D/: п @z,|O/'mu)5G~,VXoÏ?hqz|ڵ~ɐO80a˦2-`-w<0&Hٻ~ߏPX\qƋw✹ dl<ٿPGE ?t(Ep9.Њ˗/7lx;"0p~~z4mT@5GxRqKY !%kua19喞Rv\H 60MPdR"sR,W1\\3Krf~٥Oϊ p1ݗr+|ĄmIyCg ͉'k_fnOԹ|!?/4wvwT~ `Ȝ"cU*O(o Dq"m`H m\J)~ctүǤGEyd$yRWJ4fD:xB No_<ص|J¸֐~MK< !Tk.|酆kx쑅 bs6(=IiE%:y1'%+&H,M?AR3Ą:0典htaY`f+HZS?qu#9c13݅P7xBDX.Ԭ,Q#9Q ODxJI١Ԏ,B[pKOTzJ[\ϲ6,Y6f%jM/ %R_Q|S97MX/#d]Eiu~ed%%N7KypqfRW NfI nRs q TfRiV%faqaejņUH~!!П$p^pH65~~Q2"s I899i[MHi8n~a y s2c#! dSót^I КN./"8t6(*ed&D<]Ee r***tfR@r7'OV^ S2½s₽Ǯ-7dK !s?T-#*o|QѧMc/%z+cJP@3Յp7O~%Wܢ˭"9.1Y6j5xSNү\MszIܝMvvww9|ҜeRWrEe]bR9џRWEDe8gxOw⩮+tH?Sf[SVL!&3.t))!SSTCeRjT@~ ´sb'~^~*Iq!U_| 8lbz1xcY1n&* F J`*@ `*@ `*@ `*@ `*Pix>_iU `*@ `*@ `*@ `*@ `*}Ɲv?q޴lm;uׯo``@7VSQQQ3.mrB>zT8ƍ?Yذ-]7F(Ww._<gYTe/ޮu飘={v.U\* gZ Y?h.˫\K 1Cݖn-WN<ޜ;ٙىq;74Mcƈ2?0onx Z 9R\|dSXnI^Z 616,z~QaA4iOuh߾w^` ]dͧ J9;Wu-c\Wf\XX8e4{ W\y7rݞ_p8J+JG'` :yTpvq^vaFv|mG>1R)/_B2[=iשh}E23x`""]sxK6S ))xqcASSSB+`J93a^)%,]1.5z=EсEX5Ђ 0o,1!Kc1`=kQNwwrnf5{ JG6lÒ Bx=ﰶIobΩ5a[ń,S6hUxy{ך,,/ xFz쩔ssZ .[w%̺ݕr;x;zQ%EdIw=&cG bXaMeH/Kyqq^E% {8ޭw_ nF4^hHzQV~=8lqVƀa"sR505Յz/ς88 a p)EY1 -恢7+|ةLa!}3r)^oו/|}ydn-%xV W._|\^5c.9#~|=?~_{@$}7x.;eff:{R˴UG5|RXx_ƚDז,^B,Y3um.)~lMupf6]32Y2qrpyp,OB~bҩ,lQSkZ{)󷲏' o|k_:t7 4Oy=Y2]|_կo >t+LNݢO-zZ2NH.Cl ʗ-+|W ^Ӄ2_$O GM|7M˯)?'aAa |皯7ׅO҆Ig]Wz9*gcN$럫zn#+Gvnտn<=t}rW~%1|G>ng?UX'Oakzuڟ][08y}sXl8}Eǟx"Hf{Y_WN1c vz0;C@2JI`"A `"A `"A `"A `"A `"A `"A `"A RTHHHHHHHHHHHHH!AUel]Z .uujue~sKkzEEA\P 髺%eO\2.>wE}INUG\TХi(Hm>Sغfhzzа}a֕aH=n-%9'.x[w;eAUeSdna~j˔wZT]'Vnޔ(;|Wf&o]/,`bלF~ op#b?#m5P>;~Ǟ֯]//)kNYbqu-5̌%\9?-^h^yK9cFy YsVݲYګo~_Ѻj`++ h>+;!=\p)٭o{Mi{',H>4wl`Q D ׯ uҚxDK/za7p5b3Ӳg,^:kXɺEUm6Oda9i3{a𖞟צY_6{X#,RքOۼw6̌kæ\B}eL^ĔmnY9g28WE/S/-|(9KjE3 ;L.x#S3J5KH`M*+}XRzEkuM]6ڔ764>9LefpJL AUAH Nߛٳ͚ꁿQuE}1#y3_QDZlV,;ml-4u0Y%i7lh v;QuȌ[W٥*j-ɛhBS7V9L9K*7&Zv͝%ͬVCN;}uKW]Cy;{aa VUôٳ'&u^_OϬ^;kk:Mu`JV Y̿3|k;{*e ߘ6;.V@mLZ*6$]H K b5̀hzJBF;4 @$ HP `"A `"A `"A `"A `"A `"A `"A `"A `"A  ᄈ. ٨ 0  0  0  0  0  0  0  0  0xo|VzW^Yvmls>|ԨQ>=tvvHijjtŻ vnO?̙g饗b]v7ϽKsXl?Dvm{~ﲟ^W'Fcǎ G aɓ>jr $+-ۍ]ׯvq˗?xgڞ}Gퟙ$wyԮ\R=./o>q Ae8yqs9kګo7JySE?8nyjdj5b#3cUOXMm ?vcGkG}tjߏ<+_ ϤebO^/n3"p/ a8BRsū_J4)⋊ۆnDJ2UwD 1͓?VW9÷\=qqH+88{+= 4Oy=N8-a_չ_'c;f٩#sEO &]޴ͫm/z(6ԭH40!=]$Sx1njΎOx񬋛Al: gr\[Wn2EA=߿J/8L]veU?? aGIO}ڪ?$m+VuW9G=rIcdSrsUϭxd#Hn]~ ׻6ru~,IDATӾ.4#,>v˯?:y}] 0Xt5Ի vn߂Ad ϻ{<`'Ǟd8/=|HHHHHHHHHijj `S `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"aHkUE)eu֩y}AELrÃ-zӇ<-){*穲8i`00 5MMADLZO* Ӛ/uM+*TZ_/*ز63{I݆SڼMZFNAiEMu u9-G7;ܠ8;%%oa}$.l96v-N#cvņ^i2 wvSQ^3;[7V|5mll}s>su*fgV|/Te'ԗ9宆۬kXhEsҧ-~UG\Tejy7۵f;ޞ)[}03~ӧh^0M- "]uww;g SR_Z0oL;^E [Pv5y7+շ[6^ٜ5uS{ S{}aA7x>tMah=Xum{l]wuf-(ˈҪ ƈUpFvj6lJ/( o(/wøʚyQFD.\seAiM6-{¼-okj g+*J\9}WqٯJ߇g @t3:$1dV'ƚ%G_=AlB晧W[TQr85E9i))mm^|QΞeņƺ𺠡jvFnn<֖p+ˊ2b/ڶɗ$nfM;8{[HijjfucUq~t>NZ]xmk+ UqYwV727aCMY~9f) VnP*Ms(m?ٙon.x26+u}yδq`O6vm$Xi%UW/?klECӳ\`CWdYjvaeڇ;}JV)v떮X}&̞_`G`촹=z}Ֆ7" Vy-'$kD@ ٱڦ k5B̈́koZӾ4ב=y.JL6{|a‹Q' b?[[UrH,înF~c5yW|c(',9wi~h/>Ll7?ZaM/}?fޕnmS~672m2HpQ}ak̏Ux/Pw`P[?鎙[J'->)_H q<<3o!/]򡹹s3_jqф 8iLstaN>A'?[M >5aBg>=~2jE%L 7V:\ˋ\73JtqF=~M?4Y}L72m58pȁ_s3|nkqG5|S% A\+IwĹCcݱ8Qb0؈]bG޽N]9$ϟV(RIȶFS=x33ox'H̘6Ò|m3-=xkh~^-i[uU|/Nh`Ѳ6, 󦋅-'Ll _wzZ{?-K/_[vLb,yc>__Z~ll}:K\&vmsU~{ze=}o!ݱ9A a6&[G"h,0-K*τFln&rofwFpEb;f5׍ydRҁYϴH?^J7͗v05ۋk]ф +Ҽ(N#,AW [>:ۤoج a6 ŝ;mMkĹ~$~<ݓ0\x ccV=+]6wQG饗cL>/~v-8}m{ No :{9,$xˀa+IDAT_g<0!l_GM٥AF-M:.uk^^Noǻ-?ۿGu+/7 4; $C__9o^{O7K/0ۅ~H ?kWo2| {]ʺKlO_a|se^}('ߖkk_o[0o rJ(Y=+A'̫?R__?}m/_~ڱ-_liZڰ ;o̘CFxKYkq|0{}݃m󉪧Y䓉{nIII A7nFKʇ:.#=}?a°ܝ  I2\=lNurX {$C^9.'筷ފ uPAF}u˭ͿD_rG>vN=%,/[<|?qԨQ6e]>9jT͋)8OtP}N%ݯ¢;?1@JIY_S .#Gfݩ5M8OK'9LޔY'YVܟH\@e~7.M!^],:7>6)¿\3Ҍo}bDc Iv2YYӦ&ڭ߫i$:o_z&og~˗׭YSW&W#GfřMVq:8;^iAۍA/% &JM<{W~k<`Cמ\+J.$H_T݋>a^ ߇}d ߑ:?ml𫯾zη/0WׅʇO>{u?!/744$g?$&5/n_9"y'&Ö2KEv{?}կcn`{ _>e֬“]~32҃^o&Ə`3.'gȐ!|oiӦDDc0WZ~g;N#  y^ aEs~OO-:_>y'۽6?򉕷_{{7<+G~y?K4¢l\*HOJr^ִ,)OܾӞ`Tjj>oC7lH4z;Yuּ y nyk/`1Z  yEZo%ۻO=fOtvʴ~6O|b9gUcnw0U= }0g~?_tq39gs(n!|V6ȱ5k^|ء7.'Xa >W?`544/Zh/:ENFDžEG@ v$߹;O}}|#^t֭ |pWg76^%S>j1njs}uךH</]ZT=cÎqAT\<>eu<g?ϥߙēO&?CǏOi~䞸};~ڭae]_D܋6m@OE_<N4r&ls,\E}f}kVzuuu00~&LO]pDnn Vrko:ua/ŧN6LbVxNewcӲeG՝=UaGqF&O>&?++˝4gwtiN>6mfI; 7`mUn=KhQynpc93wDupfAVf|-V mN`+Lj~_UXj~I_.玩M, ?m[em1Oe -;OQOseFaby3[>w`~Me//?Hdsޡ6^=|TgNuJT=T:uIGп„vi}ߨg-){%{)o5_*θqY=xcso{.u:D ocHևaE:/dffxóx**ל@lǗ]xwͩ7`a#:<;Yɪ{g7T s3/MsX~|݌3\zSpa]o򍭽\Oz/l_xceK& 8~_;ܸcI͡l׼G~<9VK$KǏ4heĄK㭲)e'.{n>++_h>+uQG饗cL>/~vۭm{i_oXrҥ#Wy@+kv΋{Ifm^=7&VOB[yG/[Z?&=:ɝǤԈ\r7W@$S8ir>ۇzԯ]9w5/隩A0uemoBp' ͸;TVOnm t6'_MoܓڽWY${4Q zK)lWY^yflkMY^y_/7lnuI< ]b-/׏t,ƖWYs֖nνŸ^{ƛ: 8y=we{`ǺdFF~ Z-~Ie,^. 3>%Wяv1 %wʿ|YOn29kګO9?,?0}y-^\8OX7 X-eȰ"}ӒXxi9vخ+e͗t^6U%,k6Ï7 Gv~99;׈Xes/a5xg?w.b!C|sj\]zI|ͱ0شp7[a{7W󶼟5 \$'?&88o7v\:ӵ.8-͝ac&j M>Q0e%u3G^tAO?vmtfyq+5?}hҭm5}>6:FmŪA'%sp 5[tq[W1V=w͵66^Owݻ{a)kgAao~ %v 79~.^_T݋{*M4p+`?&ۤLBׯvq˗?x63搑#Gf}SAt?\A^&/VE5ϯ FM2Ӄ$7v/k/w=dgaul؉ykoBJt_񡏅]cSٶ{C"Rƥ?9u]Ï~?zIGX3Ϝ~|QCw$AMݼys|,]ޯκOz'>TZ?|Szmg}Nɺe-AZ\xkOioC3g2cE?>om~OMƧO4u8ڶ3ٴfLfm>m' l1[5m1Psp_-/ol/uq]W⋯ӟxC/gk:kY]u Ko 2W߂;6~-Zd|o'6vy7۽dg1-}N-,xBǡ=@J܇O{o#FSRR}ډ(>O6˫_s=xGL?W>tԔ{.lKKw1O1ٴiӿyWq9<C,:Ck3f}6u{\x_zqʼnΘݫ~M<D qSfHW=DҊ755 W:5GK/ a[V|rq"u_@dgeOhs}DXqN'F@c{}Ӎ>ȳ'>_ ~qɣO~,1Vߔf4xƊ"G ` mvӦN=O׽^vOwߏ0lmH_[ϫ>=:;1{Լ{ >}~Æw?u˘C>`?}>> W__^]wׯO,~ӎ|@o$q~0ڑ'}iF?^λN9555}>79Czᅚ0&ګ{>|] g+~m3v5IhUFzzRN2i YY +Wm~Ѱ&{.Sf}c{Ԟm WcN%wpX9'&H:Ij~ NtD믿V{HlSrx=_tШ}ȇZbܸjsvj-Ns^[n]㺷CUI{{āqAF "C L'} ~ C@C']Y.H @J!@Rz1_|󫳿`PNDԧ>c]vՏ;s/ڴiS}'^{`vf05yy<7YYY>"Ag9lo1tNGv``Gz>?-g[;}D0qvm[UOV-h]8#i\ @l~ſbyX~f}~zСC$$ vwx~e o_nL K؉Yτ{<#$03 'L 0IJzG I@D @$D @$D @$D @$D @$D @$D @$D @$4550ة 0  0  0  0  0  0  0  0  0  0  0  0  0  C^UQ#٥u7l^XX_fCK 2:YjFv^Ʈk{|FGǝq+6&llXy'=soь5w"xҦϳN,X:k59rWCqk:_Ekn>1;9f(oݾuo†-h~WYkB9'9K_?6l{%݆ԴҪދfVlϽ]]&֘v[eQk*ok^T\ vqQἚ~;QMΝ=kX ;aFNscaaBXplгu9족] l=[ }DO78-qIAF2 S2P]/7//ouu)gf'bʪX;onv#5-Qm|w~ -Ѵ:gf;k)TTuե25';تy@W/ݾ7x:4\18aԭ% ~ RFabO+0UMi)YWl=֔찳DP -/Rr n^8;sa{ؔKfIXY%w"+ik}3a˥s/pW9^F~g䜸^,?/{Q N>4dhis|a}]),XV]{ zRo @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$DBwD{ `"A `"A `"A `"A `"A `"A `"A `"A `"A >/͝>تUϽ+k׮ vVÇ?`ǎ3#g~+ᄈ.ع=3gU^ AF-M:.؉`+J^T۵={]~z]YW2dw٥|C j@jd?xDo7vmO_~ڱ-_li{Ӳrfvf{OXwI,<|„{wd@jd,G{SVT$L)d G+zIcՉ{nIII zO!ARZo7=zSrPa:oVݷ0iӦꫯч雘6. IDAT I>8^\b92sweTz.Ҋwh+]7O~b3`^] dʐ{_qG?j ɍ=rqS`$Sn8#Zn?>6/y|̼.֙ ؼv/~+tI7޹Yrj d Ƙ#l̜ ~ԥ˖pDFLG^.i w_X}~<?暩A0bˮM4^Hu^=jG{,&3wDPO L'r)W]IL]tOJ5MG6:Ѩߖ7 n+#r3CRJSSS+}g]'=ۇ!K+*NrAH'}2 _zi|'lş^:ǞA$@O=aϺ>Ⓥ7S>0).q#'A?~:פ $Q'skOX =G3ȱc' vVaw+>zϣ *r 0@,_T=t}rW~%>򿏄 L:׿\lV _nu?S<;gTA&pw-_t{x'dp<'M d` D @$D @$D @$D @$D @$D @$D @$D @$4550ة 0  0  0  0  0  0  0  0  0  0  0  0  0  Czԫ '#5%!-;hIMuiNJJniMGUQFJ%ձ5i./OJ~y}C*gZFNAYUc]zn#Yacu_}qsVSeuash !m-/1憰1;_X~Co/>\tV٬59^#~ M gŗd_ݼ w+<^XpBxn>ca}m%ו<wڂ3SR3**[W_>#sn[[WԴK*'㇋K`+6HMm"p🉅]lXU)w5ğLd͒v~=cv<7TUVpNW4nؼ&(6Teq|$K4MM )m%g.9{X+)ye쮋yx]s{bqϤKJ8#/5-muܲd>P+ϙ>nSg/piY@P_]6#E~Ai y>i5M_xL>lڛO.C'ڇOw_9'PT;gdMwo9+cЉ켂Ҋ}V,8=Q^5K 3*WPT!ò\p1ɫVTknY]94wM]]2ZhZ悢pScMeLЍnp]EYO+]4o-x旖M5]_-1z4#2iC}9k;0kk<\82 ˕u#v) *g\Uq [ϺbEMqNXDbn<6ۙvڊ93ӎ_m83oFX; N>eŰ)_uig `G ŮD @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$DBwD{ `"A `"A `"A `"A `"A `"A `"A `"A `"A >/͝>تUϽ+k׮ vVÇ?`ǎ3#g~+ᄈ.ع=3gU^ AF-M:.؉`+J^T۵={]~z]YW2dw٥|C j@jd?xDo7vmO_~ڱ-_li{Ӳrfvf{OXwI,<|„{wd@jd,G{SVT$L)d G+zIcՉ{nIII zO!ARZo7=zSrPa:oVݷ0iӦꫯч雇 I>8^\b92sweTz.Ҋwh+]7O~b3`^] dʐ{_qG?j ɍ=rqS`$Sn8#Zn?>׶X\qGOYZ%paӔH$m5?bwz"+ZN L!sĘ9.u.]iٲ(0e/SgO k]<'Ou{~l5M- 9n_3c&i9ҮiWk< uăT_T`x;̽M_^|jf;y3Z\Z?WF'tV$mzeDnf_jd|r o^PŵWYû{ M] ?~y(.7߄~4/k^}<'h{7|wqo]'{O4sL@J)vXO-,:?~ǣ ?gMh u\+]|j0R:];>> ^٣?N>EdկR>2vV{C{9,D|&?.E|Aƒ$#CW)窞?֏a#55XiԨO3ѾOX =<;#te923`%5>O=tvIDATӣxtQ9c;v`gUXWm;#xA_>_T=tKN9+OGGlM_. vxo7߂d})³ vb* 8/=|<A28jY_w}`&Lr` 2 0`"A `"A `"A `"A `"A `"A `"A `"A RTHHHHHHHHHHHHHͲK낁UW/ORAEC$3$vKS\Z:+؉dT4ع NR,Iۚ`56Ay59v=v = eg6#NΛ]VIǚҢ1ǩ9u:oUQF!;KUq fe5]†yioLv^ Gό;k66/XWьmՕ)seCúV.3}d`Yt7&<כYTsw9}׶3jq]T9K/@g~ cCׯ]ᒆNn2sҧ> o6a b}o.W.sK[.]=?+ءz|,%A8ۜEgVeqSְ)[:}h;^ҚXM6s`5k;%+VU+37whum뛺Q0`z6y+JjcAPس/(l+HMK 6D.?g'{*H =ٳ4& fdO_+06:##3ncueU}ۆƺ%ٻTe%cGʞQV]\NAey)))eu&%.#~,yf=COnIAFG4KyA/~v-M~3* 3X뒃F ^^{o_=t\ >y_Om~ٱ¯Ŕ~]iӦK 'xuЅO;˟Ma}ܽf= z-9y)K+*O'qįn^C/9g>䓉{nIII 0p ^Z﹅/Wsg'{}nPٴiӿyWq9<CCN>tԔ{.lKCs}qN'F|MM[^s.͝>تUϽ+k׮ ̞{/Ç5*wӧ( Ơ?u:N<I~3*t ֞xwjjkǽ7￾o{٥ :4OYM牆Öw/*z.e??ϫ{ ;&7ソfe]¯ΐ!C>7xcӦMЇ~0!.~mO_~ڱ-_li{Ӳrfvf@gi|_ZSrI<ں׿'}::kYAR2>ʕ&utHOOk;vh_ִ,`uu9ꓯFبzC9$?[,'Ɇ@q+њ~s&^~t+3A^~W]x_?8 處V%;}7W=\`T}˭-H /ћޚY8o{߽ƍ3z5vƍkjs$W޴iF_8€>9.[xY^կo 聆Eŀ 7:uQLxij:EW &}w#q75|i_6>S>sz1;~7:k 2=ޗh}?^(?>':YdZCvkv'siƊnܽM6};sxӟ^{MJJJ0hЖo'cmtv+{0~| ?_K\]]hr2V\TlYӲkf֙)3otU$ĵuv;u𨡻7 ;&M_4h y&woh)`˙~,+N<2Ȼ)>]? =sΧw}Dgeeg[L@^7戭߽63wDP}pf˗>xȫ.׃a 7.٪xu޵P}}`g~MeGm|AzvxXD=*3N~+9qvmz3^ +6>JfxvV_ܾ5ZouT`G^&qŧfdނ`5'1hyZOXDϸf⢭f]P>qӁ^iyr@Თ3ߡcF7UuF*ߋ-uƍ"歖9>eo7 ;=Z-O/璠{]}x/rOVU {'eΏXY:9x7%3I\|'o~{/?>[wl4'_i}U6>$[_"Eo>햗rIDAT^YʖGoEmpҥ#ГEz]vA=TNfǰXZOi՜s-Ç3O].\}`U\<>^Vxxa%/Zbө[-k~37ٹw44uh0bW51lowV8cXmZVx@<ꄫv'VTV3\ؤp%g&."wgղ025Xo3Oq|]˞~woӴ,WY${468XrMx} [ +LMmn:~}<9 =T2{%"P_o%FE-yc'~fջ9w7_/n5L=D/N nmsڭEeX䮸pDʺ` bMѦxNnyX90߫YX[aFo|Ʈa&vΛ.]3 )T_cCFpӒXQ1^AkM ya5^6m{VkZ%4w~;9{1ݝ;;.l1x#lOTmυe/y-?m Ĉ WzVK)Ѹt׿vFo6 ~xEWg#rhkm;l`IнoܚwQ =-[{b n+VZG)ǂʽOP3UDUu^nji%Sx}M4^~1uǯ}&gي<K*1mY@͓`u29VJ[\:f/}ۿҲybƲ.νKu LxiEI_.i?WOƶOi̽?e8|„~`K=Kz<۲^I!S9ftvvhkų.*O_ ?/H~7H3q玿9%Se]_DGIOY%)3N8>IĮ_ }?v񭗃nmI[`gGM|7,l_SԃO/?3onӴa?`P;}$ +.'}66VuW9G=rIc:SrsUϭxd#Hn]~ v+$⋊SNo0ԅG>r-gmv>kg;` ,͵?G?7^q.':(@'i;= 0pi-|sj\]zI=>W t 0  @ `"A `"A `"A `"A `"A `"A `"A `"!)NHHHHHHHHHHHHHH$ 3RR2fW4S+onVSI8zC`"'C7UNKIH+ZX]Z.Ni7#/#/3 '#54gN6H.^X/%%--/_0}Q)[-w\R~EFqp骢-WpcUq#Ϲu͋66>|=DT pCߚ3gʆ+o>1{vE̵}fW?\/J\OUEG\T5l֮o _)bjL^iM45ռعOւi-;{ 뛟yڼԈ|y+;!=\d aV6m03qFy}ӊ#ݲn/mIni} V 5W'n,HS3*揍X9pa!siiTg>W1wE)\RtV,co=+54֨SX޶5Y @tJKI1x‚벋6Q.)k5vC^X~QZ~iXc%}95lJuq]=x#$?5 *uUU>u~)KQkUMm fu\10_٥ʢ2u/@TdUiō}o8 bW_1T ZCn[ԍ`4wV㭬X7773q[RV\=WM8wd]+Dk,(2ה^=ev~646O<"!й%񹘃ug(o /35%%%.V+-ِ{͒ٙ/=;-9y҅5mhIiANp򶘕z8ag*DPJSSSw+ s_.D^muŊq5?zmuKk}>):>mAe+rGT[MYr\0o3r5IֿpicӇm^:,==kʬ K$늇V,`JVzKvX֔ x,zfm`hziϽ.jr DDhޮO;˟M<3mӾ}ZVN vwyԮ\R=./o>q A24R8',.[|ՅWm\1\3:;dHTnv7=zΓ~0pO߼{7~g87m_?a=ο0ض5hIDATtA-,K/׷ VꫯCXtŐ!IpGN?h_;H2{/8$N+w"+puuuqt剋SƏ1ֺ^+9>ׂu𨡻7 +vd Ƙ#˛0+f]iY6}.!C=rlz0Ajo5y=t[Uw̑g.VC_6^48zk.n5$VpM1|-O.F?ۧyO.o/}dAEy՚}ŧfko&]I;pMUWw{;맦f^Ypeo|eS;QX:*,]l&L10KSO?1Eݫ^k=ev* Q_ߧ~}%R{p]̣\?,95y%{wxII8󘥎mi)AceV{N`7ɥ)Љ'NIƺ'~?R_'-[Vק+zu o-wp&ÿ{-'pzտxgYW? r)';iܸDžݪ[GhRX { |ɴڇ|G~=Lf >{?V+~iIg蔷~k}n^{0XU{ΜoQG"8o-A㏇A vcà'H&X0Q @` (DA 0Q @` (DA yT*0Q @` (DA 0Q @` (DA 0Q @` (DA 0Q @ fcimahk?(?ЂʪEZVYߋ + &Xº;7ApU֭[|r~#0,pu&-HGqs!M7$+ BT֧:,y3̩*ϔϨK^a7(Kv z=7VluckC-jzDi~Uyqk +k꛷?nۖpsi5j+|\:u~ݺ|ӌl9IX߿Fq{C-+ےIwt>}I.Mayu_mU'\d=|4sESuY+{lĔ*9z ?eq&ImYm)<î?f J=Vn#7޸oʐ` enJ]4*]K+ܺ96~}q k~n%=^I,~:sq/'99 V^2\Phcj_so~l渐1˫}Qo5ꋋh_Q44WԞ˧t~ϳ-f.6O>Xͭ٬50?;xhA/t\^^-6W_";d}- ^^t0LaEMKg-qu`wS7/VU|5mNQ>=\[9`ZCjJCzlmv;!_9m]~ymtY:4?/kzehY{|MMEVfߜ^Y] ToaۿM-5Q)sfm'65dG æ|l>عDi셙~'OpAE{RKcCf]m *27Gvsf4g1d3tLiIǻoc5`laS=hQӪZ7VZv7<}U¢ޕ eܶϥE!*Q Ӳai504//`FG_PPX\>Gk6mp~0ʧ1ӧmq[险ÿ8<ĥ?*`5pS7/]qŘmԍm u53ʋqwZ} ksCCUQ^:ݾj~;o>ef~"m-Mj*&oP65]Y̞L**ihmN '-X[&UGR5UGLill-/{6L^R_7iA_t_m6e/}rQk]Eqo6ō5]L7ӧ(pRs=k+ <߿)ls|.o?*`5` -кg7_t.Z 1bĸ3.yk7t JEewۗmMNo|㉛l8kH{?{~CArQѧ^4o 5!V}QF`ODA 0Q @` (DA 0Q @` (DA 0Q @` Z?lx(DA 0Q @` (DA 0Q @` (|^=dɳ>/]6|ȑƍxI?(/Ju{ևK/y0p<ۿ{G?:> b6<G9:[ڬwyƿ\{}W}}{_]%0x?׳aÆ3>qO?=?삯^0x#Fkiny7/jZuwV&Lx~_v Cn?=?>rק~iISO|b=w兾BN{:oe=v@DIS2%{\/Gȥw}/+Iyqcxꎽ?邏^jŪ|4IDAT+yz}d`ɥeC.+ol{};`^\ lsNy?Kf?c>̉[)9-pSSTǞplWWY[,xSr>!w[.[{wW\ [\sYOBuS o<ıoܷ 7ꟓ'N|lɒ,K- %~6n:iBzs= {&NvzGqtaaO- ؃D_{OFԍ;xj󲩙;Dݼ9[1bЫ}sx>laUӪ4m{r^II㡿V.o#/ŽN }ܗKsZ_iԅeN tozܗKNST^k=eഓ?U}ꭶ裏@˥{ϻlG~a뚖4e~ӍyyyܗcA:yį>OzٯyW̸!o{~k}^>AtrǞyfy)gR|rƍ;q\dw/V$}:+O]%@ sgϪ^zgyGh O?懝| gn^{0pf/]ČCo]?v'VN̔|z $AH 0Q @` (DA 0Q @` (D!/J 0Q @` (DA 0Q @` (DA 0Q @` (DA 0Q^W7UuQXq,Qmn.j(,ïi(}N+Q7wtJ (DA 0Q @` (DA 0Q @` (DA 0Q1 @`[d(DA 0Q @` (DA 0Q @` (DA 0Q @` ( n?sܴ9}ޞC8oai!7t^3y]b k^[g1G5Q~)n:.p]隋_2s*k}v~ͷ'L\y~ʬUKQ8zMZzɘp{^6_Wga_~:n?,Խq³o>NixՄ_gzW.3t~GkIb?d͹K?kxք粕7=v[ٮ3K+Ύ*.Kek5/{_?}i/%wUޅ\n_Q9V%i}\{_hozcg|m΄w̐>㸫poUٺ/UvJG/vT*퉷Zrß(|<鑋{<}Vӧs~=ݑ.ٷ_jar>OxJKҧ^O(=_zɜ9?9o#3|ɜ_9a0?r\N7[ZlU?1 ]aÆ#/@Ƚ)w=w}P>a y߿s78c=& J@ʽ裎<o?|IM =H~~a ǞW^y_f'PzgIﱏ/:tHcx!$}Q'0wC}|'+嶶կ@. ;o`7y7>TR8V~& 2 m~? ?k̞UYU]k>Z<ɧ&zʫ_?\ :lW^ snu՘aoΒC'/6)lܴ)ѣ-ylɒpĉaQsr ܷ㯻'okMF}_j?eC.Yr0q|x1Ტ}BCsCX>;m?ٶmeng\wń^Q9#d/ٷ-+8(f?{YU_UU/h\| /1۞i^4 5z?L'o:'tYy%%/]AxGMbpIG?yi;ݽ6 摒`O.u鍠.+ŬRWIDAT=κdQvWpVU%%WeZWrCҬ[նE&XkGCrV ؼj--uuO|䰰JXv>;@"| H}aG,7׷<w酞:V7[>iw )r)l3\ /AБ#O}haL^ GDam=;.)$MkVyc'NzRT'~k}d~Wz!)s֙>j58 [+?] n\/rA.3ǟhL +Wp,?x45|M9 ^.xG'|2_S˞Ζ_rA.OH;t萏) (oR>,,rA=iذa_^X8|^}?z7grD.=/ĻTK˚7՝5g}bҘaP 4ֆ ۋXy g6~cW#j)sŊ-֯[o]ڰxcmi ҚT*z谛4Wg)ݐJj~#BQYQ'2vg୴ׯI]5`h44xZMôץRu֛-5ʊW-(*1u,rX;ph7ool[[u^м1 ɭW-Cݦ|Y߯W)$/JtkXS=H ׬롧Sԕo{}g/=ouOuM8E].,䂞UUKMW%?eݔũmZko 'yqFQ{R~꼟/]yO׭jۛVRl<I &Mbqza68_~|mE;ۗwT~鼫Tw;V߿>{psU已g0}IlAٌy2'V\1}~k7|cuEӪ2>ݿ4ަ!΋ko|gl6iAso?ދ/j^<%/^ߙ *Zآ*Mma`w;pcMMvr7ϯjRlь3GeJ?k)3wmjlXm:kZjOڪ-␤iA͢=j뎿MrpKclK?͖Lyi_?3f[2,/lQE3[QQ߇BLvo 0 g]cgb}{6z;VPPrӍ+(*ͮmlv(1w\iQɮMFKMl >m7LZ1MߙSM5s ;rFf35Tnqsʹ\SgT`Pi tiu]ft*jZ' olki,+WZaheuv/,ih{c[iEcfo`l+S4mQs[MbE`ܼi!27RTOOΚZ XUp5뺞=wysUqO.XM}ƪgh'ZKC_3nnX4c)p.qF Zs?Zu>G#gܳ2{Iv V~ymˆyƸ71bS.wϞ߰I)ql|H/ae_Oqg̼}]olvo 0Xh @` (DA 0Q @` (DA 0Q @` (DA 0QvoНr` (DA 0Q @` (DA 0Q @`  ǖ,y^zk׆\3lذC>#(=&M*STRT'~k}ܞZ_ {o\!CAÆ\3sͪ^zwo͵ۻvGǍǖ$IO9yb 䢁-Ͷ 63~a|ţG10䚷z/YaQc0rl p?{ŝxbqA!g%>ϟv Wްiæazq BN{g˕Um9~2y;7m/\ }/̖7yW=ΑȖ߿@ȥW^y%) :d{c׽tҤμl;!)2򈑡_,)ɛx؍^(_N la\|1 K)[8c{hk-a6ڼ)=8#(g/\ ֭ƞ3rOFݞ],ua'_lB8}qUy€kƝ4.[^;m>}:{ĉ-YztDŽ~h{7IF]zag#y~㑿Hupd63xՉu?2ɢ ̈2)3}: y0orI%k6tɤsH 5O=7wxC pϦCp1š_6W-L+i_=^yE2mJ S˿|λ8p l۶ssg{vGORXbUY?̌up2;#-֤=L:hu!48k}sfٳ6j{gK#ЇUM®wpdW JeGw*3 ܳWf #;m_lhl[u9%WtT7~s{Spx +LJTIYpapve7֝MÚI%?2oݮ60+nXp9y-^n;-;J 3/G?Grgm|_4x6^zgy$:&>p]wB%9),*o{[I0훯_aRq9sOGyd?lx59ov݂$_^c=E-` &X0Q @` (DA 0Q @` (DA yT*0Q @` (DA 0Q @` (DA 0Q @` (DA E$IDAT}IENDB`././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/__init__.py0000644000000000000000000000000015134002420014365 0ustar00././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/adventureEngine.py0000644000000000000000000005364115134002420015774 0ustar00# adventureEngine.py # Copyright 2005-2006, Paul McGuire # # Updated 2012 - latest pyparsing API # Updated 2023 - using PEP8 API names # import contextlib import random import string import pyparsing as pp def a_or_an(item): if item.desc.startswith(tuple("aeiou")): return "an " + item.desc else: return "a " + item.desc def enumerate_items(items_list): if not items_list: return "nothing" *all_but_last, last = items_list out = [] if all_but_last: out.append(", ".join(a_or_an(item) for item in all_but_last)) if len(all_but_last) > 1: out[-1] += ',' out.append("and") out.append(a_or_an(last)) return " ".join(out) def enumerate_doors(doors_list): if not doors_list: return "" *all_but_last, last = doors_list out = [] if all_but_last: out.append(", ".join(all_but_last)) if len(all_but_last) > 1: out[-1] += ',' out.append("and") out.append(last) return " ".join(out) class Room: def __init__(self, desc): self.desc = desc self.inv = [] self.gameOver = False self.doors = [None, None, None, None] def __getattr__(self, attr): return { "n": self.doors[0], "s": self.doors[1], "e": self.doors[2], "w": self.doors[3], }[attr] def enter(self, player): if self.gameOver: player.gameOver = True def add_item(self, it): self.inv.append(it) def remove_item(self, it): self.inv.remove(it) def describe(self): print(self.desc) visibleItems = [it for it in self.inv if it.isVisible] if random.random() > 0.5: if len(visibleItems) > 1: is_form = "are" else: is_form = "is" print(f"There {is_form} {enumerate_items(visibleItems)} here.") else: print(f"You see {enumerate_items(visibleItems)}.") class Exit(Room): def __init__(self): super().__init__("") def enter(self, player): player.gameOver = True class Item: items = {} def __init__(self, desc): self.desc = desc self.isDeadly = False self.isFragile = False self.isBroken = False self.isTakeable = True self.isVisible = True self.isOpenable = False self.useAction = None self.usableConditionTest = None self.cantTakeMessage = "You can't take that!" Item.items[desc] = self def __str__(self): return self.desc def breakItem(self): if not self.isBroken: print("") self.desc = "broken " + self.desc self.isBroken = True def isUsable(self, player, target): if self.usableConditionTest: return self.usableConditionTest(player, target) else: return False def useItem(self, player, target): if self.useAction: self.useAction(player, self, target) class OpenableItem(Item): def __init__(self, desc, contents=None): super().__init__(desc) self.isOpenable = True self.isOpened = False if contents is not None: if isinstance(contents, Item): self.contents = [ contents, ] else: self.contents = contents else: self.contents = [] def open_item(self, player): if not self.isOpened: self.isOpened = not self.isOpened if self.contents is not None: for item in self.contents: player.room.add_item(item) self.contents = [] self.desc = "open " + self.desc def close_item(self, player): if self.isOpened: self.isOpened = not self.isOpened if self.desc.startswith("open "): self.desc = self.desc[5:] class Command: "Base class for commands" def __init__(self, verb, verbProg): self.verb = verb self.verbProg = verbProg @staticmethod def help_description(): return "" def _do_command(self, player): pass def __call__(self, player): print(self.verbProg.capitalize() + "...") self._do_command(player) class MoveCommand(Command): def __init__(self, quals): super().__init__("MOVE", "moving") self.direction = quals.direction[0] @staticmethod def help_description(): return """MOVE or GO - go NORTH, SOUTH, EAST, or WEST (can abbreviate as 'GO N' and 'GO W', or even just 'E' and 'S')""" def _do_command(self, player): rm = player.room nextRoom = rm.doors[ { "N": 0, "S": 1, "E": 2, "W": 3, }[self.direction] ] if nextRoom: player.moveTo(nextRoom) else: print("Can't go that way.") class TakeCommand(Command): def __init__(self, quals): super().__init__("TAKE", "taking") self.subject = quals.item @staticmethod def help_description(): return "TAKE or PICKUP or PICK UP - pick up an object (but some are deadly)" def _do_command(self, player): rm = player.room subj = Item.items[self.subject] if subj in rm.inv and subj.isVisible: if subj.isTakeable: rm.remove_item(subj) player.take(subj) else: print(subj.cantTakeMessage) else: print(f"There is no {subj} here.") class DropCommand(Command): def __init__(self, quals): super().__init__("DROP", "dropping") self.subject = quals.item @staticmethod def help_description(): return "DROP or LEAVE - drop an object (but fragile items may break)" def _do_command(self, player): rm = player.room subj = Item.items[self.subject] if subj in player.inv: rm.add_item(subj) player.drop(subj) else: print(f"You don't have {a_or_an(subj)}.") class InventoryCommand(Command): def __init__(self, quals): super().__init__("INV", "taking inventory") @staticmethod def help_description(): return "INVENTORY or INV or I - lists what items you have" def _do_command(self, player): print(f"You have {enumerate_items(player.inv)}.") class LookCommand(Command): def __init__(self, quals): super().__init__("LOOK", "looking") @staticmethod def help_description(): return "LOOK or L - describes the current room and any objects in it" def _do_command(self, player): player.room.describe() class ExamineCommand(Command): def __init__(self, quals): super().__init__("EXAMINE", "examining") self.subject = Item.items[quals.item] @staticmethod def help_description(): return "EXAMINE or EX or X - look closely at an object" def _do_command(self, player): msg = random.choice( [ "It's {}.", "It's just {}.", "It's a beautiful {1}.", "It's a rare and beautiful {1}.", "It's a rare {1}.", "Just {}, nothing special...", "{0}, just {0}." ] ) print(msg.format(a_or_an(self.subject), self.subject).capitalize()) class DoorsCommand(Command): def __init__(self, quals): super().__init__("DOORS", "looking for doors") @staticmethod def help_description(): return "DOORS - display what doors are visible from this room" def _do_command(self, player): rm = player.room numDoors = sum(1 for r in rm.doors if r is not None) if numDoors == 0: reply = "There are no doors in any direction." else: if numDoors == 1: reply = "There is a door to the " else: reply = "There are doors to the " doorNames = [ {0: "north", 1: "south", 2: "east", 3: "west"}[i] for i, d in enumerate(rm.doors) if d is not None ] reply += enumerate_doors(doorNames) reply += "." print(reply) class UseCommand(Command): def __init__(self, quals): super().__init__("USE", "using") self.subject = Item.items[quals.usedObj] if quals.targetObj: self.target = Item.items[quals.targetObj] else: self.target = None @staticmethod def help_description(): return "USE or U - use an object, optionally IN or ON another object" def _do_command(self, player): rm = player.room availItems = rm.inv + player.inv if self.subject in availItems: if self.subject.isUsable(player, self.target): self.subject.useItem(player, self.target) else: print("You can't use that here.") else: print(f"There is no {self.subject} here to use.") class OpenCommand(Command): def __init__(self, quals): super().__init__("OPEN", "opening") self.subject = Item.items[quals.item] @staticmethod def help_description(): return "OPEN or O - open an object" def _do_command(self, player): rm = player.room availItems = rm.inv + player.inv if self.subject in availItems: if self.subject.isOpenable: if not self.subject.isOpened: self.subject.open_item(player) else: print("It's already open.") else: print("You can't open that.") else: print(f"There is no {self.subject} here to open.") class CloseCommand(Command): def __init__(self, quals): super().__init__("CLOSE", "closing") self.subject = Item.items[quals.item] @staticmethod def help_description(): return "CLOSE or CL - close an object" def _do_command(self, player): rm = player.room availItems = rm.inv + player.inv if self.subject in availItems: if self.subject.isOpenable: if self.subject.isOpened: self.subject.close_item(player) else: print("You can't close that, it's not open.") else: print("You can't close that.") else: print(f"There is no {self.subject} here to close.") class QuitCommand(Command): def __init__(self, quals): super().__init__("QUIT", "quitting") @staticmethod def help_description(): return "QUIT or Q - ends the game" def _do_command(self, player): print("Ok....") player.gameOver = True class HelpCommand(Command): def __init__(self, quals): super().__init__("HELP", "helping") @staticmethod def help_description(): return "HELP or H or ? - displays this help message" def _do_command(self, player): print("Enter any of the following commands (not case sensitive):") for cmd in [ InventoryCommand, DropCommand, TakeCommand, UseCommand, OpenCommand, CloseCommand, MoveCommand, LookCommand, ExamineCommand, DoorsCommand, QuitCommand, HelpCommand, ]: print(f" - {cmd.help_description()}") print() class AppParseException(pp.ParseException): pass class Parser: def __init__(self): self.bnf = self.make_bnf() def make_bnf(self): invVerb = pp.one_of("INV INVENTORY I", caseless=True) dropVerb = pp.one_of("DROP LEAVE", caseless=True) takeVerb = pp.one_of("TAKE PICKUP", caseless=True) | ( pp.CaselessLiteral("PICK") + pp.CaselessLiteral("UP") ) moveVerb = pp.one_of("MOVE GO", caseless=True) | pp.Empty() useVerb = pp.one_of("USE U", caseless=True) openVerb = pp.one_of("OPEN O", caseless=True) closeVerb = pp.one_of("CLOSE CL", caseless=True) quitVerb = pp.one_of("QUIT Q", caseless=True) lookVerb = pp.one_of("LOOK L", caseless=True) doorsVerb = pp.CaselessLiteral("DOORS") helpVerb = pp.one_of("H HELP ?", caseless=True).set_name("HELP | H | ?") itemRef = pp.OneOrMore(pp.Word(pp.alphas)).set_parse_action(self.validate_item_name).set_name("item_ref") nDir = pp.one_of("N NORTH", caseless=True).set_parse_action(pp.replace_with("N")) sDir = pp.one_of("S SOUTH", caseless=True).set_parse_action(pp.replace_with("S")) eDir = pp.one_of("E EAST", caseless=True).set_parse_action(pp.replace_with("E")) wDir = pp.one_of("W WEST", caseless=True).set_parse_action(pp.replace_with("W")) moveDirection = nDir | sDir | eDir | wDir invCommand = invVerb dropCommand = dropVerb + itemRef("item") takeCommand = takeVerb + itemRef("item") useCommand = ( useVerb + itemRef("usedObj") + pp.Opt(pp.one_of("IN ON", caseless=True)) + pp.Opt(itemRef, default=None)("targetObj") ) openCommand = openVerb + itemRef("item") closeCommand = closeVerb + itemRef("item") moveCommand = (moveVerb | "") + moveDirection("direction") quitCommand = quitVerb lookCommand = lookVerb examineCommand = pp.one_of("EXAMINE EX X", caseless=True) + itemRef("item") doorsCommand = doorsVerb.set_name("DOORS") helpCommand = helpVerb # attach command classes to expressions invCommand.set_parse_action(InventoryCommand) dropCommand.set_parse_action(DropCommand) takeCommand.set_parse_action(TakeCommand) useCommand.set_parse_action(UseCommand) openCommand.set_parse_action(OpenCommand) closeCommand.set_parse_action(CloseCommand) moveCommand.set_parse_action(MoveCommand) quitCommand.set_parse_action(QuitCommand) lookCommand.set_parse_action(LookCommand) examineCommand.set_parse_action(ExamineCommand) doorsCommand.set_parse_action(DoorsCommand) helpCommand.set_parse_action(HelpCommand) # define parser using all command expressions parser = pp.ungroup( invCommand | useCommand | openCommand | closeCommand | dropCommand | takeCommand | moveCommand | lookCommand | examineCommand | doorsCommand | helpCommand | quitCommand )("command").set_name("command") with contextlib.suppress(Exception): parser.create_diagram( "adventure_game_parser_diagram.html", vertical=3, show_groups=True, show_results_names=True ) return parser def validate_item_name(self, s, l, t): iname = " ".join(t) if iname not in Item.items: raise AppParseException(s, l, f"No such item '{iname}'.") return iname def parse_cmd(self, cmdstr): try: ret = self.bnf.parse_string(cmdstr) return ret except AppParseException as pe: print(pe.msg) except pp.ParseException as pe: print( random.choice( [ "Sorry, I don't understand that.", "Huh?", "Excuse me?", "???", "What?", ] ) ) class Player: def __init__(self, name): self.name = name self.gameOver = False self.inv = [] def moveTo(self, rm): self.room = rm rm.enter(self) if self.gameOver: if rm.desc: rm.describe() print("Game over!") else: rm.describe() def take(self, it): if it.isDeadly: print(f"Aaaagh!...., the {it} killed me!") self.gameOver = True else: self.inv.append(it) def drop(self, it): self.inv.remove(it) if it.isFragile: it.breakItem() def createRooms(rm): """ create rooms, using multiline string showing map layout string contains symbols for the following: A-Z, a-z indicate rooms, and rooms will be stored in a dictionary by reference letter -, | symbols indicate connection between rooms <, >, ^, . symbols indicate one-way connection between rooms """ # start with empty dictionary of rooms ret = {} # look for room symbols, and initialize dictionary # - exit room is always marked 'Z' for c in rm: if c in string.ascii_letters: if c != "Z": ret[c] = Room(c) else: ret[c] = Exit() # scan through input string looking for connections between rooms rows = rm.split("\n") for row, line in enumerate(rows): for col, c in enumerate(line): if c in string.ascii_letters: room = ret[c] n = None s = None e = None w = None # look in neighboring cells for connection symbols (must take # care to guard that neighboring cells exist before testing # contents) if col > 0 and line[col - 1] in "<-": other = line[col - 2] w = ret[other] if col < len(line) - 1 and line[col + 1] in "->": other = line[col + 2] e = ret[other] if row > 1 and col < len(rows[row - 1]) and rows[row - 1][col] in "|^": other = rows[row - 2][col] n = ret[other] if ( row < len(rows) - 1 and col < len(rows[row + 1]) and rows[row + 1][col] in "|." ): other = rows[row + 2][col] s = ret[other] # set connections to neighboring rooms room.doors = [n, s, e, w] return ret # put items in rooms def putItemInRoom(i, r): if isinstance(r, str): r = rooms[r] r.add_item(Item.items[i]) def playGame(p, startRoom): # create parser parser = Parser() p.moveTo(startRoom) while not p.gameOver: cmdstr = input(">> ") cmd = parser.parse_cmd(cmdstr) if cmd is not None: cmd.command(p) print() print("You ended the game with:") for i in p.inv: print(" -", a_or_an(i)) if __name__ == '__main__': # start game definition roomMap = """ d-Z | f-c-e . | q

command

'INVENTORY' | 'INV' | 'I''INVENTORY' | 'INV' | 'I' 'USE' | 'U''USE' | 'U' item_refitem_ref 'usedObj' 'IN' | 'ON''IN' | 'ON' item_refitem_ref 'targetObj' 'OPEN' | 'O''OPEN' | 'O' item_refitem_ref 'item' 'CLOSE' | 'CL''CLOSE' | 'CL' item_refitem_ref 'item' 'DROP' | 'LEAVE''DROP' | 'LEAVE' item_refitem_ref 'item' 'TAKE' | 'PICKUP''TAKE' | 'PICKUP' 'PICK' 'UP' item_refitem_ref 'item' 'MOVE' | 'GO''MOVE' | 'GO' 'NORTH' | 'N''NORTH' | 'N' 'SOUTH' | 'S''SOUTH' | 'S' 'EAST' | 'E''EAST' | 'E' 'WEST' | 'W''WEST' | 'W' 'direction' 'LOOK' | 'L''LOOK' | 'L' 'EXAMINE' | 'EX' | 'X''EXAMINE' | 'EX' | 'X' item_refitem_ref 'item' DOORSDOORS HELP | H | ?HELP | H | ? 'QUIT' | 'Q''QUIT' | 'Q'

'INVENTORY' | 'INV' | 'I'

INVENTORY|INV|I

'USE' | 'U'

USE|U

item_ref

W:(A-Za-z)

'IN' | 'ON'

IN|ON

'OPEN' | 'O'

OPEN|O

'CLOSE' | 'CL'

CLOSE|CL

'DROP' | 'LEAVE'

DROP|LEAVE

'TAKE' | 'PICKUP'

TAKE|PICKUP

'MOVE' | 'GO'

MOVE|GO

'NORTH' | 'N'

NORTH|N

'SOUTH' | 'S'

SOUTH|S

'EAST' | 'E'

EAST|E

'WEST' | 'W'

WEST|W

'LOOK' | 'L'

LOOK|L

'EXAMINE' | 'EX' | 'X'

EXAMINE|EX|X

DOORS

'DOORS'

HELP | H | ?

HELP|H|\?

'QUIT' | 'Q'

QUIT|Q
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/adventure_game_parser_diagram.png0000644000000000000000000035036215134002420021033 0ustar00PNG  IHDR gIDATx\TU3FH:V*Y#C6mZцiimliɮXf涭NBLiFji봢R@(&$h*{g 3g3ܹw|=ׯZ> `O |@0'> `O |@0'> `O |IEJ֌9Y<`O2)MPUw)\zzkg^]&N?dyGږVN/>$}T)#%GNY\n&X[U.߽$fi)Τy˧6y:B˚g<)7r%k:<%峷7Rxps*D<%d<yﻥ X^ɒ^ϝoW #'m\7Mk 5e7:#v%LT8u颧, xHiȔD;Mw1 g98XX.Zg?^K7O6 XDcJ;vBy Km,/veg ߯c Zwu01|kD]Մn 35qK ՟.1Fj5{z6}_R+G-:m+wPq\^ nN ,J#YzrۗoM.^m~T&?Ep VM @0'> `O |@0'> `O |@0'> `O |B'1]x)*@0'> `O |@0'> `O |@0:n@yc@"|𓋗h'k\pAetNgh`QYQܹ@ٻ@S:܏s4=(Vsڮ{]> `O |B'ai˛e H 0|LtCxҫj-3;ݘ\bmVt6`:M91*}faٺ+Sr2(O-)>?[ Z3mZjݵm龻^fRTEĥfm0&9`*xw6-Vg.#mD}ڢFɾCQO᎗K2lʩnSØҖfA6E2.R_-]5GRN"ziY˜ y*_\d#G]P`h{2.*)S})z5j[I2GɇOF a !w׋"$1 (U+5z|Jcs|mu~c;'֞8}4PnۯCج1]]} g8VMeTKKHOOĴdY s,*щ}9IZ0s,^~{SRC՞L\ټO%-Ś . #1T>Y?GK jVmV( ڶ2R JOVzޛeZB›=B+E4^4\ ߰ V SJKԚ*k^RJ!SlXg-ɋDUYbFј\WS_J'uf{ Hߤw)&Q %@-Ju {!g6ND{g-sbaTQQqUU^{I ouwvÆKq̙i1 LƳVdQTf;U%+drP֊폜[pv:PSnJ`K@ K?2EXӢƇ)II} 7vb7o ֽ3}֬: LHL @C:^X~\8qLbˏp%ͫ+ʩ͊ga.YKuބ(e1UV۱/UteylZn9$KW ^@a~o6'L!kq-ց@ox7߽^&Q3+$ؙMIQOu Jfp:>?YBRr!I)u"}Sa3SMfC2lRƈҞ,e1v|g4<}h#bhA01 4q0'!Q=\`O |@0'> `O |B'23x`RE+ A5Sj0d RnSjI{q'/!a;E D[q-w̯(ॉ/)6}hZD`RCX6<+kS*/DXj[,o(o+֖Y2ՂkCK'W'"lXbz~4ĩfO+]*7{b9]R>r_e:U ohۂ % ^,7 ,l1x #I~GjK˪Gs,*kOm_f΂kM;Y2ǾO]ۍtVh0l /h'.~HME+&$8[fH8`xրjh-+d[aCS|Gޢ]hqsp?y#)I_Sr d[b寍uc딅JWL Җuڏtfnh[b+Fi2xoIGXvWjUWW;qC pYku |RъYC6&S=^ E'?((+(-tsMD>8ywO:UyT#u(vj`ٯ-|c4p[o d5Nu{+W>իh0.Hnɸ+Gŕʀ=2rO"s+f_xnݺ8{p+`F|67 pLm}wT޾ث zCLth x_R3zEjdÊrmoEԛhGҠM:N8~mWRp6:p0FoǴڟ}@Lhx}ԗsrh O#DNvYE+kꙷ5'Lpp`NTsā(=e]=MPy^'n}aŐ憩- :e,J5w=vL5sO#HՎIǎ|gy)'yAEh< ]iʭ}a`es\5GauӶ,\o_ibX:P]tCGeu-J㦎X_{.'"lo~f mIɴ{/ׅzUCGFn!C.~ 4yl\|qwѩ_k_.].S X@l5]v/7mڜɧ_2\g11_}uh^;"_~W8k˅ߠb!ݵooѣW][ٗ7lh[EE"}} OCB~,ܷ`QQE'++ϝ;#wY= O|22?S \[?;Bӧ/+/h$6#O>tUjڕW\KiFD|wZCߧ^i~=>%Z@ % < BRd9ExFvVUUɧJwQclY|sPmz ?͟\|Ţ*++$~_ 4A_^B )ʎi3gd߾N[o-𫂃b򋌯/xO#رscƿt"ZZO .sͿgOv?.r!C&~{:ݺuXsA>f$8_߾;N<_MIw%Zd(Zv%gΘ.&><󁄝viwWkzSӉmNgԍ6iw  (Ѐf:nd  6Qݓ_c.' w=!^*Z䧟~vTwlzmH{|/jw_J]5e=a.ƛ3Wks,~JBX`͆w۸óg 4,@vӦj.L͢^}uy敤߶wEÇ.z)Dܫݜ=w_= O=H \OCFeCwohݻ3.}уDJ{Iki7|@{ԩӫ/iۑG|epM?|ܹ민U ^0a蠁Ҟ=G)^'ZrBIICFjǼ[/|@smWF{|'k*N}[R"~~~Q#}r/A0 +ZxYO>,?יw炎!yw Wm{뮻\~1Ưh{\ )__}``@3Ƀ+jmhk4--N4ߚi)L?Z.R.446L`{ݠ 6Wb EF 7ȑ:u:ѣGϝ;ܫ:|YgϞ-;\D.2\|u\PP`WXU-RqBkt޽fi셳jn__IǏkuƆfu9K;z~*,,lWs}e k췽btӫgO /(lmWtmnOs^G[k/Kձ91vzfryfxĉöNƈ`0X'ח=׽5Z@^׬}> :yvָ.2O _ޡ5\K>Κk-}%ou;90;vYնN@ 6I&mh{^ks`q˸qW :g+ 2䦛~.R-xu?(^;}l6i:c"z /o!Z'oBQ):u4nmL1S~醸;):}?F`:vT/&8~Flwc?Nov-_W4;[To1QQ}@e&I3K /؏?4^G~)ܷ/~߀IDATtݓl?nȰ!+5O}W KX犯,”|Z)R,UUrRB?~%و!}[L~/d4kIy)99ʓZ-SRZ(y¯ Kx)駟:vڪ]votx!odgD?59rq˻xCKqef%5 ;V˟:'gϞmdŪe-tϔo'զ53N_hRX%B£4:tHd5t0^x6_mvwM֜*y]\ Y4zӕ+K޼LsKM[%jKFR,IhDX1,C䮼lKJlqDR@~PfŋyBzD= VjPs*"=kV4=cppQج5ZL$7Rw+D& =AM_+,,LF, 8"gswee"Z+C)Tl4A/.zXb%sSmfiطR9*BuoSbղW'88_rKOO],gObM-CO27p>g%,IM*ͯ'ȑ#g̘!ZK-IU'LnUMKJVs}bl x3&ӳPR?xN,_lҜZ6!Oac IuL 퍡lKل6 #SPm1q~Us:mCZps=<ԷVүEfTOȰH LmT\YŬuinioe[ vq^!!>wֽ- ayhY3YعY9M>3Sh|Sjب§j%'+6-!?63b5g[LLdJ73J,5w)MG뛢lu'╒Ry4ecUh/gFיe XCnU (_n><+S-SWq7\jvI2ݥK<`g͜!oۚ։jE"!CjHC␍=GkKXϟyZeǮ.\8vLc&;TtѬ$ZN?Kw kP6x}3Rҍf!ޔ-EnnUx'\YQ.<1pSКWu*-xuWy(Юe% vpU%WvK2Jwl:OIuݴ*g+uDh±/;t6g`G2Fd'Zl/|QA= {.ۈmS&?xsإ3E:vQ^OY]3f%hEVEo6N8Ζ5E'jufAɲPSR Ab)C$cL۱i rjβĵ #ǔc6l=A3`O7p882Ƀ%yJ{J'?Xh.R'\˚i)LnRo`nҕqQ `)D$k`oSKH29jBD?CgYj28q; m,zPc!7SճQO \Zl/8?* ^M<0Gj]5B:8u~(9y~= 8tp8@Se8jGp(Cf ՜넾v(@r8e>/=O0O?iN::~.Aclyڨ̾h@XhΝvӧVy 8sh֐QǿC ~{E2kyƨ2yhyu aAݻk-Saݺ t:Yw:u׷]7Vqu#UW;?'D5*+6}_j-w +Æ6rܹW^;ylw~}dk/EhO]K&s-JƈQM쌾.2|޽z no׮]_h7G7UTT۷iS/b )/?Z;,+y?^mYp~s tv?ңG en:^;~ ́WvUP:F{:ZV[kϝ;Fݻwpd78攼 zo`?)}w҆Ļԩo~H_+̝;hIw~uZA&N5bwO>]P"Ex>R\z_sX.aڐӣM4t萫‡t,\-_%5]t`AF_'oGˎmE' uD,tdŅn;&/ʟǏ_NA.]4T> `O |@0'> Ӄfm@!p`ÊSo~ql>sh%`m`]`DfCE ̲N.ulGD*0s rz~u8 pSkz;WQw]C5i}yez{fu"jS*#ɬ{k׊g/)\/`n6e[?[ԩ"bY+#;PHYsz2Zζh^iI$/fʿ-+޽Zɂw|D}"!p; 4ǥ={9ROtsO:.%O-^"ж?JSGVkYg.cpB@k[ص@3~@k; Sya.((>|ٳpU^j*"'*FnY_atD{ ap ]N\ =`<V *ٱ+k,;&1Q5k.--ghڵx/;vY7fh ڿl`,@OFy9WuxaXܱ ꌱ#(,Ɇh QF]TR8hy VJzv y3K+џ}'#2tƨ u_0{8U7uZLiIDATIaڏnK]lQe2G8il H 3&ThlUx$/ FF}1|='-:š*eIQV͇lKo.#,g=2+mMJHR7(aJLۭܾĨkV4 YEpxak׮ᄈ%/SԪV)~*iPdQL5CfxLK89 Z6.!YXVZk wsaZ9rƌd^ֱu&GWAۊ[o-y{_y(R?yjYY$ڥ91$mB^{~*ʶMhs~z<_Yc$ 桹sf͘fcN'Y\Ĭ3,]V p"6ufԴpldDlfZR(X曙J^j_햬4/Mg+f\l4&,Rtp xd)x{&sw.]H^Z 5s tLO/rkI%/Vա'm]JQhrR]'\}YױGi@ h]&opU=~?'j= ѡkʊrGM_j-w xk/ITUUeu,s-JƈQnChqo{SEEž}6/e[jBmp=kP>,p!8P?~xw`.sͷ֞;wNW7ѻwo)ە9Dzjÿ޻/$Xp0 ʎel$pҷ~*))mA{N:=__tEގ 4W tb۽{wgΟ?h@c,5:y;x `O |@0'tIVDV ͖AԞ8`nv0)E+fP$ZSĩ.M@{)ޗ/DW+˽rb WgEJ/DhSs 2+fQ|@;5ǽR^Yn҈Jﭐ-!u^ъK)KV>x r^[@E o >QrN+: "o=iP)[8:>aT}bq0ELZ2gZ{-g (ivVCL\o+jWn`_Zy`&o <`p5 lY&^΂4|]x"F}z `hS2  pF~;5wo|`m᯾z lSPPTTl2dw+1q0 Μ9 4ߗ{k8 4:tKVT|Hi. 81Q_ {mYy@ɢǎ?4GH~wY?gZCӝ>@p$?irp-8qk7` 3:G[nwWHHPp07ܚBr!p' `PN5#x"(Z/}k0<֞=x/+@Ю8^X/o̲Z{D fۥv" YVc1k N'wO9gO +R>6_--Vg]$[Xh&ZK9\ư4qM2|EңܵKXZa6GD3>szEF'1/)4bɤN%'933)Nj*CE%-ĦI2NR-jo6{m@.{̤9´='ZYj~fg?=/J#ya59p߾ӍwOwߞ` ~&)JJS4VKls VMXPAdh$TjRXϞgCk?`tx!n8.|®!8٬B8*- dws'3ƛ?=1QQx/<;W[~ݸiFLtL:XM [jSZL/tZlr_\-IՙL KnNwrqڴ0Y$&֝/ `ZNo?z~ᰳB{-)d1Yiȗ5k:_~5cB"k%֘\RYTYTWV7%ޖiV}+'Ms*BuҔX5tM}9}[x^~x/ww?d={ x5)eF/ͪn4ld-~*i*7Wn tXO|qjdڬnkOxƌ.HRI*l7ɩzk1?ǚ~kUsrRB +2e|J%2ʳYYҼ$ғԞRkv?XlKل:/ :^!!>wֽ- ayhY3YعS{t/FZJI2dض§j5-=%΅6OX 8mR,7OD7ʊno Yٶ$*_(Y 2ݥK<`g͜!o;6' 0,BEC5Q%ݵu~VѦ/ʪcSnC6n7V=ʊrL,[uRIDAT?ם}zNv5cnGW[Eay  Q33Z엙Q7nB)2k.7Iκ8FmӱeZ^6"tl,tckEUiaF:f@誫8 ѡKII:kS#ZiYc TVt$>|20$6>%'ck͠ $o{3m|[VW/JXzuRGJ.Lgo2X5Z]To,j e{<9dS=^*]`oGV`<7 h/@`)5\>s 4ލMGۢACk𳘮]΍/KߐFnZ 3F·%֋0vh0xRѯo_!qSK߸cǏYOkJ$-)S&;{lUU)Tk@X@Pv?RB隫 4G,ǿ^ktIըpKLm \ȵ#w~LT.h5]u+`P9@7}ŗ_j퀀C #H!:'UUu>e>Lv!R`m|3p>hIwooxǎ5Z[4t:u${ 4ȷ%n XN^eS_\tt:^ܹsnCh܂.x*@0'> `O |@N:Ӄfm@ x`ÊSo~ql>sh%"L=m-t|`g~1|]H<ݱ8|YRY)NHf|!BNݏζ<ĩ5ɫ(߻! ȉBr:uy{)dֽC kE󳗔Wolix[^`g˶@[cS-: jEb9euVG E+"ajxavbpx9I lAF<^l*lv8o2S=f͛hy#akœ骫8 ѡϻZ\:{PQQQoNVV;wG>lw/}W^!R`bG7TUU}il2;F8}QcZ̙3>y׾-)h&A>f$8_߾;N<ٗˆ6/|ľz`< @̀Rn3ޓcm{"x@h7}oϞ=+4#q <MF>>t{j& }Ѳ }lܡ5.4H9.sȑB]~Ў ȓ%n2k'/'3e7ziotbEppESeak5+M7Erx¬kސ2V>%.-!=9IU=P7})H"V8V <>5kvZp1Q׏{S]{3M^h:}˵i}k9=1t ]Rd CeM(aJ9 : Ң؄*}G'f{scqv%6~@͈1,M=[TϱmVbӄ+)E9IQ:c׏%8 )oÛȚzkM:A* _Z`1FBߙpls d]kv\ GԮN9=.PT"9Ƈ=鰌C{fD+Ք^ufAKշHSR AŔLIױi r..e;7҂SRT٨uW75gk{.`t ɰQ7dȱ t'h#ɡΖ})3㛴7ׂ&5jRFM4K8/6`p]'q(NG@}`pO= 4mm՟Wɛoڥs]id1-8zLk 4@;e& G] ?pv@W]]tƩN%0(XkTV j7}YO{'-:{T'*s/dkW2Fh@h7G7UTT۷iS/b _|e ?+ 0vIDATܣGz-^{cÇ.A uo/d =-+{Ν #G[fc v'kNˬnK. ` !hgee26nIiNWoo6 ޽pNͯ/" 4vr\?{Μ?2a,!juv`9xwGt:tB޽ʓBh@tP0'> `O |@0'tTH0x-o=q9j/VwWm 35m(:P j[ ^NI#E:@6꬚M.kP&N_ ض< `5ǽ\Y򖙳CsӳgW^U-Zf+r_޻`V5-OB/'m^iD",\op41GdOfYd8QBm S|l1x\WYQpa%'.l-E(' 멻/Dh ^0V+F*׺xZ|mPIORK,Pg^Z0QX6_.^ؼIyl,GUWW;qCϴFeEh'}++kGcǏ @Ç{H j̘_޽z 0@=^2/?ĉvd.(%/~_MOto>YYYQQȒOgnk:/^ܕ5tD0 >0{c4ߗ' VWR TUUߐ.@=}'o=z]?vW]%o ־29cСCPQ]]}_}/_{u9q˖Em+E ;ve wi'*6n`@][EϊNX䢀4|li/8p@_rI\M?ڶAz CFbUIIg?pܹsڔ\2]:w.Eh< Uf'}sj;ߝvt=ch3g\õsWLϟw{5uux.rz֚5Z~MEMs?xo udK{F~Yp醉qwv)ohrMZ{w~? -Nz֘k{tYs'V\{4{F``svcбKJJ뮫3?3o=Vlz?g1M_~ts`QEEEPPh'77`Q|XB.e_5fL/y..ExNz2oݞ)`SGu-Eu_^FnR!x\soĈ]t9}P/LoC1y/X O>i j{WGyu!W^!|z}|][#FP/v}ȷ^"Gw[ߗ'uI=*\s;q{pA?oÇ 7b^ѯ_F!Eˋ^̵~Z/>g1E~/G^}աC/]\|]SW)).)___|-lٲ5򺨭[>|啢uuݺuoda5?-gO p~`'}:Ρz5 D+aOh%o/6'.B9w̏?`Rp@ܷw 9zEwN'8^wA[~5jZjԨZC~q#;oZ{dȵk;Du9`O-EKyqּea `<5k߶P&,k]o T_tEBYD3< n=I7M}do~A"y@\w@䟡5k a0;vY=ǚ3giY3gt]-4stؙِަ{uڏhHёz__6~Դ4||@ZwwO6.Q^~Bgc|wXA3'Oʛe Hp?&/y%Bi-+k⊛6m־qiu:Lyx~Dyi5w^as:iaF.}uF#yңܵKYa6GD3WfF:ǚ_J !\'μG:-vll) 2S&Z=`-A}J93)=ZgpX>7 )MuXZ~GpXL4u>]ڳgZupݍ|^)+ޭ5FF;}||g)n<^L\}f7<}1u,kt9 GCqGK] i޵77'IM.ѧTkxў>Ζz^\*GeSܺSCG b-`~hy4l+wV9ֻkƊOɃMZIJ_Nq  nݻ6_`,ne/$ڗbts'3ƛ?=1QQx/ ߿wگdrnܴId#&:z{ffs-00MFA !bc3O[U"MɅ iIK=k))/GXYՌɌNn[Fٍ^3~ޜ\(i(tf3Ƈ͎K4RoP4ϭ:>b#G߰ƌ/O=xv7'7Wdc za~Zfie /pp[?2L>,/'푣N3mHë,3<"ZwryťMFI?F7uwh̜R҄B>ӭR*h~aNʲRٱc5o(c?x2ϟa `vMZn>o~Afס~ˌ5wdik-SJ_~޺M@Oa: o;t ʽkdl2D/I'D֟;Ls}vSY1jBD}a{}UzrY(?UdP3$,ɋ`hᜓ?zpIDAT`=aA="unSү ymH`Cs̚1}ڷm {d4s[޳U|)x*edcrBڟefur-&?Cg9^夦B {޺l%z +딂oeܸq7o֬x3gU. a݇jcɱvun[~`/_S5iu;{NZH>h=R+VTئ|W_^{]_NܲekuQ[|0+t/oB1s;d{;zhB2>դ՝Oo`q~c \o?Ғ'r ܜU]u@.޲i=o_z]u^DDĕW\qU %5o;t… '=),om MSMkN毭ߎGU;xk-J/q硫$JR^Ȱ!^/J&xވ5 k& E+ *ڼp$3mhho4$mX#]vX]eAXH^E8u[ڇ1֌}E}.֢OL< cne/h9\[{ohKsQ SWm}c&Ϡ:F}kG U=}q]e=G  pǗ%nk cUzcIYQN 6zG'uyC!QWӅ_xp;Zɚm %Щ=78'^k4&kK@z֦sDz|[idnֹs=t .+,EeO)Ƈ.͝кԲ_ꖩՁ~c\Zlԁe\3VF~>|aͮ~Ο??s/>BeD3yi͘[^6dBgڻ6m/F|3ֲ?LM׵{[~@ 4>O_>H6d`KMkIQfPk'}#}®Ϝla@@Eyi;~|wK.Zx70ZB, ܹ[zD1yAK. G|^{3HnӦZK{:ev3::q`QEEh>R}?g$PJ>ȟv 6FDw-iY{{3fByIF[ޚ=l:,b,݌1K.OkO/n7NȬ o7c>fxn#?3ώ=qD_k:9O8 -ۻR1H u}=O?5:u qf|T/#>Dndx~r~nڱ\q{޿ @){WRb FtWڵk^YrQ!^.@{~Z/>yCEC„xi޳GkW4L2ΝUUUZ{77Z 0Оz5 Dr8y۴y[k֮g⊩NWmv仠v? ڻo9u}[K{R\hOz+9B=xWv_ZEk A;wͷ-+1QǺl2 4Оbo."Ο?i{$Zɓ, 4hW~ ׎{4st٨9끲c|_=+s[>N՞ԗ_,o拽{Jk4 @;c򂞗\"27~߱z͚g>?^-r,&_~pDK..k ],,^ `}wMGk_ڳ%OM2E{mZ5FDlhK+/{7}W\1b={$8X~޽ߗoݶ-X9x0Xa+~c\w]V(O>4+듌e&/>vf%A?p)ۘ??>s =/< ,I4\ K?%hwsrsB^P^/t_V}/qYΝ{,<{@=;>sOyC|z ӥKq7׉o-\=L_sNkd:soက'O { x#Z6gΜdvSմ} x)@iO9@0'> `O |@N@JC"&r[8ZnY[̘PR}ʊwYêLFk:B OZbXil[2?8M`q @hrwV,xY6<`w(wY{"B]qJН\o_ib΀oD͵qbDmmLl7n3W\g꽵 ^ 0אV7rZ3xUJ"2HgXzkor[VZ1x{LڭӃF$.pm,†fv8w j_#km8sk&:1`x~EE2BoY^.\c+ T^8O;-nxo2N|G^%F[oj?qn<$`XPD\7du`|u]/+^wR.Jl9 {]t Ҟ 6h@W if8{l憾7駟믾r#_w9u-++ܷG~ BFS>}ݞv787#F 4h_{z/M7)PcW^wh#~***ډ7;2Nx@IjJ;f?_{E xXIDAT^k زySD( ;r`KFF_pp_,5/?eaa_'^>4[Z.x07W?8g֞:uZ{cGe+n?gΜ]tFިrpv7Z~5ZEx2 .LIm0$vWZ~s[w~Ӎ7wm_/(?^u/ނ 0._e{4ܹsv֮/gh$9R"ch~HW^! T4paov+y7yy[ AAA_Aއ{qaw]w]<=1㔫 ҥ6gyy+ʓ,smy❗A}l@+;w.vڥ t:{&DD7i]_/3(TywJ 3|/OQ:+џ}ɥ|56U>cK,5ꌱ;yIFy7j˔3ڗQNE%eUnjPuugj|nT̬nɽM=r~iw.%%%7Dž>s ئ_k+Х6?:|V^A׾ w2~v/Ox/ FF}1|='YH,=|=Snii2&ȝRJ"0Sc NO5$?!\.K}ѬU򫪪]?<Άo}`7}mY56˻~q :tqS]@}WR|J-3Kk_u!B" _x/߿wگnHq&y홙  +..?}WVV!UO_*MIy2r,5Nʛ0rVZ[Y #%.-!==M+ X%WиxǓűmŔ8!-6!~d) N=Lb,ON"BF,O-^"oM\*ykdj…:++5gCZsjh}_%}_ ZB 4ykyEuy޼y-[8[nyW{ IܵkwYŗ)Bk3ZiƤW'V))9D-հ4gZemPI'[w'YXVR2OW#MUnTvꫯRiSMW$IMwֽ- a)cLsc[w1Æ,{ o#/zz6XW$i6ADдWtN wYvZv pSR?_$>8[]fΐ7wrIզ4YU{2S酲gye|QvVS JqORmAwm)v%8'^9%̴mRa>][xIY?|>;{}ǯ{{MCk=ٜ؍YhN6 wVC}SSai%B֩(oh֑#G) >7k+`ȚXg3lXi/1Z^OUd_[M)8MħU'ۆbR}UzØ >%/.P 7m޼ɧ'5m^V;Pɵ-~駫Gߋ. {3Ikюܢ c"oBRl]dXz&'%A0,K4(]CeMlG{,gkN4%#CUJ>I?vLhMeɶ}s,Q}. cu=[3l*>$؆NU/I>VZJ-߼F n{aK/-?v?Qx]uOpBt(;؏|Nu:y6Fz|.]U*9 _7ٸaf[kjcl`Su]gi>tVdZ,m;5pĉBhmNwhͅv׏>A0uC२h̉C˛l8NOK}[nZ{WV@_i/ӯPp@Gcؐ!%=5خ u9 fK.SLދ $>hoSeeָ| Z>>p}$nUx5.nRR }X#)ctyg[|Z>`On^;@Fkqe4 W_h 0'4aBAAg(-ӣG > ]\K<CG0|^yk&oulٳg_`Ǯ, 4DEšÇe#4_|8uT#2Og/-N:cCP4j'x0O I@Ku^!̙3d | @Z8SnٺTI=A}oopyGl/!\8IDATX5|Hˢh"mF^RߴrAD/%)ӦZPC 4O;Ǩޱ| #ǔc4&wmZ2aFYoJuYI1X%QI&kwⴰ:-1$EZ]4h)0|^yk&oMFr(V93r$ 6cLcN^ 1'**>,|N0"`pKhO`O |ۭ*y@"|M `fذeGP;&Jx 0$oz0"`O h ٞym+&:z {M6zՙOF;vei N^ 1'**>,ڵ(++MqCċ)M6e={_`'x0  t@{$.2qĉJ | @u~eJii隵k p.ܱC8g> 5|@01,Mt?s.K\_$gΜ`4$O2uoZLY끔\Ί]k>xG]B}QO;bk?/S/ʕ/UUU.{`}gC~+ZG> Y9)z!Lsr[bm^Ҭ8mLgkrCDuU ťT'l-Co$>:$FMv0g0p?n-sȑǟXp,kǎ#| 2wwU[TTl~qկϸrUAvz/欳qޛdt1*=>/7JGb*FVnu",YgfjmÇ~Gmg+]  1 ڿl j|ɛoi$+EDԛVe1Z信JO^l9gZo~E"~29~ޜlIZڠ[ K䨍\߄r!1F%L]eu~=w_pɱc hLAą ջwy7֭[qR YYN&gO5kOM[U"M)pi|ќ`vd,P*C*=SVoJ60*&*Nzt}g1 M7t޽)+^O^ FVޖ-}qg6tCoބ̤Crҫ|3Sk-2eVvﹽ.~'\VSn3T c{6JXGRo&*4m\a3 j :C@{dc4:LU7 QbE*ݛ2!1``O;ǨKXPI rgh|^yk&o(Aj҂M?K>hncDeN^ 1'**>,|N0"`pZeG"|TǹFQm `O h ?(@!|@c6,${Ǝނ 1=zɛ gz{@ۊ޼1C@E0|^yk&ou^ԩ8w7ڱ+Kkp20`9QQqa _^5 EDEw8AӃMYrϞ|ѧO $/Br{О|koI@K.RkWVV t41jv`- Zg t(k֮wqv`k.ܱC8gCt#hIz٨>_=8-h KǼOܵKku:v`rڪݻFIII 7qϜ9#Z%/)h HʳM-6qedxJʴfH>6ݾn[좆IQ:cF&DiO>E,u:y|by?VbgZ.K}Ѭ]?<ΆoV!} ֻM~BS2m ,HbTM̩Qn*͇U ťT' o=Cnİ!+1T .Ȩ;'Me9 1rcm1cRP.w;WNWɛh?p_!%2fEVIm[%#v|qNh[wpQXgZN=vWBh홙A-uΘ~AИk _6z57ߴc ƍ"")q137/-WVm|3Mj=2ciiVuZl9ْ3 қe-QQݤV7D73{%rOa[K.KCh=ӣG5q!f{^u;~\aCVVU釄_t^m]EhbBY‚iC*=3mZڄt&sxO͔m?Uz>*'At:]߾}BCQÍӶ/z0"`.6rVogz{h9\ˡg(0\rHڋDkߴXkL|6ODޖSN(2"-!]ЋV޼1C@ X:Y?PuƩRƎB9nAèbIG{!P@Ǡ"+mԓ{4]r,gs4r/$wuzEĥf,K PJOh\D9Y8$eWڮ9@h_7ٸa&ڑzBob 1k s8>%Oyz;vYOTd`sò_$/Bhu.@И:Y;:20ir?5=/Dt|``}y/!u4&5~ɓ'|_iA:4*ӥKŇ?>'3 ?- jIee/ W 0 ~ֽ8ݺu/Ot|j3NpBt(AzT۱+kbG={m!C (|S=^ [4 َ0/X;q_|ѹs[nIx#0f۱sױǷ{ӹҷ~*))mXԩSutw^A4ɓ'|u# tZw;ϟ/bFT4On&޻˯MN>w@صk޽z~u.ވAp P0'> `]\K=1!|0 >\cf^8[Vyժ1t^'@Ю8 vFya^R@;֬]+\v3fUWW ? cǣ(-Vg]$ԑc;wxgV?,OBfR5;6oBQg4:͙\cXJIشڏ>Iy o%Ez&>Ζz^\*GC}b:vDGe-tϔo'hDE a:l|iں#MM6bgf CE&-\jKņgcu9s%x YaFMIyL%2&Vgķp뭠 "Bf!ZDVq-$^XڵzK{@GR:ڀ²Z%Vf ' YA=[kWeI/Q6⭷VHxh{x^!!>wֽ- a)cBnfu}UzBbJ纕 YSܼ5"K_~Ql<v߾Ϛ9Cty_EdX",ey2f(EĆk)-5#Zܨش,2oK=1 0པ24*`/Nԟ$Λe>d|)Æx(I-\: s,g8d6̶iz 2rLIQ1FYV& gTG"my`W2 'WhSb~mʀ^$~+M x.E ͋^U|gr.8=rS|F@2o> `Vy `OUW;N%0(XkTV [Ե{ `O |@0'> `O$4(%`^nY[jO07;on㔢^(t[`>`qZdvp&l C"E^91ndž"m")VDʹuQ,-(6`â6"ֵ.b"?UL+-++{RP*ܭDnkZReIeO*W/s&I6I4doϫys̙ &|y;6x'b@oM?_{\t͐>xG-LcOt("zxاpc8a\^GGG+^}eK)o{G~t!R*/~s?=g_|OhӚGFq+򛿙2eܸw$Qm fӯ_|k?|rɄ `,`J&Cټq7/O@2~W]|W~kw/oذiӯ|?k (}1c?i#o2'0`6@_zǝ~b``ޙ?N;3?ů>j00pʼ$> kW}i:=Fa8g?ҕ ;7kCȹ;4~*}Xf;֝Q<#1uwŗ\>3GSS3zo+f}]1fƎ_ͻuq|{f#]Xo*Kv l)Sw}rߟ^2{>Ybw~@wZ۝v޷CnKlKC#kvdoI?D[o @Vc:lٸqvg;eM=n LJ0~zonؾ,-2ʵozp@m_gԱxpoԅ+)]ݝ]նE%4p7ǀv2oZ㥙d8 +Z6W;cCuV8! Û%v=\aa&=oqB>=8󿾰M %]O9=w!Dgǁ-!4 ޻di'>Y~?_\,3 ~}zWQcY h2YZcINsKnR_ӽݹi#Zr/Giyug\Z7/bu ny*?tr{2 WTozW{+|Eno71J] $fVG0Xo{G~Of#݊d#GuӍg̸:݈'M7:;fxP*-֕]]ٍwށ#%!ͨлtdwʜ9nSMFaV\|׻Z a/M=]^ܢP.MTeϚ۵W7v@]NB[}aϩ^kt; `*K|ýgLxG%Ǝ0}T.{;\/̈3UITgpu`NЦ>Nb.gTTTTw.] tkOk:qSʵ_MehTeh<4_k4?RIƯ=ⶒ5]3{"v@oD?eF5-x7U0sf`ꁽ coOIzLNeY|ھ#NԬ(^Ɓ%_b7\rջMN'n}H>触 pSC,J\+wϸN_^p!VPPg}OeLwO߭])*nz Wkw(=ᵖa^JgFn_?sAE쭡 e 3K]8k 絧ּ9 W_q{zg7F! tEiQF&~Ű[g\%žQ/'3 1BW,.>I|k0HXRWv8F(V֎#HG8:FmlF:n\Ǝ!1<|4= { :g\{jQh9\:s>D'q‹SE=\Q>0sM ~+%">Q >UUV3E%(4OZ<t4?zNJ.x}UKy:k{3MQY<7ՠnvux's5۽1eԮ']8n_÷N3Z,}L9#W\wuOgu`IɄ-^Y|w{#V0{'G0|ȸLZN mF5M!Crn~UIDAT_/0<0뼵#If@f+/dN}Awmܗqmo{[` }h[ж300 IߛJK?(۸6>˸| ^嶶 kFFݓwXTQCBַ}K%`TSFwǍ( ߟ<W5ԣ WFM+[BNy;:u$1cNޑx_{|p~뿔C`:qF)=|bMcQ >?ʺ /}mdw5㋏ ?!~EO}_u/$XhwW_/ݼy(oyyy֭[@" h6*$ @"$ @"{J?z#W\6{֬W؇`A FaްaQG n-KO^RrIXd¨ F`:1?-0`B0-gFHcndQߟW񙎎ܛoyy[eFaϾt_rͣ }'Rs1$κ+\Z%ʎv?[}E7ak}ao/|ɺ3/c|I,'/5Hǟx~edQXNѯ KN>k7-kz 2합O\eX=*k;x嵧Θ8k3n+\3c+n?5 Kn+]M^ô{~5GT^)>#%C.?!z՟dHw=8YfVGgqUGԘ=k#WH ]YWs.Sn/kQԼKUOִXr[W6ʽQ+maqVSsׅiV.3g4K.̙־;51dV>`w+x3v^x`je&bᵖ'wҵּ=g}jց3GW~ ˌI"-x7U0sf3A7S@n7NQyGJ2IjIo.{*/8YiN2\P=.=ue QͶp|hݓڵɖO-|򇍛[vZ(yYY/bu593]V=΂EW؇Fmi6v@]Q2pWSo_t굝k{]kup4[%?{[ɁQ58=9s΁hCebmyAʵ%WϞ14pe;#KouaִyjfsP7&t <@vaTJ_>gl -n @HDHD!]r%DHrO+0H0 0 0 ]xuU v#00  :Y\|5ӭr k_t~ayzÆ#j0da0dQ߳y#$1T|y( ϫLGGG}7<-20GVg_raSfzm^(+bu/]G}Fg|f=ԺY-iqe%'5ꛖ5=XltGJvaM~k+ :֮M?*S=_%?aZ~yR__r[Ih}}PE*Ɵg:PT],?~ /.@~}zWQcYVE"EEך0h>oCOߴ(xVRx@h6\=ruG}.̙־;51d>?XC\vWƋqaۯ#V8bRkQ’/K\3jg/m3߼3dyEztNKgk~Wv_66H;κ#HHDa/F(DHge}-!qj0r 0J0 0 pu]8o]p?-\`70 'wذaQG k\/p_n[d럎&L@v/y{6Q biӊO Ǎl޼9~ -_OFOL),ϫLGGG}7<-Q{?] %7?ٗ\aty3N6KWyѸo- @v=82{֬gwjj{SO V_Q7]coߌy%(ZuW0uP:cGݗ`?>Į=u9֝C/ǟx"s˭OW}dQ#[t1vƍKN>k7-kzlVOcQ:l.cqڽMBc/OaΧo.\\yX/laVR_]z4}aPRx@8ǒ(n츭dsM&0}ZT],?~ {dsnC8~zU#dÏ^ KM/<0\pՍE)T啷=Y|WX݇C:fop_m;축_FaԼ ]K´aP]8zWzrʜ9nmhG>`w+@.٩:zmᰲ {NVo wʴY74(f|aFf}g9nya.LPz7~?{F2g/Lu?[&@Mawr{ŗWr}r':蠃FmRg.FX #'znsB7 KOR2$쪅 iCatvV=)Ե^TF%;'m7rp_-;^wŘK `q\7#Gv]hFtoou1U~7Bh].(3 <VTCSž+ 4wt}Smn*WS D r_Jvl~'Z+J ;T4mѣllojڶg"]߻sZj0ATgU&J!qayǖW]{-uv]V[LcRUUI}eqV6..-DM\5/R7RTQe}c^\׺cM./`LzNW.îo_^QհU 4[\MUܰ0\>0Aя5ZvbgIUU\Uau.ײT/~,8nAUR]W+%2n^E4-| uҕu&Һ8n_^5E.olکowtPY~g&tGmya>ês0rgye?8UQ:T]ݸmuշlO7\RU{txw}X wLr`fNL-+~~Em[,kmY~PPѾ{оVNL-+RmL3BSmmD*{QT[^[<]Gviz2Gt 9R Cv;1 0\/ wL.r`p~ޡ\4UV]{ms>c})js>tIkSSf&[}$)斾J[k yA0qᤒ0Kkjei_PQ׵݆ ti?4wڶK⎳{w~3~)w4R="plw8+*9)+).C.en|As߽v0ønxcr Cqu{GcŰ O/=%z>cnE hw-ˀum}_PƕtsSCEt\735t*;T-(\P7>#ncpo+oׇ۰~  *;cgEeI{ڥ6z[Zוahe` 3 M} nkjܜ:pu/qzftx *i-p[S+/#2&a#C){p:vso_>Yth-ݸPcJߗ).T_S{jbOk\؂G7oenAIg-*Z\Iy…sLBÀf#FL6[gmoa_䚚Vmo(/>]3zA)xqc|<|Aqy\Lkܷc.{@##"pimؗn>N[G \[]y% 5e{6;mY~FAy <̊?wI4HTꜸxnS;V_q]7Sw-cz[w`D}i+'[VžQrm}NoyS'v2;6ה.4]5W_מ{۟h+wἼǥyq]>~li}=&!a/\UӺoBӗE᮷q_*xqV-=]qjο'/5V⾧o/V_zIp/dá0SV􅖪>@_8Q2}qUe}Q @" @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$BW>d\ADHDHDHDHDHDHDHDHDH+~p#W?_/9r_MxGsKW_Oo0rr)CqNvZ4oڊ3>ٮ2!sވ{YvQKwdcmu/zԤ_3_ய8 k;6,X4s%npU/oz@90%Ļ|؋#3vLi HyNJG˺뮭wݸn,^qkF?k(*y{so)6\KIwbٙƒKosMjfݲ9QkKgj.8gE{tCjyS `R6(nV͘qxr\/W . KozoύDiS,\q͗ś:mek*ܑhXjFUk7I:9ii3p?!I83Z{m_윾{`uttW=s\ۿU dy_n|j|H|C}Mʻ,yfXv~QCG]8 idȥ |dJaah]U+=_`R.!n?ӧn1$̺\ i66o\8oawKN*;0rr6Hg?~6n-;o_̶ۖ}iy3@qzۭ`DrGzj]~;?~b좩'L:sj`mCӆu?]Өݽ[o0YƭC8~ŭ>o䒰=5zwn׿?!N?횯 ɑ8ꫯ-'zl͚@vwk'?s?uG'@rvHȽI`/$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"uttTHDHDHDHDHDHDHDHDHDHDHDHDHD/V7TR j0/Vް뺶TNJںW֕.U^M5Ek K[[|v߳XCyg0j;koaSQf(nL.. C&]=}._y{-)ᱚ0 'Ǎ‚[uׇdA TY][GǪyy::S+v^VWֹlnz&[;ҶLm;mcg]k26?~1!{{w2d* Cn鯧\[VG+'ԵCПSl59^vG˶4mcw?U^s\҂~^L8(}paIy}H{#yׇd*He XXTzR Z{L\PTO.kmY}YN8^WT wBA9wׇdLLES/nlySyPTaI(|nzo _IJ%ýC~N`pAqɸpRIQ:50^~sŠƕ3>  ; &Ɗ-_Zұٟܽ L0nNJwQXKY_X:9 \88hPx،-,)nhnkOiv-}rjeje@l(pMeC/v.\TcYKuq^^^qMN=Ǧ*j[:o`59*7e:i{i(pqEEf]2mOY:lǼέ 5E_iMw}L=NAv!ŋ楳×T739oki*2?Oǝ_sM/AlMǧzi[[smE., vCnmn/9Rkua2wMV_^ta&/} [ ysӕy:F*$ԐO*o7ϛ:1λ? J&0u麗q);omqe ~j+ ` mOa%le4`4 0 0 0 0 0 0 0 0 0 0g~-8q THDHDHDHDHDHDHDHDHD>zOo/aDr!5qGQ|܇-RXyx-!=]\Yi?~+Wy̘1!|ȸCvO  vkWW}sM_;=߭cԣ#wԘ=k։g j@@B }~;Ɵ>صuS>'|*~zH!^qɇqhAaAQ3oڸ񑕏t/w~󮨽}\xQ`R~׵_SO|!+qW?o~`R^o~1f_~9'=c},nrmKx'vGϜQxKa/sƺu#~bʥ7:{ufތ|M:v>=L׮)qfK;|w욫zc81u u#!͛q[݂sVpZnĪk;8 >^ձvm˖g^RhmK:ҏN Yvټ&_~_Gٙ:~7]0AΞ5իC<ȰZ&YiGc.룊i5g. Cn)?xG+n ^ȱ %  8mQՍ[ΙҘc#*I8+]5'ܸ䴼5]oF0?}GkG+Zu衝3?? L:dzM5=ozZIqָQoz\pAڨZKC?Tp:G8Yd3K 2#_jmCjŗOڸ[ 'wݸ<̩O7t& >6` /nz챨|[z-I?|}=.Tfl6G޹F6͝mi,tzp3fdYvQi}WKرc1=0r)svꛢFc}3?s :kzY*n߹ΐ ~ B&FHočn Ľ1ү6ꋧ1n#_z)c+xyܾk>۶n[e:SGO_~-K+?}bڨ³/wy'~ĢESO:u0~ݶiúi^~Kw 9C3ܷ}z(mF%ao͞!jRIDAT5+>hQckW_۷s׿![~5_!|ȸ9#j{֬ Y/yTL"0o $DM{A `A `A `A `A `A `A `A `!#h @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"7ЎՅyխ{躭"hh(56K~*UTZUx Ahssm 즥'_~E[6o^M,pp-ЇG_ͻ|a_8iBˊ$/`a5]}4Ckuwחm %]Ʀ Kjۺ͋ wl URV؂Ҏ-o {iΟ!lkkڱ[wl7.(q1o~wڱcҰ >woҹhtTXոPÛ~iKiŠ!|P:.k?C[]Y.nټ~SJֶ켵8_>cfWa\\酥hyy:vTYУSU?n;iO:/}'KO^KҁhAKztmdun|u{[.^ή}߲9ٓο7{獉1gpyIEe*- oC)w6V2ǦJNͬX?vD;!???c?0uIckmYze5'Eʒh {\.²U2}S:v#/&V#7e\[ª+3֞koχqKm)z8?0l%w55qqz- q@MM>v{.Ʀ >7>jn˿a-'&[ZCiA +T}j@[߽w'ᢒƤ+o[ b8p~=w*L~XY[3&J+@N\TWmk[:o̻hl^^^I+NƊTPY4Mop炆nlu몛]twVֿy6ו 4/.{bmnk)--fl//:cy2Hn0ʦ?>zB0a)_yOѕ~CA[SN&L|Ҽ/,;^}tFc +^4yŽnj?u/o9qV`p$A `A gP-Qn;7%ih n-W?! Θ*K & `A `A `A `A `A `A `A `+[dLDHDHDHDHDHDHDHDHDHQWGV~ ~ŗ_~9$ĉ;ЩSu g3@uttW\O\tq寞>Лqz1L 9CǍZ`kkv?7ш~__ǰ~3 }~;Ɵ>صo֭[OǞ|!{Ź&zġ!Z[Z_Ջ5?J+{+;蠃0oQrּW54Of-gŶ/ӏ}~^^^j0= ﺻ;_V~#KJμϋ6z*]&jO>oQܛoy1>}zrCJ'"jx NcƎnuEkw/Lπ kĕ??nxډqh/U8BVK5zg}lV> ͝S:uQhjFތ;u.K%'Y61~|F^y\ĒIawwZuF7o7>{.o,ٹo?/U`s :Ϭ[cٜ!L]>9\ir8'lZ`@{tõyou@6S jYYW6vqGjbUb/[>V4m ,Մ_i޲GÜꝗ7|0D3_vcfVM | L]k'-o7>sAWQ koݺ~'?G]tqhs₂!<(~>eIa@2çwk-o;;n]tf&.c3/U* O[QI!6i\ԱvQ;OR]˺ް[jo =tAa >@ tߙ}^Qz)'vVXk~  xReS*#y{9=|:SSG=i}k.ǹ_|]KN)ߥۇ^`zJhkhMm{uCjni_Yt`ㅏ?Ct@˱^yug++XT*?6(n'{ŷ2J_;2iZAəÃϨ;8vT}ff%sg5ߚ)iK:sZY~Y|ckzT"=i%7J_ܕsL8C_y%Ot U{-a p^ ~7!w~;|??>nC0n7Eia ߝ5W_?wz7g>iÆ Q ?i"2. X.UW5<߱c~;zȜ|dJa]5,vK?wM+8zfS% Z?w=F/GeW>|Q}rS?}ƪЛxNId/1 м9n[vP8yr)Qw|K3}CY>u~lh{}Ot~/c:IDAT.q]z]Qt͛7Ǎ>tl_}_g>S ϾpޱfM=aԙSCE?[GF/}:Ϳ lU mӟƑt{}zӟF@oN3{߭č?f?.yS١ǖv[ lu'1KLzʕ>l`s6︷!uttvZ])N^BKUA`8 @dWPZqUehhA `A `A `A `A `A `A `A `A `A `+[ p!@0 0 0 0 0 0 0 0 0'X?0#qS3mo d^Wʖݢ{ŕzgrnj 0k-p`kv?7#S{맏~d1{֬gځwǍ?}kb֭|cO>TCνE=Ђ‚0^igߴqSc}#+^yFaD2XU W $D]OAw-U;>d(G=NWԬXr[Gᢋwaӧ!^/+۳'3|w]Q{ퟹɥkLrCv{JW߾ɥ7Qc1-nr`O{Xܾ#$7Nʢ[r6Ho˗-i;G/iS|dA% 'GuЛ3vL`D%,PP9aӒk[6M5Cv|um?ϭS?E<8ˢO ˟i ]K^j`ЛzǍeK3Z. Z @r'n<\x+JefڃU߼|ff4\uMsV-9Mm\1nR#!iEqy˖':~E/U/VN3 {(Ȍs7^E69#a@O}QޕOW6Hv_\bmkvZ2qqC;a 0ȥ |dJaah]UY?o>!KnOn C)S- ChcƅA䒓N?-0Br6Hg?~6n-;o_me_Zvތ~K4?ܿvk`5-٣>Ժ³/wy'~ĢESO:u0~ݶiúi^~`d }j{|=p>=i6GJo䒰w|Т`-^}eKn_7~?lUvi|?,v!!IDAT@pu?[&d|׻}>SG}Tz0y` !ro, 0 0 0 0 0 0 0 0 yF;`A `A `A `A `A `A `A `A `A `A `A `A `A  k-yyy5}f0/VEqﱩ-vVWcwcS%U]i/O Dzv\ZMUo&Uմt6<}y5 ]/nֆꊒ%5mۆhg(nL..WkSv߼=^}?cAmaoMg~PquKxo+ISaQTXg>woҹhƇJ @|MGKu{5;ֽ#u7>!Z3 KjwTyhyy:m}'W^ʨ@*kkkMfqvf}yyg.n۩{zCm{IT>z7}=+W=?> #U6 pJz]߼ttcg[k+R86UTYҩ!.([Kᶵm[f aW{xxfeݴ9eMY'~˽]< ipA]ְE>iKU4vWQKmYcw[f HWew-Rc&Lwl/'VG6O,-ؿ]|PAqq2 M}ۚӷ  sp7@?*J3'm嚺^o^Wzw[[s]e3-j6SNE.I'l\pyHL~\8]{**rr7@߆*Teu/8dR]rv;[\> ŞSB!*&St}Iyîho(/j̼9x(~ YN˦xT6e.4S鸓dU\]w~#p~ռ!ز|nAɂxc J .O$i% 5eyF! A/}z6:`{Liiܙ.+N:ޖƊ񷭮ll~np`wF5}1p];tOŅ;tvyɎu^N9kޱޒGkJ_`I?SN/3a)WڲlU9vޘhŋj'Mc'O^nk*~)#/VfӓRU'C==*(L_{\UYA`_1D0DHDHDHDHDHDHDHDHDHDHDH>l $ 0 0 0 0 0 0 0 0 0 9WGV~ ~ŗ_~9d'vS=g^Wʖ≋.χ\#_o?i!|ȸ0 }u?-\0صk]_5}|opr/"a=00 }~;Ɵ>صuS>'|*~zH!^qɇqhAaAV-/皟ލ{xᇎ=tAa Q&pg;{UCChV{;^l9_n^?G?nS=o$uX*y?/Y.U_=7MԞ2}ʝ߹~9໽ss럋ڇ^'0H*KrUq3vu˯2`}Ł^xpʥ GǍO;# #oUy3j{)ج&;':]3fŏή W0(ֻnǯ>sǫ >$͛w*{ڒek;Fn,̻ZiYl^//j9=Ek_|RsVzɤf YѱlNظc@Ĩ[k_1tѲy^6kDĻe]Kܘ0arc[=q3nٜ[9Kg^| 'ށKovuTjB`8 cxMV|~_f.fO,Xꥻ O[ΛKN[r;kzMsg=OOG5̙ֆ`jQc+̷s׿!׼{W~CSFW_}n=gkք\0{֬yɳ:蠐``Qf,$0 0 0 0 0 Q@IDAT0 0 0`S `A `A `A `A `A `A `A `A `A `A `A `A `a@vkoH*pkua^ZˋRǦ Kj[3A5ӧ<׻Ty}[?[oo]PZ۵-ٙRT^R_͋ wh(C!l1 ӁԽ?|x.(, XUxs/_yK7>|rU׷VWz `]_gL9R]|g~O9ctl Cxr(*,e`tOj>@N1}ho(/8QkIWz[;"[º;ΟKTY][G Ku/H޶R]޳0;ֽou7>!Z3 Kj[vzASe2;'콻Jтv[ך͏wwL~~5{>8{qN{ATga.#4-(_qqiaUԶ< h^P:}1u鳭Ex㩢gN[lqP}Kzo&|{~aYmݧu< ԝ%# ;5Zv[59f^]m5kWUVM)w7VUqݸpA]-qc.ͱeUGmšOQ3?//= 7cwsq]qr`fN`A†_TT: ^[CÙ_rMyc\\P\Yd-mh-ukM=,m\eTA\,\N/9|0I}\.\eksc&>%%qQԜili=(禊J[g"< X|j*{N&#pRIQkS5E)M[gNU4<{);Rݲy7?)<(UZJQIa\IqA=#xNw b$Fv~ڝFЎ-lhU7_9tK[zNū慁KU4vW\4rtw|7ܟش Uekti0[656fzTQiƖm (~vS\1o\zDDZ!?=)>6d8URws]]s]Ryy5a`5U<=p~5uFŷlO7N( ѻ*vʸc K74uަ7/khLcJdcCCA5[mbqK/զқ6XM}kTe%ҍerKuٙي'_stSѻm9'tW;Na=_^*=n8_8jǭ5Vl8 ⚦SӍt(_ۭ;naAII|Oݕ$ޓ utt!PU<}=n鳍Uk[}y74nՕ^5{jzP&]暒?{]G}߉#ӬLJKVH$S1Xi#'-K$+MP`d7)|lH8I1MZDC,D#@ĆZ*#!pNwI˒,ٺ3;w?|ydur4 pF^Y}Ǒw5E/̝Wv-JlE]]s/:!W V<ڋ]V0X6/0 0SmT@ LhZIyA0omUi @, @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,¨0o37TXXXXXXXXX~W^{,2w_xaQ%Kr6RW`f{'A \p}`{L5wE?vk7_{vgYfݲ?ٷmdMlF^_Ntx9r}?x.8'o zCAq /L&HWG+?y{_أ;=`RLe8<*},^Z\Pyz^϶?}>7srrؚdonp VS_?o(DK+n>~ǚMz^RꫯE-gʲ*~_^R^ s9MrWQ͝{gӝJAf? Xt lʐ~뱨qʫ/\xa0_p`-X`釗F큳xdSnoW$][6.Y~nf=]WG '8pq&9Sٷ|c˞9w ׸n-}QWdv~2}_`<):t(j\r%ctKڻ7woKp5_ޒ˷6.Ɯҹ?uM˷fa{٦6w}Ezұy[l?`IAk'%K~C0nL&Kz`L_~h25M7e>'|b`,{*.ذ?ϯٱmkں%{6u+ZDX|^;o߷_S|`](j9}19?RvC:`W{'Z,^ Zؼ2gsQ3W{tM H[U2r*ٹ',Sn<{!uq ~` ?ivS;~eӒoƜu);T~[6.^ѹoݰgSْda;;imǾ1o޼9glQF듾"=8ycKߒXcNќs3woh gzvuqp~0 5;v-:='ָ}s__M$[6|/GA׎-] K&moMe]oNݽ.g@-6v^\rq@MM؜egznt7_^-=#a yqSWUӳpoW.^߹` qIF2A2l䝗|yja̓Ӟ^{_ۏ?&hNs3U6 ^.*, ?Xq~կ~U{]m~ l sΖ_=5w3Uzr.~q۟n_֜q˲ ]tQqkusݏ88=|KC5\QR0tJ?s>^W_U\teQђ,{wS>50L{ؚY7V;cߺ}}| _A \|puf6_{?rIDATow^V}'Lɲ8xƦw RW-]ZYъ^w3 dQ``&{`XXXXXXXXIRTXXXXXXXXXXXXXpuԗl 8m s"-V*/Q\YumN6b@o{CmYqb:CLꗞmτo7wS 뻆i$*{DOSOcz 90*:/gbri@6NG`ߴ~łs kZ{ǷűCw ];/]?tlpE&1SW3Q2M%Q0:3))0E&0://7ț=l]qmG*u`K*vym= ;㉶'u|-m⮛KY_R6;:/Ca+}^;r￶x 2EyCD 7;/yam': Lo #U}|Y#kmR|4Zr讯o=>WEro 4t:c9Q_S`L 'jDbNW7w쪘/i\- ˶>xMyeE[^j*N}ϋ[҉/;yqv^aUs띙Dm}]&KgCNC?XoFyϮiUG2e5p(I!+۶-h;4ťQ+PsWwq̓5þ/1wV;U/8>B x=}#B|NNNq_Xzy`nEUɐ>G]_S3/~yȵ)ɏV-w=i\^[SxJ')05&2 t"N2ɔ*k!Ѷm:3D=;*FmTM|y\ +>{C'KϴD";/9]ղ-]߿+HVRƲ!pp$(-^ic9.)05&%seT\5sѵ_z&=UPpwvꎞ^ftk٠o+/)R_=bAp~iP\,[Z ΔiUQnlGxod5DpPRߛj:cHoN[}*f}xF#=sνOeuԏVP>}t%ZSSͼ?}Zz21pL#z#n<d5ĄH7a<߻Tx:n6Z['hn[>pd g򼜜Q$˪SnU%GZ=0z9 ן3g룚H3>!=s,'8]5\V2My%um=*̤ZTXݚaLF:v#ƺ(w*a'/ u~|dЃn;X|4M:Ue۸,ioY_{mJґd[_,޿~Q'SF}.S^Ϡh5#cɠģLJNX N]{]᥷Lik.϶&>zH8@v!sUluu K^k.LT6b}^S4/7Z;[~HKxLU3X_ Ns,NOuyMy2t1X0XXXXXXXXXXXQ`}P `bA `bA `bA `bA `bA `bA `bA `bA `b!W^yׂx?/蒥W^]/'J3۳'>Y_E 7_. fϙS?g]j'v|_ghOd֬Y}mo{[0YzA`ങ뿑5㗽];GC>ɛsßPP\p ޺:^+/zwy2TN, ^Wqc⺇λༀ5m=}o'gYAVoʯ?uwDw'“SqsE[= b,*oW_ ۋ.[tϚe4կ~unxiKa{~p9 )@jyVg?y K/ uÈəA&jn\}6AG/t"..nneeOzKfJXȒj.[5zzz&q3ZGjG*ܗ'vAqrdI~°my `vXdN;0h+;7-_:?hMk>s<<~u$I b7r,^`swܼ2'[S{t'kF,i.MG>"]3P|Τmk+F3`Mcc, /=EFQhn=5X'õ]%EԮ0m&sHOϪ6?,D;S^n {s]knC_:;#z Cw: ڞ7o?``.*~xqnrhtKӳ[E3Z+}c -MtyGwzjҳsto7Y ؽ~swOM+:Db^WK/-~G? v.K?nh%CVIDATݰgSYzƝWn^xǖ;R;/.\8M?)*Qe=~u-?+zRo~4x]NTݳ1'sQyWί.ax]qH/T*57^?L8GNbʰw^^% ΰt^ Nd3=?nuL] Nl\T+6_(=U6s9g/F|3lɦԌ.~q۟n_֜ 1HW-]zqnx\?ÓW>劒 ƲW~ |.ʢ%EAԣO , w`0@ovkǾu )?<Fr]Cp N8 ||g?yH~jo>`*i8o46=gO@.hG;sMNd;8m``bA `bA `bA `bA `bA `bA `bA `bA rRTg;`bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA fn%999%ۺNœHe˘Ob`#u(k-- ʄ~jLL}sW0Z*G?iىҚ殣6G5m#Go{CMiaŕ-]蟨j9L^!{!U3_:ddaq(() SgL:mtDd0Au>k[Rj翣,K?':[t+,TY'rjCr3c*r "ZP+|`K=:hwnĮ%=Q[KϨ7}_8BAל/f%2yy#;##} Y_R}B]7:#]TO}ɉ_Q_ [kڑh׿xq׭ t'h9sKeoj9q]XML<Yh8W K$T:XoRyƣ'09EɴzmSV뗞,Nֵ<\c<`Ӎ-/v5T' +,k``pjodT >H[U]_S il;_p#2.{͕'I*ai2''8=走4][QU2riEI+,4Z[ۃk}"^f˫Y^ykJGz엞yfHirh(|+*/%$ K; I= Qͯ) 3o Fq}[i20N= Z7ؿ+HVRƲѶlD2w^rɌhiΤeɑ.kIzʆ{R䗞yfL š0UӛP.zymfXXS;3xn SOk_^[[~Դ"=KgDbr鱣.S-/+&=:Ǔ:>kzNKO<3DptnthTݙƲ(4%ʫ0ɈY'-4ӦtY0$LގEe"mwg\<5ZpPhkcCU{&jVe'0oՃ/-cK*[zQEzLSKODUkd|xڹ\Kb|z3'tM'n¿tB Sl` xssMN}}͕Қ֮]t$ߣ\] I{O= O!=k:YKltW{aɠn+kh\KWִ{ىM k{f*)&V~ymOCiNNjx5)'M/љ _l9[ɠc2e2O=|oI2xJhNYmt)4T~ 8tcX{TUeH7o:q;Y*8c!3ɠUE;ZΨ⺖-懛}gae}KG`SL<겱w35-ǩ~Sť=}Li>k! ˭i,O^ȱ!KsW=weOc?>xe:j\nM\qס~7>zy^{-`$s.\XrXQ0T*57^?l~dO^~9`"9O3 Y5ډ7|sqW6sR-\w ]L֓O=UK^} ZS7wkȑ#|?s9ysn .\xa00{_;[[zז &%[Ʀ̟36V;cZYvp?xiqCu]p^?*|U;ؼa#OwfY+U~Kz;?'Ȧ[oEl.ۣO^~|38eS6rgtYYVQ\qopԾk_ vٔ!cQW_`Sxq ;ƾ} i+;jW`Ύ5A/n٘.MKm~'غqI0l>qnG<8[uwrps$5•;3]Wfg?*Sw\5ʷd s͍fzn߾_pApʦ C%W0ݹ%P#m~͎ 2:wvElV|$ ;2)3[ݱwtYf]Yn58McxZ{ҥO=t0/8aVyq͵{֜P^.f*lr Nؒ@;J=ai7;$3>`=7.^{Z}ea[jW0) 0esO.]hM=5dvsw/7tO㑲i Mݛ,\IDATNWK &a=99vե{_ӱwo鉦|{ b5GTK;1!'|+,^rsΓϼkyÍ-d֛o0e#G\; _K_zO{ :Xwz0_`M>L<Ir\_:dtTLUU0#U5}C)}pr-+WlȨ_qd5o`">?ym~[hkflQ ;غ;=soFQ2[=hIcXv޼`hAzNV:d\`wM_:3{ M-$Z6K/-'-3ϼgcN1BMGKZ6./ٔڻiX/5g3lɐ>Qٍϛ 岩\Tյ+6Rz_~#j߲lMsٲQ'L˔a'|3ۢ |tY.tҥ7Gƭu?q;z?zp1/o|Ȧ{#uwnsë*.hIQHz=x2l,__ &>oH7|cWDxJ ] p6f=__?U+/~sS'p7hlz(|}wϞzWG?%7``jew,&S+&IXXXXXXXXIRTXXXXXXXXXXXXXY[G}INNNɶf0'R2dUOse"gʖön=GycUGZJ VVmkE[͠}IT6pڜ*:/g<ҩղ`ʵTza}={jˊev*<ݥ =cw(.m8:7Lydaq(()㱦;槞moo[mɹ V}w>q>pA78#Kg’Q\WOcy❗~,u>_`;]tngo&0://7ț=dM"R0;PѰbz[*Wܕ^3w٭^< ŋn<\tWW%=WE[W:Ek;RVΏ*eRC/fE'&7/o.i/0kw9[VQ_|A=?Zt^wϪy-,m囲<g D_M1Hk]LJǶwX)][0fշbWn-nΔgWܔ So6𶧡L#48u3M!' G9my8N'uП12k]aDt=/n) xy8#p@:es[m[[ˆV+[oMW#5Қ!{7P`fc +999taiq|Iˉfmk_TXۆN]mKQ_dؿ'J= a"]v_s |9T*8EuKNwMgߞymo[mw=3N.\S2|z\V=xcOseM+r&^]g2/h(+㣞xH?%,}$W@6 Ե9kes-X:J <9QaUKϑsϭ͛ۿ4w^5޷7lžs}#]/5̄ 0@Z1p@Q:pkʓ!Ă!Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,¨0ϙd`bA `bA `bA `bA `bA `bA `bA `bA `bA >zy^{-6s.\XrXQ0`RW`f{'slnnn0} L}uQoqz7?m|Vh¿k`|*6Z꫖Nhx@6뿑5㗽];GC>ɛsßPP\p ۼ/ԣO ,|U0)_6eаh{x@6ʲ{øHK;WUjǶ7l>vX>w_v¬ |sZZvʯ?NC^}wcǎ)MQ{e6lu.n?yo<MxW㯾jȝ{gӝfeYz\qsIDATopԾk_ ٔ!cQW_۳1gƖ`ƾ}pc(p{{{xՋs/.~pв텋 +?lL3^{*/Y+2mߒXu5/ }ш>/=Qpʲ):t(j\rȝ_ckEtnx غqI:p`TZ~eP4ݹ%?7ر&ndSj{7 ;S},N*L+7T=)n p>GˬY,pʦ1Hګ.}駃1]|cw^0ٸbwߢ7^ko&{`Cunv4\S3?H'ջwy|euys5}mZX^6]o?6n&|HlPѽvϞuŽ uK& jqGX+^-뿒)lT|?+sebtX5FںaG;;7`ꜝ)V-֭k Oc_:?hKߐUKKasxo0QoVԙ{mjyVmNeX(^t1OWWgo 3k>Sپawx?=~3[~nz7%A ]}HLFM7#yG/G[F;!6Vm6X +T>K' 5{6&|yKTAhڟuE͛3E$ͯ`CǷ׹/2H$ik]zi ?Q#t8Xz]S+-keK-mܱp7g֤yuEݛ;ƙ!tʜǻcJO"1g 2P?Jߔ׋/,eS^7cxuUEW-) MϿ<'=O_{ 0>)y}>oS1+8[xJ y] pm*7^?l_{EW. fϙd,7x={l~c7K.yo0 @6!(&IXXXXXXXXIRTXXXXXXXXXXXXXY3[oKU"''Qr4` s"-CV4W&r)k_VsšDM୏vW+,384M[(zOi,}دRٿ+zm  C7Snkzd{8Q$]n ƣ+DE;S QZ6}d_ΰD:r%Q0d \ \`M`t^^n=7{ȚDycO*:/ ǚ*RI}zM*"ZS+/ɴ{[*WLؚ]/I;wry(n$Q|t>ym=!V@jקN8h-KM:jՠMKȼfk:ً:νvg"8ycMU5cߵX)][0fշbWE:v[vDqusu]>8/3̄8.`zM hxWVjOX6tWcM5uDζ}co.)`:MdDr^o弊-[aZ>3RM)CqMmz$ta[S1e#(*/X%sєDD";/e^q]`M$e8n,iKKUڎ JF Gtz wVr<պԒVW%=JrzjCt_p+nN$ \q\S;HN ǩ >|oeܾP;{lח(zmմ/TSgzټkk>4).]--IgtT0&TkƳ6FSSuU>RZ GG'j#hR557Lݯ1$ZS#̂ &rMOzQOmjBxbReݐ,)R[\є~HRM-O:U^Y@ ;tmX6E(,XDese#0v}~?q׊EF;/ZqalڷfoOcA$іlk'2y99{o9dӾj>z Ra]{\ r3մWtP;򪒺#vmY?N-XZS2 O1ErRT R+v&1SQRv^[[U0y@ @ 0  0  0  0  0  0  0  0  0  0  7^?H>gnmTXXXXXXXXX~W^{ ̙3_pa忻bE٢iJF\뇃/gs9Ƿ 9sl3wE?vk7_{vY ᾢKzêxظjҫZ:!hF^_Ntx9r}?x.8'o zCAq /L&lz/rwgwksS>5UeؔCja!(~| /-{ V_VѪvlްؑc?'˻}e jiڕ*׳:z;?'H6zGE-ڰeCpֹno=j嗿7B6]-a#wvMwΚeqrŕQޯ}-`*dS|[EW^} lOŕ{ɺ37D}ڳ3P6+;rs_3DKVo:C.F|U`&nF>pp|dIDAT]WxC,xa}~n߾SMСCQ+FyFn٦6䇍uQ:]R|׎5`+:7ػ7_ɟK6vn({wn 6/LoM/HuS-UlQ3 ػ"lto.۞N5 ?lٸd f͚UteQS6Ax^tSO?/NfIm:/߼{aH6VTv†Wh˦%4|s}QE-zφo _l/g<\{z3?~;5أ:73/|yCAa97y+,t{w-ؒMW4[t~/娱~h'djmkb%*~x8=Tˠk%y=l:L@}JSV)3!ItWH 8e/8j36M-#p]D7ܲsoz=x+mڙSweG!\o9`tɷsW.+}S^/S6@OU+|3l یNN|p߈1Ƴvu#;{HovyyaZ[Uҿ{eCKye懍cM5u 7:F@NN|DfN$ü$G/%KJ3c^U^>xe =TO@mkhO쎚U\S t74,. ߊKG9DaI\4%,HKfct"u{8m&2Af:Kض,^pnNN^ćtK%j kST{](ft58$x`{ZOJT6{TDtؘEt8`ů`NIyA0omUi @, @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,¨0ϙd`bA `bA `bA `bA `bA `bA `bA `bA `bA >zy^{-6s.\XrXQ0`RW`f{'slnnn0} L}uQoqz7?m|Vh¿k`|*6Z꫖Nhx@6뿑5㗽];GC>ɛsßPP\p ۼ/ԣO ,|U0)_6eаh{x@6ʲ{øHK;WUjǶ7l>vX>w_v¬ |sZZvʯ?NC^}wcǎ)MQ{e6lu.n?yo<MxW㯾jȝ{gӝfeYz\qopԾk_ ٔ!cQW_`Sxq`n Qc߾l|1 M=jŋs-Wlz93G(Qmɫl IU%j3DfN$(9hW˶m-]A-J6 ;P*?!=%ʫ{e =TOΓeE[Qy(FD܉$HKºᦆj) y@8cV ^=;4.Įš3:Vۖe ˖Ⲛ֎ޡšt+XèכzW8mo\ }V474 a vn8:ݙƲ򨪘(pwcjyk |>|h_ZDY}[o0Uᗞ6ť˂%`ZLDpPRߛjhN*66d VUW6QU*i2م-=G^۷[+;>y_QZLqҙ'Q՚}@0?T`P;qGSi` xss{}tShAeu=GAuk_Qx3#OOpV'n4Ҡ)#_AT%rrU-'dyeu-m}掞+klДgi :c`'xh2ǏOp 8t}p7'tNZ5 ,sP WT&c2?A:R[ZzWf_FS{+=ǟoeK:}|SֵU[mzO|**w-ə]8xlsgc7 sъAMi6mUOca6dw^W8J=z&@V9c +._57[k/ڲvY󊮹tm+tZFJNL`ˁdik@ >k$˪|]^S 8]    `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `babsg`bA `bA `bA `bA `bA `bA `bA `bA `bA >zy^{-ϟ /,*dWo^9Tjo~8ٞ?ꟼrm.Zwi0},2wE?vk7_{v3߬YnYw`T YfF^_Ntx9r}?x.8'o zCAq /L&땟RK뽯G ѝ{n0)z`,e8<*},^Z\PydWz>OG?5=͜``donp VS_ϮJ;vo=XC7`eSa{eY,կ~unxiKa{~p9 0~ w<ٹw6ݙ7L?)2z,j\ ^y{6,L΂E ~xiiL_ G{{Q⽣t Co8cM2Sx]S{ҵ}a`>^۲qa;+ذc`>|}? iMCEKd.K6vn(uᒭˣM9՞ 6[vw[S{wnX>K\5`:Mcx` jҧ~:ŗ_Tc',lytw$Kj2ܮΰ[i'H N݈>̢ES9!cj=MG;5=mk2 6o^83z9n]iofϯٱf>ٹEO<# ?j,J%u;7ok:+^xqTQX.Xo6^{s}Sunٹf4W}޴=ʖ?8XzG4.Ya>b}Qc޼y: s|G_ &lϣMA~4Uڵx^ K'`Me$-# SzY$@/ޟn8Zt կjo{{)9眳esO>wwdSj/bQ_ٚ01HW-]zqnx\?mχW>劒iM=oxuUEW-) f޻za` 0~S? j'v[oOÓ+6,_54jWO=__?ow^V}'L8dqMd.hG;sM2>0p{`XXXXXXXXIRTXXXXXXXXXw?qULR+Q<<>Nq N`i?FHxIPv7Aiݜ"ܤ[q""b$8J'G! 7r4 r6fI$kdIF9wyI>'_HHHHpu553=PurDUg@)L]oKiu v'Fhy'zEV7utUj}v)gҩГlz6lc[O0չ\o[uЙ;.V1xDiX(.Kot;N+^z48@sG0fĕNR8,&ޣL .*})J Uz[*cpax*m_kp5uԖmt_gGn.yʃl/d{]y,M ͝]LtF8xbS=]]E`F@OO9٪#z-k> |aTٗ.*((N#hقڊ`uOWjP8_t7הSb+cr]=Gk۳zßR"G3Df34WddSmΆ3\\3Uv4{x6w͙1uCʳpʚjֽ}ڒ[Iey3 rDܱtF.~Eӕt47 lni9NHc`&HScc0L'[pOxvoX\Φ¡>u;cu-]}'F4MufsCixӑ/V}3ZnqaML|g[Ɂ0ť`&HNwVK۞RI.%[&.>zd_ps^/*c_VZ2_^6Q:vO{ۑSnܙL+Jn]/Bp#pC.((&N9A^oo>Jiwҧ]ukU'h}L|~7%/套/}ɳ?7߼鲛?./^;`_>ȝ';p]wo `}/ef:xg}tʧ w ׬%o= mJxY/ iO]QҸvYkm+=]]X߬gpObAJl% 7x!. iOȑ#a+/º۪xG\6ܻ7ymܞM[Ol84䐫>uѐBNc|=]Ketz[0m'aP+V<{w08WUlQL}e{b͖tj\Oz4>4^>ضmp;R&u;RϷalnط`Z[ba8iOO#j]'?tj,^y -޲e]tjݼ<_yov>޽ug#-pNDʹu?^PhQq`w7#3zu]{ܘ߼kgxLc/Nx9]8{K;zŋ]Z}۾VvϚ 7 ~_i\fCށiYHIDATg\]0 RԨ;L8Nbd?~:](兖 bo= ;n&Wa ˏ~g [H>Ї&2~շjS|[~0)wy[eX~嗢'x-ߜd_ݝa_VPP0lW(,lknޟy兎ҧ777veYY4˧g]]7yǮ)䪒%L>3;{dy`~MwOv|7}ͧ+7׮Z6gjYc{ϙս__˯߹3``k>~`Ϟ \bEuǫ>~üyMfLe``"A `"A `"A `"A `"A `"A `"A `"A  RT`"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"aNXVPPPpΌ?4& BQ;Oh'z5剢Eu6W օҊ;b9΢gw+=[=ɦgo6S.Y=pY=Urbmgytm8( e`uԗ[zOuu>w;F6mO#'='΋׌#Ӵ\9(+ x0jCfcEԖwB;=U;wt՗zduʻ3W޾㙶_}qmWw}jÕC2pWcn|Hwu һ=p}+lY{ydDQT]t_ƾ(}[T4Jm7F-gwtm89)C_KL= l,,JT4vj~z}mbLd=5yŭ%A&2+#^|g=t%ݢه~WY7ҺHPssgЛl~*1;G-%;l涑 DgSyʻy #xJϱX,`:M$e<ёŪ,WgRhpDg{6eXV^}9 ;> [WW)s-|L7ti"8^V>?XY^L~?fr.쟗HXA?aii +=JWޣLMqYc_*"QD~pHhs\P{S,Y]!CYu率+=b5`LDz҉҂ll,nw#WmoG{vΪLcF[#;۳便#gD'\hku]2wޖʢd_0ޖjS'Z]MO9jƆEjjJXEuvF2j0ki/Pu5#I >ZTrs6?P]3JG[gۣG3#hvYlƾduyv٣UXm-ו/nۼdeM[K2k;{潝52]WVƕ{+ Oِ,z.:+QZ_5V7bޖ=2JE7?\?UG]ʯlU|׾}- {GT=߇s#iZ3Ro]pVQYC;޼x~+o{GߴXu[ڒs=s\{#/L[Dʔ3^oa0@Mh`Wo(Wft2p @$ @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$ ;a8~0 `"A `"A `"A `"A `"A `"A `"A `"A `"!  0~ w& ¹wޕ7N凾])2}",\暋\l*X)L⥋W|dEX4I>whzٲk꒛UWNپv`=]lO 9ΐ>8o?4I>#GKdf[ E[.>l+kxpTxÚNŋ ?sWn tPm;NGuK.miBWX.`zߺЪ{r7v/^f[zעmsﶟ|0W/U,˗޳!cj[i2].N At{yC;u:zdohc ;W97ܵ+,,X`ƹ0A~_xa@`뾶uѮՃ3ٴxˡm+o޹І5=~WƯjUA=yXlAt)w饥? |sf{JmXl؛شl-}>7Lxe]-|g]fꬊm,^%⍹ztQ /,`:RQ+^;v4q˝xuPtAQ -.b{6vAzb~pXwv~0i8~0UDf_mڔ+7|0L| w-{ b7&swgX׷L<[+n? -Zn~gA^yi? u]YV0AW n^kJ.-dyI0S{`Cғlz6lc[O07fOcPz}e .u:ؿ42OD06]{x/NPe&_<袢XQiutR*YnVL0P31ŭ%`U흃w:*n u+a7s*n?5yWcó[?U'Ov=Ɂ6u:k#F|W.E7-* Td:nY[vP e;n_K`V@b`j$DsuueKVm؟)lh8+n-L##Gx(J'[k'2p㉩ΔUtQo][ٔ^8WrW`R}t-&GN` iWciAAAi&&3au~UιSOU%k3]-a]Y[PwmxyESjk9ch\掠933we,x>Mo`Kv&ba'Se%M0 L$exl]Vv`<*[nv9ܪGr-a[ӧQX]wK6ូqԩeay uSc?WQ;ܽaqάn -|F3'47&Q#G2)3ˌ3_K M$+K)WXQ_?0ں_lanMMy&іpY]}uß+ J:ߕ=UwӠ|e0,98Iqks~翤IDpPؗjPpN3Mp|JWc}G}smN%>ޑA6~OϭfJG{&[nf~WU7+rQ58HuiCZdK]c*7#͙/:9i|E}tL\rKv);E-}< :sju'z$i C wаJ2ݡC4h,;ɠ46ݱڦ{oκv5%6 [ᦳ!yz7 3R6loKe鐊wWP0'='@lWօC}{8xyCաo_R1\>^PP;_gV4Tᥞ~S&&1ߘ;Ôd]߂ĐC޳% V>EMUsfT*U=lGkփ]uIr -0:Lh"h"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"!g~fw??8=D @$D @$D @$D @$D @$D @$D @$D @$D @$}Gٽ'?y^~pw_tQI%+j> RԨ;lGL_z)`gɒ曗]vi0M}] ah8_/}ަ\'Ϥ͙3~_xLִL}* }Ǐ_χo*.-hED<`zz^:և]PPL @s |T;UV}ևW0[So/)/~./|=0gN7߼鲛?./^;`3P>ȝ';p]wI!}WЗ23`<س>)C>'5khEJeS,xY9@˧??|_&lO,[V0)M=atD k3AqϦ3wlfda߹{S-jz k`t˝ w59q7WLەƃ;ųI V~][3raݟ~/lޛ=ڪY}l`L vdO)u?;UO}<\IgXc].Ye0+-6sM+ٽ;W\Yt}sې=xMdp]Aնu]5ް|Hܵ{[x`mu{4i`T/[lv%u;>Zv{kA]m'Ƹ-|iX=ؿ4R5kWeKT,ߜYxˡthlY~jw{ZݳVYʺ|j lٱP_h붵MTl/ڵzY9(޺`mY,^,o;JZ֓Xvn^>#-.t"̐O'tJێt,hEs[=uŇrx*k\_OX̃ <\eki5`/_? xo{<}e{tް3i}k/w{! /5C'7/O4eE `*6oڵ~tqD]&7-[ݝ} ~3c7oK{6Ύ`SG'>}]aa{q p.S^t&g_+6y<;r:>k\StMrIDATS̐Dj͞ny]S!M>^i؟u9t؂`Vȧ|饥a!w,>.&*BYZ/+fY:frlI8;82HC+3̥fG[=]2'̃}T)Wtl7ԇ 8ݻ+>Ѱ\_|7ە,8= g ]bŭGae[ w,`*B~ uM.Ly?op]SzuiU%%K&swOǟܙ`3ԯI׎ӓO|ƛ>C=~LkWzop~&j{ϙս__˯0E~ o[>`zk>~`ϞpU f6D L? 3 @$D @$D @$D @$D @$D @$D @$D @$DBA* ` @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$ɱ:V0X/1:+JcK+ۺNl~'XS(?~Qwhޖ‚\;r'SV]TIq 2Tj\z}1>ۓ5k,>G:+cwuW\y4rk=e;+j,[\ڙj\=ʖTjgUvxԀ㯾+;<ᝨ] wx}^ 'ʛ4KV;;_<>Gpeim{S9ڝٷ;F$_Gnw΋U4vX J,1 #xTXp+8}E̗$jyU+8+t1<[Z7nKv@G{{4ʲi;ћyoG{v9 ?xuaS]M-V6wȮt{ qy<,p:;gl54ܗ}t-&l}ƆgPi%ٍC]f/Y+($e*K ɎZ]7dpWCm6ο"#VxKfG[X~cvST۾duyvQU` Ee e˪ h~ ݁|Qx_ЅQ1|&SZg}.kؚݿai|pgm0jz5w[ zN=Y__ݚY$i-ɦ3UTTђ wXLJ'?ĩeÇ:XYWT*5޶[ElnoKe鍏E7?\9b>+~vWnMՕ4~'GXp{wWC"]yXgΦr+D$@]PsZMUۯ-syko= ;[o^Y߇/^y?ޟ~'Qr;/~Î~t_H HHHHHHHHHHHHcG;Ο=D @$D @$D @$D @$D @$D @$D @$D @$D @$}Gٽ'?y^~A9߅ ,YRv^]4TjԊ׎ f~O/w/̝;7q L}] ah8_/}ަ\'޳d6_RrI0YO?;+.\b5WPx@>U_&Z;Ǐ7/:T\Z|ђxo{/> o`Re؜Cæ;OCص!(ϞNO[ uA>}uM;lr~_0yڙL|y~GX[ ;]>y"x߿^t֍/埿ҷvTȧ3/~tanܻZ3'ϺW} _L|ʐp͚k.ZrQ0{'7}:qqc(pgggXxߕ;SW'-KlepqeC_ڴgHŞkdw%78/rۓ?Z_=%/;) 8k9.k.Ai|vݎmUAP޽UV= l)ݶ7[Y7ew~xG*6=qQڙݟzlceMuSfK~kAݖC#+q`ʼn39sJ*_i\ip ^b3wc3- :rWWlVk}u^+[5ܱl};tږZp#lf6/v嵋lx|O+={ẮFV8/}{ϥ V~y`_f=7oFԙ׾_cצ_'UuNg핮{iΞ!X=پ˳=#?r6|8hq᝽ϙǃ3 zLS^|),lkܚzm>l0F-@ /0,<hҽ[>5+k׷.ژ\wi6Z?8srӚ Vp kuvެk|qLy5}a>bIDATg-@_ziO0<6eMpOvsEX\9ʼn5 k-g:r>h٥Vg>j޳"pyc;lYlkAeo|d{)]~yY˧|ݚ}o O<'o 죹cՏ2csVwo]6Kol3,߿``)OCW}CK}T)Jsܷ[aL| w-{ f;WV^&`*:WXqQXnr? fOlm\ɣr4YT4oL[?~_|Ń|'5W\UR$7B =.ӿShN"O>of::_l}?@y0Y~>  rM%ڱ+_Y5w~= fw??7y^{ևӯMKx0;|`$D @$D @$D @$D @$D @$D @$D @$D @$Rf;=D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$ 8]WcYAAAYSOw5XMDcޖ Ao[ul<{sN<bmMG}/(V7uS'lƶM>ۃ\W(?XiE}[ Y|^tԅ`i)-|祟SG<ɻ_+o 8VLZ-o=JKXeKo*lT3j~ mWTN?[d=WW63DLTqOsKn=?KuGTecOfApaQl|q*3DM}Mi0[.7$"Snhr|0+3ii~UMY0-5|sxYEX}tddOHR}-EɾN7DVYcfvGm|ξl,|\{ .h Υ擙58l<1&| 3X:5V|L[p[cm,`ڴ~ྒྷŷhq::=04K?+naW4=b5 +3bhs)\;gY0uaYSO_rXA ٍpҩDCgV_8T0p~)CRG},Wi\Llv6yE0bn0xW RTp=lmփ]u $^媝o  E[^-ɬԻ!    `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"!g~;Ο 0  0  0  0  0  0  0  0  0xwyfzÇp .Y_bi"p&TjԊ׎ f~O/Dy?/} s fw??xKM}] ah8_/}ަ\'5Yo/)$ٝHO^⚫WLv<`-77~(,ۿMv<?~??n_tM% {/> o`R؜Ħ;Oص!o<{8?qo҆.xA3ӯu;vlٸӟ/,4sL&ro>֮ͨ}~NO<FO7oayK7n=_jRXK/}o&䓿/҅sjkΜɏNO>YsEK. zlSr"پvd܍_\|hK'7}:#2S }ڼҸvYeM͂M{=#+#?2vcۅW ʐ^GYr~~߾)9r$,\reoV5bߢ7nޝ{Sf[e~m]|ueo|,vkro_sGN5_Va{Μ9%W#G~04.4j^ݻ1]|YHm &⣫]? x0.ڲ=-ˇFt[78ҼgsE4}tү`R6, 0:սeMEC*mY,^ݻ7WٕM]oiaݟڰ-[8eU s 0;&R>͐A+2CO|&@y 7; ya1,E6|}jAoF@_N]~%xUEm+p񥰰qk{+z/°pLU 8nw-.𥗖1pv}},.zW ̇[^۰fxUf@5>E~7l\Խçzh:j=r,.<`|5փNxO bfAPyojsXXyGٿk`q-k3s /X`|^-Md`UߦMT*u? &x[|[NOۺ/O?O=[lqM5L1;墨#sWV^&4y +V[{7lς:qĶ?et?O^kJ.-dyIB =.ӿL}{)YQ'{M!L+|ʃJw?tay TR;l_{_:?'q-8^ki}8q.;{?U'nO\`\~` o,HHHHHHHHT*lHHH@NWIDATHHHHHHHHHH9ZWcYAAAYSO93Ә(U'ny4V.VԷuڢaXbuuᕉ\Uaȹ2+dӳgz)i=ch)O7/J48DiX(.Kn՗K[|O?r2s'~xM[ow3S8,&9j>T]GzxW/8L]T47+*Ѣ/Y_ti;|R Vם"QеB-gx7lsQ(R1Eֺ3Df3Cvhk~4>;G[T]Kv`mӞ=DY$GJgX,|(κQ?]ZW jnfl خ00UVxYyysGA':STgCix +2 Vu3\n,6_!NtuɼWJLtvfxY`e}=GBX?sґ?XW:ӕ 旗G JEᶧwG6e}3=D_8R> ϕPTڜS J93Dzǒ(+ɾ%;r5hoϾRB<ONvhv/(Mo1LUWTdNwg˨K4w2S2Vʎ942eߟq9Ɔg3jjr7@nSDݝ+'o,o<%l:df]^duݙYV5f) Aik8 zl=\_|ֶ!jG@Dؼ25XmjpVYCKU6m]/Os=J֗۾润J<NA*5=ז~C-ζ3+uW\y7&F䰎ؕ_=2oaoiK0To|䈽s{S9Wz7;ʱ j./SGGSQTsK9xm{wYTq#,?#wa%Qí-o;v`+.t.(,cEXAAeąT2>TtfNmOuݿ3DQiEEbEEEO)%_VXPh fyߜbOCXzˇ@gf7: l`6ྞL7o}dWw?v( bT+*[Doo:-{bC:K/0Lu0Ho `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A r׎ w??E 0  0  0  0  0  0  0  0  0xwyfzÇ3… }E%%ꪵs JZڱ܏~|%Ko^v٥ /֎믿?7mu3ߜ9sn[뗾dMYfoVQXhx?~?~><>SqiEK.'L_>y{և]PPL 0~s |~bO֪pO< foKJ_K/_s̙g~Лoye7 ]^8wy| ;OwnܻZd'C_~̀u`ϮO>YsEK. z{6,۔ &g+>",^mA8}WŏlOWmKm^ַ{m<'?]~WUmoVv⍏u[4r`U0o%}!¾K`S#G%W^UWv͖m{S{ӯǶv/X'X޲w[U6v/ߜlYTl6޶*>)>Ȣ!\KetI&T{+.UJ=XnǶekYL~˗޳!cj[L^io:|x٢=ez `Nڽc-pN30i|qK~[њ,_;Oq(.<.]<^⢭[ɷAMԺ]ֱk'W;S> ^-M$҅_mڔJFmYh|(ݣzW&87߬X߱t `:䊑;L8gf$Xi]Ꮖ՟}o<+yeYY0qzq`ɳu^?ܲ߻g{:^H`Pw/g=?75W\UR$:wwy &K0M$Xt8=wo?OWo]m93_{_:7si- f0=,8^ki}8=A>zŊꪏW}y3 2>00L30 D @$D @$D @$D @$D @$D @$D @$D @$Rf;=D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$RIDATtU0IENDB`././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/antlr_grammar.py0000644000000000000000000002613415134002420015474 0ustar00""" antlr_grammar.py Created on 4 sept. 2010 @author: luca Submitted by Luca DallOlio, September, 2010 (Minor updates by Paul McGuire, June, 2012) (Code idiom updates by Paul McGuire, April, 2019) """ from pyparsing import ( Word, ZeroOrMore, printables, Suppress, OneOrMore, Group, LineEnd, Optional, White, original_text_for, hexnums, nums, Combine, Literal, Keyword, c_style_comment, Regex, Forward, MatchFirst, And, one_of, alphas, alphanums, DelimitedList, Char, autoname_elements, ) # http://www.antlr.org/grammar/ANTLR/ANTLRv3.g ( QUOTE, APOS, EQ, LBRACK, RBRACK, LBRACE, RBRACE, LPAR, RPAR, ROOT, BANG, AT, TIL, SEMI, COLON, VERT, ) = map(Suppress, "\"'=[]{}()^!@~;:|") BSLASH = Literal("\\") keywords = ( SRC_, SCOPE_, OPTIONS_, TOKENS_, FRAGMENT, ID, LEXER, PARSER, GRAMMAR, TREE, CATCH, FINALLY, THROWS, PROTECTED, PUBLIC, PRIVATE, ) = list( Keyword.using_each( """src scope options tokens fragment id lexer parser grammar tree catch finally throws protected public private """.split(), ) ) KEYWORD = MatchFirst(keywords) # Tokens EOL = Suppress(LineEnd()) # $ SGL_PRINTABLE = Char(printables) singleTextString = original_text_for( ZeroOrMore(~EOL + (White(" \t") | Word(printables))) ).leave_whitespace() XDIGIT = hexnums INT = Word(nums) ESC = BSLASH + ( one_of(list(r"nrtbf\">" + "'")) | ("u" + Word(hexnums, exact=4)) | SGL_PRINTABLE ) LITERAL_CHAR = ESC | ~(APOS | BSLASH) + SGL_PRINTABLE CHAR_LITERAL = APOS + LITERAL_CHAR + APOS STRING_LITERAL = APOS + Combine(OneOrMore(LITERAL_CHAR)) + APOS DOUBLE_QUOTE_STRING_LITERAL = '"' + ZeroOrMore(LITERAL_CHAR) + '"' DOUBLE_ANGLE_STRING_LITERAL = "<<" + ZeroOrMore(SGL_PRINTABLE) + ">>" TOKEN_REF = Word(alphas.upper(), alphanums + "_") RULE_REF = Word(alphas.lower(), alphanums + "_") ACTION_ESC = ( BSLASH.suppress() + APOS | BSLASH.suppress() | BSLASH.suppress() + (~(APOS | QUOTE) + SGL_PRINTABLE) ) ACTION_CHAR_LITERAL = APOS + (ACTION_ESC | ~(BSLASH | APOS) + SGL_PRINTABLE) + APOS ACTION_STRING_LITERAL = ( QUOTE + ZeroOrMore(ACTION_ESC | ~(BSLASH | QUOTE) + SGL_PRINTABLE) + QUOTE ) SRC = SRC_.suppress() + ACTION_STRING_LITERAL("file") + INT("line") id = TOKEN_REF | RULE_REF SL_COMMENT = ( Suppress("//") + Suppress("$ANTLR") + SRC | ZeroOrMore(~EOL + Word(printables)) + EOL ) ML_COMMENT = c_style_comment WS = OneOrMore( Suppress(" ") | Suppress("\t") | (Optional(Suppress("\r")) + Literal("\n")) ) WS_LOOP = ZeroOrMore(SL_COMMENT | ML_COMMENT) NESTED_ARG_ACTION = Forward() NESTED_ARG_ACTION << ( LBRACK + ZeroOrMore(NESTED_ARG_ACTION | ACTION_STRING_LITERAL | ACTION_CHAR_LITERAL) + RBRACK ) ARG_ACTION = NESTED_ARG_ACTION NESTED_ACTION = Forward() NESTED_ACTION << ( LBRACE + ZeroOrMore( NESTED_ACTION | SL_COMMENT | ML_COMMENT | ACTION_STRING_LITERAL | ACTION_CHAR_LITERAL ) + RBRACE ) ACTION = NESTED_ACTION + Optional("?") SCOPE = SCOPE_.suppress() OPTIONS = OPTIONS_.suppress() + LBRACE # + WS_LOOP + Suppress('{') TOKENS = TOKENS_.suppress() + LBRACE # + WS_LOOP + Suppress('{') TREE_BEGIN = ROOT + LPAR RANGE = Suppress("..") REWRITE = Suppress("->") # General Parser Definitions # Grammar heading optionValue = id | STRING_LITERAL | CHAR_LITERAL | INT | Literal("*").set_name("s") option = Group(id("id") + EQ + optionValue("value"))("option") optionsSpec = OPTIONS + Group(OneOrMore(option + SEMI))("options") + RBRACE tokenSpec = ( Group(TOKEN_REF("token_ref") + (EQ + (STRING_LITERAL | CHAR_LITERAL)("lit")))( "token" ) + SEMI ) tokensSpec = TOKENS + Group(OneOrMore(tokenSpec))("tokens") + RBRACE attrScope = SCOPE_.suppress() + id + ACTION grammarType = LEXER + PARSER + TREE actionScopeName = id | LEXER("l") | PARSER("p") action = AT + Optional(actionScopeName + Suppress("::")) + id + ACTION grammarHeading = ( Optional(ML_COMMENT("ML_COMMENT")) + Optional(grammarType) + GRAMMAR + id("grammarName") + SEMI + Optional(optionsSpec) + Optional(tokensSpec) + ZeroOrMore(attrScope) + ZeroOrMore(action) ) modifier = PROTECTED | PUBLIC | PRIVATE | FRAGMENT ruleAction = AT + id + ACTION throwsSpec = THROWS.suppress() + DelimitedList(id) ruleScopeSpec = ( (SCOPE_.suppress() + ACTION) | (SCOPE_.suppress() + DelimitedList(id) + SEMI) | (SCOPE_.suppress() + ACTION + SCOPE_.suppress() + DelimitedList(id) + SEMI) ) unary_op = one_of("^ !") notTerminal = CHAR_LITERAL | TOKEN_REF | STRING_LITERAL terminal = ( CHAR_LITERAL | TOKEN_REF + Optional(ARG_ACTION) | STRING_LITERAL | "." ) + Optional(unary_op) block = Forward() notSet = TIL + (notTerminal | block) rangeNotPython = CHAR_LITERAL("c1") + RANGE + CHAR_LITERAL("c2") atom = Group( (rangeNotPython + Optional(unary_op)("op")) | terminal | (notSet + Optional(unary_op)("op")) | (RULE_REF + Optional(ARG_ACTION("arg")) + Optional(unary_op)("op")) ) element = Forward() treeSpec = ROOT + LPAR + element * (2,) + RPAR ebnfSuffix = one_of("? * +") ebnf = block + Optional(ebnfSuffix("op") | "=>") elementNoOptionSpec = ( (id("result_name") + one_of("= +=")("labelOp") + atom("atom") + Optional(ebnfSuffix)) | (id("result_name") + one_of("= +=")("labelOp") + block + Optional(ebnfSuffix)) | atom("atom") + Optional(ebnfSuffix) | ebnf | ACTION | (treeSpec + Optional(ebnfSuffix)) ) # | SEMPRED ( '=>' -> GATED_SEMPRED | -> SEMPRED ) element <<= Group(elementNoOptionSpec)("element") # Do not ask me why group is needed twice... seems like the xml that you see is not always the real structure? alternative = Group(Group(OneOrMore(element))("elements")) rewrite = Optional(Literal("TODO REWRITE RULES TODO")) block <<= ( LPAR + Optional(Optional(optionsSpec("opts")) + COLON) + Group( alternative("a1") + rewrite + Group(ZeroOrMore(VERT + alternative("a2") + rewrite))("alternatives") )("block") + RPAR ) altList = ( alternative("a1") + rewrite + Group(ZeroOrMore(VERT + alternative("a2") + rewrite))("alternatives") ) exceptionHandler = CATCH.suppress() + ARG_ACTION + ACTION finallyClause = FINALLY.suppress() + ACTION exceptionGroup = (OneOrMore(exceptionHandler) + Optional(finallyClause)) | finallyClause ruleHeading = ( Optional(ML_COMMENT)("ruleComment") + Optional(modifier)("modifier") + id("ruleName") + Optional("!") + Optional(ARG_ACTION("arg")) + Optional(Suppress("returns") + ARG_ACTION("rt")) + Optional(throwsSpec) + Optional(optionsSpec) + Optional(ruleScopeSpec) + ZeroOrMore(ruleAction) ) rule = Group(ruleHeading + COLON + altList + SEMI + Optional(exceptionGroup))("rule") grammarDef = grammarHeading + Group(OneOrMore(rule))("rules") autoname_elements() def grammar(): return grammarDef def __antlrAlternativesConverter(pyparsingRules, antlrBlock): rule = None if ( hasattr(antlrBlock, "alternatives") and antlrBlock.alternatives != "" and len(antlrBlock.alternatives) > 0 ): alternatives = [] alternatives.append(__antlrAlternativeConverter(pyparsingRules, antlrBlock.a1)) for alternative in antlrBlock.alternatives: alternatives.append( __antlrAlternativeConverter(pyparsingRules, alternative) ) rule = MatchFirst(alternatives)("anonymous_or") elif hasattr(antlrBlock, "a1") and antlrBlock.a1 != "": rule = __antlrAlternativeConverter(pyparsingRules, antlrBlock.a1) else: raise Exception("Not yet implemented") assert rule != None return rule def __antlrAlternativeConverter(pyparsingRules, antlrAlternative): elementList = [] for element in antlrAlternative.elements: rule = None if hasattr(element.atom, "c1") and element.atom.c1 != "": regex = r"[" + str(element.atom.c1[0]) + "-" + str(element.atom.c2[0] + "]") rule = Regex(regex)("anonymous_regex") elif hasattr(element, "block") and element.block != "": rule = __antlrAlternativesConverter(pyparsingRules, element.block) else: ruleRef = element.atom[0] assert ruleRef in pyparsingRules rule = pyparsingRules[ruleRef](ruleRef) if hasattr(element, "op") and element.op != "": if element.op == "+": rule = Group(OneOrMore(rule))("anonymous_one_or_more") elif element.op == "*": rule = Group(ZeroOrMore(rule))("anonymous_zero_or_more") elif element.op == "?": rule = Optional(rule) else: raise Exception("rule operator not yet implemented : " + element.op) rule = rule elementList.append(rule) if len(elementList) > 1: rule = Group(And(elementList))("anonymous_and") else: rule = elementList[0] assert rule is not None return rule def __antlrRuleConverter(pyparsingRules, antlrRule): rule = None rule = __antlrAlternativesConverter(pyparsingRules, antlrRule) assert rule != None rule(antlrRule.ruleName) return rule def antlrConverter(antlrGrammarTree): pyparsingRules = {} antlrTokens = {} for antlrToken in antlrGrammarTree.tokens: antlrTokens[antlrToken.token_ref] = antlrToken.lit for antlrTokenName, antlrToken in list(antlrTokens.items()): pyparsingRules[antlrTokenName] = Literal(antlrToken) antlrRules = {} for antlrRule in antlrGrammarTree.rules: antlrRules[antlrRule.ruleName] = antlrRule pyparsingRules[antlrRule.ruleName] = Forward() # antlr is a top down grammar for antlrRuleName, antlrRule in list(antlrRules.items()): pyparsingRule = __antlrRuleConverter(pyparsingRules, antlrRule) assert pyparsingRule != None pyparsingRules[antlrRuleName] <<= pyparsingRule return pyparsingRules if __name__ == "__main__": import contextlib with contextlib.suppress(Exception): grammarDef.create_diagram("antlr_grammar_diagram.html", vertical=2, show_groups=True) text = """\ grammar SimpleCalc; options { language = Python; } tokens { PLUS = '+' ; MINUS = '-' ; MULT = '*' ; DIV = '/' ; } /*------------------------------------------------------------------ * PARSER RULES *------------------------------------------------------------------*/ expr : term ( ( PLUS | MINUS ) term )* ; term : factor ( ( MULT | DIV ) factor )* ; factor : NUMBER ; /*------------------------------------------------------------------ * LEXER RULES *------------------------------------------------------------------*/ NUMBER : (DIGIT)+ ; /* WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ; */ fragment DIGIT : '0'..'9' ; """ antlrGrammarTree = grammar().parse_string(text) print(antlrGrammarTree.dump()) pyparsingRules = antlrConverter(antlrGrammarTree) pyparsingRule = pyparsingRules["expr"] pyparsingTree = pyparsingRule.parse_string("2 - 5 * 42 + 7 / 25") print(pyparsingTree.dump()) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/antlr_grammar_diagram.html0000644000000000000000000104150415134002420017473 0ustar00

grammarDef

C style commentC style comment grammarTypegrammarType GRAMMARGRAMMAR W:(A-Z, 0-9A-Z_a-z) W:(a-z, 0-9A-Z_a-z) SEMISEMI optionsSpecoptionsSpec tokensSpectokensSpec attrScopeattrScope actionaction rulerule

C style comment

/\*(?:[^*]|\*(?!/))*\*\/

grammarType

LEXERLEXER PARSERPARSER TREETREE

LEXER

'lexer'

PARSER

'parser'

TREE

'tree'

GRAMMAR

'grammar'

optionsSpec

OPTIONS_OPTIONS_ [suppress] LBRACELBRACE optionoption SEMISEMI RBRACERBRACE

option

W:(A-Z, 0-9A-Z_a-z) W:(a-z, 0-9A-Z_a-z) EQEQ W:(A-Z, 0-9A-Z_a-z) W:(a-z, 0-9A-Z_a-z) "'" [suppress] '\\' 'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'"'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'" 'u' W:(0-9A-Fa-f){4} (!-~) "'" [suppress] '\\' [NOT] (!-~) [combine] "'" [suppress] "'" [suppress] '\\' 'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'"'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'" 'u' W:(0-9A-Fa-f){4} (!-~) APOSAPOS BSLASHBSLASH [NOT] (!-~) "'" [suppress] W:(0-9) ss

s

'*'

tokensSpec

TOKENS_TOKENS_ [suppress] LBRACELBRACE tokenSpectokenSpec RBRACERBRACE

TOKENS_

'tokens'

tokenSpec

W:(A-Z, 0-9A-Z_a-z) EQEQ "'" [suppress] '\\' 'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'"'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'" 'u' W:(0-9A-Fa-f){4} (!-~) "'" [suppress] '\\' [NOT] (!-~) [combine] "'" [suppress] "'" [suppress] '\\' 'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'"'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'" 'u' W:(0-9A-Fa-f){4} (!-~) APOSAPOS BSLASHBSLASH [NOT] (!-~) "'" [suppress] SEMISEMI

EQ

'=' [suppress]

attrScope

SCOPE_SCOPE_ [suppress] idid NESTED_ACTIONNESTED_ACTION '?'

NESTED_ACTION

LBRACELBRACE NESTED_ACTIONNESTED_ACTION '//' [suppress] '$ANTLR' [suppress] SRC_SRC_ [suppress] '"' [suppress] BSLASHBSLASH [suppress] APOSAPOS BSLASHBSLASH [suppress] BSLASHBSLASH [suppress] APOSAPOS QUOTEQUOTE [NOT] SGL_PRINTABLESGL_PRINTABLE BSLASHBSLASH QUOTEQUOTE [NOT] SGL_PRINTABLESGL_PRINTABLE '"' [suppress] W:(0-9) EOLEOL [NOT] W:(!-~) EOLEOL C style commentC style comment ACTION_STRING_LITERALACTION_STRING_LITERAL ACTION_CHAR_LITERALACTION_CHAR_LITERAL RBRACERBRACE

LBRACE

'{' [suppress]

SRC_

'src'

EOL

end of lineend of line [suppress]

end of line

LineEnd

ACTION_STRING_LITERAL

QUOTEQUOTE BSLASHBSLASH [suppress] APOSAPOS BSLASHBSLASH [suppress] BSLASHBSLASH [suppress] APOSAPOS QUOTEQUOTE [NOT] SGL_PRINTABLESGL_PRINTABLE BSLASHBSLASH QUOTEQUOTE [NOT] SGL_PRINTABLESGL_PRINTABLE QUOTEQUOTE

ACTION_CHAR_LITERAL

APOSAPOS BSLASHBSLASH [suppress] APOSAPOS BSLASHBSLASH [suppress] BSLASHBSLASH [suppress] APOSAPOS QUOTEQUOTE [NOT] SGL_PRINTABLESGL_PRINTABLE BSLASHBSLASH APOSAPOS [NOT] SGL_PRINTABLESGL_PRINTABLE APOSAPOS

QUOTE

'"' [suppress]

RBRACE

'}' [suppress]

action

ATAT actionScopeNameactionScopeName '::' [suppress] idid NESTED_ACTIONNESTED_ACTION '?'

actionScopeName

TOKEN_REFTOKEN_REF RULE_REFRULE_REF 'lexer' 'parser'

rule

C style commentC style comment modifiermodifier W:(A-Z, 0-9A-Z_a-z) W:(a-z, 0-9A-Z_a-z) '!' LBRACKLBRACK NESTED_ARG_ACTIONNESTED_ARG_ACTION ACTION_STRING_LITERALACTION_STRING_LITERAL ACTION_CHAR_LITERALACTION_CHAR_LITERAL RBRACKRBRACK 'returns' [suppress] LBRACKLBRACK NESTED_ARG_ACTIONNESTED_ARG_ACTION ACTION_STRING_LITERALACTION_STRING_LITERAL ACTION_CHAR_LITERALACTION_CHAR_LITERAL RBRACKRBRACK throwsSpecthrowsSpec optionsSpecoptionsSpec ruleScopeSpecruleScopeSpec ruleActionruleAction COLONCOLON elementelement rewriterewrite VERTVERT elementelement rewriterewrite SEMISEMI exceptionGroupexceptionGroup

modifier

PROTECTEDPROTECTED PUBLICPUBLIC PRIVATEPRIVATE FRAGMENTFRAGMENT

PROTECTED

'protected'

PUBLIC

'public'

PRIVATE

'private'

FRAGMENT

'fragment'

NESTED_ARG_ACTION

LBRACKLBRACK NESTED_ARG_ACTIONNESTED_ARG_ACTION ACTION_STRING_LITERALACTION_STRING_LITERAL ACTION_CHAR_LITERALACTION_CHAR_LITERAL RBRACKRBRACK

throwsSpec

THROWSTHROWS [suppress] idid ',' [suppress] idid

THROWS

'throws'

ruleScopeSpec

SCOPE_SCOPE_ [suppress] NESTED_ACTIONNESTED_ACTION '?' SCOPE_SCOPE_ [suppress] idid ',' [suppress] idid SEMISEMI SCOPE_SCOPE_ [suppress] NESTED_ACTIONNESTED_ACTION '?' SCOPE_SCOPE_ [suppress] idid ',' [suppress] idid SEMISEMI

SCOPE_

'scope'

ruleAction

ATAT idid NESTED_ACTIONNESTED_ACTION '?'

AT

'@' [suppress]

id

TOKEN_REFTOKEN_REF RULE_REFRULE_REF

element

elementNoOptionSpecelementNoOptionSpec

elementNoOptionSpec

W:(A-Z, 0-9A-Z_a-z) W:(a-z, 0-9A-Z_a-z) '=' | '+=''=' | '+=' "'" [suppress] '\\' 'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'"'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'" 'u' W:(0-9A-Fa-f){4} (!-~) APOSAPOS BSLASHBSLASH [NOT] (!-~) "'" [suppress] RANGERANGE "'" [suppress] '\\' 'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'"'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'" 'u' W:(0-9A-Fa-f){4} (!-~) APOSAPOS BSLASHBSLASH [NOT] (!-~) "'" [suppress] '^' | '!''^' | '!' terminalterminal TILTIL CHAR_LITERALCHAR_LITERAL TOKEN_REFTOKEN_REF STRING_LITERALSTRING_LITERAL blockblock '^' | '!''^' | '!' RULE_REFRULE_REF LBRACKLBRACK NESTED_ARG_ACTIONNESTED_ARG_ACTION ACTION_STRING_LITERALACTION_STRING_LITERAL ACTION_CHAR_LITERALACTION_CHAR_LITERAL RBRACKRBRACK '^' | '!''^' | '!' '?' | '*' | '+''?' | '*' | '+' W:(A-Z, 0-9A-Z_a-z) W:(a-z, 0-9A-Z_a-z) '=' | '+=''=' | '+=' blockblock '?' | '*' | '+''?' | '*' | '+' "'" [suppress] '\\' 'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'"'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'" 'u' W:(0-9A-Fa-f){4} (!-~) APOSAPOS BSLASHBSLASH [NOT] (!-~) "'" [suppress] RANGERANGE "'" [suppress] '\\' 'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'"'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'" 'u' W:(0-9A-Fa-f){4} (!-~) APOSAPOS BSLASHBSLASH [NOT] (!-~) "'" [suppress] '^' | '!''^' | '!' terminalterminal TILTIL CHAR_LITERALCHAR_LITERAL TOKEN_REFTOKEN_REF STRING_LITERALSTRING_LITERAL blockblock '^' | '!''^' | '!' RULE_REFRULE_REF LBRACKLBRACK NESTED_ARG_ACTIONNESTED_ARG_ACTION ACTION_STRING_LITERALACTION_STRING_LITERAL ACTION_CHAR_LITERALACTION_CHAR_LITERAL RBRACKRBRACK '^' | '!''^' | '!' '?' | '*' | '+''?' | '*' | '+' ebnfebnf ACTIONACTION ROOTROOT LPARLPAR elementelement elementelement elementelement RPARRPAR '?' | '*' | '+''?' | '*' | '+'

'=' | '+='

=|\+=

terminal

CHAR_LITERALCHAR_LITERAL TOKEN_REFTOKEN_REF NESTED_ARG_ACTIONNESTED_ARG_ACTION STRING_LITERALSTRING_LITERAL '.' '^' | '!''^' | '!'

CHAR_LITERAL

APOSAPOS LITERAL_CHARLITERAL_CHAR APOSAPOS

LITERAL_CHAR

ESCESC APOSAPOS BSLASHBSLASH [NOT] SGL_PRINTABLESGL_PRINTABLE

ESC

BSLASHBSLASH 'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'"'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'" 'u' W:(0-9A-Fa-f){4} SGL_PRINTABLESGL_PRINTABLE

SGL_PRINTABLE

(!-~)

STRING_LITERAL

APOSAPOS '\\' 'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'"'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'" 'u' W:(0-9A-Fa-f){4} (!-~) "'" [suppress] '\\' [NOT] (!-~) [combine] APOSAPOS

'n' | 'r' | 't' | 'b' | 'f' | '\\' | '"' | '>' | "'"

[nrtbf\\">']

block

LPARLPAR OPTIONS_OPTIONS_ [suppress] '{' [suppress] optionoption SEMISEMI '}' [suppress] COLONCOLON elementelement rewriterewrite VERTVERT elementelement rewriterewrite RPARRPAR

OPTIONS_

'options'

COLON

':' [suppress]

RANGE

'..' [suppress]

APOS

"'" [suppress]

BSLASH

'\\'

TIL

'~' [suppress]

TOKEN_REF

W:(A-Z, 0-9A-Z_a-z)

RULE_REF

W:(a-z, 0-9A-Z_a-z)

LBRACK

'[' [suppress]

RBRACK

']' [suppress]

'^' | '!'

[\^!]

ebnf

blockblock '?' | '*' | '+''?' | '*' | '+' '=>'

ACTION

NESTED_ACTIONNESTED_ACTION '?'

ROOT

'^' [suppress]

LPAR

'(' [suppress]

RPAR

')' [suppress]

'?' | '*' | '+'

[?*+]

VERT

'|' [suppress]

rewrite

'TODO REWRITE RULES TODO'

SEMI

';' [suppress]

exceptionGroup

exceptionHandlerexceptionHandler finallyClausefinallyClause finallyClausefinallyClause

exceptionHandler

CATCHCATCH [suppress] NESTED_ARG_ACTIONNESTED_ARG_ACTION NESTED_ACTIONNESTED_ACTION '?'

CATCH

'catch'

finallyClause

FINALLYFINALLY [suppress] NESTED_ACTIONNESTED_ACTION '?'

FINALLY

'finally'
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/antlr_grammar_diagram.png0000644000000000000000000407214515134002420017323 0ustar00PNG  IHDR Em^fIDATx{xU/7íRr,GoH$B@T"WD[*SE=mEJ[H/FH50KjrjW@M$;|]zZX,4- I  I  I  I  I  I  I  I  I  I e˚&eeUk7r͈d*?23mdfMxhPz>vk IЌH*+>s;քу%‘Yne,WMqJ lb@+6x^=fBh-ko=?#{vFF ~8=a"#{e :#?C#k=lnbJ:kZgl/_YT0id^VfUKf ˋ6n5oŒK5z~'ӏhueN?%^o7,glYФkF(Z>&@3w.k˽♭aZ#3:Www**9vꮇw&dd1Ƶ t|QC3>ӄ,>dfpC]nxu]Ynkԯ*,7,.]i uʹ @s.[FV#\īWK)#ߟ?29ĜקH^p7W^31ums7;#֧|^7Z7$+?~/^^2Snxػ~N3`և[1׼A=Ku?!ƆUC}*wxܑE[H.4r^"aĢ J[l5e7t Z^C܂_%]̛Q ɰ3>zz3̥CgKQ~l{xk;t-N]m .]ss['/.ˊ׆OiLb˟xXR廛7?}m:ϲ8VWx^ǚ ]P#!w?NPe3+o)a2wk&n-ue]$Uv g'2e$7p5D wIn7kOfnV.5-k &fW!y-zvF̽+jwBњ-ՏTx gHKK]~w~CyW<#F5|=,[3WіY@<.{f^X=x^a]?K5-CcL4≕m&Գtr?ΛxnϋVQ{5g^=3\<:3Q++{xù24#-p>ktq닦8S몑=θ|EGm'qC\uO=}g:$ϒŵ~|d\O=j(qAN|_T* ӁH֥hdZc鯯54*YY\h|>_^??Owh(Er]Y7x r@ H? Y1Jbi9R$HM$HM$HM$HM$HM$HM$HM$HM$HM$|o4WwLI  I  I  I  I  I  I  I  I  ɏa \dժ7m>dI m۶cǎ_ygw;v 4-iXl'۶5P /8֭8`@kѢŵrMZ Tk׾CHe-cǎ&կϸ_ziUE*++qι˗32:\;n\Ϟ'w֭1Ǥ۩<%;k֬y?-,* lcHODr?#F-** 4!~72^nEz>54{"@<2њ|5O-zR>qKy/~1^o߾1c?@EN;w#&8'9ڶm[YYW/R.u}N 4-Z7+*HeE+*jw0g;v;e˖ٽz޽{x񦍶R\G$oHꚨرcz~Xi uYͪ쑝;G/Hel^Z**23;#8"*V^He-R}ꩁfoӢbÆ?)KDr***Λ}f#333;WT=)KDro~%޲ekqq_WɄ{<\ 5HaΝ矏iii!uLMI~8: 8x.۫W ^x5;:ބkzP8*;iC 'Xcܽ,VZ$/=4eG)~ԏY۷8~}@Ji۷/}ig|‘g~5kFrsoeJnVP~T~i4vZ+|Zo// bM=(Gy vgӮ?͛7RAZ,m >>IDAT,))itGoܸ1| :ϕLXҍcFn3%ߒe[-QsdBܱ XW&qiabaȜZݏѱy_GC ?@~=WHڷY?5Yվ}#;w޽{n>}|VVhڵR\U{7/(=@>2=SutjfxJcɠaٍc[i'Μ8aɘȽ>$'Kڿ;F շky!ix r'YPUx],b'?*VycZ/K"횷[x HpTQ'&F&w^'zĶm֬]…Sno'< MD;=l*II|-'qc SP8eaSœhX>%.]xQVy?f_? =tJ,,m2?ծ{;rzGE걲{JvkتJܵ|yES&'~k;>_ziUo`6[l}W~EEE֭?+ÇhH6w/h ytaCrP!i=[rF;k`fn$9%gAsUf"|YT-{ɎD $I([Tw$dg]_XVSxǾ3ѡ~_vrӧm6ث/_hiXl'۶5|"HJ4pHZAyAZB19.}eBVuL:*zD13uސe[-ޱfoOnW]5#Q{ܽ3GP37u@ɔu,_B'wT~~((/*ϙezVK Տ?uYn>.{+ y}x}l/5=۵R'q"DL|DcH-^ߺ ~K/842"@vQxtAy#" :QٳMD2ŕLMIIX*w e(+[y@Jw/Rщ'жmx/})PtCErFuE_HNq'>rr|"'p.n^D ojrIQWKVEEff@->[/޽JDgZT9Ntg"p<]̌{gFꛈ$|VZ}+bX>3a ԷTVV4g32:t@EܦM^xK.*5ㅳԩS|DǟXRRjꍛ6m޼9@*8}_=3/0R8"‹/*ua [|;vL_/~ /{<9R/"YYYs]|Etqz<[n=;.\D2]z5333@--BJydΣ>H>X,m;wسo{=ZH'v;TJm/*z*Gig>( %" \3cT}c/))YjM|.YW۷?sݻ3xgeTH\2*R /8֭9{@}۶mۚk'._~;:֭[Tګ"*9-4n;vaҍ_H>|3VX,m}>#*-9._":pq={ܭ[J;S–-[_y?,xrQQQ4زeˇ |"wLD F ?L?&M2^nEz>5H.6N y&yM~S,<#x}+nj͏d}ڹsoQwѢ_v 'UTTDE>-Z 43"fǎoNhٲev^CwQ񦍶Th/~o/V^}'FWDEǎÖJafͺmV]g9*^~@3J]$8∨Xzuh|^Z**23;F@JdvvիV5dSO 4}6l?hNR)"yoFyIyΛ}F 33&VL 4'tYgeŋyWb8|ᇗ\6z˖q}k_ 4ƏVsf#"-[>.ypchv97,}?hup"]~ŷWn[R)"7pq߹&RP+VC_?YM_nnhNʆ904Q8}񢼼|grohR,"wםwzjvTYv`ޙ5ޙؾ}矟6}Ʒ.yΊ?C4/7[fUXiQ#@As׮]Lsǟhb>Omkh{Q\~,)) 裏޸qcJc;]21w`=2N];vd'c Ƅ羽*oCᐴh҇;?\K£s 6="yw\"jK7ٽl{x7Gwk۬̚u۬oΝw۷gv;Tz]$ڵk]w~CGaKcyCyKI'3C(RP~T~i_cy^w*ẑRKғqҩOYIJғǚ֏EK1w/5{'Fux"[bcZ|`|\)6hh)|׼}8TS+dy"f=%s}C2,ySdBRYy{.*wTtʪpLW}ݽc(r{~ jc S'2aUlkд|μOn^Zh0!k+F?!|>d^5fۇL)ٓ:ujzX&͵>LXvs֔҇M}euv3wPu%˪'tXmٲW__͂'G^[gv^p&)j&N-?%e!sX2nWɏxͮ>dxd"qD$ǦB2`IDAT$6RUswU[kI90Ks>m۶^|@Hb<޶zUE4V߉CQcŲc#dQ Qz.:dJx1cGU/8uynڭ))Hԙk{MFWUoýeϖ>l]*;{{~񮽗^~0kmB"?ʐo׷ފvRYcL] FMԘX`"MX^grZ91\mvݾXg:D{SǽZH&Oܽ쉏NM׉'? BrK/8PlݨS+tRUM?1 tEFEgꛈd#T8$-'';wn NV{j!yh|J|BĒl(+[y@v#6sZn^Pzs $n۶meee^QVv?H¡ѢE~}z! HONjw}7PD$GEFFF^H!ҪUQ)PD$?;նn%sz+I84iQ:uEH!t33׎o"Y[j壯b̼374PZRYYyӔ[?ٳ @Ihp6mz.](^׌zSNbIIɪU7nڴy{_|̼@H /8֭ R7[oLJF$w1[|A, "p#.K.@Kdee79waFFkǍnݺ8rX,vW# )9.**k"Hb>Omkhdvyb^oFh""*ڵRY*m(٦M=|$PTH.xraT{cJɕ+WFE>}BggnqRO!"Qѷin|wO uK__z+^k'|rhNJcYn>#UWRD2;WTZ%" O*E$ͨ;tYgeŋyWb/lٲiwGus}RD2nsMTi}W( srҒ ^V6$y8ֺj.D CkR,"wםwzjvTYv`ޙ5ޙLMl=8͎?W/v-_IJҩ!-I37Tܽ,V:{Xz]%$o^)/,BvͿ&YxQ2.B᥇'G]r~pEOH\RRW̏]yA޽?2q̰ >R3Y+?wS Â157 }̂&~-eW&m;!x:sǝw? i߾;w=o>>++Rd\v~c?/~xh/ZeNDX쉏s.:qysd_? =Ͽf^fް ˼aC2wOpȔD{庖̶m֬]…Sno';=_ZDˏYnbɽW|󼿾V>{ʖƧ] H6jl OD2nQ]_zšR4謋Ff7I84ƏNTܼys^H¡q 'm6Wꕈ$-Z7+*WThrNX,;cyCE>+7MeyoÌ?=+tiӦ^,}n҅ux:uh)|'ZzM7o ;GW 4Hcmݺ)eyCo/{ldDrǎSnb) > /=O4ԋHVVV~s/_fdtvܸ=O֭[ )b^~EM>~?PKR袢&?O->*-{۶FfΝ'o^>-R, ] FۋmڴكGuI'FŹ >n\reT'4bIIɪU7nڴy@S׾}#;w޽{n>}|VV eb}xotwމi99cmݺ@sղe~[ܺu,k!TH~Qvmۆcǎ) YhVg=x)=C#" THv忾VXܒO>9Էos+/xI^=?uhmٶun(_d_ ͌$R)"ٷ/ObVO.P#F-**{ u/f鱂Ǧ]7m{xݺu-МHEHٽbժա=2њ|# G6g ~zWH)ABqK94triF,?3Glϰti_'.{C'}֏sp)'uoݶuT(?6>]wqQfځyg^0bԌ{g.'UQQ=cJB]ԵjܽGGvdzc_O<:Z5.g\9|rFW=LуbBwzO"* È7/]/~DL#-Zr)Q]Q@HdS ׿VspѢ򵳾qI=?OywN{RݷzRw7qҰ~zdyCC{`C1ӻd\J/_xPZ꓾H8 9&ANlkGW%Sq|bܵ>XG>#/6}ƫk^JF$۵k]w~kBܵWذl?`隗7.'e̵o_B{4}+|^_g9iz\ Y!5ov䙏"s9c\8$߽Sk/^ݨ2 ~B!ke6çm۶5k>p[o7Oپ}{!dD2k^;aXpl=$ŏ{tZs.3{+jV{|j}-붿[:snѥxZ*zFp۔'^fk OiYq:_$tX鄺VZ:y)ưt?/3~^M19QuGuº?3+_=~ŷ|3scJʫϯf֭?+Çh)E{wϾǥ//۱XqqQ+{?w4y]e>`t_v5:'w4sѿdžiI G|l¾;HF]nU.cH#43'ztd2 {a&)1k9种__'=zX./#hffXQvUQ>]v?y/ιKfdt_vrӧդu=W@HOOE \>p_g]{E#!D.2'QzA63Ӌu]?u?v k:h?O"Ս'{vq>uhAO`A?\nv< 4 ~Ul޽9>+oqXzu֭K+l}‘"cs;fv /|ҹ3nK'sҁ$Lv~ͼaBr}<8~W?.^ߺ ~K/842wvh(lժU~۠:>++^ly{%¼KC(Zx#G~?kǏkڬŸFe^r0ȸAκhԨ~`@}k]$#.׿Y/F_~ُ9KJJ>gHT?rڕk5[Ipf ~}N+//~\VT/Y=zs־/})4&Hw'*Vk}皨;s'\J+ґ99iu}&7T:_ϼ,(᧳g5y_|>2Nh۶mT(+ ԫ [~u=믾~i}_5)rJS ҹ*Xzg˞ͳfp:u몊>-ZÁ2ED2Wx뭷?O᳿y6 4Wvأgg8g1+H/YlݦM?]vzu?<м ;ohɳG}EEVT@|\""q}׼}8@3&?%g_>@jjmڵOR$HM$HMd{%%%V޸i͛M]ܹ{} |YY%"/ث_[.Мl۶mڵϓ Sknrs֭)EhҢ"gڎ;ntW>H>y_/j3?èhQ7@c\Ho{C󷿽;t𲲕5#ur=h궼կy՟_}=>ںu~eVO.:ڲ%*:dt4ͥ䠳X,vU5^zYt$Ldt93gԵ{ܵ[|E]W=U5謳FsH'*_l袢9~dŽ_h?>ۯ3v***֯/pvh4MD򴪈/uvΝzE񽏿nufؓ[u~G>:QhLKDSOɉ/?EEOuwλE>΍f.50'\;.И4,`ZZOg_^|_nsΚ \_OMI44真S99YU?͐ޜqC\r%QQVr5/O2} 4&ͨ]b:.x`Vn+VE+W\5i¥#?fp0bH,mچ3Kcu;[,9tZ׉KfEO֏sp)'uoݶuT(KTVV4Xs;nhd׎}o>Qfځyg^0bԌ{g%v\~=븴Ekf .Z5#Sik\wWHH& ]0G:K ]:'.'Id ^Xӻ$lxlAw h&~0 K׋6|GHE~JT/*z꺉'7k׮NfvaFyE$[lՌ,\)lݺ5:88?ksr'k΁{kL~F]׾z`C1ӻdZG8 9@=NlkUd*tp0}|T<̚iӦ':ƧyE$ڵk >]{ ֿ9 y yyCrR\!ڹj)NlukЃ;ZRIDATaϸ'e!5ov;Lo;^?Wm xu0 ~׮9۴<[3Rzh~Zhkrs2yn{rVn=tYxCBѵk͹D}_!shrŻGD_o:m-*(&xQ.׽XlN] 9eЈ.U{Au]?b sf?4eҚEgLAґ9zi19Ẍ́A3cbnX>d玝5?|ą^z={hĚcD2Ү]+nݿ׷ފwqu]5Kxq"5xINxwTtK#k҇_Չ,C#xDJtnc,q}"t~=ⴡiӪg=VuX鄺VZ:yp"Xy_c"}N#kbOtG􎺯O>2Knpi]T̜1W^Hn}:#W~u4y]e>本jJؤ;\_k&IMnK' vX"tdNN֜E9ہ:aCUOh1D1A3 ێf__côIh̹td2l6y0wLlS>bHsOuN#42/Z_GAmYU_N!"]#!D.2߿yT_;~\ uH&lrzų+pOhgOP7Tʦbʵ71˞wưRd5Q=w NW#srLn֛uxߟyYe[Il7᧳gRJz]wϯXQ_N+JN9ShH疖 VV=[o5ㅳԩSh;v숊-JDrO-|r%wͳO:}_=3/4W_];v +m]vzu?<м ;ohɳ {iժl.YZ,m {7w/. 4'_8^x%yrhH[n|T?m?v;T&" ͷ:}ƽi=߆FFDHu=]̌{gFꛈ$|VZ}+g1켡"ʛ2waFFΞhHB۴i />tEEfp:u 4H>KJJVZqӦ͛7HvأgF G$_xűW忶n]2켡z˗=6`R2"cǎ) bXqᅗ^rqϞ'XE$+++qι˗32:\;n\Ϟ'w֭qHbK/&ٿ_?`fffEH)ytQQQT_ۧGym[C#s{z7uvvgC)TѮ}RiEEOE6m#RDr ssLPTH\2*쒒 `E hx}N uK'xb[*E$[^;{}Fgs? #UWRD2;WTZ%" O*E$ͨ;tYgeŋyWb/lٲiwGus}2pq߹$^O?=SOwŋVy,S1 I+({^zޒ1k&3.z!9SkewHR]wQ\v3/1jƽ3)28 ]+-}(+98fAlv^O?KңdQ>eHaeWG!W%&H[N4.)E2'G]r~pEOH\RRا5oбw2]:eN;dԽG8l;§3BӾ}#;w޽{n>}|VV^ɸv~xם_8ApV|JNNZSڦhj 9,/}S'^=W|۶m[v NN|۷RJF$#߽5|߽3N?p`woG -'Z9ɣOZ*RU|pUm۵kwЌ=dCvvesΟ_ƌTᐴ^V̾{JfΔs.OgE g˖ʟo<(>ںu~?{x H ϭBs Jc˞|Rwe/;}Z۶moj "ٜ$?2ߝ9xG rN'.2xWS'U_]xQ|dW܉%EBQ<6Qc̷|/۷_9flF'cxؘ̂:ԍyv '+7MeyoÌ?=+tiӦ^,}n҅ux:uh)|'ZzM7o ;GW 4Hcmݺ)eyCo/{ldDrǎSnb) > /=O4ԋHVVV~s/_fdtvܸ=O֭[ )b^~EM>~?PKR袢&?O->*-{۶FfΝ'o^>-R, ] FۋmڴكGuI'FŹ >n!l߾=KJJVZqӦ/{KUܹ{} |YYfZ<IDAT/"+W>}T‹/*ujF=P߶m۶fɅ oש5Nuf,}N ێ;ntW>v>|pUf,-{۶Fsψ}Kh*++qι˗32:\;n\Ϟ'w֭1ǤRΔeW^}~7 \TT lcH@*gjzfff>?Io׭[mѢ޽O ||"@KS#sG^Ԣ'#?Kc}3O/~1^o߾1c?@#"Yv[Tgg]whx ~mݺG<h~ӢxxѦM=|2hY̞h~dӂ'FŹ >nCgDEY͛7@YreTg?@Ø|㤛nT{Nh۶meee^QVvhNtOQѷiCErFuE_͌dٱc/ZlݫWPݻwTim'6>_[oŋիW|ɡy5Qѱc@}YnU#;w_~9̤R#8"*V^VNFРR)"]{U:"S@>Eņ TH7Q1w/+**BcEyf̬=I*E$uYYw޹lX,4~%޲ekqq_WÄ{<\Hd˖-O;K{7;wN K>:fƤ蜜!9gNjX,v^1n@CHd}皨IAAXQ^|1f͎7~PH >T1Ȳsr܉Omdq(վ}xQ^^>3o۷o4u);N=5;׬];0 FqecLl߾}O>[p%%%}7n Bit )yK=f$3j(R<K&+SUR6{/;v*/Sqq҇^DU 5>$IGnSN))|Vy]ϼdzz)6hh)|׼}8d>xGz﫻-޼ P>SO W6{g'K/ 4ڵkw㟐 >1kkqwVɷoW0ٯ1 ,A{9kmlN=0%,> GҽanqRhlʫϯf#[W~񳇇;/RdtP^mH{Rl SjGWh,~u#XxtNхIws9# I{ʖƧ] H~v:"oQDrS7VQDf/E#qv.ꂟK.$l Ag]4jTT?0{vH£s\䴞Xs 6xl. |q߉7oԫ@*4UNʾ{'LY9ڶm[YYW/?{w^Uu x"+*8HUZ(XN+-B "(r$2dH 侯sZ{u6~׳*.wԪUsf.*<Pt 2R24|}R^XlYRH^y"555PD$aiiJDrYeVX'DuFJ%" {7*:xbfHT2I &M~Q}5W*$isY>@e=e͚5zKS~E05##T]$-\w&#~Yf*ɱ=?e9/\gHw~ |w^> PzsmrQGLBF$ׯ_?[`N, hҤ_rEmڴTċHY3{Θ^tګnӦc@E$c%#tcM ɧWfgDH`k)X+Wj櫯:MEvcj%XE@"K'#իG%"_=<# 'M?f̘1&MkӺ~zw9.Ν3>`5kVTt1$E]qկz vՒK9y_撋/ P&.**NO 寏?N#D˖-Ͼ/P"%U8zP(5*V}<$k__Zj]=CGyǦׯ_?/'||>_FCю'&X jnڵ7xGlb="@B}߶26nt37;Ϗ{KEu~v$jMlԨ=*Yu}UW^Տ?y5dUYώ}.wiiin=_=b@&"YU&N̍61?I Tz]=(_5[@՘9kVTtyg2uj`7L|qݺnzӉb_~eF5.U(*:u<1GiӺ~Q]LDF$۷o#wڴO?,P%FM:ŋŜ9sZnYg=#IDATG!iMzCVty35SNdӦM"ΜP͛7͚5Q֬Y`OizPK__T"E$۵k?6;??*7oިQҾ}KRsTDHsYQ1z3EEEڸq}Q`ճ>wcIy*"O;xdK8jwfnݺWf A5п_~)">wQ=7~qÍyj}OTx/4̌^#CuЛ(^t񥋗, <ֵ?2N73T-y}^ft]v3S2Cs=?m{&9%q2hd䈇zot&"q}vQ]0wnSsabs#l3s_z):@&O>XZx7jeaBֈyBrzQڥ_|1SNnW_/5@J,p`Zz_ꫯmq[׮SXJrw޼PyXF=bQBtu歏Ne_w8næC3Kϔ5bʿyVVQ^tۧtf|%_,{Ǘ}gv+JuBNtMV[oC\:hFތoUV=aÆ=#<2S3qlzz4lYukР ύh$$>>}JV▍#{KN$g͸E>ra+Ov%c_:!,^+=ph٭oR~I&xaaNF(9i%s6)ZzɁf;s;^,mHYc̨.W+W̝ CoSnyuU)!#pt 5sG&0Ά' s[K/ 5?%)*_vwג"+vu%9fMd+7ѭz@^v{ ochYuzQ:B3̞2C"kРBqfNso1#M… szqf;V7|koU2t)ozvw^w|W߬]ø~{e_r!,_?/N͍Guv}@w^Yvw>oag{Eq/ƧiŻo.seGPvIf{soea_qhw.#V!`CUzae٫e˶7N .ֽٗ>vNMmܥs~^3G23 TX,V+UCag9p܆{DnץKe]63:y}݁y뿹jyXu1ݳv֔i EdXW#vqȂ>]e:p\^ᖫ ~V?߲-N4#oFH.[:/Gy3BӠaD$H&("M,*$AD2_9GEuΟtjFDHt6چ{.~hĈ@eL>d fd#}\Ө9sg}TTwOvW~5kfyʣ$j)>T*]$A TwŲeJDΛJ%" {HKkT)X+WʬX-۬YJI6h8$2]$a=FEOnH$ " { @e=-?N=O:9g*[)k֬[/⇩p " Un…;7ߜ017^C͚5 TH})Sx>,@"wO|Ԭ@H;;|Qo:*Pe2"~sbXq@&}?/jӦu%^Dr͚5sƌ^}u6?V.".7<٥s{4---lVH(O>ܨ2;&G[Kb^"T3_}m.Z(^k^U+"(4lY"m=1(Y^>|$-ℨyGqx>ÉsG}Ya_~'w>j~'ЦI'իg:u5X"E$g͚;v ۚ5knկƍU/}ZwyxȣwQ=7~qÍaoϟӯ(uwj)9;Plx/7nHvֵ?2N73 k֬[/⇩p{Fq ^y԰oRu^;ymk?3z~'`ɸawپ}.;[֩`L{P.\8vm1_udJJȇj֬Yػ Pvs3seǦOMpNaHm:Doզ]AW\ } 6NJIV\իW_p%u:ej[^yvӞoiٱY@U49ќۧ䒢nm (f^_w`MO}Ԝq%䶛ݪv֔iww ۑkw;찏?8T ~Coak/Z[.13 _cfٳUvHd 4OHώ}nO.۸qct3{'ع T"p{oWD ԥ\CwE$G.&Y3˺Bn^=`Iv(;Fpc˙$ ,^vSeyWݭdio.U()_a6{_߷|Kљw}߀bP6/ߥ<ﻷ<Ϙ^ l+[z@Oha޼iӦ/M|񘣏~sװ;/.o|(%#nCڽGL+-z4<7s QLӋwĎddh n6tM7d_](+Y^’:Y#CI,[7+t")QQ7 p>>u9/^:3gA H!k_/<7C;L0QDruD2nƍ]2gΜx}-g7c} _9GEuΟtjFDHt6CHT\zś#ejuԉWB / 1"PD$?f^_7#gadd62TVz=ǿ8!$kiT̜9> Tځ7waÆZuѩcǿ}|9kVH(w\׬Yߛ9*.{BQQQTdfv TN:FEQ!ԪUsptVX{v=8bٲe!ѴmIybJ%"'Q7P͛!ԫW/*6|uRH M69sjv~~T5 PFDrOĨXUV~!O`G$;oL@KKKk׮mT{h1Q}Yg(#" 暨{F`mܸK/_"^:ʈH!?zI"9svW_}u/nx󭷢?񁔔eD$|aÆ񢰰)rۯ֭[ynf=<":n33lv`Ow;⡜ .8mذ{{v3z8KΙ>[n{MoM[~sfm iQQ{}JDr:WqcKV^?\㜇ߦ[׮SNݻ?Qk'kQq*1er3 솃k+/}QѠaD$?Cn)={]o_Ö-[L+ǟxr޼""G-g>mq믿1rdHQ'F;ФɅ}vIz/R;͜5+*:wvR3{M:5$/?[ĎQ1/QF6UTT: mڴ_~T}y͉HQvþ{B6Q駟\"m>_8^̙3u!͚=;*9ఫP!) :uЌa|D|D"ulڴiTϙмy׬Yi͚vOӃއ|Rl׮mT$h$nv~~T4o޼QFӾ}YT"E$9=晢P6nx~mzg}B>)/&)"ӎMOK.cXH7g̈uֽ2{P`5jh@~"& OoE2g}Ɛ =w78Fkdnzs%ً.t%J$RD2[׮WʨsNN;P-Zxyvtѡv]~sUФE7ѣ$\D2n]wo. uy}.~~;TXl|/ ԡcfK/EhU> Ӧ}<}zle:{/xy)Wꫯ}*%U8zP]^/y׶8߭k)Syai:ΜyhC:lkta9 ˏҲ7M7N>[ކ'7ꛡYSu93;0ofg9p܆P'+Y^^j1va:hFތLؑ-ߪUB5аarȑG٩g86==T{ 6,H5hv]4i\IψKr^_$z(’!t{Zlzvd(,UY24}JV-ddyͲ맆vO+K3%+ʕ+ }q„֩I73~ZIDAT%#Sӱ 6zcwLvsGK0Άm]'Kd&C.gL4h㟐\nOQ]V+u0koUdIx ۘY!2:[laƌڅ]uwS{~9&Oze!-_?/N͍Guv򘧟ճg $pd^sjNq_`Wo6ϞqyqdauuF6o#]dٵiOsūty3ǟܭtǽpIћyO~|}>8su6'JzB5ӠaD$KiӦߙv@&C;L,F$;+gϜqԑG[o~Fύ7?. Ռ$l]Z mi6mZGϏ IKW c>PD$_yuڵ☣P 暨gdždt5WժUpҤ%K*d52}ƌ̔P|W!|m{"|ofRHV#-:*x5j֬YT/\IHF}tT|gJU;Pm,-mδA 5w{HQQQXtGN˖-0PtF "555$}7*6|uR"Y4=iT 5޼y׬Yie;nFڷos*HNjQѼyF6ڮFz>ċ9s}R^6nx~`'HV#5п_b~%KwfnݺWf D$[dŒK/Kѣ=Q} HKK D$49⡨2:>5zt1-Z <;:?.vN^Kb٧_~ǫ_GrA:fRt&M|Z]~}Tg@~ugF~sװpOhݺ9sBriӺuV?# =А> *<@E!?ZN:\)'hqXHv"-YR"Y}u~iOK/==z'[.$< ^z|pVX'DuFJ%"YѣGH:ިx͚" PD$a/7yD\l"@,קfV5kr-]OZƏx8Pt*pwޝƛoNϏ|f͚@G$>S|pg} |;y'jVj$pDwxy>(@B}ٷzG2 \~[nӃ9X,@8I>i:P/"f͚9c{ajjkMև~xc bPҹ=6Q+$'zzbnnT_K#b V\6m-Z۵kIת`OH 6,6ڞRW_}T>ؖDHqBT<#8<$ 6׿>(/WYvLsޏk~hg]'5y֭9#OM )"9k֬رcHvN[.˖//,,yyrlzN<$"EEEQѩ!yOJQVZ]^X07Y۵ RbXW~J7_^V^g-/ 4h{GyD oVZX0dvmpjV`kаqHd"cO<狣sf]:g%/RXX4g:&gHV:qiѴ~jf>2 Mo7 3jf͚?o~衡fO?lŊ/7lYaak`hkKw}{D'"1e={DЭk @DHt6dŲey4hP?Y' m1eꔩSCIoΓuݩQ "M:ŋŜ9sZnȪU>+v9"=g TSNal(@MPɦMd~E$c@>^ɘ}6^4?о(Gvm"?NضDHsYQ1z3EEE`)"ӎMOK.cv!"}Sx7RSL(#@Id\]Q眜'vzy*iӧd`,"7;۷osv:> ioJ$d&xŗkᄉPcrԩ!lٲF?O.9mڴϟvs3/nCs ϥezK)gOMLvo7nyJjgMvw:5JpMsg;OaO`sE2A/<7:I G]ʴ{~XvZ6ϞݼpFddΎl}Gny>=~uuG#!#pt nڵϯ>a(iO{]y#.;Y84##3pɌh\ ~<ji{,{?˛w&iWviٱ;{'p5W;qٿlnlkJ.5Ͳe.׳]޶m۰[ڥ7`y./ޯ;簑SL<ۻH6l~t=sry(@L7xӂGSO<~ݿ[_=)9lұ>N[!vFddt+M^U Oɪ]vI:Y̞]:wΙ/XR$FI79^4=z?=ztT_sO9sݽnG/h\i;?=}ƪU6nxǝwxDjau ?$| 'ƍEcmpEgYbEJ""7.*TN,.FŋzbK[Ox'wx3g0/ Sǎ!ťYf$" (*իKfg$ފ+㎭Ukgd"Q NIDATdDsE˖vX]oqHT(@M "?o~H:-Qvݺ?6 Ph;4=iT|lQ֬YJdhd-[8?gaݺryHX$H&g7nŤxQN3zHV M:y?uJTnx17BR(**?Q6lHV =OӦU8y?껆v3_|i%K_2@Ib^"Plذ[֩s?ܟ_7bٲp^8u3[4ld"YN>yٲaFz9Sǎ'q)))[bŴ~kۯ{,?kՌ$D$̼y;۴n?gNZn=g|ӍCnE]@=5?9gۙv-N|ŠAoHdw ?' @.,YO׬]۟nƣ<2$uޏ}fo_y;FoċC Â'L %Ё?؃l $:]$;vEM[rkO`gHV 4ܩcTlݺucmڵ^۵ 3D$6l/֮]c[FZ駣raԩ`gb V\/Yc_jUtx@&?i1sɢEgN9[nj=A T'x K.p@MG'OλӷumN$MAy>N:S?;FNF|~z'ijNÚ#eHVSmOhުUzuwX sr-֩slzzƍ솔XH+PS5h8$2]$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$@rEHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@i))isJ5mpK>?PT+@2ٱYg+;q-LnY2ZDZ7/V8,& cn64wZi.M$kJ_ɝ^7wyuóJS_K/,޸7SN:PvbGoyr_^Dr%BpFq=ڶL-Żxi5 Y]n>ue4v.(.yD[0s%+{Ԭ}J+-{/߼ ~o?e*91+E6 =DY1wv\3z!eԣٵ{uyo6 eԴҖ?7$ˎ'Ί {n *[KiP20Qmmӆ]ؐp rZa/V9)ҳ>:wڬmPsJIҐaOϺm %Eavs[4jۀɉ:-xh.^҆ ߼^%;άj *3|f~{j`˳8.5miਾ[H<{aouiaz5jD2Niob늊Nsu)is ֆݑx[ ~ fM.]Cle ^*W0?슂iQά{hɎҳrUK~)7/TӦ8x'.z!̝Vm'"ZSuX|ۓ>xֲp n1RfvGnۓ4=kؐ(ihPgJo*AϬC]ڀpԸ(?wwm˝U6[͜ f6-ݶ׍ɾm\e]6+;v nvEi4unެyÚWakYy.>8ᾜwL}JB+Ɯ;gV&@9Cf,'̙vξD)Xlκ⥢G{`T԰Kr1fۼï.IDATx{Wgy[ Ge9+68ᙥ#+3_c Fee;V̲|ڐ[#ivy1f}9usˎoxkZZˏ넰~;kYqo7ktﴰ<7-ڷ!i[7 iJWַM[É;Un羉)|d\zVN} \{̞PIU[`A*);,yMzpRh%g~fbz㷟 Ьqgyk}K6mM|j\>)f {Pjk>|~7n֬)}.W[H&}S.h/5G n.G7 "ٻHݻ/W?, $Z!LR4Wm5Po HHIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@6#W@kаqyt$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$>"9L? ?UCi~'ЦI'RbXW;;|Q#|۷ X@S5,*~y㐝Aׯz˭z0g[=VZ^sCow}î5"@TFŪ/Xfg1ajËUVyh _=O\2:'[.5"@͔`jsm׶Þv |ͳΊ{y昧LII ;OD ɧ.G)##[Қ>W_0a3W_}u|-v8wU+"$7^W>ߛ>$@Kܗ|dzus׎#soHӧ3n 5Rua*ۛ7mFS~.8[gx=o_y%P $RDrO>CwOrh!-ۆo'W#m7#a|:)ş-yoF7k)IJǭ'{Z&rЪeM&Wx_c^"~k1?~[rtWcڳkT]5kVTzG7vn>CJ v#qߟ[=uϘн߄S.Hbӧ*Sg;wW,`eu3~y?kvԞ%liKaؼlyM;2y`-V ;=vg٤k^i2[6LM׌ 'e;c%)ɲbS>]~v>6.qoqH Ǝ<oc/F=)cˬno.v86* w.GqErg}:n삭m`lhɶέ+h%Xέwh,A{bqT}wo/MVk_-~6laohc-@ܥXXIOʗjm?nϽon$#ZwVmDrxĦ rL/ɽd}e1`&w٧O ~}^]rn]=[|0_*6kK*+ U\7m>m%GeTkCYO\~џ/^/5_ǜp'BaI${y;Jr,)>xKҿ"\χWBr[wƦݷ~{ۖ[> f>|[ҷ1խ)[!oPI^w=ï}{ϸa]6KC~˂7S04٬Y{nIam]H]$6moi^΂m;$+E3ͰZl܂O:؊3>rN|~{2z#oz9U=*_7vAh [n~b܉ނ+Pо}H9gpɶ'~Cf#qߦ]q;+h4X*܀{w^Y!.{UԑtK oݮOxyS;"9o-6N|bbTsYj "O;x|Ŷ1qs_I$naGEQuפlgqyS߻ =??+ w$!%iY6n8!+׭9?~HVpa(5*V}|gGՔS{+^W=g՗s;gfWk4ljD"׭k׫zeT~`yǝ s͉_kHBut:f|m=NrB*6ko̎9e33_}97*]$*]Pnq.&xŗk?'^rzOuT { @MS]$?K"^rЁك.՘.@͔ɸիWLƛo؃uڷ}?~zjĎHJDj#" $!I HIHDHB"@$D$$$" $!I Hg.`#W$gHP)Dbkbei":U08hgbOm:C*R OIDAT4gH]0 '*#m˹Gm&mo_uV=9gA"@H$" D$A"@$-H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$AoQ)j ᡋ$AHm*[i[W Wl VEDrgO[CUq,<ڦGV4Ǔ {ͱw5Uϲ=[*b,(mسunquK Yv7xKUlӷcusN_V1x9XqUC[0܏Z]VgmwTVzFoY(ԗ.ݵg3 :Z{m5{׾weqEN7Szn-L|ׂomyyn؟e,|wsW_3ΎOQW>ƍ{|Ӌ x{hxE?yEkޑ:zk.:iВ;[RXU'Iͤxpێ7yw9ɿM[_Rs4u2iK}9~i7$,s|Q=ncՕyɩahEO+-*MKJ≧xb_X) =+:jn{pŜؖ[>Y ۍ쨫ZGUv5U-U4 ,omOkb)!̩1Vݞ XvWg7^:)Uoo)KKC~9w%la؟e4/HRPە-iL5̓O\wsbReCMP;sOO RO_Ttsgw]-նwd&,4BD)}}.~~)i)}ub:vbE}Ž\=`M[8']_W'uM}颰~|fT+mx^ k{d#=ã +K喖*@ĝ-uűXn΀Һ-:g7XuC&܍BrZU̲tF򹮮i/{~g>!- McNYp{{w>H|ӶԶ Č![H ٴ2 sg_#ɂtFoKK{|߹[!+{{kaEk~yG"m۶=xŔOo]kiio!yi}pw2Dx{KTTMCOZsy6Bƺڶv]Sw_8Dm ߌ[*;#rvYt֧f4\S6 TCڍ"4MZ Q2Aۥ͕@s[- wvTM$ IA, 홝ξ{VY8m;#҆a[H%Ʈx旊7,X:)<ݿkS_ 7'''@VI$#w7^~󕭻eT/X=RMuŻڪF@|~}i>wuԴ1,R1nT2eұ~:b3ozv7L 9wnk""P4u^`GCY#GJd /nom]Q9mvys.ZѺb~*7򦞽w4%MP^Y/).dW뿞4eZ֭;GԷmY)ɯ\yŊ{|z|$Y@]$VXbkwmAୱ*nZH=]$4&ޞ~/okjp҆jh=񶚊{C纪?iltuN}]q`ɮySѽ+:KQG]lĪZTONZ=! H7G_- QN"21D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@ |v pt"HD I D$"HD I D$"HD I D$"HD I D$"HD#1"Y~6llYm`Ht#߹>S\nEN"rWwg?ooo3_ZviAۓ p D$A"@H$" D6-(]F]۹ݣ+Ywe+w-i,ްtv{0xvz}o9}Js aL_s[ѩ,|dk;*Bv&Rµ{fґDǪwt^ abCԜ8V+B !{ H1;{֬6lC=Rm&ͪ9w5,]Rv[tcےI_ kt|}vI{!B\F8K$/m|;V_^w?:tGy}>Hk=u_KW\D#_^RSR2k:? }=s>髿_=@]$rQ~9y%CMbOoߕ=qӬŪy貕 }ILrVk;^>y-\{eYmֆQ_O>uw׷7\p?n폏9aiɤxizX6Qђ3oըo^|d|y钱7GPxs˗~o7>Y3gf/.D֦~1u v<n^Dӱ7/)Y>b;t0x)̇Kkhˢ7 WZV`S8CXIDAT>.4suV Q9õ|᠌|:ho?쌐=_eǛoy9O=T:`uQa<|l^Ce„ M裏N[<ӟ"#NQaa9gg?Y D$D3<3Sl EG3# E?"y岺}]K#pG$1yxHnSL E>m~LHMGbDmpdHqH#Noooՙz> D$,o.۞ O>ӟT(<,G}4Swo E"G~˾-[2kYZ rĐ=yю<608gqiyYwGkڰ'zm8s>w Ҳ8"k?쳁yq-fͥlH.[ٳfUU~ ?c/"cǎs?ϻ_?SNZx "D]<)W7 #"g3%߽҅_I$`(<ꨣV|S\, %g^=Kuˮ^.*,\y{O?]zw~Lty%{]rMW}݃'t>pwŮ W=qS~U/6rkƍ]󡲉Dcgg"ZY}pUrf˚Xf ->iӂb5Ί;vseµۏN/Cyp0/"t_|zr]kU˿ϜS~w;W8܉{S꺖xcM,W-4#]tFN',m iAiɤ%3kb\Fco=/^7KњGHN<{c oU[S-+7-6N\xӬ'7`%%ןX>;,$^k_SRSR_2dQrqgt6n|:D"/n|;VixMYW/_- ?pXŗr%9X|:^ KR»&־nĚ!}vTFˢ%vИEjkgO_o"-#!N+W?жK֭ƴmDձ Lwg}* B㼽N|a3#WzĚkcOhQ>p:yߺ7|sE-gcǎѕɷ˪ĊdUBt_;7| ݿ 3^O“O[^Ϛ933/~qH$DTp9W_"]a]7dy|e KJm#F6-(]^79_{ӒI_ +pbпrbTO}>IJvnLO9_.[!Õ%9%bm2n=S;*ƙ8d"Y "oY:YoO D$8E眝d](<8L+@M yfH&@qɒpȇ?)x(EHukO2eJ(<m~LHMGJD 6<D.Gի3}.@HY|/]X׷=Y|?Q$"ydYͥ /l۶-p }3@eqDr.g㎫[͚K/ u\Z߻-0:gͪB>18d_Drǎ"sw׿~iN:@E$ė/x y̙߿X,-SGI$CN0μ9׿u>DŽ Y&eAۭmg򑹹zp)"'2gϝ:5 #"]]]3 wn \VwղB6E${{{3Ō3?M߽RG>x|gw!Z< olH淿M<̩K}%\Ɵ;w\sGO1y$=?LSOeSDrL"H)"9e? Ȧٟ)EEw/taWDJ6E$:7ߔ7<7. CY_^^c<O?}zxkwpbW=|t]7MLZھ7Į\,o&Hfp@&{˖e|ncV]PAEh힑D,/ߴt1evz[:WVdYJBV_/~?ٿg.׵&_!c ;f_;eUXp`ef՛.Z70JP|r(zw~q)+#'OG~{K}x-\HnHFRZ'VG־(=aEɷk::peA˺xK:+KJrJJfqbM󃢐wصPv&Op3ӫsaK_hwd=H%O+@9=?y%WPM)W.jY]F.;kN K6[5ov!,K7}L5''w WC.|~eEK>@eyIQfy92{v^Ϛ7yn?I D$"HD ~w;(\g!"ɘ]5b*I5؂IDATI rĐ=ny.@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@$-H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@Mv&RZ%>{jQ;jV4?9./*n @MG[uĪ$ H*㉴+ #+f!Vf.+[=[iCr+e*XZspˉ-UmXUaضy޻V4MhɢT`qb_[UͩjڊpXƊkZڗ7 ҈dwCqNNNqCwEe3B-du^+˛;2$_\\VSz{zek{m!>̲-2"֘j't$!Bܼ4V47M>颰(D$WIx˨V75_>o7wR嚑Hm=v7VSWy a<-+kY:WS[1fzn}ǦsgzN"YٚHںp 򪶾ù~VmCHƛ+srK4LKM)/iśCWbW-k0w'*[?%=5#0vHɮMCv%t✜} esW'w y56HťU0fr []?xgqznB*?ֶL]uyժVeu>rלcw&]v}elHdS8+">gnv~go?eSD_bRV0aBg/l}]6 d]y>ƪsJJү+xRشk۶mlHvuueSgz/]TRRt .7ٹ'wNە h~t̤LĦMlHffv'P\pBg>zR8EX5a„i{{12zwAΞ5 ˆ>:@ JO az>_^P^l8[;ז} U~ܳO孷/_<*(S8屟=,~Em7'_;j>;&N z HNѭ|)% b(?!yΟzysS{k3w?6s'U0pyJ_=κ>qV_{=-H}=Ȧ~&_mND9Nk/8a`ÎF޳la_}|+]nYl:hU8|Ϊ>;랻)9!}8vە%sH!~-7W92y飴lņKrο'F[6mؔQ6=}z/?C&"yQ.:ax.sv7~} wnS//Y{mrGJ.όt%r{/hq :? ֧^ ?O.iΚMSOm'Uw>eʔrYAώ~/}g?ϓ'rS, kYs,DCN"rW߻_CT?o863@IDATؼ[G$^}?L~䑐{[/|KyiqOD/##D$&"HD I D$"HD I D$"HD I D$"HD I D$I$ Zt"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$0\"7gږwņ\[ն-l]\^փi-+߳*?'V֗ywYqjB88zecJvucX2z70[w73u-l߳xe3OYz{轫#f#= 0~UL$Ā\:#5qqi`bi}<3{mt_CS|3K(L_:h[/57&xpێ◟^sQ]3vʳAv̍շ,~>M"7W\Jn}ܢ{ p{y+kbEM]ot5xt16^|i,'Uez:vu tLnޫs+j/”K2t7Eef^G|`|;deYloh$$Tr+/khhqK*.*-(-Ku 7VT7uu-o'ikܜ| j:D_HG~`|;dwS J^Z[BnU`9{(;[jK fޒNYN[qMk礋xɏ64w9ISo c3AE$wuՖ,:xMLt1: 5 dܲxjN19e-{SW<^[׺Xuӷ3ez{oYOcb }0"nlLM϶xKtqRmmړ} MQ~I>P9عE5m6޶rNI/Y=^+ Y ڞ4eZmo n$$s73ˌn:Xbk"G' :+.onLx֥%7/,iɷi5a$c|`\CD2Ӎ1cgtΊ ύsMM]#wlg~^޾SjNkĪ*׷uߦ+]srrNlYq Hags,eOO64`XUKNJi?YV߿w54Tgikܜ|YqE$w4ݗ.&]ZSlnURŮ3,msNy){5{U7u"wuՕeS[Urps抂/޷k)k+b[zrxܳ؂Ճn/ }#OƲ{Á]ͼwL2eW,OD^ȫ\)=>iʴsyzGO&< 0΍E KM #" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@ |by]$"HD I D$"HD I D$"HD I D$"HDٻ*;_ߠ%ϑM8V(D1"JVX7-vZ ̬!2ԙuBʱiKXLim%^z/XP5ZVm9rѳg_ w~x^yb{}?$" D$A"@e|DrēO>/ʎ;B?=g5yi]6`вx{v ǶoןZK/>{ucػN0/^n-C7| ů\GҨQn^/~'tR#1SNN7xcwޙgM_} wC~AYg ʋlirWݱ;_8ðѿ$ǎ H&54/ T[uƻJ}P= C'" qbT([sOw>laٷV 9I2!_K'[~!R?8g Ӯnw plnnN7ο'/2%k)M[}yϾm;1d;w.4|^^ hޤϾsЇ#mO>u%煁ھ&6{YkW,XpѶd_Z9vҬV.`mEjaYkRfx[qlº];kٶ~()l xt:2t8~^!.[fwN;;Ea֍.L;5ٓ\4f?ka:wۺu֔Z ۖZXp慁3:ɤBCS|{g<1LZ;aٝ <z$!ro];//ј6ۖM,=%ׯMhE=V7pv9Z6k`dw]߹M8Ɩ[Ν|nɘcJ*yPECW-;+ym]-=eUjvj;O٫ܹ%;в%7no~݅6IDAT:շL*}g]T됌B.|8pqR f{)"ݝŸSƗM.^aҬ)S:vMȜqC&ھ_!#ܦS:%OtXi¬T+J^XpJ1Y:<3iƊVyf-d^eQh{]Cõ+K4Ȯ}3dRDNX+?Պz5) ձL)[2W~tw @2vZ-K׿nO8៾Oi7=ϟ/lM_.?aQhDE$./g7u_^+ ./|S'i~y6'}GOtw^ZX aD$8NF[*=:H=oGI>3nMx_#Qs7V~c8gT.T89EcGG$S[woCD]>mZYJ?v'm";2;"1EDclj rD$"HD I D$"HD I D$"HD I D$"HD I xH$" D$A"@H zD$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"hTC eYn %c+*_sX`,gP@np ""Y.uy~:tǺ99ezt-Iڻc9c;URӞPPێݺF:w/mch"9&`A}dڶpB ֦'u4egee5tXDy}No.*N+$10,,/9%}LNN;0Q./=nWj˜di抾5ڜڼ--hJ-!PvqmGWT[঺^f.( ZݬзÑ[qՍyQ蘾˷֕A)]uy~ՑHCޭK0,GUH2,"J_А,VPuo>#dW??O6/Ї^VVV:I˨Q|d²o=G&''qۥ+M_L:EIj=wQ2,߾lޒhOgN80DNdRp]C|1o=s =_:鿜ho#`dRG?~0ݸbg}Vp&NvtItKh5)Sbkݶfn5m  '̱stcҥ;> o^%1~~ v>Ν 9SNӦ=䓡_]r^H^anh:g}ٔuƶYSN.`msg/ږnE054cEEK=uo+lwJ_@˼z&^41hoo'/W ǡL*=Ty=/nܸuqn*1HW_1#g-|tEE_ޞʽuɉ̭NV^_6e}V,t}ޫcFȤBC2b0D+6&ώZqjȵS"͞ǜ~[;3u^dWhԒn77n CT}Y&>3Ӎ-[;=wM[KmˊlX4kʔ!Lpiu 6tl;߭Һ33.#' m_pA/~ːHÑ7._;{֔t۾&6{Y:?cۊf-k](۽OVa#]xaFNV<u`]aXYy54\D#k9#d?ẉ؝hWSKIDATXTh{UWM?t,-]W3#ەUeFN&E$O8˾n?_jX_Y'߹"+++#'" OL]_ }M_.Uٽ+ )eo1Ag}yG(`e'OUO6oĿOK }! }:ulubiKo =}'x23nMx« 5H5w~c嗿/?LgQ|SI2ZG$S[woC&|ڴҏ~캓O>9D$h "GD I D$"HD I D$"HD I D$"HD I D$"(+hq$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H4jP:k* rdɉU45deմ^[5xXQC7kMye9Fǔ5;餳2}LImexO mG$kKrN;ڼsg} &̺kg54îsl^[̃pU7a2@D,v;7m}mo'Ǽ}uun{wlZ9gls]Jz;$ӣ{ƞ{Զo]}tUAŖꪧ/o}C,g2'~#5%v%RS^=&?&;V\Q#؏19 Uն6a_muTo'fuwvGem?C>{i'"-շ>]R[;|8rzkzqAPAaa껵鰺kO5F/j_[_.CU5{Ӈs/IdK}}K*{ H&70UuF~[TS<]@ \:۱zvwq|W<)plknM} ˾Ueo|(y5< ݡ fuWebzvW%UN IhԐf7Ud&yu:N>}•7եfn->$Z 9%\ښr]++:f_RYQz7C<)p4 -"9|W65Vz&Z suUS^1'V]N9 >}]zk?=}8қޟ8H9=m]it]c]){3.M4t4k_muX#)OtoV +꬞[qkЏAM IdQwccs1y-O-YyE= VT?k{%ƺgT쁎lK~8H)(MyGyu/q%' וMw=vcaY}ŖT됿|kP/,IPuM{/{,Xr~U r{IBūjRIn^41V^֑>Fq_GK}y[Z e6|: +k55RTǧ{=`AMʂ0OCoO }Yx -5E7>?hXUQ[wwSՅ]UJU߾+Ts}ޡ+{w0}{91!}si/K`ČhB} ?]dqFw7y՛^Ԕ Xuϓ1kS$2ω rD$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I Hٽ+yשcEN"HD I D$"HD I D$"HD I D$"HD I D$"HDHx{W^ٱcG8z6~g]x_̚U<1 x{v ǶoןZK/ 'ٿѣGcػN(nJ7ʡқoW7;֬"yiw ut0;CW?̳SOn/?by8cKxi['~Dw߽뚒9aXt{m[*O?:"e'jȂiUV3S䜵.[lO\tх{BFޚ{54e ˾ķ|!.{3$޿'@fE$z_J'^4qŁwXtŗ^ทIu ꫉1o}Ԩ ;ȹleWt{2яL7}Ygᆿ!شyǎolnnN7ο'/2%kNɚaYgwGnIɝ;w.4ܐ^^|rCyf5je;vb8bN9-{OēO~wya cm_NX-^.KvX m>?9KkUն_O;Iz5?nH|°v{U e)CV7E*?߸1幉l歍o\QB…u3V$&pŚŷmLO~.n5wMy-,Oe"+f7ٺ8kb%2[(ݶ2URϯ4zS$߶e[0cݼthr|X g65%sșn IDATZyM73|s=mmazw]_M8Ɩ[Ν|nq>8}d*X6 :ׇ_n^O8K]RT5 " myƖ-a۫k~rNܾxٶ0l#UZ7uQ3.- m_pA/~ːHC4~^Ƽ)2zE)uk&+\o]+6EV$5%,_¶e>,'wbAf-|`mo[b϶CvL\tQ[&E$ȿDsF7֦Z+ncA޼yWz;7ޖnT24ky:mI7Ǎs$ǻL*=㪫&bF:.a׶ ?_-ݾy2)"y ',_tǟjW/2%+,ۊC6RzK:0ze92)"piϤ۵+j{u/Oڎw~"ܷwߊ_)c+!2M쩧}vSW|䊂 &_6y8rMoz|?|Vѵon~ܜ/7] {DEŕ-T>r윕{^̒>*gOO}?َy kRwwx's];Iy1fv흪=}lהm} ߈d29=mUccM/,OFE%=CfXQ^p򚣒W[>nW m5Se]i2 dAC/uǖk/eI/5V_PFm[;0Y8;b'ctVdNyէS]1k'gɉUjhnc .1U;.U;q/%5Md,VѰ2udkժC^,՟lp:qӬ }rV c׃&ūVLv}a7S%笪)>b.d~"mM0]~Yqog ;낢To[ss'Ɋ%%E jh Sxkmiw]kuM\9TTغKvquK| ?g3';8uM%y͍ yeaNU-mﶖtur\v)o<9dQat e]ib[[ۡ=MOw.y!ޏof_~cSsNtAae;,HqŇ.eAG}EөuFR^Y%mwUl.c[1,/ Ǿ򜬬drC4i8olkX|on:l7KiAǜtF'=\NqY쬮ʎy9 [h4YFzWݬXquc{:(oVݮD{limU JV5ko.ʻnrC&[WuDҸ(C̩h Cfdc󢉱[i)ϛhsbU g4L|=vcQyMs[GM5TܚNl.)l輙\gtP1|UAOZXq`K.`Ւ_wM,y/wPYBxqqK8e~'ז\ކo^T]}VoiSuQfݵUn~0qN 1 eݱǎKxMgl_Kܘxļs͵%9U ni='d s!>v`*.]}/ Whv4.(H%!0n=eG:9SV߾uK'56m陏ףM.M/u~S\Ӷ7OZƎ˟^zlڱ0 OvaUV8q+3Z{Âؘ0l9qtf*=$7yj,yEʟhaqLlAc?=މO;uUmɿS/}~❿. @zIDAT!:t]80\#c'"hTe9YYY ur=Hq$AYx<DS$"HD I D$"HD I D$"HD I D$"HD I D$"HD I Hٽ+q] DS$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$OrZ)}⑐ 1QHpڎ7^U!3޴{Hnu84]y.csɞI|^Dw~/3ȍ3SO/<2VnKٽCzm߸sfbmwzL۲! !tw~t×_x#ykɫ󫪏~>s?7~sə?oϽszk^{JſJO~$Lm҆[/8?yp[2Y7ҿ>||[.~>yߵ:vv% S4"/.|G>|Iܛ{ӽ=G6nV=s{?[u-ιWܔ'%{;ݷ6|9U>-k:E~9y/9?}ZwgyoFB4"̆7^I=_HRvٸe_́`#kOvo0Xw|d[/k$Ot-OgClȈHCZ>O2Ɏ6֋/8-9w<< rˆ_W}_/gB_ݒ`Dd^2#sUX~tHGn Gw㏬&=ԱK}xa'o=̜ziev_;/3+>[}ޝ>'25iSMyh\~Cuy7zFpW~'N;Qo_/ʫ.OlL>&'fnj|';6;7sN<1OD$"&<;wOzk)z뵇/՛ ?7م0m/TOƏEƝ8b߿My7L޽;p[ӗ3 5}{]4 Ix뭷zZZӗ'?D$"& m~{]^~%08ggϽfΥ//_|I|ճ#I;餓>Y^{ ѕa'\ƞ=޷u˯6m10B7=n\XP=\1syߕEKN ѕIm/}bY6>0ӯndeeݻ/0uWM3θl3#rϐ{س{W8<ݼD .+2ziفx㐞~?=N;- K2A/*#(Ա91d::4sv`o-cN*Dت #$8G5B mP[jEZ.:c"V RTv Q(1V%f-q#`]hޓI{?9;sνH?"y-1wto֭llfg }6lO?v͞'Գ'ڮT[&GUFs撊r2rb`Ox=y[Ȯ]wGe+{`mLm>eڌQ1A}dzٕnvle[oU"@ JsLg 4H<:u<4Z3iJH8N9WFe̿OXtݰŰ7̾.,Ngm٣C]딹6h}na+WG㇇Sz3n! U=gWcC]o=q3&WlNY8<\?3-?e/gH~\)}o>_~Qō˷&.7Ʒ7XT5޻!Iж$T~}HsErwXt9$xSrξ)ퟕ Uj^WKX7^Cb#$GUfn:;甹ޘ8O=}LE}n_1}l~gQ/6xOyW~uͪJp&_ Hu{p~&SU%̽Ӕpg6I$؞8ak>=7k௣Vl=}&2ћ8szzw6'5SpcB}ŦYV~c򑱯j'a)gO (Kmwb)}<3o^]Gտw}ҹuYϞrSc lsÎr+q/΢VHdl6wФKʫ*QpVVVYY 7P]| pZwj2w֬)/~ʕ.J<)g2wwᢩ}5ǛstۉdMؓfG7AҴo͛ܦ5iuqNF⠨i]5]mVwطU]"ܹow,Z&v]8n3 9|ˍ~D>޹ۛ߻n?dY7~R{cZ2u6lXƍ.XpShڥG-z»˷,ΔՉb ۖyެ߼p`G4lZ0Zi2pxߦVͣ>l{JNNFNdHUUɷIߩ`|m~5"+'D[nO>SθxnրNu弪N^xQkx'>6kEʖ~UĮijmz'Zئ&䋿P s/Ψk9d`^S]>EW9{IDAT@JdVVVFFFأ)xYS)_>3[57֘6q 9 Kw4͑'"\T0f^8ɦYOiȋΐS&ro8oӚyͻ.ڷ֟ȕ7=MOjVG!;^T-ۥIشS}UwD3ݬ̜#h{xm 7clü.KCÞV8+fg\; |~Fuon7Q#9s=zhf-_Bu#E =TG!xGr`E5^$>m=bEfu'ހ)s?B]ZpFEϰ~;7m|~GlT/zsT}$Ήɝ'}EޔC3soۅhw3?ȝ@ :֙~OY m'?qw[6=I#ħ.ćs/މ#)o9E+.7Ƨ)%qVU3gL[tI֮]m9pO&9tv'wrQmnS{W?"fd"}VO// EoliU/rɫՖiܢݔN5^|MRRW-K|+BrBf./1.LiOlޕvyhk@EEϿ:W]3Ctimvl;Pc s/j5:SEbM9{;O&>unj¾h7zMI 80<.߯5W_|74‚_͎]9N˨+Ni`"w,(\]y.4ȉxkx4{b֦F_&j͍bX1.<;cmINˢo?QPr?SjٓyM߾΍VG~5? Lm7-2jԴ+A$~ zulF ".7Ͷw_3z! [Ld; ߻=OLLVm)$#KH&=6nxq]~Xݭ[קdu>2Ì":)#_Z/}ʩ˖-՝;g-yqaƍn{I.&چfNcQ>YfレHRFm)M6+V=xn-؋Ķ`'M13Zj;Go?aYt)7̽8#'ӔKvv3sMMEW ul,?Y9;d[oճwQq'ݩퟥT'fNJEUo:/gI%5kDEO=+Skּ}H3z;Ef Ԧ:|%O!֭_}t=<̭$9>{Jd@kM\ szvW-[ڶ}ڱH]+VEE۶m{؞'(6VWMC{K- %KFE]$,_{Q}׿v'Cu_+.]nJR?d;-)H}Ͽh 6zO6m ev}bkwzboӣ߿3/"YXN{ra? O?o`=#t]XQQH9_|~0lu:#N?g$_Dm'Ԇ sq6jO>ס/=qwN==׌ٸqc +_NQȫFEoZwlY'/nnH̸xu7m4#?q6loVZlSvzGŖ6mZ: SׯaXdCs!_mw=VT@ofQ.쫾_XPTIR~p'ԫgKaÆs|E[տɽOիgnݚ6mH}_?),{; ݤI@kѪM $eQF'=g{7YՁ/[ӦM{?hˣsĖXqJ>̛HegwG>(c=tw֬Y4jԨ怌-###oܸ1hѢŃ3_RA8/[}1{}N%D۰O[ja3b˳A$e}N>ys{Nͷ{TџXtY8N91G`fm#" ;[^Ϗ>6kG Iwoذ!V|oCڷD$RL7Wlذlɿ<#zH;-{j -;O.Iy^Q]Xݸqc mڴiSO?lqzdÿػ2***jy[ThÿC9@Z*~n % ò3_`עU@ i]ӿ_nm|EEǟ|d7VՌHbEux第Ahp :yg}qL *##z rn֭-xbW5>v68|[>,HC.·~{ʷZlHW>ÿ/UFEEE;>p]ѢU@ EHA"@ R$D$$" I H)HDHA"@ R$D$$" I H)HDHA " I H)HDHA"@ R$D$$" I H)HDHA"@ R$D$$" I H)HDHA"@ R$D$$" I 5 _ɽ222z/oC2"C 6d٬x~raY? >aUTL uhD۟ۥmFm&]YCgl6d!]Wo־²mzE8j[j?Aڐ\׵}K7z-/eͪOe|u蹫\\;tS*7+}귗vH^篭%kf;{W6.%k>nΑ3FIDATVGtL|z!]f;}OXk퓊O>ۜ|֓&alϊ;7;랺ȮeʏU}X+*~j\L!ջ ۱pHZ2ϿoQ}ѯ]lӚ2pmyg}ŷ'؆%#$RoDr~#es+6kۥ_%# =V;esGmai?6x+[VvҾY nM8ml3xYúmw 0fY2V87)Qi*+nxl߾HehtmU^zaMPOD2Kğsז$\;4Q꒵Ǧͪsg%ߥK ݪKD0nz/;? EKSc?4|X֍Xhs~[Xkg|baլLf 3gC I.vky8uĐz';~6?Mߥ_QoOXf=0~ɋ>]=7owǷ+3g]>w322ڏv\y|X2.f-_[y)u%UO2?omw|Z8,o~T<:W:rc~gCckwҭz35w.+[:ji/ߥۘm`h{͹s&55 c4M[Ьe+ɩUG6O;\OV ;m?j8v)g^sߢVV#T.;9/MrD$(g ie;fzH!VNI eTTTԢ$D$$" I H)HDHA"@ R$D$$" I H)HDHA"@ R$D$$" :#.{KVm.@ R$D$$" I H)HDHA"@ R$D$$" I H)HDHA"@ RPG$_W_{};|}Q=#{zU>llh۶m3;u:G@Ikpm|vmliۦM -5 ɬ}v:ڹs -eTTTԺׅdʷ^{N_=mj@ի}n]qC>E+fvH~gowL8oWwo>lWQq;~֭6[m?'s;n;oC@J˨u ;eQ;~MȏF[b{_C>莇w<Ú5oHi~}c+/1iFˆ_-Z >46@]vۍ1^F͎9*yޙsz횕kb<:_:@i믿1zبڧe#Y3%<+@EHz7|sTlr_i@zk}@'G|>4{Wʾ66{HFEEE;>p])-[֯ѽ{s[Qѩ _e?Y_XѸqeoi&Z7Lmwxh*sF6_keS2򦖅}C،elaYWyHB*7bZn+>9L2E$hڧk]cӁyUxn-*=<;oVڎ'WMIJӁة(pEIIEwfo502Z?db 썄![HC='.nO CDHnk֬N:1FLBFto[Q6!7h*JJF+E74O,'ƏӡYae]Ly _|Qx?*sHe@Q~a/}ޕ5H3MӲu۝{J>̛WQ{n/:s7V [v={zexUS P;j׬d+gZQmrqլ-ᨇ_{78r'NL/-=x7{b'{bC2yZ쵖oy'2xbIBGN(jhG82*fvܮ2=N9_x\OwxmQ#+H6Q65ݯdҗijzE ^* B/l1dbY۝%%zq"V8n/${ &g^5_<}Xe]0(EJxʯ(R>p\~È:~*?>]顋f\44b0z"%Y1.$Gy#Ճk  ?\PϜׅcsVl|Bdh՛ [L^zT3({SװW^9#{9IDATs ;?;;zء*7XtI֮]_ܙ>[쇛7oHoEHa;vi}/gE?0{ n>ůYYى?s00/3^fe!99ySj;Wf|E!sԊGE#԰xE!w}1|hh #GIS7sZ^*UoFz04wbg٢e|N^4*ڷkWטا;y>9gR>qGѿ_kg{tR ο&" s5kwN~_YݻFv"!xF2BC$"Es@'_BѬ٢㱿 2uwģEWT(}Eі9ۿ'_.~Dq(h|;{#U'cG%N8`B.wDU7~0-"ۊg7C*UHf lȳ޽{]c3ͨO?C}9^rIȣNQW?\vJSiDQamH׌3_Ŋƍ/yqaYێY~?󌌌IEz~gC/p]= wU|Rw)*>Gy%Ӷ'^웗ŊMVZm;W_qB/"V_q2$׹).[,Vw#/ȶ_-Z >H_9V|LR֭[_0XQQQqy׮}w {҂ea([F].㷟|wc /Vk>2{~#8"y @kԨNiڴi^iLDw5kS>?5?+־꼫?aZPQ04+)߸sFGyك:kkfEEed%;ߙQ=GiLDا<Ĩ(++_~}cկNŧ_tG~H`)S20e9GxhLi۶k{իWGuO @F/Z8ƚ}qۼyO>$Vy֭[:ewXu1iF3zv;۱'_ 9Ύ—%e~K^>rON{j]GY&*5kv1G UY\Z\5jD 1wzo3(if;u˸֭[|h/5UFFur1~Tqi [׮QQ)#v":ӬYشG3:G1^4Ǝ>[|7N_TDEӦMB i3.x~iyN {Πػ#Hy$~wt%" @zmB~T\5jD u%SDrڌQ1An\[L I =_z @Y:=H{"@Jy/OwL8oWwo>}[ƕSmܸS>g[Ή>a7l&MR.k_ZT,/]~7Nk#FWzGw]vg?ױѬyr-gwfk^f'O>Η֣,Y۵ mݻFeG$_cFu>]/.b?.'^y5o:rʈd)GDם}Y7˖_n;ƛo[1+mHoh$4ocuITץW4$3xb45v̼a=,7N{~C(] ; ^;pNЬa͏4ۑ;Qe5ꛗ5$7-OΥ\eq$$oתU;n^waA&oڸi{]Z23ˋBv ɿi7yAJU+W YKbCdp?kwݯXdNSBҢޣ?7ȌO`=`_ũG=adc{O):e-)3khAЪV\\*CܸacTpOճg6mi "ڴisfnnlyW x0南yF:rLf(*O #Bm+Y]CL#Ý$b`䪡# JFy=S*/cz,T_Q_,]8w̓k̝_S뽣D>2buJ=Ȱ$xG7O׎ dh`[tpTeeEs00/>u!o?w^0L> HI?+־꼫?aZPQ04+)߸sFGyك:k I }_rDO8A^S86'#elasp]6!?*5"liwգO<=ؓJR?sɳKb/\}䈟 l6*>Z6$DvdHqbed\7vk@YdiS-VkWKCؽiNPcF?8dgGЃGBZtiTo.ƒ)" ]g,\@9Awŧdi,&Y '])!yh`j %|(}Z6!?*5")"9m̨r[k{.9ibFFF %SDr[o \zKKՑ#~rR^fmUs͟|sVo3oҥ\{  #/,Xp񏆿4pЁ(@B F$7lp/5"Ngs{NTI'|rZhm6?;Ν;gqDCJE$+**'׾}F!?),ˆ9Rƍ~Qݭ[[Ǐ FdH>gP={>oNJf͚5JIdֳw#FYaRgŋGʼn'ͷw׍31$ԉHY&*zxB[D$}ィ8 QqըԕLi3fFŐsmzڱRG?Ga~~ 4 c[oEK{>XlY[2E$׭[רXTD]D$}bk֬ @Kdg٥Kx~0ŠԉH6n Gg1HW9OeQ}=N⋋@jZt99[/gTޕw ͤTD2f-wKKO{9>nV2cMSQR_y9=h=}LJqJr{?h9sbKH|f޼198juѕ7n2Enlxl7-uwrkC?>'!պHƴh n׾6̽8cxu슒xrФOԣKӰצRJEEŪU_3.8[_lPܫF@JKsEKC_~٥_~?wmטb ]~6n &ߢE /[@y&hvExn%ov90̝wǢЧB]31@(}7xce'MZv_|qg?ln޼y Di64oV]Mx]H1Gѿ_kg{tR ο&" ]!l{qFNN|x}&nxgw )C}9^rIȣNLmPC?+owìՉIߩM39 /yssm$_z˼e˖ƍ;gP^ƍvۄjԈ@J.f̌v,UL^J֨QҴiXbEYX2u\[NIT%;ߙivȣ d" b4L]$`zHYN H~_ǖ@}QQz@ XQڵ 1IRʒK}{I&" /vqݻҘ$c͚5ӦOiLD_|֮]8ӿQ밫FdH>gP:\y5=տ41###ƒ)"٩‚^vhu䈟ԫW eTTTԺ؇??7NaaƓzsQaHB-Z >Er'<3-]͕+RڙR8"‚hkHxk~ɏ; QqըԕLi3fFŐs3lÆ WCTrJ>C;s7oJ2E$Wv|'g~묅 _V۶mܹsG =D?|dNok߾}LBwFeÇ?HHOErƍ?֭ ]NDrNcovh֬Qj ԉH~Ѩ8[;sXD$/^'xbO婧^paYyyYYy t٩SNNNSO=:5kDEO@z/OwL8oWwo>R'"{E1GkF 'x[Ή65"쬛o׎{2***j>͕oEEn?+?̱4sňա#}xч5k,>7WW.)^2cҌ ~/ݧeQ;wZj}dj|p\l$~ywu>]vg?H͎9*yޙsz횕kb<:_:@iREn]beH'1ckӗMLgV7'u">Q1m5k mxQѲu3Wc-G7%~2***jBR{tߖ/}N>Hu~f*~v }ŸNJƍ,{M6 Qqըal6*>ZvGnWV؝3ֽ7sQ=gfL9Q>|dԼeaP<6#'j[ؠcVUeꪐ 4p[D~Nc4Lɕo-u 8OeQ}=N⋋-^]tkLu:0/*Om^ţ'gͪ\⪩]6Xv:p;E٣()(y̢ ±FQ+L:a❽P,[v={zexUS P;j׬d+gZQmrqլ-ᨇ_{78r'NL/-=x7{b'{bC2yZ쵖oy'2xbIBGN(jhG82*f}Ϯʪ]g*++vHmT"ӢE(u-_W6k_={;t/-gfT2{e(_bhu_ļ;[wKJ^Dp^HJ'LψjjxtywFBi%%ˇv({E9 T&r1vΩjT2Gee 9HF./tm%6nސ٣ Cffv(vl=6_EU~[mJ<;W2>sIQoU~^NFK8`#3kWخG}o\ɜܢ fV{]7ԭOedԼEaq bٮzvU&d -(/j?Y{kϰlq6nHW)8v-Z\xnڴcyee~i͑ uQHB?vAƊ7^~=PT4=>e]0(EJxʯ(R>p\~Èuxlwŧ.qESЈaꉔdŸHR^TMԇ2+2l1Iz=^QqΠM/|B-/͚5;s>m-M̯&GUF࡛hz/H.ۊ;oウVsW쿻oܨ$:8*^YJ}㲲a`^fFɚF'?xq[:$ݻFv"!xF2BC$"Es@'_BѬ٢㱿 2uwģEWT(}Eі9ۿ'_.~Dq(h|;{#U'cG%N8`B.wDU7~0-"ۊg7C*UHf lȳ޽{G]]~}.aɨu ]VA7lV,oӦMgddL*=zJNQ9ʋO,./gP$_/FDqfM֭/v~k׾3=~TfiܲG-.lhrGݱCF dtf+G$d"T7l{zAߺ:: ^-,iVc6H>_is@Ku$@I.{H˪DuE}׾)OT􋃎 5cs2rZ{:s|d̽" IWZ t g s F{/^=ģ{ѳ)ݎ=دJ s?<$/rGM?YSuG3}f}.IIH{w~{2u72>Z -tq1:o QqըajeErڌQ1Aa~?1^4Ǝ>[|7N @2sv%"G" {%Sɕoꕛ{FlSXi x0f=gPl߯_ hHA-+I H)HDHA"@ RO婧^paYyyYYy t٩SNNNSO='" ~O̊eeSO~DŽOƯuwiLDr 7no~?\uOv9q7xpӆ sը4L {ˏ=$+FͽU1xxÎ>Yf'7VrIfĶ_/yq~1>Io[`$SDSCt2IHFw|dl/4Ҭyr-gwfk^f'O>Η$fҥvM@ K. @y7F]tl|d:}ǟ||zהd#" ´3֬Yr7GE-6_ }l4$iӧ5"[x~0Š$fQ}<!ᠫ*Ϙnݺ$/{?v6!?Z)-"f̌'{٫q$9s Xs9g=lj^FԲo(S-l1*2uUHZcsF `@-c>$o+dH|h {ݓ'`hڧk]cӁyUxn-*=<;oV劢QWT<|gfQ$ F2C[w&jYatqW*W}N} ~ϯ ;h{ ݻw奥=?aÆ֬Yǝt\]c:(88QwP߸ԣlCn K2./(TE<{9D#*JJFcoh0T4/ޗߙ*]X;'}g=7A93b'`4 أODΙ[b)}<3o^aݲٛ+3e܉VfU\1=sԊY[jVAyi `bpZlzE[sKCs_Z{(*pK1u|mo.Cbw{bMnyZCʦuP^s%*V<:rBUCo=ǑQ1fƖ{jufn~wAh:II-hw[կ tzvJ_*+[.,{4d P6x`xwGVf9ʫ7*# ʻ҉vAG+_o\VV1wXs] IDATcl_<$''#ojYmʌO]70+7!v#sӄc~S>yn44rD19QE!sԊ`E#3i'8Q奱~vo21=w04wbE<kjNe-.lSپ]@[]b;ɐuL<#e͋YY!ʢمU=|g9''#'_静t€xv"X?qVsXG9Qw5d'_1~(v h|ĊUy(%'_νT6gʮrGL\tEs?{_Eq[fLQ[*ЪTG$wH3uasۄjԈ[l6*>Z6Iefv322&M͞aOxˇJ#W X2m],_x˾yYhڴ+^oժUJBkѪM`I.-J֭/v~k׾Gb4Ǐ,-[a M>~wW;vبai(H9HBR{v֙p4;_wychaI۶AE]$"'" :7|ͨ;G{G؜Eu̝'އ&^5q~$$" .0zػ~yw'NvI~W)%e~K^>rOnD$E"q"2[q1:IkBmB~T\5jDؗH^MB6cfT 9wP1szsuKKi裎eͧ@Kʷ =#),<H33(/)" @-+I H)HDHA"@ R$D$H/WH|Π&RP)緾@5_زuۖɛ+UvY%oֱ]aNo+P&GK %Df̌! AkY/[楋֟5G{|V+_${'$Sɕo-aQj8a]er[ߜ#Ir *G&nm[Uyt3D'^~ #c,y:C#,g=gU@ODžURj WUP_d|_P ՏzUg =Dۻ!{ݛ~[2(qó:Koͻޏ ;3',\ɛT߮9`P'8?w`4v܂?Sy<7p-E߭ >>~Eg:2WJEҳq܂k+@՗>e걿X֥c .|̼3,;(o6Ki/ekU=תao=]f1NᲁQK{Yhkt`eoW1~.W[~ /f^vq,X!q߂37y`PUA3_zc96j`Pj')qپ}cD$wʷzO7v\Πn֯'&RžWBqCxhaџ{ztUYYyO[>%;m{]^4r ^'CzعsV k#C)"9A_ZhQH96lӫWfj'O.^4@J{7bUf>8{o5 > .+hz=쥿FuӦM~aҾ}v9$$1~Xʫ/o~Y1Ss]Cz׫W=#t9m֭[H!3 (/zs򾳻iRIVmd\C|A=ēK.mZ>';p@H 6nS+{r/s XTe7qGbuT2QsŨܪ%+\ITfeb[+.B` %;pM><̙8x]z=rtnѼ=,,,#u毿mf[6{=)(7"rdI<ٳGǚ5m:&QwnߺuKʡS'{;s`~#ͦq/>ߦu+u3.# *HjK.v%33OoY5k `hH'd}|d#FZjroy;ԓ5 /XФ1zqȼ|d{Eb98*[n0{ȗDBŋ;v|ij޻}x|(umn5irJ ~XhЅ[V|>^v=nZ:<' G6"8"ڏHEcbMƸ̘)խ[ eǖA~x3Z3fܹsG̜PuTD$sa#FeeeI\t)2jZO7k``g:<""==]5kO>f3gVR3K]ܧEv$z3Rvʝ|kTWꤤu `PHmIJY,k׫~RhaiwYV襕Vcmj+c^ti2/Zéw?o>L T!E$Ctl=:۷_jj޻}c䥾jqi&և˞Yoxvq}\͚ֆ *< l1CM~F`h )"iogљHBB.ORSSբm%:Y澝.mġKT}uWO=wN|]h֌}S,2= m~5SMpW=‹6lT7WY GGG;;[{RJnwl$#`1;7Y egLgGG)Fˎ-"HeH)o999{mRNٔ *j׮.eR? 67jSr@c=|CBǫl\vʑ5rY K+cݺy옝mvmv}fHHVssˢfϬWndʒ2^zm۫yG6΅ ̝LLb}7wqt̿ 甐)fHܥE\+߂Μ9k/Z8lvn/D$ 5~#Ю^^R>o.~WXTo6Gfx1Ywq$xӭLl<999qRdX}Q"ӓʡ{?D~֭2`NH:` vXDNCDG )a#FF-Y)>޹Wg$S~,Zõkz?o}ꦕU7^{m[W'''-?yii9M;yx^K͚50:NM;^)&hBF2%& Q ;wiW6%sdhԨ |;233?d~w3U$O:{ 4TRy䙬5yH.]5i[}zvn )ۧIwlWvS(5l c$|e!E#)QH֗ ~wBh""QS:thzС&:ZǍ~kkBg*GǎnZ:<'v.lusC F!2a^EHG';&C@""`eX~UVι6ʰ{ckmרQoR!޺u>Tk7gfff-^\ʃ?~ʜo-QR'%%[^ӫWKP(O+OS(dBrr#ɝRSOvE@EDRWuHvi/KEtҔS\f ym+WV~Omĩg8; ѨZ!-ΕX=a^Rсmy`8ԫ[wWU}[[*ѽV n98/شVVE?8sW:u*y9w+ƤkSO|xa<;{_/;݈y{uvGDKNعnɪ o<ޣTɣ4IΝrpNceFFR\rVZ:7x gvR螉iSL$t%Whۅݽ4[jqYի{ 6[~ݢ T}||uVjZ4~0Xdƕ+RzӦN9'gg([Z2#/D$֭#zLcgnnbYԬ(VΙ,2B+ SRRZ4jHQV֋aJMobP:` iI~Rlm=uR$%jerȋHvABQonS7'5+M.kv泾p^ 4~uxv4rOv<)I-5mڰa0QHg{wl쌴ʈ瑽8cE}q|G x~ըg#}&yiffĽ4'͈q8 _Z4h ƾ檹~Md1μVgHɾ#zī;#6w(zgM̓E$ǐVDݺzCs;vv)eRYȣ.{a؈tvnѢg'HÞ^oei*o$)啚%SgϱW:\Ѹ{xt7Hez^d,X8Wv11J,^DsbAV6wBwhn/TV,.;w^Wy I{;[uIcvP}jbb"@wtøثicZXzSuNRӘdcbqwkv'ƶ q7+>;)]BRG{-Ҭ@1j}愄CF͐"aʶjMK~1=*崣^wckk펍_~nN|gEG"{-N[7eUG?\6cNkdʔ/|%/FYs{eV.& n./3}̐mcٶ7m|!6#lɋ]/^ދ:n}{5=rU3kqR4MdխSS}x~s.511wsʝlaaaY6͚5V>2 !~Ryvƾ1;&LL4fĈ8mծEV^zbf*?no;H>=reo׹DfOcg\̍^ t~ÇohQTtխS1XdryTz37ow?bѬ (nC\fM1/~xؿ{Rz~WZh7;h/J6{5u~ۤGvZݻOݴkmܢ`P~ѹy[Ξ=۷It, #yH.]v`׭ZרQY&+4n\tu%Nvm*ʕģ# ׮]+ I&:ZǍ3gvP愄Ġ@)*UumKԩSG e6GuMģ*;SN^O/@7Hܺu>Tk7gɞu9uS}|LMMXԨ^l۾kw^D$a D=}R}xq[.!1.\s& | !E$ PVE6i$@=;hc0PN:VYXZ B\Hhy˖{&$'V999:ۻ}EmTC0XaffvvmZW^]Jcǿqo3IIشyGsCz|/[[[ $_xQ-ڴn-sn޼yc-]\%'O¥l{sSkׯ]fmH6"ЦjްAs+ş*:'kt]͛jQ^8o3 0uv횴nbV?y"=/2zsfK)}2oZL w8љ9!E.RD2,"R- 6lF$u@}|d#F:hVӬ{+e~oLU_IcFaD"S~nn"..^x;v|ij޻}x|(umn5irJ "3$PPTL TT|ZXXZG?R(u,WiQS`LyXxP>D$MaꐊӫWKp@%[ 9-S-xRd24oRb5i0j.哙°iiD$M jժ|۶o4y EƳ`\Zߤ|h9ۧǕ{٣>4|kKj77Srsi$g~tC_e͚h ]vIe8rRܹsgMZ)&MٱC(7"0ݼ_{uZ_G}*' /.YWO%MҼHvNWq) y\{VAQ}awZgϞ,u|9H~W{e£//QDz2[}4;5϶Ї\.󣹥Bﭰf-UȟZn_Ęi&g$yZ+z}35; =zW?{?e;6V /$G:n=\'ܵK*PǎդKRYWO.y߱4/åTs!:U}dSgT*{/Ͻ xێ\(ns/B{QȢӓ"r|Ņ&+S'[;sUܽA$55U-vi[E]lAڸqJGWys礔N8qߐWwvʧFdUϽ k(C)ҤBu/ݱɂ"փz\Xf{SD{E:Ԑ#g3F,8}gٳrzM,>w}ᴊx\E[|Ϫ7 L_tSSm^ȍ@y6}P^ζw*S'9VTp ;*Uཻs!S3Aן[ Aw.rK҇J-,j׮^n[CU+;::&''\D{;-[{RJnwl$#`1;7YntvtbR-"~TXϪϒi`m#H¨X5+xfuݟ%`+{4]-_dAcwvA#Y:pzo܌ NZQ?+҅sT/أv}o>RU!gNt`߻G7U֜U HE5 ync-'0}zԸ)&̕ll;vV躛qs3].5oۥ~KBap}Ky\YkT/c{5ƹмc38{uS3Sцϝ3{Yd;](V?n#=&F*{$f9G~޹StEHY/Q!^mrN_9KykkHsמ+(䉗;,|kOCVާnJI)ye_q7g]Uʜ{Qha7ޛ}v¢4 82Y^vqKu-);[[unC\fMѱAxRD%cnn>jeoo{vܵy,,,{*[Wc7H4#qₚ;kE'QviEts6ib"=ٹ{>>>R׮]T{VVxm][HHL<~x\\楥4z/愄Eg8~x^;tL-~k@Rm{;[uPJժUVתUKUN-OB5Wȷ5vjO=oi5>Zno[==T59|2uw7#վƝ,-s^>Rٺe/ߞ6ȬGzuwIӻs}ub+S._B-l}{D{VZۤS rqv_WWP~;ӗ-i&N9N:R!.4e5ٰAw~[S!oV-O3gͭhՁԢSN9O:ߟ{JWn݅_WmoDV,Z1râZY!" h]>׮S7n @ܼܷkLMMUΝҐ~ʫǥL$$Ez6Pi@Eiݪ]"#,Hۧ2fs'$Uk " MsBBbbPR:u<;wj\V<͚6mذD$H^)33s]x AD@]t;F΢WO''JykeX` )"?O&D}Q]vcǏ{{uyG+HCH }z6nMt&))Y6ohnHϞO||kVts.IHp`\.]W篠6t3[nU^]K&NKEٸ77N!s--rZZQ{'I1j>jӬYS cRԢD\IZ\HLy~FyW޹}z _/ZкSkvMZ71i&Zr㇎ld(8"S'Lf[)s}}x;dM83ZCVE S! Pَ;>e4n><>\G|S7ߚ49%̐"NG PjaaiHGXֱT^EMu3@L TJED1@.^6bTVVKQzҼIח&uxDDzz$Лo۾}䩷n2Ytk׫~RhaiwYVED /"١C1׮;zjFͤe. K+&('OE}9gO###Ν;&&&d%޽q')E5N$ULn྽UV7/9!j11(PPhZ=" m:P#G W{;BEG.0m45r#UTf5j(uRRCiNH:` )"#w׭SG).Mte(]2xlؠ;o-ٹOo^jxRDS0R]zߖ}~-V}JtoŢ[>퀺VVFsNj&}W}|Nw#Et٭kG,-;*c纝?!{tչsND25:01(P " mk>t(3,--?n}H{&&&ӧM2y֭ZٳgːmC ЖiST֭Zy#IIjѨQ#"" zǧ]a>#4d*w|qyS kk"ƌF飌Y,ВdƋ$!O  UA*I"33a#ҕڹE=/"[&ء֟D2/޻}pDpQw7VG&&&u0$(;CjmogPrskqqRz?,qMtZ}}­ Gk;kjF$(CHx==pZGTu|-; 8H` }Ejw)yXxIh`?u>ztqQ /1*++箉^{i053>J רII֯HKK"$m:tjժ|۶o4yj]jZ<61ۦ uwy&=g,=SkL=eZBN4wߥ87[?ԥ{L^kr,SK'~jyk;Ѝ9!Q3dXD:êkS toxpZĔl܌^N=J^:7\|FxlFO8!g͞=Y'!dS+S)IA }sӇjv0gIw~(,XbK_ AIٳHOI R㉙7!_mP`c@TRC??Yݱ~!E$O: 9C7>Э ӝvsVjjZҶ)^3D| 9DS)!)AܻϧΦW\"ySTBn1Mc@T֞_>vȞIG#{>U^9藬܌ϑS1^],xi}׉][cj9Qٱ#P!CK)eUMЬ]^ܰazeH[m+6yY-]YquɛqfO &cV=lD$kٴ E?s bKм7v u=p9e+iWڹE=(AQ3U$ IժU?Szߖ}s[maYh[G*l;֟D*v(nޯ:N> j=#~gS>U˧O^Of͞3N-[[K:{lJbʱߏXءcʞ7xtܰ~mf(ƩEF!E$ m 6T#qD$Q._N{//9!sk`moOv2!$jAdw͛ԱBˉHZ[fHl!Wx*RRNٓMҟ|LL~1uO%/"ٱC(%CHj*%=cXZ?>!_π~IIO DD?Ob8|zj"M%}יJ8~x1|նf;w|p:ya؈tvnѢgO}O=DDdЫVqGjmI c˖/W^OH^k4}1C ,i%rj_б&MٱC?3'$T0j TZWǩ :zt޷oqҥgϪkג3%$ٷ}Vj~DʥOI Syw!n쎍UW7xz @RDS@ۂgM$$t`B?t]hUjjZ6o'$/.>6ulӡ$|nItnlZTSϝ@bv8o{R՝]<=?xL lkWz7lبn^Fm6g7*US?<*E|#:b3aBH36ϬVZͼ[IDATR.Mgw߈(@* |ŲY3խ+UQ$Ӓwsm+tvt,5L39u%נ~sf/PHBqcOBzy Ko.3 ?w 6p%}@͞i&Ӣ?@y[7o Kݼ??ŏ/(m9B"Hr gYDJ26Q{ gƞ" &"׹lgK8ƶh\=FD*T "R_)5vh\|j'0,M=%oJ11S/[ S QY }fzU߯Z4cZO!aHI~P60BU~ -,,l-,G)[)=ky)Sp{TN;ԋ^3D(7V6 ayujkqr"^mżc;d#]cggR&e1rrJb̊O8j,B̓f0r86'$T-& x*a(xgD|DXugcgg,N,9;` \@yRDS(1Vo|*K&*zݝc^O>!'yuXDh@hրW`ۡKkXgJ{&mX]كE$z7' iI?? YT~VL?U*vnn "&?rtڞ>p|V3Qw@P*~ɮVk2/ќ,,,ZμX]Bļ(? Ky)]Wӯ>@)h{kՌEq{u\s5Ku'-D$?׮;5"OYQmfXDd1l9:Z<\ɥ2~knܸi֬i++œP(goÆ ?5vXQcp%]<.]zxR\[xvT^=$\~="2ܹJq5j%WYYYI8n  |C$++\I=sdN{jeNw׫ir(hy3?Jq.^n׬9do3vǑn=~+h[[j @{ iI'#/yuо]j,= mpn\;yD[lsشtq&fNy͚/<ɽ#HNY^,ܺuKr m'0 7nرkZcmHT3qΦx0ʃ$<8ǑLhִi''*OϞ._vmӺz1'$T-& xRD2,"R-aB@ūE.%z/c9sK:tp|{]P4GGePny=۴n=rpggfM r]v?yخݻKeOFF˯޷w@7HBh|9_|2LMMԬYC7e 3#_zT 4i4vhN<&omgkKeVE&OrB.>9#K«K۷uT7ߚ491.";w|XD2~B'$=cXZ>էX:VB`LD$wƍN)Nꫯ333¹E{]A)5nxj.ȜPuTD$ڲb5jދ/'Y0CإnB >8mov*peF~Nzk{w3hѩ,fohzmĹZYܝpuĶ9+2xNsmҒ^7R]2eG)Gbrfn{'a6yxhwtdɽCQ;{3'$T-& _VjؠgNbDj9ňȨ'sHjM21(P@g愄6` )"j  OԀ~"{n$dHɓN kؠ3TP5^ xN+mTVFZmO<_ԪUQMzvԷo..bRϝ_wy#gNxT''G{{wwݻ?ޣz2E_ͣ6\Zv9p  D$M4C7]򃽝m''ͥLvƾ1;&qʕ# Xz{g}g/h7nzzTdelڼ壹!={>󭭭EoT)ʅ_x^mUОNC`nݼժU-x4===##Cw%wS>ܹsO?u`7.]|E)Usoݺ%吚ӯ)sscxÉ愄*#/u]6zdrrژq;w@XEaj~(>>UPy9/x歜e͚fRJ׮]T{j m:8\Irc) )oںrcǼ=ot.u41>{;[[<^zj(e˧O^f͞3N-[WRׯ]?~ɣ'x3;X*O?b=q6%1EX!Mx <7_ۼY3AKE7jH"" аaC5"GDRΝ;ۦ͒L}劬 ee/J(++#Go\_tU-xDܸvC+ر^i߯hoCt'._N{//8!sk֐ dVӬ{+e~oLU_IcFKeЇ'S k{ket~ߐ !ʇPozwuX t`\W5IaګE\\@Ǯ߸6L/o\nCD DGׇ.ܺPG||~ۺ *7FTu88"5jۧhɭ[CnٱeARi7ǎ}(T,ͩxaaj|O<:5-j̘)N?L1z  Pk㗔,1HXxZ?=`#EDW..݋v؈QYejrKMM1rZ9VZ%kמ>}Z՛>Jjڷka_}%eѦJmfܯZMU:89^J'fB u#&uxDDzzT=Wm*ŝ;wZPKa#4L-z-tabP:` )"?OOժU?Hm>iTA:w F\xQ6ho\Z-x/Z௿ agg7͜%3g .[\->zR:mSBqq𹅦'Knȁ[V*VLRјEHK!zZ /bjfܭZW.Mv̎jOMLL)CH٪CPګz=:۷_P!~IGNyE_/-spZ usB]<=/mÐϜѡZIHυ~]vǾ: o<ޣhUjjZҶD'q6.st6EQQE*Uum{?礢TV-ԱR7׮us豋CELLm^K};B>^<@[e깊{R'#p 9QYXyءr:w VC3zǎu媗5e{Swzu'U@{* ի{ 6׬Qd1u668::1"44~2ڶu/x/Rm;sZsvtCtyZvl{nx@eH)+99۱ۥ˗{t^0``uӦ%%%+KQJ5.>vvsRawM;mzq2&+ڇ뢖 ,i¦;偔?E*9E}TuֽtRQOsOF,J7 uRüW՚m.}w`bb2n̘c*Ц hnnnbYԬׯ'''WVUt±sv2ѹ%! ]8dqqvt,fnNJJ޴yGsC|z3lm汣GK)UQd Y&MY77`lڇ)OR0JdwhbbE^DqΒ3$'_Kd<ڜPuRD2,"RqcOBXF&Ȍ׌#Ӑ}f +yp Rwenݼ%eoo7nͽӏ[Yhά?M6YӦ%[K0KynQ,:=zryG ]~LM6l ԴJx0ERI:~Ҩ%׮]#;k/Z+?gvpɏ>)Q5$$IDATtG4Q ?IO0/&pFbys7.jZBbb/>/]R7۴n=rpggfMIdYDJ26Q{ gƞ" &"׹AMU b͛ ǐ"*N԰aÜʌH& Y[7Yfn2gFʩ 4q;͵ 4TKءWY`әr u2zW)Qg|?(g>j'+E"cpdO@}ɛaO>uԍk7Ժ01ԟ hf8wK~[{H<(SO{ǎ^]ܾ9iԔRzuqpWr>4 y8/CtAy:5giyoC>S|hne3dZיQ);H=1;;;KKK@6v5]ģG SǿP8yjNH2ʖ.ݓ){ٓU&7!E p|<>Z'"*O^-]\"B4iYYYRvo_+e 5nxj.7vhu}[-|CvRl:`‘ҭ#yiC#jժU贯Z/:h+S'6%E\'ANZ.xg݇BqeHȯlͲˣjժ|8W*PS\=zzދ/<6SsΚRzvvv R/襥_1c@T+&z |p<]2xJڅ4nؠ;o]e˗1kԨ!S'yQ\,S+~U"S'OhIYv9u~qjiV9,:vO'}:}XE:VVK(]<=R&zm[W6V n9#-tKΞ=֝;umӷ'SSʽ;,gM 0|P hO*&jQf3gl߱c߾JG0a x}kN쉳;oٿ-JmԨ*ZQj瞝;]N)Rϝ2VZ?t}˗56n[ŷǠkۥm3f{}pAe\T7ѽRSS̬M֢mdq4h\L6|Uugu*U_$mH-RzkWz7lبnnu2DyX=ԢRǎ̙n4`РdejU߭RTӦN<9gD$;v蠣P>b4mmmm@(!V?O@_ժZga!IssˢfϬWTAOܶeS0Z-֭#6jqpZ;99nۼyѢZje#r߲Mc'}z2x}[7^UUWUTyF:qqcOBzyԫ[wܘ1;m7+K;wIH̽Z=) ť˗O8!`eU984}fMJe2/2"lΘO<Ʃu);><(o֮][m4e[<}R\|N|=v .컵]֭` GۗwG}tС=hIhmСpn˝:y׬)F$ɣZ|8)g?շo*oofv5-n6 33Yٳ\]LƎ˯nܸmf=u#G#jժUpM21(P@g愄6` iŲHur䩿[N53OW^Ƹ7zfĨ;a#.\ 4xCZES@6hL735rrʲ+nݺժC ׫'ۗΞM=_{=y!ƍ&/+Wgeez"?kkk1:}\|Y\B+ gffŞ髣ݺuK)qDv=osӖ{u)=ܼY&NN%ժU ᇮ=vrv{uܩGVLLL`ܵk]m߾y'x)z7'HBڠ'@Ν>^iSLT̜իIhQ2<~/]["+wrږ,Bq|8cEꢛFuV3g|Njw]c³sn]("s,ͥܜiݻy+CJFO&kU̚w/ 11"C)o>%|IH(ĕ+Wv=PnCG:e2auſΞUU>j#@YPkq$ƍϜرfM P!6lZi]jU МP(T(ԳZZު'OMHz](VPN)))'N޼y3Ǻyum#n\|yǎW7kff*,  CH1K׮__~Þ896mVڵٷO&M(CHۑ2l 48ݯ9>>ULMM^w%eϵ{#lݳ+tÝL.~y͚M'%^=v`Z4jH"@EiذZ 鳃d=@;vh҈#D$H iI⛡!>@`@ںqqnq锔>js!bNw0Y?9)CCء=fUCJ-f tfMtߐJQ^;cO 08<:ibYԓO,8gNHZL ?#Z=h;,"RӫWKp233_6BG:hѳ!E$O:aZ!'M*&MٱC?!6RM W}|`oW]СvƎ7HB9!.EM6z$)"2*3S>{Ϝ}ǎ}+n=o߮^]<=;{v,荘;vc輝o?z$R(|Gv^xqÆ5k!kLnݶMVo*hOXdQW,<^ݺ!hP9EF("ЦGmN?nÿIhW//@_uO8?f8y_!hg~ؿ{7SS盛9BزmRGYZZ <" mjֿIDATZ\~}oFff毫֨=H*HB؊_W*š?Sx۰_uW~鷉AxRD@hެMV:wڵ'x\0^/+W>sFfHI{;[!ygGmF0RϜٳw_?4mǻ 4چUZS}7vzÆ ;(,'GGgmOJyd&3<9)9|dG7ݻ D$+vgLLLO~qcݫgOG{z$*εk#ȺQG7-[[ ǜP(eU TCD,,jF@ohz4U[cHH]y^&< {V¸ΛGf}3SV,艌9gN?ƛGΙs wFN$()"9tb`䐲Mp&߿vw6o(>]sjPԙ]uޯnE#*xfȵ3T3[;v{5< Yg:+gFV}kmm>|[YQv6gs,'xH.\(j[0gta~3hǤunk46[zY12ܟwg&wO mv[fl7C[w{kh3{̰@vI&vmVI-S6Ν\n? =wr~]ꝹqGn`N[ږΚmZa[d|ys,3_Iқ$TFȗ.hyi_v1"mK2i\桌J{3g .2&X RO~qذO֭[fڥK`ȭn;6<SO??qⓅ1k֬u놂nݺ([LKᩧԣ 'PGpd?}W X8cz֮]{5~2u { Zv~ᇳ~yԩDT<қ.MRuCH˅s}]M>ƨʖ- ވHncfF$٣=Zj6͗.SYզC;ݾlat䑵v6-33+:#뷨P~`%I37ؓ{ٸqc""+W^~UZjՈ/E-o)*W|7G׬Y0z̛/˔;o{dHcr3wj!K¾]ɽ/{pccǍ WD$7nPX=&JpV89;_>|ظq1o`?zqTw'c{sbҜDŽQ-iN"x|РF|ɴPL>=*귨ˁ{' X҇ENMaYVΣOr=mVwwcnnzLtc'M옚{b؍@FÆ b9-[־%Ȥ> Ʋeˢ^z{t@rrJ)uoYĤtbѣ7˖/~؛u֜~6G!wkRNLӇ};PtܳGEZ?:oٛo~ɥGZh٢&\f {)Aʮ}blV22=wMx5)?LINp\b?FZcTVƂa5ʧWЉMN혬\;_&=r|zNۍnҿm㩪wf9KOE˖_ΛWFNS.0dY$kլoʕ+K#JBKOO RrQ1Ĕ\;vnJ)> (N&oն{ϔv\4zm°\MH|C.Y䣏?듃/I }ɴ`\uu>4o 7z@#ivF>;vlgv]֯[Ip"z#{yrخ>Sޯ8g_Λwg?_?U@Y vM(6rVnP]~e/+np%$ |8VoO3gܯfIDATjY z7ɍ1굲e(rju򯿎C9c>Z2?KqLԳ?rei/mxiZW_ P((/R c8Sr;}n8pLۜVjS){v۶rG?hެYWt>/JY*yުKR6*"۞&d|eI'?}ثD-PSDrQ E>< GE!H6l05j{stk6_ai o>{&}hQNʸaİ/r>yoxH.\(j؇gt9tAbQ8>~y΋J:Y!?_ߺuF=}lܸ1@ϋ7^xca4 nĮg W N"ڎ3"Vdff~Wk;:_y!e%}zpRbcǍ Pi:ubEܻCY8; 9'=}=IaolڴW^߮6db|~;dÝwT:А%o&UWj+eV\oNJJ۳DPtA0?yz<]>#;%粣zS6{>azT?6𑄄oD$a* ~/Q{;{=W~qs"SO?5b @49䨘6}z"e[T}dh>p̚4+v m͚6 ov%q6m]G{kN:uCߟPP4sYly_>|'L=Ɨ_oYSN:I@L0=aQt6k?_8<׮]+C9d׷O{6?X /!!޷VZURbҥ7xK/{뭷^6m^x㏏ PlYh@J\a#Q'%%?՗_ڇ|dʕ#*R2euʕ{1q!>e< ""y ը󨘟I6Nhi]I8OfϙvXv{??8yp lGg\l̙QQZF$Ch7rwknSRikgޗqB 7飏cڵ2d۶}&V˗=gQr1عr]X ~ȉH6j0/BszAFuڈ93kɴ7sZ0Q[8'v#W_:#f{EbC: =S&y=[3o||fM=[Yʜ3;9=e7()"١}PT:ЦMN>NE}bůϏ:JӲeˆտ:PN)ݶX0]5dW=9c?yNX}~ݵ{P>~3{VQ3#Bb3~(yLV+vf5⮻ ΍ѵ{x}[{fuE'2:x璲;;( kf< .B۵jֈZ(BZҼ#c69fMcEO?6m+W^S=3Ngյͬ +6x|AH\ZQoV2)<&+Ŭ#;ynV̭xLַQƎ12ܟwg&wmsG+X1桭;սn 瞉wh|L/"U/:E͛5SGSHn։~Տ |$!!!yǭ%uOW>o$e֔fYn? =wr~[-=ṋoVV>rs=VmO6?o|[ĊW2<-Obr@Dpy}^1mK7rޘnDjǓ'7j/}2ڼ5=9կmx}rs~*dK4z"Pf-v1"mK2i\桌JF&̜9k…YmڼeuZݧ˸3[mzޚ<3)67+5nOoӛFӹ5봵]k {ҹE"( )"pѢPU:syvfM?˿^z7WMHHzpBHũ'rHW?H>ɓm/ 3?׭te,X8F<]qIš?O+gi#jۣ{ӊq ޑ2OdI?gދo?Mn<7{lɒ /߅NCESv;v=_ .֭|AEf&NP-:v˖- EƽUBk+vwݵGgfk,ww5ʪ3wq█$E?p/ϙ:hb z֮];cwiBnݺᄋtҳjc:IMys͛5sTV-@3vܬO?RJ}GZ#$l\~휹_|?:gϙ?\.-@Gݺty~Sfff%Bbb =[8e7~e3c1cǵm:@(X~74_>YBBB38C-Z˶mJ.R}o}<9f͚O HRŋcE2e晜9 5n0BQXV C"^#*GY;y D$) O'|rS+ wkWbw{M:5=##==#ڵjJMMmuꩧ:5{ 5YpQTԪY#䩜\1 gċ]FIZre[SSC><.-~QLZ5k=>8ŋw~o g'VZ+/rT!~ԪY#j#c6 Z|_{_7l{a&=Vԓ_6,u֭Yve⊅) ׮]+֬YSBL4%sJ &_}ݺuQQlt^{h~vN8*[l#?|üOڻ?ߋ~(>8?灏GEAOrժ'fį=գ=Z3>s?U:ɉy-v_W_?NJy'%ă7(hpҤҼy_wToQجau /X/xSN6o֌`!<@EZ}*OrS$E =~䓣z9-[־%Ȥ> QTF{qDּzj!?sx7ڛiUd(YUW;]f]{u;yfr};B<=Nnye w,w]vڹE][XlYTkVoHNN !Nm:뜘NCv7z}И⎧: u6o,)+\z[om1ztŊ+^:ol1܄AKCvAߐSEY!5S*޺cMM[f_O.] A )2 +]-+kbޙzgVQ''S8 nN{%UnO$?ܧT벪-SSs^|soƏp9B;u`ua AnpFrϽ˓>o. "!KڒPiĊaUPa͚5;۲E'*V rݕ\f {)A.'۟L;s;^MO#S.踨XlZYmڼU"IR\W_y_Uufff(HF7 wt+IYAV0mSUsV:)ەsϾQѽs{l>ݮ|vYry ZX88︻U ;l پ6jT2y7Ȼ.9͊fz)}I-;X̾vˑϿ,:x'׏'wܱs䔔wyeJ­?/M"IԽ[׫bĉ1jtW(ɔ5+ljI!5xǝ=ȖY-Ge^Nn.ͽwAw4/><}}{sVw_\pWug;4OCw;ɣvyu!;(yu4+פ&l5jbQv-ͺ~ 7z@#gz}v'9#ٸa>LWZhѱ.n_lyAD\rWu2֢ 6;'O4w{7glVmZ~(ZԼ #iE֓ fE]e8(NӓԷ[tnZjU'~fBBhujfM4JmԶM~ᇳ~yԩD+VuիWv)Wv˱ϿjҺI8@}6/*ڷK{i" %KlۦMsS_jUg_sUa>f_̆a| KhzӄP\}%7r/_]-,|j.:~]V8rJfGt_uT׭[wyGݺt=G>"ja5lwD$6lY$kլ /tAXjbO?}}*U*䋫Gen=Mި)#ISBU.`wWaL4iWo( _e"\i_.[wtϽQݠAc.Zҹٸqs?z&g?~yf-;Y: S|QaÆx0"{"ɩSwܑ=مkK ߸qcT>d<;FysűL2?LGQbbb+٫{~Wk;:_y!q%!skBQ>bT| |z:ҥKc13}]}zT|ɡ@V'՟IڽC{W>GpxMlPYݟ%,fڤ>yN =~ZS\hQ<>- 7ƊM6zd:̨BZreT4NoĵkƊoC٫c;޾>,BKHHmn%쥕VEa*+ڦXXb%o}[GNJJ(('/Ș+7G$+U:4@\;5j<*g}ҦM멓?1|hEtqvGx3N?-sDa BP[:N8I}+֮ݗY$sݶm=3Z9sc WD$NCm^'Vj8T H쵖4@&'oڴ'Ҭix#" VZq"9bfMkN6$HD`>z̲ekuR=ZLf+}U~ǞQ8$" Pο}ゥSgdg}ijxH.\(j+/UF|)oxG Vo~6|5k- mO&|-޶~cn*s9@8NJ7f%" x|Р[|ɴnQQE155İ ZgȒݍy[⑈$lְa=gNVpɀ??2飏֭[@,[,*5MBʉaUOBWG_|yU2|K.쭷ގ6=:bE-ޟ0!P8(2/VJݎ^g1KCFI=>9+;Ԡ'L "%Jtu>4oٰ~3e޽K9n׭Eїzw'v, +WU+;|X_5i$ >ۥ=S!͙;9s#^fӦML|cke˖ i"EUba91)\yhX)a̙$ժV q.ccmοf:?<οP,ܳG;oP5lX?*1"чCک mCZ?İr" 6 EE5ƽ9Fưi 5(X1*[:P(kէXvm7nLHH8v`3Zq3ŊRJ-?C EȦM"*:^.Qgis=z5oҺI 6ğ<5X4vS>鿡Okuj(4\ly芧E@1Яo{6?X /!!޷PpQt@em¨m^:))pRG̟UV ]"T6Nhi]I8P ̘93*U(imbmcg 䑜d E$Ȳeˆտ:@%" @qiӦK/r5:c8@%" @qq-Nè~l# KDɓv>{ΜhoִiHȚᇓ&}4Injlִ=c7()"١}/ 3gZptV6/ĠӲE.pqe I gS?6+V뮫WnڵS=6dIffeWtG6oo=SZ{=EW=*N>F&̜9k…Rk֨qIZrJE3"@XlYT49q?O|o|9o^[?듃t=<5avD+VO8!ul#bکq~dI nT\y_NJ/nݺagS?6xȥ7]R?Q5$ \8wznڴozlٲ"mƌ`_EUTfys[iqN ,cDu;~GjVjmÆ#PHOn#j"-agSp}P,X(*jլTĊQՁB)^#~=fL;Ɗ;IVǮ_z/^kts?Wx\ڴiӥ /;cn];y'S:@QlٲO^z$b;B SBVQ @Ԧuԉ+Vʫjcތ˔;|dvx秏7.Peea/2' qA=z۞;7Q15Ĝ%RR7:C9zo9PtNMHCԗ sL ܙnqNye)bn։~$OZhqE5jOɁӧOdHN6V=>a͕7o} mFOkݧ$cxd2眳涫HbʷiEXn=GOgʔٝ:۞&dﵳ3q I6GÓ;3iC{zmye)2><9_ GD3iذATϞ3ewdG8jٲeQQY ig~Ϥڌ%XӘzveb)=ݺ͹7aN>~-!N7vؒ>L42sk'en;͞HSz%O3BJrvͻǮjB[!%))z7˖- ?]3Z>QgMZH+#P\z[om1zt9&ߟ0aǞĝKNN1S5aO3BRZK96d8jXHzU/ ͳϹdך>t 'أf2s:&vL~XVe;{'\?6>!wR#;%gU/HKWt걧O}ɀw̉qKO]B8Mrc_y<{ ɔlhy> -Z<#lVkO<- r]XGcs=؝\?acdžcncH={'ݼrw~B#ǧwꔼSekgJVCj6%;d@\HIDATA[rv;>azT?6𑄄-Z\n>xЏ}ĬIt՟{~yC7k4¶6$ag~P,X(*jլTĊQՁB)^#~qӲi|2-g~'rIO J'L?~NgM;&P /ΊkT O#$QȐWK.쭷ĭڴyg˕+(|g"8)Wܫ/_*U ěʇ4b|$%" Gݻuy)͛A-{6˵ ,RV'YF7  m䭒!~ >"*:^.\[<3fFEժU^2$]*UbY 7߬0]N>];tp'|dL٤SNOy>KZԹb .J]y2cdj"^3$]?X1s_w P0nwFƂ_tz(J)}|ɷ5qأ(9F ;7(iE-@Ea×-[ _uG8zlN텿ϟ žտ:)"Yf;mZ>NW^ =S6muQY_7n|r,+W^S=3 {()" ᠃zQ=nW^w['~aT?6𑄄D$!lu jԸ'L ?VZtҨ۬2WVZ8a=Mk➌͹kO_6ofMW2!?i_})͛5mڤi&βeˢt;fyhXh3SmzOL c$X'N{CC5)SJ-?e˗'&&;?pҤ&~8i19o{D={xH>"*:^.@^{/z;|cX sL?aB DO䕑͍mC>~AZ GSY;ӏ>;~Ӟզ ?U<-pѢʕ{{XJޓa2BʉwWOgJr#,ZgȒ%JK <˔*~C҈o)" {??8yi {0jIw$7M~hܺucLo=Oy~z&NH=fۃ/ ~e=ȿ?O mC(WU`97`xl;IIn7d#mX>S2s~jBwv9DŴ=$@RJTY?9"]Ϛ-rا!lai rWw=v}G I]w{ÏQ]j TJ&%Պv| ҒQc155İ22#$]I$LS̯<շzKjz 5yg'V֮J^# 6lu̙紸;?P,[o^m6jǕ(!^OQ+QC*N%J;~jPy$"jRDV#*dG$fu7()"9txq ?\zu2e6w1poVw/AON2-S\ٲÏ?wߕ/_>~EP/^`a֧cED7<39ݻumԨGuquʖ-VffErs=gsܸqosсp衇~b5" m1>xN>F{7EBBBBl:z[O=W߾ࢴ ᄏ5C%J7 %7^͚}E&2e/<\qBID_w{oT$&&g*T /Un]o/}>"~YjՈ/EC_ZP ]ۛ~_ԩS32bQ8jNNU+55թ@˲eˢɍCqR^ݲez{$,^k~P̟k}q}b*=$" 엥K7G$6l>z&}Q^?}txo/|k{w.!={xHvh.P\U\y_NJYfխ[7PNou~1d ;>cFTT~.NQFk^=*>S2B{gκ6e _}|Р#ݵ˵7cdj"Pd4hJNƨf͚ipr6oWn[6kXGn'vy/xSN6o֌ըaQ"ć_^T 6|ٲeB`ӦMsT_ܾ](~=眃:(d;8pި(X~?P%ȲF(XߑÆE;/E$Mթ+V\yWeff?sScEҥ˕;_yE!;_؛3p \jȗ~Ы\͏Æ_fMlڴ˯\:랧{g(~? j"-"CZ9蠃`TO[n-PP׻Gos: EmRZP,;*zh˿^"PFŦ+VٓC&vLM8q!i ;t%CI|~bƍǼ((n}FcIHH@OɅE-P,lu jԸ'L _}㏱ŋpoD{S5 a >7!5uK;i7{9wsk60'U4ɿD>hzCCo\&4/} ƞl{ك4am|gvXMo'vڬ9-vo~wЙ6}zToQHа[-yedF_ӗQU0!{4:炧oy  {hoִi. mOӰa=gNVpɀ??2飏lٲeC kt̛g;R%QSܽyʥ5x)]jPՓc%p]d?yA9 75siA C~;MUmSO;筷^vmw;<[W|n'_ِs ne x6zA$]6兯lt\!z's5xyR֣odG] ؛3*5''ꟑҳ{m:IWaTqcѿM$Y ^|y ̛?G~owbS?:7kvϟ/EZq7^zhѣc-d1 |pW.]t̘1;ZjU'֫[wYa Ҭ,sM.޷TsapAKclNej:i?>` dVQS{s͵?,YRՏs\fM?*+o7_>mN:5bEݺugISb!(;1I{v{^YszvA/vQxe!T m7soRJ[ڇc#) RM5,$=j?;aQ6o5:.*cD ݺtOw3$q\r4~}T)PdLiPqAaC/=K[G6kԨdX7;+}-SY$zXrYC =6 qLz<uR$֍&ZάQů[ KLݛůtP[\}AͰ፿o9 ~˒a2 KAsBHCBΉI!$5M{db;ph~e椧,˔;,#r}}Kv$.uu>~6&l. ]}%7r6-)k^9K'Vvg٪T6s*۰~4#s[!%C\?#SsvVϒiu,،OgZn}@TXw]4bx3N@`mUr|e#.ZԴiժYcms`w! ܳ{9kdjn5gd:UeŪ-]Sn4eReMؠ.b~2effErs=gsܸqos[NHH8mX gwf;W;&t,=¦׼p;8 Qͻup#OIDAT-KlOi O=Lfn]5jtQGw\eˆwGr󯚴nYEmgl'sJ\FU4{J#GZ;H9ӶR&X'ּEEvi>T OE8yei(hĬ֥fXzȾzA|[MvaA Kz;+F9k$JHHY駵ޭ\XҾfu(@Ӧ\\tOb+ C ̹YB.|ӄLk!k5O}|d5} [>2J*Q1wݏΞ-r%;D>ݺ}N?M|vl)ɻ?zδ9QQj@^3$p eO8=en*}uY$N.M:5d(sVپzTfԄhj]2GLX W\.WB a5lX?*("!4~Im}LVx=2q԰:|D$6lk"ISؼȫLɳDN\xw:'b^M={֮ޮn'{r?=eqFEbbߞ{&O1sAqƹ3~GMZLNidfߖ xhlHo ɏxާY m*UgܳG;o[}Tw#kNJ7>9xp`\jȗVZ#̚333Kn_bw'wCĐ:ܸ۹ZtE'ԼrH SDVQ @Rr+St [2ev6_?{`1J:uޡG<@-X(?yGCW%of2e,w3ZW^QJw~{ SDhHOXvm`wM͚5 yJ?O W~qO|7~jpŊy8){-[?-_إe˖EE|pV6ۣ=׬\8|&4h٠n?KY8p3>kN|97iN I \{ڵh9OWoG%KsG}R,]9"ٰaÐ?퓘xo~gkPJHHmn%D={xH>"*:^.cNRr`zT|٧e`ϘիMz6jtw̞3'V'|>qiOɅ- lJ*Q1s.͟-JSjՐڴiknjyq谑/ ۷۶ ? mhBհa9k#Eh̙QQfĐn6֞@qU"O=眃:(V̚;؉M6=JLL|"33UYre 7)SƊҥKwrm!" p=4VXח^m :nZj D:ROv |(~t1ŋs̛oF xcfvDΝզu+W]N=z{ڵ駃zkmtrӜ|a*oϕ(GcI`7J.M}/ڜ2ujŊuΚ5+{Gy?_}F $*TNWjF~9s[zzKλ0g@1O%תUL$&&vM֭[97_:loct裎tI/#/bŊ;B1LBfff;vM(6'V֮yn7Ċsn{qu@bZC̹ , |d2>yD,>|GGujÆJ G" %/\i~qW6l׻M13ڬVɍS@xg@OɡGDENjY#_ސ1c?>#9)ՏyKgboL=gcSBbڅtANS\^&gȘ5jw/˕- OYh ͚69ZJHHŦ8Zը(StӓOn(@>NrrҕI߳ZTTƍ֬Y# o233skB!@Qqs!OO߭](/r?;B E(D$"HD(D$"HDο}ゥSgdg8TvrRZN=V8tsb !333&2 .Z5kbT|vu/~'!gq_xZj ÿR!wJQf^hظIGĞQԓ_6,@cm̚5nݺ \ㆧ~&gSN'|Bcjy‘eʖ q?ϾZg 8<ֳvګ_;3f D$1SDS>xN>jͪ4dʔ-s|v%gN/[,AGYkk@1SDO m3g<2oWn[6kX\#{F/xSN6o֌ kD()"9t|3te˖pFEY%*[lyO /:lXOɅE-+W^~U`\jȗ~(\͏Æ_fM?6m+W}&|-cu*s9!L옚q6 [V2Czou!u w>|bXqc [nd.4Q&|2-iӧGEsMI"I۫tc6W6 H~XRSdN2gҰw#=C^{xu,ټz.IaCCÞyӷ=BGn8Nn׳K{HٽV])iSJK22#97 {fNc6 {QX^q`/Mhwqh,lִiS27xK/{뭷7FXѲE'L{/Nl5cj#'eCjȔ\BG IҜKB5qh6kt\T LjX {,׿j短\-o(v"rʽ=R.uN91)IO ;1CG9!ٯP Ғ؇d-=cc1)=go+ۄyJ)B_1VBЦM;gG.ovlخ֯[O-:v˘2IDAT- /H\rWu2>#_z9V|WMZ7}PrrJc )=gBR3Y3PݳdN鳳9)1S%`i)Nvkg}g~*@!`m|Qr;}G%=dRV۞&kӇ%vm:xK3r|zts^;I?5=gVj(n#j"-fо] ֏]F$'FIJ˚a{4kcY_ңSc#R?)CKCFvs!L5,vswsl9Ɇ (233skBQ>bT|vu k׮T{ƍ lrf҇2zJ!e'C#M?vfXQTr! /ÿR!w, /;_yE̼Wȇ|Or;N yoAÍGXwQ}U+#(<",@~XjUV}Mnʇ"dU2}X]riSTh3 ϘEdIrXJKT'k^EūOQ>2G(J1txqju{ckxޤu-mVg? qk;6iϧ|CߟI"j!6?İ˖- 8džտ:?{]WU|oKkIP$6CjSh%؀(ApZm"ſ#alP:vE 6:cFAtRhPHZ&#-$ͻ6Ϻw}}ob-=2"=|>{\nn‹/~Sx<?|uC=:}`H;rȂoޔn//̹6?\9Xnw`H:e?ϤYYyI=VxfrmëK\P`O +XNF6Y3s'I+V=e55[ "ŽK>_*}xϲeGH՘|pp`Co[:aW~eM~{F]1⮟yc o}[ryW1;jU1;q7;"gl|3N?= CCseF~~QڕSǿ{}ŧ mnĈ$ۯ\K{aO.xZx^Fessojݬ^wg""  GWd&Cz// SDrG/ io*mKH@T c aֺUF@H$" ߬H7LɟqxQ`HĿo~AtcȑHQWRAI]-m7YD SDGn٦#"yT,vرO4a°aA=S5^|5O>>6HuTK46o ˶m&G1 D`H&[uvͯmmݐn@ 'wn?{]0S9DǼS|r޼}CM}Q{s?A #zb+͛L9}rG_ۿþsG;w.` 6` 6hNIa1*30p_ɴ&Lֳyy}s`5X#=m޼9LFFFÐapk`h"F+:U$:H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@e-H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$ACvePkCUianlxFZVnaIEu匬XI͖pɈh)=>fϩo. Tܲ$Ų/o'm^_hpID1[5<+[63;pFUG]@Ѱ¢¼p@ID2ƊqW?ۙo]<;WP8 ـ͙҆6>{X3-w]9)hvZE-ͭ 5+*nwMg+TIU$* 222bumób5+Nlmm #$mVqQYMc떶-5eeU-EyF532YK*z?m΢#RU$ rD$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD>#^lF *-KIDAT@$H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H4#wt˗?ē{na5G}Lz9 {= +/?XpT֨Kdlc?&'7' WZ_yϬ]nGrCWS!/^[3$]!" iCà?1Ҏ|dޔqa5*1qeYy7?ͭ&/ӣ=!!aP~&ݞ \\8s[|KuOͺ<|_Iǝ6 >@<_rg~`H.OS1l0d}gs?tn j0E$={>c?&왚/g|ᰇ.Kҍ4" )O?(7??GyqMW4Œ +u;tXX}}H)"Ғn:ԝ=:'/;u=<#??#W H/QS99cC{t2d/8 ò)S\{\nnB17o~USDCY͛~7J@k\;t.gSD2a)?n/⏞ѧV=-| d'7!q_0ؔՇVxD~r'My]uO?uѿ[p-㳻{~~%/>~x}o~0쩩SW ݳˈ㽞ʆp`}ŗ^ o?.XIM UeEyOU7Zʆn[Y5g+aFU]eIaΎ)jk쥅;f-,L5j*nI̾06<5<+~?=/jh^vN;TS1#/־wkPX`>[Wχ˚h^\w]]}gĺv8gIybnzv6yȞ$bo3/kZ\ե5q9uUTnkoҖsn35V%o(ϝp횰c;m7>4Ǜkf p迊dAEsr gxW]53r13շm?]-w];k++5N+GVՖ3s{[Iv{i l'i {3Cذ䜒] 2nY\GbScs ^⒪N3 /jNK*W֘tY{{s:UܝwXQؖr R2$ dpIr7n*k~:7q̐ &Ϯ}9o|<< N>R1sꛪs;m<1`u]ynع%e]5577_<(/'+Lm]lfvE] 7̫<3X{:4vQi~ru{N+K~}6&giҶpfN, 2pŕw%]QYmUdŭK*{.6Zhw٫nlrZᖊsO//r?^645uJ%uhX,pFi⚆-me!nS+Y} -/~U^-׻(d]~M+R$Y\}ҫ8.T."P}X\\¢5Lrn#&MOތqMaJ*8Ҳ%ߺs%"cŕ=sg4o^_9=D˽WO.hEf6邔u {N֤ s{yŶf8 F;^Ű}4xqs/rK^_4gNiǴWPEcyE66oo~y9m%lqwnױݿ9h7p܂'ںފN~ֆ.->E^ab3gu9a/d啔44o7~*<^V^1$+i[T^S }EcsgŽMmMu깠 giVV*ѹa/5kosƊ&g⬜<ʻlm+*I'{}4UdddJcjAIDATIi\qU0֎uUr{36o|x/7ϾekqfIQliTFy} o*ۥd ]\SYQ [Zk+K c;U '_=.1m憪qW?<eVaeÊ5v\XIez5m'nvqEiQ^VF^kI⢲So%>(U^zxnIUC ͂ՉvM`;-,|^X4u玻 q?_EF<߅a[jJrιWh(H5[ʊ&H\[=;bs tL8}Y|qQDUQ>9+oi,* og.Z_[ ue7v۱77u{Վjfdyg.m*j?0* ;tijkJ:m@McUa4gEMyAV.U axQUӳK:slf{Of3_`iȄu9,{9_nG'V8cҰ>n"wvmoyCeg'^a望%ndMn޺3oS>2!̐9}(tpji:>sWs>rOinIb|9gg$\' AfHWڪH]lciN rD$؇s3l';H@" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@ʆ{gĨ*@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@ pߧF5O7OD$CW7~08~7^8 D$>tOeL=.e'Uir awNKO=3 ]62u3ӗUyksv̐Nlsm6CiO ' HDalt|d6xq]}yȲOfx'rބSWݟMf1Wj6ް#m.v;.:-kg^bFDrݚt1WNIʶkOԷ SV>}z1douwE+?;&7ڧHEwm;e)}Cߝ&0:!^󙕯nlS;m~)I^镧|3;d+O-rL':]w|duk&^B2h?{w('^;&V``Ddn-y {|L'#Z|Zksbqᳩw\\{ zC6zu:;-Sc>B=;;gt;[眒5'uGmB٩#G=5OîM\xǫͯ"Oi#}j?MvӶiSɳMpXV>'d+GYĴ }uvH/?{= aS3wo?{~&]:qͼ@s?752QH>ഉ_~&l3gL.8|hw>?&G~ wANdjp+vy|ςK*j^'_2ẇַ-o9|ǎxnxXv ꫯZ? l͛Gzh``F']*7ovOE]ԣT6qtxCd|v^Ax#ѳaĿɶm6_ו>eJ>9thʂ ?<H__Dr]?3ό1⒋gl~i#֭[ M7?ǟH?8H ZgI46mՁv򑯽Z`,g,w۶mgġ}=gZ'=|`HIom߭z u=nG]ƽ{b~+@SDW_M4z?4d +ƨox|ٽH,O>.(xqgN2rD?W^ gl1.wlfaΎ<,+|xmٗ-s ޟh]_ Wn( !z.NiӟׯO49I߭kՍ5>=ox92;Ȗ^~56lؐnӕ 9m붷-Gz3ɯ\_ge;X,з~xKK2N/H[ 5*pxG'~`?W |u/66oN7gتuۭλFk/>" ӍHFi1V~]>s7~`?Lm nl{x< )"9]0"=&<.8crAFПO:c H%"AsX:<,LBl H_Ppy^nVqys}Co[:!eTbw4`!a߻کZ o*mMB5.ݖ|Sm6 7%oOX![Ci[N:M]^N[߇8X%.bqMui/ _<3v}c ܅jO]4$ rGƛ o}lFJs_(|pժx1G/ a ±ųc}c$}I,5Ϭun+NO瞷01?yJJ-}ymH_rs_= ZSn9d:k̏5-fv]5֭J_mnͱK~ricXzw| և`ySkCm_ۊCuomuwzph59XIDAT*٥mUo]u_S񳰪t2ǟRjf`ò)S\SͫMl@[~͕cWWhuS+ϻ~V{kn.Y6W^8K%`k_<PiOV.F}Z?\-ߖ;ڏ- EN4nN̞vՁ\;V_QsT)nt$dR‡o*,̮MU9M^ޘ8-N֧L]^1U԰aڇɕ^1tw߃/\&յׇYΣz^~ڜL m|kJ$;O…Ss]>enTܳZSɽ,uYV%]N'ѹsWlV|3:ufϏ*ϻܡģhiXޱzn ptbцN\dJluTa/V)a^;-׵啔})UG3Ythc,s?g%RvO)x-삃+"b6WE%wnb)4ϿN}7N[UnDi2UV\[uÔϵ&, /ؕP]r7`?_V\.Ѻd}7Sq[C;+A)&sFpi>͕FV-cJVL~S%?;>Tmsk -U{ 9lO9x}o[[o#ڶSkwY YnKl {jfo^ڳc^߬(Lϗ3(jkC(ҶcT,Y nB:+/ewqxM*,Z[YڷNm۾ז}ڲn{xE]q3&=܊:x-tsq4e xYԧ*zN!ϬufmT}D/Pr/1^6_O~s}?{Mu!t=+K]۩ܱ7ti {qM,~'ﴶnH{{C=K?F?ۍt1xn3kHa0]3yyJQ,K=@m,~w{{ j}4?vi׵_fo0H"L mQ.񱳻v[;_Syힻ{Gѣn5妺 n˽vo={ۿMm7Q>2u{hw=Oni/-{?8Cv ~'L^կ~ =Go# ;{jgg/={@6[WO\kC 7M6=6ݾs"#|r/,oܱc} ݾ76ڞыB\^N毺ߤF;6DF~&SDrDŽYx*yvarȐ믿טRy/۷o7qq &uQmݺ{ujj:'׹`O ʈd”'~{6lHn#|6#3o}{1xȑS8P~xϰ;Olڴ)qv[nM<;3uʔ/9#޼y-[@okD2*&~O^v]z?#Gffv'=1oI7^xGg='vespŧ/ w#-#zb+^o~&~G֝^~;ŗ^ LdFFƔ3Θ1G=@`e$cO `~M=tq/b`{xEƍ@D$a'237>87U?n~=64;s̉C`ٲe믗/'m۶='Їx욌xcv!ƺ5]O͞|좜 D$ Jgy~q^r !3 rc!4T0bތ^Y3ʮlUU#T=;程ڐ:`uSX؉d+kBx<޺KO_*` I3]^љ{g4vuRxC*ZV)mHPJH⢾ 9sCC|[ֶg+䜌^vEnⶐ-EIJʯL {s~hXnጲʚ-dlaY-M͡o-35 7M662aMˮqeKn G[Rc"ȾK.niMsz)K9iΊloXrNaEc .vUn9XOH21y?^pմٙ;Nm@E$ L=Wu]mmzh^n3W+/W5No3*Brf']vʫC39{oNa/_C{̛_, ʮTd"HD I vYkMI,c /h MDr7UvG*k %36ivQN`x<D9"@H$" D$A"@H$" D$ٻ說o; RJ A+ *s28y V+: UA֯*Rmbk((ZjQQ@&kEbAwoN$!yu>{ιɽ叽$D$$" $ I H HDH@"@P/7mPר|0$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@$D$T#Sxٳ,Y5}QH u֭_^:rJ ^K)6y.ŠV ??=ԪUP^V#w78GҖ-[nկย.>!tA\}կoC TIʏHVY;*ؘ]ܣ{czG$Oi߫F>ܤ @*,[n=Yk&<T"oIX"V7j|p(&HPIT|aU9idG8CbU3f @*RgS=B)[7WzRzz9hԤQ:EuvU"-~3'J5!3썺Ο5u&S{_4]U 룢Yf{ҾaXtrJ!GV,v83uSZRwOu̻?@J1"Yf}8ڹSWgurÞMKݩeN'ŋ=g4驃P i^uzΈ;nLs]\C^ֿnAc!-FKxʎBI&Q?pTtibkä'ΟjHN??'' O:wtƧ[~Nqg )9_צޟ7-FwSo=jHr x7l䰪`O*B" IDAT}{qݘ{gƠ8 wi(g\#ϟX0g&'n噙cJn:SRRc 놴t>ꎗWwԩ(bc;ztǟ|+V,^ѸyPRONٱar}q^H?5WaF!ײˢN:g[}Q>cbŢaeN蕻vݞ.}n9Q1W^pȨbo7#טu-Jim]闞#}|a^,29NPnٲg"}wM=GzuԜIWO:u?gD׮շG_{nNt^ ; M O/2+->adiTeK~zY E$[j"$zM>˥a/+jU{҉G%*O>ӤϦM'Gb*w'ig$--Vd=ogXLm"T|{W޺w2{^տ{RRRP"1;uOsbwҹKcw:k_ӡ}-媿ܴ!5kG{t/uZX{9ܢ)͛wlȢً8WyC/Tߝk P>T %m^zg/O_xhB%Эk<>2xw<(Y$뮻?P }QÆ0_r,8"_N496gNHP;uVZ(D$(?*vDrEDJH8"@$D$$" $ I H HDH@"@$D$$" $ I H HDH@I999 EH@"@$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@:hzek~̲PRKNڦ_F(1{̜6o .{~-%7ku5-cNF] =Q-w~ef%ng\0x1su_xka/weQXAV7y,vk')(JE$&{*aӱ'NXIc8tOE J7z~E };>n\ju쾣p=+i/ܡ_qӯ6;d|Iw^ޣՒL+|vW{Ǧcro5|k451cVyhfȗGM̌2'ɝ@Љw~jl׳}"2Y{R.{|Ƭ r#v>2oY]qe}We9ﻦ[:Xy.޼_Br2`@nFrE_9w7.?vkoyטˣaBD"B{?n~y`JωY@֥1sr6𑋢%7L4j} _vJJ_}YjZJQE$GY¹vxѬ6o_܈\ȏsmԅi]Y6}RRRq;VMn1`}swV0w [6{ԭvg-m؍HVN)~cv I.3 ZPR 9vJ2qYΆ6i1jďqox1sw97d]{jЀΞ6xp|Pk?P΅i/Z[eNJ!A Eګdr }lָ] yX|mӖe*k)M]i~߸E-kwk($mЬm㣷7z2͚8fpW}ضuu z(+^grޤƻ_4qLOQڥs3e֯KJf2j|c`E?a&_]v`$r-)''g/}1 ǣ ?X׳supib֯̚y ;=]g}=kTl7G$Ò;ܹզ\lX^=dIktǭu#sg (X"|OS1]joג1E[v׼̝)jgj_;ګY$C}|'9-V~K:'~9k[vQs7zVy,wVFA>rwkwX6hVGxRlrX:Whc2k^, ^.='\ݚoVi=Gn~_u׾M_yَȘenדkmkU'z_GƤ jt-?,~CǪs#`wrIv?/rJH8"@:(P Y%'%%宲3GR$ߴfMWIDATPRNNNH,f$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@$D$$" $"#_nJ5jeI H HDH@"@$D$$" $ I H HDH@"@$D$$" $ I H (">ws:ڱCS:YguYguֹt>vGnؠA֭AZ?>T;;{ժ 6* 9ƍx|I`͇ P5 TJI999rS9n͛'<>nZjs:3ղE}Qc k e-uS(GؤI`uvG||@%P"sߜsک '~Ӟo-^jUf U_hnݲeQnÆ ^ $\+V=sG39Xǟ|@B*ueEE- P_˯`ի33W*FR6h~P5j[٠~@HɵkE YvW^/*U2c۬_ѧ?<@rrrűuGYYV;FnVܣ7nͱvcu /=8, 4S-ϧL}"o{|$}ﮏI'oذ*\M͆[뻵YdNkBf( OJO߆g9;%mºPae O7܁VY=V|73T2)" EEN-S5&?Oز[s^ګKJ^&m;%welgy:gOpF^r7FĒaas{OŢ*Ib[~}T4Ь>uOoC~7n^S;F{'cw8"g]6??k?~f_O .٫^3~Fȏxv5{sz#yͧ+2߳f~*qJMhN^=Cz\(PѥLє C|u9Wfv[$KzR!\\7m;sCC=0^s ]1H^{(j_o$bO2)d=k-)z5zbT赣N[/MZ7XN+׫׼yNĻG $.H CѺiaۙƳz3|{yh>%̹C;t-W2wZwϟqݘrc#8 q@װ|&t/˽bH8qef :v{̽me*C!{`)]zs3fêĕnݺ7||g6o'" $~.˟6uuh05Ll?5m4_Nu&wjʝWuW_;6 +=)}m8`s]ۻW>b3zϝڢk{/FbPi'3'1#^.hWOvwzGRO͙?{4dS{E{suT\yOW޺>qwm,X_Уw1]rY(>dx۝Ѯ~i'7 3fL/{!t {nJvHI{V_4#e3#:vuO_Ӝ=KZ.ߘZ7ͻhsrr$Pj"* )'3Y.ujJJ_̺njVn _-:[>ܤs"s½hVzƎ9¼ &|95rr{27O?Hērܤ TnIEͯ a~)Yh5FE@7koIJJ;cl *:hz衱zժ3g*1 mޯn#ٟfPRO͙?%5?e>b^>â1G}M7HKMޭkT?sJLD{Wݤy6Pf2' e쩇ӤϢً݇Pږvʥ]۶QpѢ@%S/7mzQgn?P{RۓڝѮeM;4N6gkcsߙNA7/skXrŲ@px uU %mM<%*];h5kּcho3*c_9Co@s҉'FEVVV+Y$KݣDC̘1ƛn^|y;G K:v>5VԩSw}#fA tzƂyoL<* oΝ# %K"9N+ݻǶ?$PD$[jD$Hׯ8iRTs s1Qq%" @oٗIDATbujƧ@%&" @s^=?@%&" @y_qˣk_ӡ}@&" @E5}csgd4vh@ɩO(кu؟Xɾ}z}7ͻ[2P }QÆ0_U" ۛn[lWrrrsN^>ժU /޼ys3ZhvZ\uUfM5jڸq*HȎ:GP$6汿N+AkTʁk e"E$'N.ѭ[Ԭڵkcu˖-^KtPIU|nNx>GVZϏ<" YEH3>gKEm۶c#G27a78,@ŗ8GEmc!+q"~YT|I'"yG'kڴiH/~q/B)nCrPHsLT,Y4[D$[lKH@e8{NTL4yĪo޻93kٲO?g.xTJiE[G>Fճ_{톡7Jc:wt^׺MZKOOy;㳯k_LBE$cFѪU˨^|y.?1oT?C1g6(gwumQ~u2T*UByg/O_xhc[ȝcٳ@zqA -J?>ssuR#GŶPڹ{+W֯WyfN9*,'Ow;ßzbꝣF~#@2ҤqYgrC:{KNl]i?XnH(999֭{7LJ~6``z˄lS"k>0W\읷1tX|[~~u v?b[h(ނחs&_ |1Qq%" PAwwQaZVnY˄Kj>.J ;GΞ3gҥ#u*+ m$ݖ_=s5dHht:CcU3f TbfHH{c Qv?yݻ*+HPڵm - Tbf k\@%V"}b[`tQ*RDAzvkժ̨SN6 e%Q," PHG78, "ٺU@%S/7mP_U>@pxZlUY$'N.`G~O~6 G6n|? Tb)"yXEH@ޜ7+\|y{k:oD$ܹoy}􌌂<"9'_={ɒYGZ]{~@J؈]A\>aCot/J-[nկผ@ܩSOjK͛yւoEk׺檫5kڨQƍP9$TD2'' ,Gv/>J栐@:Q}ŠA3. SEEo޻9u~GTlQ#PYUdvstzk׮UV#tPBM KEH3>gKEm۶'"~h׶M"\?dpH)6rf)Q޻^vT|1;5jUf\`/$B ^3yqW4[ʽ|P=3~ ^V`=& MDr/ܸ^mP*vKG6 l ADr~7˛0wB%w?:f_- 3=E)y-֮ј#D緯~M^ؘ wF(1b^8a(u<Z_ .o|'w_x!1_ Ƌ/ NG/@)/+bt=]mKG"g<Ψ~V\`ɝ.>bSzվ͒xύK~^cWэSzO]}XwrGx>hڲi|ix缑_Dq3fi8w_y .ѳjlި'/\TRvGlnӻ6.sɍSc3 _:WKR@fz=$zKG.3Z:SVR""?>Xs9?_3^ j.77w6da^Wj:oEu #YpyԷ#[Λ25ܕJ̻ay+ΟwѿЦ?z 9A(u<hު \Lh4~wQ9?W幛۲+{j yx`v]LڡYqʻ7 }wg,@iy_l̾k^.[1]WlK͜4޼b^Q7ܮuvݹ3N9 {f#=xb2g9+]+Bh݅4m`A43[<JKEH;By5s`^,Go.[F'z[{mzQ>oJ`[ w2eA e_$wl(y:!䏿kct6m ̽m>W36? ImXp̱EM䊢'}?%d6m>NgXgB*r%;k/ywhCswh-}B֬^js΂w6Ě7[zM"wTphbșWDayfϸM˚3'ܹ4>yNV{JPTcxPv~VYgǟ@^1Msӥ;=#yޔ[Ny"s;ϝܽc=_Q$yƍT)/M{}_b[ksG%9{1^S,uYguN_|ŦMINrFD|^CKo5_z[oKs[sS B ju~.c /͊t֭B\=7llP3!{+gЮmF)DEHN<%*]; / e˖Y/գ[גNr/-Z$@B{c]nݔ'jzAH)6rcЉ[١td̘F;:u=6T@c6mZwoذA z ɧʕMO>IZkլY3@<ի?(حu^I{H$רʖrrr &Uf^q"׹)3_{ɘ1{3~Ǭ 򑩍O8]W ]u}4ㅗ>k׾YQ4 A?:i~/T|=svm 6lݺ5쇶m4lP?Vҡg% @b{~?'tbd˖fiӺUl N|g Oo2~A^\P9/7jUʫiݣDCY$>|$gv?CcŦM|a(H_˯`ի33WըQJ ӻvlO:{%K?X棏> enݺk޼YSNuy(;&i/969y˖-8rrr = k֎/6f5qUkP~ӓO:CB]+zŗB8PѼ9oޥʕ?ZܴPy|ys撤ܲqxZlYh{|P|cڴ+|dLZ}|ҤOlٲaƬ=g??WPL_nᏺ|dLN7[n @q^|$1G'ĊK6m42UG vRۓPZъk]xc'Z6nxɥ`w ۱D>̫{yѮ.yng`[n5~rOR[;^JZJ(2׼fŢئM~}c~ks{jժh*RDo޻9z1D%%g:댚0nq5|e(rrr~z|dN-bG{T([)i)ٝϺ講߼hE>&%%P*B ׋Bl"*,Yʁ+vnѩŤJ)k=4vaǧgdDu=Ce^r5osMMEHޏ='*&N~pvQQfQG}wBYyD+V0#FںuonhҺɐc~ٸy㨾}Ĉo&{c-TD$qFXgl999ϧL}"o{COwtݣQ=i 6\ڵkcaU9iAcy݄6a]w+;9XjU挙3T(<}OT~3f:g܁VY=V|73@̳EũZzxꦴ3L;c3hԤQ: \?dpZEHN<%ڊйS~`ܸmڽp ,\(*Ztjێs'.dNp=㍅Q/ʿ)lڡinȎL˾E's闞4|N؃Zc"E$|aϨ#Zj˖/}^8}P֯_:4۫RRRCHMCc CÓӊ8eGW?8Rq>.sF);|R,2=׾aH=9%>F`s^‹sӧǶXѰA|/%%Aꭷ)e>9v< ss^M궞))a7n6%̢sNΞ])rù1jڰaC'yG<8{5ݹ〮YԻKѣѽCMS5k(N+׫׼yN@4^:ßzbꝣF~#o (333'g>Cv{nJ(rrjy]{iêSvn~գhvcIN,b&,L@qž׭[ƛol-[ȕW\읷1t~'N͝ne#vЎ#rvm,qIJ7mݲ5}?qR`:uEG!LO?@~2.,x{nw'{1ǔE.I2]dS dHry] U"ի7_vYsM:O<%^kժETdVB OȈ+ Ʌ,{W˖%qQw/5 v윰/ >FZ؍rqF$#w9iӦQ}|M|avYg|!w7^x#oʷ mz=w ebqҭ[;ew==ܧY}WdĮgcӣD*uDCzh^*s̙ԬYsB7]xS١l}~ãjԨ=zL}tzk׮UV#Ğ,ʉg$--V>(?F!gfz$7=973Ƿ~;ϰMٛB*Ƨ R"}PrRSw<\(9#8"ƞnuÿ?w(+>â\1G}M7 ufkg{|{W޺wau3J!:bP\}ϢًcOJJ PqBŊH6_/Bj׶mT,\(yC~땷z7_ 漢ӤOA?=TvP>,m^*ʉΝ:]WD'9; ҹKc0k_ӡ}JڵˋP_q(Qݺv>zhײs˦~wB φ,~mql;cɪk_.rcQѮmWFxzka^U?kS9EOi޼cP&^g^-hо*q1Qq8pD$C-"++5kܸqcشiS5Bq9"v#GE|-8l >٢4IDATGgEE✷={O~ /Fn]>*N<1*|w@U.%UV}ȍ6~'--55N<'؇|dgE$NTPxcdżp•ʈ#h׶E?VE?cP1_~IQs ażpƞ?ﮍ_Ķ#{G3;Y Bhp%wyOU6K=7.z]G7N=wam᝟?b5wk˦5{Y̞F~Ƒ0X{,nvBâc&TY$S;*~>>ۧw*] Ν9qOaH,mv {68KOY;wV"5Oٸݥ}Dg]9E'] l`AtޔaZ#M=O-x'ѿiϦN`h4م6hsBe,?OB"ءO)$ԯmn:ףcOJJ wlcS+}1yͪl3617I7Oc+5męƛWk6j%gNXyw.G1LɟB2p|67VY m̿y\{h $4}Gp⬬b}oeƌo?699@y۴?1ڽv5́y3ɞ+uڜp[%#:oiF^cJ`[ 1]Vn:ovY.*J@6b;NX:1 msXXڵmRRz߳`U>TQCUVrjӜ_;9ϝQء}Bˆ nKڴܝ:y f5>,ןڜan<4՞yq^O>7lnn[۴Y{Eޠ'ܹ4>yNV{J6wuB l8bKMm/["'''$Eҡ!$'|u%K~fG}4u؟LJ!C}v \}e!~GwhyaޒXGvoiuWry];8oΛw/re9 ae dkf?ƔkOi[ϫa⯽>vHaJ{}Xuj?y؟'/;_7n\P}tG=vk(e戮*'ǚ? Ԗ-[nկคԹS~}/{AjժDbK}yhp魷K}뭻Jom˘Kb/ݦu"E$9Rm޼ۙg-XV[vkY5Jm8@?^^paH8[l+YYY=u5$"o(BNNO/Xء_}$999@1cҷՇz;cc_ku{rʎ ^MO:qMWοW5.[bԘ OȈ+ QG $''砃Z5kuG*}{;2=k\3w=#@$lݺ7-[sԈVRRR~G|3w=B8C~|ٯ~7v7l?CI׮]+VG)y *6[ŶNtʧ~֠AV-Á|PTSlgqqP"E$|a,Z(*ڶmJTe⋍فKxW,XzufP5JiؠAzzzNAB%Snw B$GEmTX'OZ7=C9$ڵk/_|)U2c۬_ѧ?<@rrrGDԷρY>O:)@㏷l{+CDy/Lo;޻/7_f7oju#GEM7+QrHDԠ~p sIx6mJRȷe˖Vj(_)?ImOBN:jG+Wzyw9'kٸq%^ւw5vQq =znNmr$PшH9("dRH@y?PSΨɣ//Īժ~blva}k7]>A*-[DŒ%KT2+W?QݢSIK'R>r'z|Oi^wի?PnH~|9Q1q8p28BY;z&NR󈚱WVZ{ IJS-g$--V|g?pqNNNN?캅XxagODT0=*}ﮏI'oذ!@ "IIZ|{zk0ƐjP,<}롳/wII%+Ǖ1IK*[fRjV'dV?$ SW:bLۀZ߭uO ¹ϭ^zog<|Hɾ}zG[]t"7uvou`R@b2jyJ=Ͻ?8/+Wkw)2y\;KݞQ}u}KVmD3ه N\R(%u~g[C>?u{r~T`^RFgEQѢSv3<)טu!sB^:(g/݇ "E'O](!ܸPeS "ݵ룢Yf{uBJJjiuwhL;ahxrZh^}AKg.' :T?C6(9=^|=P)ɷYY%0(gn*={O~ /FMbEڵCh 4.+]>%$m?_%ZJYCòf_׾s4(&n.uOr{O>]L-ċ*=8mᴲx\E{%Ua7Rvv-jVB.l~ӡfp%;z#?IDATn١e]:0?u!C\uŽҵ˽|rدCON?oyJ.CGu*h(VY;_Z6lPΝ::{g䔔}87vb_y[o5SjO99v< ss^M궞))a7n6%=}ߘ {TON3t 6hƯg~Tݾ>7iIأ?'9jw2R&{ϛ+nezҞe0׎;XqUj%HW2r-%9yoˡ__".fgۺuB< ?u_x<5Kuڡ)§V% 'ŕYznMiSNN-4kc~ϔԓSv;aU el݋Y% [[f]'IsJ.w:x_"$+|;ocN1%6'rOdOGeҵ|r)νY+=;;wTvLW^my7?3hբ#uEF!NOm!2_ %vARDt3;|8"/=sK~'Nne#v8"gƂG,_woݲ5_71?]׹)糷}TXz#B%O[EZh{E];n~ۢݯ^7oܹosU^}?㔓۫LYꉴDk鯬]ţs:.M*0Cg^Ys/,}aW@ֳn)d'/IYw`ʵ]>kK<9?R#cO>$6mvM#c:Q}ŠA3^T^z_vYsMP &Nm{JVyh$"٪UPr=*aoJm=^wX7Yy&IQ  {(+/b{bo셊4$_>c >x+{LW_}}wq衇RY#ɹCU.b(Ly /9Qzm=4zD*翤e/|Zj_G(![nwDu˖-5bus,]4V>bD޽b_(DÜguV2W~t~7W_h;eڣ{PB=*/Mu q]ه>2$%Az*<>*;'"w" v=;״;#G7DɓT)1=kƊUG:h)CQ~ժ3grf͚\rפ›?eӬOPF?cУ0"Iգ{䬬X='oix8.`~9xNzWNZ,KwZob3SN{ꩨvکa}Ec>n %g#(`I*͛EŇ ?k׭-[hѢh۶mq /G>^ywPz>M,Ck %g#EJ{nψ@eKs%<_룢]69/k6 puw Volïc';]-vh %?űmiD{IJSCEЧW2V|(s99yK_ӟgEE}·l7eVVV(i5kܸqcشiS5u#b1rT7BKJJyÆ?yd=* w;G!IJҚ? JڵGժUCYFXdMn}M7/[cbB}S>\6V\uCuzFlISx2 m=9~JAEH6_/@bcvr҉MfظqS=wmH(>+ލNT (Iw#h߮mԣ}bW1H#O*~>I?orŎ7jr@nm&"HɉDE zJ\{KKm|lrLPٟ~Աw(5)"@%KxW,XzufP5JiؠAzzzNAPμ>?]v:(%= v_jO5T9\j.vP&, PN]+zŗBY*3z{}?Ã$ ʓƟ}+rrrBBXx):rPiJR>x [r!ʇ?ʋ/2{ᄚoGqgء|?wvvѤ;' u`;W^fW?^>w'`QUǿHDlj ("e\Ԭr~oQ$*3ej@`V.R &+`.;sMޯ<{Ν9*cVڤD3;|8mF64"`@Fw߭٧'O8{T3'L 25mo)ruqO-_!0]D$4nhSh?-)m]/4յKعkt!Kc>dRy뙷Fwս[7'w+m{-C=յk~D2+z0>4D " ]QC@e͘nmmތ0us=J333:eĤoǏ.چ.edfMܙ)'󃫋T۵%&T8qR-lmm˘f dbB5_o>2*vɏ7C֯o_>CDSD^׷Ҿr@G\eLIP։s~gЃj1>4D@!" )F̏Evv$x}lP+j*&˜"1j1tHPn[G/%E|!0i-aӦ͛$lڼ2._cm-vɏ㓒dd߷_)HBYUgkb/:pдII'z@@D`/]|ɧC _"EDpBGo߾Cݴi/w֢E 6mH0&yyyOQ훯 ܊$cWũQf 00 " ]QCе+W{jiftR.edf 7+~=zRXXX|hQZJaLɠ@&&jeWEGlBttt5خ]ԢK. K~|$#$;;;{;v m0YYYjѵܙϿ0wLk֭}w]łΝ0`#b|hSKH:}Z-T˗'N#~#=p}ʕ+Y$fM8yR)8&w…>߾}S?ž K8+9ߞ>w">ܸ1aŲׯ/0iw' L 51E$#cbP4kLH&%'W""N¢ÚD`؜]c@O +~hJ6٨333ID$@Bj5{'HJJn+z+ClX@>Ҹ:*ZA+4"NSD@ ؠjUCʕ+oZhA8Zmӯ]&0Q<2*J*$t)(0@m_m]] WcWzQ005V-ڽ{uUÇV^-0Eׯ_9PYKj@j׮Ajqㄉ+Aط[4aЄcfucJ!SĠtx/N!şŮŞcb[n`iZmW _Y'LLشI64"I_ߗ_ck.pVʐl│^~咽2-%~}7 r۶<}>)I_Yá) ҇jv0IW~K+)Xni_'էm۾`;?ITI;.郟cCRlspP9x7^ǝ,LD>;CD 1sgwޗңCAOF|-[8*++K-:tPCDVN/9)K¤tб}o3 H[Rt~- }c6hoG#Wє;tqqv.3Vo0*qqr:feM?2^[*u'zz͚投+&9&7Ǘ}lKqSVnL["\>y6x,VŁ;9<:9O1{en\)I7?~4'XŻ vS͛ڟ"@14*Yfj+aNik%8]DH+b',HQGJIDATm\+PIf.kSǕ{ҤM'ozOkvprV> Yiw"mm PP#wR#vI#FinY߭4nNUE5yǟە}K`۴azqhӓSD^t]|iDh?$Qk8iLIU[n7 2<)gkˆGjPim bŷ+L&%,K=:_Y [:y] /]Y}"mcz޶9QYyU Kڅ>LŞTŜ:~j+( Hzn٧Ms~-HV}YTܲUSn8q\gK["<=赲ׯ_8\9viӦW*h|h`Ҍi:$@"j׮A};1'd.QjDe#b|hSK$++k^~5ĠE==jKN<)`It͚6U_nnnT~} Ծ_xEmmZ?r<=5Z=իxu^'@Uٽ;I-7o.0'QCБf͚$"Bgf?PҐ9!auUZG;?Vo~?~JNʏHfL mgdfMqwIITQY&̝`8ț[OtfiiS_JaDңsg cHؠj%}dZ'??^Co;|8MS#HB&ïwﶮ]D#г?Jdćm޲ER s Zs/"^.?ڻʝD)D.\뛫u։T¦MD PݷO*u'zz͚投+&9&7 k..j>~lilWnӸإǂCYnZOS)񛶏߷_)Fh|h,ХiḬ5@֫[aiťsn;N?]s9iX}=]$}sZycna.5mdYKbof,"ХL;f~aDwꕫu,mW;Us7 qS>>Hӓ0sJܭJ;&w'מQ/ wƘ @,--G4`_JWWHۗV"KII].$v[-O[D:L>h[;9fm])js{b֭0`tt0r͚6S39}=egHcȲ\/m]l8r2/]ֶ͛ `XhTFw;99uێ$Oi6%AԱ?H̟BZbvxT+"P߅wیv~-HV,>vkOmy}%.A;fr_Z`H@U=Esssǎo/xPui{qVSh퓖ߜgP|̨ C0#0wP36}uspl^Cn?j7N_֓'N,j0r_C7!BN}J OVfrmo=Z81" &N:}ΞV6ܳcu>V'%$޸{Oϟ;v6noU˘ɈHBY(/'' <4e|_/WV-[R{{{I蒣)Zp_{eK&NhذICC`X/MgLk)kJ r=ƁfL|$H@{'O4#D$t0D$K1j1tHP}HB223`Lɠ@&&bLIG{(Хj1>4D@!" LI,L 51E$#cb(1E$323XhZNP`l0k+ka5Ghj+V8+waouHi3e.N7Nnt[ w$ JM֎E{)_,׮I=/O|vZc]HoHaIB*F3dbNm_GhfG4hͷݙDI`f HB"c&0]7,L*8PfL7Y)*eA%@'HB223&A'tҬ=9Q;JZ;}W_XQ wĘ L3­#LNwgB9:^9HB\k3wIDATޔ,~7cH:: jqlVsl8ݞ]iL1E +eSD@b'[>QWT 9SAlnb<+tfe+V^tYVw`fGՇ$۸~%nެYޙ;Zs#5ҙgN:|xxW6]4iX] " ,.^=qR^|^zE^^_Rz{PC啸s9b`"cb)+]f @K}5ϟ!3eC6i"(̣8׾NNy!LJ,+ 1")P̏K >Уsu0,tʥMkujYJ]ﵳk"%PM-:.#?M4Qfq'RP@GutҦ-[պ__?[߀GܫW}<^"" ]"d2Jq_V-[uY׭[W@?fG."J;)Y-ڵu-'~M7k߱GO9#(йٳg==={>C=Ii1"Jcd(2[ }9oJrÇӔn >gkk+$4lh~=,++_}zA]g9 0D$K1j1tHԥ[v1|}Z:88 \p᯿8xp֭ғ/ؾs0D$K /577S~Νݕ6$0G<|2o-[VG22~[Ҍ)"HP0'OIO?֋AӭAC7mެl>a999 ]%^m@N8~__TWƾD>B曯YYYN!"K223v|ׯ_W 6mo[ {̞Q999PjED@-YT-Fz^z{X[[+ŵkV*t@E>sjݵKAeuu*صkР!*CCPSD22:F- $++K-,,,ڷ_PY]ɬ'SD2#3ST3gΨEjժ%,Nɓ@Xh@\s z5"Х@@"%G{;| Лj ZU%}ǧb`E@Q͚6UL07s8IӘ?0x" ( sG{5kTt*5Q\nG˨mVkiG~~dM#WT#;c &}q-X^p7,9v( V" ]QC(Hx #3>)E;9Әĥ#R>UnyWڹu>_3z܅c&),"Gmn[xUixL[-Ns'gf^L%v\~/ IRFfL8&unY}{‚]7%) bRaI6ۄ%i DZanRs%$ܻ}5vBMr)|h` |6<+.n,ddFy[Ҍi c;q3n^ZtQ:jC3]xԑ_,؝6k̍5W/N.k׮}]}vNJxҙgO>-Tv7+Wdee ˯B p=|%wHF+ǠLiΞ5'N1"Ą5WMPrrݷO-4iR|+-.\۷P74x\:طwvu9}S-]a>=XNu$#3MQ7VT~} W_xEmb*Nj.s(csqgI;SG+oŸtp& z.kVU0ݼys&ʘ"YfjD28quEL}-ٖ++ZS^^F#;v krOу6 +g~%_ptp,W+L-Μ={GGGg(LyiHȜz YԷhNi}FYYJ[l1zԋR ΔVi]??|\&ۃ_m'@SIDAT;̖$&a;ERR@.^.^ʿIΝ+%,w_C_`=#֯5kԗ.]RU5)?\7SӏYN`'Nc&^^3;Ss ɟNLu3--}+I~ԕ&Zqxl@T׭߳wRԫW_>#W\yԺGB |K<ͷIUCaޙ2 4)#QQjLI޽ۺv-g̫ĪƸcYYYGT#7h@tdeܯGz3fԪU_MuLKU=Esss߸qY:ϿPSήcgIb8"=&hjt:*::''G֝ݙҌ[+ŵk>_@Ogggkޙ.me!Z SD22:Fmv7N8YPN<3O>͚6}7Dw-_ z@ U^{J-vKpppZgEEPc,]C_Z^].JBڹHԜӓ7h +k+V*Uw&mhPORR7'10WV>MF¦Mj܏(cHfdfMP#}1j=o|;vTóKah llڵK-ܺ5Ne&ϴM)EB9%Y뛫Uk:?=tu̙ai#eWrRғZzz.>&ɷZUbwF+aRxO[iaNsܑy«MKK#GxO>Tj7ooaLfL]P`Г~y]x1))i(yKcϜ= yNeeeEnuk{'qjzKw.刲*jժձ{ǂ9!UN:}w6fܯ{vy }=Ux-[wh]C-F!KOOj:wl'':Qu7S*zgD%~>#-+88sVNN.!*i&C,[ ڶ}ӧ[w?& zO>5k+W*MsLn肳#"".^X|*C{-,,lmm,-sI^ʼ25g[vjV.FY]Gۭk*˯(MM]iii=_gΞurtNN֭8xifnnWRwpsKJN.]]jպm]h]QN%D٣pUc!%0Mtܖr3"8wQFgΜ)}ȱZ_NK7SNܢy:uH_331F4Y$KjiḬ5/ծS[¹6R┐C흴v.Ne\ʕ[s zlO_JE GTPzu7 B^Us"/0}և]L3iK^T;Yfni빗sOIߜV5iX5s9wF64"0Jcnj޷Ϗ?^l;4}ӵ/}EӐ}o,~pU;N4~W._Jٱ}_~Yk"66 ߟ=3=SLUrꕫܷ`F!KOO*bo{'nKUdE9țP흋2hQA)fSn=xW1ji&L|4zh巣W , ceii9rp tK'N 07o֬_VGTݩm:jrpA(gGp_;p[?|sss{wΞVd;yD}}))^]"m_Mr+s"M=jғM^r r KIM3f1|}Z:88HUhg,%%YdvIm%wnoZdeeׯ_w w)J+= YjzvzOB׷OcR>2R_R{@q$#svx*؝)DnۖWEo0w\|qu~=k cHM޽ۺ*E)ASjm]ߨ\+{̞Q999RqGι ^ w@,6]6>bH:~j)j=r 8ϿP.mߴDw*zgO?v]^ܲUv7ٺG)+SP1E$&re߉ڵkZcǜ9RRvL2=Ŕ]2W8񯅪gYOX98}"ņ~BgN8)TR7k7(m䒥Kbի'S;y2NV3/fy$'N m(reߡ/4F#? lw^ѳ.~4g<9Ʀ&UZڵK*euS35d@ȩgrO  l+>,brKKy̙Ǐu.]D Δ&+3KɟDqN.4ժԪeX,;l6رSug@:vѧ#Ǔ7'cԅ >_ͥ"ԥjW8qݵ˯V)E։R)uԉtRƍ3fzc$1uYYYGT#7hРd|hP mՈT#󏘜z<1[qs񯅪Q?I;qS ?uR7k7@oE@Q͚6UL07;vܹ%KrJN͛5kҸW>~<ͻG_yٲ似=C'hkk+&o}cgΞU7~ƦzCD@Q:\3}Eܪ+W(޿){v,\džmK; n}_-ZԩS'?ٳfܯ{vп7]x߮[lڼeoر\ȫ|P"Х:$@]^zT$nۮÈqúu>|8M]JSj77d1!fffSL4qBc[ZZZYY PYD$KQi8tٳϜ "wpÆ FtE }o I7M͘^*{;lMT ]ztR)"Ą@U;VrZpVm=WiR>2XWll?{渐WȨ ~}g#j @eSD^Tsmޚ/%qCʽ;yDIMu鿏Wڵkk'@e6ԭ[}).]:z؁kJ*fjڵk `fGէ@1]z_O<)-_)nݻ pE@ɺxyɸ|r^8s:n\@?jcHFFǨ!@8N9s_Wٶ}GέZt@wpE_nתeK1E$Wa5mzB^srr Z:3gnHcC]<[߲֯EC[ZZQ{wZ4o\%@Ui֬Z$%' Hݺu՞&M k۹>;|HII[["4cE/(5;gR$%%'X`D:wuiyhz{ﵻyY`Cl&1(Hzt,啸s9b`fG)+k8-ЛqqC*EƍnN`}R%;[gOKbyW1_hF²ACBۨ:~{uuUSO?3|di\ ןzftiӦW0":k }߸qx}ĄM(uB=|}_~iǟSyo~ۚ8z}))渐Wy{60D$K1ׯk:$1a3oܴiǎJ/%GχׯO7o] #aӦ͛$lڼ2.Sz`HBN9?(ϻaXSOYV\rD;xۯ` )" 0l KH+3"iiiӒع>5k3g״II'zFG{ սvši>'<-[wNxB%Wm;v*Ν<;=rJ_nnb^|ncLHsp 5YRGPE:Ѓ2_66 }y 55kZwϰ @ `L:$@`ڴܳW7n <`矟8z옺~fLɌL1{kgff֡}{D=vlj`XhWv 5kZɯZ8;<1pñ?`3 f!>~s>ݽ="w"=.\ -bVsZ4ݫADU…  inݽm[{lmcvxZ 2+qǿr?f[Yۨl_hD$eUY$ "" LI`HdLɠ(cH:: @960AD$ 2+qǿrưQ_h&ƲACeLHFFǨ!P:cHfdf @9#mGQ_?4\s4zgnL6@5 "iKta6bG;Ӥ#"Gz(^s [-G]3L=$fJ+OsA=yA<9 @{"g(S(PLI(. }"qVny%P㓽 {"c'9? >o3+I327/?UnL@l$3}v`MtRsliN_5Y3Ϋ;#Θ;4LGR >)$VB ^յ΂'(T"aXdEK zӗ'zwQ%=N5XfՎ/V/JR蒸㚹%S H1{ZKwbm@5#0@ta$f3QYG;2դQ_x ?Ef0dMyך" Rub#h:bV=ڦ`35sA&d)#u҄/,//s$#S-Em|n#¯zW5<}tEWJ8IБ#\4J6;s+#}:엓ڦM:LV jd HFf5>sF6M*3`ڴbi{AFGѿ< yhqNyh/@""i(~};\|y??ޯIk6IDATY^^^;=#5us:ĭZ[nVli~=U;_]xItrt/SA,4Z4_dtZ  &$//VZj7cfe=|5u3HFܪ}z gLɌL1Efff~33>\LEu8[&*999W\[g4m^&Nvtt.T " O $T!"`o۷Nhп%?nOJJ>KsرoO<.`fG.w{.G cZ͖*caauJ=ztؗ׮MD^<[[[[aԁZתբ/t.P}ja٠@ժ%>Y'N?pp^&7vZeHX]J|rNNY2q|B5o]rEB͚6=qR$''IU|Zԯo!Jȸ/.*  ZҢg+ 9?cwJOnnsϿcٳ¤>;O- (… }}uM^ʥ}+{gWgi2dJvη]~7nLX `lHj4kLH&UmD>d^a>C07o\E}v>~A~or-[=Ep60ɷnrOZήJ1GaOK lߙ `TXh[ݽZ$%%;xФSԺo(=#PwQ|}#}qqj= 6,|llkz9H\bETcHMtA"2*:++K ;ァVVaaw5K#ַ_r3rz T kFߝ>ڵkcH::ثMtͯwﶮJqgCu̙%j=aj]W蜜pVzQ005V }-[9%=qS<]S߫[R>jj mkԮ]:~ 'Z2NMp6lܰ: 1J)]2Wp-_ zUE#vΝdUHIQHN)sNh·z "/Qy{xuݱcvE'NeLbqLxyN;RY[>P9"nn3ܐ>a%G!_ *%=0lJFUcCD;wvW}))=z>dćm޲E FVVZt֡\8;IڻrH{G'ȇZ3gtr\zzw۸at QLZ11j1tHǯ+?k֬U7W\41!>^t M&R+54)w&_ˍ.Rm"I)O9--~TJٯ^A@wm1\條>_캴`"{0OSٹ~q+k =z8x޾cݻ?h,jiḬ5KKK˓J[n;yG.%wtvvr@M\PIͶ 9J9W )K;C/cǶl >ǎ;K4v}{È>>b^ZXrv{>w/ԕWR@eمƆt,5=욾-pJ;p߷\O0ƴvU9b<3|DC]{wjrpA r;)JJJh׊e?ׯ__ӢU'O*E6Hh'%M=jғ,) w۹O-7o~ho?p~;E4kL-RwJIٙm\tʥM~}N0~KFnέF<[EC֬N>v=G9IԲ;OcJa!~;PQ#&FD:EFǨtI- $"ٹsg{{տ+主Cm򚟬Q< 3qs2 ?z:oꔑ2ڵkvM-kHuغv?5 m׫W_>OfpssSwOvAbŷ+N?%Wjm(׳ەj ~;1|R٧j:~j)j=r J,jYV/.WR>jjL_m]]B8O r'k)iihӓӤ"_>)pҹs]ŸW0vI76n&O8{T3'L 25mo˖Ԯ]z;̑\m>R]j܏0v!"i7j?v Xrѿ60266 JtE-v%Kc:v{ꓼ9YOq!v h{12OsN[sݭ]wy3[B^}RUv͏de͘qӦ;v*?ԣS;t*+~aWaنn!~;1E$ŴX[[*Źs4hPcfLWoFgM2y RAϜQƍIwǏDbO=fZu_PT>~~~vԂj,ڮNsLc..RUoT"8}:?"٨RA:KK˟ Q5mdYKb8>͛7zb?u7&D$jq8-]*ϯ-1ёO<.4$0@yz=Tʾhܸ(1#Hu'yԋ/`v'%mF$Eb.-iܤ^mgL m۵ݼeRd׷Ҿr'NWk֭@,--G4p #;KJ/^t}69Uc/zD3Ӥ6aI;\KbZl38V3P7uu@rHbeG;8C嚓j7Im=39qk4Q3ܩJMcŔ @ `L?tHFwݵk6͚5vaU+j֏ (U(5Q\qdr5J:lvr /r$|Fm&V6IaI9j?J7w<1'{ 6}('^+Nq>i6zd쯜#DBؙ'FɘT|ׄȠw.ݻy+OO=3<[;CK6z=,UHYqɃm_qT{5IJ²&?Y;s:ql[b7)萘?r\LҮ{f&XYh[@&XX#WeɝZ; `.IDATϘ"53gN8)ȧSCBoOiZ2#333:yǛ9I<=+t$f6#fL\8Yӝ!%W/N鸙ɚ|d#)^1 ^llem3lu; D` H+~عkYbΞ`ܪ z51ë>\j7jxXdEK zӗ'zwQ%=>U#eX`e2y(U.o:;z*54&qoXk)8BM^شyKV   T-&pBGl۾]ݴi/w֢E 6m=wsu8~x>~L' 0Ro(GtWlmm[:=j]n֭Z[[{)I:c5m۳gNKߗr}).\/!cHPbbWũuȫի[O-y|ƍ1i-}y^v_Jҙ~$czzX06tt>i=ЃwmĄXXhÆ lMT6Ϝ9sʕu Fa 6oMd8,,,^VZ@pQLO:]0BD$a ~yZ_˖- F$LԢK.SV6sYciiiS-Z8;9:zzz|z>(fyyy%\:$@PFK д4X/OO͈"$n[TѣGG}yߤJgγR?eUL p+5he8zT|٫k#c{v>*J*99Ǐg Fa 5mzI8pmO3][5._[H2 7CrCkJsC{e؝;znғ/ؾs0S\z$h޼P)D$a 5kF$}ɼ|dsaanzٲoγuM?2^_pop LXSOYV\rҔ&;;[GYqsǂfyj麫Q7fy֓}7wĿC{=F+{g۲4;\n.sMMQgNUs/$)rJz"P|u5պ%\X]J~ng dsE<7㿋wGUϻN&:%*B>ծ .mjx׉6ۧ[:%λY-:A9sK\3]:zKumR^uTx?Ziiie[n;yG.%wtvvqi\-Ű5mdYKbt,@93zaQJۘ UlmSK}}5ɤn"&7o}sRiR0e+nYsoܮ2T*N~e>;濬x"P^;=|yMsEM[7EӐLSM^Vlg5D|N`uf7ͫwYm-}߬κXp?Q+W]wN)Y8g>)ӕWR]Z)3+Р!ACׯ/I&KKˑ#+Mݼz~KLܶy/jߞFN9y3}(jp?f"n\PuF(dIwc9"Λ٥:sKif&=ͻG_??.\hw66 _}ZhҦ3G.Q)=ԵwW&T/~!4"ԩO$&&Ĺs]U˘Y_aU/62KSNoΏS|kG[ti9?C$cRh1:r4Wc Ծ=oVxU0߂ڋ*W^bH{gpK,r9[9^wYܖW󑊱zIvss;~4C'Hw_cFZr#+7I;ܹ`iɌLtvkŋE_Μ1^z-˻ye #mb ʫVLw!D!/x|sEϽ3x2&,H̿wպ~rᄃfM/d@ʯϵkRwnY#հֵ[Yh[׷`X\5׷_W^9}ډ$o/C;}5% ΌY׮]S:utwѣJaaaEj"kkÇvu7|#TTSOM:EGޠA;;))iӦMO>SN17=|7"#T]3B߰!Z\~bmi PFI[b>$ݰk>:ii}Q=n##֯/H֯P"" P6M-VfңGs_4q|gtNޑWyuO:1얥˖E>8@L6ʧlZyHit,vjϞBUn݇˖ӎ8"@Ld>V2;2=A7V|whqa5j0@LdfM@a͛7;e56S7lobN-Zj! @,SON!!}qGׯx.;xO HTi>_xa999\hҼyFFFN8 -/y%7w]XU|ʕ}lg"k_WRDrIѢ9@{/t>*ʕّ1|ȓO>'Y8(#oذt.Z||N ^zu _+/Tg}mq#oܾ}P:ڹSon݇yyyMHHzqBHŭڵk'թ&~|$q ag>dcbn9*ZqT;^tS^(WwҋZ P\6Gwt#z5C9/}UoZ4{Ļ&_2p୷P5Tr3C K (xI;ᄃ8ٸYGʬĚGe{J=m=Gzh^ U @ŋVxw5âu.m&,PAD^E{+:'n9*:qMD01777^oj8ʒtPRk֮=M2I(?pA~~~d &??h*W& h=ač7Y"Y/t|SECu{N {ÙY;voN{:@m3ztf. @[pahӥMgH6;ޚq֔ny?D$Hvme˺v;OsG9W_Ѣu%.NL iǤk&6MJZ׺sѫ[ fUo*O=yO3F:52"E.]^5+P57߬i%i͚5μ<'!+'O=,7řȂToZo-&{Rdî]YYӦۺg}V`_K]$7k*@ZG ?~{_u[l2x=u)}wpEJfj(I!.YW_c~>c۶};ժUtK|ο:s{7_S7_&'O\>믾+N8~vbimjպr|y4Rw {Ɋ7VD>_e˖/w/^r]wmܼyKz5k⚈$@UѨah|ҏI ˊqM!-e nܸqqiG=ˑW=_Lx_ ']9dp`Km8):@S&;wxO6*֑?IŧB;CYmڴiJo6!!wu^kg_GD8ཕ+ԩ͛;w=aɒ%EEoU7jթ*W,uoIII8/R_{yUvl룵 7,Z_p8GFTVmc8Hre3KD ?HQUYW}ǡlXah\f z#Z?S%" P\{_{-{?'C{pW/nCxqb…':rTtZ@UrJ;'Ro\?Ļ&vޱm׶::0PN^Zsysޛ͉NcǢdn@rF )))#oFdpݰk^}UkGuTXvm ~h*vG';=--T:G|dʕѢq%" PE}W&MuY"ӧwU^3N EGdIxfm*Ԟ=#㡱IqD}vKɾ}z'L?9@dfM͛76F#<F+/뎄@ :wŗ ZlY错k ;<'TEO7rUqw/ .ң?RDr`WbERhؠЫxѯXHD}Wwut~~~tҥ_sӧf͚}$c>S~|aIDATEիK/mݺU-Ҏ<2bI~~;8ٹS<@rrrRuhqU-Ď{xig<=U>!]$_O7Fm<"@̘:?R$&&>ժ 씈$3xhqڏO=`D$phqqDž0G_5k%Z&M4kc[w9 P:ۧwaѢqžyu_j;+V5^yտ;i׮mT y}GGc>:쮯ל(];ᤓdm f4jp݇FwyUV>S~|Eԫ+~&aMSSURUZp?o'yl޼QyO=x͚5qmѢ`wRI`רQhxɒPv?;|d.mq/E>*|wGkW=_Dh$D$ѶmQdcbO-;T/Z|)/3ni)|sf7nܸ~GnG[>ժɈǤ͛7O/Z[H]/rssu8./_HXWNPb)!j>G-#G|edy괧5O."߻q+WfO1# ?P e'$Čֳ^z骫)OnM1l%æ*egڰq%\5}͸}qY fƮ"awQTԲ]zy2q[ڿId=Bȡ;{<<''niw\'2R|マ |gΝ$cF ]ze]ا﹣rǜW^UѢu;YCRB1-!&m7+I2s=N/:|zR"{e[BwK0yߞR(gM/wGӆ<%sBZjvEUB[=!-%%֝qa/}Tsxrd֑#תXSOӟ=̳çNPcYv}1Դh1mXƩ RҋW~e=~hrBݚr0{M\x53G焾w˲!+[<1_evY3{Xe _S?j++򑓧?}ͨۦG^w1vW-ڵkk']<槅Jo)=z OE=jz7~p<-]3{lA0gKNܑ삥{J햕.܏{ڰ ׳ vN2sA$1LbZnl䙧FCoʟ-et\vY\;ojԥf\zFF6cش?>$<32yjW/HmeuKn%F[J=.k3/]ݭ2Trw/l!6Νn/bOk.wy[o,xѯ6jժu"ĕ-;b݇F勖y;Y$MO)CMBZ(cR--Y/a Ӌvw[#L(ޙzSw}B=oa#+ )u-/r~간R-$ 9fr]wa邥Ѣqᄑ," 5j-/\e)_ 5v>o6ha;h 6vxGOLe1{Xa h5S&|ud<>$-gRxZA˔^){ܥdϜ,dϤpX9${L-9 .(E&'7#ۧwt2j۶MuDIzAȔ;(آzmD*sF.oO~jtꂼK7=e?>p~_5.;', e[D9/²=.,~WadW~{{JaK|WN/|ѷeE>TFԭ[YG$۷k`GwxO62j'Ջn L2uڴd|a6uVJǽn}7.ɃK,xJhi瓼O"cLяN/-28PYjթ*}B[GtI۾a:FM{bzH2NNwt{JgfZSfLsv͛734L;ȓO>)"IlE=Y=|zwY+rE 2薉wOL)33""W" T>Ib b5hݢe;*@X2g.ʷVF/?7D$K'E~cDd(/]k xtms@pE/-'^,씙i}7D$W=ĎUW=SOӟ=̳Bdb)=zvZؗԪUG&Z>2/^2~7_R-Ď͚FG K3J#y/u>0@6F F_K,iժUʲl=z}xY-Zh~DaZڜ9+^_ؘV"23c3|fG~xʲhhѸqPFE*BF%KT?;+wq>_܇{|dD=tQ?4Yɏ֯uvV,E$E$2E}]۶m^Hxr\}Ͱ-o9BT#5渓Ց~#@(Ho.@r> H8):yF?abnnn?>Zߐb'>?+T&D럜qF(XHZ::ݻLO|*ؽ޷yH:h ~=Mk){nj P"F~yy#uڑG|rUOUP,E$"~sKW]}M Ȕ)Ѣe?`/5.{227Yfӆ&5kDm~? P/뎄PF"vr/ݾC^[b߰aڵѺUVdБ9iYR{`ᜃZFIDATח=!g٥Y[ns6mb:wn~o错ʮzB1^~9\lYn'S)3cfǎOnnnXG|A&S7f60}Y1att{o7sIQƗs׭KJJ P~f9~yiӊ'#:rTr@"O??3<=|j=&_5+@yKkVZɭ|Lzg Mze\>r57W?zn.#@oSzCc6UcLyP?`,˞ҎI~Ij?RSKsfTVFBFF5?-+-.}j$P6hpۭ<2ib7s]"A\˨;wPRZp'R3S_An=.81mؙ!+f3%d ׄ}*R.]X2_=cm^Z.8@dK-kߡc^]"wܮd Ѳ7/,?>$̌1oۤve Ey0IJըahqr>Av[׳C.¸@4t^gN^RxwW:qU[,mݷO1~RRG I0i0lvSkL )YJn"lAQ f͚%%%b)"ټYיgF͛KX}l;yy7u{h]焾Zº|薇9ĂXHć^TFH Øw1$e١M{bzH2G"/xQ*OD5k6nZ ?FMJq'7U^B~~O|UFzMyb7|ӵۉ/v9u^ B:w᳞=hΨVMxod +"'Nrr;?IvǶVo/xKO?4:ypgдiq,PD$W=ĎUWxř3kPɇP%vyl|$1f{M. Ue~MIi vHM7/]sa$~~wݵ,{kM7֭kwTbL,m 9k^wQ!KDC"@␈$D$8Kɾ}zRdfM@)hC"@J>ʨT/Z|)/7 TZuK]$O-;\;V^2rP;^)8kHT=yu󟉮q~a݂I=\b)" TIn^S"e }.GnZ|I>PO7}i/˺+'gMޜ5G>")̍pd]"Y>7l{mslrKUW`/VZ~x衇 |$ko<7o6=-fA (͚yovEI,ubų^?~vNNvvNeZ`͚&49*eNgyF CFigDw}SfAD(OŃ.}BhXxox~sᇅˆwQ!F@ f~>k:t|v"a%{݇IZ5kF/O? PtJ￷ju8:Ζ]6p%ok2fa-F^wV[>P䟑3p\33>᠃#EƍkD$痼λ)G6m>p\!.$$$4+t҉.6C۽Κ󻈍Rzժu5ʃ=bŻC;w/M>r;}?z0zs~*IDSh[nkgɠK.V@Kɾ}zGG6LHϷ$''}" cbGfMPL:-???R\~~¾!11]yHsӍ ~爿?j ĵXHUЂ ENOq֬ >v)96mJJJ eCOf7aVg/0윜(m-Z4oNvBu>u⚈$GrssE:}I֭j֬ya+ug Uʕّ1|ȓO>gٕ:ǶnlqZA+Wfŗ֮-Hk.Kc[k|?uXۉ=7kλ)G6nx2ĚGe{J=m}-.xQ-Z\LN܇|5j3bl )3ZϚ ^ ڶm-dѪQf͒/IDAT>]-?KXe+V;aѺM6L:DË>cW\uuN{JW}v}טּ&=2o 3b,"ѹSf6EɒW^{Y/įlW}*`ͷK>O9oPwf`7FIGLq`CtPRM֬]n\GOrުճ_qOy?yy|OM 3bltbRR/ 7Lڂhؠxͻ+WN~ݡEjj{YC7oܰa?OQw }*;[ۋ}yGիjѭcnԩI'tR͚? &|駁J7uHQວ\2_FFLeJd^ڛyj駟~「<̄> >u_?1GhؠO8??kԔ&]%CXSSS;ug̘ѾC^[P.wf}ի#믿nڴiܸq>h!ҥKGƜeWn~gOtz|1cgd TZj}:''^hQ(;|YWdFk\1ȇNG>r+fms-EOf'yş"-x ",yK=DŽ*g…ѢM6 {mB[3erN5aO460%Lm\vV> P9sD?͛~wH&u8'gzE=~trbb$!y>dck?>;wٱcb8iչ6XlO='DO\Y/4mtg/*Hk߭^Og\h6p{Oi1:۽_mњ8]Ɯ0z햕 P8_:=q]=wΣmwxۅO}vͬky=Ň۟t҉wtqKo+o r?~o{n[ [A<0 w* ˙_ٛݣ1}nެi{tJ+q~-M6,w{d˦>x_k8O8bŻoc';w4D zSOӟ=̳çNHѵKhr7`kN6oؐv1[ZdI3c61W̺p9z%_?z0赑[m3y蓯X\M-yׅR:w8tk֬irH[vyg4jp5#ߔtyGFhժՒ=~2)h[ZQ  yN~)kCn/^1g-(C`in yaaGꫯnݸ6*mZ('&ۻ5 } O߹Čd-O@ ?xmoUcLyčYWYsz%ofݶ㭱5fmAqH_ 0k6D֯_xsv}Ͱk>:iW3.倰l~? .s {5 <-zX5{[իؿEBHK^B2R2SCVX 9:²RÞG5jxD$I.x雯Qw-q6뛐ܫ w{Ufd~9]m\'crgKN ׽zN}ޫs&MuY噾:۽OT0&G>QQ^;:|Y__޼p\_ͼ~Ks{]mգjoJ^Χ~/Zjdˎ̯^!N-Y3*+#}ܚmy}i(_}?2ibO>)mjժu"#POj̾}z7oִL}SFͬpat?o3mz03wHejo틗lb{L۶-ML}vA2??oͷz"LΘL2℄S{P=\d\_,lb{Y2eL]Sp.8o Np][؞uEfי<Ìl@K.n߾ֲez͚5C|y4Rw,auA;;mw7ϻi_:S_h12 Y۾)ǤxcE;kʕ.)kCn/F%?j +째o₳2Gق[ﯽ-*!!Yf'm%/֯uvJ`GEY[z>!c {[ BsŬLk\Mn桂y=ȦM7~Nڵݽ|dDK^]-r5;Q,9ݺ7>S=vzi%_lhܸq" M 6G5?{W̯ &~=P,e'GVf$DN&bK/N(qnwa('}dNϋfg\}Bl(2LFB'-Ȁ6 SyE646eJ_F'ޅ< E.dEsa4~KzuYXkEΝ:M8nݺak&Z*":7L=sm>fj12MĄ޹K#ڵ 7I`ojyNm\Kw["r'A\|=翮2EPv(ܾS'b͖o1Z$%%%qi~~E_y敎?*a#y״L?9ckF6= QrBg_]zFp=O 7m%8 }F  ~-"ŷ~{1RXaäɏD|Krrr('III(뙟}T7L;;53G焾zhG5Լu 7I5lެid$&JLLxE'P SNϏׯ߿_Ύ8֑"UCtP(窱>]<~޼ _Z70hQÆ_{mH쎎96m d…ѢSN\{_{-{?'Cigᬢq}c+ N@ٵnݪf͚y].)))KѢqB8GK}ɝw7~];vضkVZt`{^Zsysޛ͉NT I2\tE!m=9s"5qaߓٙuѢ]vb~SRRҍGDxURBBuîzU cm'Eƺu-.](ɛouOLMI f5CP}Q=|$@EJW^_|e`+M-,ڵk6ϭ}W&MuY9O{uO:1Pl TiO=WhqӍ6Rh&IDATMhWzN32@`_$n:5j)rss:oOۢu"i}Fnܸ1#>jG߿wVVJKwD$8$" !I HqHDC"@␈$D$8$" !I HqHDC"@␈$D$8$" !I HqHDC"@␈$D$8$" ġj;;pDzBi/ &91 1MϡS~*KP N⬛^etEO|V˚ a6C篼=(rfkye*|y?Xן4LXv_ U䜱m"7N;'$6??aQ)c+Zѥ FA)2@*eDr-"NK.,ګgΖdvVuB{mz(ksEN$֋^*R)Hݾ2?bjW|/ 6NM" nM;=¯Ssf,ڦMzHeH9>/??o|ς-Pߴ搩={o7ѥyG˂'z%T6挝1L| Om.ܧ #IHl"I0fۋ.o:`µ_|v-/_Tp)C TX8"5B)?g̛9͉?yx~•_󎭱dݴ~Ge6CΖELFz{_*N7MKGiy].I”F!el|y?`ǟԫҸd~ʥ@+.U@wD$8$" !I HqHDC"@␈$D$8$" !I HqHDC"@␈$D$8$" !I Hqh>`GjթjEC"@␈$D$8$" !I HqHDC"@␈$D$8$" !I HqHDC"@␈$D$8$" !I HqHDCB|qAz.bS_*&^"!ؔrMopdAD$sۧ 2))4Bxw`aE+ >s^ΔjkNw||=VFS v<|n8"% N"熴m҅u[6}K'戳qZ ?|zWuX\r_ܗuWΏ4޵vxo^ɂ;Dz m[|JS5w4|E_aItrRENAM|ogbIhǔytv$eQƜ9bh5wy#9ڔK.-npK;(%̸{o"{EKouuh='u8yC|D$wEu%s?ݔw[m~UrKs[rwL/z)[.꺛#xoYI[ZHFǖ/@^a[>8h{;3/Ev oJ֖ٜ'v8-2|Ws+ TbR֖`e_f[vЇ2yq[epKȭ ȔK9∰ߟ,fm(GC(H{}uzW]aahCO[)ɚi"GrDCθv#)man &۲7/)|ۓ֛bKP.wxO6X1vߍ+9vt8òJ 轻.] P|D2UFcqYvs;e]CNA2Ϳ3,\ڵkO=Go' UVLn=m%8=?HNNn?1hS',[o_F'S7;wVl @{s/uduA_O߉:=GDona'P%%$$vp@dux~߾abiG U5Tm1v{d͛7h6TIHPHRf"T}þ /̟??;'';;'-RS7v 'v;!{C,u?qRbb͚:?K}P)N>_t+.7-fhYZu_}hɇ+/Tg}mq#oܾ}CE>''7eTq EvRh馼ݵ[GWwŇ?УMz{բً&5xoeDoG AIbAw|dfGL*U58*2N9}{\U{F>(Zw+V;aѺM6L|v"𢇏=W]^*EG$xѢvRGXPYJb5ix*EG$o0i#jr5l;&Nܸqc*^G$N)\3?vRHNt*^G$,\-tiS228/IDATf\zFF5%+~[P<"-Zwj]̔vLj(&mBhڤu;zuxCTo7vYvx*55yf/ 7(mZkf攼eb'EF(Gų*ī HfMݲj-! 8u߭JL %X#("{⛯)yQϛ0]_dɡd_u-͚6@U`DMyߟ,yg?G#Żo۱{2][.ѢOבּ*ޮݷ{qEQFb塬JE-X-7@ŋEszvD݉HdvPرj(%v~)/Z3g_]zFp=O @ŋnHJJ:y"??s(/T~4߰h}ԩSko9*:PFq?HQUYW}ǡlXah\f TH\{_{-{?'C{pWn*E8GK}ɝw7~];vضkVZt`('E/-99n'Dr5Cw%%%mڴ)R|'u)ӵ##oFdp]3_}U(6DeWq ;<'C~Hѿ94in\{eB8t'n<'"3BURꪅѴ!bevN-=zt?Ig}VHyW޽|dDq@FZyHi'aڳgd<4PU[oG#@RDAevdco7k֮Arrzjթj.yruM9$=$G41>Z~Żv,H 1|y+"ߏζHM}vwWc;UY]Ǫvd/.Z`ptO)7\ünLJRŵkNS!M?H>`GjթjӳC"@␈$D$8$" !I HqHDC"@␈$D$8$" !I HqHDC  " !I HqHDC"@␈$D$8$" !I HqHDC"@␈$D$8$" !I HqHDC"@␈$D$8$" !I HqZ(_L<`Z^gLHH4H`nSSFi١}=epz QmtJzep1B6"MYחQ-/e/sMӄs8T]$93 uO|o=z^Z]I/.6zhnɉEU'K6xRvl5F4 &l'stV N.lqenyi5\;W'Ge/NկM;K5jojڨm|ii3wKN,Jk‡O[8vp&~1wϡc.+rsvzh-]>5m{ULguuЎ3=%oO}}8/qԂnH>;߭{ijDUM=^1gZY󮈶WȘܲxI&ixYu>2>kT\F u3O_󮡵68'v8vBaӽ_KQW>UyTL@WD# g'~fe+;*):jE=JF.D$sH#OdmRl,HMm*o->;}s-/rՋj zZ܉k}i9))YyW14wcI貝=zh;k;dbνg?g9hz"i?K JH򒂼YiG]֩Wٹ*YZ<;wh6)))vxyeϔ6zQ O8*cW?6;{cZNM4ҌcKʪ׼N10kr/TL˙6g'g ] XV9=;رa7*vM?7ݭCUO]qCP@txWMVcֱW7 5V PQ=5qцw8ScwGnmӉGƴ)({{voj7uyUgV9ou{T܇N#"Y՝+x}=j,~]#IYUqEa;LxGuѻqw,#^wfU Q(z7dQKc0ĈC=$YKHn:erbITQuL<)TͿkg5l>2$x۫/}7%6hW.}RۣتQxEÄ;z7{8uTU3\6;* 9vCwzrDn}{OZ;kA(|mԙQ_lB]OTTTԺ㓏օbUƒGeX~dNtw;hO^+譮5x ;;~g'? wݻm۶o…՛'prJlHp(k moڴuֱF E{.2/?]zOL&u y>{Q%K^vU+W78Ǹ[?4+5"TtՈam88/reqک}wffeF\=xE^8 O:ē3NNMmnƛqK.bg;)>9<hB30sb|5$ח" F[?}6:wta=M[YUD)?rɒ]uʕ@y7971?a{jѢŶm-[3r{&R***jG^%[kފ?W,"3%3j\{Bmv}/B2[OΝk&wWkY qUY8Kܭ _9#þSZR5+WԾ}GQQ]N8ߏ5={a̘GvpjN mך.iiKE۴m_zͥaHH=Ѱn- c/qG~RQsL\lپHI߬[*fSװiӦXs?~56e+~pEܹ3C]{5.]@D؏󗿊۱cU$xpʕQ{Cӻǹ?ڳkԾ?Z]򍋣]6Md3ʍ o ?A]@U8}jѢ/W,;NȈ5> "M[sHNtf@EfedYXcR23S2.- Pҥˆ E }KQ밲Qc.'wwQ=ɹ9&ꮨgr[l @24kz+EcZ_S9h}kJFVYkʠˮclxubxJi9 Wsʾ]C2wעu D5W;vL错&H5'?cPSl%k__f]3{Bڭó2bKw~h]~Pa IDATP}xNA6lpkoESS;gNb uqy%ƣ9i!|bbnxAvD,psʡW$rMW6Ůwg`yA=oGѥYykr!_}`9@D0qHUDOߚV6.smslh)Q OQ\\ySJ|dުn\0*Q#O^#~Y=1;_&GLގ;uڵkF3{929tjFx>rVF?*wj9tj&qFya?Ld+E/y4%1׮}߯߂/<~X#졢!tHD⹺cƕm/5.-s\WV#:;$gPJިK=s鸑OW$6.ͺfn ޫruA깘 ae+5{$b;cɒUFD{#C 1.wk[ܗw똢[vS:t}e㸒kMpde?{Oo刭GYظ& _QQq mn~Pz΃޾z^aU^;uluWF >'G];;o^ktiu k'Q ֡VE/led;K~-sWS3'Uغd.3:oS6.3Z7U;H#)V2?B;אdI1SքqwepZغ'PG1*ijϿOo9٭n6:a֝!J?v]uH.Bۉ%%'bs)u55sj&nmKlץ)e!-*7:׌Zߎx2x49Kl_.dz#o';G5.w[h nڀQg^qv>^иwR]Q.[^fUjq{7TGιuv渼X;z;؎ƌr׀񺒕|PhIcSLjYWSVGq*p >.~ vذ??q+o=_󐕳LIQIر㛯-PwEo;ĪH.Us}킒eFv"vkZ|NUn)8rέi[g_SuHјyeyyq FUL(*ٔ2akOTs}ZS nj[ 96,^8Z<*fYv똢:?zׅc9&j(^Wy>2fyQe,2-cBr]p_f渪[WVe[E3Svo1Y9>gqte|a!ʾ?Ze;^0=Iu)3oMUrr*wעx:i,v:U]Ҭy׌sK<7;%/6hyQ);|[LxeɎJN?lDsU?5)QgScZx P?sP|dјlfµw|tR}'J-~zYf|i9#+ni G;"4;CqΓ8kaTG$rJBJEEE;>h]# \4vڎ/bqHU=\;ko^HR}?vLc~zu.p}͓QG:s1mP՜^tFF\kL05k@)g:۶mͱQ>[׮$tq#I!;XCw/,ڿ$TE9+ul}z1Y ֱ==)95룏>UVaZhϯWWF7$ ]}wڶmۡC@ExyCXӭN8oPS:=?þSg_9 ;Oʺ? @ɟ^_Sʕ3k/^y7C#˵ ٭~gqͩ;Gfmڴ檫bUyEK/NPECYs"yp?klܸCUEEşT.C|/});jNɘzXRTbpH*xokz+jg9%%%%;jfcn]O,X8O!cMd◊;oSf9sxQx`C(/6mZoܸ1js/Ԧehnڴi/_6g^#yXGV]t:K] 5I'^r?6_8j*i~ɘ-[+WUnG*b[EEEm{Oҗ坎?.ukH.WwI߸qSΔꖒo۶mHح*VuqIHIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I TTT䢊$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I xbFJ cMyS4]|Q^im*Gfd]R+%%+rHinFO_61'S6iSV\Vmj{X0;Nif6V8֓)/6v`&K6nOLOHZuЉ%a(vfvSeϺғ{r/嗆gة}Tp:IDATi/ͫkGt؅YtࡵK;4(e{OUK־|DٵG'd%1X~(64?bn&1+UdL5MuCbw4cC*jyIƜL4zy7\Ԉ{QL2mќO_ۺU/_/:}ӼW!:ESu)taO~EŮbBд•ODoԢwsyKoҪ.NHi`jXɸ7]+>S hk=:?k10wѫzf &0vðDVrӽwvء3#;\1`6>);0^3^-6WZt.irfU^gF `~@C5<"7n\$WJJJܒ2;\1m`.d.a+6UƀG Fg7ct#7^k~џWvӤa⍗o>,4Ti~^y!=gQEEEBT%5RvEձ9=gױ>sZFV {feԩW ѫciQBY[OxIg?zmjG[{}a;i*?K:tlrv z'UL;DCyqAJLfM̺;.8#Rڤed_\sQŒ{}6Nӓ[zFϗMɒ܉/$M$?3F=-W>iZ݋ [dm/_m&5*/t7k?}ba !up޴SWMy1+'u v`nIņW~d zv}.u8`M%9CC }I*7 4EUȍuXCw-z٘O c H:t#9Kw;>}`N؏9w3MFѹe-:,33q_Wl좾`g{o O\yDJ#|"tobI~Wى5dQAA4WF-{}1xmDjnӌ|3FWTTNJr{ݞy,͊dpP^ç̻"4#9zT{=R6- yb(#=8];}zqcNi&tڋ@OE?/>Ÿ}qӣ[cr^~b?^kMv=LI;\;z`#%_H4MZYWoTD#}DUw XR ׋rzm. [ZNϟ2{8iInO&LZǟH#o& _6pl~IyXVi/ytдνΓZѝW7054V_OXuM;ꕔκΕOj6;>/L݀Gܽ|Ky㋦ N o'&~*qORz!TnԛغjGngwvGh;v;E(ݓ|I[t|ݰh|~6tv?vxZw9_PZܭ}$@32$I HIHDHB- V?<-qd@lEZg y8D$!kqZ30=XJEEEH.-@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHBuF$?h]`=CU$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!ɤiӦ9O]pҥVYs҉'m@uV׳g~gyZjhba5ωN4g$?%oSN9w`wZ͛74毟{~|$'}쯟s˿ǖ-[Ju' 46lpEKmv?ѣ{.]NҗZT(ۺuo-]7'W~K?o߹sxGGv "ټ޾o^qhOH:oֈy͋.p#OII 4m"pXhyÏT#yjޓ˟;gԵFOΝ;?ꠊd3e˖oڽ{mB m۶g/[,%嗖va&LI8X$ꚱyOE6mԩطiNiժUreFܨqх|K]n8?jW'`'-CѮ}jH^/T\\5N=[yO9`z4'(N(Zd'k׮7p(9ڵj#01jcۼy~kva{ Jb[hm۶˖-~x`/W $Zw|ѺGuy6pCLɌ /g;v|1sv{ $~%K=儓{Xcѳ wިc}WLL#;`hh^^4ju z9昨tٲ.D$dSN zz5.dv3fDK.8px40#g۶muv]9CwrFF~oUD$-[M=|ɿIII z;I+j/|ٟtsbJːtt[2{Uv]u;k}z6(s\Y-UKu[j+Ѯ0nJƂ%v>Nc/XX8K/6o}YY`?Y8&AYucuru,^=2ѪC̾q%#+~@OѥY>z9GϾ&/&oma#^4g3+oB+;p(7߯f?]=ۿ_ nIZ{–gO #BeS+*r6e‘˔A nL9˘-wk#B1u]N:^z-٣C>/oɒء+%;FyTpUsI9 J5ze >XR%b:MpH"Ec)غýWkK…UsMtT)ٿ`9WW <-ƫ5@lI]q\b;>FV]5vk{%Q߷E"C٭cLSk 6T,5ǿ6~|uj[=[.Zzjт%WY|5R2n_xRc-FuB:U2(%/͚q{pAbÆ .hɒ7=ztҥK]o `eiƍkU/H^[q+;2'̼qN9rkDg؎Z몬+y۠qd/u]h zH( / ߎ7x2}T’B8OVPBn}MO=9XChv^y啾YgiӦ͗t׿ߤsoҥ~3yryh}Ν#8"j7xյM;LjU$kH$Zv2ruZٸD f(U#9gAv״LpLVJBSSQQa#g~_ɿ8`@]c=/~qч֟<0-[FIkȸn.K.]ߘD[٭|kJ%nOlJ{T`] nY"1ӠD9;/{?jžY픏~Vcw 'sƾEc^,,672giaM^֥;@sR\?h]# 7]bRgX\͎]r;ukvrWؾ`јl>,QfgS=dPJ^.ӲR7UuGkG];'?QO_k_ @">[Ǩ]ʪb=a5T+F}|YYխ8%V)1C*ouZf/'xiԡevxm8۝찷TUziʚ[wxk.)XTdĮ^>Ǐכ _¾րw7RR.h_߿bb!CF$ܲeWzzc޽{鿶h|ӎ|gͪ5S"w"p(xwOvrem۶CmvF-[kwKK;찰OjIHJBn^SQ>M6=un1֏s;.=w}sVZ+Wy@H&9O΍]xԥGz/%˗Λ+WF?xTFn(-I8jzꩍ9.kO>5Z`mP渲vݺx-INvs\8S9FQ:ED2i]6jvjڷ42g$^_˵3ͱ@ /hPɘ䜳 @2j|>!$Ԝ"*+g p([8" $!I HIHDHB"@$D$$$" $!I HIEgUڧkC$?^yy{HU' ^y{3JF>6Oث;8L>1b搪`{z wR2ҩ[5X;6U|]+O UY:TI<]xQ˗vSԛu+>)nlը^a=nr=Cf~X:^*rb.U!;f=V9m"7yۧV} W6sl̨/6ujuf'|.Мk5>^_ionUƒGeX~dNtw;hO^2^9wYTՉL ^ZW^}uMQgNC@VF#;`P }EQCrQG }9/k)IDAT\zM<@&" ruQooݺuH?m/X\nݖ-[?@&" Է)GHFg;>Sz<Ih#LHp0z .]l5n8 =;gh]9k>5j|<4 ?:M֝?Wr7 ~oO8aSNv6VF#;`h`}^.غӆ߼yMco|dL9lٲݺeekMϲe˺wyqmv;xÆ .hɒ#SΘtKHDiI׬(^_m6)>9<#v{'5GM*ge`ߩ^z?\oWGĞWr#KCbaW0D$ҥ"pSI;>-vWhɹsg<@R>gsVzh.'wwQyЬH{w{K/P\\5}wcy8#33wjܜٳV<FLn KVUQyЬHRSN5J/o^qe@]6j8+^ֶ_ydso\kt2=s=Qu'w6Λ{[pa]GտH> Əߐ_=3sXTx2\ZJHƣ4xBQVV֮}jv; H&goq={wC.4д"I}ڶmc8slCiiiZZzskIHţߪ RԺMPwy_)>g>/ThD$ٽU׹gqF8 =kV-Ki?מ̟F'Cx֭ , $x쯟s˿ǖ-[Mim^5bxTNzc/ڳkd8?de=VRT5:vk.Xo.]7'۶mۤ_?ss#41Hps1QcEGA^?pov5z,/Eu ֵ}g8a#41"ΌݻWÈdÿQ{򹱿ZUkt1#}N9%㎛ԼQ^m>9wGhbD$[kz+z?o\5neF j)!NvޛyQ/ pwoO?4ДHpy'gd6rQwJCIן랒 x'$m6c?*($V=眯??=phkѢŴj*^I;lү/_ec>[%g՚x{U8jvoRRR@dt6pQ{ΓsM$N~~3_+_ ϲEbo6o}YY1N;ԨQT\hJZ8&N饢X{+{g]|Vzٳ=Qg_9 ;Oʺ? tiɵk 4%"ۯ_>裏<ݎjW~DbpP 8/j| !+j mW"QCƷmf1qBSH~w>6Y5dVF$?٣@mڴ 4I"bXYG]ݨW_=3п_o^e9~G,_5>0 mb~}HVk۶U#xx-jw;@&" QGevݎNŠo\5N[׮@S"" {bOnzo'&%%%ДH@XX8K/6o}YY&FD__4/?~@#"ɾ1,\tkּ0M${koC>zM?ɹJD=yq'"7_yG0IІ \xђ%/EnzޥKn]8D$6:yMMKK 4xyQO͓IQEF۲eoEݻoĈHhzc6mԩ-ZE @#"IyrnԸ .I8jz$ImڵQShD$i>0j $HIHDHB"@j_ծ}jWӪ{z7D$*xKҷk iHh^ ; +2&#IT}VO;a#{2,:2ej>欞!}+G\U}yvȊpR@Vn; WO&\'{𕉗]}Q:]dC~<벙CRwi|W?0dsZ?Y \xt2>Cl{wO>ǃZb.q\'^V|?ˢΙ>Y'IEDZ|ta^68yCuzk$)+K6zmY׉K*t~bޥ'Mxeɨhl&V7sV3yS 揿yŬ˫H^>ʡ}Mݣ>4Pwg'u $/I%;_W; {XFdw^=8e=&\wiXGVY̪ѣjy+P9Z;Y" LD5De,峇TzE7dcT.Ä#f Vpg-u(#>\#ɉ%cSE 2P5լ Zhx۫/}7%6hW.}RۣتQxEÄ;z7{8 iIDATuTU3\6;* 9vCwzrDn}{OZ;kA(|mԙQ_lB]I,|.Мk5>^_cff ̿jXxȿ ϗi#._x}p<ɋ: ߷2Gv$ƛo>E3yKggyzVOр[8Ox}zg>PU'21xs/j̍C&@DZf1x.'&zqNHͺ~|VV^>=ewxLja:vyt+^ 4X3NrFF~ADڭZwމ}@c}Va2@mVVY92ڵk!{|…K.[fͻȱ{q٣ߙgݎg>so|۷o8D$?ˣI'/^x#$w^x[oSN]!'|KBnݺuQCu7o|؛~II앞snزeKREF;ce˖u=I2"yG5fÆ .hɒ*G1֫q'HiI׬(^_m6)>9<#M*415.[CXEEwGE,{EYHF/qu:Iwlҥ"pHÏϏC8tʂ)GҎO+~pEܹ3C]W#pHh|1}ƣk׮ !i˖-?Q>'hҏ¡ǹ?ڳkԾ?@#"Iy'gd|_eYHVW|QyO۱F6'̘Тš %z/ouxrew'pVȪjh%Zf* IQA*J6ppFETppd{fy;=ܹsJIrʿy=gm @yԴIh)r)S~3>OʢڳkT\ JID]oQ1S;jf*EEENmo$1ww\b+hQhOIFK~z`͓$>xO?xM;;ێ-ܱ|{?-qڋ5(=D$9@FsYQdnݿyUyTk׮vsiBӛz>x r7 z#+'N cny0>r/7X CA9uW=?8q?z'A !Ol~fg6?1CGRJ)߹{3g#Z:mZl /͞on;6։ n-<1+U-ח蹷ӹж{˓'^<:{]^3[.D3}O5kԪ]}'i+P|[VhҸgڥK/ nHrj֬5zP\*W.Mw:xjG~`i|b>‹ ͑7.,<W/Y0|Om#a?x:4}Қjի^~GǦ_{}3ۿjf`3*<"Yhś8vʥ2ͻ=KX?HcD=v I~dhK(4ޒwxR ?'Q8)īĄסYf^iΧg'w޹`o޹ٱE毽rʻ_e_d׬Y(ML @:?}[͚5v⽣FW^ԯ_gb}/}Ufy%_oҹs(u=>w^vmTx D5kּ% \4[rJE}p͚/o[l߷m?AM.gdF8Oi'Q}7]$؛c֍/e˖ѮmJ'lNiO:)p$" t쐺~7|377wafi6Ԏ $lٶf'pIϋW^Ni#DD}[wo_[b-7{y~睉=v)cjĖT 6 &&`*U)N>9|&kYyFD$J]$/ 4?o]vO*U)gߞ%%%n "IRnnn>tc,UnTlޔ`8֮]{Vjvy睻>UFcHEۯ(ٺUs='PHrs͋ߏ~()))PH@񼒑1hK.VvJK 2"_Λ7s͟6}z`@#"ɡ1^=;++{~a.8RIDJFt]IDATbE0ԯ?~@i%"Ɂ۲e C]}ՕW]yE5$? ֭[燷Ү]-Zn*%"Ɂu ;u5jtxӦOxa|$.֭[q/:9{GئMߏիW*E @#"IM25*z^|'PHRl-:(D$)kFEJ%ImQT!IʡJJΌjծ[ 3Bٴ2T`"s6o#MenʺOj@#" @ Z<.˘X͌$:M&?*USG?nF/o֙Eu[#+s!:yʇSse_8.g(z0,#l(cD$(A2B҅F_qߦͱ%{d(>cQسiMo^uo./ЧmY=7eX+{|ӄ8q7N;[m'nWƳ3Fn^kȌ3 K͎'m},r0O1OIJΪ ^rcvcAnJRl\<ը̼gRѕS2R{6QFg{ϛ{éț{L\Hrp_}(#M[g)j 9Z}L|6ﴉdɵx/e' ;!vp`xrpI-rgn ej׍͛rB1؃93P̸0p/AL=_77 Ѫ\2~a}M|)QVڲeVڦMEH7j0PZHRl7hNJm۲eKTԨQ}_ J)I)oG??ѭҪRb:"+;;@$"I%'YY"R"۷.$*zk(}D$){8MXnk!777@)#"IU\7ճ̹aJID]oQ1S;jf842TKII-iC+}ȎEO;pvyYg%GKuW}>4AHo:`V>6wG]ǒr&!T,њ9CҒ Y1k* S|͜hui%$zL4[7@7oޤI^ziĈ`e.YB6v<Y^wn4|_g {uj_?=ժ]w;tOn@ynZIgѮk.}.,P"ɁYNw @ph$*af!5J˶M.>W^ytl;#fJ1I̓-Y~`ΝAK~nܱݫ5SRzl2k@":9fu/W۶@֊gs?֭[RR~}@YV0M9X=)mY`=$۬w-|gHo2fmbB`齒Ƭ)4HIJ ~@.[ogee?4ztNN޿;N5j(*1up$" @i2{HZg->]R*[f hBQ]mHfg8tZjuх~ۏ_;sN+qOG.~Ea3WnE2!rI&k֬ho!9ڀY[bk׾W5s';U=vsSRIXG~l߾"w2t#ED6znn2%" ;w;;;;;VhWV\y I8RL Tl*UUwy3$6[_xQ=y@iR%@4e=ml40wrphto+2- &"CW-;DڵJIVڵ7m+>c9f$2k Qq\z 3ό5kJJNXO? yz !T^=P*Hp7>)*ywe(,]w\36망:WbŦM{"ySN(>˖Gu-$ޱǦupj{cŷy'*N׎?A֥s:vؾ}ytJ n"z7ljWbNi-Z4BЛ2mڵ5>6[(a(>$g+~kNG}txJ=Iy_^Xǖ]h޼ V~睉=SW@Q^{-+*6,qprRCuViʋEemݺ-嵬d P" !Vc{]|QNi>$'`.ɤ$ݹVZ9I'r׎:(ZADYgJ"7|@YVvݨؼ)' Pq]999?;w} '۷_sQ>uV{N41ΛտPRRR4y%#c,]?씖(eD$`̝7oΛ?mNiiwGDCcϽ4{vVVի?P\p$때7 |kŊPa4_ MJDe˖?*n]~+5jJ1I~=.|5Z[o]-ZhݪU¤IDAT#JD#;w7j(@P)@=_MՃ4HJ]$)[_Fur'@)#"IM+W+UҋRGDbKggeeZ)祗7u{kŊ&qF]Hr-Z:t.dd i[+V!77_yѱ鿸񏥟uVrڵkc@۲eCs'{OuXRnnn>tc,UnTlޔi̙)?{.\jZnrKvm[hѺU K-{=:''_qRSN[5GT1up$H["@L>=ZܩӟߨQ{{qy՞__HJJ 9"Hbm(xxa|${׸qbN:g/@ddYu֯;ߏg_TI}Ύ-Z4Յ+W!H$)WPJMB^Ə`Ş^jX;8cFG JSFEϋ/:M^p~Tm]솚зnp=T߫baimoÉwg,no.cT]D;[K͘=2x@8uX^"a "ShzɍٽQ=?GpLF^˳[ʟDͣf,fxhfG7ab/17h77 3F [6o~?궷Zaž &~qu=O[(*_.X~Yt{7,_;1~1*,k˶jiֳY٠ݱ&./봡˳'2Ozޘ7lҢ 1A @ "I)Qdglޔs_FBhdqoÌ'2ڍԬhVO}ELߌ*Z 2aw;M[`P%mRo+>{oS2R{6QFg{V>;MXHrp_"M[gyZ)vÏ̈Nw& /b@a,Tt4zZ_4+>?퉕ySo Cc,4ݰj91fԨgȟ,x <li #Rk͟ѳR2OZwB4;ధʮ_e&51ZUjiCFQ#ԭ_Ӳv#ψ8*&Z5}ۗMvq]Q73.v˄toii @[>(j姝6o Ŵc{4¸{3k anFԥ#Dajt)t^D3΁-W>Ӗޕ+I23i:|ޓC޻WeEcH,PDrճq3nqYٹSZNisw/_xi-ޚ0/тSϝ7\c{cF>[RgPy]B˛K~[ S.^~͈7-W M/}w=%1D4 %/7gDx=u39+ҩ pl۶-9M9赬KqxݴGq0fO)/N:3hf <(+D$9b/ Ζ-[f?~^pS.6|ܲ)];w*,_Orr\4^7h T~jY (L]n򉶧8#7jժ| '4jԨ'ʠM1~[+x/6i|&xg'-ow]c CivWve> ODO˖/~͂vM' mcm8R4Ȩ\rTԩS>[n(j'4>.;M{ť˖W~3/q^"'gӣZj7o8.֩Ҝy~_|w *U:cOˎ--On]L²oWZ=#PT p$8-5)tQG]ګgjNN֭[Oe˖XѠAIơ"i}W֩S;V3 IIIwnq׾v[U=o]ҫ੽qFOmrFI)cK(ѵ˺u6mrVr⵬>8$r]zIZBs1\٧qcʕ)_ #OmrLDJ/ pͨ1X1խ[sꅯfHSL?g…\+!բEfMt?ov?;@u? $=#G3rT(6'Æ93d|W+WQ.J'OmIPzM=GuT(ͷ %wލ-#7j(@)nh|I5k[Տ?G}\F7OmʺJ}׬m۾ ?Ԏ%E쵒S:ٲeƍ֬Y$[W@3hGEb;A>8Vdggm۶Xnٲ%*jԨc^}_&-l{_۫~mkό~&6iӦ_Ww;n-qײaÆY&W]7Vԩ]{/nqS(xtO[֭Z\{ OwOmJ-I㏏Y[ႤE& G=3mZtOK9-\ ο\ݤ3[ pXlHD}v @Efm-9̨ŊovGŢ.pIDAT.bzF3!ݾrpXD$۟uV @E&"I}K⩧Yvm(ywQQvQό:p}l+֨U#ZŮSO?ߺSLDb;GS۴֯rssCIZaÄFmoBpx58~g6nJۯns @1͙7W<[bES;PHRl+WG9sn}X(IӦMu{=ÑpiKkծ+i_%imϝ7/?zfBlO@&"Ɂֵ-383}jW_ %#sѢ8ySR`'?<&* +r(9^Ȉ]?<:6Z[)--~ظiދ-"RRvZ )tWg {HZRu϶yқ+v!̎3qy*괥J/MӋO,ie&]J]B' @%"5J%Kv+΃}h/CjڵQѮS}>i[CSJ)߹{3g#Z:mZl nU/͞]!͛7oڤ^ziĈZ'>')bx#,y[}:QM-aᄏ۴iUV>>oZ놽uUp@~fJ p[%[ %kCh&JuO5]f]V;mjg'J/6&%Ov:kh`y;9y´{9%B>s{̯O==B|jG?{z[VhҸgڥK/ nHrj֬5zw}77w?;;QnͥNl:X4OkֺMvO`ZjʿmE@߽JX=&8__=k[w[M–YvzW/2ܵ&4mS(z⻇?ΆFaݒQ2^ئEj|/ʣcӯKnr I̓-Y~`ΝCIڶu?&Ou}pʼnN]7{up@4n(h{&fuKhKWxDo1IC?& yIR^bW(zQ̛)Ove£k$b)Ծf \R*6+OmoXq9ӟmz/@I36@͚5ow}l %M|X;o+B_pqυ _V֭[ni׮m-Zj>~Ky)w-8RJK~ΗP̙7#F)K]cjत1Kf5ȟb{n&W00wrm M&;NM+i_g@1lO e0 wym25; foo߾Jda:d.Oݦkzۙ 4)=,Ewʴ>io߾`${ھ}n]tٲ~;++ѣsr6F;tHM:o5jCj)><9s斪OHRXhY8rf.F !77{+Gvi+/!^pAVb#{|׳='*W}۝W_ػKC ϯ=kɶPMme|ybzk'^~G96xw5 uUstfL!yo^&mktW=gϞ>Yߴ7l~e˷z_>ȗ\wV*gGwKltׂFG %cRt_7$-֒k-VPA)Iv~!i}vz$m4HHьIR\׽No_|1km8ӛ H.p|V ZH6 '4{Y̍r.yɖ-[[Ί=ٸq/LbSN}UWCS{/ۧZ{zYr対jk^rǣ*UV B)u_˨NN>Q󐷖-נa_nJP $?7O] 9yN1'sRa _!! O}: D۔vkwu!1Ou9Zf߾#ow1%jӦNJիiJ}/WZ7`u vUW-"eMNØ/>q\z;hO)P@D2w챱"g]m}nO C%("+g=|EQrVrB쩝ֱémZ/~睨8k_(OL]}>2&c_Ν[hҸqꫯ짟T˷2j <5777V׬QӭKr ڻt[aG}ʣΝҮۚQq؜{NV7|3T$x7ZpyjPh#S}M7nӺU 5jʠO>Y~[+V|kZjШQåA.hif IDAT/:?\s9 CJ;Bpr8ԦLvGO:)Ԏ=S{ow裏.(D$9ͨV^lek^޻`wޙ{:U)ٹFݿ-rjֱ/ߧL/c=ֿ<ԇkkN]fm)kiP~TvjW2l쳞]ؼYjڵŊ?첵,>W Ph#uViʋײmiެi~''WZ망ZxSnKQϋ.#ײn(tHw챽.sXn 6|.Y"wUVc9Z" Yd&/8/.oj0nq^bti=vPi2?2#:U^7M_`x~<@H%֗MVkbrMUjiCFQ#ԭ_oyovFbeF;qԨĴan_6aht]Q73τ!Z>Bii@<|3P%O7ʲZ͛rB1̱>_JUMdhԟx.$h9p8͸0n׿J_nϗ $ʲn8e«? ӯќ&LFP[U>v`m۶J7<¢ײf,-unØM<}oS5>3h(*8P>~b+q쓜7,>6?8P*%O7ʲZFM9X/~vߢ~;P1̙7Q]z+izYOKcHEqQ]z͛7 K/c_|3'~#PHp إsUD 66[ڐDg+}I:Tc7 k ҐwNN<^n4 %)%v~Vݺvz߿)%D@ -ÜyΛ?bĈΝҺtJe/<^_5pRҘ%B O={HZY혻{ s',=24̐齒ufÆd] mIAIJKC ϯ=kɶPMme|y{-ϐޫډ-Hpe^6`ҶX1[JJ`c'B|"FєyZpAzLJҘKҀ`%c?9Z2Sr𔴅ߪ_8(%i/1$-NOm{;冈$[si[wN^Sq~DɹARԄq"駝֤qXQv$SNt!I8(7nںmk͘5$%џ?[B0g7/==3JIgM]a}վ}ePmذ!*=@!" @ԬYcɲe۷o՟}Y͚5CwڵQ}\=IRDD9ꨣ6m+cײ:wJ+'ÆƖPa0777V4h裏S3b+CE,̌ꔳ$vr͚6_}Մg'}駡YaߦL5j$ώ׭{O,Y,T$xTA 2"/>e+T+W./肓[2US۴QߧL/c=ֿ<ԇk]FGug,\n 7k(}D$8p͛5߯_~-vjM6ĄIDATYnnnyN[/:1Ԯ^ZTԨQVNa,))}« 4bI4*٧eYubPLs,<^SR:8t!I!I!I!I!IʡJ#`ukծڌbulnF+I]hSy]bV+C =Ì~;@E&" pxSNǸ/oղeU٠M4Rs6oٜ}c?2˳N;*+6xTv-F1>'vUD$eeB+G2oXjv~.cYyM(dj $[qYFhݣai3F\(G*55ףY$Vw:OH = ZO<6ؔUaYvQ{FwTM$ ND(d|f=smX^T'#K٬Eu\4#ADk,>mQf->n7:ipAɨ$sș{v {|b֭Un/6N];wPaU nX=M94`Kq7s6E7IfPϳ!\>iӸ ZHraˎUkN~~O|[㞝;uV:gy*^pٹXg9f˖-UV (INyL# st)Gj" |2A>ĈáR%ee_1vmSS׬Q#P|Y<.\HrȌbuëBX5}l|{Yb~S.?YbV2;Ď͸jr⅃%Ț4.K]:"H򈖙K/Ef~E)wN[l3G꣎:Y ?W^ɿY6Trٷ.mpo9<˺ >_jS'G.~Zt&M/1w٠᲌кYAoٸryv~>2~ͣf,f#c .>w܄D>G=Î3F [6o~ɾ궷XW,r@j#3Zj/]vNkuܪ)/=cm۞{o7n $͛rhWhBIePOfLJe5YѬBݛSʥb/Thc\luqh.ﰗ7Z5k~UWs1N>}N^ $pfˋE3O)=(d䳽?E(jL̂&V|$O>3,u9UѩdG }@~hȨYF}gzjժキr~ϮUKNL~}[ě&nO?2Wr톝 fܜ:*rTۼ3͈3nlɉ(dLͲ[DrY }c}(jծ7b:c9<;¸]gub]3.qa ,o%K?pM&۞_{Ͻ4{vVVի?P}[VhҸgڥ%zVZ5P|}C][TPyju{||\jڏV^|%#cMZ"$+M?k_XYg%fgyf*wܶm$M$7_|ebEG^"I;bDFOI&MaQ7_=[.'pB886nn9?#cַ|xkŊ9?g<ꨣq9$" m۶m,]~5W/\nhӧzjϋ./jժi >23ϠA:nݪ駇l֭ϒ%K͟ظjyy饿OzNSPԴO7ʲZ4޼)'Qҟ_~_{SP1lݺ`I']* U?ѭEL>=ZܩӟߨQP{n0w޼h?']SRanb `0:SOV{/%'ZϿCw\!-F? ;|4?jwb]$*-Y[o^qwC`;{D(wA|њiCf'66|M7MڑUuWx(bg!ZYhzM齺 O*;i4#WZo{巿yn8Tp??wQ}_g]0ɚ1Ն7+۬G֎IQ1 L1kBG%[l %WҀY c{_([ƿ]y$u.(B//-ȿȡKo:`V]y$ܵ#eH}7nKgOw$eGPaߍìnYPw?X3<ڭ]_2䝿 >Q FI?({J~hN;'/x{Dn2.sRBJ.Pq0uw̙VN[F1+!VC!s+l UtOwN^p~!5%?QyOpjծ[x}=]n]4{vby^n/'n Mm>`0oj4f!}5Uz{%^Ic]9 mGZtݾѭ[+V4i3u^=V)[-KzUGekcBs6Msuzc^{2ja80{F-\6m7U<7|w1t)Gz XĎh%bi8u2i֤C}J47{Қeӯ־LN:?" و«_N $T\5k|ىy\z[=&%)%mkwmVx}{5{Hhɉc 5Jnתaĩz˷R㑲fE95c\imm D2l5 q.ۯgrss?_yѱ^/cW_/sP *wپJ˕sܝ_/iCw(,۳l'*NR"/XMc wĦ 9wֶШ(7{?oƱ>ĽE߻I6EjU'(iۋW=;؍ " ̓-Y~`Ν!T0eKݫ4 8;g/׳Rt%F&溍KJ^XߖE]5ۯ殝& HDSN3MI80zC+>;[TRI} D`H<\7U}"[8>yK>m~w㓞h`ayW}γ%4)~Ove©]#ӭk7PbL ;~[wsOS*M4-%!E؎OO▼[t/sH/; 1y4nn'MJM9.HTyA.v_`ץN !6+zbvHUn6ìu w|!,\%Tic2){%xE^m۶x;.++ѣsr6n߾7vΜS'Fw.%ܻ2mY;ӈ7{kE]}^.ZKX}w aCugwCjϋ//rGW^s.BqxzO={HZTI̎?9]".s}l&2|NcI5Yۢ5;w{ PSJui-rH%.NKHoZx~%k鴽y5.}y=Fnqm+VD-6\ݫnu^Z|WmJ9ژ5U[;EL<]lUTiݪE^xm?~yΝ:Edd\Pbƾ-cVǧ#q˕9^}5󦁃f͚3O=y׿^zPfI+4vd[4vMcU^0$9yAbmTO4>iu<7\{x"je.>&Dw~~t.>}l^^RS&} k; fm ;&aҎy/4ڧ5c iiKUW %&/T[3&)mIw]+Ԅů]|;9yA!iEMTpPJRއSwCqӧN})S>}+C zboKXhMyWQە54.%zFƯU/_/2V/LҪepX5 896vw|swqJbb7읓.])<3,ZwS5j!I,s=ҽN~"x234;=y٠iw ;7o*(O7ʲh`Bσ9ã>߽+]pHɟT}K>}Ύ-Z4Յ+WŴW&?uM8~.#~GG<Tǥwm˖-3f\tᅡdd^&6i@ʤxP#ǣEŵ߻p>#" iJL֭/}rpM͚5ԩg&Dŷ4};vk? [vmTu eX_@y&" Plܸ/}*VԪYsB1~pߥN>J*m߾?޺uQGH92k#:kM7)-*zƖPaH;y5s[o~ {עEPmذ!*=!RzWK,i۶m 7X'p[6i[Q)V\w [oHJ|Tdeg^ʊF]$|_~%V,^fΝWVxM9g^K.K8NN>7ވYY߽X+qeOi>R?64GI`''p Ċ/rQ}Gη.$*zk׆ W~ *:6l$!" yDW2 iֿzGW=zڦMX~ߐ*}([g̛[bE`H:Zj~i}g /|O/x53ZmҸqjTʕQ={ΜnuP!eee_w}($g֥EΛ[ 쓈$P;Ooxl䄊zj_|ET|{_(ݺvGcƤuj~,2]~ÆjݺuhЩvSz+^>yoVTغu λcOnѢe*[;n^= VI;MfժU%?1g޼(dnݿyEu)-Yʯ^sΝ:mz.O 6Q۷o?"@ѪTKywy#!w/FSmN>+6m8ѭfꁢIDATTZSsfG42uڴ=&_=;T G}_9쾗}6$:MԫW/D$iѢ-ŗb۳2sA>W5k|n=<) .񳟶<唽n_IڥZ>(jΛyPLs,ϗr>{gb˜sC"y\zW]ynvm??+*U޲KzYOKcHE#f͚7>vҜyQqکm#_@ p͚/>o+*WܭK~EdMqFoĊ>8>͚rUjJW(t(Y֭_{˖-[կs7v阚(]$JVox7sssffxq֭NmӺNykŊF ID]xAc;w۷o/_ʎ-͛wnoI\v)s8p&(q*U~k'`?,Jh8H& 4?o]vݺ+W@RRN!Gjjժ>㎫mV4K-rg^뿁k $rX&`3Odg3C2ʊ<O evЄDT+&LNX*M'{6qv~|~ӽq_o?ߏ>\hw/6_hwe~]o$D$$" $ I H HDH@"@$D$*4K+ש}Ni=syL|&u*w&q=뵑T͗$L ѳoM<屙\v}Wŷ9c̛/92~hrqNDhK2 rƒ?|j(?GSqVNDhz@VY4xo_="‘(WyAyH@"ښHFyftgY['gnU3{ءn+.@DeǞѱwyD{bng.o]WV7w^ehD$fi~ù^wl˞ _9i}ө}N=,k]tN|fnםh@-fTr5Cܰmv~jm"9:͟$МX?Lxs~sw[;xfT>?p:6N~Ա#n) :ƋK^L=zt} ADh6nܸ⢗#Emx㜑Zʫ {HzV(WwiidzGO?hD$f??[֮ ',ֲy?@sTQQQ늏>=jw/6_hwehQ?|􏏭 ЩSߴgv`OظqSl_^3߂K;1" 4u~rvu>2/7զM~xdJsyڵˁhZ&_oϫ%%%yiU;v8kûu@%" 4i _i}zRRRճZnx+4O?oQ+ '>O8;sQGVuO}S}"S=Xwha4xx!|fpWhf9I A`+rx7_|`r?_*oHZfnӦM^wOۋ<|?8@ $м=3.|)>۩S};u䑡)//ͨŋK瞵km޼;f~HuG 4g;t֯ ;oŅ[`]p9sⳃo~߾[#͟=3ᤤ@Xʷߎ9GCMn~ /`mZiG<Wxv-o luַrs>}nO> 2H9O;m۶[ Ѓy)))=3Z"xq~aݫi ^rh^~xqo}N!qmXA8?yf(zh ׅ}g7O扁&?2@bx1: P"-+{/@`mZzu蟞SqǵjZ]$ڥ{)JJJENjnݺսeQEQHIm۶mO>dɒ%ޛ|ˁzr)CB *IhqZn}u_sYs͵Ϗ׿箤@=ltuq_hW%o_y/|n߾ii{qW^d%n(u|̱U3rM.e'h['`L^9g..Z#=we:쌑3ʷ;TwϽSG^P2xo:^M@͗UO_Ž~kڛ?/{۞BIh&|Su&rҥN:]/G>/[2^ƧFdm̊-zLy5V O깐W$^;VRsr~zcSMn42[Ü<|UnRaf(UNʌ>yemW-5'zE8bzaQύ;^b/L"5y=FÉ}a|~+cS$pv ܑI_ACayUxz諌qͲ78PyU^E9?+gT`ӗ6rcgJ&.Yo;Z" -So_ةh0扑)49KB;+O29kne;#3ٱS.ɏvi?L?cB4G^vwNQZC4V?};m39+3}֟So ^$\ڵ{iL -۷{UqP?8Fk:[RMJ[p[N_L bJWw[EEŻ‹/>090𥗶{{/~xVy_}/FLV;%/\ͤV 66hK{v(lޣl} KcyνkDO`i4Zx!u9S#\}aU_=zxOd?}u(XmwfKη ^ " -UW^+w -SPsWj )dRz;IVP0@\>c\U:06lqlhSlu1jx/6o^vyg13qc{mvfYb`LP:ΞYeW՟SLɚ\k9viˊ\jowq~y<9rIyavgZBͷ͕V._5>'w#$6]$bz_xIY,WǞfƺVī9,=B5[FOһ^1KNNu䑧vڵy80 yٷ***^o8 `sW&g=]pў3ǧY5^s6)^*"gtn׮=wb꣏\K9昶mۆ`LFC6Uo2]cgņϮoh>Eތ!yꟋYԲiO$b K- 񁆫:?ԜhߏݖNJ mdM쮗7l\tU~!'}'m엿)`dҰ{d)zķ4͘~kC9dά^w}}r֬)Sx燽$sR1fQ+WUL>3,lgXm°ƜU$32Bj>wemܸ1RtOyaJ ly8i6N||2X5?am?U=MΜ0G9˕ƨѷ*HҦߗfp,;Q諌5Ō1{D_n7x|C?}gvU>a놔uKQS>\hΪ݅Ewg_~~bw.( "=2WyAO,))ԇv袗n:4PfU.D?};hWW?^?SN9z /3?4]i|+ ZjЃy)))=3a)>;.12}\i񍘏~/.%5$#T$޽zv?yfO;-i WW^y%^ $Is{€㏏G$_~9P߻Wmv?A#EhҊǴi+S&oZ"IѽGӚeeŋۯ|'0mվ`\zRzhҎ;UV7o~?O}Sa$,H7h m۶:(R|'K, ļk|&pD$Z]Ƌ%%ENjncmztc a@ iiǽ꫑b⒯_ܠ]a[ߎmomCzt?$4ď.2.@ӵS` Y)SBn߭[-]$#y #O @3%" " 9唣zVtk]{N H[Ituqh/.!ѓN @h)gf~W?cP悢Вyb5k":u *9bOo|~^*K.)g~ fd 蛖ʕ+_\Pyfω[n;kURR:_>R|`<5ɋ.Ƴ>_2kb=&ӟOʪc?Oh 4]i?0kncex`hםsC,hD$C>/Z76Gn]͐똣*|秋׮]/)-+KJJ;@3$" 4]pud.]Cqŷ. 8IDhҾyBо}3N?5l 5k{{dž> $ ]$O~rH^Gv떚-ٸq6lX惢/]K;vhD$Yڥ{G)' _x?v+~;2mC=këg|iӟѡllm# ֒***j]чYņ ΐξ9 #EzpUZ_6ǧrɁFRw'h=4mC4tȐzVt;:6o|ɥ#^Gy_D$YjݺO?͵Z1\;ox{JJJ D$o_K/݋ D~l'iG~@s־Cxa@/ଓj 1`@ ̛?y gϙS0٧[ߝ|+М=5ɋ.Ƴ>5{vd s  >hl-ݺu 4%چ]vO<>행7tKη[ -HH4-"r^w0hP q wՒQWd}MIREEE+>p]9kߡSذ~mh(++kߜx|)6nh h͛7_rx>בG|M$1\;ox{JJJ 4%"0/.S+|IDATX0ʫ,]hbD$^͟_X¼̩^80#c4HgL{|܂ŋKV\;>hD$]/.X0Fh1t|ݵ䌺"TH6m4VTTapf~&LD]3\lN{l;בGhT"슊o||䠁_hZh9s99<5[>&EI? ?ii2M$ 6{SNh۶oV"f>9+^y~XGD{v๿o… -_l vء={HOO:ēN 4+Iu}Nb޷a[zu˳yW}'MMM \ۿcC GF|c~? ;JK?S m`]ty#ſ>}*߽zճ_}1sxچfߛ+[4%ׯ9ꥅ?ubE$ ֵkxDrqI$P_[ֽĩd4_mk{tёԋNz_㲕e~asFzXXDhKK;.^,^\bx뮿!^yܔ):axcvD$$ ճ/2,0g?;8u;~:$t~N3oJNh$"4!C;RZWTTe[fcsMt]~tS׭[vl͗\:bZ+$ ֺu;n k@6{xZAƙawazMj,˜v>һG8벳wh)>s ;6k͟h<"~RqZ_eW$GiPq#M CG Ͻ{9ߝoUSDxCgGwKw+W3Le>媻Ƌ D@dM}Kgt _x!-LYYY8v౵oqMgCz2miu/N9YuNӖbG8]z=s*WEgۯWXAX{y~ǝI'|;/h$vSo행7t O|jzgXlY4i3-{9Wnhٲ![3<}۝]ݧ#QzCCv~6mҹm?ǦF/.쮫}o>:ejdz~^Uu_u3={Z4ҞD{77ݫ/g*z]=, *ztP݇xsXoG0oA1ɾ}ZW|@s־Cxa@/_}'III<}πS=n#v{E7Xz2i[&ks/^yʕ"%%e[o`g|+ Сe#)***~|я׮ 9C/=4t /l|$@dүؗVYs\Z5|~-r@BYޚkι傗#u.]u%P/$4]$:ҹG 8Ȉ' "+뮿_[={ 2 mpZ}>ӡYϺ,z~Qd*|תMz ]$$C&|S~v/BHJJ{]{M906{ _7?+$c>G4#"aCYǦ>z GREEE+>p]9kߡSذ~mh|+@$D$$" gޟcɻ~vqII7>٣Gzzz։'ub`OCcO֭[W䳟lzZI~_~{SSSU`7 ;5˞{/iaʔE`-}!CO[fM| sوo;{?_o‹/@dGziaoUICК:ŋ ׆ڝ}'|K˗ώb?ЦMj}kot-sFvw @c06.wO|$i Ȉώ %" +^?W}g}%p~_o>>;ᦛDD`WL͛7G^G`g>soSN]n]D$v3fċ9RRRQ߸:t|9ONDVYSZZ|``FFx '" `eeem۶_1۲ 4\r֬Y/x챭ZɚWw\x '" `7Wċ{GmEy'$Zg١SLtˢuG?Vgyluز6l`?H1vAD9 fH39#J.=\aͷ,g,gF0- Ư/DfvȎDghJ3TcV, 'WV./k n]&Cn%syϋos5q H4%/Gf~ș_=%4ߺqȖmzs)Cb;T&#c5$-$@m|3zѕ(k" @ #" ЄlY=MCJtg rׇOUCt@!" ДU6k&Ϲ?zͿ2޶$$>Ic\τX9=cbwt7:Br="K}lڹ;gVvnhMEUsCܰW^"t'IDAT-\[ 6\; ;:oÍ?SxԨ9ማ_Uۯ]zqGNN͆ @#{h6mB+o1Y64ocdZ˖-q|H4?~rM6Y4m"cGM5|ݯm/~:o׮ǹs6lXzE,|_6mhD$Ǵ3f00#4=c>:(c@ ^xq'|z͚瞓jh ҩSVZ]p޹M3YS֭#yΎm۶ݫ|$M.k.#qIiYYC Dwٝ;wޯmM$@ԧ>ՌqhD$-8a)/ {s .[|ٲ:C{葞u'eU $" @czwF_KhzkYd'v'MMM 4VxӦx:4К>x|Ɵ<ˋfk-Dnd5a7w@#0eJ [WNIRRRҧOl%KEΝCmذ7ߌk׮;h~'?xF4jaǒ+~;RO{Ё]ݫ]={s1ݏ~1ݯmhV+rѼESY~쑣^ZX[']rAŋ_=&A`Qs4w"e$Ԧ:ڭ[hHvvnݻM:OF3mvGNԡ ?.[YY~on6:gTh]Ƌ5|bŊ=zZXDh,^\,ʻ7poudBuG?AS1ǘk7~Hs?ॗ`_vyWy:u b°m6c~DǴ^>,z1=B*~xq\qo2F$GfIݖ=r۔0tĠ=t rpVN0Gk{|Gc~x}#9ҰG44e/.XtJD/,]:8._U Zu=7Z߿{'eؙEsCH_TT&OZ7,id~r2dN/YjΊШű}n=CzףUC/{%uw{ӶZxhFgơa|_W汃*.INN~8S|vSO?r+vG3 A4o/5{vd33Ht۷߰a}=%/OIIINNСCii鷲w7dV|vY9gT-Mɚ\]K^#=1']tj]oֵ鳸$ԩWZ:wywJ59Vos}w7sJyGa/4QSXdu}Tvd)R~ofmAQ뷣So꒺~!P']$Kvx|-o>'lڴ飏>jۦMmG(EkKBֻf_i°o.O|jzgXlY4i3-{9Whٲ!kW9 4bh^Nڴ/zok$.;[ljm .d箺r^w0^C;ժ:Z)_nӡg^ayW#ЋU:Wzhrn kN<,֢.KwûN?w%a>qhgpf/䌺"ШD"v]~وz[Cz͚9ի?w!.[РӦE0,}ܪ%őU,\XRze׼aIa|̱;9'g~ipfs.qٴǧG7_{sot衽BxzӡNz(;X kZ6xZ?OvWaYIG.OW\jƫoċK~ /͛7^['%|vJI֞}ιQW{_rF]qR։ݻw5Wn#/>[|vF&&k_V~!:,v虓uiÆm5FGIJOqcʥKn*]|hhAU-f@rCOG.Cwz޹֧f?y!ޛ{_i$E`/_zWžmWt\z3+i32=)76S13;`呝rsI oEɃl9.OOWƘAs߽z\csCzlN g)!\0lP=6H۷,| ._X8={}vJD`{ã^{/ f]|҉aYTנi6ղ8sRaES^yuG/}tǎ3lݺ'|_x>v}㣵ԕ }'a3ҐTTqSmyӡ&Ьg=(2>]Zk˿N:qG{e 8eD$5kċ/{lV&;VX~}YI顩Zn]ԱcUoC?yb|_L!Q$%%뮽mҎ;.^ah$@{"%%e[n)|'ڴiӆ BdۇpM쏽{ 嘣~bu##ڴm/˛':o>4 6lXnݒ{Ǜ6ŋ=MD`;蠃믿^]₢מ88ճh6~K>w`ymɒxѹs*Gu5^+VgEuMJJcvmhxڭ[`OE`;z|y4G;%X,YvGm۴o׾SN_8#|`Z2"ٷoTQQQ늏>\hw/6_hw"n_}O:)))2[_K˿N:1w$UTTԺ:ŋ ׆ڝ}zkWw鳸$2ӧdם4믻n qh`/:C ѣF}S sG?1qHMD`ԩ㤟p?@KզM;0|R`/3v2#@S[ƒ$D$$" $ IDvsf 4$D$$"I]JJJ/_XF[hq cKJjbIF#"I]/u"HD<:ejYYY"ߣ2%HD$˪ի/qyEEE!6o|ɥ#֮]h$"D_s`/2. a5Λ??xD$ٹ{ssKrK؊Ǵ)7,)cLAey={{EE9!fߤ`AL4*IҷoZXtଓλ;qW / H&GE- l86-Y5o/5{vd33F9i68<%kIXt#Yyw3^|vճ'NO-#G.[S1|FRe2u|̱yêf+ڒ5c^ט6#7m+Gzʋ͚[8)s-+u)bFc9Tl[v*ˏwQe۾C4y~;:u..ԥ]vO<>행7tHhg|}KP1sRa|9'ur1t!'eQPmOEgOGF{[>(~Yƥg]woX걪fdV-,#[V||&M89+%q.+d,Óc)M_*&gG^;ʂ\,GG>Nlz#Kη6h$"UW^+w qYc=ӣSn_g1*{u{v1 C(12=~XsuU=a\*a̯gҶ]>vfNP@^|._xr+{ǯ0wel aSGfb}(k]}_GT$?-_}?^-uEQhzi׮嗍LhVN;c֪|!--[[dBt\zMHԤܼd4zG眴(焰%XlIqvcgfΙ53pH=snVѢ#\P>y={Ň.-CU#ɑvB2"퇙ɡ<䪫1cp50,weH7iWBΔ3F)qay 9FޑTQQQ늏>\hw/6_hw.~YuwL,&6ftN$H]Yc>%kƚ193ZUom.5͡vxi;إ /`˒9a\tYfG9 wFyꖟlsͩfq#sV˨/`o Ge HBBvw @cLX1 H` ɍ$$ƒ`_)>{tG#D$wwfMD} {fΑS"@hF4*@K"" $ I H$9fhD$$" $ I H HDi܂`// -$D$$"I]JJJ~`:ih -4VvlqII`W-Z," hD$"NDHRGL-++ 4\{ԣS$uYz#.4͛/tڵDD(xk>cvƓ`g_:ܾ}dH]Y5=hEv͵ggQ_rM.7.}\GIɚqRڄaۮ/DYs 'ei32Slc2v;9a\^פֿ{vycP \1..t׹FRr(]]V,+kY]լ'jǞ7,)tˋ %K.ԥ:7Y'wEw^@"'5>rFޖ5cڤF6(*bƖ$eHͩ(<;k)gf-(@04"1{ܼGcy=Fo1v|[|M9$ؙf7,o-6>pzZ.\XRz+;ȷ@#d箺r^'IDATw0hP 6+қMX٩c\2gfjIΨ+@Kv.lDd ^ 9xn\XnS!me/9X0Έ۵c̞9~FHRcV r^fdM8)`LZڌ_9ۯsk~eYMoPEu֝8(zhȵuےLm*&dL捛}I鹕Θ=Y9xwmm)3ə_ fBIf*oʐ<|rQEQ4>57 dR?Gc6=va4hRfLe F(OuFpxcȝ^] DP̜T87)sd}o$msY[?Ϥel &{Ef؋04$g-~Ul***j]чYņkCξn"~_F:64s#gT.$cB,j5ƺƗVu]}F5X6y{(]YyU'nik)8fkW^gWz<3فaԜ_^s굕 >o]QطƱ05gn귿faGF4ja $4h4Ʉ㡙WDBDoeH@cI GDH@")cڌߴ)Y7NJ MI;X<|ru4${JڤEɜTXHT"M¿-LOJ.$D$/ ܰ~mv$D$$" $ I H41lnAA: ̜3kfhD$$" $ IjѵK?R'M_V5,QY,Z8^t-o ]Ƌ%%]hqeD25UD`_iiŋŋE$v]uD_߾}KDZ|ċGL-++ 4\{ԣS~+}KDZ 2޽#Ūի/qyEEE!6o|ɥ#֮]{y'9oHR֭[qx]\{}!\s/+)))o%|ʻyo77/sM @W0&cp~yLrI5N>4ZdQ0hE1mFo0f-~Ulևfi[t)Z3Gz.c[[N:>'=eQ'm9]jNPyP\ K-;=oO%m}۟%~%k]~_8yϰ=m}ի$;4曪3uy\t/*|4e +& n+^#=}\iB^u8/q,IQĤM8vԜh]K*knP9gL,=ae?M_gN`LF59vT Ӧtf䬹3#]Q"Wȫ\=brVJ,4Y?xX^[zn1{wZ]lDo$ƧSPyE"6<\PM>y~ǝI'GȘ? 4]$SoNFydA,tqjf .y/{q^XQgV:`ߪѩC.ԥ]vO<>행7thF&ߔHv4#JgL^:FX0ڋ1ȋ9,*b=󗔇Y5dª+S礆;kX%o9} fG&'WSZZȷ@#d箺r^w0hPJCJ3"C1a?<9vW,w^"p1:qj27L)5bvel9UClo*뙻29knut2oʄhPw>W583wWKrF]hTڦ^ڵkwe#"Sig cVF=\-J̨YC[$,YB~i!<_66#x6iicy\R@^[9aXh' ]]<Ȃ3&Nl'W2zÒrW :T|0') ,^|v^7挑IUQDo''983sάE VPRs䬔Ҧt U5\둞fLfNoxr鸌1ͼa˻l=6wڤϞ97rdHru^>ǧF;Vn;3<7Ie̜T(*:odv1UIu}NbH]$պM^ܕ2>sai|Aab5ǡvO[:*ea-kk*WbvI9wdŏ߷PUk*l.-rV!l=Hml# 5/ u[5uM[cǩ1VoW>]$mᨬQAIH,%vw @cLXAO}"X"|K "X1*@s#" $ I+w25bfvHسXD$W5b q@cLX]ty#EIII>}@F4*-Z/uhVյkx$,Z\LM" +-xx$@S׷o***j]ч9s=H^,g|Ffo׮~'irrj4]$!C;RZ( @SyK.G:ȓOrD$V֭}R.xk>y_sWRRRD$|x}onn^z8T`A;L~ 쒤ч apI5g~ "> c@0o/=gN7gh1AD2}G]g}n33UN:}]vOD__֟x|-o>M[Νo?6U>`7HW]9zk;O4( wՒQWv"m@cI GDH@"@$D$$" $ I H HDH@"@$D$$" $ I H ("$]$$" $ I H HDH@"@$#IDAT$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@$D$$" $ I &.lI;ԩwץp붩ǝv݌ezv˅sB]lΝکkY6gDh"[n+gy¸?aw9a]CXV&rD2.n9Rue-.\5>xRr{G]_Ԙz-kng_>4$N|[6v.Ͼ//īg]7eݪypXQuK:CE2=#{JܱvQy>gϭ'=OѮ.)^,NSYe,*hs⚊Իd RZ{ A!TW&Rkvߩ6Y5xz2IjJw~k٬ɮJ3?wDYyii!3;7:-@Gɭu%yy7%s Z3Z9wd5,{%% 3 -)eY_]LOo Y*cX崬ЂDʆ!=4qwt?.m#?Itt g#fzܬQ?L ΙtYE˧^8mm}]MMU;+;3њOHAIkfOon"KL){ 6&~5n+-?Yt2%/5W8% -'"9iql'[6~Y=㵷.%y-*]>=i0oҺpYxœyPD #--~3W36yTQq c؛O\{Zreͭޥ/duIq*!joAރnM.+.nzbFYrLBISrPDj !4/ڌY'V]bnj 8w:v--JUyʪZX\9=3--wnMKo_V՗':Y֗& tsv3Rgg6xlAf9CSu`d/ɭe%oKzw${ONm,[1kʬdڛڋ2rZ7lo[:CZWQ4妍}Ξ^>rK.*?yi{ޞ^8C%e@dFaQىrVmmz)YnoH\50+ѓŚ[T8C+LZ`nEoʞgͫ*2GݴcP^b~Qa۱ Օ>QW8 {z ;mγӳCUq--Ťű};sY_o]]"*sKdž_Reêy׎ڻg`7jÖD>HtZ]@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@|gsCսgMI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I  Ѱn=2dIjoީ:D$CMw S+Vmz #O Adsatac_gÉd?Z[GG%aƕه'niLmm=wڼiG#W}vۡÀ8"\< %] ߼g쉩;)s歹O4sη^`B7G>XK:/ܵią|&3YN&v6d/rjŶN=k6L1rujp!f5S4".w R_qוR;%)[6>W5.wUkO+Rk_9{Hb [~Ud֌ '6uƥc.|T/5 F!f7߼|N_ljٸv|?Չˇ_ѧwՉ|dkF.hj!4͎3сrYa/M?by%Scc/4Z#~JF`Dص?Yf_\`BSL7p;e5y$w|T˟)splA%D@"]xN<ܵ3M^$n<0{@(ҭiOG5aMCf|njȄo'N,ܴÅR!\m/ ٸm279f=2pD/ȵ˟[P 58(bXlnŒK&;w>=SGB۽W\/!ݏoQfff]$~ 0IDATffuv6۟󃲳#"??][[oC巿߽hҤve-[dfm~ ).zd7շuvToߘkӯv\^wAd3gO:=vyB= E3fa_=򑻉?랧z5߼v}G$RE݊->PѫGGv;2ugxD7X~OKキ!/ŋcXў9a=^3<׭GxmqhHJFdr{N+nm╻sr~%ÎW5Ю"ܸqc2j>gO w\ְeuCNo|W_ @M1{я-]TVVV}}Yf68|>5RnPeF JOhOij+@Tu.555X,엏Vk%dS[ 5kv"١{^=g{(Lf8n…an/} @cDM{8ك+S.}g^8mia?߸bݩNŧ7l| w4=;}Lmbmp@jTۚUkREfh{/Ml-Tq#"O:3u|R2s?x^>O8h#?6/mc"]wuՇuN ˙Y굺fL՗Lҽ{>hG$oӫW_ mwzي7ƫo}(>vu~DsOnO|M~wA_ZZwdd !%|=+^oW}6gU Ǭ\le. /}qb)OV>ȸ9Ώ~hv'U.{2^lڴ9q իuRF)"yL^}fPcXuR',mԙ"qgqz=3'*KbN!tx[T,K} Q{:Yzqƍ9쁧|"3w|_F>裏11)t6n|5^n'deM` - >{fa8ABTT=։Hӫw?W_k}};fwN%)?ݺuѽ{;>}9tiXىw67hQ{,"HD I D$"HD I D$"HD I D$"HD I D$"(-hE I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$:U+LOKΛdXZZnIurA]YA̭oyyo9znnZZbWԗOwfYW==+̺m{ݨեG>&-Wɺ҂T>KزsuYf᢭œRvزamnk\AiwU GYUOiաɤ%Uuؖ MN5l?zՓǒw~#W5m8eFFw}}NhG$Krr29lJiIɋښOϚkV>.+)P[P~tQ }(J2Pm׈dMeeJ*oL6-X<)u>w#Ss #EO|?8mZs!ɺ©񮲊6:h{GeW7tʰL=/3/O$C 'n+.345+ˋVX,dMI Wigͫ .nD]InEuq;m{j-Ȼ{}եmE2+Cڰj޵c4sYoT>uR'k,={Zyݖgϙ|=tҜn^HtN]@H$" D$A|JfZۤTìG$+Kf۲5){zڴ|b-]@H$" D$A"@H$" D$A"@H$" D$A"@7lIDATH$" D$A"@|gsCC=D.@H$" D$GD I D$"HD I D$"HD I D$"HD I :}Dr/{lҧ^7l>Pݻw?N:>3n\|bXlnۓ˗_OC:ï+}v: 9?"yTq݌ζۯoms[zNyC ǖ>ti8sϞ9M!" @$dMmm-[sVc{F/_9OVvV@m]S[1낂~av\E{J>"DRЩbracC={/=܅?m׷!qXT~q=Su x쎎̈́izc>~L޶m%_,JgHR1c;ԓ]TC3E$?/Nj]gϟ}aw9_9'UL~T>>~9UZUaÆJG WɾОg,ǪN=]SW @Lɍ7!kqYBu\hO٧OǪ;lCSƍu [=sǖ. {ui}*w|dyW?N?nًo Pb[b7\xanizF*F z'ſ|}zˍBg"Vsv.yoXrvq.&eC/IѝG-5>d`VVا]pcq.m(q.P+`-+#O/[IƇO kv]~c n7P;F$T󵛝ݻN_/>ʺxa8Mq95e"SΞcct▒9^2-מ9E-;LmOkֆ{0'dӴuCVބw4JɄ6[jMי>|؟琊HNcr7է `:+nL};/MƺH򭆷61Uי"w~x+~cte+V9|+.n϶ʝ7ޙ*>3rd޺HЙ>{̘Afb='ݟ_pHt>K|ߟбZ3cҌTsyg^;s+Su-e_YLxnz7oJW^o_fdO~CKlg'WuϮȯ|;s3=}h@խ[]zգգz?w8T~Dr挢m닾?壿z4 G}/~w ѣSi񢭳ŚxgsCnm7x#tT7>CvT"G$y睲?xa|c&}K2dpD$HI]@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@b-H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A4QU%5Z_UZ?,3= =sX~Ѣꭻ[TŽ8,\ueO6nKlԃ7]0Ȭ)!bDrXQu,[7g`ju]5쬺d'.c?yު [lXuCw]WZݸ4n׍v<"  v*ʿD1tγ5Se'.3M[T육ᑩ-"Y_^QX^2s!NJNՕN6Qbz7fOglX3lkhWmHVoa~ieH/M]+/}$YݚQXtyDq"I}2"oiAUE2! s[ZZZm}u ISgWgKn ]$Y[<MȖZ_S+#rLBIS8M{XYE-\YQZ:,;F]YAFZZFay}hE$3cđG3 OKvf#eŷoKO)HoêB&mHtNi%L^WR꒼Lg.!  "ܹs&5nkbk]U锬AW?{5oQQN8iXى3քV8VtQWV076*K 2-*vvbɤEuowءF:R~>}E"GD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$j1"Q{>t"HD I D$"HD I D$"HD I D$"HD I D$"HDwIDAT I D$"HD I D$" K.#[KΩJD2 t9bզo0H>vO6eL~>Iv!uD||䭿HL^Lm\}xrΔFVs͛k4qe|ogLY<  "ɵ]҅op͛ߎVϞO /=_ZM.9|{ &d|sӉn]L\8[g;8!w6,X>Գ6^~acq#WLҘ}lvQ31O`?E#"~~^ w]/5SecsO)~zU~W^61Ϭ"$F[0ܜ<{̼WKfXpbSɉ k\:N5]Za~8lW.{SˇtNIʦkK^^|Hw}znZG6Yf䂦O;(GH2#AۻY219f^ M^>d/ F4]aU &4+ko>!Lʔ~߽S[GrǷJ% _i=wp6D]B$҅t~];8E!݊Vt+Yf4d'{HLXvDM;\(r%&21&scf#7N\E Rcm - _^"-5;Y,dr1qÓG<+%SGZ_;C:{[Hnݲ[/;W=cT? _8HC'а)^<ጌ~}x K/?3FxCÇwM.YCd>{1 r&\Pgt\^hUtb{Cz̜]^.yU~otp!XzNhۍog> *KMZOVV$>v}NBu 7Դus^*4&C-?;5c|e^}޶C$B+RXj]|u}%_\~|f]|z"3]ZZگopV}irv]22索#EWwDOK 9)Q2oA9^ƾy]BEuEXr#oosp뽓]nú}rD]aĶ3Q|xq3F冶|fwAut^i:^i99-_iB+ⲦmW]pE.yw5|@ՙ>F2v4 Nľcc9Ê%vfĶV9\\]Ŋܕ?oޟ6`eř97W[\kg^uM*y?/VM+*[AdW}u_NW=۶+v%M:AtH"@E=w~z[Z=:?!^uZ#-5;^xqs2`n=2c挢 zսgy|s |ٲoӟt<3h)?Q/׬uiYoo*UUO[VٶmS?L]$9S?TIJeHCæ'WL# tdGLOAف»ᄏW++3׽{1z8^E7L]CJbN!tcBv媪֭12 : |u.{ڲez YY/,qºu ,/#ٵkst :N|-#9N:U hlm њP T,59g'!$\WϧY{g[u " $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I H5IDATIHDHB"@$D$$$" $!I HIGdS( CMiAHKOWXVPV[?:$* rͺ6_S?ZeȖ¬tvdVAM]]ݛ2?;<|6Nn߬{Y}B蓛3$c%݆*;*)?#'=5JM?dBA鄂d`7䖪 #3R"#歨lPY~zJyeFOm8`Ȅy^b^Vn $6}~_;SS~SSܒFeow ]WJ]]][kϸ iFY~woc-*Nk>{!gWAgY?졚!?IŹMtA[?pfEeTUA 7nesS-+i\vu]E,/>KwYY.fgfuxoYPY?4kVM]qۏ=^{IlM(jVlJ(_]|CԖfD~V4{ŽuܒI5hzMw}7SڊHV0*PxUy#KO+-=8̫i_-p@ƄY',"? !Q氲q삲W'[& >V͛0܇L)\<.ܰ gJIcv0=&H|svT5֮/^|Е,+(>y;,7~ֳv:tܬ۩Uc OUEﱚ'?{0?c}iE_kl]PP%$]_NKi="YUV5j0 #څe{.sUYib;Ɗg?srF{dvNS%;ٷ)t"=B?KCR쟕U_G7׵(;U5-RV:썌e-C\QZ98+#t';N*Y&h<1eBImX9.zߌ,T+sN#r'D+J?t+;NfK6,8/#pEM[jV쟚UX@jك㍧.?~-2Nw5$cҧ̋S2&W&Rbބr|c 顛٧)t)uuum-2qd3XtCjs\`Nϸㅰ+}n~fVV]mL{Kd6l|;~ֻ,/o{L럯)H|ƚc.Us]W첷;.eVm~3q~W7E.-kV7}ޱ[́a%_W1n~7ϭsMI|dwOSvUE $D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@j5"_6hsSEHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@E=ҥ+WZ[֭ ]͡{'f>%##{-eC^,/|͔x#$8sMwޡ;tnYQwwo;}G{ [;.O񼹃 {-}nX#t"t~<䰴icm͛7{˗mv7]9pN<F/oեť=\cO~<ҜKY'L9ؘ2bȬu1G.дCc"K.ƻnz5}?~ذ`]Ï<$j~#wsst>rc#>2޺uU&`t_w)Nq!ٓm޿Ex?pv_WH..ywމ5z`f]f;}/^ }<וROQK {䷹)6Gx$#vWQbźuRDrŊQ3NkcX"{y*%$oj=︓c\qm8'>w~"+E$ׯ_51a_(9!]ѿŽ˖o_B8gql맳գG_ׯcvSϰrX=sĈ. m {1'UoEf~cAnq]wx;oI4LФ \\8GS3UFCNvʋOkyW#Ϝ{~RɽEuˢM}7 aP 9/Hw#cRzORW9`zs^7#-6G]lS)"ٶqZ_W2B*UP}ř)WeuYU,ne흦 U`Al|8p׏=޴v[۶Nwߍ5^{Σ-ɽc- V=26g3H+7Ə f_}İ;۰-=-ĺRɣ>:j⵰3_+{KJffo?r&S%Jmuꨑ'iVpCo"[oO gUɸD2+r~(-}ޘϾhQ][Rqq] /$jFߡoTWT4d\\?oZp)Q]M|oڙÆ`7u%_?y8O~񵛿vTQ-BѲeE-9eW|uno2Ÿ́ۗZT;W|qP}" +-}ѧdde-uuu!ƿ`u0;K~y?IgMҟg<+璋RD2#\~TO+^ Ia-?֏ mm` ]ͬ_z"~76k_KC2apjj֬*[U_ױvcӧOHG$o{_+ӿ6_^!Y|Sz|aO9bDtc !eC}~H"9\<N |(IDATsɘ?h^oCW#+2hiI I: HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I 䢊$$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $m)IMiAFAU[m*)V?:5=cd޼U%SR -MifUڸOvż! 2$;r+fe4>{. {0\RbץrEe)RU.%A O(,m4Zd;~;jv/{߁E51kE+eoTWwwOV}ǏDzntq=X]PXʮҼN8/Pߵug8q _ URS~Љw< Sw\zA'#wVejK&q6Į˥ e), ,6g>6t&L)nD;_ϖDvKZPX%.mF$s%iSѩznzZ~|CNdž$+VG;L.˔ ɊJ;.X݆SIVH$A\enYge ɧ$7-%%-6gdoR*%~YSg%~gCu<IhGDf^A엗L㒿%O4ՕMmfMwx_Z\.#+^_+d^"3rZļAρ7_8|ÄW4CJ|jJv~Iem,S{pV>wzFV ge]W ؎0nvf<$WʘD/}BiÖN|?e//a=/\6҂(!yɔԜ $6ZY:"}(ҒUU+?3Ҙ]T[WW[y+blӊDB2dg6$kh%s %BNdY_O̺;;刃RR3Fٱ&cFs5ϝ=6껅-UGLLVW0픑WT/{J!ɪQ;_rWᄔݳ/i_ˍUjn[_2"X)9Q-=gBK6ZOWE%WL.7.E{v™A _?qs.cyC9(%cBqd19Ξ Wsܲ2f&>rWZ2ٵKj,{„Q _̝W`gHKTK[ߗ>!/l=G6 ?iaZNs.dZvAeWyts_[aYLEeݜXf$o,P_RMxkbyz#Z^l\7'.?AG.e kkIo yVgqI JKCZ =Z0*tԌy%+jj6;>*,aY{_s⺄oνO٩'ґ!Bv I\3kVM]avO^|;;r 5E9i))i( Yl\uO̫_7}dN"ey))YUa_KM,--E?/bi&r[L갗* RvC&̫ VWUBq7&#;pE!(zڴw̎rdMi˱/TO^ZvQm]]m^vmIBm~I۷z޼v_Olpundc%y5*&jX\fUuٔ⪰O)b|O]>rj{#/*8sVnjsL(B{0~!_QsF~:TZ֬7<;1+Jf|v -8\m.=V[JN6hֵ\1o^T;OTjܾoZnQzy)歨JnY1oB38:^VaDo8s?knq~F[sOQ$fHwp: <6혏ܷskK3|͏j^Nz+90#s0xvźf'3jvGv%;VZvq[| %5_}'QW~nş*A>2/ [k$@3$I HIHDHB=V[2!=efTsD$wCټBaIU}ODr7dM'ާOhu`K ɥgwIDATH:"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIՈ>cHIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"]+xqI /|A=п?O<1ϟw^)JkqLJ|6o<>;?[{d>c"]/7߬ >'x͚9qC|{ͱv޽,6sAD>"]}G?'`WW.?nH]GN@D>r]?1+ @;éw=Q7xG@!"?^9j?hs}Gx tjjjN<9#j//!cc~Qկs1B PE+{Ũq衇GS:蠨REED$;G=zGd?AD{A!CDw}7t=uuQW^HjjjADHB"@nbUvaW- ]SC,IF.ݴѡk7b; ?9욈$tkŽħ=JCYڻpgdbާGWL;dؽќ3D7W3~dl3H̳ -wF^+]0YpݗocḵQ|rC̺ +sE_yhӢIW^G߸p좱%1+W?Ng6|zg,fNM{mY~Y}qiWE >Y'@D$Xztaߋ^U|7u}&IkV5ڙ-\X{%3hlCɱ }i75zgvn%][ic5YIdk}%wV>h~MzW69U|d/l(!~(^rh-FgÇ("" Ԓsk4V|7dc9ƮgxNy]b1 { keGd;$wl(Wf  :@ @wO^d{kn>-F|A7zpE/Xf1hکMY)uTf8* C<XXÇְ;VkAVfa~¨/6F=D${=v^¸Q7otswoUQڇ~YM8usk7 l_."-TY8f^裏Z3xFVoso] AvuYi/XD&vϼ{1ʂ?^DD$!mݺwޱFkˣE)}ɝd1cN'%zľu݌ ne/=KGqDHRϗs?ܼi=<RŊ߿szoЍ" i/\۱Fϝ}Nc']I;kXw_׼F~M6w9T$!l]ށxéFW~Li%IH6ybQ{ԗϾ Cwra}Ι_BRŊwt?"l&t!Cu٨RU>5JMȳB73G5}ݷ~;LurXZniqJFFϞ;Ipaڦ.BxU;..tvб;s3g.mݐ*T}ィ1`I߯oشiS"݆BS-Kl{/;裏F+~ ^}8#У?_h##ꖅ.=꫕Q㨣 +g596u ):;$i/WvO:jTVV=uͿ]s͌kB7'O`$+FzzN>許rժ=tb6lxva5nڴ)t"pW}" JOO:tHnD$;gJ-ᏢUt{yFԸw-o@V\5~ĺXg\rqv(+47ve#X#eīWZZϐ*n=>I!YVss*,l3K5΅kvo{voS-SaJMKä˦oՕ9bғu k'gu۲!\_ҧ'٤<^D&#:$1^{w=7}sh ~(2;+Kz~ko7eMInkRM;Z~N]s.<4<aNCxĻ7>#cFYpaT4韒H5<(j gKϜK ߊ?mbr9 {0%޶m=4s~[=^nݺwbqQœ3Ή ύI/[;ihohfqM3 4GOJ̼;%ƛhJ9*1@ka`#Fs*Ŷx'[|L&pz0gzkϜLJ._-ʈ=.keڶІ굅{5gzۖ5tsYg&VtjGS2з>/sma)m7G?{֥Y|&4MN8]aGʥCܺ,HvO6N{DDw*@oOL|Yb:ؾU_-7ى$.c|?X>55鶜E#T"5) oe2G|eDCm£ۊ''➓KLYK%΁bKl6ٸTe{֎e.f x" m!ŋT3) I:"J"vlڱvJfM.>jJݓ$y˴oOExUp)[?˖UTT|Gc^_E F&|ƼZ#7'k/*$ Klo~5?P2daxIn~^5O\8x[mOMT[rĝeݔufafJT.}{q];n[dT'_smxF"/aEr≱!Sĉ[n5>Zg[͙w|o`xIϷoc>SS2#F>P̹pz7/L,[yav,1-r%9{-o.YsFc~u6:5)Yϕ9;pת#y)gO膾;sfcp񭍜tUguEwc4a?vY ρ/ U_lu0έ4'wn/!Mtw?->2@IkqLJH;Wܛ.-ks`C"Zv=`;ϸ?웅|h7nOl mx>cNMC{[5=snKU;`WlO>2f}Sϗȸ5RӇzh{13/=@oLGDuɥOzb~S},yJMM~}7ޒ-W[/G/[IeW4VwgoyGc֭;c~0ɺ$O' Hv+e/5=Ќ)_ol?t؞oVn>jy$t;_Erٴ6m:3'bJ_V7Ѧ?\ʨ,ay@UL"U$!{1G[leٓڟԧNg͈HB=QcyEŋBTz9s)))fD$!{1O}niOCeև]쥊h>s~D$! 3j{l^Ν=޲eK>迻,tK=tRS{˞5bgb@!" kW.{իrοo$IY_zͪgY]9`+˧Fc];sP+z[~]dƴm"9v8ӢZl4|@tM"-ߴ{僚,~$IPӾw`GVŻ_+4kj&+wǪx>6^ {G?@9|ZwhC> K&"Gϭ-[ތ _9au 4+:&|:iu|Ēܱdk_5 4̿sg#l@3tx&kW\sii7'6h/= :$aԃ/Z~0AN=lZgMů"g0eQa%W2xǢM&G>uܱ*^ 5 F}i u6/ @%" u6{Z7jz._#6x 37]P0k7zn= ⋀_JDxkVū3Yx>ֆ}ጬ/ո[~w]VZ} g$ֻ(:e}3_̾OWn@%" t[;wmyh=o#"̱3fݩDo"7|"ҲѾ֭{ųG~#@g#t^xnܴI~b|7LT:^cg=AIDAT;?O|qwְ ׿y‹6m:s9" 쭧L `<'|N=5gJ9H{5Wx9jٗ\taN;9_6_XN@D+u:m[:Nl^g H{z|kgnKgHMkov`OUUUES22zyrai!ymXtE^{q`REs^07jlڴ)*WJC{ޏ׷yT䔔^<#g596-[EfJfkb|${iS U\:N*z C[nm lذ!@ڇ~쾚( WMŪH= mw_/`/|gJ-GD.^ߧvZv+Q#`O\jGqXhpfYguoG\uw΅}雙uiEzTlYzSVQs.͊M?oѐX >yoO#6{< AD$ O>9jl۶w9_/^n]}kғuS-nKuΥ7eMI-Mq[M-=#ygm?ɮ9YrO0x[kL;L ﭷZ7͡/EO &|ӟ~E_?0Y]c2cƌ҄X#tھQZ-h[5ÜkBL<}MK'9"ѻ26QwujƇbȄBk>O=O;DIF<`x0Z{rp|C֜XzMs 8vBh ?\r_~#"I G~g~OydORBύVaf(dJ'df]dn 9zn鹭xzCr[5) oQXOTa{)/}N t(y 2dpuם߿ ZW7wOq9YQYШa9}3 pE:tc*n=y=|z d<YX;aҭ'خ4krq0iRs6 m>IH]t}!Ƒ) =G> eݲ)LJ3T\t}[d$͹0&̔ʏ!}JݝCCX{BY5򁵓ꏚ?̆cxaJfߢ o[Ғ;&\xINLJ%bNhLS5oζ@W " GkuIkM s벦C/[J $)H{NIDHB=dݺ 6PE2S2C7aƟug>MD+G}9j,x|YJ[o3}.%%%$W=昁'>?ᇡزeÏ.XREyq t":gԨ?ب7;ϵ{HMe˖}wYz^/y=zָ7>^ڱ91^ҵVS32Fٽz @ " t={\|ћoVٓݎ׺.7㏛=3Oc\:IÜpBOe֦).%% w葏NHD`npBoޘ׾C`s$D$$$" $!I HIHDHB"@$D$$#ג9,îZX{{c{&5L;dӡޡM7I.ݴf떯c̀ה蹵̚YU}SgnY[Ǝ_+3_m8޿p'G3Z16O&@#" Y<>~oc?Ym'ݛS>sQш3f5kCuDMi нH~Zy4ɘLⲅ$V?V7`xѣF! ݕ$_5 }+.zdI|o|j0fu[3_y$"4S2Σna#ʗ׿&Ϙ:VRtyE a'~3hv[|qK&rX~wuHTZwU#aVW;~d|o=DK)MkӍ'gZߵ& ?9|֯쯟#aWjjֿoc?}g?>H ,[Wn/ʸdU!{XsCzekG':dӛ斿zڠj7{UK6>4:>CWdb3~>ta% _U;?Ьg%ǎ7|榍W,>0pZ|c}qǝ1#8GtPj'a!fxƿgϞ۶m_['*xKTbP:ilhV Fϸ#N]T;w +[9|eŵ}CsG{hͧ<55k]pʱQ~>t]TFKp)g9syAq[9yI_|!߿_* "nkiQ7nZ5[Mnl8r֌'׮3c{ڟ=7ha<pMKNn8Z[aWOl A>Q_>΍6Wr[o`WD$kbV\H>OQseK;ǟ3F%z\2qЃWعeCn{]MU5±a:~spgIDAT)+=xIkmh!ˊ7NZ'_uaiۇ]Q;?5s嘴CXUXA38jVbYan^똶0?6]١{'f>%##G<ॊƫJ-dwVh͋Z6}Ƽ JB^9clCLD!D&|ϼ[8' Ge|.wy>xBS P *Hh[5")AXҊUU@]]B+nQi!UX-*jk\Qb 5hVCE ("wfnHB>̹ޙ9s?wܼyWw|'!YVŶydڏ7v%2;vG[9~ @D$is+a[0-6&6Mݲ y|򠔔*+7DȥK{5zH^۶m/ܻN>yP`w.d}cӆu&ʗWŶʖ}e} {꣏>8ߍM /`Ħ{rË/+Â]0W_=#Q6 ".c3̃:(?񄁱٭:_*޼%{h#-se_u3n?nlHN6,Յs~ym۶]; :hZe,]tٴiS0Ns/#@ny`UV6lkzO?d2#ww5O>CU9c_ |Ihm"4 lݺ5ӧϵ#CGrWW!{OmwkG9{1!&wŞ^\mh$Mz~Xӟ_rCӣGK/$j^敿_G]}9:/}+.Խgz KDƭ睨qGtKK [ZZC;ڻu;XWFq[.j:N: 9O$#*Ɏ+%%%jld{ׯH|A.92-k.]իg3+WF$| 2dH|Bېm[S츺u ~(|Xiׅ0GgO^m‹QfW>`yk5V\T{S~UZ]Oeޮ} w-wD$;ݻGF8h{/_522CW@\SV3L`t tTGqDذaæMClx㍨=dH`N=ehXzb7F"We?@Y‹~;?]SN̟2th߾dFFFV"wAwU$y˭᧟hӋKY\k6,a9u속&JEwd'_Do뛡CoMpiy^ *T$zkWXQLCZ+ƎX3G]!Q,r狐F.(\?h-H:wu֊go}S&wҥ‡-Wvq΄;g̬L(kNhjy^zGeL/]pcgkpkC00󩒙aRUCFTtb7۶m[ezz_ϙN /]HB9%enE ,ͫ;a[pSr.Zn="j|/5gHaU3L@+ر|Gu/??lMmxw_'q_us)\_{Fz&ԻX>j!M<ح]|і@kPE/UUUz[V^z<읬JJg$GձmNn(п0[Bqȝ=L*Ŏ=s<C(~:'^l]t.)X?Uٵ3K@91aÆ'ݬSfQ*p} {'oM|EJ f~J EFѮuOPZ:wى'yFq5'PCb qs(HII /=T[o<{MȎ]DtM^yY2sx33ykxAte/v=_4)gjE|rb_红)D>ڨݪʋ{stҺaF~ڂj.7[ff~Z|}bXCynި1Un)}j-v~>;k~duik^ziW@+QEpw^~~ak 0mڴjoVV.Q{RYp~"ePQ)SYGPM[fE_Y_<+7zD$q1v}Oߓ_n!ZMݒș(oWDoQ¢ڤTb!݊º4dbZ2rSjޢRTbx+ԭSD* h]Y%odm۶uJi?|]mv[:"FK';+B6[~Ԝ5uaڐԊQsJeB2f̩FgWïM g+j5'` B^>naĉ˩cvK"|ېΡjiSΉHhƖsw)czMa2 )SԉCܸ Q+dIkC]قx{ѽNO:e+G#-LǮu1hI6 ">OEI9..JӚVv#U*}59D\\8Z-ziI͹d(9j6,zuk(4rBQUuKTny=a~nMKK rNnBۉ NX8r;L,)KW_79[gI#;wޡvYX;+^usR-sgBD㮕ݲj{n8bV_؛=hͪtDeL( v_9gL/]|}d{R&|]lu:qSs^;^z}vJU÷ *0].3N8ߑGz .Me#Cфk|n]گ/Y?{BJċͬ+/%'dWli޵ 3lrMބK:ujvޚ?"IkFjfsnҊxDRDYӆ>[G.VjSknDK`߸4̮wG]Qݹ͆@h7^ vxVȏp.:;O"e_{k~aA^[0(:sD.6$*7^62~S?U;COym+2˄ŵ IJ|ަ#ܸAqj "oA^<}XNl {W-&EstIi{섁WXq+C6 e=&u^thYFg(@ؽvy?o5wje gx۵ljإ$k‡tx_ҹW\~}k1gN[F$ -]Q2!^z)G{ѵkuWە&"Iڶ!os,+[[ovaM~ǶGƅ="" ' yX *",[,jr)idԊvfL/]pc6%" -aƏ>v^mƉ' mN: 9O#PkݺuQSBW"?B^=O[nظqoTRN!CoTwމCw{ڰײS$;IaEO?wt2ѡ{wAh%G~xXre G}6:ֈH@G "IuK[+۶m?ܼyVN&|Ԭ}"CW$<&"7{AD}ӟ__k-{~u?29/K~'F>}>τ}(SFիlڴ{-?6Yg."9 _mFM58j<%|A-[h=Yn5tx֭Q/9{AD&}ydm۶:w}k*+7{gaO/.4KDܨλK#Y‹wM]G|)F_᧟kTWW+BG5{f~F=$#"Is=>z?>'Bѩ$6=@pv=bgo~e˖Бeɒ!COcw&~{XNNNjfy\ZZ~⩵:{VEES^}}q_OQ{YR/<QG1玂˯[oqi 9 IŋKJ}fqɣ uɹ? ^d׎?o%Ϯx_Wu쿦UWW4{ѳk.a/ /knݺeh̗G^X˯?\zMc[`җf睨QbmZ$-:yv ,i)))n'|Re>}2sG|!kpqǦ 4s~'/![n {QwC,U$ ;bLh8}c-{73n>|e^v?rpFCD$`D$'Ƕ[g,?~Q?>3Ͳ6;UUUY{}O-z&j|a^={Y"[%>Tq4Oӝ;w6슅aIOO5}s߹ݿߑZ=OEEEZ׮U$a閖Q_?)g?^^QIUYoV球>a*ڧUYȣo_KoǶhW2F}WTk<wNM_HEIاz>d׮:z`W>*/_ݧ$9^{^_)))f7# ѣGz^}'" GucBܡ-$" $!I HIHDHB"@$D$$$" $!I HISkL/rHzWO+ojFշg @{#"I2`妍woa^ṟ,y9s|qE]5t7m, Ï// 7{yWG3/;OKIڽկIx?/=E/$>j͛:'q+kB8 kV՜ zY<_ОH$W?ɘL{WߗXM{h<%N;g M{ԏB&^68O}Y+xνb=?|%12c80Hvmsr;W\sw<`/ W"$QZۓD%c5>vX!̸.!YSur'hD$i&WjSFWjHƃ?]>{=-Qyw\}{VͿ$W7H<%=ޫky# W]/zT@#C{C>rI'~Gqa咛gбW_o=Wwߍ_եEX|dFF qAhUmiLIDAT65/_xAJJJK/[+"z;V=fuԀW]Yr!=zO6,o}hWD$i7=WF^/ң.,y/|>L=8}s9r# 쾮]]3.퐈$f~_'/_*=#~<ƿO@)@Y9~;x>r۶m/딜Ӟ~yT$ywc_S .y3OO: /+ ~tX__}ܳ΋G]$^mƉ' myݺu776t`N6,Յs~ym۶]; @=$j>,'턅i6lܸ7b[Ԙe˖XC}';x>ry^:OX;6KMnyfqI$λ^{=c9& q__}IMDd0QkW_u9g/{G; IMDvbʕQfi?GeoVH^ڹg5zyq;g!I`N' yX ;,M+>Խgz *{֭99թSan?@>թC{VQ/veȐ!QM mÁg֭Q#S  mw\rH(// /5ov]͞=mv#G~xXreSq2S~UZ]O^zܻw=Ш|ŊО=|yؕ!)y"ɎSFիlڴ{@u<2ճ6loD%iF; <ZW@G58j[Wbv}SWѵ]kGa9-y.mⷾ5fr뢧O/@˴@F_᧟kTWW+B|>y}V.JeI -:; g9%߯~Y78er.]l7۶m[ezz_ϙB9tuΝefVI]&o5Rs_4SO9gf0 =8 ~©EUKk :-xs|@+QEs9駞 BVU|FvvJl+Ex,-Ho/mؼ+:N1:?ﺌxBT5UVZ#Li;7Nݲecw"d_pxfzUwV?9;ԒT[O9Dk7,nl8*2vy!&6Mao=7,XR/rQϞT5\zx榩[wVֿO E FfofMۡQ}eG.Ij{1wׯpn~UgLJpv씑8OaQm,qEa]2lq|x )5o[m۶uJi?|]wKlC_iz"GS6yJ#E؜e#5tM]68"uԜԦ 95yɼ~bzlew_s m%t_{7|Vem,g=ZW7qAyq5j؎/\\tS۹dM#C..W' kw5\vڊ[EkLɍK/_G.W=xE; nޢL hQ:_c_ޝFǗ45/s!lIxM6mlr͛7wK>LOo~sРx޽{z/njj].]?;CҚuW`-Q]{cFk.>U2sx٤.[| ggL-shR?g]׽BNW']PW[PͯlR3 GIhL<5&__*kZٽTūVהċ9)W8~i[楧:mذ_zo[B@Ժ*#(7sځ5=sEA7PT1}QU]]}uy{ߝ4|d*_}u!vVLºI m*k9hiʼ5-*Xvˢ_w_T'ޤ$/PL5'^i/MgL/]|}d{R&|]l/)Y15;gECjgT5|I91 nƪ #ojߞȻarF~-[ɛPtINm[SgNfk֖vx+^?reD9k$^32`qv}G6c{)o)5Glr7.( #]u5  +ֻsumMϑ႔좳3*TQsxT5]yo/20, y EgņDR67^2^3^B %<^/P/;O vW5#)"X}58QujM5oN8u 2!CR(엑P%n}uwTUm)|Լ_Iط;_E5Ztyv1Y;";ywv-vi6t_ҹW\~yԾcΜІ -]Q2xkFCmxxt]vczIDAT]w]M`QE:o}Xl[oua6&0Ԃ^pg?{t?Iځw䑱F={ᄁ6ok?WVva[E$۟e˖ESN9e罧 M#V43czt"zm֩Sa9X{ݺj[.jzН^"7.(Z"t4;oȐ!QDͷ {*&s;D١mdՙFHBrG+W~y۷o$t,zhXbE 5Ɍ IH"+_x1'00ֱ?29jzШzM6u޽&dE$| xzqI8}XNM6V`aƵobv˭[nݼ}ˍyfqIgⷾ5fr뢧'|rUVn;سb$t8/O5ǎvŊ?xqEJJJ$tDwѣGQQQ1̳mڏl:,Y2dw̞o @I pT[ۯ:89w\~U)?#F~irN=Bzf⒒gY\…urrn\D$iz1|A|yEο?ի1;/}mf FϞ=~Xhv."Z9SO^xCӻ-?mnݚacMD$+H755ouΝ;Zɱy-[ogy1|.JKKoQ#@!"I;йsc>W~Sy OmY`'x1"N:ߑG<֥/yWrh?D$i;2$;O/׏?8@]Z[n @{dN5!׎|寯 t2<;{n|z+_8>sb.כOD$ۻC9$jc{OƖ-[.m; 1Qb]Sg3FG.{~yq;/Tw mwzhXbE0t+Q}% " ,ݣGXbg۴mٲ%6oé6w}72=ׯJN7ڏ?,xxWֽ0#F~irN=bڵYR3 " H>$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@PJuuuH.HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@Ίy4"s g^3kFfĹ^_8.#%%ЅcRZ{Lhj\ĒF?L岹G ZY\Tfd?Qm#v~*ž}&%=cY _//ȉ}q ?j;f)cFLn|R,}f^(칊1MIKgeH{4]M3sTewhdXhX5]3ӎ>;wDU&lX96uw-ꁂyxf贜Ymۯ ae[XقSF$3}T׻߱z֬FW.sY?_k:{쮱5=kECv3ë+f4[>ka~]5`]eoE孲/w_;7e<ử2* IfY'[8&#؇9~~̼wlAϚY$zfL[L5a4L'>K~x/ {$cԼ&~v'68k4nnPwj/^!a=Tܝ{k'Uhެ;Dlv.QX2yґ.{#2ӻ{5xeG|x^z}g_Tm0'Ǐj`)c_I|wUof&sČwZE&~QV-. 5sDAOY 5LOΘ[xoϵ$"QѼ']Ϛ81:~^QGHvl;$gxnԉ mbğ7λxb{3'քWMxjŐY{mE;>fؔ;.7_9?y(vzX9}pnT[qY! U.>faẻ_'8%GΉY*q:[vo "Y1wV0qbN*)(Xh <*p NNl %sEN7<0fΫM -P9D{`7ON2'Nnl__FG̫,&. ؓDB2Ԑh貆u3F͚wY"$1s{}Y<4pwV5>pr_8&6a]LzW}hbQ~Y|۴ uD;>|`LA^wT-7vNxf(1j\۽eP`ʮQyuLQ0DUaqu^ IDATM\I;lq~eX]25ϺD,ywavyotHϛNX/c_yF6]?(K;*{^אeV7m56hnT0s܉ww_dVnzH6Z|,3o/Y8nh7:#u7{NUPi2e$sge-AZLϙQe)lxr|Θ'ܽ{䲹sꄧNsN{3'NVg[9}̼(Kʙ8wYEMes5 g6v֗SP{;5D+:ə͝#c'f6,B3rv-1=uo/576~؇JH *3vT}g z {Q}|Ʀ>e󎚛5}{80R~munϻcj?P5:y5Mfu`dٌO)}?15]c)7Uv;o.};wd|dST^Y~C/m~}nmp2'λ f/ң=OB'_vۣ/mH#Qs ,sh" о#" $!I HIS*H=]sfv}Un({{<[t @r 9 ˩# O$\R@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@j2"խGT$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@Pk~9${_ c$'n~qce7ܻ*7=AǴ$=I/^^а+˘؆ru4yc}rշgՌ]Cj*SƶE~Y^p;kvL"?.| ]icel+7,?+΍5ϽsӃ_}7,]0eIK31rӃa|cɋ3OdFspI"X?Cl񓯸y}@c ]|q蔚G-sWk>]^^L"?ċH6\+MU|<;ύ:%)k//yEk;ՉV]{ΏgUU|/뜰=O) 9p+_Y8k XƝ7DF; UD8pH~ܽrӊ߫u$eMؑ3D:`Uo]_w|yɠ|dõ%$vo䦍7/9)wF;keՒp۳XV\|pUM{QsA5KcǞtINX|l__;m:5 K^ucѩjܽqP{F:X%!N`EZ]1gaWT qKһ_K_d?8jFbYC}Xǔ&pUKңqILsJ=퀦:×UJuuu;>|CĚ_w]%Wjsw=k1ewǮn=z " c{;zf}_&K??kxī|Moe/kzkD&Y-?na{V#&ސKDh-چ}*55vӝsʻCXV97Liwf??zڴ-G<' Vw{o[%;qd^eKӟ}ov؇, mտwE? ӋKY\vr%{hh֢$ YӺvݴiS0Ns#-}*+>!" m lݺ5ӧW;БpWW!|?}BD+cԋF^ؽ{K.ګ׬}寯'" mh /FӇtPz{6,'j?WV^jh?l7 M+֏?oFO|%]wT76qkR}QwL)oW^nП:jNCY; s/XTueIDAT4ZYmSH2gTE?RV??#*.m* LidŽ&+Ȏfa/e=TR:=#>CCxa4UCvv2;Cċ]}Wz쮉{;G䭉}^PK EF1u4N]|Fv?#gPCVZYm Hv{>E^)/ΐ ES ÂF˾]Q0|i(:^+k)_\VPҥUshҖkue˖-a̰O&L6-[eB蛙(nK[tE.2ɜ>P[|n/-7UCyg^\PV#c_9see__5# ,͙0ud Ğx^o_;{do{Tuj4`J*17M-ޚ{_^ֿO E75:lx~ ƐΡjҐRSs.. T\ǯDg֕‡PxEqU7F+ܥ^|[_yGm?%7~HY$kH֗/bbjGhf$Hή_9<^-_>~NhB"4o~閙Y͟M̙#AB۱ى$.c|EkCWfŏu!.wLui}[6U$cSǾԮV ,}*7r>N.icΝu+r6y-ZsѤµe]׼H5»3{KB댯e:d{]J G,, huSҥϽu:uZ? sUe8c~Ug֕2gu@_[FC9dkVҾfGI]]t{ǂ].Pnس__.?O?䓛7oNKK PIiShwuT6NMm[qvCN;$aÆy&juKǿYK-t[fֽ?ʼn^Oc[vo&Q{boB޵]tcE^=;2h(.iiic\hWD$G 5aӦMQGhoD$RԨ6lظw>ܼ9@;QLMjhm?2yPvJvH.߾᛿/͎mxzq /k{<(쑎3]P԰oV'^G$l0bH:6l\3}K.c.:w}7jtAhڅ֏Hn_~O>?nݺ>X.jr$RPQc@=cӇ6,'t`~ɥeeF>}]}ey֣Wh fd %Y3Gd!+=IhC=۶m?t<>Hv @uVQ{W:/xU<ė>!" mO#/8?jo?<~"tԧg>:hcg-tP7תּ32^Cv/Y6]0⼣$ G 7~|ɳ>b :_ӪmU>}}.epu>|C`3=jlX8x2z AI HIHDHB"@$D$$$" $!I HIHDHBrHzYZڧƷ{"1 ōeڧsW^??HBGp̀]Q]6Cmk&?xϐW=fd|_ MRS2},:3D'|lxHg34Y0B".| ]icel+7,?+΍5ϽsӃ_}7,]0eIK31rӃa|cɋ3OdFspI"X?Cl񓯸y}@c ]|q蔚G-sWk>]^^ZHD:xɆKT{ŠɃuQg$em%|hcs4:;ʻkzju^j]_{ewV_I5!N~e+k\xQ߸(hgHAD_cKTsM+~5%cGΘv=kVw~]W%u^֖ڽ񒓛6޼Z5yUK@ˉHBdz(97ׅ'/\U||pE\>yP'ysS+?N۹ecÒl_Xt9wo?:Ԟ:uK @F/?8ыm>j;tۇ]QywX2h/I}OW,I,~A74"veÚ_WbSONX{W-IF]2S')2e`)_^Z,!umX5|{Pq1K>w۳Sv9a_z욱? 1O[^5H(qh39z~8X/65%魭[g̻9YzxCN.Cd/D$bmHZUUU{7V²?j7OϹaZN0Ӧn?<6$++^$w{o[%;?$D^O9k־B ˹Z^~WQc>1<%u/\:ߑG ֢$$ YӺvݴiS0Ns#zCo 6IDAT nkgث;Z?13D$!y,_MLMMhݻwO=.䒨]Q_ @$" c 5qӇtPz{6,'j-[)5Ia7'yOnL{0x3Kb**nڹst0HBX~}wBǖCݻwt睯f# RRR^\Xa9 b|U_WY!О"y Zc /k`/LY8ΉH~UP0d=We6lܸ7b[H9) .]eD9n2Q#ojl W?‘. aQ윉/2B˒%g?5W:#Y?EɳhcYN!56'7O%!Ca !wN0jQv_w:[ /.w]eȏt삊w̒7:jŷ6kc:س7c}v-5p#_~Տ?#>b3jѢMM6mZh5K˷ֵׅ73͚E'Xt!c( kjλ*th) {'7ψmMHlWqqq&4t=K_7sdٻ,8805qС3CQ1QYYY? EifieJ2O:≓:Pk1`vz\w_u^Eҩ_c<|Ӹ4iK%g (Sò]dKsκaTtAW9ftJ7c᪂bxfsn 83'Cn텬9WS|}K4H" =?s-"g׮}'LB|!pW׮ osK謡9CX6k“[Bb nɈ5syMCjӹCl%ge>7Ι2*)I@ƣv-"!8/1hJN)iq$k٢Eh=IH Ŷ@$D$v/|Q?^T?"Pb[^97ވNz:$v/uj׹㏣q~D$!Iԯ_oE۶m6l_~>쳼+&"PHBUVV-/^:ŏtWfϏzAFENQ1ٟ}YQݵsF%IHGqDV-c֭['=2O? ?OFuzzqD$!ujT\>E:y7/E4}F+IH*6m쳢>5kguG*5իOlܸ)ۤqGvw.Vzz5yw/;iӨs~{٦uTc"ڴn5hY/׎?c+]~~~՛mg֭MDSzuO:{ff:;Sb+]JJJm۶⻇zh!enmE6|6p5Hk׭ T~n*.@$D$$$" $!I HIHDHB"@$j`wi QK{Ӯձi!,3#ء0nn/ 'm3ô;pHŽ:}cݚau{?|1mkih=4wݤO~yn ֬_f+%!,ykAccc\ێm[Euuv8D$ECwE%ىiGv[0h^7w(9c/;&@< Y[:ݎ 0"P.IEC^\y)% QT_fNvឝ3.orНv{skh`q8ޡ5aƇj٢ctA9G}aƌ,]? Uz|wZhq {rʹ}Ω]v`ϭ߰wŊ:u{Ch/7n*Bj*[ւI#M7]m޼i'w<{f3o^ aRo{_{MfA(=ib7{_9륙}=䭗6uUe'W%KXѲ۴iۈ+gjE~~ /]>{9#ԯ߹S5rH'i diӦ:uĊfceD$wѵ1w=:1& DkƔ/ΜiY_kҸq7֮C4)cZ~t:&yԯ|GժU+'NzV*+ɪg欗7ׯWhfj͝{ŶN}ƍQLKg}ܹv5jcGqDc Uٖ-[y7n5kn۶~/=9_=TUZJi6|6p5H+Xz5eL{📖.[+?{/;e˖hw֙{S'ľ^NvOߛ^93s><r2S0TcEO Y*VZW<|!C=TR#cZh1)C:}'| )HVz;wޫQv޹}Buvv3zrryA_tӸ_Vf͛oۡCh_z֭Yl3gŶ2PyHVE}O! Z<ĎӞy.OM}ߏu˽֨ߑ{ڵk[ilfΊm"dհx>,Vԫ[Yjk={ԭ['V\rҦ`Tw9CR̪ի;ONIII 7-*׆=l]mvwY6V;Oz~pZhqr̨$?T]HVF3^|G)!%v_93tg4f͚/"PV-[=3Ŋ@~E?T]HVRwsMΝ3B)Dvy;0gʨt8rȐ0>˄Yfl?vքMdr3cxfϜ-=cAsnucuH'o_yAok=33싢;¬[z:I?eЮgިH݋!atv ={Ow] ;Q]`v ZسCw-vugϸywUPMKͺnj >6o][^zߍSUF? 2>b@_ߐ~NJߙWf:욅otth |gi^~MɟU;?ʟnH9|FᙣoH_5y{V)v P3;bW_!ɻ+ء>=sB K= Q&^}C|_AW 9!KQ>O-L号mn!ݟ9CZ捯3<~>]{4>'b|h<,}Hb~߻SC87oIv9  }WO?nE"ʖ?`w2L"a"}t֜}aNMU]v9!vsbopm"YXl|V,LܜҾɸeSGPaߍ }CN>م)vcQ2 FGMtKPp*hbgI|5M.A)W+;C;GMBVj"7YnEvz|侦"Y<ߺ;ӧ?>Sm̘19 "Tܹ,Rg%QS*ʋF/<:{AƮ۴K"O} QmڴYxqi7g/̘Q)w_]K+r}- ]OpUG/GK;0q˦!}R=?w֣sn w/S^ݷ;l:8sSna(GyQ1!YCZuiv(cvLݾZ"A b[tryė*L,eY/>Z=no+&v?wУ%~v'fC.a=3M?<Pe"Yԯ_GiC4 n)]c[|ږQ}Öb-4cx>Ĺ%~G7:q>ezrqtԬGBK;xx@ÖsC"F6 Nܷ-??>xWI0M=;.ź;3jʜΚ/iy;VU3}vjwO᳔ 6m_,Na֢tl }wLrCzosގc}4BiPߖa˓DUOP#e-C6on~dC/B*6trɡ-YBV][Eb g'xvFaR*xHbZ6r)] _bWߣoD7eȻaɃĒӻoųK'N,\;~Q?_|Q|F!< m'ۑx0`Dxq|(o90M=//)ٜ>$Jbn'ny&x`~Uƒ9gtTqɿZeIa/dz?/rUBەW8 ,mID>07^]2v3xf=:wtC[<9Pk._v0h_Zۭ_f oHb0`-׭N !6+z`F( bwG!gEsn]/&]vv=ve˖wލ?n}͚۶m߿KONWzO.w&}_Fe[+!ּ}Δ!iiy}?9#Gvt+IDATÏ\>s>9goܴiG+֭{rSg==[׻p3{&4L^pF)YwDu7wwM %fv[{O_>;gbɻ}iΖ(9`$0jWWHo ?x`|U { U.W<ݪڹ W$ieyDnQ3D劳%3!Kh}7h [&.\8wxy[;%,s=Yuv'rj(M1X욭nOr쎇>adž@uRZӸ @EźEɟEU+귕V}۶m=O]`A>6wn͚5*)LE w]1wھ{p폢G7N/:Y/͜+e~~Uc |Iʔ~R"hU5ƇTs5jԸܼy{-ig -wJ~+w.+*9ɪU>=>%VOyxtVtkET"@I'E$s +Qqo.TU \Y6ݒ وHR%}a^6L {nC⒋,_I'+V|(bŊ<)TalZ;H&)]C5vcbhP!W=lϒVgtTFm۶\/UV+Ivg #]:wh-Naob[*dyo#h?8*7n umz!\uօ v!믿vخG[lP)T7lXdg}{CFE&"YfQ1@«GEzzT)HV GyĬ_o,)'w[N׭ ZZݖp`%NJ|=:59ڵk.޵KP~:rDl ~dpa5;Xq㦗f U~~S:# TynTL|+Vj7]Tح[H@#"Yeףbnn+j),կsJJJѫױNJUWw{.~_✥˖8sVldD$;1mfL7lƍǃslѢ[΁ Uf[wKTx_jiDO:y,qڲ_9+%wCD*9G[osfM֭qƨn ~3wyrR?ԬmԨ @:֭sQ <[oۭYFFIN.#8UǴ=sf:}o~Zڵ/1ř3d7ugu33O꜑w~ٲe̞K/=X]4}ן7o^Y۶mԚ5PɈHV1}y{-~6c ݎ2N ZmQGy[lͩ_Y^L@Ij׮O|LL4SOŶ1Œz8蠃߾~ZVs>䓨hܸq**#\yD7Lt)))UnrQ"9k@ׯ17hy=貧\**6=$LN]ltmjVdukT6lCŗ^ ՠ!M\|E߹;v+WbE5~%9eR?aH_Ķ.^xqfTwl{Hj>Zr˯syy+yݨy|tz⠃i Zjd̓N=B|tJKKg۴iSr_E})'uJ)%??>]85>KN:w1mnV~4h62)0TBۺu9{uNGiEÏ>VELVOyr@K!" T mS}լY_?>;LIIa7q*"5@vLۣc[ooYfÆ vTN>&--[*Bە\*_ mE/4 HIHDHB"@$D$$$" $!I HIHDHB57K Q.w.ܙeܱ4'G3 L 'mEYx"HDM ֬;ul=4wm.(oܿnM&!֬_7ʻݾ$%o7){So=c։+6;ۿ1J'"~hvhzqc?i+6?wXNkuG([s$NH$# v]mdYfء㒷b߸#Kd$%N{yX1ݺiիWPuADdvCK/c.1'fМv!"~s4dKkm/ %E!nKYPpn($Pd|FD'VȾw,M~yn -JH΍'`W"7;\z{׏ߠ˝K}$/(j"IGtl֨An f_$]9n#wh`]kmʖ_ @ EukBRXrs5f\rOsV`?K_* @EH PV^=#MklT̖-Z\rQݥ˖?IO׿?<&WuiP~Zô߾}""IEZv{屺cƜ*Tk殹&6%|'/ysu {ED 3=-[gMi* 싔ltmjVukB4翹<_ۦu_jf6i8@߰aݺuキ~6L UT "YYT cGufիyfRHF}vGt9Vj;~K>駟{5FY~#<,yPq9oݺ}v YIDAT#FiղEZTsn޼y֭^HHr=s?s]dKB5ӡC?~\cw7mv衁ue꿧Ŋ}{I|D$9p|g ۪իc &>И_r~˾(GO>YB/͜S<_NI re$֭_^شi@">y.[+ڶ=qFM?{v6K.GuԱǶHU˗/w/MӞn{с]4nxNJ5k6h $$?s;-Zح[RRRZ&|AW ~O'$V{A?_FҴڪQ֭@Xhw1'Q}r|:#wRnhw%~@EdWoÆ ;:y キ8D$ُVrszzz$#<":!;;R7O=55???VҤɥ\(Eݺu{_@1\?!Iy{}vfI'|g?ۉQxu֥=Qnޙ}܏YӳGON p@XhhŊQq҉eرCzzG$Q^^ADs΁2ժU넎>  mW=+cł :tgqӦw=:W+"~]piW͙WrxTk~g+f˝U9s{uաyQѼy@$"YY4k,HίRf-{-ϣ:],*_(fC-_+.-/H,]YddtZl؝Ν "+ҹs ,Q1VXm۶z ʡ9ԬY3[rO|>sUdeqF^Ƕo+V^W燪7jܹN:Æ\(.OWƞ|mvwY6V;Oz ,j֬yn/x#CUsO|hRl裕E876G^]zzz|~6zTƍC")˾rժpï3O!%%%P*=z|{;b?sttk.? {/wx9wJ;a֣d̞9[bE!g?wМb{٭_¬[zl?pa-񗼱Oy!ɟ2(4i=($]8nܯ/P1+IaΔQQY}.o0>K**qEw~vw6)zvbOg5z·%exl2||zOįRnI9oBC]7]Ie_e"fϬ.[^~9Tb+V_̢|!M21Ȑ&g;jpN^pCA-YWAj Sk3E?|ՐSO;78}3֭ dДUtv7>#$"zswh<~CbUgOD>2ޙ;ݒXD>ξ@a9=n=9e:sGM=ةbb|BV*tY~Og-= ?%ṉ+&, _B|iί^WEU}/׉}N UK3g_ti*Gv̼TYHV:O?ķ.DO>Tl /̘*M:uC?q_ء BEY=9cvI$J]yhנ=g;a!4o؉>;>%n|pW?ݻg~6;Н봴_Ι;wN"סC|3ʋgF/<:{A;H >zœ}x ό:ṛnɈS*PƝ)Q]͛njK)SCs6ɿ [0eZإWV?ć~ܹk]dG'}vb,%cTeosK{~v^9%$ULUe/9 )e)Nt6/g2aHIIiٲO˺fnЕWDV{AO>Y'%:݁!-C e=himga?=,5xB.UKX{/Ow#[h3n7 ww+qʈi.jya4^`)j܅=$Yc_<_ǹp05xxe%^v٭/g\tkCRrF'm_g>bwLa-=DN]nyQnSO컗v/^2g?o[a{۫MOoϱ;\)]b3D9x tΚt;;bO'=4aÆ@*q݁'سT CwZ=ѝ4~'g}?E=M-0+8&_)~ʨxurp }nw,?1masYWvxպRK<ӵv'Zh;VB~]piW͙vN1;5k|s8MCf Nz8Vy%===T|̪Ͻ:`mʧ6 $/ mOuIDATm=4~1GyDغuPI?տGՙ$YC[l֭[u:~CSS4ir%ttC~be@8ۉQxu֥$w޼޽{f 왳}'z4#$T ;vWW|QuHX"*N:[z2+?$_O:T{j:cY/?öGJyyΝ;cՍ$hXS5;4ã_;k=Cu2W AD}ʕ˖/7m f6G+Ǥ7o*$_ON ӹs`#Uf:~Tl2---T(T[5P99眚5kƊ ^{P=l۶~]?TI,]`w&>4i j"Ϟ/QTҤɸqKByp폧>t۵K瞙V60T$I) ug|{âzjȩn>uօ*nke}ϠWw91(yH&~Hbuԉ͛7*ȸNKKqsc[С Br9#lrZL6IÆˡ~@NgvBR5{Zn*ZJ~~~6|6,^dG۾]ZZZžS~ē6mJ.Guԥߺ߹~gժU{lÆ10TIR?XqY;}$PQR@e‹/EȺu}ԑj8?P^Y/];w]v(7]$0|CzZ׎?{k˖-=yΏvӛحk)%v͛7G۴nשS'@WY7nF6LoկW/C$aôvh7/oEl+:\S_?v)5k5i٢Ź}Ζ${I煕Vt(%%]M.rXz[N'v%I*R6iλoᛱ-]v.[lqԑG}_ V$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$R@rEHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@PrZ3kR"g qɗļ{x,y.qʼzڧ%SKkʘ $F$7.;q?ڂo>KϺm֚oY~TWH.-ءO?c>Oر{!9cz߉yO]tSS/I/F%Sw<7o~awW/ݭ'^{+5LٮʊHn: GƊ?8g\uu}۬Oalgɟ{wLZɅc0>gbF;l{bcŦ0Y#<KN)))n]}VOeËd )w}K:N%Ntx0,yaOͺᄉ{p69oVzKo;yBfSb:~fȬ5F3$Zځ 筈ۮwf)Đ<"pcT7ųfmڣv^e\nWJy0J]$GEҳң6žڸ_To5v;cR[MzzSuՋnmԈdߜ:&yrkq7~Vَ_=3z{ NһM]]$z1+q¼ƽՉ`]6Qyɀ:{v}ymYx[N- @2*="YW7KnʺdꚝzIMKbEo>0 qƒ_셷y0o} 憬1OݣWSǿS (X渉'2kK>2&y̼>Ι횏i9n=u姶kX0԰ݩ܇y9fj u۸p|̡E$6o);릗ی]8S,v\36g=9ɗ ֆP3}y~~{ 2 hGKybR@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I %p.@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@ô+5jvŴP5-3JIDATP$KD2Y^jj=4wu;& I"K ; 2&#Nw, a]bn >r0m`GtlԠ˝Kk]!x;̌]sI_NW(y0hvh: I"fv; ~׭Y'{Ƹ s+woܿnR7޸d u=&C;xZ7viGv[ N߱ X`b^J7wN:}?U4Z,IYвq[ 7?`Bku(>:76c|I+zw5ô1#=ܿdIoLui;D ,qֶU*BrD$KX׭yvb_KRl\4ö}A|xㆶ.6:y7-# -}ۤVx=FFky2 T$Yh{'"{ݻfr%OvNe|oѭo{MbƤ~%wf 7Ї2Ҫ:N=$wRQok `l@J I .<7u}F'vh,6`Dᬻ;7؛:<.md|ߤů"u(ƐӮhÏ\65[FZu޴ r&h4)]vX(mH<|9,"%??>]iW\^9.orН6ۛcf_:@KoĹ=0@V#K.W~81,c3OY|e^٨`Ic-<륙}=p{sLjjeo)" @W^|Ϯj1au?fL]FN&B.%^?9ӟ͉t.jD瞟͛sO^^YgQI@U%ڞi ^{=k׮}GvXzzz;,TAb>Eomܸ)lݪEJBT~U/"=ii;q!)l⋧>護_=B#" @Ws̘1%bP)u䑵kNMMtPH5kl[ݺu;ml0T2 PUɅ#ժUˮ3B$${LD/5T?<ܹs/YxP8MVvuꩧe/CU"9Iuiղe_V|g ;HOOEI*"#GѲ͛7;Ƕoɿow>,(*+qE>$HX"*:vm2[v_mSt Sw?X'> ih=^1Cmڴiղ^xa̘1ah9/aN<7!!lSYarlTv_ҲEŋ`Ljukv,Zģ>ȣ7=IKDŅwa+>[}]$,*[3_UH.?O׬ZUy~rO>mCIQM7kVu$( GDf:? C4ɞO=vc{{nԨaP yް?XvڟINѡ{ 䳵⫱mֿg1獢]ӲN RɟG˖nݺX駟|{t_y=/%%eT=_]C?8*i$)@_ ?ߏ^rW?<{ȟZ8WcOm>7 I@eW#T-Z|%*[$35w˓tхcʬ.S8w G|s[Qݮm졪lҸqI'۾]do{EGլ١CU)"C5y҉۶m{qSg`ϥx`çkC㏷nٚ}?;,==T>nrb]$wSSWWҾ14U'Yz;tPxG@P#3gbGbǶѦM {?Xi$֭g5Bծ1ǶożWŖ*EI}>G\f'k):JR~4hv-rGUV^*ltm?aMB HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" g㻬$SD SS @aΜi9n5-gY ;,ec&ßļSY9 %C axm6l`\@HEI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD <1IDATI D$"h@gjciI-_qtCE^z2rk{|-_d]}UiXFs*->>$++J? =~\sݲK4~Ͳrؽ8G[VMEY<ҹO^z\F|-@u.ihjjZ>sTݨ˛Z]ૣ^]X˯\߲`Jj) mӆ&mv[5k&3 hO[CO`kkSsYx968$lTL-Ds U[UPQ~[^WZh1KRYGK:7YS?7Q:r%Y驹d)({a-1&'U[ j$֏^W^"8( +*~]AS*s36;~vDrbQ^fXcU~FZZF~Ucee' s; 5=H)+[lІҜky]nեiӒoVVo2ğAE!03tŊT+7*wuEEm'kbiie$"7Qɲ*?#--#K`B۱ʚS%]%3R gǚKPX (, 8siuQVz-;AbNaɄyMOS0ǖ\3|qoOX/b+>y뷟9J/ߔN&? =*qʣo݊D3oጷRz}3;m“<9agb@E#"rYt|ɼT|To$esygT:l5`-|.zI&Ck !}Nh]?:~ >m_#/aÆhhh8Org˅~[뮻rAņ~z=7=SK[>9bq'YhE$zbɓ=k ~{A=O?lQ92S'GDoӧw CvAcK֨}_GmA;4 Jз˅#﷕7|?:6IHHm"}t|9'3*ݞ>h#?{/ko?X,EI_E3JRL+-[K6lxADaG4v1GgM/~k׮[vm,6,tS} /l*H5z[GוFQ覯]派=#9C<ȃwKɺ?Oq菍NSWX"ɫ~TcKn+caGs=gmn߿zFvY}4IDATG$_y6w}Î?V=֬YUMMM}SB29mCO}sp.'/ŵƘIc:.o<{o[7du?Ve>@xDrթ#¨d?sLc2ڸk>^ @z=3zI|7eff?|p顛F1gm}L)e5[vSW%wv[W)@T*MMMG>4 %!1`Bۭ}ݭʽzQqg)+9[/7h.#~^\h7l]í_x㵗^ =VˏyggyT~˛C}6׋ɾ4Wa\lEy?<~}inO˙gjߜ ;]+՘|})" /^]ewxae]+ wϯ7{q>ן"=v'?eVLٙV6\{ɵҝ]Ï+MMH}[m⍷^_n!yMU/~oo~3;D#r ~j/~pwjG}MwL5H-iȑ!gY5{Mwf,ygȸ>n m#8ѿF'_,^粧IGzh?E$k5jߨV!}0ԟ"q>={Ϗ|t_ZSSSƚnT,jh/ }CYvZPzK>Q^k|W'w{7/#5^R‹/_<ַ_|;:;T~kԨ%oNY?"^{铏;6{꥗Zccvɴ$=6&nӲ yזURU!uy _Қ ;6qҚv5Ź^hIOO6kbduCðsԗ禷m{62eASEng7T9뎎0[k+c2Ϻc}Kk7TJ19'4s/mmSUM襅+֕4#G3iז?gD}K|;jM5GZ7-*?+qΜūxi]8++帕Zg09ɷ\JD2VPԴ`LfF2))Dڶ .}"=si]y^V3XU+Li-, TE%9K_[۔UK.NFFb갬vG%Tu&wtvV"h ɪkȉ3וee4W^Lψk`|v~A2#ys<'#-VP.A?`2&&&ԕ섢D"ɿuuTƺ겢^'߼rJOJ]6Ɩ,ϽMX]Sװn䉖V7 mΔKKKՄh2.=q0uM$~UkȞ.YLJcZ@m$@?50D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@HiD_o ;Cm$A"@H$" D$A"@H$" D$A"NIDAT@H$" D$A"@H$" D$A"@H8~;Zɕ?!<"mȐ!=O=<++(iMMMnk_.+>\k&=C7ve^yŠA>dh6iÆ S'?6 CO~?dK@SE]Ocfd k_;F9D]c㚧>3λTU:wetzisHNDo禜 ;cuX,}i/n*;k׮ toՂq>:!" l; mrkk>{Y _>~0^~y_{^dx:$zł{R_Ι# )ԉguV}Í7^#+TO|A#_TcUV!"+jkkSc9&my[wHիW6 plT{@/J1alj̘1?;+===xw@"HDV^?.cc2OۿD$Gx Ӊsߚwч$" ; á#6JeL&\"T<Ķޒ7kŊYcG&ل.͕)sMrRo9{?N yvG踳y3aamt}{’^o*'5*~c9ozkg}ŏ-&L;⨅?L|k^;#.ZTIz K&'#ď~}nFOXrK"y&<Ԅih,9yvvxza5""%HnDg]|tsn:1&I|z3gT2ׄgV${Ϝxss'WHW.[%$Vq9 +f}{3Sj. yD3KY8//93UrE7]>vj"@"" ;YGKTzr·.~&I\1g7_$^,ޕEk}ǧ}{"WDɷ^Zͣ;l>˲O>fŬX ?95yis?vDKsŗo^aa]+7gM9ɛ_r:[%ة%!/ zsFZMx=36;K&g N?'&~z3Iܫ$vXy>v{qG\ o+$KvĞBaGt*<%%"s\&|mlj7Mq·.ڤgϞ ޴%C̒p͏5^IobCN֜vg1;l("Vy>В%O|C9 }!C>8{1'{xVVxnقΛ6uO_v1{FQ۷CJ^!|a46\,\xW }֞C>8 oFݲe]w={W]}+ D$a'x# {<>y}9@Ⱦxzv킌wʛ>=/z97?~?|scѲaÆ+;)yO~?wu/}txW^!r_S>9bxXvI>d9.#c%_G5rȃ:h>?ic㚧>3λTU{}s>qN;-/uV_o =3R^o K/].vذ>/dh6 0 m@s=/}t|dܮ}=ϚM>#=}Pk~s˭ȋ YpWGƝןw^xj}/|i!#| [{+~{A=vkJ0yG0g=[n ?" 2 g4rdstءTbr_Ι_)ԉguV}Í7I`{C yݩ)>__TcUVgFz1lW;B^.ViaGyj js=?o7dȐΞx'(zFIz﬩ҙ֦sLw>В%O|JSyGnk׮_ ')" 3>pMxԨrJiڵ{?+ ;oQlYuwOUE߽Ax?Yzu1 [ /J=zG=OUĵgD-U:Ukּ?kbD?/;ۻ]w9GŽWBAC iiR~;@_aÆ_y%e]ƎWwwVYSSS!T7.^hz'M񓺵`ɫz{D$5- o|#O<$6lؖG a{z RvKsk}~N1jG<$cH}o4_[lEuew>y;ͧ睶HÏ;6cmg}RS_W2+mˇjL|;p`]]OcƟ/\QcF}gfegOj Ճ=?iś `ǰĒd,6,@Rf-x_)0N=<Î5$cȘIcӾ|ڼy}k|Wxqq:}Cƒ' WuǼۚ?2%߾g[kfG#t'O ׏z#ۙ\8ܼ; ¶x̄TcŊoV>+?濹UUvg?8tg"ի+MOgt/n|y}=陣2CpGnwSg{WMXl1~|]+?oTqc7ŧHnOTظ&ua~>g'StJ}Í7mS}IT/͘;c_jJ%"=]?H4---%O}C>k˾/| ŵV gL⍦sO>٧?|vv]1S>agSC7(jd p|ke[7|ԍ6Yp܄7ץEv~I.ٗ}0k[Bo->kK1xKIIDATyUo6~r?<G{t؊3DŽ0&3[>{ݘ>E F]7]^6xόl=~Ҥڶ !vՍYW]P}Φ:|+WnHM͖+ZŮZt_6 aӭOM+KP6,`*oԺq*Vtg~=tYw۷2߮976׭aXV=kmCQn| ]U`n*KwS.?ZYmW[w+tGFR}}}Ǐ;j냒 2yu+tQq!Qk_aZbe ?6[|zƯfzwmnx~CIiP!;.yYi ]xRBaa^ǜCqæg69⪜.ٯ/[>+ g\󐆲{~̇o肏LVdf5m;?n٭܍{StLԪH>]sb?=0<_ټxw.j${(mz]b%=&Zˏ-Nck-hc=Rm٧]P=0u^.K-h;ښD͹wX[y!ԍ-kosHԉsXO|eV%Vm)p[1uM ȵrU'RmZoWB^>Y|ݘ8׸ɬ6%]G}`tm̰t A?HV:Xl2Rpc-Ýou† ͉98v?;7tZؘ#|'%O%7o#yɖt3k|7u2$fgfm{읰kָ6=ck Zn##3;N.=~cicaCH oLjcK*ij'>! [Rc~zܒ46kX7۸n2Lh=tCy%⪆p`aK@*Qn`yjNJMCU-NK&Ru}YuyLN#]'_ɒ[M0ݕ2]tqwg=i%$;T,ZԴy ɐ,ha{oox;c|W[ROonN["7Vv vv>3{Ucؿh޼V~8%VO?b ^oܼunYWVNfB`|ZKݿYnKLu˺ wkd2$tg+ֶ_{6-K?n4Vu9GrQ2.N[ORWBrqgϕy7.Jxw肖ŻiߙVzQoOzoϥ?- ;yI_维W>Nzl:7aXE[NƬʗ9`&wٷcur~fdyl߂RYhcųGqyMʮu<Зx'>laG poviT~;|:~`mXſקkR"ӖF{*W;go,7{PZ|zv~sRa>-[Y%5n\߶00+e߫6.qDRT^вKZK6ke.%'N- '/j©'QM1c[Buוk~CJ5}:X-Əx-[C-[,Ոņ'QtW.YT2!~;p5|Y=!Οt?篼1gwnyrupT޲dEۆ֟zA;m&MvVN^)}<ۖ|dO%@/jiefϗTwk~ W~,Y0I]6nRZuǧ ̹*gǏ?Ew^qM!~Z /'U,m|rg_wW*tCe'o]"`7\tKbXy }Z\xoloUɣͯY,Zv9MyYg8Tj=k/JLJf\p<ļڱTvWycS73w}~Cݩ/ o©y9!S}\sYmn97/_To|#ΆMξɚ6οCe˃ $䳖mMxRngvĹZ?Ƈ\ٗ+nķM\{b.-O_|u7V;[HE$ =i_}b{OO%dj-6sa+=}Y*6fQn,{ԓjqM]8ukkwфOukN Wl2{Ӛ_bc,^\oϹzE?(@pqURc&L6o׫Y):V_}}۷u olWk ?e}ROoqg?_&޸wi]z?=;\چ~_O5̘>/˯~Tm˃H͏+O<<++h|)75un=C"$?u| iٗ=H9s>x˟~,]6mʴT9'{M8@Jd'EMZ^5N iχ o/Ӯ߰~CI֭]oK㿴5Cq6{iNI?{jSy*h`z߀T+Kp7Pwytꤏ~?60 O<xo6lVwR]a?\t~Jf\Gy˿4K?&>nt~x˧xkO"!2VBƽ]SO][v=>ӕFFFF?_?GSg?1=׭r;~ҤFw?"- ="F$x.O+{w-Nz!]+{W}6?+v>Ǐl+a \ e]^dž a;PIDATz[-~~};p^TXCWzW_/!]X_';kzT?555u_o s --=OBtUyx㐃>}mB@>cDŽH{T`'QE^{{3>zDI`ۉHN3ώ| D|};$, ;3>w4hQG1|Xlfݺ /6aAI``u!YmqvpV~Z[Vwv0xG}7 7hЮO؞{{|qm3T`Gɿ^lll|W֯_: --^4C }FZSSSƚ3>dh6H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@HEI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"h@˲ҲK뺼GU~ZJ~ULHW=hYU}gWde45ccj*3bUk̏[zE5ElI;Bɰ.Guٻ<'/[ܱ~s/< o.Zb}OD$-)"7$5ٗ&_=a}&"W3[.idviC/2eASSCivcku Ue9YXz˚Y9E嵝W\W_U?&f|AiU]MqVZZNyCG^,v٥#/\PնdCEf;WmkˋsǴL>=6&nӲ yזURU!uy DaTU]嵷oezZٔUuP֦n)M{bҪKt&>k'?ӆ-\?jk%?-j)央#=34q T6t|ܗuR-l*H;NM(]gcMq<:uҭkDD؟|hv΂ uϦC,B%Ɇ1gvkme~uXYw=si&Z_LvdLۡ 2u]L69TWP?[ COSS]v[F]r_MiN\iYT姝<7l!tS[5vڲmO89UYRErL >i_K'꾩]Ҝݨs/}m#Z7Ӽ^sRΣf.o&bUZx\cU~V*L79^xi]8++帕,(H!IMZ43s%&` əgth$;#dĚC'ͩ.Jo}ߺ˺sOFL]\~YqVy~g6g'kC֔|lTK*沊*Rq57׆nҚ}1囮m/eekn( Е人1XzZemmդ:sr::NjY̰V t9'7/cYU kW-^0kF Ժa=vTptNTE{<)(HlEmP_S>mf5dXVZ!dWR+<$oLVKX'6^g2n&G[H6Vfv7viQb{--,kX״ 6| ۮө:^<5m7%$_AH'[H9d]Q_ڦZu%6,Wv,+;"tbmuMUXA&W[RU33u꺆Tv+SxTTvp+eeBfvvsnm8;V:3CeӦm?}ceL ƈK4[HV]8sy]y^VFsXz SK:3es26nLnOEW\dJ RWvBQ~f艚WҊoDcC6ONfuiIe 3ҲmwT;~ceQѣЂ삂첪TH~c%[Hvxc-D$3cC]uu]*(;ɉfrJOJ]6Ɩ,ϽMX]Sװn䉖V7 ϔKKKՄhִfK+ $oL R%qcoL uEc2:ٶƪDۆM}$KTN$!;3q#U%v*D.y4;4Tw=aNuUU~kv8k'ͪ,J9lSrf)3,_[Wn2o ޷tmy SmoLgƿ_.ƿ^sY H Ue8g\4Q4!Ű4sCWIɷԤ, M̿[%(aR, lҠ *9ss|s{<9<@RYH GLF 2^t7YYYY#Ɋpb^(@(@" d !@" d !@" d !@" d !@" d !@" d !@" d !@" d !@" d !@*5DM6;0@%E@B$ $D@B$ $D@B$ $D@B$ $D@B$ $D@B$ $D@B$ $D@B$ $D@B$ 9!DW'JWIG1s̙QG_ѽR@-ɑeAɹsyg11H;헕S$̟To2v2 -cz6>GKyۯROO9%mn>D}`;tPt֭f[ NXlX#):+w}1sW JJf 5d"Z1ʳvΎ=8-pcc=vz8'ygqU&Ԃwύ"`y+>XR SرWݖzzݿHO㰮~}A=}ؼy>IsoAdWm[斝?}]W*cTWz*݋.xeVE2ָq#t+P /RYf Add+4i=g| |M7PWë{*3;+;PI>'=PI=w(QWd6('6zflj?PƫonUD6m^[('6;0@%D9!%- 4LF2I  2I efd͘93Phʳң{(@+m۶jTgʼn -G\t 'P?瞝CC~y'ĉ}s_Z"h@Dƍ \$D&mܸq˖-q ֭ Ԑ9*6$!-C$׿ޥ_coY2D22s֬m۶aѢŗ]>P)QH[Ϗ?;[p^ۋ-j=dAE1Èӷ&49f#NMn-Tí;֝J|)?Է)͛oy;v숞6j;dE2tٲ= 3wyŭ[V|#3wD1wn~buny c7JΝts;-xN8Θ,iSs⻇'͝ѳQ23Tݓx~ O==}jȬǴA2D򯓟=3RO'O?;g']C$c/6unS'O=w6qsA'^u}it7йWtxŗW;G&"KRQ*<[gǪon?d92g{$;==E{ނKcO^ +@5 ՂrO%f޹ tS/+77+{∹CYE^pUӷ:7;+pK-s^NvrSYvggOeO~MC*5$4( 7D21MTR}t4TD 2I  = o2xR^ls̖;:V=27{BH~@cI  2PfHN<) Q$ $D@B$ $D@ 4D^2e_Z|k~G!ݴlٲ2IDATuV'tbNPD ܼy-役g!Mz3#n}')I{d޼t=>r^q~m۶P%;v{ (/>B%=9^zsrm/٬ynV,]߫__ >쳻Fv֬ٓ'=>Jzw8Hi9ŋC%͟{CMm~:ϣν܎uLHzqWiџ:v/|/xe~~~uʼn?@KEt-[D?xBhѺc/鳓'?Vfaƍ~an/Hi"9'RVă=[+-Ү}q~4GǜtLu;vT|9*(d \{^~Eŧ~`q+zVאk_Wk([+=\W|~?F%-C$#3gOnHμ%KK$T ֆc޷{䊬h.X`SH"77)]_Pv9/'kQv0웦[mܹs 9kuP ]O .,;͛:gOGO6m 4 i;őK-gsZ99]rt=uIT;6,;CgZۮeyNvbX3^Κ={Q:o|}2@HɿN~;_=~:yʔ%zt>cjߩ}(Wvȴ >^䂻-)k]}Ψe';yv2`BQ+w3K/JDiy|l?=T`>r}OM|A_s?W۵HC{&?1 g- ȂYW.Yuw~2rŸYCx-=`tb\o kV3*$2<3,|msڕTr3ӿ՞2KZ"W]qe"z̚=۷m62['$uN֨"Ke2=9#-8!1 K.' qdH'yˣGyƌ}a?ofiݬ]0NL4ud;քڕ[jX`?7hrJ9 _5]` nJfv\sF-k;Čdߔ2e{[[MY?e-[P٢E"zJXb7>RޔgZᓂi{M;wˋmwa#S3m2ۊqP;\tmH%9O ; nZdn^wǨ=dR!O>9@_ lh'>pCe O`A"V񊛮~2:[6l~j™gQuu#o=Jt ?PmG:4N<|9?d>oG?3ZAH?O;-JtMz8w c̅qswVVVAHF@f͢${ng떭!#,[}Dk5''@(4 _ܟ{Eߍ;xGֽ_rIthCCY8s+^1iFjaל[ ^C |_??5;_'DO׮X=OD)돿$ gؙg1k?}v,rȝ|b} @E2vG?1~…| ~Hg=wo_o>(B$c;=Fd" d6!@" d !@j@!Λ7oʕ+V 䐃nŖu8kלsaak!oUW__P{/z,ZxO__]rw4`{L?Sdp|.>`ÐW_k֭q{H4a-^N*CN=ڋ|[K_R}L*o+/Y^ђ)}Qk-rHNHvaqbwo*>և?vw:.LhӢ˙].!{7|lE 6/B$;u'-*?Dr7o8ݱ{?~BNLkM6Xܵ6nܸf͚8ݹsN!81'֭[WvUn?4gE^zkEs8q)~Q$"_?CB˯/-{䄧!_8$40u:UرcǘcqC )DrkqzY?ɍ2ej@yohx4mr Ҳ-Z=O92B:HFzt~ Nߛ./=ۂ DCޔ}Ԑ.f_u8b?pW7o?~z?zڼy @h qdez}֭kNN.]<֭'v=-v8mXv|. oW^7٧ɖ[w9ի_zyٳ'OS>p S_d䯓ŗoN2%z3f,}o]f_=^wO CLK.uwn^ ,o;lʀ }FLg^2MYC2J׎pu rwsHs>%/.O.- Alؾ&>蠲s~Bo׮ mgj´LܹeC '^_H,0nmj[چ w=37aa=ɻ׎0tYbIJwg]8왂=3lZ^;anݽOg ^iw^[vl2I&eg939]|$'-G]?=f͞]b۶W`KFwmaaS1 Ck뺡w۵-ÊqHm<Ƕw=3z-ݮcXy9=E:'kTVH=+W>_s{ضu[(t}=d4 $xyeQW.*v+BۇD@c2>21Hd221#v.kL/>{٨s& {kEqx[e ʼn^>4i9v;8CMzaȔkG_3jY2q钕 㮹neY1n@րq+ɸ> k\e84$=diN>cFda9wfg wLn3w 8}Wۡ׍:'k&e :*~5M .…mM\s]=KѻQ}2b3klA[>4$Y%ɦ!m}ᇭcǎ{͵}AXdzv4_mv`nKIDATJ̉8_%nX!40s&M`40"Ć~<AW}a9׭ aЬֆ}hCqƟE̜h;iӾy8a}/2ں5nrggO;w~Wzšh* 7woOrwԣ ]OCxcf/ze+?>q=Z iN$U!n ̑__[ȵ=;4O>o+>2ME|Iy7-~+B5mX ;(l/=u`ʍ"9[W=wP?+hW~ӧ^!F̹=/?am/{<}A+>EyEjqOuWP]yBA|demu`΅S7P^dI~+ߡiht!!=Cmt' ⷏4mޡ# \p`/aNtd^[ۻyOj[?'MּwnYGO ka_|KWF Tr=cD۟_׶ 5"٢%-ްtP <\ G/ esO|d|ާ-|ڜP=-.Ͻd͹v &}!oݱyVVV˧~K{m:ݸ(hEnWKoœk[tm99O>];l,#g-(!2)?9m遇tO^mC50dz$GorO?G e" #D@B$ $D@B$ $D@B$ $D@B$ $D@B$ $D@B$ $D@B$ $D@B$ $D@B$ $D@B$ $D@B$ $D@H~icHOF2I  2I  2I  2I  2I  2I  2I  2I  2I w䧟ny^j2Y/̙œ2wsZלSeYf eYR\feYfe932^#PQfeYfeYfeYfeYܤI8C=KG?5Dr˖-/;Alڴ)`˖-&m߾Md-ڴiӟߍ?, Pq!Md'iM "?߼ɝ:;ԂO6o^w׿۹S&/Dr'^6N<+t>9u͛'Ok>}6mꟽBZq|dVVV>Ga?*N'+??>ٴ1Lx3g.ZxGu?gА|G/_޺UN:i yHC|/_;7~e˖2rk>ͨ2,sܸqf7pM6=mxA|Oᥗ_!^<# Mz3#n}')ieo-^P[~aCfPU/\beHK~TB$lmj\nڙGrC=d_-yt~e?߼yjɚߞ?ŤYRqZ.$B$?d-$ߙ2uj[׮x-Z #f+~i߳~O2Pl߾ۧ~CXT|؟F} ;T~aNHl9kNOikď@MxlܟR?2乿N )Z*ǫ鳓'?9kU0n|!??ǎB2zN!Ԡm۶_N:N8!N:r;P~ ĦMP tPz-׫֭Zu=DgH4PSߎM6ﵗ+D(ATE>ƍGZ1PL(Ѯ]ۣ<2TOc>S#riQ"3 Ҥg'ljgҗ@):o^eRHV}z@ ֽ%5jgVdW_{mʔs^|io]G 5k-[y9]Nӧ:JN.qpOҖ1B ƉSO=5eRX].(@`D֭5kVv͛7t=gb)^]|$46mZlٳ'-Q p÷lR*4U h֭['zJԥKAd<> POlڴ)N4sΛ7V4sIDAT{g}jǎwt{Ee6o~`2چ _}7_&=;ehɿ/>y-mC9xoFO>$Yz5kDVڴn!hڴiDVVViy_!W~/ @Ѽݺv]zᦟn޼yǎW^֭;w>ĵ{8гP׬œ(ѭkIcǎKܲeK>:c>: ՠ+57}wA{y=i]sG_:H^@׺Ub8 q߽qq sSd}W_{mʔs^|io]GjWziޓN:i}_ƍ=+TߜC_ih}N:G`<B^_;?Enj" D@m޼_?@_K/=0fQGcO>SsΟ.l{Ղ3cd?ז~ _hۦu7F][UڶisGꍼ%K&P&{;C9`Hz! ,P{ʘ7o)9]>{ʿ/?kgo۶- +]N4/~ [bsWDN a=XbeυLUB+= g͕O.[(yamd>''?f曁:ͫ׬Yʢ?e}9/9/'5k֡}@) {ЧnY}+@̗;n},@2$P ONxjR}>_߳>c;ۼڱ}o&,Z{ٰacT5f͞8ECmm-|n !xx_V^uu˷}e[9hx M.Hy )|kųS|ԕO6o.Of~a;ӯ^{h[n]([dO?*@ҮQλ~ 9]!QV{Y/̙œ(ѭki]sK|MC=3'ą>?ung{˖D۾?6uk͚5<}>?=*olj?PV3o<|UшÕr osDhc^~(9w"BчL? ;ueO?hӊ^x=r䗾jْ=_>.zm֑E4?Y`7 =nQU_|TĤn -J̊. JϧL:^&~رҁ㞝;l֌#Zj5u򤫾鳓'?:UmnO,2e g~h ʼnů|E.z^P8UNy2z"WPSne,,#^ =;ejާio}/PxSgz)ٝ?/\9+P6~aH%vA7nͺu }GGDE}rWL*@FӦM; T#V1s=d_v =cv<7 ,o8pg_>o۝82C(#Jvu2Ǔ +Wi@HQ&f.٦:{Wś# Wo/J\R ioo%7?pek64iҤoާ?}טzlԿȁp+@ƍ9HS[5'zDP4 ĥ\|g둇v=֭[zkŴӻw¾EZ荟''~ԶGN\y}~}pcbI׉"o?p 'ΎLx`ɸɯrJ^ѣ81/ ͟EA(maJ"݊+]>$jry~zSyݷWzKQB2[ = @:iӺUR ܲeˤg'Ϙ9sѢūV>9cF 5k-[y9]Nӧ:kM2u΋/-_k?@mUR'f^^ޒ%K^<+=z{֭Zt҉O;馲:o^eR L̳}Um-o// 2?[^[#^˲?CEJL@R.TɚRgGmȜ I͚`Aܩ?N߻ܖe5紮9^gY7/ }9=~?FK'4pd9_S-W..=u}8ͣFwտpaz䗎hсڧڅv!5np_Yې9g\jU'w>|yg{صEfK~*Lx_Աc$R\gWh`nnڙ^1vۻwjNW^YjȼyOzϽ)UJj\n] TPT3nϷm.]NֽjkqemDʌ,IvGFJ.ש<[T}[lyw^=PTPA=Kdm#Wm I5_>}z7mZ-۷}F wjԨ.MU4 2 }Vy5לx Gqđ_R#Uxzڰa㫯ˤgL=z~ч:z+gݯG}Ա@-Ң*ߏ'xb#PCm -{+:YYfO>ϻ}P{qT_>.PTPn6+c:{3fF~\hQĿL:裻wZƟ\ѧ[n}ߟpY )@$0qZ7uV U׬^&JnժMV>/O6m Lj\]+/߉Ԑ}E 2nQgGHNi);jg;Ǿ?6P:V%5ubGv{~z P@ŭYfgB4~O(7JԺ3f͞KQhC=Ced{w;0vvTQj7蟬5{, .׾/ʹ\iԍog/;T __lXY/̉u Ԏh'Nn]svnpT)@ꕲ\geϧLhqJ]`ȐNyptxSW \|wqqQ~a͚Eyjp8nIDATCUsOQ@jjIW}g'O~ 3=NֹS/}|q#+b}iӺ.l?d:5F ݃Oց=}e{ކlsbPUzNlذq䂳 GmKuke䜝]ER ȩNî#w:+4t [ǏPy۶m孿ӝ:u#ګ6(7N{#T#V1sс PV%N=B={ϯo;⧷]]꙯}C9$P QSTG̘5+PCTPY=Bd#WVms95rU_JiA:O<=Diy'.3<#Pa5JĉY#PQCc7ni=R6~%w .Tj韬K5r Yt={_|.seW%z.4N,\fMؘ+NQF;{ ԐrǓN~z~~~`9@(0TyT\ge*h('K_:"^S ? dɒ8á*tJuI=U֡}gө=e5ciӦ@ iۦ1Gզڅ*S1uGې=͟*ϹF4Njɿ^}-N5|F}4m$J|+WY *U|G ҎLABðp8qꩧ~4n7Ptɗ;n}ټys`A/|!TƜ_͚5wyW>j|W6e[|kF@kٲeVN:6WvUR O==cEZfQŖ-<Ȝ.]VO.w/Uv=R?._&Eodv۾xc֭,?k=+J}V*<+mۖ>8˪]vTƿ;mGlOq.ϟ / T>gzU>85Qٶn4 q:?˕Z:n5jt\c'+Wk&ԨYPit"(@* QoF(@{e]gSg(֭]N=%D 9]uJJ09R+%*rÍ][~1yʔe.>Xv/^>N_jY^~9Tg3sxȦM.[~Kttr'BTG.wV{хz r"- Wv..Tj.韬{<}e.u.ϝ7/Ts9hԸ{/Nn}'P :8QPY :*@@495:zD@2U|n=~Tղ*i֭{ݩc@йs8 sO>9P%7oSrs}}Y팛m۶Q$nڙOĎ;~{N+Y3DG=Xxwk`$JE|PY}WoURI̫O աڭ3'ᾲFgoC%D[xs9iԸ "77*jmi~q>!KjH%v Qԁ"=fZ`l2XD3f!QVDO+QX~l׬ UkK!_Hfn@xѿ5kIS ?e`Uy;oit(^|;oudvڅ˗,_lgLqz|叿疶VuN̢{lT0]ʕH+";+;Mr;.]z '*ɤ}]DewW*/1'+]}V*?NTgtnLKM_ewzh\.^RKd)++{:{vmF-[޹\6gzeU-`'չ&*[6/QU@J*x@9HMmhQuN~njW+xlDP/@j5~WR>8NDmP;2qxOf̜Gt _ѽRVD͇HC,*ע/䘩?\Gt IG~=^n^8saHNy+cYYYFUXϿ䲁;|ehּYqNȝ0jب-sz^9{mZܹ(WqJ4LU]/V)a4jSB5v+eVT,ch#@ӭkN 5Hhl9)ڴnuZלѦ:nݺ?7 F-RҿsTWLe>SJsrUyWă=[+-Ү}@?:c#Gر#ԜT%۶m孿v>v]B:~/+1n]P}SP؎jJ{*X)ǿE էڭ=UReO7 rCqB h  uV25eI!}ŗ^a(c8kڡCw9kVEVy~?F8á `8s5@r_Wk([+=\!JLo%4mr㷥fϬ39}cƔMX.c;t{˯ F.xWoURϿL#]JS.U+$4.] Ieq|%P@ hm2X۶m? wYYY!}ͼ>'+;;wk"%K^xq92,Z_yzs {̂$&/H-:/';+%e_vᑝolEV}dɒ8}ڲv\׆a; gWh7rSVfߔU/c޷{P*^+|ՑUuH~ƭUs. ,Sbt.Ӏ5ekq:On @)jBFLUJjRBMQVu?Y/pw=6z4ۯC/sy[u*y˩~'ui*zD_]W?dCzaNny,]R 2RC*Ztmwf"/t~#v\wéNo. T%:.1'=Lhh5kquOnŖ-[v϶yY{|paOtǖCZW0~Z;7?~L JKqbfq%gJE WP{F-k;Y"|45T>v[amZg>zMI]ˆvHPJX3 ]O . Vda;>Cم̏5IDAT_J'%fYdnk$rCE<&4z' T~ b?( uyB:TxF9یMOr ]Z׿zFgW73+9ٻ}}EԮ.p*_(mGHE"-)r]AZn޷k}4Y%4`vmF9^cIeYcǍ";vfOAj=w~͍ k+lb`O+[*n__AʿQﮨv|J nȣGV!5DXԀdӨv]+ڥMSRvkjRv]QZF[]˹y=g:5 PoTT;]ʕV}QRRo[gI!-*R@AV컗)2 Z蹭-䥪}z6'Jh@Ɗ4v~jΩ_ ȍ~z͚%B^Jœ=z)A6^'wB ;^q\K{0W(@F=)@j#voӭWJ5Rb_gjl];x]VþDg2*D22f¨F zח.[/~oP}67d}aݬ[Z;_s_n߾Qwu>G㧞-y'4г2ԕ2GYn]8鴓J{3w ,iwvYR㮝.E ww<>w{&Q\<3}"}uPulL9}N2|ǖײQ$oW ɽvه5چiwVl '֭{'TIԑybyв]:kv'ܶwmvQeowJe쁲O-q_]!rG7 lBA ;wyã`=[X'Y%׊lXꉆl*paGD$uQ-ݚșȳNҫ չqG̠q-FςsFA~mO׷KéŐc⃡ ]RAˣ#1=^%[R3uP%zzLܼ}$GSxk"3nCne_xQ Ψ ~ÇYEΎ}]AߵP|r9=z~[|':֭[CZH\ʊC:yEƻ 67VBEDh,?[X<&'UZv/Q66te.mh|P#J9Ap|+*X).nRB[Trm#K]?ۺt^WKԅARiӦʪ>dyX?.BdF݈JTX޽\!eU}dni׮Zk2 'C88;-&u!{d4 FvL";`W?1(QUO4RR2/ US5HRyRڵ?ϨjUҺnL妢f^?vu<:J+[솪~~; ./L{~OZ5k(Zu~4«=w1c[n%JЦMUV9s(Hkjиc{{FQ\Ԯ7X.ʨ`E}YJa)&2$^4Yݯ7䒐քjc=-~-ju'jE^SjTm7e C& ne*'v]G]RꭓSV⍙*jrSg]vˤڭn O͊=*ޥjq΢;Mq/N0/3pHM!.#%tRiVFe9WP/-cKZ r |i: ={>}z;| _AJr)mXz.]<kZ %MRWKKiӗnO>Yܵ9uBU컗s.x`w \NT#c]W~(x,M^*EC%ڙcU e֩* ,MM5NJm@μۣ﫰4iFt.߭Jk /8[QXn]ڡ{Ͼ†K3:MnQ!'c{TOjF(/` 2gFES݌SH79W0E^n_/s4at%E1c/u?'VKs_?`J%S^v#RxJL7Mm><><4 5[k^N lŊ'Lbad钕W29sr4LhzSt#ה ֬F^}a9+T G͏>D+=!ɱ* E.wTuuʖ=D_FMBhne%CvJ^BZ΍O [=?qӺ`<Ӌ7AGܜcZ|$ԛmUBQi[ImKi{T-";ERs?u"5"LaDyTwؾܟC\rCbĶIKv JKD-1oe.Ǖ<p-b+ HjEOD-zJ!ђo*kwJ L4?p;\rVF"$e,{YVOk'x%F,eV(vm!}fL\f&~0E1vꂛźʓh@'!ؠQk;VDE'JV=ƖckBb-Q<~C'4YPtNGP !vr69MA#Gr\z$Α>4TAQӫDa՟hDُ$p֧!21vEv vq2++W&QLgvGNj7 vS;nHub |ԥw<޷s.W2fZDuŝ{;o}*ԏxCt*@y̳-2nwIťv6.gSCy 'ϑZKɸDs叱{'J irEvRw=+6yMkV r[fMy*KZRq[UJVmT,Z׋ZT:8n]$jLy6lXo#~Η_Pү˻dm H jVt؉hDLwC*$c.!QS;sp=[yOQt~SxѿM_ZWU^v~Ju5 Jv_WOܐ8nDQ NGs (q6۪Я+1A I޺kt ?PW~U1]KE#PB-(٥S* 6ګoLzvԂHч:5fQx7zriO nsL XS=t|dݒq#KqĜ<3ZWDYG\HL),IT_2QB)hDc"3Q&93fb,_Jk'-}2#CkZ`i8|cYi6o|}͛?m^s͉'pG/5jT#~w민~IDŽ*k|Pu_߳>c;qƿN6wi=nЊ Fd8@eͶ& fЪ F?HES85[,]R-Į6 c;EK)npPu8LOTǝ >@CFu$.+Kvys!U7'(lEw,&fMqE6'OB{v9sϯ|eUoE瞨z)'=>ZPIxd[=A%ӑ5wz&s$Hʹ7gdh)Tr*1VeHTV|֭:ēѿ_~>Wkk;U񹭫*71VIX6Ꜭ +Jy sf0'v]sN*C[5ESVjUjb٪(>_0 qzvhO獒[u;XՙcLN;F/.g}ڵ>5mwׯl](g*C=7(5qsRsR}OJlخo*wt6U^=% (T1Vw/\]z|.J- *0UVbXZ|ZJ'I d h>OD91EĥE ?*݀B_`r-%^`jJWL*9ʂ\n;VͨqB,+I)*J,*I^Mިqr~ТXReZ1R.yarfQz]%s)@XCRL)@.]sr*~P{*wQU.HA@dKD읡j^Ib|;qz=[ii{/^XOE ξ:U%6*ƿQ⧪~V:"#]#:pr?U8i339XnE#K[c15[1щwV 3\!yK-"oݦr1ʉJJωi7jX4uK/kT4ܱcǕa'^_zow|mlٻ_܀O8`tI#%&^diyb-&'| %HViw6VpȲ W$a +!3Lk{IF.Vt,4u+ M3rz .[PwZ8<\60uE἗^_sL#C%̲$H?쁴O%؂&o9U<Vj1s~DmP1̟{C{ w{]zѕ[T3zw>;bo얶bO<[ T=񴭶}Cپv>K&~'i/̴ =T"j;x#'/ճTmi XE/Uo#D_nJʟ;jY%Mmd%Xډ%hpJtύnLJD_xVC& O-QE8om#e B/?4m@fD㘸7-O޽҆Yц+?`(-QU ܦN0In1.M|´SW[p?ׯ_umV¸O<׭]mMrXC Ƅ >zX!>=N̉r*j :Z0j#pElًa ; BWeεͻsWn>䰒UēkZ4c;/ۡuk~^Jn䐚M-[ܭdT;;rcFw\[ug6ovKϴm=?1a"W؜klެܳ9sw&} YOm)d]v_dW݉?WƮ3߻&60I4gU6Ms7jZNML5|?Z:>f'*jB2藏#h~Xz_z'П ^2S}G_OKdzDLV&on x7EIYqys5״M=`L˭I<[>Ƕ|REd R j'wzW=%R"цKss-Д"~H2"z{ۆdFhч$wP[+DOksSh9` h yc\vDSrI,wѝ-#vt~~⹑|~6e,~P5Uk|'5io| WP]I==Qh["v{ꦌk~RXأoz 6gNSݡ?Ҝdzȥ߹syMH@N3rqkH2x|27CE047k$R-hvnnWARbyĨ-p5lJ$ FoƼUtO)#ZvQȍ(&FdXY^Z\UPItMGVҦU/i &@ӨRogf"ƷEW?toƯ_qșʗWKҬQ__+Z5%4|&-;^yn vz:/~Zt[We|Y.y g6}= mBfd7/olRhDϱ8zrV^m bp[Ҳ?5~?_YW|[2f|󻑦w5汰,c|VߓZkwL6I2iƷ-:̛oiUm>o ;b>1&n?էtBC;qQew4}Jlώy۞;RuYedڴ6~yL.hVsf_F70GA6?}7k#sQ7o)r'ҀEoGRu\+j@_㛱 PG37֫j'̪8d3ln;$y6{M8i7}*lyL$o7 m|X?,yy5ezsu.#mǣEZmG4UUCUW+op23g<3캱W5|M詺?د.q߻ZwJ~upMW ]!|T#ቕ_j#a[_{G}7ތ?4O۲;};ԋ.;{~YNwח~IͯN c2?Ꮾwu3)?ywﻡ3z5l[ou苰^{vx{sFtҨ|C}f:U{o :q}_NSvn]BvU73EߔM7Eo!츛I@kZeoXZ0=睢ԛvH̭~lSO#Bqr{BC#/h GQJ4 ݁dkv])[]NThQIGƱtK=fUmµƅg~59GutmryI6ެc !z䑧V=7{NLt>v԰g7i'o~pąO^qyG5"7?<.[oVjD񥗖=M}_Snt.t-ysKEZz>oOO]d5q AT U:~>u's3rr2 c{ #B+ֹ|rT~iM~ϡziM yvU)I4t聘v%K{WFFFbA\8C}>-.?gpG؉^\cncSN?X]]?)tf׿֭[dɳv ;S> :3rsL*ڵ}_Snt .'1Pi9+CFXꉽ_Y'T:9Vys~ԣty{r2O"RB[4 ;Nt$>&"z'V)vaQ!t3[svi}k!3rH~X:s o櫯zEWL⚛ջW`'XvO_w>e[Z^x)nF)bɒ0N8!tQyy~{ߏʳ_?sy@mg~m}3f to}\w}܂Ï<2|'~\ʬ+4|C+{wNˍ閳ovNxGfKnK=v;nz&ͯ1ySZъT_;){zC |kK-Uޜt+pݜq:Hu04>vH8>tKB$ev{>^WG[;Ynvc+;#{zP tnåaW[R'h#ssjժUq][oy駟y&/'GQã'uu+V.moQyy{ޚ'nv!33}{߿6p;G?nņ ,g5z[ 'S;}=b}u_Rƅ@Wvn7%oNVrn ao:~{.f~}f4:(?۩vn9?4˯x뭷ٗw@Oug_^ ÷-Jr/xh ]o}}?a0v믿6uuBر⡄#]rɶlnA︽soGݻj:)w_Rj;BKnf tϴz͚p>N5N6<=RQ`w߶nzjrW_5.BaL];ҏTG};bٲv{;uyH?NfYApßs-zwH:l[xqak׮{[B6펤ڢ HO֓_v8-DrR༲?Bv;7.̞U],ɳ̉{n`Wnh͎?oz2 HGh@#s $'T )s;_o1ihhx7 .u>v԰aQ^丫.{]qo:*=Nh3ؔm8 B4 ]JЭR䠁)=Sdx$VN/?vڨYpYإv};OO>/;@tc'~O=t<ޕ ׬]2Bv]O W^Kxަ/$ Ӏt @wcmo/ OCeU+@RWٜ֭ /(wj>/)=)gCtc9+nFa}7*rWoCy i O/ +߁tw衇0c?w~[otk`C[<ˑÇ ͳ{饹nkW=_מ{^|х|P v:]7?qdd͋/?:'ݫW[~gSOW>paɁe$-;fSre7441=kO^'r!𼅖4 D Rۺun{/Г~2G?(=t==Sy[lޗ={rG5g'Fz+~Kww/)=mWsfÆ qaw#o}TsJq\Oԙ;}kkgmCΩ}~>dȉ'ͧ>3G.݇nZ>}=ovwߚ9ѭD}vm5O?'=qgtyo.D@'р @wJUrez<0.ԴS]yͳ9#ࡃCo_o"߲e?􎟾ƛޝ3O-^{&/ׯ_ԧOW_m5_暛 r2rZܨңdff~:>修:*ûCA|@jv`m>\=s'z*222N>y옋\K|A9e6V>#}%?}z葶y}1˗S]g5q,)𗽩B4 ݖT@sDž.m3T_Sg=8 Г 6$F:s&]:iIŒh+Ԝݷg{..de{︰j?R͍*@}v`ӧWia}95mdciv!DS94 @:8`I!pdB$n ˗Xvm-}֯_=O3d@O50tQ>;s_,X0灟s5VqqRaV^V ;X v>t@Rˠu׌λn&+++;{x\[VKfD8G{d\z-fVZ5{Μ|HMOsv*@Mv,k֬?$ͿU䑹 i@:`'E&\{W]1>w-,A\8F92@7~K_ΆwWgݼ޻xcuTz䑧v*@eWо?xۯo\;i^+W}/z<}0@jҀ]BI;ǿ>644\yէ.]ڼ矏WL"ts጗C؜iSfMMԱ nqQ睓bAwyg◾Odz]Rߖ-$5=n]B V~Q̝z͚PUk^@?<8g|5ђGRdgҀZHKg8!7߬;/\xC޽+}Q›rz,QsWe_x-ow8CC7 3^:$ks֮"vcg[GoE ۸a8`Lx>5ᖎ<>PdIg>_grѓzaÆZo]ZQR45jk'_!^U&[Ty7El*|]E;+n_T11wTyvYeG5646Ӽ)ykmz!M2ՌlyrZf)my7x-X\JJG̪w|ͮbϟx[|'ݦUBNuwy'$}zI45<VW]#pX- D+jW֮\HDI:fSgc9~W8cx-983jrw6[ҞXDHb71! nes3 M:g8 fWU5uF\ig|KцUɻ:vZ|dI]?8sN?sq3Kм%> ei@:HW+W>te4Ł݊I:']|E=3ijC p VmrIDATNL7- [ Xt ?y6mxy-|w9wdİޮ[%Bw\qT\x'Gn|4qGnB++Jg%.kK'V4.+U^ߔh*RtvfJEjH/?mbs@}gU5B?,yVq ʦvn]ɠM}g7AI #F,F;ECno} YeKC'hQ =nW).цn_6瞁m>veng)1Gouo-[o4 ;v4 Ⱥu#s R)Rd'. @s=I 6[G=rуe˞z>1eO]$C:aZ,}KU-P{ݾ'޹9)-pu&kdW.7%ȼ!'=5&HjKrF[V/0%]mzN.ߐQv,+/k|ViTIH @7+j/#sO;iV|A;N/:L嶬}jsÿC6LDUrՖ69<|śfLL&7G&Bkaȥs_>\w^p"Afb.::Ly2i?]neaD?"wzK?}IKm[U}GESBbhx-FL6OPx\ؗA9C'\[lm'Qu0֤)QLl}DDNcg97Q\Y8r^cF2WYey˩;J ݮn]w%*jڵkoU;!32_HBm=Eq2phH Ç;}+m;%`Ȑ!<608#c/j;ozhzkqL-%vi|V>ҹq0ĚnHw>vXOe]5lLO1-'áJdٜ|$#wn[N 3GF&.߫pqW~r ֚[țnc[N.O m9,7b=jZjPɡ3&uxɱ>Q s`q-l(P^Rµ1t#.+22x$ 7L$]9- #'=e/X6U6O>%r}:Q/!hTb6vu" 8<z}}@7ɧi=5@Բy4 D4 @$b>%n␣]pFra-b)/Z_b4/{~"dg=6GQɬ7-l>XÖ^[,>Dm |wO͟7/&Gsh-5|2rѡCaʓ話|gQ^ٜjW :oWdzÏp ]57 dӀtRN<׭]m%8t^c-3aC_8t{et[^˹.*5}9?Zv`2/[%lrٲ]-аuN{WeεL;2Ș,D|d2cbQtJw5j-hZēŅ{-yy;_{2ᖶO:-k\1d:ܫT__GL?zb +Kg3 g5mJ[$k*ZQC<dڢ #]d$WcnF;OJ1͟R3# )UW*O䚜;12 #yڲP8Ig-s|NÒ%^%ɽqZ egϻ;䅄Bx)_fÕ6Mxo )i -n{!/;QU.i|࢝,_5w͗ήH}u(Zv9wO\xxw^}<8p@baÆvU~ydT}ƬR͏ZOeQl@N=#aC7DѓOW>teT8id#s2Z]֛C7uqa;%zIT?φH/mls%+Up\;v#,Z'ěo~h駟[ƭrmQoJGжk5|Mv[{mߎl q]Rnk>cٟ?6nK/i9@Ww^8s*vxT?hڦmg`_ 3BO?K6k@~rV嗌=,w\<_,Xq秮j" ۤ;dRiڕ+)=ۄk ?GFutmryI6ެ{OG=Nh߁~KGdg\ҲBChhg먼}c =蠃.df5q AT -]z8+.ka'>Kj@:ѳ=Zƾ=sхU'>s4c Kk. ]$@tKCUGMvڒ%q{߽+###@OSN6>rܱ'{СΐK6tY[R'h#ssrU6T2i~h RnZpW^uuTvOh' -<^ČopЃ RչxW[+JMHYGO۫^{[5+W>teT8idINзqk׆p=I  ?}| 㲇GSR_*HE 9.{ذdesG<0%KOs_{8`_qe1I*Hv .>J<ÇMӧ[ Uo>"H}ޯor ۥ#t]d͚5o ^C^^Pҁ,@{kݺ?Ģw}7lloo?{NB*eqagw @W@yV^~xa:CgІ^f͚+WV/Y5T ]2`x`\ ۥ*f~}̛gmŅtۥ+vTbÆ !93Ky嗌=䐬ٟUmJeU >J!=[4.sYYb5ۥtА!EOڌMfCF;RY_n⠃:cm1pFƅH'p|\X|ڵk{Hsƈ HK-?^XR]R9{w}g>1 tܠ)tKB$RFVVVv 1N+Zj9qs HK7|G>壧N/:LeUNW\zIn1k´;W9*444\yէ.]`/?q{߽k)҆n]N b~X:s of]]])~zvXgzZ?-յCIYdmEJX/OJnyI֔U74|)ykxoVm<ĮMnqVM ajAMOv bb@[Ҧ^QMMv~6@Ӫ;|s5/^7 #ss@ZnJhŊڕ+WF 8 t'H;l=%qwfC^y啰UV5Pq_EꉽsƗEUU UUהmHF*`j(ZQ50iSYLL-(XUaJyiR*ZfrWɳ/YڸrլP>~Pih_޴$PkOFC|ͅ-޴<4^`#VW S;E&i:]̺DŔP[:*ٗYQ}AnNXżPW6i~jY]"gUqV+:[nm' >vYv 6<3){( vu))B$|x =駟'9ЩJ/-?e .ۘ){yqަA3cy*erk؈KG ՚ƘDEIAY״H%5i~U%99ѴqӐ( YeO* wP13& Ba-uMn<.oR=U8ivJ]X4-p`_p_'ktAqzP!@۸nW jR)Dr#x`OO_36d}Yv"$md)mtl^V}GESCbP-sVMNv*ߘ%kɚɩnt2> 9#N< U)??sClQyy]/qi =nw+tJ Y چ?vW,5o5upWօP_6>P(7'IPq_Eq#Fd 5-0Ba-se&yP2UfnӰ+٘haRj5 #`&\M-8it2%pc-Kھ( |,\00O^mmn`" @)Ӣ$IE+f/=P=wNΠm h=^u%͡S ƗgMd̐7V:m&oZerxЍgYÖՅEUX<0:k87i~Uzs9ƒ gm|J n#.]J$!i|q Ԃ$Isr/W* r 6YZXepC"ST6 xmv񒜜ɯ/?1h#41 YO_P8 f)Bld !GWL:8i:6Θ?"9VkOjҖ+ͷB6}PJwVbƢB2N%ť*i,@d4447Wnfƅ_R7n[o r a{q*f~}̛g]AKwғOW>teT8id#sCwҁڕ+@R$Э 0dȨ!t[{/^OzttlADS薄HT[\xw[=m}Uevن !0{JmMO]" Sxq&t99v^h|/t%.vN$NuDž. #=sq!+J]=I ˗Xv{iqq+vA +jW֮\0hНةWW/ʷ1N]o7tV=gN\>s@Wvvʧ 'n!v ^1'#<.ۥ ).x'G+ҥK/}gݻ222@3vb"9hx )3wߨPWWwʩ_ׯ~?䞔wYu0277]z.@VW@˛ߌ <ѣO>餑'r!R?Lezх ]`~fffYt=. -z>*42=t'B$v_7\~[o [TQ38?O>`t.`cӟYgq>Th[w=s>;@pP~w?#P%t(]`gZfM\oB7JW??}FH}Gq_>8_^222N>y옋\+:]Ҟn~{˯233Thv<v},wE-_1Gyyn&8`@ :CSW}訣6,t?E2~'=ydnB*e ? O=]Cekz+;KDXȺuo2IDATW^ӼdȨ=#]`^UU_R/D2$Obڕl޽?⌌xo/4wmm{!}yVeUVYeUVYeUVYeUVYeUVYeUVYeUVYeUVYeUVYeU {E{Kc{3}S׷o4Ç4Gm2TN}aÆнe5";;VGRff^ {?Nwe@K,m" !!@" !!@" !!@" !!@" !!@" !!@" !!@" !!@hhhEI ҐI ҐI ҐI ҐI ҐI ҐI ҐI ҐI ҐI ҐI ҐI ҐI nѰZpl ;FͽmYYPVee3{pY$X8vYsV\~ժWu^)HΨkhhxΡ={\yZaݿ^x1ı# e444gٌa_bC|fC8E00=AY$fe4V8vRcg̘?o"pFlƒ{o=<+&cϬo(y3joeT{XV V5kvkUN|f,kwM/4oVtv7dm~o׵=+[v:KY$`ΪҒif6ϖtX7ʋzЦMH}%ܴ˜Gfnu% ˾жc-]|BF~{UGLㆵXRyCoWmwd°tVHfήkhxtLu Oyjh*{caq+TʺȺW>?Qs× e!q|d3| ~І 4\ɝQ״~ݺ{i|S XWnzmrM7w4uS*g7dϐ5or.+ޞ=9[_XvYɁ^\V9 Ɠ^r{h Qdž7M)<ڰ)$۳z"YeO{]*O?x㾅3JNItH&CZ,]pޟ.a]Dsf1%3lxی}7=l/VӅFWzm7]wtIə{f,l{'BMWP7#7!daY0 raye;a{jIy|a=fl}^Ͳv1 @ɭi |# ۫B$M[Y^%M5$9oW.|1tWO BC;j& y!CN81oEd͌q\(2aĿ{;?{nƖoe趲Fc$[R;āD6o-wܐ{61s%{-K(~qÎ搌d+O=q6^itu5gL=oFFFָS [,+;9Z,?f^Y #k ]+EW]~[}.=m^ Jcagm(?4^W}AnImfomx*&.h,{glV13eSo׿n=_ǯ[xԩstB$[:s?[Y{eEs2fO[_ZײZҤUB{ڬŮZYҬne^zո+nE2֫W;<[ tgi{}Y,B$#>ջwدtF|).5B$#C of̜\_).eB$}F\hNvH'ZDž=#@ o>]H͜6z_oą hT^^Fm] ]$o:t3{7.]F;kiM7-U:+V  zBwgl" ˥Od%II ҐI P )ijT^ $v )w tދ @Jf9cqʈ{ ia?c־V\c="ҥNvڸЫW/5C$"ٙV^~>H})"9{V t\E!']a?1wH/)"x/}wy'{nl @ )%%)9ЩJn$pV%u|YkOn{Qz~ eoE6V w|٦[ ,ZQ{|D)kJq\:lmwܺurww}7qr׿ ]dȚ_'\2wUw6lhEլiQ~(_0h~CqV2\jIfʪ)Y dY|Ҧ,1{^eđ$7#+&f/G/}h+;C d_.%__&]F-.ﲼ^;,-U^" e:tQѵ_߰go>-@I,}Ͽyۭp@ N.prr2.d_Wٗm|{'D]IF2qOj恶֗ʝ-;Ł+H;)9v>}\}ոh`.8뜂QY E+2JjC"c5ݪUf̨  uH"ES 3&&g/( Yfy5l37=qWs3r R;d)SR⁶KBȚqy.\ޜf2>/ӴYVJd4_V#MəE!oZeC㣣l+HhEU;kgϫڒogVҐI ҐI O, @EHCB$4ԳB$?2*o7dҐI ҐI 7n[o =5odҐI}ݸnR_JH.]c 蚯]sׄt?_}5.'@-. tUVŅ}'@KHvիWY&.z!R_JHΞ@sCvwLo.-$i!%C$_}O!/bƷ ^R2D2R_sKw`SOfHY/)uOqeU= ,ʚR5RiAFI&3UNKnsAMV<>{Z?-{jA亦\(jFvĺurww}7so>@H,15/8*OdƷ˞x`2*dMΝXQ4aV~W%* JmU&.L;&+nGF&͏vk?)[Ur6nfi3HyWBiм'Wv M##{n4!\O?yv~eWOؙ.{Mz[ B}M拳ʦeYaC}l)uWeMyKg%(d҉*&fN,孈a:㮺gڸ>?}FR2DO>?4zQ}Ai]≧ׇIn}\}ոhj7nm?k}SǖW( S r&ו *-Z yEY%LW2 4.\VB]IFNIĘE礌%J&PQjy[b7T)Er4jJV-ɽzkU U8.d/jh)/`[ UOSR*`fG,(ո-M%uغhdO[_ =šmCcUGX!@" !!@" "93)=,@" ʍ7DSzY$4$DHCB$4$DHC"9E&bGF1dҐI6l2w=@KɃ:gTXt1ӑMy#BOS?|qGjBM\ׯ_Է[H|p\xn@zBVV/B$Dž"ٙV^rʸ3& Rfy`ժUNr ߿,T E&UVT*LEދ$f  ͅmS[[;yOGFJgӿ"B$#\O?yv~eWOؙ.{Ѵ"l rs2 J[_}ٙym̺D)YtbqJ &ejJ*=7߰M>J u%8mw9wf؇丫96^>eg dd>}~h7o;d|Y}7aӱ#?XX4[Z&O˞T+Hy5~#ZwMz/tPI]rr⑵VTU(jZU,)ڢULʞWY]l7+<ߖ%%C$cgjw=N ;b`q#VMU^?9xUL ]_6yLɩWK.&XI@[;IS{)w|EG|N Hd:ɫk׼M ̏ i?t&hdMjH/nX:9o$=YW/WWǕ d%3xQ214Vn.`Ѻ7.ẉh3bnm1TjHE+Qus'V0.qJ2zmi뫶܊iwت"YZ1|C"Idr\ S kP7qAъYGL !QH&;6 3 ϫUj]2'EݑW<KkGsBr6L=NNYzA"'e'[hP{buZꊷ\R UTD{gDS}O/._mdԶ >}w8@" !!@" 4@#$Hi(o:@7gl#Y$4$DHCB$4$DHCB$4$DHCB$4$DHCB$4$DHCB$4$DHCB$4$DHCB$4$DHCB$4ҋ,@" !!@" !!@" !!@" !!@" !!@" DW"ke#KWq{ RRc@nܴr} ^3vzp4FIkp")noz"1(XGp-7'XND 9-a_yϯ3GD I D$"HD I D$"HD I D$"HD I D$ZtΆ4uYL{G{P:T/8gx9CxlVae|d]l˔U'R顁X)=:糄͎N9{$Ea~{{]TqzeMI1ɑޖڋ#gRӧ*ώv={?g6Y֧B8@GOx݌x5Y`!:UD,=dv7wg;z+w\|jSms S߻nIE 4t O$cOe[KcsGs;ٻ〕m msxÜxT=mtCG3㧹0Y%T L:&fwMs]uynU$Z_h,6wW)V7wQkmLʕ\Ҹ{>^]Ohwc.TyפfpGgs:ˊiZ_^o_q:ͺқ0qb^s6g Mkܝ,qkM7ݲ T̋tnm7][9Ve2,{rhgr>*7>?LixҪƶhxmsA GNUE`0D$A"@H$" D$A"@H$" D$A"@H$" D$A"IDAT@H$" D$A"@H$" D$A"@H$" Dдɗ_:K̗*@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H#; ?7w:ŋҥ˗/֬_X&r嗎s_;/ .~>?)** 7,^`|Dw|g\Gg?#sotgFo^3WU]ǟx'WUs INǙH/?\Ggѣ{g K7TVW^ҊxE`*/·^88x/>~<ކua^>zw|u˝- INDžaAd2Uխo. *wl߹mcGe烿_eQXP>tؘ㟖x7c~~0@,+B{+6m˛/{G:>Rh>DBHN?}/(*.EX s;׼=7оS - )e/=Rh\K_JodPhС"[z댓%jjb[(ęyw`sfݗ_袢BDBH>|иg\Q[*/gYЋ 9s[/ZU!dWZOSL+'>Kl~޾;l\'߷z{fЎ˶6o}[[j];K%aضv 6*T[?v^Εl*Olۓٿ0/[n8,*sV]toW[y{6&/ەd7nذ3ӷ1Voώ^'^LY3@n~_f{妵ca_R[el`ۮB̓kj֧!0>?[wk6ܵcMꕿYco˚=CS%jjr!m Kb5W6>~uEvh u+M=ߟam˻YS38US#q +! )"no}e<ȍwxI%a*;',3ѕ[3}[gՙW/3tVvub0w _{;JKU RE۫x1o#[d2|=O/?[h߾Ѳ"\pA۶*yO$?15۴lwkw6YȘچukDBHf]jm{v_f0wcufo`p=:Xs?},)YsaXhZ'|kzgUʪTulxs#[l,=ȗ_?Dz_>{W]W*ofs-dx#ɿs԰n]_y9 z;>}7 y"$D$8"HD I D$"HD I D$"HD I D$"HD I D$e2-H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$AN16PFqY.=4:6;Qvx}ԟ8VRKY,6ՉTz|t}o)KNd#Y/% f4G , s{޻@8ӎ~kӚeMZ/m7߳w𱱮#?TɲDh&Xxlܝ9衯qeMͽsĉD٫ۤOlxOkv~@[e@ĽB.sncu TOjSӭN՞8w UGg[7ݿQ~;+ 3*eu/4eG^@ۻ|.hlQPGSuYq(%`AEY% |?Y#k?ղ7Y֝O-I$o* ,3ftd úHw׶$*/t`8@GkbQC}u8-6M^ _No0YVV(EJ+ m.75t 9CDkMlEXsSٮui:ҋm2:pSyޛkң`nUE2Ҫ{pw_M]\oG!%@klVTbk+’Av?wtX>SUX. #" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@M|# 87" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A >"O|~СC!B.]˗^ZUuwsZ,L9KG¹}탿^7/_~o[8a3ݭ2YO?>#iѢEo# uVwD$8wbIut6=zo_d xCeu/Ww|~F^*t;w]tEa^$̞}N ի[?z/]"mO/<7~b0w"'s;:LlL|OG>Ueox[cK7঵5v)o۵39CORfϫ'Ne:{ÌV\>;-xQƥ70mcrwdm޶6wʭ]K;l.?araV~@>zwsЉSk+L0F$uԻzx>im7*6u[M=q{2eMC /MD%0Kgxdr=e?AϿ-a&+**gbbe/>=[< [VZZ0Gݾ @d,*ozӛ 3%6 3WqiESl;8ańseu;;vl$beeY"yƽmC!"yS{ڻ2 7[ܾ:+^ݶk۞5ZяB(o l,,o^{_fclʭ۞ٚڱ~Y!dmml[mҥɝjw{G$x0X&r嗎yUh{w:?m\RK.\󮁱XBo{il9:{;YoX$a!]^g#6qtΨ~B>-o_oBH^pm~g>Ĭ#{pXMMb_Xj_?_h'bLc!]]r疿-Xg_ix@qS? m /"uuݻyfk~ꫫYU*DH~쿏W~yO:̗$ ÙΖyң|>/sz,׭^g:ix w\pHf>~?a8K.i㏚opSEsHf˝]}u߾QWZh|wEs$玅"" 9"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$AL&EI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HDEl(M,^XIwdWOs877Y6i,=\ؠ5>ye?Mk"=DlV⩡0ܝ(^F9vxp=]vQmj`ƹG>pU5G뮫s4wdY{4n,<6wW2Ԧwݒl4t شmʶc=DY65uE|%;4PVxnLhÅm{ |8u!?܉:yV,.kM(ʖB F; ɢ['m0!e @*"9PtĎ+Kt<,;>ʱ5b uc;.4ܴlsxsœ-W.T6a7Y]tc넣]c%&_=f1{[ʦ8˫e('}T̋tQΈ亱f-Dq8A,h0D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H4mD嗎8CްxIא*@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H#; ?7w://K.__[~E<2̔/t$۞>yp #p{%^Cg>"ѻ[ ?eӟ}ßo޼|g:罅2)4Y{ͥ/ }ؖ}vÇn(4?tPBHo3N>sC; sRْa˖]TTh?BH>|иg\Q[*/gξ֕807Cef-ZUp~05?%zժǟx"eW^f4^9CܼyMs}w lXmu5n6n ݷ~P(|`熊^k ;,9=5$j ;)d+\S'S޶kg2 o9Ec**&~SXqŊtq_wf,p UW,k-0з1m{?ԗm޶6`ņhƍ]gGwޓ|u .M,cٝxed߮WWF-5˶UwܶlڕaFEE;U$_g['9vc˶}2akBS_]C6&w/ [/>$d3Uב)gd~<VnW~JbD'?y~)GOm_~ms{[Mƾ5V$b_\;~vyۮŠ}.[lՅW$9#q +p~[Huk~.xGnK. sWٷ󄞥ɝ}/0зa}'/8a '<*6LYPh;QZ$绅tw{E3϶~?a85[{GWp{%^C 8"/wv}>}y?n_p5#,". #" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@Hd2 ZT"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$Z4pw,6+:.YIDAT5L5P8ѡt.^r|D*=4^%{O:vq"=:i /.~ݷwZɿVb뮼2_rlS:‘P\1<ͷllkeDs!dt[65. aɺi&ks,̘}DkM,k٦0#C=7?{ZҘj8q-b74Ύ|h1k>^c).8JVzK{׫,j7ZW}ݍa-wls\HV7.j8ŬB29zu.hN0k3U(_t E?\Ly퐿d{V'/dF 7%XI⤈խ,;zsDrJj[{v7ޛk݅@5'xP1<7[u"mn"8;t#5{S޽ͧd{:]G~Nm{{_g]ߍۂb2ztְ$!`9!e7n@7k! ; NBN m= \$j؂ སN|?({ιNNG|>h>>u8 dȔdw_\.|fٵU#~|!;YXےMX7=*'+P^xqWP\ӜQS˄$?ƮdkUFw/U ǘl,}cn,:[{‹usn3.z*;G#} ִL_ /$LM-^2]0]q2{pŰF7Y_CT(kv>` ;_ްsgl5wek6=3V[VHKf6NI*?Ď$C"@ H1$" Đ$C"@ H1$" Đ$C"@ H1$" Đ$C"@ H1$" Đ$C"@ H1$" Đ$C"@ H14fDw8N8qV@I D$bHD!I D$bHD!I D$bHD!I D$bHD!I D$ɇn< [w_3x}8*#_e5{{w>Pb'8+ap#_>|={ƱOdڴi\ϯ\7)BE$8L}Do-;w^p>'埘[+yR`KWtD ?x^^^<IiaJsȪhUD,yd_McT"ꫯƧy}|ߴiS,y'~RN+|{OwqaT`*JMmF3gܺVJ=/>7MSjs}plJ)Í_$GW+Ҽ ?vy8 RD'T;u_9tn%]s[]%wFkC^wn~ؿ<=$ɃyP8L*OȊ[ZBF]2!PxCW_R7~O 믾- ejOx9\;Sq!{s]|GKMmsݦ,J떖]ѼahtaEォ&-w|(\WNF^\S:mYK w2\]R 7b>>Pv_ZPE$G;`_hgUjPpRA˳-'%N GT^ޘ&R򥏝?w|-IDAT8L{)'8+a0m^TliKn+y}g00}^Eȹo86Lq{7Ώ..+\e}W8zuOGO4_ޕ0mGnK_J4>Ӿ/Fo{碏^sB8 m0Md*_|Ƈ83±o?O6SVh JD(?j7Pw{'G~'oR?\pp CWdRtp=c1nry] h>Yp$MQVUmՉsnٱ;^r!<8ry͇44NfԓsޖnYWvi -;ro{z O;'C-\x[w>e]}dyL76}sƈHlZ2a QH2QՖܚs]:2\SeJ:iI::=cԋܽ7oG$CxɅ${Itn֒z;D3X\sSk* áŌ9Kܽ榃l`FuMCmm}uQh[:ֲL+ FQQ{MB+ mny>3XPSW_EoٷyOC]&:wMkmш9 j/Kpu<=ϥ=Vk 㾪!IlBɹׯ,ӰkG3|ϒ5¡dmg`XDeCK5qx $/K9-̬;mo;>of'oڞsE);`L(avmko*zʈ4TF;zk, `(9D8HLdڃxٙY܊(+ӻkudCTILUm]Pؼ${)kt۶<։<0.R{(#9a(ݙrN; erfhʛ_Ψh]^U2LO]̙cQb_rc)m5qOU]O`*hD2 2G/OHrɦ \sg̞5c}As9|[3e 3յ7ǂ;۪AH6G/3 ³kk''HF#wܞ\ռ,k>sV)$ 0%M<"BAU˃ِduMK~/I+>p?G,*mhInbEqk-f]ۣ, mN!<|񹲎_UgܷauNL=(:<~i5Â#$&ZwH]\{? <<%)O-*9OxAATZr7daYYf)[: p&;۷..dq}@H^H`LD2lwAz{ wnE== yyy ކԖƾa'LW7nZ|__8Dqtg~T=kX=ן= ZsWd[:O,1 |L77geߏ6Q3\n;ʲl'oj=ؓM~Ω׷\)kE$͡[d5>tc[tHɛ:G=[1 Ō&Sr֕0K9ksT0<e훖Dw<~yYUC,ԉ|z{:A,9PrF}·54GWEwhMh!ds叧=n75fV>]LKi[^v4وd:$ټpmDE][o;dOsu%dz9X⡰k{oku7eZR_HOssTڪ{j 4KAEK.cL%Kܱ~aQ1&sϱpjm_E̬2SqOxq}[ˑZۊ_޶t@HDuk(M=ԃ5…w>̹`YZ.G۞l*^~soK%m(>ڧmk-QEǧG} E];NY lާ_͸֪xks1U==zΕz+ d%[*e=sxiusn7M^/UvO?XSEr۹sSO}/XP0Oi_|9m߾_7ۿƯojk6wqW^ THNm%R_sD"4SwvܙϘ16yG=IFS7O_Jwɥ^đ*Sث/я~6Mſh/'>8" 6=#gΜ{ :\z%uGBuSƯ? ~…`®G_|17 /~=LROOO48묳-QxCn G8wܙwI[o>Q`T¶m >iӦSvv4޶;*ZlLܞ={^OS;8tgc5>hz㉎`y5ޤar#PD$B\敆yso48餓L8;F k޴6LwE@]+ xC{02:3DDbv&O_{K$%%/n#""9ws?h;:Ĉꫯ.w_˻p@~1CJ /}E~SK~?ѹz^vce{7|%7/*]e{fEy}U]W ={e{]5aeSK{G'j7.2s?˿\?ݲ%xm5甕=ρױl~{I{{ԧԄƦ3un3TbպUnZԾߐ/[aR ?kzyͅO-͞8saou44|ռKW~XosȲ+Sϰd胍V84=󬲗_~9L[p5Ws7͘1#Qd䰿-a F^jݙM9s bXEr 5t* ]hWWWg]yh_vjSXLiLS[g%6 Nױ,oY{(_>rmvJ|zT. ۦ9|䫯>O sȲϾV(Y`ow~[|[yG]+J뻢u0IuG_`*ӳn`{2lDre颛/ f"}a&7CSް{k[ߵ29Eyc;%)Gwegˮ!+]Z6Fb}'˿Mkj{5U_ǿAg&lq_lyLjgvlY){:PKU_}\}gJBx7꒏qHwyOtt.混6QYt\ieﲕM;faMRmM󇮹w=&frꩧ #w>䬷5Ü1cݻ9iOUGt钊V E]4xJ~aU;WlY[ڸjynnM3pM!_5nM1[4r+˖=UoI dl 3ҕdD遅f;_պ7k teݼtcyEM+6.̬Z S7Coi)JyDH+*+ӹy3:3P Ҧy݋6EaBM@İ/-+M  ebQc֐XdEebx ?>rJRWok{mb&ozyMe֫L`nm,ZNyW}3t5!tMr{ڗj^s0嫒ᔥ-<%MF$N*ڧ ˭ݼ}OZy!:e!ؕG3+:)MbUM"$Om t@vW:4#ks6K)xi:jE:t;X4-Q9~&p8"]5m_%Wf2v ݷwfJVN,#IM6&37,M/Sfh!L#I72ε>QULN1݄zO!QTC4-ʋYs鼏6O:߫?lmZ侕eX fɩS25GsցeIHif{[q<aHG7Ʊvҽtjaoo{cbULu5lB1WmHFKVIdF7v'0_g~ wY_⡿Yۿ  -o~־̓ZIW%R/q=قpXab jJbG~CF~JLg\@z)8)e:$3wܟ=ˋ_\7]Ul|*s uS5ú>?>G7}/"wqW_Ю!>l2{]0zy\z_t7 {?ս)ӺlЯڢ\=]runaBȨNq!sU"ґLuɛ[CNFYLH \K^v,/+QmR'?^sy꟟.3gά8c'xbt_U믇7Њ4:IDATvwfMW. IڴOnؗjŪt0W 3?+*eZD:iaLt0yҼx+עLόKVsd #[ؘxIՒ4eGsZP0+o5wc^{?ZvEF+Y;揞S|+Ԥ_q:(3UKK6tf`d O@<0"tjZkQoJW&;fjuâ}-}!1ҵ5k+~٩V4-[־'\Q&)]7&'ynjkƟytћK }{{뿮̟#{qY^ՙ2܃m̾L ٽWe/k[ZZ0N3wzҪq; |2{wl/Umk} N/_{Xi:5[1}(f,NάIdbU){~$jT5[rCgתw4T.< Jo^{?hpH}[nO WtEyw2N`Fq(9s̯{~!6G{GGG.h|Ϻu8HƯ? ~…Mf݆ogy&lR'~՟h/hpYgMP|ے?ug,k3v. E+cLڸ"ZZlLw8wܙwKD$ck۶m>8BEm~#5ؽ{O8֕nFuwL0mڴsCs#7Pw{'44?Eɜ>vŵ~&5xá1Y/hw;LRqqqO~_X ǼESG$?7ns""D{`afΜ ZpR?J_|{`jP&.TbHD!I D$dւ7}p(H14-^}o^{-L&LIo]]/]{ڱ䥗 '&LI̳xCm۶--o &"xyFD7Ҏ;~Gw`D$O#/n#7~*dH2~?d#+I7gys`O=|dgu/.[ֺ7azݫ|ҕhWͅO-z!,kL;M~5m>Ujk %M6nMLڸ"{GnSjjBcәنH)5lw)5]/,gIO{,#7svg嗯ױwiƥ㬶cyY4aЫ8r{fg/np72s9컀 ?1ܹ[n_~^K}9sƮ]$"xr-[旟%LqɆήu3t1ҕĪo!' 2nO\sJ&xgz݋JWTDfZڴuS+5eN_?ױ,+Z!{ӃW%2[wؘݒImǩK[ݙ_9d\>2{êގ0yAQ>k_F7y7xJM}]eh=Ґz%Ҷ6 ^~hoN:yiIYY^<I#_p#6}nM;Īu_ u/.kܚ-=%WM('n|<k㢛sG$Oml{C~QyfIvnToi)a#wOнW-lZ2Jfy~8h^8ձXgdkܚL+k!ٴx"Zg[Է-_k'L$96V;0yM^jE/^h0QbCabT!Cb.8)E'SQ\/Q*%&ǵ2/-+-><Icڴiz_C;SZ"҇XU>=$W-jBGgyӾ,lB HUf@N䙫W&RX9Fv3]1oߤn]3jEϭ,kߓɅ,W?-}<ۙwퟪn߯AdBN8O^^G~<{qS2QzY&]טҬ`函C[1ӱzO{c NNL2b:Yտ|]%5re +~)NjsdZ}7-+]tp6ٽ4o`Sj+3QQ;tw/1i/_88"&?7~,ЙIE\wW'W o{J>ݺSLd 'KV^n=QNXBMbȧU{[Wa}Y+Ӹu*pZ(_ܮe٫QLZ\.q{,Y&y~g`̨f9t/mK7 Ind]K/sq۱m5PQ>`4lc,]-{{^q]:ʹlp:â -3?W^ւh0<7+A[koZ2?wC>{xk-֏w|s.GN`&Ԁ`jbHDcHө[ڙ߸4UX־g^]$ǐ/te!8 "ҼG%I D$d~n"@ H1$" Đ$C"2_[/~=f"@ HG={D &"(N_$5xgIW\q++ yso48餓M 0' yoy&$H2h3"v0yf0IFqG/m۶xwD>ٳU&ADQ^Tӟa'q?p]? $H2;nqǷopd=̳U_s*AIDAT+_PyGdy>ǟҗ{l=@I85&>$Vum\1U:V.xe{攚vܕٞt,/߾wܖvNLN Mg˟\=op婩V=5dUJͱ|Ʋ=æuZڸ5@a~ȫd.hըۇvppv>Dvy-~/k>IRE1zK.ٻe>䒆;|pPnZ>$6 yQi^c򔚮wUjN2(Й>L/=z淟m_Wty;k~KS+׍S^>tYk("3b"'*u3tߑ]݃Еyɕe;~ 5E=49޽gr<`jƲIc׺(K[}wz{#nmnEȔ̞=;L$y|8M>> *.\s˭im2[[e+CJ^ic5XddoU&f:uY!WfqǞt{/m}rGHӢE7wi)a#,G˺+!0˓)a]ukA oy[օ`D$ '=t[x!ԱikH\]2"#bHI7.f{Ug-}k/pҙC8hzSчʚtr'N>;7&>4tHKN/_懭& NM?3}X Q2{ڗe:|{͋ ?KK>3/?$[oGFEVoW$'_;>tP辽coHTyKWڄqfD 7?ƦցawiHLH1l:8n]3Z}΁gg.dI[\|v}HL!qͻ䈻59Xy1S&sU"lm ݼ4ldn\ۺl ׽|FcrzO/ZLq\/Kw垟[>‘do8&w4Ȋl_v9ջ]4P&w#]U $GTd9_L u 5ؘnW1S|19juC2 SGoOע\9+ڛ-ygt^]e%$V]zw׺ʐC-{aiX^r{[:`OHg=Z7/-ӆb̥B:l:qHMʨBӡ9ܣ=^J[Ȕ\C W 8z㕗w7 [o>5W\q++G;y uh#xF'8+$bHDByQX;6:@LHִi^W_}ӛNJ]o` zٳ'w\1"u;_?Ij/Ak6yso48餓pO>9<IO?L4H$f#"[%%gD$9ر?a4.=cG;S٦U!q;3{*z[V4ܙ>Le'8+$"[#/XɱK?p]?cdlwqkX;^ë3^V}y >|AE GD2ϛ?T4Jccٹsϭy XP0[cRX_yyG`۳gχϿ`h2… ?t9eegdGOG6mݺ5ژ7\XQN8qVIW^yO?7>޼'::[>< "Ns[x*/hǷ#'"yL6mڟ|lйwퟪn߯{cF4bHD!I D$bHD!I D$bHD!I D$bHD!I D$$C"@ H1$" Đ$C"@ H1$" Đ$C"@ H1$" Đ$C"@ H1$" Đ$C"@ H1$" Đ$C"@ H1$" Đ$C"@ MQ}eyyye cl7-q&km|2ƶZkˋ Й֪Dua&VE2DUMK± =sN_~Gv_sg0HΚkӥ5g-X؋;Svl(0~D6 }ڵ[2\{ZpQ L&{k gfP6lf?z_lp^Ig;//+i,hFhر.\ mOtwUsۓaŇ--f8V_E!n!ܚ5l+ww ,Ž [@,޿iIyG69 wlÒYkۣ۪bNm%EUmzԊȜw N&Zwz}}wo]&:Gq?L[gVYܓr[3+I<!7ts^*wfǦx\˲w:<:gїTFcʴp8Zpŵ $`xmgιr+fʆV5to빷nk.Ν(iݴdVHg0+kree=]\]d7ZzQEqaAL^ܹgW+XvSzq)wy;mhi>v+]޾IDAT3D7Zs#tMiU]gndcOgܛ:`AUD$+w.HD]{;5{{q' ɖƇӿg\XOPPze:{}Ck6X\^ٓN>&2*3u,{{ 0 XL$ʫjZzvgB/n|swl{;v|s{͌+]|Cٙ O/nFG?1*㞆i_KC[j}2פxve.SOD,h _O[TY|ߏGfg:doiLކ'74'î-3 s3$͹vo۶w^{tDecڐ3jڒ;_tK̝=#cۣמS;2F[}&*Hs?]=Kx }ѠsKʋFbWzgMac<\8S}2jO7gê4/8cH1N/k ]7Q\QSޛտg7]-,u-#RGv>~-* ,* Ug =sˣڌm5<3*F4.(oI_|.] q۪yyaƙEmk3z}Weշf~gZ,;̹~s8zk k.$:DfBə+=;۪Fm-S'rAmUDqY=tpOg6 k1-' "z{Mf۷lo[jZXdUehﭯ" +R9QQ`cGSVUH>z6s@M("(+= 7֖' DM3҃=7jJ+\]xO?zHbÌ+k*kk nfԿk5Nd[]]xAEE=zۊ{$styȴ՗նߚZ [7GOT7F7:pٓ- y*X7_Ӌ):wmǎ p}F9&Uŋ;_lJt%ιmv(8K6T_۞ no)V1\ \($yՓUlumUy ׇrنʂ \XOcygń]eW=cS‚{_l 6]>g_ݶNJ U afEssY0wY.Xr͚ /L6#sYnjg\p?K퓏 C86@LT^YV\4آG⬁#S+/f-Mk.P2ٰyg|䠹>Y]pMffմ'_|ˆ}vjˮ{S꡷-Sw{g̞Zݏ=S>cHrPU$y0]~I t-מ) ᣊ$Cy ^TbHD!I D$bHD!I D$bHD!I D$bHD!I D$bHD!I D$3"; ' $C"@ H1$" Đ$C"@ H1$" ?{w^Uu |@(ENHU V赊*N|W+ZVT*[R%N5*j'Pf49g'!@ &'_Ӽ{ y? HIHDHB"@$D$$$" $!I HIHDHB"4HS33f̝;o%<H.[oݱcvSNRVVV펕/ P8s9[oU3eu}׉Vm`'jXv壮QTGHľ#7֭ *4 Vpgm藿.]t=@2`o=wooC{zxڿZlHN&"I{JOzho>{פ@y9=|yqw)))ALmﹷ2y=2]>QرcK?s͇~/lU$֭[^|4i"}W}1o޼XݥK/e]BaIDͨ?#[hI#W?Ή͚5S 56QqqO@#ѵDuP-I껢8C^`NŃP귥KFEC{޽#K~jRVVV펕/ Pn+իW{ϴnXD6YEhHZh$D$$$$~޺mj?,4LnjyfZD$C2t; S,{^v @K7¦I53$V 36떻#g<;|fbgD2ں筋sV!:y*;+Hg3T?Y039xf[D$ ]7J-唙[^"7fH;ƞrBt7 |犩<08^s3=믃oYt]2uHQ^Kᵳ;[<^ 9fE^<<ؙW >0{yrDC7MuYEu>;EURq-zcc)邱\f|~|tb!+yG~GuפB̓z)xf\rD$i7+nf**[0ߝ!d= fv{^*swüx֭X0zU=j2- VNHrIh{Yq;zRiEu|bKQz9^^˜ 3\[tkjt:*oIW*Ju>kc|, @i@<)v|q'6=˛Fuo=b_{pØ_q`+#Xhd_og8%/Zﱟ6;zt=a^|]3x`TX燚+Ńtv @K)++vϗⱟ83z?ۤcg?zN3v{6ۦFŊaG4duHԽVm`'J䢿:pa\vښsXgW/yANy*'F+KL.|m>s&?<'?d3Oӱ(Ջ6M`!ȚIDAT$-pj͚5͛7ϟ5 ˄Lѣl6_b4JvԜ Fo[ >x#s}W<O\2wѡ3SB5g~8S{^= T$4Lp_'\.ɾKs~睿Nji#vڂ״֯_ m,^nށ78[[o(}tU~h#z [>`:~׷-7|kޫ^&wǡ Fhx.>'|dv뮻5g3+|bZf~pdn`4kkTCN9uV!k=o<:؟G{|G\o9>GBcҶmKs{68? mȪvuO8u*Or{{#ڼ-ZLVVfT̝;/@DkҥS/Oro۶{oVY6-[6~L`3'X0LC#"ـ+$'?^Z,Vw=aO}عk_Q}/[,c>[FFO~6eee`3 )"9W`'srNvJΥ3j=Ҝ윓.Ϸܜv]o;LJo‰gغmX_N$3#Qi]vwӍ쳗]~ELCH.yW"ڕĊPWek ]'u¦_Z55S96Yuf C²iaGzq̞zv#/ꓓv9EEQ/s*|.lθͫ|i0\~~_G_&L=0/TWLj|Q6kUu]i;=>m3MCHv֬PpN(;NX?I|׵ gp]֍kᰦn_y^adbs BtȭڂzpVYaԝqhؑ?8xhONuNtҨާV't]Jn2ڼ}}zf=[6vձ=mo.|BPgZMݎ{fF|G]+7#5-˛yykFXѺzsι愉W_,o`ƥ9 =b=оgl!tHuY5}\ .‡m&2$Q];klTӍtiś?_X)l6we;.Zh;Y]:gD= 5?N~>u@׸V~"ԘpY]{3.=/o}{Pٳׇf=g>.!={f\7x}heX2!}u;{Z|͛&'p{HYg_k]i6, 9[ӼEP5Gh<_-iLP{X5d*He͖]ЬiPw{l}F+qC*y9ybIHQ9}On.FYn~֔69uȭ*׭];<@RAK7l_[-Ms~}-.D='vʞd ם{lgP&GQĮQf\{NxYd- g_ } QQe_㪺fm;n;mjժ?{Kfjj~ҥ˾Ӵi- ?s?ov{o[<οM=?ey7rKih^-[nA U$k%\:#d=xkn /s֧];1iNtTw~Mwr'V&3+} ҁt=Z#ccϨXP lLθϙi:z<xe~gc_\4̙gyvwH4ƈ䜓s&, am9*\ϸ4M3]9͵C(|ًmv5Ft(8'%уs4=(:;dT,6nȌRvmB}6SR'T:ܐwNt#~i+76{ʗrkv!Q" /?}kP(iժUvmC#tҨ}h 8__bOg{;}Voe_˱Wᣅzr{Dhz.H.]a^;>"y{e˖)uVE^ .Ym۶cަMPc\;cFj^JJձ?'_jO?o{G裏@;>"ySDW}Ks|O>tGuO+p[hľꫨhڴm6QDry#!󊫮.??;1?2^FT{~$Zh_~eع/`k+W.ZSBEIDAT/x{Tǎߍw. c=2C]ѩCbbsۗq~ގ_EO^~X>-Z4whXQXB5{v?_ñ^<)W}oDuרACH~k{GO{8o>nؓ[o*{3o`[4F1G=g΋3gF੧nTg<$%%%PȘއ''V'аV $PgfG֭Za5S̋uwǎzO>N>9][B "1u_xcoxɻ?iFEW=A'Fo]v/c6G]54L}V'[;u֕IK _쫌ؗWËHhGCN7|+K&USj:v.]|RÚ|*7sql֬YhڷotX不w _裏bo^.CNT;L}5LnٲeCrYxIT:uIh6m:9yֽUwW76ڻ> =u l޼y w.nY=vuא,^;rŤ;Dw bߔd.]꒾z),%%Mꫯ6w@CΝ+=b˓SS#g7{W_{xnݺm6;߶oX^gvϞ`{la/ P͝;Ox͛{hȖ~afM23G2#ODw7' e֭[hb_ܥ]D_w]D$idE2o^ziNAyq7ۣKu_CJMW~,@~̙#{a}>$+Yfg͚5_z/_9ִiӐ\ZiHD$r~b=3cFp1VZ#" ;F$VZ=0v̷w=Ѿ~w_R#ODѤI ?WhRRR?Ff44iH:"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB)eee XEHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@PwK&ƧLx3%%g|q&YGn8KjB%Su tMZ+ _Siw_òOnY ؆e :h`ЪrƗT$CM%՝1n}Uޠx|wNXIs>X[OZt;V^ǃ97 !mX&2yJ&:*7Cd /6>bhb!3Z$&e+y}\yѽc?zb ɜCۅA5Lȉ/.'#-X 'L%K<6?wH6⟓ɴV())pt ȅKvͬ[f<"Gpeee'3zk ԁSJJՔLYT0y`MwlF\vbS7m)-2r_T: Lh=.Yʖu;/,v =+R-jGE1cȬۻàXyF\zZZE0 /2-+}^Hd̟tDyrȜ ɗ/>|rQI ꒢ӻ]rnwĤQBgdn8aA[#FnN6OO,}/.Z|'N/۝;b`)熥v9[%S~'n0)3ف;{?Vciް[a#<ퟛ 'J2R<6[;7?K]8>}ǽS<2=l:\vGL*,^":h +lΤ<iޡǀ|}lh=hPe3}Јu$33+'Bqs>!z>A|$4(۲$@4$I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDIIDATHB"@$D$$TcDrF6V$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$|Dr?|fƌs-^>Idڻc=;mRVVV펕/ ۋ3goVhwIx!Ykզ]aG$;flT\uŨFk׮['tII&]\sW~;";>"ٺmjTX^Z۽bժU;~엢6m~rOfvoD/\E ^y4xh^OW˖-voGDE$cW{ӦG2?wڇVӯ.Qmq{wJJJ=I&A{+.6II;-vC94|Pu=ދzvŻ4i`ϯ㫯!?YXݥK/e]B-YEF!E ?#h>1*]ygᣏ=4ᴇO<Îܕ)ٱװBץ[~O\CHE}eg\iq=S߳PuIM{{ڼ{SikKFE>ݷ:9=s(:(=^)^陱Okk-K? @ 0"ٺmv߯33f-:Aaktee_x_Xtl5ude(q=4?>|;SOOgvS/xF,gpEy֔W?ċU^tֳ[T|p4t ven(c)fsI>kVYU5n5{}|sӅKމ.%޼;.7u-?Ͽ.)0#矚>*;LIzs<7E|Lu9'=lM5 v ~ʑ _YBd庒O-|4 uz%SL-Xx鹃4_f܏hy{)S:tx @hHsϨXP |} 2y'^muĪ}'zhwE|nXvݳf<4lsciiPh;++W_ QD=OӸ'<_熝x_nWNxQ.L 7OMĔ?^J4ŞqevyB  #r~Lx 0:~Z/!D${rHjRVVV펕/ eGC~4,VO2oJSyzQ?TwNL6 1G-##V~\z+k w&jԩ|d4.2_? o,Q攔Ԡ!E$c:?<O}mk!+|yȋf)5^]ZMKkw=Tn3g8G=B)Q/iTyiզ]iѮbvFc 8昿mrv·_Er/wOC#G.lĹU$?pD2fʕS?zB߯߰?S[l7Iꏆ^h$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@PJYYYH.V$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$| Gl"c|ɝ`¼i& KMI_ISغP,!tNcv 5:lϝ6IU$ G$RbV}gt I)l-G$ GT5,?.)\ϹE𼅫cKm"5c{l<}́&O6pѵͨzc 6>}jFE;Nεbsnˍ Gav:,[tI=ƽ^4xXUh\2ePi\S9u ]vtsiu: T?<v|N̪sWO?pS{ltgw8ޢaihlFVt>ɢ x)}{-PĖW[\6}h]|ƃ*c/_< mД** [?q_sh'9>3sW]1='yb O.*ac[q>4XFt*UqGta;1iNyozRQ~-6\6\}n;2}x:Z_L>G+MBmu>wg 'hRpDPVOqS_>'zPNzDn}FUm3:~u1:3;-ݡ?toVnnաEZȂDi3c^_8yxfyoy,oЈPotUkXy麾\K/V#ԝZF${{x†ӆ udʄ&N޴Gs $eϯ#mxPlˏӎ[˴ }?D;&ldBQb]Ls'ڤtb_q}6'V{.~u_L>GCH=2ZGpg+*2 kn;2e3HżUk1"dsz#vh^c#_\(GnNuHUG;4(!wG 65#ր,,*;յbj9@}@\IDATEZc.[//_nGMdnjU7[DCZR-ޖ7;k1#| $"-n:_zL/?4xZJJ~-R3/5U\RR1 b2r ]TP#g~KLϜ:Z]K/v#ԡLKPpiqQiz'8< -am9p]KCXz)uiI&lz.?6+--3aa|#}5^K7,G(;5L;յbj9@ڱɌ̜ϼSټ%EGvl< 0Gzn9#A.-).2~Ԕ͗Ry2O.*^?*7wcڈ w\sGTN10bPldڈĮ%cx^ovxz_o7axu˯~ub\1?:`rt@iSNJYYYMfdEt`єA%Nr aKS<*3‘i}d/SxZGL JK9-|ErSL$j-Vq;0ւUVnt0 xuy]LucǮ"BϦ_~Df=\>iΓcEƈ#vh^9ڼC؛q|jCP/sIB~qm__p|dLjUNG19lK[9.p~VQ>rcLPyv](qF:Z]K.֟#ԍ-"ɎRrcqL߬t-Pg#" $&:T46#%&:f]R"cVU$$RVVU$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I \;K68V$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@Ploںmj_3$|ymy;I+}z@c " ;߂aE2&^nY*Vc}?yO|筋ݚU>3w_z%)_2:b3VיW^@<]o^zKDvӅ^sW,/5t >Xy+2/=pŁ]b抩aЙw>kcw96108!v3S'7f=@cg^k^4^W:h_] ];zKDv">G+>=Σ*Iʊr7N[^177%FL-|/cnޝϛ3騰˦q C8ꍹo,O|YsD Xv> czYDD$agEQw-/]1eU_WIR/;r7衿v/φk fv Ud_rr13N.]`̟3I-5+Ev>oμ1 ?)>>pzTս5vxvf5zu(f>x;ǢS' kCBo gMsŗ<Sh=58%oyQu@yM0һc: f&_/} ؉&jŷ~+6ўy?͌OR}^*N۹JK)++vϗ`[|˙py۱㢿gu&fΤwnz%Pk̘֬1wK~O?Lڴiݽw}szzed`giզ]GDvh;䁰~[KFVݼG8^C+--|bȄ4~\<0﯄G^Pg<#|ʑ=3cFgve \suPD$ر4چdMuһB(zyckqxjsj݉=dۦN{xz~7G֮]{ϷN)_|O=&OIhhD$}g~ӯoD\2}VZzkKsN<=#ZjqϞR_{t>ԓ?^{7xyyפ;OtRhEYgn {0[h;t3ЈssӢaL>}Iiii;G]yժUbu˟޳!3mc5 @)-]6@X-VXw6mի?ugF{G?b#ȘSO>gb 5ks@!" uӦ]6Vgӽ;v uk6$R=DZn\ۨʼaM4}o/Q[o}ϽBDy|GiӦ'p|֭CӦM Ջ/yͷG{o&5|dc>Ӣ;4"PW^y8On*5]>9QҜ9FiCG>]BCs/+*) AԁֽQ}Adonj~ؐbUW:rHfsƊ%ᄋ~Mk7Or\ ъ奡CCgf̘;w%Kvl*M6k}7;[FVށlrժU!=; {V:G;j24n-[s=bEV>@tҨ}hN~qY=6;&_6~?ft>]y5k֬!M4;.0U$[&m^H|iT|ۻB8ZlѼy@vڏ?$V.Y[yϷN(++ ;ŗ_~ǛCm=oafϞ=dAx_m7Ѐ[9CN{=uHh׶7_pѷ״75]ڒjSvyh߾ڬZjqϞR&O.I̮혞vK?땷_TW̴gb#oVow<褚^{E+ ȎH1msFEZZ攕3+2?wڇ:&MIg4uԛ.iͪxEjs=byITy!5͹{G M|fb#71x^k=wk֬4bѢ+VTKIDAT{"ԡKNᄄ>?vκuFu.wI؉;hLMT[տMzOD}7bEꫯ~ᥥbu_{ycӤoavώi#/0*nM3}6PHBxצ@+4J֭˟{hϷܜRi=xx};oO~3>vΐ;XQVVvƙg͛7/P5 @X|wߍ{^ם}MI{Ĉ0ab; ̊99眼){’hJg o6,tPl~9k7}ϴkgM:40U>YnyMx7Ks7q܌ ώ᳭jwXᄔ %UޱƬ%f~go.qѷ>aiek>ϺcPFD yp]֍kf;FiL({i׾n 8a'ĪEYκ6-4NU>{iDoߑ i~-^rlkg=rOMo\-*+*N|dDJ9abk#׬Y4n ;GW#kpҥK{a+J !3}|d72kzכ\\#ӻ5c-I&=Qq=4M\~nWմ$ߔ:\Euۮ]e˖ҿ_gfP&=:|CӌD}Y+;NtN kͽu+X6"v;fs v&g~ f̞Be".`vDڮ36 ߜjo9n{Qq{&>~7m_1ʺܜ\猻g iޑq9O _Vn-<=˧L4g5ީSŋo>|aaۇmpP:'=s(:ųN8siZ}n8⠮ᕰuzv{c//{mh {gEؖ*P]=(-/蟝ɒ_F|1f^e2+g>.iX᢫~vΊ$euH6rsNzuߓEAH5/ HB}|m/t<ᗝsLHI8*axkb{SK&^ZpOVN|8g+o]b똘$4=YPid~kksk/FN: ;xgcn.zzFG^H֭]H"uh{+{2V73g*,|ᩧ*{֭_u!x/=zt>9dokՊvwωZcq={6 yų4Ϟ3;G:côej|؞96?ÈY\ՕWQ FHٲֲswփ⚂p-眜sN^pًg]~H>kr9'OjwNvJG@yO y~-}}+o~5kJ߰zy~~fd駟v=+WF))!>9{fx15t^HU||ڴi ~bE9_}UFcb/ CF;r/siy96/6+Pyu'>i۟vlⱿm 99jRo&›Ye_6][pu5~w㭃0.-sϨXP lFN:ȘsGEZZ.;!zW#cq=wՕWl! 7ٲ^z$oy\ᇗ!@ѴCy)룍fw/|o_vƻb;e AߘX0BڵQz *i&п A\{霫o̊r[{;%>e7nXpćVpNђ5#FA'ɻ_}Mb Ƭ-\mʄK&d7/c͍Yם}M| vwn^9o;}Y?dH>u7e|WC<#lLx/&Ų/.Y=wHP .1|pH:)e7ealcmӺ~{u\zunڴG%7k,@ҕ_b/BR~C 슌o==?ȏŊSMi>t7_~~Xqh^O>Xrʴ_-[$+6ӫUvvh{&Go꽃_kŊvi<W>~: u[ֽwGh1g7= ;>"yi Dzeg<ǟ~ҼYa?O?4*vm5hժ?1g :ѿ/۠~$uU |GK}wʕq/J.o."V\pyů??oPgg߿G$NXPϴn[ǃ .''4bysĊ=cOFߩZi`DZ$ԕYQQ/"4V~>$+"PWҥscŗ_~?>|znղA;0{jJ7 tER4Q+Z"܋Xֶn,ٵ֏bEvewCLʥ.nwsfT3t~Oas>||`nG_|_5ݐJ|F=\2ݏ ۊ$lE5jze|2W^Rpq{lؚh]N>̲eˣ]v޹Gi^^ywY鍫V>矻[FqSv ݏkѼY؆D$akѼY}s^{퍙ox7Du^=^k ۖ$l u>jZ#,W*yեWwm=5>\Y*7%MU^[Q$nIDAT$$" $!I HIHDHNo΄ 9>gΜ?o $zOVC?oJf bPKqի)z VZXJ7Uz l9@:uZǬwu|dYj՟ˡYƌFɘO_I8Nq Z , /z{fBvvXz|'F EHIbڴܣ|[ܷ1]KFuZ˞С!($)BDHV:s΋w_ٯU@y{>춃ƣčRq廓;u %7aa^0{Ɠ3:Hf{׶)AxoAc/qZ<a<αX! Te">KfvDƥRqEE{zz fC_2V߻ێIdJ.*0^&\m e.]fcѫ̞f3PH>54w%A ؞$3-8<A.ztaCrm{ECS~a3 ~x~.>TQ9-,9 T)5~;WNҸگ7mfy%-=U$)c_;vO//PzWg;<9ܡ[Ԛsgac+ۆo+1Cy34>`gn3ow͚==s :t\9rO/_h]I_FtBƌfW`Y*uf=m6g'n+WʫN=",sОQѴִI'tijW_Cy}r¸d2:?Y/r$GzyHienEٱ~øX8?z'#/{.;R˯jN\׮]^7=$<즛EujI>'ƌ]lY]͚{㎡YbŢŋ?3KOujB"$J7Uz l9F$ /lv\תUkɒ%!e9֫W/-[_ojիU^=:z9gѵ˾S󑑚5k֨с֙:k̗_} H?~ŊQn]MTr G˟Ѯwv={rr IEfwN:uzժUE "Iyc><*vaSNIp3իW^z?'vٽn2$Ny^{yg/@ $ټ;qqXVx$԰a:gi{]<(ʕ+?䓨HKK;t󰐤%KIRGH~ Ў7(q}mӎ:{qG;w^`M۷;DA~JF$\XP9mxDEHF?W]yEVիWGE|y~vϚ$*VZuȑu ʸOMz==O~JF$#^~kXӛo=1mgdfF6̌:زQ3f^Чo>=O>)l+OC6Wv3T:(^v9 ^4s)o5׾RFUHF1CNӦ(h?(Z"l{2N6=%Mőh8)XXkhqcHVLg,]WC~n_~Uڰa7l+ыum6{c2{ $l *yy/~Dyoz"q䯇vaY1RRz50}h㇭kb^<9{ JdDCŬٳv;3;r^{-1i`֐L)2q#>,ِ6^<.t{iM WP~C]9񦗺q˧oB] *, [<ɧFUVEiii#ァqa[Ypa\Ԫ]UVݢEZg6^AC26Ыuֵ*zK}*mtK^{u=#;$QzIDAT?v{̎5O>5O? [UG!n/(Ή^?Q2椁#?,|D,}WSFu`꫷>3zy1_Mqc第a5g:O ]tyiҤ@ VhСasL}ѭ~닚G6x^ʹKn7\<)1W/(-]?Y1kĺӥISsC( 86"?ln-a=%q'8U榊vFﰩUVP(T\7ԫAÛ" STcڶzı*~K FsoHĥxKlpD>wQ+|ֱ Te]tܱ>+*J"Ynݧ{˰we[=5m.t)YI TS53:վCn^!WF3c+&^6pĐ{UQr~ 0\񈛅#UNW޴|dd;l\  -ZlSڵBSo-c=dQѵ!Eޭg,L]wWmoF?<9JF$c_v鬷˟~a9o(:b:%7liI!_t{T21vUb<#FϻFrk!|rcFYcn*Ⱋ nژ+CD){PF4.5VLP7`ڥwޚH%U{u^طO(93t:g9kдsl9Gs㩱WLztRhe:fM-5yv/BhCL]hKZOlʂ~aS]7xЯZ1 QQYo,?_7j2Od3ɾ[zuz '8V?c lqf͞ݡc7k^خfOS'תUʶ-q޹tg&dg-իWNyr61Rr67(LN"Oa3m@UQGddZB![p_O5h܁23lj(>vLz6 yCz,ZM ir/i[wя޹*qE4lOL˼.;l>hq޸q6hڴ7:uD-VKN*#o)9v l=$l%5Ϻ4-(U}E;uS.榨}d̋^'C%KL=pvY nj\w& :ZN<վ߂)!:N[y5Zj}._LɘovDA-s]vٹyf/wG=&3?yMæ[4dӦMׯ*vKΝz><4/wqժUҬĘyZސ!?t %rQSr=)ċk oȬ JwqfZіߺ1K'" k`z,w*Pe&֜JnKzxyq}߈KIh?($M6xI'/wFţ=']7)Ǜ_=IV^3N?-T*[8SN;=ߟ3v޹ʧ3-w }?ܽX/mT:3O?-Z"@{GwG6ۥZVⴑ6A[M3bȈ^+*qYn/ۆGKTc9 PIJ5m-QP^^ޛoW]yE6m_\DzCEuiMB>MkIOO)+~?eJi-=n l^zen_E۶msc~-^7&^W<8N:q=-77@Yj~Öh߯)Γ EVVuVKKP5j裇G_NzfR^zv;vno}Öތf2㍗x|$nu]CժU,z긨^ G䣳g""I*FKH/oG1Gm&뫯ۖqի~m͛4qOz;w^dg~&Zַ{qM4  6 2ڵ#yR1Puhhg~GG?1&P*;TxxȚ5k$"7߄kٲŤ^? Е׼yPq_~YtKKվ%j׮߯Z,"$u~>Ï>nҐھۅAkm={7Q#1ǟ|bŊPq 6[_7x} [Mt__gsMoРA/w-@R36Ievhڴɼy:ww*WEKHOzmviPA)rj֬j}ޙ5F_|{6^{5xе*_LoP\*DDdӡ}8"ns&Dǟ|2m<}|m۴s=i.$+W~GqVzI6{lٴIXjcoB1ق[A(_M> X=vnp}wlD$IBG[\|Wѷy'7zQݏ Tлソrʐtv޹yuďH&& ֨Q섨^lٳyGȐU!][ z{ykժ5kcݺYlW_GuP^PVX5WPIԩgYly;c?+os%}oyy +y>矻[Fq}ON<{Bu]b֬YtOT,_|ʴhYC=W栃jNXdiSi6*`-&&ihެ_߾ڷY_zSA_r)Xxq@>2Ō37عV]?~!YZjZnnH:o̘($:uj#뜵ieեWwm@Nv,Ydw\OjժmsP|?8??/\|yI5nK۱s͚5wqǝwy[joH.-裏:CeI+(({8Y*7%FrDQˁ!*_C;v @Uڿk`16\ye\&r*+CDH~:GEAA}/9sfj1c}툞'"@Jx`Ջ.G롿]|yXt鯆ݾhawocqoJf bPAY[k޼ݻ~a:J?y_y ~aܘ}|$orD$9@N;G~|dl*IRrG 'pBjyI^( 0$OG3f_}ve38si۶M6Q$H"EDQ#$I HIHDHB"$O>ҤI3f\ᇭŗ^ $u9M49]?שBienEٱ~øX8?z>yŗΜ]4iR >?CWi[A-ZoIDATbŊk ǖG"ur6HT.]z 'N:-^mذUW\Ѷm-[o@2|3?`SN`F EH<_jyքxΝЃGW^}5^=ۣiii5H"L @x#/ML)M4>Kxg} UE$r۶㏣}v/ժhՇu=b̙Qݲe7M^zH"dGH#k׮GȚ5kFܹsHI#$<'p{ ֭wl\@ IL>=.=@T|@ ),\0.:1:u*H.\YR$I/׾] @JPڵD$$$" $j!h\ߢ[ ޥhP;v{~|̒#/nWǢ1痼ucN`sy PQ**%"N,X$Zf|Z|9恷zщBhv'|<Ԣs}w79mQl"e$tM@EgTH.v0O.3],n-)mk{36#CˇnuFߞziܷe7M7flCd<8ṡ{Z`y1gM<=xt(DV<( @U 2fm~%0myKK`Gzwr?\Cf&ߝvإK(-3іb fwS*=PUDkyoQ*n'6C-OP4: 7_^cLL (cX֓+SyTCM~{XP|uK"*=PUI/ 93޻Mk WSu* j^wgoi;-,)41װ6G8u\tRO|9GsbSN Ν9G]ur;*Ï>z~WCLA;lhDl;v8$Hin:%Փ}i?;7Z:G]˜O_'pBOhj3oذR aƌwyg~>/ʳQWxy x TܐtVX1?TNHMI8Ï8!5\λՃxoM UV߷o}_~J4i$3>!^@xժflPu i߮##o^Gۯվqf*"{N#'GH%?]?,^;O> Q=?(z|͸+BUѺu㎍<*k9I)FH͋32jXv0$%K֩];/hڤI\Uuj qQ^֭7fyg„h9s|'qpKs=v9^1t:s|TN*D} u"U^|qԩϟ7o~آZlѼYnGq%BzTѯl/U}CkѼYZdI ,\0.:mҥKwwgak~}#wÍ? bשӡqpg<J@SvfM9M?+fy2omG{+===PH~Wq뮻׼Y^;RR^qD!ԩ.¹sm9sQW]yo\ ZvUz?|ʕy 恰1~ي+{|A[v>dz<3T\tK.[tizzRDrvϣb̙mڴYk ݏ]AL "3-M;C%r7lz;.ct3 ^X~tG4o|װ^r͚;G7߬^~W:uꔹKڵk_jլYʯBiU끰Y7ޘoJoŊqQNPAWx'|"jYxq:mj0,TП+.~y*-J;a+\@R"flִI 1(M˽q]n_ )-k'^pg_?}ɓ/{{4--̽_?1$ٸiaO kUu#ծS帳;cu~/#޻XGcVD*^_}vq1ccѢE}Q\gvP^]|yTxG=򑥥7M3(g}W )I}mp~-hΜ .uiǷR>r-k퍿|k?A`%1cm/ lU)"yI?я?p-.رITsЇh"lC/oUVW!R%nu~}=r&}[}hӣdk`~Y`{bȰo:q=kݎ<̳JfL#]<1t`ʔ /ِH2kZ0n Gśc5zWiJy#M׏R!2從5BIE*:~jnO\9枒5=Wꈉ%;!]՚!]7 `X$:Zgwo[yo(z*<7P~tAC{KĀVL0~19>O>u_<4Z*jLKKy=7.o 8yh~PF2}q+{ _#"yh}P amg-+k+V[BE~/rnW^}ۇvF#:&+YY7a**v7{Qʞ-څЮŞWB%nrh߾(H?Fz~f [YY_%ŠrQ{~ܥ%n<;K}bDѯэ R,T8ο}s{īN-CX(*&ʝ0iDy!y^6 I +rKzܜگu~2kjԩNɺ.Oo loѢżyʻ ]tyiRyVDaoSeԩ߇ ~ -NrC9A7s sz3޼D*eȬ8_"S sK(̾T,0tâevFٺ} wjbNoRPHq1g؈Æ"//{LW>*5k`2x k+?FF' \eom/N՜ H9ի7idplWi#%R9VUzc%l%6f_ ["ARXo#> oo^=cyxTPFԭ['2]w%lI9FpDW_R*w)ME:?uȨ:u#!$y`Rʙ|Jf=kDbik%qMbԽR9CZ8V5K)W%Slo?M>LPݐHvϷ::$rc _F:즂{~6SFMkTM/y!qcݒ<7TŞƎP+&iڤIR(Hbe% 4<"P[B.]/w?$@*Ʉu^طODoޭ/nϊL[<fbfn %_s./斚,wFB9ucя{dKyy-K](_f=N uø!#FDe56wSl'K e#FK+Ye]ܩ!{CHQԒw(J0|H-l~5xPryAd ;aʝ7a@X6| xEWi+D6ҥK;ĩSū 6+ڶmӲe}޻F Z J9o͉O5ַn1O1cwޙ(n9cgN:a۬&_/1lt6 k+}J£HnyfsCne6+C..%w`y5T7{]?~&K٣eLL& t5zްBn/Mgw̻a`no%-'N{\;ݰ`ٹEơ@K/- =wAߒ|a;O}k~9qǵo ##EJ\'aUj\)Jkڜ[ݯ旯r-O|Aߋ6y%U) 6;)/!+7L)SO_6bM]O60k.M GJLWp2xRq4Hb!%/Z%?SF|L=Do\ڈĹmk4zifZѤ5z7F(hyCvGK\ı>*y2)u2ʼn!$Į== ZGr>5f#K+%LO2o´\{|q7[Tӡy,]Ύ2'{oL\\WC BlYM tңoV.~'ļ:4]_> q}Y Z*01q6h..6+"9o7TtH%*m[I&ώvuwsO̳>{yF}Yk=]7EBQtHfp_ ^d8"i卽7BidK&ĜR0%$hC3)/Wsowa+LrDQqu^6E7DO=偰m˵NdʕmGu^Ka"_xq-WZvt̵Hb&y?_vt+\fsԫW/l}Xza]9sfTliSWz_nE7v/`W^¨x:GtիW:}Pl~G㰥y k~K#7M`_ygLF +xO&Wgob>/}]\_طO To#;uŊss߽{XD*fMK6^v9(((uᄆWܭW:};HKK [̳qq w˰%zsTMkP1{=k-&곯>(zݨ}݆W!dnc(-yFrֺxr6v[6¤Y]'~_=yʅ#ph7|ŧ_yyϻd%5k [̜wsߙ|Uk@ZO/ za u]Fwϩ^vQ IDAT]}'wbʞ~;~yǢū?aTӡ"(MD2h)aKӼu6hP?.6^{u=#z}NT~ըa=]zt9G|[rOoDiK%nok@Z.\=]+}7;tL]۷f;-EFߣhwS.ivDHI:].,#"i!,Zֽ%aSJY?qO=hy?2E.T[vqjժH.|HDEU ת{~zś9ur;oMp#y 恰14+.Λ6ɱ3ukcStEz+GȰIf͞kH^3>{yx{;ֹvZ.YRƒロƌ.K\ڵ;8Zn!)x @H|,^)H8{hyxԃg^\n*TE*"yFs=vmXl+TUPPN;{H=1;gu:ؐ>;7.gw-$HF9q157SBJ‹~Q\gv8$---@J@Y=sVTHb3v(7~C_xi'~zGXnH ˖-ԸզMtpHTU߯Jqղe CHI/"c>o|'Qs|y眵sÆ!Ԯ]kٲeq!=bժU[zuT\rv`g&d/\Yhơ /rt9N;TQVXիWHdڵ8Nx9jjJǡΝ7qw˖N9juޯվ'Gj#>9dd}ԑ5k <<Jk뮟}yT̚5M6jk ~}qeڳds>ty$k׮G]CryYqѨQj!ԨQI?9픞s۶k` WPPP:^}O;j B){\̘9s[oiii!YLcʕ߇ƌqQEdED˖-.jbٲ.kEaDxҚ5m5@ ۽[Q1cs@]v޹ 9ͷ/Znwܱ~zMs}ad_p!`ik QVoHO;w(qW76`նpC:s'}Qn$hu1쟑_|}.,_P%^wQ? %T^nI/|͵W\n5׾yZsD$H]tg]#Fdeڴ@wϽū?pU第PfEˊ+:?:geu:}5k*˗O6-'W^͙]}lώQF Yԭ #" @j:Z]tyiҤ@SGsܱ>u$[H-u}jovvkOؿ?. $)Zj_v鬷˟~a --k.;ykf^26زj#" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$VPPQ$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIFѻ]zXÌn͚>]ZZY^6/{xԽaQQQeIv1}e4}FL[VAiiޮyz߷HJi'sg hQYGyv[sA;Zq{Y sweaXL5{DD)o3'䳡Q$F/xꝥ K?5.s~vq>NxK# ~gUE/sKm{{|ַ-(ɉ{ !D g{9`-[d^H.PE;oQ3jT"O:]( JQ6j\y ֮ݰGxcD?{$ D$ ib[:i34"{z޲5{Λ'[d -*mCֈyj]|Q'-ϸbkۣaz<㼼ʲ#zfx"!7& $ F$Ch}o_uaCd("CH_78-ӊ٣O/:]Y @؈dz==/`駹^=جC8Xl\YY?gg7Dd^D14nQ{k4gXVbG?߽E#geFkv}F͚pfyn= S G^r,wŒ C}a%~6ӧݺ[[>D{@2d > #>vщ>+hy#1׆Yg[~~h}9>f1}vN^lĸynCGwdٽ2?*j9|PF{#ƈyHB5?wN>({V~|\7}Tvg+Q7iE=Q[d 5=((YؿE'IDAT{%VлEakzqqEߢ[tge4{Dφ 8oxF˟.G<32ҰYK7(nոW=Ҝ5YrΝpGnK#*dHTM5@$D$$T-YójULzTn=b>4*'[jG$[tߩV @VPPKtD$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@PY,u5PEHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@ɱO>ҤI3f\ᇟ~ijիמ{>Y=gd`oɓ/sdQzvo\_VPխ @#yX\jnH+V#{Uھ>mT/4Ik.?ڥB[7$ߖHXa\,Y_ѭcҥǝpԩz ;Z7٧I&9oΙ?{q_RI#?tJϓ&n*^7xкQo"T~5BRPPp}KİF{4 UV/:y숱]}ˣ.YӦ:Gۄ}e/ȵe]z8*E$W\wۯIg߃ͨsGPqU)"9!_qTԪ]oV ??1T\UJٸI?jOŹq;O? @UM6c}*22@}ڧVZq=-77T" .n-څЮŞ8yh~PzUV ? @[͎n֮]4iRX:6EVv'{%oq2Nm=0ޙW>^cnQr•;~GMŽ=֫můQKբu(w_+-ath z(<םwLX8 p?MsnYiju_9}BZ&>lu7W]JKd%~eM[Tvl8瀱cjJLr}ەi񸏉q"mv]4+wnZfƞ!5ڻtǙr+7uNjl~uvѦ=؟_ᗇ}|Kl"mٽdn*8,l+V`Smň6̯]kO><*}/TT+ץ]8xSFXYS??3yxқZ:O]j09qq/oEv /_~5xPy[ Uw}xw^静q`qf= o=3$+"n;ñË6.W6y{ac2{ $TܢezzTPUh}voV#M׭Ǭxn*#ڔ 2etRmͯ;?:OiW/9MSԫ嚯2`PA.v :CTPUH|OȣQ#ϞUhFO2܍7LĤgOc X5{ߞvضv/3l˖.;<їՆ ߽$5BU3^~irz;sx~v]|vpj̙b|1KG{OƍI|D6yF׳Ϝuy?x-!YN{-l]9**CZAAAfQ?_~UH"=O>io~j}C%V^[HFя?-/Jve38si۶MD$vDBDʯFH:"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHBi EHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@$D$$$" $!I HIHDHB"@ik>/T˲D'';w7< (T57" Z'}Ywvr&~ha dF${{-<>blC[PҎ"5(}ݝQyai1`Vf hdɵgM5[FI1o\2fݳv3 )Aۥazóg?^+,:]uU|mY;|tv%ޮQg>d:Q {xk5bμkj[ 3O?gԬbHfIG~ao:/_ƿn~aqöS39Q0҇^ݿEl)IR#ųUO83^_pa<҂:VχMLJ+{ܲsoo6Wިn{^>wyif8|x<`vIDAT=\2kq,Ѡy>J_3'%55+3-J_N|>ߛpO,L1nsԤ{T8'RFOKO?z`Y:g ,(H}ԭw,+8'WΪzΙgMJ>%42"yOV ^}14, -rAѽɢg sТ[V/:iPިɌdwAIᲢT~j'14/3銢I{߯%ɐ; KH5a3:a_9uBfXSj!v9+mG}*לSY2U=aBM3o„5KWI˩%C[㳯YyuM OvYimR ɰߍSx݆Y{٧Ohco`IDr`ޙUOQ1OTgNZ&2s%WV5te}@Nk UF$3kxKŚ-.jG%U4Us?8p}WZ,ܚYYW?U=F޳fAYE9Ǐ_ofyŤ!qOTTUQ44gֳ4l |{䪿TItLBY.cMɨ~3oGi"O4nso.-):Z9)t,5pм]$CS_K:wz 8/Ιx ;eWݼKG04U۟\z~g^v='R/7PsFy&z3k3upW岚|$?uh@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@7"涭ҵ[*]$"HD I D$"HD I D$"HD I D$"HD I D$"HD"'\tU?/믿ڀOgyq{vAǎ@HbuNmkڛ۷On*;6fHn+j?vK'gvKnh: *V~tpi7tsG>{|j~;47]$!".{̗ք#/8a߷O<{6p׮]>v7x-UdNcݻ@3von-K_OSС[;v׭[f"" [ee_T-7 =T%#m QiktՓuU]fאSxɥKO|g_x_=4c=q pRgr)Nj5k@3iOI`_7oN99pۧ~{7ywBx1iϝWio䓳?SOI7IG$?sV^@cUVG$|r+W~/_n}h-3SgC=t˲С;߮ge[iXΉ7m MRqs>?+BNN6sNF]zߒ%|-[\^s ?yEgcX]CY_~7=t-R do;uƋ-߿h>-)Knh:={lTck}+Su.{E_4͛gȰ!_;10w`jGl̗Ȏ;cRADڱ[>:{Р-Ҙ1;v}e(^^UO>Vo0T=}ƌݻw׹ ?*y͛A?Tmߒ*.=-:|xnxe}W^ْD$csr&9ii9Բv㗍wfEֹk/'{An^|ߒ:r!xv^C߹~;-sƕ:7oT=}XʽW^6^+VrxO4tgH[rvn294-w;"l}}嵾^EEƴ083qzKįs`U=>ϣ~97f^{ko͐ܯו?M?<9E'ܦڲu̺geYl^^ܣ;cFAl^~z⽗|dʚgUnLF-KObWo|xNѦWϟG1dũgAR㉯ u)æ%V*;3}XvZQe]nJ ?&oQsGz|dRCJ6ewXH$nt|g=c2 /,oNvV)?!LKK+;G;kͩb|z{fzJIDATD>oK}|sGX>9Cs tIR=˾ݩ5Ȋw%#?+Wڹsgh ~d&]bE8+~bgȘ6/sڸKC*vZQt6U;ේ~^Kr wd]cd=vcY#~D#`nvѴxne"8bܔ+VRnȐ5{JF$æT >fQՒOՊ]%'h\uYWb?7!+e;>}^4tFY>Æ'\zlPf.‰NLe˒KxѫW7oYC7@Dd\񥥻:MæN%Zǻl';:!nX1 ?={rJvj/Aձ_;Kǥege$)z}^vMw! s^SSNuE/"Y\) +ZC/ ἱk;' J|91ê箒qi9ȲgAG+vDsDsJqhefOIDLmw5`3b3NwxFw)[{ -{-u[lOn2_B"W=!`EУ֧ẓC ;ui%Se=&]oӇeOy9oNLrmO+Yu׻|uc(jYY]T5RY2=KVs~wY]C+vA񟮺ejO)Ghi\=ګ'3 VxB%6=bݢK(H=zxB+oݷ "EKv-ym_e}+7㫛_V>ێɋwkױ-uS8dWzBK*Cz g6-6v]%U*ةc{:nw#Vu1Ǥ<#*Efd"JaiJwDD4o!^SzӇK5L-xN+L>avZ5,˝ry^fbp|HmTݫwV>3{^o?|qwxWZ޹s/H+EڦX^|onژÏ o%4Gizҵ-{g&O, CG=\Q]v @[emx9o߻j͚~q .zWC;jF~;,SI6EIht"HD I D$"HD I D$"HD I D$"HD I D$"(-hE I D$"HD I D$"HD I D$@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$Aꛬ\9Y03AF- -Ch *@UoD2cT[T{bCaa~w)KGF.M_h "ւ9;E˾qY2+cNႷ@Ԑ[% MFN#Y߻DFh_JH0!' =wVZ0 6 ?/ddtK, -ɊYũ&$ҍ&<^5ֺ kbؚY;}CoI,'F$K 7$3 S!3G2̯mρ" HA;c􄋒ņ|kATB2Ҫ{S;.x+1F$+wI/"YQ8kUwޞwr+@RODrũFg6s¤SŪY-3"Y`hZZZuS8s֚wWNʈOx|dp݉iiTV9>vޝ;K;@b-H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H߈۶KmH$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H!D~dÏ>m9]??1QHp-ov١}=׍|BAD" { 2&_c~Iv̺ico|/#=S29RTu~7Ysū74jej yPtIDAT`ӏ "|ot?^F̋Sɳo}bg|Az}uF\/Ƣ.;&V˷qç‹]|O$ėoOD'W_GfO\[oC"7Rzm# >>0^|RU*u<&FDrS{ {}ˏ:>+{Fk%)Z6nxf-Z뫳?tbtmߙOZʙ'%F[( ٷ=ၩW?./|jٗ~ۧk +!:}#oTkZIꖍO?WL|W'~Y{][O#m|jWٷ&:P:wgC<Xٷm)Q=G_2;Pnf~5b`军Fч2WG~U+/J@'f w}H /u\տUɃ>Uf N:|R[fOםtyubd7_'ZE_}ϖC>p#N ,Sgٽz=#,}aj,~+k$—WYb:'ܶ5\~Yg7]6&G;73o{6Um>"a?[_y&ʣNjN/z{rOdr?ee܈񕿿o=N8!=kmoz~W^}57ujh싧Nxя'GA^B<迦JK?o=x85"[;R{#Bdmھ?ckݎ<Ï: ;~{>SC9;="}L:ΉwmRZZ>ю;_2bGCwݻ_xaN7>ژC;uжˍ#3&" @'"IH?OW^aB:>{;̳ {=u\pΝ;ٳC /~?VOܛoѢ$m_wYګ'5v~_ziΝ33&롵>?G ۷}ZWvH~dTk[;[0U|B#}}rm5N|gߞG;94ߞ̦]7U3~eA0;rBEHA?M5={̺kVt>e[u=g9^zM7}Ǐ/"Cg}nפꁹ|G%~;cRsՆ *流Ï<|]vDh-Gud~XphH ݝswѡu}}Nwu֭["\tY,>/^`Feg_z14Ņc.<ݻ.mZ^#k֤ϣӮchĺXo }p䋿lPtkhQHn޼9UtI\'w}j-[|o]:6DX~330} pUwKhy~d&]bES}ճ矖/:ujh~Y̽׼XT&E^By^ ʕNtb `~}z UcXhC;ڠuy싅_[Tu]sԹSZQ vlSv(Z{3c',Zo&yqׯ@#`D׶;XsK,xϝzxqƂeg'OߞM\}ƺ#q>ر5vǎznZ^7>#nj[cصv ݽQW}.]44˕/_3T}]vm?qa7'1FMLQGŋ-/oΈ ՗^tɤ}1Дk @~D@9?=zw^r%kVIzKq*"vʹ?)^o}e|S>5kHVqz,Zy'ʞ 8+H^s&#|Ŷmۺvڨsg͜?3g&?U ʫ~ZWv!-9涭_? QȱdžƻvrSOV38+4[/~c~&%]1Ch?;#b I9ՏZxׂZ.8~Wiȸ?4Ror>o'\pxm 7th꥗Ϥ~}SDGs)'f;:[.U|c;SD2nSOyw3N @b:'ܶ5y]gmOm^[l旎G2ጸ׿+>\q5m3 B;He͛_ϿB}\֭[tϽTYܹsO Aڭ~N81_ZZZ5}]8h:j~Z_K/s˖-ڲfvdZ/I.>ÏCFb:'ܶ5@]tmӳ I D$"HD I D$"HD I D$"HD I D$"HDX,EI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$Ѕ 3Ӓ2 ׇF\04Q@KEwS!IDATlQbqKG.}&T&@]$WNHKfxkQ3:W1pTaɚjEa*Z#[7?v3u)UYw}V;1w=OnO7_#E$n˂c(\dΉs#lʒ&;]Q8!sϩC]ZME$,K yNv?3*222@ki.}z$+++]SZZKE$;ǩkR2psh- Fvo.蒊-o%Gߪ,-9դbNqO7RYSuP =`NݱdTFhE2!cTIoƙztc>yZ" >"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$oDm[]v HH$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DPt"=\=ګ'4]$jgJu*OW,_"^ F@ izC3Z>"Y+ cwΝ:7+V~koYh!6"HD I D$"}>,{Jރ혝lzNJ%2 bZpԉzrޗYP6%OVxrx 5wGq%NƱ^[zs뜪)u;y鵊9S^[^V .ݫ8c:3l|K;͋=ʲibꔲɱY9eXqr`Z^Geݳץ 26 /u-ʖUgZZGvol^6lZيKveL+:xyEΐaV7e)tgMw=. {_WD3߳h/CVV'"wZM(.XfYWh-weh6y0Zecy@cHl+gZyt(}yuM{#wNLL($BB#MV);m*?V{}AmJ=>S>>hi2 uXxbw{<-c6quhD2;-;{J޽*{w5{5Z0"k[}?=G^xׂ7ݻլ?SUMvUYQrG)f(Y:~x^gXVqlag}^Ң]Ai˲D3*?qŞ&+gK0c5WOk㗷w ?qN_+@kjs]$pyC^oCvZj|_u5ξ9?rJNu0xؐ]= OkiJ7没qfqWa Kyu(xwu.]n'w-՗Ԏ@צ7>-Y_ǧ̝wOɽM6.q]]uZ6Md%ƕ aSIqղk=ݱӲǥEV_81랛:q'Z$U&rJ݋R?XeI5j<;F]_=^gdd`w/0---ɋ&7p|mɚtf8}>透XCb }htɔ[=C͛W=p,T1+N Оd\= _/\hnꊇ\[hyCϽmՏvWvѦMf7ٍTVV=\H7UvhƲ6Y!UIM}Wfe饗^Jz 4$77Ƌ@ i mjDCMw4wlr!>9$7j,v6@E'"k[@.@H$" D$AьH=+Ֆ޷Cro" DP~tPovYܹ3UrH=u<|o)s3(oPx+Vn'HG}t=u,{JޫΪs*d6}3fƟ޽;~ؽ{[ d;&YSCκd rUvdݳlZFybWAƦyaYwU8漎8cM>KleғԥwOg^xEw͉>%iiis#@T.q;v>_~Yti=&Xhl~Ϣ%,MIYWvQ((kn4$}O4GAλ`8;~y B_D2K.,MEs~ꫡYLV)!+4Jd{uTNݳlϵSƥg/pxhimtWx?I.kNΞR?o=B2kn3wi}~We_/#LҥcF߿lm-Y*6\cY,:U2~YӇe +50vcYƱsoM"wJ"gϩ;w o&ڸ`I'Q;"|fqWD1랱xxj)%lޯʇ+/V||6eU_)sJ}wO]rJvɟi)N,hT#Ix_IbuNmkh?ls3(oPx+Vɍ?9ᛏ-]v H.@H$"r'vWs?혝!"rf( {!+κ"?H$" DPZ,sm[]v HH$" D$A"@H$" D$gn໬F<b4i 3MS: cV(B{_>;=z HDH@"@$D$$" $ I H HDH@"@J EI H HDH@"@$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@$D$$" $ I H GؕrWƒԤLvmD)-&{g3ٵԼsCΨgH8" ?;#%)wjFYջf/(5{lvj|\ZĂ㛃[}m9 RRT4ꢱ18rFd\ճrbgߞ3*iYc:lrI7?+++Ni̒x0w~]Q'|jƐVvwhvqhiih)-hvCژy3nG.6Ѷ8egElbF}߈鏭PacG[q)ao+VNO?iФԭ紆Iݴ|CvS>V>>9'_Fw<:>+dm|hj^&W,_!~7EvxU_1:vmGVDbrmWY:1;5֠wjҲb^j¬SvjfMJ )+OtrFK7Mx8iI嬱S2*`ɛ\}˝_Q;~7So ?A,+('1+o3&ΚkZTvޘle^uQC"YS7?SXAY{gAv05ٜ w( @Wѳ#ee3tiVU:h^^o!6yJҝm 9iH4=@i}xu}P:n>8{D8iy[WLL @j="Ŋ&䗬 n=5'?9"6))ڈHEcQc ˫7o\[Y^R89/;wRRRVaeubՋW5bɫ+J & NL_1|=. fU4₼ћϞU=!kK& ugU#]ڂHQ]sُv꒼Ԏ~[t_MK ʇS|}l`y԰0'kۘ}=KSƦЦ&(1٥ު0Kis|zxJNaN:mP~[?}D{lx>rgcN1zcw?"?'1 <6lwjBr{=eG]$ H HDH@"@$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@$D$$" $V# ֧o@" $ I H HDH@"@$D$$" $ I H HDH@"@$D$$" $ I uƍ^y_o} zle vRWNj4ޫwp!GH\]5"iӦ_X/l޼9gڴa7z+Yrczܐ@w֮ks멧˖3oJ $յx4q~y`mC rߔ!C|? @6n{ޚ^k{3pCԧo@u.|d?ӻw:(9/t<~@bڛo5*#3A3p?/F>"ʞ ,' $|6t>[lyqK/ջwrDקo@ud'%LnIچݡ_?<蘃<0n/ZQ#^/GSw4"ē \0R<|WOޡ>>"yc!wDrq놻Z;;9^lܸ1tГ ƿS}>]iy93/> $|7@;t$@;H GIOK[ ɭ.Zxq =%D4xj3څ ͊8TIwOvYrtc"LMECnl~XXc\}Z",ɾ.\KOo λ(|B3G\mzf}RvÇ?嶇7pCiL3.nʾ{-Cvt7l2a񪋚MU(IՍ{xޏL_xm='e6*fsg,){p;]rmť]zn yw?u/c~ C=,e{-XϱwŠX=y?ԟL׿o۞Նo` Nv]$gȼx u'R aIDAT/8it=7oXwwvMafEc{EܝݫzKbI3.1y2gfE=9pGT&׷,:OBM򑽲'a̞͗9:W{? ckj?W& ?={q솫 qSbcn{Շy33bR.. b3%thK¤xP/ޡ [?cnf.?%ֹpsa ܺ>,8~Xq[<sTmEs91:Nh8;{}{fCs2I7-c[;[TɵKx?t/S@n\hukٸvG۶7r:3R 86fޱf5բh3ZԟE~Ry}aaհy bFc3"7sk/ ՛\ Klǖ..&H}N4|guxa}gշEr!?a]4^/_9ˌݪX¦\d fxaׯmPݼcb{D)?]úU6^0fF+ξ(бaԟ4.]] iշƖ)Wm x ^{i=Cx?MOGEshgd]|}f{z;3n]9#'(ڡp“33d^t#̜ٱG]\V7stRa|5g-]}}x^!g)fE&o=+uBEKȊ-^zOüh;U2 s70O'7g=tv̶WKMp}wn[z _|ݛɱ.I8$'e6[㙩c3f6h⛏EBo;[Gzx#z .EHF yU4oZ=Ukt;zѼ[*ns+nẁֶ x얖8[kX0~w;ٹem-=[FxcebIY";F$#tE?:.v|]k᧣3Lʺva]+u|7;67fmq葔H>"9;}m{Dwy|k22t} touQv]a!~dmF$֭[/gA_=yxsG}zo`ٸq[WG={6|v}/_//8̽޻׭ q55III/ګW@BJ]$xs v{/yDѕ"III_)7ި +uڗ?,(RD2b!?Hyܐv|H\=CW=}9̦;׬]oJJ6mڴ_{k?o /o@"JkkCynUkGx8qs,6C>8;gέO~b m[{=6oHD]o{/b͚^oC>Ȍ@J!Yh`$BImH HDH@"@$D$$" $ I H HDH@"@$D$$" $ I %Ģ$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@$D$$" $aW.IV^IHXKSRKֆDG,Ȉ2 *|vmD)-&{g2|jFӸh#-IrN[[>krzΙ\\1";|kmYa^{IJȞX\Q^08))"vmD25ܐ:@9onIUMw}fS|Ϧ#J/&vYS$?uߓ.^Bo;!W3%n5xrEC iҕcҧ+K WQ0TϿg i7^r#=##{֞薘6"YcG1.ȋyli =ɍ%)I K8gdOU^ hfkUfNK˞XPиr-wKltRJ༂m.ۻ SK#g4.VVʙ%yX]O0{Ԍ!׭@_vu=%~hS3|be?'ޱlBZVû:֊^"Ei7v}h֔mX[ُF+˺!k/r%6vQɓnk~<[s}Ҳɩ'\Z/w~eQNWOoCI^c+ //Z1cӏ4ɗl5>f`ElbF}߈5,VvJv'X¹}֪nX:A^S&t ۵N-j'WYްfyt|V^I}ԼMݳ|͆La|M45dcsmihQǞū$/Օk:;֫Kf$&_rC^YՔɗ$Gf͢^MwyԬ#M'}Ґ5͟8;#vΨf猈|tB䒊MM(y<:zۻm\>C瑃?#/}6_Șjm$v"v_e%'Vpf&;5{If+7Ek[pɗNXSMs c)SSS<)my3S {frNlvF/l6.r[CnY/52[ɨ,7|XoȎ~{+ b $N*c'^y,l:G$+6ūg.=0i;CngŠi{goh6y{ **ç-elxDѳZI79c'F4dZ4n\F- Z?ue廠itIwRJNAE݆7{hwrZh昝HVolE|Ђ-.W̟BVW.+-R⑴c^Q_yļ< .Gnixv|Qn~+N*Go?j:VYRL37lasmw '\[jcOjn;)5g֯@thK&Ԥ7rcuiAvs~dņtۛ=uVlmEtVye:fg9PSVo%յu|mɄjcD+^ˍUOVvd{']ŨoZRP>dԜ﫜P|`vˋƦ9Y>^#Y]Z]4665_?EԌ!.0VY^LL|Ɯ#P1ypJ\ W6Y{m䜓nnqQZ?jk:헖=v` ^LIϿե-?i}ON+7T4G>[ĕ#vu$wl޵]$s H G(]e;bU&eL-Zuq^j=Vَ3ŤW*]$TWW.@$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@$ZH~6/{.@$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@$@6>pҥVիo߾_8;,F92##В|6Љ=sw?^{-]}3{%'':>}`Oɟ45^= @{l޼wGakӭ~auϠA:%ISv}Dr}Rv(;aÆӾ!7מ>8NH $k׿kU+JKd3ƞ|D$`OJ"h{ყ?utKs Nzڦ "urr_Jz\=GyW|r|dw6n¸{wԛ6mࢋ D$-[Ozӯt{}g8^~?bD$%曑"wMsnßD}eWu޷w2x1_=nR2%3iʢ9TY7=5;qo.뭂qE{͹bɒիWD$xqIǴ215M(‰ BaH(6;%ɘAESV;cqgFnմCw|L W?=eFUc4Zv]㠱/yч%_X$ " ЅċcO:!S1cd]ÊӖۧxdH;gn⇧mT-noqhqѺ_3Gcys ٱ+|c͝}PЌÐ{Mᮒv5HG2(^Լgm'e'&%%ՅrO.\c9fe=KS8`@ժU8ģ[?vtzXb}-VF63co3mu7EӚ{*x81Wݾhb g,rDN1'I+^ !; 7vł0rFюΈ󆭁;qGВ)Dӳ9 8ȡG>g# wܐ5kD1EӶ1:(mp*|xn47gޢ3s[! Nkk+_y^Ɏk19Ӫү~A]c΋UD[r.^\4쭂GO\َHe,U4MU挎\QѮɽlpǟiǜ>ID ϻ*fgEŒu-*_ZX_qѾu׭6VLji\7&+,DKl+Z<#wMWξ56&iZî眓Y4%ScхÌwq6%IDATi36KI.. %^t8wqR/2*/)0q/˼bNc16n[|c絑ᵿ/fL {`_x79[җ?2Ȕ~6lذ|y?^{g-Ȟu]t%/<?hIg"9_,~ݷtYöl" z~rr&?Y԰Na]] qpWژϑsʞ00ZxE-68ucuu臯N6yQhK,V;cĖ;Hƻ6o/m|#gVީ bŊvŒ-S;zsۡr+_p44a9/2IzFbI} y%ߝpi<٧Ogvܓ#k;nw:_/?UXxGtꅶ'^y~3isr<2K.oG? 2dph;"2"cYƎփڹah(/sUU!,~UESL[œ+23f oFWmP*hc۹qbWт׍KZ6xF|={Ɠ5]8ES1cd˟12rqoqN,Šic|X*tvx9thc>ƏߴiSmz vIeO-<)++y&UU l've ;۳wOݚy~t<˖-ԇ 7M7_Rrw"E)EˊO?z拃g,.ڥ+cohJҭG8H[ԌI3~߆r/-obU?7lՃ|#9g}w:>}3:uɸ>}\tᅍ_?Xz173{W\#n#O=ȌHkNicIOs F9ݣdނk##85G>g+~kxq+ ?sv''HnsbRRҿjsE~91O.\:ko6н(_q7.}7)#=Pê;"#^?3H<`ݺuwߕ@$)]d}ċ5 `;ŒƜ<|wY.QtQgeQ^ffRk)f+6n83_|OOD>곟}Nnc{/{lHv}Dm #RHh{}Q#;~_}{{~__:}\W/zwLJ~hGkK+^~闷|eذ@7l„>vHiwSӧO G>hNDH@"@$D$|Ʌ .]W^Ht}AvaY'0jTΑHtU>ߝ^ t'ׯX"#?{%''4zcy˖-m ۼy}##>h555ݲegȡG^=@wчx֏?^{wc~qxq﯋$]Ht"#O=ȌHw=/G06jnqK40^ӮwsMn4ѣǠ KyB;GE$%%ͼDDիףzGU[[<ģ[?;xļErE5 7GlyEqiOG k}+^*- 3>pł0rFю͟]|G5oK.WȡGƋ{f{]w~?8*''t3"Q>}|nz/tAiCUY[s"[s-x* <:=UYഃvN:ѥOӾ_ k~=)nX9WEؑۑ;={Ѱ =q;~XʆdLШ2fbן3:sEEz^&N~,|kdgSѣ]zAEs|Zԑn/ X0oE|ZK+B|_ɔQ n5;c̴ƜxL^9w7,Nգ /2H?{Aձ\;튉/8\DMX0dJ)e^1]5잒tłfL΍QB2[ ;esǹ~JDSӧ#H}a_zw"+/rĠ#Z;%-k``A45ˣ'6g֨Dn#Ӈ_6ra7#wxhJrqQm,Ƚ&:}k48mLҴQsK+ωA.L+M1Wh>1pG7-GF J _3 _xYh8+寴1젌ϑsʞ00Z[323Ԕ2Hw(l\yb%SGlݢ)Ic9.\1BoLl Q fi dc#gAƖR*_^5ms.ʋ%c&s2幣m=*gKbAG_MӥKE&IhW,龎? " Ѕ Rvɐqt44v\־_?2[ZYyĹ3r\=#79WlyV,BYۧ*+˪B6z16W^=0rӖrє&6xX_Ey#4nvehqYO6<~#S1cd˟12rqmXv5oIDAT3ThCDMW5:s@Iuuu-`}md'%^nm~旔HJѲS^bє[] p'?=⋃_ӎ|{w]btJ\0監uyvm{[Qo\VnoSG{t'Hv H$@WrehFYGEyI}֛ظa8/x>2%߯+РgKzӍO= /,+<>y 4lP`wVxqQسWU/+[%OHݸ]w?̖͛EϞ 4'" <ȟ>?׿7Og?{~S\Q/@sz<_{{OGBKE>.Ҋ_m_6,|n.0OwZ>"yqKkkC'>)ukto>>z鑢W^Vַo@ԧo =䏿 ^_0>_>`{"ż;瞗wߍ|@~h ~:_LI3@ tήg.{o/qU<%{D%" ~OO7|+))GS<VH&3G@7壎Ɵ}kZ'"ٵ\xw+}< |3#Q99Vʩ#s>_~zz}C ЍHvUk֬=cܙK{M?irrrD$IMZgwvHvI}EE˿' qH?wÏМdxqKzD$w{:^x `'. |<'|D$xѻwrD$xqQG#zwxQ2|*|ΡCv)<_|`у9ċ֬YjU#"߾K- vD$cċ_?8͉HvIN$999R,|꩛ny9x}MS?{9 3s;""U{1.wVnuuu؃~::3)sO;pF44z7\|©D$={,y!'\|ɥgK{eg =3;pС=Ca?C;䌬[ Ng8p;vufw_=春˖O1dᑰEϷrlsEH#mMՊQ>f͚dfffqJHvm1^rmť:nE[JSƞCѪrY'~C&,^uQǦնlpȧ'nu׿UjjjuIuuu-`}mdާ~Q׭ 4ow/s?^{-" jw>vN 9 04,vԒ3... +M°%\|iNcYgi@קo H&/| M]'監\رh_OݐNJXVr7Ӿ.5zlذa3>[x]=֭K^x~/~>5Iv!lZᷔi:!w:sܿ1‹x_~^:vzzet:bI'=𤬬?TU*Iۛn}Mݽ͟xS`;"xz+hū. >)>%꤬xQ^^hNDO5ohgKϗ|Txo͚@s"UxoJJ9I^|qiH?М$*yd^[>"yq.ˑW^rN 4'" ]OMMM hNDy0:~h "%+.|$lCDK_Ǒ"# ?@s"]ť.իWd֮}Vz31v̷7hmpYg8M 6` 6`9gϞoJ~Gþn3ռ{N@m.{y򺺺fJJ;OFzz`zjjjE޽>agUzE=YIv/Z}6t2{/_6tc zQ aTz6n8Gf|/h$ l޼Z#l7< _$>};6Hv=\jիW)6l,~OwoiiS_r6;KxϟG|.#=͛#^{},H=ť˞[|x? KHv;7n*_,^<~D>}"Ŗ-[}.%"|=ns؃O;|-[v糟l;o߾ׯWVV/Xv!]$`O:0 :"'/֯W`ױ6I|:"o󿥏SFL裏dqӦx#@=i!Z{Zկ{Q@!"Igp־C4_vә4D$^y.7OGe}=G_oZu&#rAC~霍c>n=Y˪;4-l|/ t"qV M[<^\;H{=ps^&ssS?]S{`\_۹_~ȡ0'7/hnr\kߟkG[K|l 7GM~5RL߰<7ާ!^~>DgXcR&i3\DD$޽rpLlKqﯺciҽϯmM|幥#;i~eϽYK?vyw y"1[ly}S'ѓWs:iWL]6m*ۆCb]ws[|`OE{ywHq?SFOƍ<@6M;05{ӱ~9d!d5')BCQm&iֶ%m+oۭE'ٶkVB-I:$( 9V9 3~]/uy^>We:W_&vݺk~9sFfoߞ?m|޹ GdqӦ˖HP؎w]Rb(QDʔ.V輆/U~r'\Q""sUm^}ml XO,kFxfʕ"@V$ڳG Hr+VUCue|&'II m"3^zg͚do&䜒%KRR*USKQZrYʕꇓ'|^fM8"*WNJLHHIIiڤM "I7= qV\pH|q}`A}y"㵱c=7ᆿugLLLrǓO=}e[pQdNx\tх뱊+ Xߵ͛7|b6l9N(dO?t/eGa֭x4Ylܸiڵ߮^hy#N(YtFư#9G礓NO!~K~uٴiӣ%K5ɵ%UK 9u-tySG?̗ 4l|syVWdRK.bz!!>]6ż/nr D+Ǎ?n곯~IxtDdfÆ t>m"OŚk,Yáپ}똙ըV\%K\?2s7Eu;juWnWxG=6̔3#\Ҭ]?sҴczjݺ  m?e˖IL5{vvN ʗo׶Md\شIEozCr)Z?3噲FM6u%9}/^umv{ը pygG7{v{ ̗Zl-c۶m1 qQBm޼o=ZQ GiO_.Xs ֿ }aJ)Dc?6yo~AD2_ޭkLLL?P{믿11+ZH]ϻˮ,Z{%Ɛ=i=t>v,:I0T~@'"/zˎ}>Pyml8qUp-D3f~78 /-cJ'zw# YZr>ӓYײcK)n7d~uk[j֬;uҺm+Ve̙Ѣƹ5tܢ¸>)bNI)gPUzϹ}UUbgZfM揩|Îuw~`}G!s? ˇVKI6ty8ZjE>k"UŇ=|2xvJ.]?ӟ~Zrհ##w'읯geU':&6褤UmrQ'3& VRp5Q҇ (ȷOMU E67l0"#R׬Qc{ԡC;5k̚5;{ccc+Vxq}6g;wTڝLF&'%3}޽Of&#:Sޚ),r+Vp }8$]<"vrѢ 'UO9Yi74a=4o,5zy@'|أňGFFNk׮MLHHIIiڤM`t*WN8aB]C޶qE+^,䊤Ȥ};Yzbdjɉ |ؘ oP:1Y;pϦz,hދf77?ŶIay NxhyE+~=ZB|ܭ={DW |t|vgާU Jh)װ{!:l~s!dzd?mB˖[pTs=}B?=5ꠟpv8Z~)_><Rd_taú!YtG_~?|݌Y&sI'd႐gTrU"ЙC]5%=+EG>NC?| |4eʠ?9Cn?@3w޼Ή'=oC7O=ީ[9}C?HѶM맟|"@wSǕ<1G.щ'xE˖~y颯?dί^yBQBh1p̛1/ZTxr9{l:j APT(~o]A{Ԫub?f\84?O; ; [D$ +ݜ=ӗ^rʕ;!gծ]+ZňO[S N` D7{vK,e˖ILLևnؿgLjK0PdF$ԩ JDPfQ/CN۸ie"#pv]h1߮6 O}2ZԯWl,WLgy㏏n۷_U˖o۶-G!<)oOYHQDK_ ?XtFư#9GD2q//jx￟3gN]|ժEu߮ӮÑ5)>lMt/~G#F_>@ҽ[טH1C6$(䧋ޑ77{}$]mDN;,Y2@>w$;my@b`z<y3n;˼iVW wTRb֭{#@-=}|7{̔~ ᰩzT Yf;ޱuBw;`D$ ˷k&2.ld pIDATsLBиQ?h=aml;gjwGn{ڔkׯNUO ~<)6h-fΜ-5kֈw-z|ͷm{Fۙw|ܞ|bH# x0I޸ F--a~ӧψ ?_xmkϿZk}g7<;KV̞<{{3{H9?|!;m-v 9?>R\)^?׮M8񵉭nڪi]ܚ8-DwM]O+>yO"D#?SQ%O(-}o}7ގn{r ']xAӐM֭eJTVhjժQbbjp~x?EF8z)rgw~[鬳Όk֮ Ng' 2B+Yhaw!;4N*[6)h9CGF^&Z-[&dSLllزekr変&t5gy_~I>|q8hXXK>|iVH(Z)*/Yɍ7t;cy \sRٲ7t?v(kFq;vRt|vgާUڶ9bؔɓ.'̊O>9Q5iCx?צ^@eeUNʗ&:3^;S|/RwqT r)=2pfSN8omfcμhfԺg.1Qu]6#ï?;}G_׼GNǷ~)R\3tQUϚqCB53 G/CXhɌi.WwKGg2N(D$ 6-], UY~?>h_}0Zԯ_xq1r׻>3'R(Q旄#gɼP]'~ؐ@\XW33&;#/02t ᗍB3kl3jo]WӛaT8uYgTBF}|cbF;]7pu~3c?==7;~첌fܔ֡chݩc%K#'㍻N$^Y5/u}?'w%I38h_/請C/fgv !5f#guqړ;JҭGN?R3.9^rX&֞=9hde}(pJ(+lR IrU÷WG ?#)=XuaCk>LOR&\&d&̳DHNq|d7μ|d̥3tQ/عvvz =sr?\"6lxi^?_fMȇlٲo?loǮJE\gR҇F7|bH'v"n95dgv͎5/\XVߍ;B}(w c&]~h͎;?nt;5^W`厣c77o)|yd챷IFdnSRyOrjr'ч?zwO9s?]дI8[Bvys}fkm7V7F>OkoVKe߱vzkjBƐw_DG\WR;syɼY_^ae7=(D$9:׫y| N;Zɴ+_y'O_O[rp)rgw~[8پl36tq{/׬p3MS}?ܰc>}=PЈHrt$%&D…ꫵk׮^G\"EwxbR%KEjSOY~}93E^͛7傑_lqR=ڶIXmǏ~mN1Ȼ4oka#F.],W#F=m*4}Y%K qd6""TrRd75:IFiiirUmDƥ͛#Yߛ8qM6C.3=wd Ge:/K5ol %$KϿY5uV%''V#.ٴi}7 q;~@""YT(_]ccbڵl&3.~o)fMG\rUtdɒUNO>Br~l"]nڵ~6g/M`֭ PPH.1,ng%zs^HPXh-{4Lґqj֯|';lrժh_|°a  \\F ϽMԺ'vw ʹ2(t|f'm)V plqY(.첑/ܤqc Ig^=:ZtֵD8l ,"ʕI)*/M5kVXϩ_?ޟxe-qFƎ ̨^~Yf/Yo 9dɒTTJԿgT dqӦ˖򭴴hrƍyS+WNzz8$S>ݾ\ nyرwp_3&&&PHB~~hqg-Z4@nٰaçIK[yɟ~נ۷#b֭x䟯6?O?u5Cmܸ?o۶mN:)) qi")S&Z,Z(䎺M;6m´M|?Ec ?^˦M,Y5IW%.ZR9߭n [::1Gf\a3W"[ZtGbm$'Wk֮]dIBBB\1] o:f#k5Dr(rA%#׏+~ŨAMw>!>n:!TKrz!?)[LbXٳI}q7]=!CnL e#M:u(D$!iղe磏m۶-@yh}F3z>3AU?/O%Z`=(D$!ޭkLLL?GՌ+$ מ!-451@!7HoxEpwy]{Y![tFư#9GD[oюoG !-75CR;&jpx*-rrqG1fC~ûBD!zuؒ>'dA}< 1,w]F6%w2%OD~3shQ:nER a\hIWG{I|`>J*1D3| )¥Bڶ 6 [ŋeʔn{)tSOgȩ]NV;g4V.ruqơhZx(^i6Ψ[xWv IDAT(QnU\?͝3g~wsr߳o(~ӓ.!w]F@#kd8-IKK5ϭUO ի6 1$WOQhѳ;{Y( ؘ%9+11[ZpQdsÆ C_x!2"ubŶnЮᾉ4N7mU.utFcM/}07niW62zKxOpנWV1wVؐ|\/fŠ")ҋMߟ#s/)>n$7}+q}ϕ{UŻM|hFhGLoUrGq3TY ګ_vad{O\S`x\i0/kVŷkmܹb͖(BF賭[>Qye|?ܔ" ʙﺦՊgu +7=nٸqE/rERddRR>[BV=1cRIzLlL7oYpQ|h@W+VIHB>V>p=nϳ > ‘Uɓ1]hgSΈT;xp:پVgݦ.Iyݎs;Cn:Gq3gmtAC!8{=ӣ?WuO!]ӓ{uF#tŮW^F!d/{5h%cqF7W9n6meե֭ԯü/n|5gձuɧU95>>>UN_jUgW GɂvˁG>NC?| |4eʠ?ٰaC.]Oy +W 122ywB*[l\=>zXΞ=6͸AJL!/ymWvOx[-{OVaw6ثA|dt!<_7ȳ:sт/37G]m2]^;ݺ^A&9PB?s~8z͘-*V<9c=NWmqqq נeMK-ho' td%KF7GI> gbwaKj&- . C4WLJJAWH>Z/i2^Uѡ(␄BrӺd/Kx\)EZ7֞=9>g!C)<{f(39zmyE[FiʇJ*r,^]M< }>sгWԮ]+ZňO[S N` D7{v{C /6pǽ6D7~çZ3FN޾!/়B-oKр<ЦCG!ܹdʠ{z͸A8%Ho…ѺvZo! 7+Z^"dS>|ko\r{Ѣ~z']$PLgy:)?Cd޾_!n#tV5z…K. @nh$}3IΝ@F%J;&ضm[HZw%f_|Fjbݷ듹n3)>lMK.{`6bd/~G#F_>7HBhfЀ!?@ " Er;9xm/,6ze!^fŊѸQ?h=aml;g꜐668.}Gʹ D3g(jTnjjXfM |:gEΩh"߯~8}z ?_xmkϿZk}g7<;KV̞<{{3{H9?|!;2SEe58G+y$H~w8lڄi)ERGֲˢ 'PxNZf25^ %?|߽^}/2B< lZn](StȦڵjEUVlZtGFj!چO۶em +rT%Jl*Yr7B#;/ʖ GJ+ZN|/!cQhQlM1b˖AD}+Z)*s]7}O5lrIeЭۇ~i!n:wW;)YhpP|7a]ݝu_/_)֮]qשcyYWwJ@'"Y$IZuڵ;cCૅدؘM/ȈVtll5j  rȆ%K-SNK%o9 P@dw}n޼3%%%\BN ͖-[֮[bEo_/~((D$ +W:!RT(_ dK/?qY,]7߄SdS*URJs_zi3U !;n͛#ŜF{4nT^Jf{*V(D$ 6-],1S>ݾ\ nyرwp_3&&&tNz[lY!D$ *I(,+-o 駟 ھ}{8"nGkcSg]3ّ .֮]z>so"Ev=x=݃O%K5ɵ%UK 9u-tySG?̗ 4l|#_ldSIqÚ4n!k$"PX)]&Zlٲeɒ% 럙ըV\%K\?2s7E}ƴeʔ8EP8,Y25{vmڴ}ֿo?${hݭ3S9"ov$F|m۶8z6nx]NѺ9ops8N~Ǽs 8"PM~ym .l-z{ɹhX8z,]1l@B_x1Q%b|p4tC3g͛$:|۷wܥ4IDATuv+Vp͚#"Yq|hjC,[4urFJ+۶m3@""YT(_]6qa&3(St{^cE8R&QhrAUJBJ!˒CHv3j-@R Wlhq##[u^vmbBBJJJ&M.E ʕ&Nнkc9&@~ igYܩ۹ռ4ի*VX(6o޲p =Ѐ-hyWX 7I(J>l;>JyXv3>mis(~)_><bچBSN}Ȫ\VE̯zvp,lAxdÿ1[?rL#36lܥi3(t,\V\5lx PB?s~ȾhތyѢbœC~v֩Smz7x=...:ؠAP(H.7mZlYdD-k׊=ÀERR1n[k4-Zԭ ;6hu/ 8 hy=)>7ۯ-W\ȞJNmգ}ߐmO}2ZԯWw=)Sg:N?ټoW[{4]$8 ]|ժEu߮ӮÑ5)>lM /~?Z1b((VߛP4ozGs4mꊖ 5-UTغu$GGFG=휩sB.Gn{ڔkׯNXO ~<\6h-fΜ ~ӧψ ?_xmkϿZk}g7<;KV̞<{{3{H9?|ɡjpN7Əi+WBFD鍱߽^}/2B;^x /h :3ZY6yՒˆ82R]}U@6GqߗF׿Ieˆ#-'Z_-\-ʔ. Io>wΧ6 椲eoÉ?N?P|ɬhQ@'O.\*/߮mꍱ11 /9:u3k֎d:u@!#"Y$ wS'|6gN(Qĥ/ $@iii:v֝:v(Yd(dD$Yj5vvH]|P @gR҇F7|bH'GeUNM.I@X~>pGo32o iR"M.[|(mW^yɓ|>w_^&)R>PXHO>Ȃ<_߿_tn#D$򴴴w શm"@'" w͛?f3Ԯ~Y;\|ZS"yڵl&3.~oLLL@D wŋD={Ee"y/xaذh}Ӎ(,]6ő">.r$@^4x۶mU D$Fݻu-QDIDpP|7 Zf͊+9뇜#F'F^ȓ*WNJLHHIIiڤMd----ZV~V8 ۷o{ ȷ)2R'C.XŊh Y~}83=+VhW:w̏~)_>jK?ɈGGDf6lйKf._wX@{l)gF%Yfn紥K?6hЩVޭk@rWѢ1%,]\j؈λW-[&1qG,r!ng KF^䅳;;3T_-X-N(Y29ADpٸie"cUZl-c۶mΩa_0lXm^|Ł|TRG?c(Mhh}R2 "yQn]cbb">w:w'ʤjI71oT~@A֡cbŊ [{j9"yQ||}>Ŭꛮ>1!W,Z-ۓNI)s\=)Kg)}v~w[uF@q':. _meǖǗ:>Rlݺqo V]smoW@NȣnuK͚5u]ZmbŊz͚j[cef3^[Z>M{.:uԩ {&׉|K7{=WwSw^YIz=vO#6+j?4pn!r;}}ux^y8q|`ըV9sf`ϳM? D$ŋ{2eJG7ǽF]v?-bbcNyjChȰ;fsY>I%nLj:9 =jqh"#PX- xt\5u+=W7*uA԰ovDpXM^j%Uc6-^ECxzE5֌i+W׿1~q 5kF۴iU<W%&&zyV .lnذa /DFYƬٳpnrETmGq) G%M^['ehh{dޡEf̆ys~TrZ>u˛YX=sbhJ|q}R.|)eg5, ?f\߆CMc~yPQh1őcj֬1k~VFٻx)rg 69rTr.yZI'L޵kȦcJsժ'yM\Z'OuIW4>"&/ ol^i0|LV6͋ӋG~Ų#ZZt}ӏlKO]S[4F9mg]}{`,= \gy_~o bK.{`6bd HuK;>J,e;ƌa1 Aé|n"NS$%ez袝_322ySh篞LִRt1]*#n\o ǥR Yw}hֳ#}r2x"}@AtU6#G 2yE^\`mSN}qΛW9bE:.))9LJL_zCd,ҝŔdþۧfb\=[7[\>onr.Ѿҁ/}a=FMvƪ^vXR|NmnAҨ}.޺CC79%BCPO;!,lAhۦO>]$ ˷k&2.l$Q{5IDAT5YLWzƌ#[4u}LHO>9oT艩e22&>όpA^:2L7,xUFf-*t>[z۷_~W>W]r6Gw`2ChjkV]+/ן]$ +W 122ywB [{Rfhݻ]>~@'3'Όn>ĐҥO d.M.[xÞ_6a㧼5__X\}I O~|IdL?y97MID`JLLx7%K"]/EƟc|H"w}@Kg@N6@UߟnYgߗ_8dHdN:x7k&M/?;7Vs͛$@? Iie_)⮾M H$PH.ʗo6}ؘp4_7) ,z>U*U;욍; "KllLB|\8~ǻ{۶m!X)S-*|rr +W 122ywB)[LbXٳ)viӦHq'=73'R(Q 'HB!ҽ[טH1w'EN-Ͻܐ-Z/D ,--CNѺS%K 2 qW_&sD$Ѻo&XO?ֿ,3OJ>vZ>Z^ٶ|`,^](ZymlܴrժkՑBw!"P떚5kDNnnŊr䏦DK_Y8cC w[:j^yQU0˳rpsw|Lf̜ ԟ'R!"P/^|ϗ)S:97jҵO=gQiii 0/g!))9䤤pX.,Ѭ4ٰfHK[ G_=^7Y6:s?]дIrN2 罹^ު…"6l k֨1k9-vrVܳiR% ;4 Ǐ׷ayF3Ŋ+/U:@ΩQ)R>(]$0\9i ݻv pDS,|j%Us>zrՓBV,Z-%HJ}.ݼE=Z11}?>OR%@nڲyKZ}WJ̎䮣ϸn9 |e#7L'H=V^7jѨu>ʇję|IǼ9ynLD\wyҨ\勖xtDdcuzכ ~_kqfTd_"s^%/~j]:@NȢw^E}Ngl|1ff|cx~]S5z(]Sjr$@dqH߇'_XM^zBwQVW/_^26wNbr$@ӒyDŽxmIBսcK^8Ad=M$ HdɾHxYZo~NoDw9a_"8P-Y#c؈#" pv4LL_khXw;;ꍾ!dvD-%" %|Rmn kms3j^JG9ӺGxcdzYuo~ݽS9x0P|m"ElLL!?o ٹx?d6@6ʐ8D$ 6-],T~U~xmrԒ˶nRrR 7H㎻M/,8J9g˖-O`*\9)dHg@N+Hrܦ~>Hre_MHQ/ĉf^t7|7rϮ.oqY%9㎫<# ;@8DS>ݾ\ ۷o_)S<*UzbH:9*F#k׮ & ml+;a?w R>rokrEw_6o!'T6ZY&t_<6mr/eӦMn.}ǚ5kT\9jՐmٲeWf͚ȣ[~۶mL;c=6pʝtRXvmȰd/qqW_&CD$acf>>S+V BœVK7mt}I~2|"EȆ燾qn|C\\ܸcw|m#^ H.ʗo׶Md\شIiѺvZ bŊ_5jD7w֭ %66&!>.2*T(lz}_uH(穧-?B#CJ(.\47Y3浱_]z꩕CP-9%^yuLx6o8<}"Y5shQ~_t'~ذ.[ǟS~4"9cȖ|dAvfnO8k%K~7*Y)*UR9/ժDD Ң9svDBV)n_.Xnyرwp_3&&&qEʕ;!'+Sy@Ѣ^JJ(LjתUh;sժUޙyO?t/e<֭[?7h'G~ŋ P"Ylܴie<줓Nqڶ߮̌'h!OJ)rr'rժ[Ν;F'sa_]6mf%uMr*qIՒQݺ|`ũS~d 6>n>#"YA"R VZ)f͞}I00ZڳGȾ۷Zjѿ/Jd钑WQF 9`ӏ"r}B||ݺuG\f»ɅWsh?80 mCRlYg̈d:1Uvh1kQ^7.Z_}Cw{hݭ3S)[l޴iS]Gì?_f"j2ZǶm҆ P\r]>"4G͛vߣupϐV|z7ugsD%J\$9ݻu?}m۶]smuGU/P43U߮^}mN۷o {믿11+Z4?.hGPZZZuJ,0<'>>[vtۯ/a#FFǮn}҇F#E Ob`{́#nkc-Ϗ3zI)dM\s5bƌ|MXj5vvH]|$EfѺS.۶[bE -],:S>nsw7ӹ 1W"));F^9-!^oHŽisAFc5hh!gD^]"#ku.3א+DǸΈy̙3EskdqغU]&==>ɋaiآ]X|󣓲phUbgZόw?ĐҥO UK.{`#axÞLqoQ;~ݟ|O?,˖,Y2m.;o^t _ajS*eC3vV1o5x-~ŠhD)S35c~pӴAѽW6b[=>h׻ԩ#Oq ڶ<2~p:ZEo=Wܵ39WVT>GZY?o?X{ϫ_!]CCZ4N чv2zˎd|Ti iiiѢ5p=ƇvOm6AbI431( $-zygG봴ܱ~7ƏoD>p㚵k7M(| OJLLx?5V.\ܰa^H]FYgrwO/Zh]N||ҍ5zaj-!CkHy_u⠻N CkEVn- ~/מ6mK(Qn%S;gDnd7nqqg]y]%vKF6o[o2zLٌi:wK(^iF}瘩wf C_J4|.w 52f'΍\\݌cz,5=?ҥK[.~;sS=ԢQB C.Ij:yA{tcϨ{ƔD?GdrA5fۡH"w}(t,\*/߮mȸP7r変&t5P{WOś\FÊY5ҷCj%–iBF2%ckO۷/_)S<sKiwq/|N*[6严cw%5٪bؒ8%_O5dix׃3ݥ[o+k)z0!z=+UK\ d<>ZPRnaާ~8:|$d*K;>J@ݰow1Vܳ[o.q.'wzЅ$w;W!_.X‹l޼yExCs>?0G;f.~K$DC, =htCMvU-:j?)AG0dﯾs%|oyQz3;rjC^4㛽>ݔ>|h{=o_}Ẃ#媶mF6e. @!fmN9w\:tB[py7 CHeN=?1ncx_%٨Z!dNNS(^n!;ҢȠvjUa>lٲtf~G׭[m۶&ʱw\"#L=V \b{HBʠbLUN+ dzrPJ9sKlϸAѣY_|o{?%lڴҥOXfʕ+'WI*\*RCWEIDATd~ճrnII]yߩ㨤8`#SZ{cII| Z<2wr.GNah1i-cet;+fЊMb~X;ۊ/\͛~ۭMF|u}pMc! =cnZ'W;};zE(̇h3ڭsƕ v]_;KV7u3󑑇9mGګ%r>2B b?:[O5|>)dKasn]S-Փp;š+I#dHBJ +biQKO!,rLs Zv.o9fM+e_ p/7eVrJ\\ܸcw|m#^ eGsAK+vyO۽'^yYw?;w-edFtFȥ+tC2nV 5#燾qn|+VvhdRaӓXVϸp5t_}ҴhR7R{*`n}c2j=ʕI)*/M{->>xp(V؆> -gۧ<)eY)m۶̞=;RWi!9~7o>f:d{Es$>n\˕6{Xr¸>)0=#b)7 o v#?)׫o({⥗57vL]tGFj(p+yb]$ 6-],2VZk&:-CJ(.\4M,y}|dllz*.j"źoi૟7gQ7iGNy{ʳ<tR<SB|\`wՒ_W;ym͛&eS+p+V6UzMCgTj?wjB[y3n;张iVW ^"}$qNb̙,ArPFG=휩sB޳Ǎȵ)׮_>YO ~<AHp眳#痖2iiiB.߯~8}Hֻϯո}vóQbɊٓgxo{39A"9,HJ(XjתUhm۶ZjsL8$ϷWGz)uo}7ގn{N8矻Ȳ6φ]Ɩ;HuֹsOfE\mxqQwRٲ!kuEˉGG.?[lY`_*TrժH1k5jY;"+7нS LʖmwU5kz-Ylj!"9 BUvO?,R̚5uj2{ˌH֭S';S؝8+Z^- ؏6|xG.K۵M_16&&dY/>Zvk;t7vL"E۶m5vXn}NZ. =H.1 qQBeŊ{xzv{͛7v'}a>"E pt" @4nHؠASv )Λݼǟm`ڳG HU|3"y7W^z^s48N%J̤?c咽T쯚_Rʘ_/_ݬ[)*r$>˷M׬yv UN=5J*"Sd˗O6=vʜ.I ?-/D$rRbSO]WHYgMjV_-\8R./\x|dڵ6ihܹѢ\r!,]6ő">.r$>s1nrN?"ER._DҥOP@}ɬhQy$~թ]fs>K- M'WʩIguWnz}~7&&&@^""I޻K瞽Ia_0lX?GgH ?m۶H\_K-Yl##E|\W IѣEn]K( $VYbŊh}N`ޯ~C>Æu|HDpP|7ĄlJKKի ,\bcc!Y~}83- $ʔ)--\\ׇ|%HJ ? PBXv%Ka"dUٲeٳa"ʕ;!d_-?}l۶m*eMK-VޭkLLL?@^U<@zK{}?JvW [{4]$ɞ[{RfhݩsmۭX"W6H)Hc^ ~ok1f~yV{H?1gʞ_%P"dOŇ=|2xvJ.]?ӟ~YȦ/OzOOO=2U\:FN>uph-ʜ9!=/wN?1wf#V3.5V-sS;>iE秾TeODlKLLx?5V.\ܰa^H]FYgC׹UAcjNߜ-!CkHyCkeNuQnS_ZK.2Z]IPNltOeǗ*vSڵkRRR6irA&JIEI'L޵kY4ow+Mv}Ka{>xnMKlIhr)[wu} A)SDNu 6o޲p =Ѐ-IDAThyWXȓD$9DK;>JpX6NI)r׊Or+BFmv]ub){}W6H`h1$:@zwjap,]1l@ᰜr)=2^ޯ~vlO~ь^1]R3ϞkȮ.ERv6vf;t{qzM*v>uꎑ]O輤[]ObX:Cg, s=:uj_նCE4_Kt,\*/߮mHW62:=8Q팔dE 9rŠ" 7L"2tPJ=t3:;.w瘩EJ̶:] SsϝĶpfnե&&&%66&!>.a9y!K3o\SLgy:)?Cd޾_Bp~_R\D$ 6-],YYg-֬]D$p}pQ(StȦ[{4I8\|2+ZT<@ " @ns;"#fH֩S'7Hay7ugsD%J\@ " .--CNѺS%K "pVZu͵]:RW(_?9dߒˆ82R]}U@)ϳM?O>1ty.UׯGNwޙ>}F=tA&DDpP|7Ąr+s>WY "E٧cD$ ؘC|;/ׯYgٯ/@#"ɡHKK}M ڶK7U"dۼ/n>>@ "I]m2]KD$ +W:v/IȾ{YxIܳW<@#"YlܴieP 7H,Ia'm)V [{4IѣEn]K( $VYbŊh}N \oi9s(HEbc c9a0oFc2r\aDC$4~$]tpWwݯ}co/PaD$Q^IIIrۡKFD啚*mm555*$+''W.$6.~/Rajb2b( IPu:140)>ʈƱa#ƈZ)/*.EWWD%᧦Z|ʩ;}kg[PtDͻ|JX=˘7h&b~&ŌE7N.͟&5 )hX|kW,qژ ")kEw2ӥqqk>){6Tc7X̲=8=`1n_w^1,o2=V_A%6k8bfؒI,>垟]ک/Eɂ|=jI8EǚH|;3C0`"Iʂ@SW<+Ͼb# o8,tlbSEyaOO6O+{Ɛ.j6pw .Ud!GZP8ID$Krr4yH0M=~'s)_IRj)}ڷ?W,}E6^^ڵ]| ZHc+E/NIͧL\"^VV\|4SRV~,2oA}W Qr22lN'~mʘoŢPۜڼo㾱 Ⱦҷ{,iW4-,EKɏ6c]Ӿќ6KO:7|t;)EKKr_\[Zrm<Ɛ18}E*f( ~SGdž rm]<-W2F(yiTPf&3y D S=ȶ%|̷a͏&^>&>&7<~Swt|?w,q{<"1WFo߶defP){ 435)f[o 0è/x^Fk-|{׏>=E8y1:FX j "q.,Hѻ`AQaN]֞ xE5yش :+K\jܸQ~f(5ES+++wuKFFP"ju^VySOOՋ/hahмy3bvRňi&777ݻ9 rTT"#"j!, Y}}ihi~OySƍ=TLJNCIbh`5Lzneի6XQ^=z@!"^tuuUu4"ez$88,,<6.ƍByZjʩkXRrqĉ"_*k^]{ ED$Qq&3S--ڶrԩ L%?)v-Nd<[oa޿?ڵhi:l_oMOzlQA/\<~/Qqߟ5{NWU]>~.N΅Jw/+5-[ yGsA;.[n["^S C>+lfˢgߗ ]]]QAw}_O>#o덚1ʪI+ k <u>*&2&h{БGQQ=znǡC*tظK0O˗_vkCjҬYurww9~Lff Ϝ]bz/*P.Rbccnn7[i/4U@O_O4=$`Mi+fIoOx޾J8PW,GwrommQtwh/W_WG~$f͋/ZN4QN`mWӦMcaZlڼew`\x*G1Ǔ?65l*YYYOa֜11rEtrܖ;ʛ3>Uژ̜-i> DD&_&''GTO?\o7i>Q fIDATQ?o$B4jh ˛/\$P'DL4QGGG*] Qv~T,ںHS߮t8z\nl֭^NW[X[L]4UṮKؑa1 f~=Sedd~D$Q3r\hV_DUڱs\tiDԄQGEh7n`r1i?'*ƢŮ%D!%'m[F Ç~D$Q13gLq'x JLLUٳraiEop(D\(BUsy%-UV:uLhPYRS \k EGWri'$lvpޜ ɥ\@FDiS&M={L8y_ *))I.lٖ¼csNªE)g<}DSSc'YON6emaa%cF!KOO$D' cQ[5I|Tظ+VJ_GKdnnvȡ᯿.mfffn޲ERmkc7YQ .\:t݊(Ua2ⱝx,LFjgR&rbbbi?J ^YYijз`%4vd|?=aw hE(a _!pV^~{옖-[ P:H2N=k9޽{*a*/iaaUbK'C&̝,~u]Qrrr~|o +1O]E~i..(QVV ~%_,m%_DIbh`5S*tuճGX /:r$Dh`<2ba^0xk9aH'ΰ7x٢R HOzGI뀒QHW^XӮHO~Sh$iPⵊ)sb׽xIcfj"GSSӦCi;F(e6))Rqۊu!J.Vqcܽ{ҥQQ<滵S&MZb9]":"Z<ң'˩> @<#33sgN'6T\\>{YԜH02j!~; |61ɏ~fͷk@chH͸sCT /&Ŷ=r}[((;")~8egI.j0"y;vR\\;ۋܭۉݜ͊@Ҵiss3~i+V?9Kޜ *0"ٹsg<~wP&"!/]NCŮn&5arѱEU6kD74lP|"9nnriŦQiG!KMO䁓Q mkkkj~wtD$K9֔~}suɟ,^O_b4G]^xK~~[&O#gG<('w'##*Gf͹#cPK "^*ͱԫW3˽jy6r9۵7QFFÇn1559}\oXbd@B8xrKMN=lvt640U@iHBpqy)rwXaC.*vU0:㖢~׭ե\={Vummmzy߼qSԜ6ݰHy6LMfNƈkkѢЬWS.{d9ZZZ6u3-Mѵ1xgfڦz3n;zN'(ޮP Du{^O.n߹-*nϮzs?KCT~˦}z JOO&:uڰ:P fG_-mɼ5GCCc9g}$饗EjZXhAOyGT\ ~dfM>-pP%[rѴiQA:rCQM8Qڷm#Q8?o6ohm_PGDulil,V2u䈋jewggQe5m:eҤG6S֕YWLjWk&D_K._0o֭Z0|^[ٹsaraԢV6Kl.j%)/tl+u mԾHKK373ҠAqcHCsIEMZ kٲٳ!DM}s=F I@JNI5z[Dޯ,SAޱd.:eۘ"IJEi\i³b^XK;m(_ܷ9ҮKi}i kg+ZNfqVNj>eʧ""^tuuLMahh jTff}g=.]*jܼy=e *;~\\~cQT,Y8oJa9JNFi?6W羱߿ oz{A2Gw>266ͻ[9ol~;K,ĕu ]P3Ζ.I^=\8:n>r*tiR۴nddd':p3zлC+ZBN~s%ʜmY~*?1FF N.ZX;oڊ֒Kl /7Ʊ+R1+@1_<+::6lTlsldؕY6DeK| @ED5cv7D]q*tME$'N\pz-m  ys̞vu69㞜6Lt˧ħϞrΔZ¼b'%Nv$j4]iiiRn߾-Fxpƍ5m6&ü!j-}zꕝ}jTo޶lЬw?`af&L5{M!tuU hЂ\||y\G9/F(Z"uIr0T]+r>Beڳ4DT^=\QWΙIDAT'g7VƀE;~88޽,W,xUTXS{bAFQ r6Ί/7nԿ_J@@DRzJ%"/׿pM/4v[VVV[hjZ-?_$222ӥ{.PjȉLXuttU޽)fF^xȨE C=U.F^"O>ݜD3359[$P̚37&&V7oy`@UZɵ`mmmQ5חƋ͛cO4oԪm[4Z+[|}T7^aնM==j{>(ƍǎ~TL* " 2}#Vmg'6h믽z035$Pl۾].&OXxP}sPj[rݵK<8H^]; రظ7nkilܪU+] Z6q[ S=@IHIRR\v*ݻMf&/ZZZm#*Sޙt5*JT'"2R;wZgSߝy:::4###C.ڷoP;/\<~/Qqߟ5{NWU]>~.N΅Jw/+5-[PERx SިKkکI&r}-ZT ^}'v鉮Er?\ԯ+*ݻkgM=}Q3FYu2iebam!GDm:4s5*ʹGύ?8}H.U൙W&@FDRH_240ԴX333@-^7[i/4U@O_O4=$`Mi+fIoOx޾/@5P/P4m%4#XjhwׯK΢45/t8z\n+"%99_<$P;Μߎk[~u A UcPJ0FpzX41Hǥ$j8z+H웋8|u]WETq;wEO&LDM5}\q%"^VV\|4SRj3v-hamW3\ ܾgTвvZB^T%Q-^{%vADskNJң'j]'Jy5K>-4Y-ﺒ_[_[-$luusa9 'sa3Wٱ{ǂד,Ti1SGK͎ vwv-Zܼe4^z>B* #ruo=뺢}KQjC&l FM2I;X+yjbh8QZGN,{Uʽ$QYn*thĉsssE5z,gFB<:ힷ:W4Xc'{Ѡݯ'Br'I,qDIkdSl)jixj\yUkIѹEgT*<ޯJ)vx=q`R/{փKXlF7[x׉򳵷.Ȼ.*NOvwVKo^*)7)ioUqkν{iU¢U^2ªĖO ;M[[;Y<:: dg?v-:eW r6DPItj1}˖.~jT^v8Q´fb٠P*8cY Q-ՙ餐XŮ!1oGs/mbb"fͷktJi w&?zFOOOǎU'xD!p~3QBg88h^Y|PA a뷮ډk^Մ"I/FOOp(|UO)`AcP;sY6T$~VBufWAU]zBg\ܡ^݆?|P?xc50kܘy5qy+-)_?i(7;NrQ^T nN $ohVC8K ;%o3ysUeىܢ'B*[/ddžh@ػK%C1Úf[F7ΒݷkڮS~PWl;mp9O/*H7IŮFܨv.-Z(d1Mㆎܹ#m~pѺ@Ibh`5S}\{ N:~s\_v-..N y$o.!H2 #ځvYj? >U_߾"f\WNgb~/Beddj "^tuuLMahh NՅ+Em2~GnH|*`|lHH[TZTE!YJn(_K[KH}\Oup<ʳmvsrE;KIDAT5Gev>MT7G!/݁{@5E뜞 aA[P9WF 幕(]tբ{NkUrQT{whh}n.ݜٳ`ӡßAAR**RDDaƇIIIrۡK9UhjjE%^hϜQ,=ҵю{٩G;vt('161DxyߵhBTDaJU^S.{dP D$uå?O9PR mm55+{^O.n߹-*nϮzs?KCT=nٴOoWQArD__T]Nr"Krr4yH@4l\T=|߿^zB kkk ݑYF 4m[ŋ5m*AGEi&ttuH{YYqH(fKccvlAˊ:er_2͚62i#~M֢>|yjcm ={L<'$HEZZ ;FB '^IKcQLMfNe#" RYm֥cE5QK$@]B(ku>)q<¢nGh oDuk 7n<C: m-;;};k ͛5̓nx+EwD$"`ۯGcnܸ!GOOqVv0;kkRvΖ"Qlo.] 79rKmZzRԨظKɈ$D$5Sޙt5*JT'"2R;wZgSߝy:::@uk֩5T"Ь!99PߟO5Z<|U_ܹ6th+T4]iiiRn߾]WCC6ك7nHt/VVm""^ )VoԥwiԨ\]wO7FeʤP:=Ȏ#ը(=7P!@YZZHzp(9PT/:f&j~xAlljTnno-Gvroq*']_C&`ŴYw'cfjjoYԃ^a.i݁r=>G|(Y$O԰Tgee?A."" W#v}9MTZ'r}5*獛": >ztђ/Psv~T,ںHSu}rݺuuI/Po/jȎ䢧[OV&&>J.BC޸qCn!"^eeK#9%E@]5lP377w üPΞ=+6l:6aQnћ=4kkѢvٳwT$%' 5CDP7? o4D{lا^z\ 5B%99_<$@4hmK/jִ.C܂|krD__H{YYqT)Ǎyw4;&FMs6B=;&Fuz=q ;FܹLMfNe#" @gС /J 5CD:())iqr=n===fHP$=[Rmh`0]?.oG_P?t8_Ou3gB ?k/@o_*LMLF %!" CRrqĉ"_*ihh̛;g"" ?'(ڷ_/-Ibh`5LzP$%%=? ƀ#"^tuuLMZ"ᥗƎyʪuMMM>ó09 -`!" *j֜11ryC FDT+WS% TIr0TKPU}#Vmg'@T/mvU E]wT\<'fb◮X) _?P"TTqʕ-rƴ7+P 5jh ˛/\$Pwt(:&F5m"2U4yD>ztђ/*tu˩J k Z3)[222ꢤ1cn֫%2T/^<ǵLMMgN& -Kݶ}\xsω*ceBcır]#pn)swBQ]ȷS~sK3WqEj%\XJÇwsSRFs-z135fΘnkk#O敘XYRS fSA,cfW4p7Vz|ڵܐk̷_u8`o݊S~2} z,|*9X|'}X~ͻܐom{W&v;˷ vj>qw_. N.ٳuO?owrqIPQZZZ65i/oce7p…JJJ ]6mJ>߿4*__y{E<\M Wr\b{@7(/Ph=_Ձr4 Ae^y|*9Ѩhg}"Ft0.6k1rpu^Fo~sgzEζr,Peddٻwp=ݩii򼧧J%HP`wkע[HCmmlßrf9xcy ,N+#7{XZdh2:( R[Y0eDF$Ən+f[/CU:Nlv[Ye5OD\r?yL?uE9"Fn"Eeo'~KclmmJ}?<}/M^ ys8;;Zns̀f=y}z PXh[ʊj-[Ι=KO?,"2ޱTDGD?8 +!n+}Xz^!E-]ΔܐT0G*[ͧ+-&\XC7 [=闒_w@wU;J-)^pȈ / rΏRy-$-- ˹ 3;-BD]a?^|" u\df܈QQk[?Zbe]$Cĕtǜx|22 (Z>1(]&E~˯… Akb-r-k#W.wǢ]?"YY;{Jym8[%sڵ΢2"CQ@]dfj2s4F !" uJӦM˥hlICѻy`-JQz;`W ˼EKN*qVz/r= rڵo㼥VD }͊յ;#'9KqGV罪_A\J̿c!c?},EH'Jϧ5KTܹ@65nn_}Z*6cpM͒ξ!!% W.ȕV xl]TλF/ ]X֕㯪WXҫ*pS+ *:*&`{P bDޥm1r Ø~+G?7玘+Ǝ(7H@]cjj:s.Yk޲Bɞ9by*G̫IRSg~3] @EEꠙ39s_!P{a톝 >+oG_PG/]R~mWT玞Ɖ'.\,ޮ*$Mf2#66VLm6i|:5Ι=##"^ yJP׵mȡ?g7 PۼԾ}OoJ!"^tuuLMѼYZ9عرcW\!^>xD$0) " """^S C>{ ("^VV\|#" V/]ڽ;_''$ܾ}[(cccSm]wxmjgfj2s(I@5{|͚rrrHɓk|NCzlTӧ8:u[ͷ*,jTT>/'|LPߗ -z(]$uѬY3|Ǝ+ֳא^V^j'jTtDtոg/o\rrr\ѣv~.#"y(I@]EjZZllř3L,׺ t>tP2,-cPo 7rS-444P-Ν -PEӦMca.ǎʒf-m|(gС /J D$52yD>ztђ/P|/nܺMY⼱Eb39ȢcnbDZn+ĴsWY}覘 11'=y}z PXh[ʊ@-[Ι=K|6]*w9Wt[ǺKYQξ!!yk<,;c̝,DY"B#E_H\\>{u< ]|O(wqgG"Zbf&3y 6t( w-x1Dd@Pte7'guEBrP,Hw,P;T###;NraᆲO?uŮU,1ޏOyVaTxsr=d`ډ$ y\lX3enxuҹg;u6칣?8R8O#PT-Qo6VICWIbh`5S*tutTW^yCs. 7=IH]]3S5m6~Ϟ=ƍRS2kaHUNbRT%""" "%99`!040ӻ""^ee :"@M2359[$H:$H:$Pb/&&#{ uKj{Ul'xk15*K+oa#1Hocz140)>]t13=tNkm۴ +'f/Yk[8L>׾"Jgsq4qq6f%nHS @YH]]3Sishc^d;x{8ΘSyq ?5U>|.KhT[(df8$I˧U߁o䭦?(M-l+}͋\ o EDʧdHElmQqJ ґ&r)bm󁊵]);4/rBI"c#O JGDR$'Kg\GrH6bužq g;nRxR:%""^eeK#9%E{@ٶ ykm_Ώ9c,vxz|ƾҌ9鿵>ѝRh @= ?| 6̧S;닝wC d&@̜-FD~a_Y+{_ݜws*iW^PCR=xxz@I(ϠCHm^ڰaCTPx@mmmiؠKjD$INMxgը(QW&ɵ|Zj{ΝudZZ@Uc=A?Ϛ=+R>I-$͚5TDIxȣksW53~{Ҫm[Q=x oUWg|G{Yf"5-M*T/)IA޽ }󭱅Hn~qڶƀط';~\-)طn٤!Z˽xi$i݁r=eҤ}{vי|d1&&&vL8QܹkV_P{E+;;+vv,^(z}dQc &@LMfNe$=ׯ_ ]]ݟ6lԬ?B{aT_w>tڱs\ ׀_ʪ~c{x6D$Ξ=+]tyroF^v"G$C @Ԣ'S }U!`ۯGcnܸ!j^KcVZ9u2`@vJJJ]:5?,JN:5IW""#s׮~6)̟#JTfgg nɅP'v:ij*ޙ)))3Ug͞~*,Ç_sa5'}Ҫ'b◮X) _?PHYfrqej5̳]-Z *AN]]͚%<|0""FT>JTwO7FeʤQu>*&2&h{БGQQ=znǡCjňh޼@T\ƚ T#3Sv ˏH SR",<IȖX)3y}󭱅N.-nD$!o XbڊY135,P F-@жz140)>TRӦMca*0"iY3^vv",e ۴y@#>,cǏ'ljTƍ P ~|uV_uFDRꘙH@@U׫PIII[׾[!PC?rξݴ/ ֺCO~DFEq@3ЅB[[{@Wꄈ$r&O#G.Z@M5zLzzT[m}׷o;kky1rssj=ׯ_ ]E[ijւt8z\n@5JJJ3v\;FOOONH*tp -@uG:v\UBԫW:яfv;vn=MZ㌄|jIDAT+ d[>J.BC޸qCZ$=[Rmh`0j$fΘnkk#O敘(P!ovΌүuD3g<c KJ8{\t) WD{;^Ϙ81>VC[uhS_Gτs~yCx} I"w;!iS&f=v]&L~/\b+\9|DFDFʓݜ>?,;]+oA"󓌤oiL2M\#G>#g!y\FB:3w5Ր? :wkp=_:_7~tkBNo?3N'5qEL\,+~5ĵEC>z !>c4)eUBRR\v- #-p24wy4swy9IjjjvQFFFƞ{|ٜԴ4yCz-ur/+=Tّ׮EKlT؄ T O:~DF=\\?cMI}&l#v/qZ̟ny$GAk^=oGȼr]gmv]7?b|㗹GHmn}TRų+a>맧KJ+е(StP@YT W+%x4.vN?)}- *`cco ys̞@-EP]M8Q.|~}-hퟗxPǢ|"/F)M[6`gɓk3ֱk'nР,YYӦBȫcO@A=*u 8a4]޹Eu-?_n8#;X6.3֘'pnc[҂ƮE貯"ttuK6򑵂i1S$/[ iݪ@ E"2OȋMj1)̅[ĂjTT>/'E555Nq_ mqՊ[`&, -3<0rWENݲ+5ң6y^%DDúydaY~vf{3 <YRg T<|O8r5B@-вe9gIC-]r̘1R1sZ.mu7B+,\7םH0źy:T}!Kl XhbW櫸^V _zuzzFNNΗ+:zخׯ_ 47v4DYdqYӄ]`m356 '3t΄I|EHErM.E]\^b;tӄ}QݻkgM}U۶R,[INI.XEE,]܅%e12 wdN8iV~.~B)B\Z GI>rwIrDX hOgу:CgM뷊ϠKX´ڶпfusnSvnnFOvcVt}Ј$!ZX?>?ߞ(\>dEM[gPk+z󭱅Ha>G3gJ#%rq岏Vt9ļ"0BToY$ &FXu(鑡aM#Zjc0!" A[\k )!G\ow(in'/#H1O(I'N7wڵQU<M*S5 p];>gԣ`}$ɼ\i R ݃vHb_,?&qΌPQy6o(S&Mڷgxfvv\I W+c՞(UtP@0j\ց3n'%ɵ}R(+*p֧jTYlg]N*իvKg銕r, mPw8.ՖΜ~> R'S O/v~ 5󠦦rM@#Boose8a@kYF8ߪ܅ej֪I*8:y`G $=\\wйOz@Ixk<hjjG[[[]޻p[##uuuڰAYHI}Y[KE^s^iV1۱U9|'^\{GLM!Pʪz]Pk/ZۻtJyWޗ+g{// !e.] s˾r9^s(go^C@u!"^ y}\{ (]EٳpAu)xtJwȵ*a] (TϽV}j[Ҧ~׭HK@@Eu횟KJJ($QTŋ=~̙Pvh=ԣS;:w5*161DxyߵhBT#"dnISS3'''%%%;;RLin޺%Uu{v|}ԛ7qXB%=[6mUT/G|!PnfͤÇOu\\Ti -`E͚6*}[ FG!8CCC xsaI#*_WzB4ktʤIǃl6[ B%99`!040ӻ*8~\F Ibh`5S*t+''珝܌|$@U#"^tuuLMڵ-- {HqCwsbD$dgB3YӦQ T۷߱zBiogX\rARq+5[ZIKccLZ@]:IDATOH9}Fz;H>{ uNrUOTI(y_oyS* 뼽n}Z~)V߃EGٹ!E#"yH䔃A6fS呛篓'׮iݪՆ}:wvD$Q^IIIrۡK@vƍv-Z\{9%1359[$+55U.:jjj uxх#_M7(݃V _zuzz\ձcIJ:tCyʅPw ' ^oD>LZZZVmG3:vԹ[7y'g͙+PH1۷oK#ƎyKRLLLwxwdy~@u!" x䧟7^xQ*4557C6mAz,^۵9}GBKP `ۯr1ynNNLCCukwNJJI]0511S.|RS ---P-Zzc\ P-" "/ݩcGccb{hENfz_ÏRqjADRx Sި#qMJզMHqCZT/:f&R_=;;[G$_|R@,-,455srr=@#"j֬\\|Y.\(-Zxa|; xCi{͚%<|0""Fi | "5--66Vs΅ɅQ e34).PH6mbnn&{'###>>^ή\#:T/)~8!Qqnnrorrr:dr mr ߭~IIIUz/Qq'MёG-B+ :Ur T~}n3.77W*DΜ>M.Z kX9۵7QB:9  ]Agr  eիW:яf i1S$*f鶶6r=na^@tݏۥTiS_ TR0tӄl0'N )0L3tJLUU({ptO..;EY̙* e9"---M4ї7s2a~8P\~=`ۯf̔>+ZCiRCCgw-ZJb\vM~>hZ&O!]Jv{b}OOsEDFp=up⯿߿/}DOΎD" ,,X]$W +W.]$ j]MMݑ֦>n3?ZEa׶@z!쏟dMvDյ{'˯Xvܱ~r:.X\?@hrhLE|`X͜9 /@Nd/n=08m_f͚oĦw߽&g;wm}% ~LII9o3i9sdgen??>죏=V}Í9[n-.Yxs˵?NDBȯj #k#O?z,##mw޵m=йssbӹ,']ْu>fi. =8űԂ^ #)`|3z³l{>x)7Xobk`"˔)Yc̙[M]M`/I332nŭa?y䴛zaNo_wkoW_}5П$cUΊƦ0l޼9YӧO>}ԩSc[ouϽ[/ZT)yy'H6l@teq5_;y}uXaC?ɉ华u~7Ʀ=sbҤIiiiabƍD$`du=Y4;k.4)SV?I``H\vyl 0FH㐈$0Hڶ;Yg0!IC80c~~wFɉefFyGo`XLIΚ=IR:E8D$m-Yl߾= A7ye%`O֯ߐ,RR&-;ÓEWWWkkk`8?%m$ IvxۡoWYHN<9ph{bٰaѕbfFƩ f#?;\Pd&MZ~_}ܺu뭿El'x5kP4͏vƫhIJ$1w,CZV6՗NjEy%u9"BNj6kbf=qԂUU݋CoUP>(݋v~XpiN<5K)%%eo"1UʕK, ,4+ֱ'ԘR)9sUHޢxq+۳J⛷*\_S2 6I(/nB[C?q䢦Cw5mN/k _ H2iӎ{_K?~}6 MJ")}67;5Lݲ(9b[04Y}% 椆h}O&a?v9OGSRR~kۺ+Vd͞}DD=5kֲ˿@V5qVa/U%9PTӴ"Ȍ}wOサ>0h6;ɮj~j茞;umaJ|~80k;CjW+ʖu#]$'qJzz8 [KRKR"O]];f&LJn)K/nK̨D* **JAhIvmilV[u$ κM;ΏVPQ՜_94yekJz,-JvՇHu[u;kh XLIΚ̩hh}m֦k;\~ o&" C"8$" C"ˆ 332N] 8%"9Ѷn]&+#)$LYv٥&" C"m+F1I`!I8Z~]"k]&"8$"  Ƨ^^5k5k8?s;SN;XffdwN|)7ꫯΙ5kV`6mV^sw|;߹O_2)0L5;6͜A~³?/_7zWJ?O.ްqc؅.p@g>7oْN¿{sܱ={vJJJ`]]]֭}ӟolo>0/7q_w\CI8p^~E\ܛ\rICJ\`AVV|O. [jş89Ed>D$Ʋ+^|5Yޛ2e?~ /ɉeÆqWlz?ݖϢsK?_=D$'7::֭M6n X55?ھ}{xͷ~1⭷ު =D$e]]XZ$---0L_AYv٥sOjMN?pUCC5{w}8 F۵OCۼeK{{{>y޼>ጳ C#;^ܺuԩS.p`_>YL2};!0|N:C=4Y߰!$Hä)ɢkjoHΝ;iCۓNJӟ>o&cmv_=vÃ7䆃ye% 9>A,Y9'z*Yj ro٬YL{w >4?(bkk8C$;9dښ&dyс63cfXzM>,Iuikۺ+Vd͞}@p֫׈ ի#s sߟ,btzg#MD}px029vZZ40 :kɱb͚=`4hxQӏ ("̌YN-X5~}?֯_E'/p=FԩS/cEWWEvF1'ɉeʔٱǐ=|~ǝaOdbofFFŕW0]ECY^J^YC]E͊GMl}8D$a,...9絷UFR";Oe-!,y~O*6;9g"_YmaJ,/K)sV6&Vރdm[)N[ĢbKY c ht=ߟȼ|vڴ#0Hܥ]WVE<ă`J<]-5tYeț샣O!Y7|K֛l)tӾ]7?1/ş pv1eʔUNJǭ[_ĦX}҉'^&ᰩp;WާRO 'SU†Cjk5sѺP\Ey%w痞9̊ZB~|!{猳 w(55sSl $,l;hgZAMkqN(Һe }s0QȻj}dG6 _{#O\RRRʯX~oX6l@teq53;昿jXrw6M{śG $>!ƞѭ:R-e`eU~qmVuݷ eK:CVp#:+iI CjhF4ܷGYv]vi`" w^V߼ys7bhٵsFRvk E5)ڝ6)nm* Un%҅O^79}GV?V kr@D[ VkY=ft*lIDAT=Q:J"k &Of~.̶D*3+kKvZONĭߢuc-*n)H[2ʖ&o{艝'v;FvߴemaC陹cJ\HbAKYzr' $M~!G䣧[uf gddv,/e060f7Ҕ{6{'CL~\/|bQQ)];_N8ح--|aR~UcW)n@ۮ0g]>ϷM?_d=3#_أA_$8탧=cZ?ڶ;Yg0frțo+~a ͎T 0g=:557֋Fp u$0={?+^cPqkDAc[ b"̌Ή8%==d06wr2"m۶O{?\4iRZZZ+#)~XLIΚ,K[ۓEJJJ`t!I`t0QMkC_J`H㐈IJa+čS.0NHN,ott[`);k.40D$ƘæN .rJDD$٤I)qꭷ:E 0H d}07X~CHID$o?F\fiWSMQj"eQ^bST:$]Bq}WMAZYEűu7WM+j*3&MYŭl(M̨Lk|dLΊvUVKhZU͢ꫯ_; .z |(0F" 0R&M*XQϿu[O:kքli]gfeSU~sqy 4e\[n.Omv:x3ȽU\U]}--!'oȯuD愡kbS'>+퇯\P`,ErbٰamwxpeF1UʕK,9CT^U7Q]RY?gF[?EbdΏ$G.nmj, mՅ^[^a8R[ud~4>wAUcWcUߜd[u En?_Wo|=0vHN,ott[6lbڴ#ޓ(bqFe-GNʂ^Y(D";*tޱsY|=ç00h@5kֲ˿~;l괰 椆h n aFnNHdVQq )K4vqkSq]ݳs/ț9ӖU-e%Ѻe EƛDx#̰Xv.^v]vi`" 0W]_^W֐\[8?ڙU˸ŕEuah {' 3:pG!" 0~-/, ߨ^3Ntjlj-Ntm,n {؆u6/RѾctHb;v^%i{8Ey]5\r'4u%.bWu4f%ɣwO23V(qRU]ݗBgu}4ue>r˖-NK?|ş "#eʔ)cǭ[_!n&֦Ɲ^|(Wg-`U}w02W]_gʂzRSQ?l3dv%e}gIDAT`BJ R3FR;;ԗ.--h++hOInVWk4ԕD ~f{:DWD"fԕg.j)^ZbYzI$i5UOhf'N >&xϬiYW[cwoU)q9ӈĻi$N4vݫW]:4qz.&d?Iѩxo~ΊƦ܁vTo?Yqkg4vQvs] xvD$qHDֶuyWȚ=s$C0R>ʦ$CS^$ !"98SpP5lD02D$')SҳfD$qHD׶&" C"ˆ 332N] 8%"9Ѷn]ND_p:-qW,e2I`f'OJof`|ys۶d:90H :*Y<3aij cʍ߾oF֮M3fn"lfd[[[o:Yd}t&mnX5{.@1)0O?]E^&0^;wn`t~Eg,~?ܾ}{`\x0ɧiiig&"98űԂ1KKNJ{}ׯ𢋓]xF7ɉeʔٱǐ}d}~ǝa[^IĦ-m(K,t!~`ذq?s͛C"k^qQOD`D|'tbFU-ͯjj COifc~vs#Giӎzw`@r+w_Nd^Ygwyx 'FW_}Gi|x_ IweF?VT/>nݺ_"6N[M>;u/#ɉ华ubӆp@LvDյ{'˯Xvܱdž-dy}iVh,ktݖUړq̩ u[- m!dqQVHݲ=sY|=00h@5kֲ˿piC\sFssS{Xo1sm4W+nm*y^{uvmqkq+]~x5k]nHÎ eK:Sϼ gus.83g0Ӣi!_֯eˢHJamʦUm;a$!,/Ta"" C"8$"98S0DR"&ɉeʔ;I`^J FDD$' 6>]+ffdpAqJDrbymݺ㝈$LYv٥&" <򡇚_xӧ?xK`d̝/+;;,X`AFI^z饥_?;çF̛ov> )Nfff`4g7|ND0" cؗ.ʏ~|S4iJw}C=402^^g}nݾ}֭[KPss /8}o 0͝/+;;,XP~ݧ/˶n[os}wno7lGzz^zi֬Y׬ OӟY<~{O9%?63##0HSN 쥗^zix9&7|bStCUiz?Ԥvow߯+xH65kV`6mV^sw|;߹O_ c>?s?pr|$0$'2y'K7l!;_xǿK ؽ?^~}蓋7ltg˖-oO:)0d_+?MzҤI+]{ܱǾs=믿k쳏>؍5۷oߺukqɒǛ[5yg>7Կ.wgϞDWW׺ugzg`D$' 6>]+ffdpA`lھ+Y{gϾ7á:wnNl:şĢ>[nݺVW,-])SEg[a+>7䒒<===0)))Y .,(o,G?ѷ>Ɇ+W'rc<, 4>pJ^^/_⋭ˮ۷V>rL2?g?M~|˿#" cԩSoMGqDv#ž,vXwݾ#?ݖϢsK?_Rv]vil:#" sl2Y_W ;~;^}Q2o!v'cb[oUS[HD$q{GMݧ/:ujHde]]XZ$---0L_Ij3 W54zg|}]-O<,N90vL@サ>b_NJ'xݫmZpYagy˖d}y;-7sxt^xq֭/.8~dq`/ܝ-[aC`$XM2};!0|N:C=4Y{&]$aoŶmۖ,RS';u4wd?9'*wI? C9oO:GCM ܛڶ;Yg0d:*Y<3a aZpIs9k$3fftv=&waߎye}vIDAT%a,5⩧ *wA ¸g?IûO7sx/E'Cڵb^žb/F_O֙G- ? {eno:Y f5`| ɉefFy,M,uG]ɺO!oWwg,N- ? {en߫sܹO5| ɉeʔٱǐW(:dLOsvaO^ٷ`ter3Nh`uɓcŚ5{h8<_ED~.IOO ?|eMͱ">W$[n >ܮ_x.<mԩ]뢋?ipx$dee}%뫮; v۵U%ezfff`pn {4ޮ 7~3&{332*2兑0,R0*2l'6oVO?X|37m #@?_K ʾoWq]:Ey%ufe6YY3$-!*,ͬl/|W={ {yx}pQ,0{㥗^ҥ{}ɏܯ^Z]]c*j S/H-XXj#m=w;gViizO<BYhv4 m$n{{\ϣI{OlyϷVP\wjҚځ8 ;J+yTq;ԂŻB[:q e?vΪ a6sc6k5v龓;Z6T:yon[^~9?60 w/~ztE;s. `wx{r]C_B6GM^[s'=>s#O~1#|*]$' 6v]WNjjmrӒワȼ%K|O~YTH45uŦ̶E-5EJS}yNUGSD$giKL.j*ǣUSrW'fѾZ%Kr>:i~y]^HiV{uzYK(Is!:0﫸5q{h,=RR%u_\)_Btm"5zvjHoAmm-yuwlW[?jn )*u%on|b5snw/U2^*a5)qq7y YQn{Nw!)X_};z[tiV(LM>2OC ?;5!Z&S+x + y9c/}KT}~I]7ey]}S9`7?K`A9s9~Uc߅x(son!|dLnnjHv:no>|K֛l)tӾ]7֭a8#|*]$'7::֭jzWhcEE?B֭[o/bS>WY⢬oi ݈w ao8z=/=sו.r㌳ cywy˖ptvԺhP -kǕί]R;fDV^YPY7vKvmM=w2kouZZڶm>K{uvm.*/Tyn ?3davɯ(6)OpKö毟 vO0k=8]ڒڲċφvh]o-orVtQK5:떖5ԶpV546u?]~AzZZ/w=\9 ;%݉]+rݝ=P{^Ξt`ϯMNUEf>R4^=kʔ)oƮO) x߅P\Ĺ;'- #+{ؗMK1+;^{-]SRRʯXv78D$1Uʕ˿{7m!atFGM7X'WDJbMm(I6ePfe.D&d|gkw&[Ev۱mhdj2DY pyqNKEKR5{m9Eݏuǐ/jod_D!qOųY9y[ߗol(mK嵙{H=swǮwJDʢ;H-*Ϳ:zZYKǜ0*Gli]g*,tElӯx8✰_Ud>j*ޫ(7x?Rs ˆUd(Cn^l2FpW_N]ղfK@ jڴ#3O?Y~Ų=6xV$%Itn۟Qq!=rq3+{F^)\޳:~ORJv&GŷnV,As^Yּ}N ObP>|qT[֝SL B^w_g')>ZkW$77c3=k~~z񛎎:)))uvZ>{OGv]=tQOķ`V鋳mбwhYTZWIշ/U<,rO ]jWmE]g2Y=}`ggмv[Q_ONHuEu~~wׇs󺺺[Fy鱗]?>죏=vcMۓ|_FC>qfeS}yb`x{]E^ʺHg0Яthx2$~Վ]~I 7m۽cT.nR0"SQSk x(#| )Yy}SefnhXT)!&o]^Ywꯥ,}9{{gϾ?5W{ssW\߿Q_q-< yy7y ǿ~~_Ʊ9J^}*'Wau7ѡ5*Mhi޴˼~f/[Wbѧj 'hya$eě&@+j( ED(hd)43.ZtF]$R-FI!gW㱦DJ:`{G9D~@f۵$nr{Vi8ȱ뺯&b+Y"q-}nxxO͚sK5,=R`2D&iQ9>Wvs>x)=|`5MX㗾E\光w;(o={KύφY{~lҎcO{ÞWe/Nѫ{^wpc9Ϸ;6K#IDAT^V4mq!۵V{g2?jzX^{w'7*TsVG6oc"+$3$e8Hx[o/{?N:WS~_l E+qc#IWG>0iW:UJc/J3eV6VEw:z2_grDvy܌rkj'^ aS%׶'mnX5{hWBP7߮^|;&K anPt۹^{-VϚêwl7DGK4n(Fl(˛ߐjH#bd#p0" Lhl2Y_W#c,74,7d6Ę;~;^}uGI`B{t>S?ĭMv֙g$k~`x'!nw 9[ouϽ($ (508SÄR^6´SNٛ™gﱢ^5kVj#m-,/->osE5+&>}d³fpJ^}ux'?0^HN,Sgg!_>Y<{]Ģ%K?^vG$[!{~u^޺gwdDr `YpI`$Ce˖d'7ۅmvk{pZF{k]ۺd=5ubƍad4lD&ۻ;Rom۶7To=ɓ^J2%YtvI`X6l@teq`Hr.ώqC_J`8D$'7::֭ 0މH5k]n"8$" C"#3 W54nサ>'"8$" Rzη:To&9mnX5{. I}z!ɢu7 O%K[bKxHk $>Jɢ=s?>HXffdwN|)?o?YI}6Y ɔ)Yc̙?GuTxx0 y0_LGM?2 " R'h{şݴysn^tqɓ&" 0 6m|?qӦІ? shxȼkS矿7͏vvH-XXwqmaJu{rQe~Cʵ%m;&lE(8,/T;Xvm Jln. j*֖4?6*pZ*zNps!v϶(;~vĢځ.[-J:wx~eyŖ_ DɉeÆqWlz&>,6oRrI邅}rC W5v5% ׵X0RݞUu}MRԢ>EBNUGl2K[#cQٔUMHzYKy}Ӫ۪ *51rO?nS7?hѻ/(Gђ,Ju Z8BO>]ME7VεѰ[[Up|`G﹒v.NzN{'MMye e+㗜Xq[- }ߚ|m>r˖-NK?|ş '"9Ѷn]lڰqc%%%W.cSsݓOy-JkR;*xcԵU=xSRR*]@eGrs]Y{kyEt[j9amj]ny(2K뛒;&vRj;'-D:ְgEHEHt/zxNli]g*s29wҲ9ݳn }Vӵ}v|'ACHIBA=|~*ڙVPYSuux㏿v‡V5`Κ. 7]$G>O~bQzz7=_=t{eYK8+RC[mYt(+'N=ګS"!uFlDb+Ϗbřa΋V)}Co!ˬbmђT-yAN<3Exc/ع,l>i. DD`ؤq?M[6?mjbu-= o_!lj۹cΊ@WD;]Fά_B[u04%.eKe"YY7}[#yS*gya$%{cZAMW2<=;ڲ=κD:^}ˀN=ӊZ^+$r]Cg|x|01ģg=w xа'R^ݞVpCoT_:}%z7䆡*n$+|!TeIVdƻ]l:2 u[$Zn3d6>Ģ&D/"Mmv31\u22X[Ro(X^UIWgVߜ9&[g{ilW 6%x#C{W]_4dY{Hu[fi|W=v!H(=1[1E;zg&hCˢd4w ۶?Š*q:ݛ콐"_xkߧyZj4L>50֦#Dw4dsr:6G|hǏ{u4yV < z?V9}wٴ7Ykۺ+Vd͞}DDD$qHDrbq9-/T0~ƹqّfv`bXLIΚvi wI]H% !I`X6l@teq1]GDrbymݺ㝈$LYv٥&" C"8$" p@=ጳ =!I}4ydo8ܶ-YNXڶ;Yg0GGuTX07DoߒKa/=vm1cF AD`̘,V^oW'̣$HN,332;'>z쟹sߟ,V [;"9w@¤D2eJzv4sfFOYgM<9VY8H|bEZZ4 " Nzх+.6op_‹.N_tHw߬(~䑱b|37m pmظӟ0ϝQq}u57|b񹱺s#O~ّ궞YM}5IDATDūPQ;gUcU0RѾ^ j:r(9b;+/1' ص͏vp=PZA M0=~M;ZT[w+Ƣ~qls]N]8PMn.&1 ,ڱ?b/'?GӦ衋IJa+6= ~#_-[J.)]oW.oߺukŭMM]mu RJ+BSэ}{]M5E}پѥ7U5Tu4fŖvFO+k_U6XTgVwtׯ*9Uڸ"''p]KraΊƦDh۪Yq}AZ|򑻻u%I\HvhIvm5Tv?k>'ꫯ_; .z_ Xh[.6mظ1䚫rm?ɏqaS4qV^zy]{0htFgG;Jzp\ٝ-]Gas9c/c) 0It'7dwWCU}y0:3֯ΐ6'wnjmCa{^8öhIJpˎ!!d32兑)65,뻫d3l.ڊN\HIVG6vyUy祺G-08Iѩ.>tMbbGkW;J4\l(KSخ-R װ~f;Y[bǙfG"e &;/^`< kʜ#ݗq6%7/\^Jw A " 0S!t֕Dx#ÊӅѪƮ|12?j{]^bX7o[g)خWG(jOf%C{ǓC8x񮐙U90yoXHVK)n/L@bK^ANUG=wmY{tɭoNVGvtL/dv3O/'{ޓF{52M,^J`λbE矻8w{~Ua=ጳ cE7o%p0=ԁa?+<&#p0qGDD$'qJzz+ ey󣝃,L-i\D$')SҳfɓśoؽƮpܣkonۖ,RS'qDDЎ:dkO;ua8W6GR"֮M3f㈈$0̘,V^`BoW'̣㈈$0͝dz$ɹsqDDrbٰaѕ!9/ԅ Lxg5yzk͚=`ԅa}h~k[_ 0:<]SOŊ3NhG&&7::֭M6n @SN¿]]]]M70֯_E'/.D͊_rŖ_޴yoiƌƻ 7~3&c332*2Iv]vi`" LtGM^[sCnxȼ[o-{Giӎ.ݡ۷G?/~s?[\Rz 5;y>0uc߫裏4>z.|D$aW)))g~zl 0?+!xG`h{‰Ν2%=V̜1#p[?MǿwΤI`8"9ᤥ|CG90׿NJC9$oJDr":}'^{{Z%?.\S$q?c]}ܱGLzaF]{z?{~ '\t߿=9wgeeD$Ǫ_~e'#\Rrw@DrƲ+^|5Y?~CDrLzm%/}1G۷o!HIKKK>:::uի״q=jU` :g{l8Ι{52M,^J6oْWN֏4:@J.)Ι!0M< ?TƔ~DIfbʔ){  a۶m߸|٩#}o?o:0{lْ,&Mr^yVsɏӦ/~Nd}CMM`p4c[Ngyƻ}L`?,ZZDj`,{'żyv]zie_sN8C=_Տw$ض~dq&I&wr^~C`H='w[|Ll۶m۴ys2LyCnnFcş 0Zհ!VZ f"cQG,yLlO?6Y̘1#5uw?M]Moxnlw3Yw U W]}Mb廆 w =̘,rkkk&߮^,23L3gv!XfM`"cG]Z8&ވdܹ yH/k""9&}v?p֯_'c #333'1w/p^?64.Zl֥MҒ[ߵEK˒WXM 説]H.K*;F28|ȎdBׯ˔)+L:?.ڵbuc=J>_?0( ɄTf͛o18r$ٲeK[n_İZii6mND2Q.]z /rHr;RӚ]k~(^6m4w=8 /:3,\lJ۔ҡtJuLu'gf̌mOvz &MJR|R-j);V3S-^}UN+ng  mGy*TJy 5ZɢK̨q)B(IC7oWor-+Vq䰪UO8]3=O KD|f!\Ze6{3o2}rj jWǎͪkH(t`oZ?=#k=%Qf 6dQPHPz.Y[, {*+$P ~"@1f͚3I!-)-@wEŁQ֭~[TQ(RJ}tJֱmE$P Hg߬_D!I!IHlc^z)S͛|Ŋ/"PUX5իעyj\JJ ;IvúPT߬_Jg̸^, Tp}םw)S&lUiӦXPX9T l޼n/Gp[n}hZy%BoРA(6nxf͚VLxIK7T wnXe M~e;c߉,^US:.!~b裿-<txĉn֍Xi1ni㶅e_8ID6\h{޼DzaYȋh;#K. L ];#)[ *NWwвCff̌mC.Tw0NORM!j']ʳމʔ+ճƍSb…mڞvA׋?4d{b-===*lÔ iBVgPG-}m Pۘ>X;sg٘Wrul7!j9]ܭFoVb#C^m3_յ֞'34azSüRM]ò>FJ:䓢:=@Czm/7ތvObE֭ߙ2%=8]ֲOpbs>Xaa`4[?%+rxJA juRc:;>H~Rh7dΈ{|uLC'KK;x*t䤱{x\Xq }b[w+V\jʥsChTgXѺc'_9eo|uDyUǬ΋K_{p# 3ghru?E2gnvX{/bި2iTe rL2ٰa Ǎ]w7oyr;ܴiSHX \}COnU"oG. kdzׯS'Xf/#:WKd֭7VLKKi18NXğvFucw97oGYv]4ެic_-W\N'֭w̗_}+}ؓiZIBh7t42^\/ҽӪK?02ǠNI[:e.3#öXa|!0$)ə#B7_: 5_yxgx1Luç]vȬcw?cfC>2v:!{IT Wi1/?v8>昣K9.>;nxt%ڜsϞh$@*]tc=}[oiS[l?c=q!?<*]HgkU;^?ΏǣewjF!]sjx7_6iaO2c]}ɨkcVm/oA \{$L(3 03)ڱՏ"IDAT]TW/N=,.R?%WpζիWisuM,_#C5be^ҲEʱ-iKGЃҺW^uY@(LGucqǏ9MNMm{H̬^]u:\UvaK:vY߶*~I- ai)WpGcs5(tuz1x;?K]?ۂYKZwhH=Ɠkvpvjt[0}Hgurdf7CX8St;/t m1/}EzT5i휭[^֣ǦMBfv;o~yNyo;,VNU $Ԯ BSRrT|~m(F~VmN?~[gpO0q^+&?j!e6_l4d<]G%=pޓd6;(27oE>7}.iO {**.#cڵ;GO>.Eſ//v;S?cT_tE}(]׭>c_{VZUؔ5㽔CZG9#@$;]$͚EŜssӦu~;G q|4@AvQZZRN[j6~7!]#+?9MQQb#cN8rE9s@((7LOr?wgώ>ϧ5sNiԦI'tRՈ3Gµjy{x;Vg{jժtVzj-Z4TR-[4&}2I"Qꫯ<.7x3}oǶ@Iu??Y&*Nj0FEɽ~2 me˖[yfҘ{8J@NSޞ|dQqA}~oL"ED Q]}COn*PZJ^ޝ {B |W3I!I!I6楗ߙ2e޼W/]ŊQ^z-7;ǥ#" ޟ1㪫{-^$Plذa…mw]wQLJRX޲em޼n/Gp[n}hZy{DE%.EHCbł 4h휍7yvYfG+^U:)u݆|de_wb#,i{t *VJI""6"q=Z78j`#Jc_v:fЍ6mkլ٤Il`޶6իW %FQ1ol'0 'FE_4a%Y^]}*W՛6mUN[ng}iMAD99Q1b]nٲ)kr܍(>zWT/^oϿ͚6VMI(Bڝqq))ի/~EFFƎG'L|?eʖ0r@R~wY'wCT?䓻?4$oPb!p)Sr[l::v8)G;*䓉ҒM E]Ҷm]/9+l;!a%_Kn$*̙_dϛ7=imO|nPbH-mZ7ѡC[j={hwܹQѠeJ&v> L ]; E~u-:df6Au.4(j!۩џF]jI.Yzeʕs7߷>5kbɕzPH9w7n .l ^3[n$%% {jժDD9蠃^?8=kd ֭vOl~bg9~QċKP? QsWpI~uΓo)-ܩ_cvQڽå۪. ]`\ O 톌[rtg2ewzv<+3:iĐ59.*볏?+݃>W^>}PˆHE˗y;pU}SNlҕY9vڂ'ܕKШNmhR׍u]ޱ݄Wo5 'eY`ҥG7ȌE0GZ9cdv^.QehwSc eev|n)oOim@S:P$*U\#GŶܱ]׮pؿ ~:YɿnٟÅ!4ylb&5cN4݄G1n'Ծ18uί_X|搐v}RkZ{mϞ n:>ï]ЭFZt')wu̬Ŏ~\>ŴҮ]mt&ng5ݐl˦/}lټ%>J^x%jذA(D$_ѣ{luW_ŊE,:cs:NaI'4hz{_{$_f>2+}m;e|^_=9bmLzSrEii)w\(z.iIi[:n_i >bd\vؼysT>8D$k]|ɥof?ގm~~Zې?QQj8, xʗ/;pUJvG|0o^TT/]*IRFFFݰ.1*%G7b?vQmi*U^xᥗa!?[FQ i-oa6m+ʔ)PX9B |W͚6$M~kCC EDƼy/####Vv Tƍw[v5O=DH4Hq+Vx̩Ӧ01Vg{jժD#" PƼ;S̛7_|EDp??mH@"3%K$vs 1H͛7Ќ *U^xᥗa H䋍7yvYfGɕo ԭ[ H佌K/lղߞ}z((y/N81{k#" Ƕl{թ?ND M+ʖ-3ϔ*_/I<6vpY?YI<6wܨh֬YHpΔ)`¸i(p"y,===*7kB"" Ǿ^:*N<IsEP@xm/7ތvOBfwL O딪aߞ+I0>xsV6/}qOY:Qb#kԨW^:q)) H1<؟|5kBP5uV=o&o}N^c{fHSMrѪrJm&x^3ܷK% 6,X0??;ʔ)SRFFFݰ.1*%G7ߎ9*M6-$fxE"8VаSfq_9U얄<퓛ðOp9^I'5 E^êmڴ)V)SfW()_r .|WBivǟ]EfV7.j¸iڵ>GcM816xɒVmNyg|nH4"7 3BI\U˖.ӷƍcW^uu54iJ%A)EbW7?XiӦ+z^$%T|Mw?أQxɒ=BH("@ڵ;GO>$3 MT̙3/CD _\=gNH"@J*ղENO2$ק:PRpX7$I`O>tiT$''!" EE@ GǏ l֭Ϣ:I8D$hִijHDD޿&5!Q}"" dc޼wOk{js;R*`ƍOmz͚nrr姞|"$]$+V?ciOƇ=xj@(c^z)S͛|Ŋ/"@"8_|6$ IW]k%Js;}9D$͛]ylhFFFqh*]/K~հaD$ƍ<ìY7\w]Æ ֭[cD$^FFƥGjo>SzR'Lս{z Ptc[l=F'" &L|?e˖}gJү $@;n|Tt8n $@;wnT4k,l0!}~m Hhެi $@z8PHD$W_Ŋŋ7h w]}WHdyyHFQ1o$I2lT vȣ:>#K 6,Xpwuw'M6%" }͂>|'jQ/Gl[z;y=wN\3wU3zbXm}lۥBMK)Y &7O,|lݺ!7kdm|W|+ztmӀ ԃRdխS{;ac$}A6'[?=cױ_ޛo֯ %ڵ>GcM816xɒVmNyg|nH4HP6rXBw<êYqqPxcȞWW;u1)yÓUfɕ[lye5+W.g͚.9}\5ysULK3+cl>ݹjW%ŏq;zh;1.km]!;3ʺT5{|9uX+b蹼+ICWeɼZ`w=e9˯ڴi=`άP222=uP)9*JΚ -k껯 %m[Dҙ4ο >K/U(VmӦML2kJEIP, d]3]|qT? H9DŜ9s8D$pʕs!" TR-[4/@( =mt_c8D$=ӥQ$'̛իW #)###nX 5fuըY;?xajR@Uj6meʔYUz(JW $͚6$M~kCC EDƼdIDATy/####Vv Tƍw[v5O=DH4Hq+Vx̩Ӧ01Vg{jժD#" PƼ;S̛7_|EDp??mH@"3%K$vs 1H͛7Ќ *U^xᥗa HvϞ1sfT''W6lPn|&" /nYV-[gWR*oaO=&G@E eddrQ})m'" ޙ2/g'" ^ߣ⪞WVV-M67)S͛|Ŋc>w $+YFzZ4ovYKI 䚈$@9kVTݾ}(pϘqս/Y5rtzĴaÆ ƶq?^wyG2eP*>8Cڼy_1Iuև<ܬE>ȅl|a](b*TJo֯ EUڸqgw5kv\kذAݺugK֮]>;nĉ3OVmӦML2kJEIPD$X$YV-[gW(F=m~qƐy}&Mvgm{zm8W7?XiӦ+z^?r&" ضl{թؿT)?ۋ?K0@hۄ}籢lٲ=|d֮.8@$iq㣢ggu&*̙_rP:Ν͚5hJɁD~wm;pʕ۸qc=gN#dGIĖ͛5 Jj٢yTȁ$@ۼy׫WNJ8 Q@ФIXimYh ~a_~U?~ B~DEժUKӏ3w?#kԈ?0i֭QQTRȤ$@;ãb!}0o^TT^-Pbg QdE$>c7"M7͛5e˖7[n]FFFTp $@;9Q1bob1r=@Qz$} %ގ? Kw` ;RRb׫W_Vy~k׮=(I\}T)S_АI9Vddd\}Uwi޼wOCD$^֭M~t&MϞ='ghѪO< -[y"8Lx.:&mv#yRќe3ψZgys|'*V+VZ~۴iS(16n;Զ׬&,I|1p@ƍSz…mڞvA׋?4d{}iӦi;_xi`4޲Eg+mSJ)mw1iם13=;'4)JiUjJx[xbU|ª [T jԐr~xtiA~#<LJF D=oyWPLXbK/Դf_[n˕+vV:?^?K.}7&Ķc)sZ/_ӧWR5xp96gNj)/L w[<8kgZiCWD{۾3;rPXמYsbSvA--[>'b[(I>_x.;E /_/wCT jJl3۾sU6-nkƞWW^f{ϻ??Es;My{Okv$@5Wt|QmiH۩g-3tUσ>BwyGo/Ov?*/4{Bϝn#MC~㋒{媴 ءg>-`ZJ /_5l @D ߕ/_c[(p*%?583NyP*#,|Xի_zխ[`ާ. PUDr"I( U=vZQԩ CH^|=UOn2PxjwƁ++> PUD2v쒲e OŊ9^xIW"GT_Z^=*7 $#E$ׯ_Q @V|"+>,d6($+*TJPCbZXjB?%d:o?}FHL~޽] He]Ӆ2fn=ވdvL}tyio _63GlL\cˢkf]!e663veYwy]`dьpL FD2-.\/gyobG3h/P+ZΚwo+ߌ.ɷ4~ޕOuyd/]?1WGWʧ;ǣ+Įpݩ Xbv1m{t~48۲nM@@~Y04=gZ\9J756OR*6K9Vtֵ\(V|<ͺ&0=ahc+ъ8#3hL0&yIxF$e7gv0KcjrߠQq},]$O6KT=k<_Ǔ4noٸhF?1E3v8ȰMGoo!mۏteۣ?ČGDc[,g־eq3vc%#_dm9 6s.ۃKb];dx$sIإd3>xL~XgU|zH ;찿|Ἇom|kN|m fnkXjcJ=IDATzά À{~|#_G׻w`We_Bc^vw7MhEw~-yt4lfapH$'"YQH}lkibz3N5檵]xf7τ n_D$eWL觓GtV-[ܲEw;> atEţ~>6:&}"3'O\_y&fȥUh~i}ǖ.@"{c+>7z͚P못.}3G3Bl$^8Nt&$ɼ5kΜPl޼y[oZ3i' @BHօ"BmN~GG]x~( '>GAt~vիWV#BZaE|ݦhv%}G7 jԬn]0+W^bY(JWP|:Px222J*Օ+UyrHHd2umZ^\|IowF͢y#))/N?C>۷+SL(.:s?#nݺ-[x`o4H楦MǶP䯿^]VʹƩ<Ir뗝;H"Eś[o=k֬˖-],䩺uԮU+--1/Δ)_b_| D5juI'5l}]~y^,)###nX kw?zߠQq}B1jtٲejլ<>k7 ^z3f\uuKButz<5q%@׭r+WqX9TIˏ/y_~kwMX>2&Zi^92͛7[~ժ& rm =S~k˖-7hp(p 4h͛7GEre>ozn}섚 ?+Wwߟx>Ȩ{^ٳa=ȣQQ:۸qgw5kv[1%}/ߨQR' XbE?~?4uc_-W\$!#RDr=GjV8j`Pe˕=>vgw~"ѡCu~K/lԺQ웺UCR'ئv)sCߗr/$%%(1ry>-$%K>~QݨuGS>rzO:h-.[<? _0qbT_tEVUY=v]?~ P$dDrQ ֪yTD?)**T0p+ JC*^\mK@~-[m59o EMo:cnHȈ׫W_VY3zKQ}#|jv7GQ֭[`>XQl#*O?ZWOI71# __Nѝe쟬o-mng.![ 1(dn7u!=iEiiIȺ9(I2"ٸqjT,XM.z<1FǶP䥧GEÖ suB:CRck'pʞFj۫e~} s2dt^ڡu^͞tH@w%ƛ bw}{~}ݕ={}צuwLُuԩU:'ƎǓKywSǙ {p\bm!btҜvZ˖/e PDĽΉ:ت{p֘Ku]i۷R5R3doUVU9MK<ꨓNj䓻%d1ph*-]4###:pkiX?ۼg֩Soʔ-~PnQgסX٠v_4F/Z4N>}C&]r{ē.&g  7'HF}͂>|'j[V#dmAUf꿠۞S[6o QG`3fLݿ;sB昞?sD=Xdɩ??ߵe~Iʩօ"&k}o֯}9s̲e5kKf*U>Qc e{yXq.PH^xo|0V\p~>T; -O͛?G֮Ajִ+W.@S1_~U>w')5Mqb]Νs\XQZO>^HjԬn]GʕWX+0$pl=Λ;8h~8a[Es³pζTjBgo-77mj-g̸Ǖ(9e'5Fͦ]d²1 oyy d:CTv7m|n_|0bh)7"lܸqGuM׿vǍ?r(vRS曺FڅI = k/#foo쐇JHF/Zz뭍7Ϣ-t!pE^( Ċ:g{4h ߿rnsb^u9F!sNOE~&m\wAVd駆%'WyfQ1gN֭M1d_̏B?}~FeT>7l"@)JVͣr:tfv - ["vMh^z]5Qh&AW:8S?m'M1>7PP7sIO2@q4p@;{X>esJ6N:Z )sc3-Z '"7\{ݐ!QRׇ+Vܧs;OF~߱-俤;~ۭ}z͚8JR5UV(^?K.}7ݷvl v ~w,իW XZŻ2fm*U lٲ11z̀f]S;a\Ǘ=ۢ_;ƵW}#~̺BE31(ъODrgPCZ4ov\JŽ'~G׫wO#Fs9'E3B;,3~m.ٜ?ѡVvּc9C.ZtyÌg׏ί0oG럎0wN-.z4Dzk u1|7.oز=no:3{( 6<)>BYKh~[bq.ڵbuc=|ahs$9W?RrfWkݞ!Ie㲏gΩu;O~l܌jXFȗ:7y,P͜1`ReNaZg !#..% kc>e{hJ4 mwec.G֩s/;g~c^{N*"˖-6Ӵwߝ>iN0qb`- ,.>A;u-}La۶z9:, mxnd]ށ _ۖ~ ]^yie3sg4Rm=^f|U/jڵ]6hRRҎB.U+TPbţq %W]k%氪Uo^:eWL觓Gt[w;> atEţ~>6:&}"3'O\_y&fȥUh~i}ǖ.]wߠQq},|QCNi}^խ['q"2l޼džNR֭/za /(W\(X+>7z͚P못.>ѣ3G3B,7w7'Nz㟓c/ݴI%$Eƍ<ìY7\w]Æ ֭[cYsbg͓z{ժUgٮI@KʩQ߷օ"BmV~~G,*jMFX^bV>w^y`QT\R:zh*e:#۴>y}86l^o%%)*l{թ?@>KJJj9>ʔ)FGEH@s΍f͚ $hެi|6beԪY'xa}\{ݛo3O?]& :?أիW@XhիNҿr/^r\J~D$7zPP|i=p]}{؍۸qcB> $EW_Ŋŋ7h 䃙3 -)-$͛7GEre>ozn}섚 ?+Wwߟx>Ȩ{^ٳa=ȣQ!@!"IQqGySD~hV>ZjG l"_~m-Wcۙٮku]CguQECjj7o~"iɒOn_T7jhE^œN>){˭˖-HRT霨1rTzzzSTTTaਁW>8JTb {HRT;RRb׫W_{:;'sIxOh5ǼշrK;ЩG *Ċ[NZr&"IҦu~;:IgN (^ܷZ^⹷ˋd;۵^]<cgӶ~هusU?Μmc{fُ[߳fQȞ搞Tx`M.O]..l-x3 ;"̙;7*nlj%u2,%*v4_m7q32g=W~ld Ώ@"8ƩQ`6mOŃ2BjҤt8(>:jUˋM)J *=@ޮ}}}ʂsl=(dɸBԅe ,O]rܮ-qGEÖ suB:CRck'pʞFj۫erV:j(^?K.}7&ĶXQruօڤjICWPsۯ_}|zEYY!5I9(,q`Jm2f^awǙc>!-noW\t3LK3^ ەógRAn>o&oWۤesc}AW{Ww/ fS]۾-HMyV f;'wiBԅl_6iR:۾;d~ٮ&)eR딪M+%IDAT6t-e -#CK.=9xFFQޱΉ;>}f:XgW/SLwcʕO{R̞K@~+>]$)f}/1rTl:mZ(`wyG6?J2ѽ`VYԗO-M9yϱ=C~ڃyҝm􎱽HǾseݏ{睜?U(՝wJwMCާ;{v?u!3(3jUiI;UO]3v۽mhv7Q'~{jĘV?kt[3Z65Umټ%역,9puwyǁ HRt/_c[߿Θ1sz_Wϯs[5bbkrB昞dw?.ˢ7th͚5?ovBS۶lѼIZڅ`ƍga֬nrrau֭!\ֽǘ^|I3BKBYh'|2o!,%@ӦM?_'F_~yM7|4c߇δpOǫ^ -wN(Lsk6tE`ho"u.{wfrX!#阖E^mUIYwU y3߇'ɼ};;wlܳzX5>(wp̌ꫨnРWI>2/N81{kr1jt\kܸQTdƍC8ꨣb5u;n/@6j5b<pA|slƎm,Qԗ EWѺ;Wm7|x2i5Q󏝇]OOH2[E|Ͽ0<˕+7> I`K~F} _d65k$^P^R [FQ#c?C0?DB϶Yўϥ`Wޱ)VsY333tsiIiQO'~駱#\su/ 3t!'׬idr!@r-]n;en>̚\9\K^XEU׭r+W, EI !]$IxNj}"P|reT6 yjܹQѬYP ReؓGg6.俿? G<԰}Gͷs(lK(,۟9IbӦgm?:}SQѼYPPl~/uu]mRlppCߺ}06}f~5>7PP7LO2@B$]ХK+~=Z_ziS_^M'|J֯_+6lPb}:w4``BKJJzKG׬CT (ѶޟV nB$X ¾wm/CA9KYz[DJC>*[l$" DGudT|tY/ڝ1k{GB~ci_,\zh,dk㏛b"cs}&U_~EGuc PbdGܩr!-7;.~XO?;'" Oڜ*-7;-$"q׬bgUuBFD n܄_u)=zLߵ_^OZjygǞ(@ S|"#F. IRNݰ.1*%G7~A"s)UȺ4h @p}>3Yt; 5~V\ِG'd+>GFe? P4Pfu\BQRb]$)V͟/"IQ_GVYmਁ Z'lǧμv]W:g?{M_(J(F͛-YmF?2򑻈֋x'E}ouٲJ*I#G(TӟB G rK;ЩG *Ċ[NZIDbѡC[j={nܹQѨuNvQZZRi!VOIKKro^}t(.^p~k85JF.XM>묓[lѢyԃ:(@KOO-ur ϑ\!398q i)ɺȴ_nRu0lBM%)DTC5C!qr9.s?|?~skOx1Ɓ5hIoǯgݺ%RH֮U3P2.^6'MkMoM(v7+QԨۘ;_x/=e^_vDS3xpRb_Z(~ئͧKԪY>_XhbB /=CSJud#j\濾own>n"%HreCzw{5j $"IqST}z/G~zV m mî*TpMc-@!V|g5dGKkO?D(-^g͟#6mڼcǎ?3&MkCEr̸Q ZjQxpꝚU/ph]Iի".n:tߝv-fͺOCH\*j4n0*1"ð:ii iiBn!,v3BeE$7n5kN}er뮋6_4i츿؇}M6Bbbz4"IDAT7lxTܿ_N%ݻزeK:~mBBˆWG4?~'V)Sf%GuT(FvѪ ,u|#8"P_y 5j%o'LJV\ GU @A(>H=*V_mZqkt`T_b)UO*SL^t٫SȎ$@.탪}tش~-o/C~ٸn〮\fUoկBqT/5ùz˓dGD Sʨ~ǗC{ɗuyO\.ټY;o^s۷}yXy\q#5o׼QF[^B.6ՙ8~8j<3"vC NLL{h> mb픓O5ko𨸹Byem^z!r/|G,],*W ;"y}vsf;~ܘ_%]^彙3>P|0~T$%Hv]@t^OrIVDIS|"k k׮3vlT dD$( vqWoڴ9V֭{gȎ$EM:w'$$Ȏ$E{fwE~ѲEP|"cƍK/(.f̙xg)S:[hqo/UP4MxO?+دs۷٧업ެYקK8U=vg("n/@ ֭[ooҦuK]풮˗pD$7ߜy?ڬ\/AuI[76I _qU|d-SIII On]Л7o^T4k, Ͽ/Xr@TFZ5kvZ֧]f kFEfMyo֬k%K ;zQ7 J|~Æ8S¡ںun;EQ];㬳7۶m g,@Pju_|+>뇜osmUo Y$|UZ`Aȹ+ꑕlغ_>O緖,bNm~:ػu7kU=~{OE$Q|"cƍZ F2qJDOXQ\!c*'XQ{G92V/]թSю;.M6JZ|'`#8aG߾؉/O^Ú ycƥii\=sZBZf7zcCN J63e`ZBpH{e;'IuZ:Ynu;"" 6[_>QȑM6sy~M3ۥg~`lhu)/qyɳg )+j,輝(;I {^n-A[6C̞{XgaxfqyЯƞ{h)',<ǹ;Yf͊}@ !7n -j̮.3}w?G]6*l!/BɃwktG0lyjvk1sUnqe&,Ln;Ӈ)'OxI~83Ԕ=z[]w1cyp|׮](fΰw3njG-[t(Lz˯xףI'ZȘcO羔Ԩ20WpyH\/k.{&gLl[#yVV\=mῶxGwP͸,Y3.MalVnx5!!; SUNo6쭯םruCuRb͚5+g;fo};mg*aI`TP'3t1UܔrjjXpA#X(d3ubv-wxYSë220d\hW|eC[#ՉS]x^jl58}vu1;ˎL/?vy|d5/l_Lշlsʖ+({q/{ow"@Aۧ?|᧷:̸n259,0qf|3l]C}V[8%]erNl7ܗlڄE!EʾL2g~Ӑٟvnf,2)zV|"kՌZFF#5'L%]1f^yf\Ctyߍψo\MvȊH6i8@nKHOOv -Bα䖼{%)S\ri|l1 tlukXN˺^l=վ.zt2 't>B׬zRׯ6}_z~9(/97lxTܿ_TVTTiÞb9WU8R BE(ڷkwRzbM WteӇu5e!Vݪoun>rǎu}Yr[PDqÏ:|~M!3{v(I: ߬i~fo)'w?oyQ與3qMOTyxLד~<@ѱ`ػ6q~ѲEy"rժC ~wn^ϥW6a~iN Jb5Ζ-Z 7, =Lz˯xף7fs۷٧Pܿ_R|IDATJ *{9J@QScǏ$PT{>[ mZ~т^,@6PUPWZ؝$P HW6<*n/@!I*>n]vݺo̜? 7u1AԲe /ZժJ]f( O>_f͡XaC͟`̸qwC(8 k׮xᏯEB×_n:wYJ3$%YUׂ ׯ ,Z]YkjP~vQ>vRP֬X|%.yiKK>Z:Z6O8!@~QQz"IqPZ`Aqu%cַ[x>2&v i޽_gg?۹Ws .嗛gF$D$|U|"cƍZiԨaT̟/"I0W˗{'{#Bl{rOlAulҸqG'"rժJ_xAT;nڵO>1Q?9Bvv|OK. b?nj?,Mqо] _y5?cǎXR/(' 7ND#xpQ=oy_Ko2Ge;'tlՙcSIʖ+ڨ~o nՏx8!!!#I6[_>QȑM6Ɔ׬Y[?Cf [ o~V/{rKgwLx፡7vagSv?x޲ y\36[?hA~ (*TpMc-@XhQcŲbxlHI1d~fnX31_´=<{` kWsf=THv%jUE捛_Og03?5/}e&, ɽRxVY&WP|kתǪT9:9vT/kt^8e% ',ɝ;xEsEEZ_'" :]xaTi؟vq)-oݻ[=;}ppfqy)g}6]5@&" p(zlٲ7QjhE- oWCrNZ}G}+bW(D$EZnea)8 Pt< _~rQ}ۭ$%%(֊ODr̸Q 6MKA?k}(|֮Zۯc\h3I_1@qW:+W 뙧I\i.ieͯ|/Z(?b͚5@~DbNoBvCߟ?k(D$WʕhN8PĮ׃~|wJ?npk!I}ÆG_"@1$" C'"٭kD$kת2Xh(D$bHD(ODr̸Qq%]PU@R(?ִbbM~y2=|_0n3ΘgVlKӺ Ha񬐚!]&mz-MS;cvߡ^7「dd.9v("Ea>?lspo]u6U]!ks!" rЮG9g+Fpc&G"P94d좐d%(6Y[7kݓ_8-؀-O8/@>+>ڵj 'o0Sס_5V͚^] yUc2~߃˭g.zB1lٲ+THXSZMBD$iWN]rU>; cwb6~ez+w/WlBFDJ/7o{̱N WC!S11s௷l 9t8ǒ[ s76k78jժV9g˖-K.sJY< jJ޼9OJ*^<&P|f3n|T\zId%KժUЮ]P bIIZPX U}8NMNJڵj^2HrW_}5w 3$p@Jj{;'Urς?7z˗  @vGyd\5k[~>0$Y$sY|eCQV~^]5NwR˖-.jUrUӴ&S^+>쳖-(h">}bd 61+.I p!#"嗛چaw&Nߧ0kܴy1G!zy]}E /WB_EJ?|UO8vCx;}z7i?z3oETzzU>t3<39ukMxm+'pB 7}Xi+6<*n/@!=cy|d͚5S͚6 BBBB gٶ5=nm' ow7OlWT~#@A6dgnխZ|M>rʕ{a=LlA`hIDATuֵKsw}wT$&&*U:oQt/'"YVͨ 6l8~Q&%%q U}|Ԩ/PM<%===VSJK/ %Crz[w8<^b_ I ̝7/*Zl?(i}7m˖-߲eKbbbȉ"dANf^xx7̙l{ Z:)ɵk=3۞(D$vڨhެi(I4_|o&V].I޻P,],֦ ;JȪETP\7>jȡ5k2#7%ɑGyZQzó|q-5JkcUErU­Zժ"V,X~|tV3wa> *j~NI&L~P#*>3~&Bd<\qCxZ':ʕ/ g}`܈q-[̽ޡz`/&TV-HwժU׮KE+M$Qբb3f(ޭkڵj{DzkU:nhgENN;9ν֮OȑWwɤ$6_F BPժU+1110X.,`K|6ඁQݰuñ |b|E7r+.Wƍ^D$??3vڵk;PT_ҵK(y:GL ;;**&V:n*}/bG'.|]WȘc\""Ii߮IŊ6\y5遂ۻ=gN([lRpbbbdk~p †Ox>oq˱?6zUkTzq7o;v\~՛6şyjݺg}V؋$#xpQ=o@~?3n|[EV1c[BU9W~~} M<%MW:W0̸4-u-9a[=VL+S^ 䗛nu;D#NHH{$_iFlҴ u_|rժX;wvzE{Ӛ4ea1!-mgxWVܛ~׿߽Gz:f5vZsrL*}TO&iFrG6۽LE_Ql-nvg>}V6<Ιq̗|GBgyQѰuÃ:`ƆWڵolu85JcFg]𼝷@zo֬h~h٢Eow"䷡C7n(.ZԦ]]6gn ]vر=IS^ɜ*UgJ:̟='Ϟ}g/tUi!z߅;Ejt۷& N Z683 [ڿo:kK0F8,5}X>lAM$٠U].gfΰw3nul_؇+^+^{hsɱ2|k@׬Y3eʔwmظ1Sԯ?pxFaM< xkou{2 tȅ¨#L|F}httիkNjٲŅ^Pj= 2811!CsZ_~2߉N&L?3x̱6#G]4 Qxµ!TeöJ2enzw±FfLl{Q}kձ[xucZ:Г2>y oܳO}+>Hv%jBB /=?ឡCR%PlLiʐtuJ ۧ?s/&5җIax,1 ڤHYa ƌ7Nk xa_LD/N6Zx('˄5d7ݹ&y랝j4ɏJ#Z|W/,s-[(z{%$띚BrpPf x,IVWaѲe>Kre>p߽ϏmD$kת@ѷOCO?4ms=$uz٩o-3wJe[\+9L_~Wwe_챫}vߛ9~ܘ_TlE߲Ng|o͘w}?M~z趥N}g 3g?޶Lƹn=s*۾m-py)){[3sΣWwë=wN7zn.pa8m[K֭}~u? bm R quؘqWZբEn]4IGbQ=Y]ge>w3Qaڅscή9s2d ٹi#%6jt&}jժO>]?3uNZf-^ʉ':tp ds/,3vv.=׾г^wMj{sO% oܵ #v.=msn_3rCx;}z7i?z˗9w=&"-\׎@ӭ08yN]ߌ_ !5%G/(*W&fWőIx쉃Ti[&K):-cYl$62-!w2WĬKW_;!-s2m_3r=శgqW6-[>׿~CQ=3‹ͻ{m=rMc'{%L6k=mc?|7dҝc9#x{^im:QԒ% m`Tjr1*U qQqPЪci>ѝ uB̘86n[ЬdƍIH7>*.KQf޽#s84ۑ=WεD>\}bMשr^;<sqwGEbby*W1?#om~n5ra#tmȔһözC||_hL2u87PWZ嬶gt%֪UwĊoQaƍ'<oRRR%=뙞~iV?Onէgܷz/w]w;[׬xi愚 &چZ5=+Wwne@~o|]P(%$$ xۀ[o Jچxc̸n]5Ï> ȼ>50/RSC!v'Y$DX+WVZT̟ _K.%I^=)SH֮U3j '~}*G+o˯bFsDmޒ+>HcT/rIMҚ :Bo+DiM|%f)>HQTB`m 7^^gyyke˖P,QO<4k}.Zm-[PԈH7wf|w;3'OٲE~3n|T\zI&<[ӧϟ`ʕ׿@ sn=tD$WZr{f]^.YJ;[z]EwuG72===U˖|橤A4ϓL>zM}e|$]f۶mo;5jx(D$&Oy?ʕ{J2&@.o𨸹KD2n˓wquPĉH͛7/*5kͷw~PM~y۴PLd]¡ZvmT4o4E_H֮U36DũBqժV]O?_~88MhiEug^7gڜ]@ժU kԨaT̟/" AH7>j!~|';nڵ(ODrUQ 9׾]Ջ7lkPpG<8?-v߽C3ajӺ?Տ٤iߟ]vkeoceT];uνloj=jQZ\4lN%wܸq^hQgvv MV!$9{vz=6L63sbΤh?D^bigg)[3Y+zf#>q8re>gK!evJ @wʤ/^{=ڜ4yr9&ߚ>=F?Qi/8*왱=k^{.cN}ܙ/4{Qi[zߟ5hb?jdcFuLyw ;MO,Ui5h}/(@gTP'3t1U\4/n:ܹ9jeHF:%2m{u*7̞3g{(SoDdPnvm5gOr*==}u=Nk(D$ѷOCOo*5%V+2s=$ug{D>jC3)l}Tg~Ss&u+'ж%%gu_f۶m07lx; mgB :^|kRtg|ZQFS}0~T$%JD $@M믷l %@VDIIv1cF/ @"" @6vqWoڴ9V֭{g(RD$M:w'$$o𨸹KDݼ7kV>}.Zm-[PԈH7wf|w;3'OٲE~ֵKU_b_9}}:@T|"k YYO, %Rcp-Y"BۻٺuͣJ6[_nt-_|IDATLD;|͹?:Μʕ+4_NԺuPtHfJOOYV-[񙧒PqK?O2%u߽CPdU¡ڶmo;5jx(,7y+y(WܳO=UTaDD2n˓wquPĉH͛7/*5kOD2nڵQѼY}"q7lii(D$+ 7 HŐ$P E] TL\1񚩡hZFE(,k O is?u1gBh'y3Z=3M6zlE+F47xUS#3vUtH̔+6YgNcM3Gι< 2γ,NLPĈHųBn#.uM_ڂ!]d'?zOϯBs ~.߹-MGn':X~3[wХ…g>)!vhT?~<,fYC^kːYg邨s|l;3e"@D2Xg?])13}jG$)3l\ɂCP{89}4f7~Bw˓BhԬa-e,]9]֏&<癧 3n|Ba}f}eӽ.IʝS6.U>^^<ɻ{;Xt)$so'3P6-Z;sM PU =2cb睽_(|&Kc/i0oƈw+Qpo6PFjKKrN% xabmҁ<OE?~[36hg.}bР”hz!4=u|ȡw!^S g6#7+\{\<*gN;m,ephn/@3u{]M}w3[6=[k?;f}zkd?Y{{vOmp0; @#"'X9w?Yyi?Z٪e[|aЯoʙXO'2c<3`pl#/B_-]GD-\jk߰qc}wKr]=!7#X;5M)inڤq"BD27o̙;7;[nƛk֬9HHHOOv Ne{6<*n/A~eʔ95PmE?u&׮uI ըys0*UZry(L*U)#==TRQ])1k狎>P%fi}),X+:Cv 7ܑ>U>Qe˖ E#ߜ͊mn޼y۶mGydBD$u Z&c-G?l}j׮ָQBD$kתKw0@a7ߜ3gβ˗-[rU:)ɵk=3۞7ޚ>}+V׿E5jլyi Z~z/ P%g?_mLQM!y̸ʕ]VSO9#C}^KJJ @xo֬k%KB:zbTƍ@o𨸹yF͛Tꕹ8:LP*px֮[ɧK^Ǵۿ 9kܴy#cb(ٟǎ d֭7oYfm:ඳi_Ș5qك~m۶(yBcƍK/rZժ"V,X~9:v֭QQ|C7'ޯ)NubN9\϶/濟}OV~0q#zlޟ3{zhcQa.(7|sΟ3hG]~ Sk_3^J.[?s_mjǎgL(IODrUPUV-HyD=cY굪7~XQ\!c*GK8%=S:ؕ经,sd^t٫S(1D$8~[o yi)Q 1οP.qaĊo</O^Ú 9S#ax_vQz&/6bJ8uNa@D2S֭y~l&Mܐ7Λ [7:_20-a2F;ݻWzC%߲cnVCgLnHOfqiZZj/;%wܸq^hQgvv!W]6*lpPZnNMɧ!zW_n]CN9#CÔݾB3=!ErH=5%w_@~owxe˗]~kmN<9BoM!)))kz㎐CR?x2rY;jR&'EŸpblٲ}orWd?{085ܳy-=em;Z}3$S֗}͚5+(|~ئͧKԪY>_Y$wSBp!Tr,[,===#5RFyǔSS;ݹsdJJ+[l,$IngWS5o>0z>εDŽɣ/;oիW{x|ԕW8QߟOHv%j{>[ yij̄)jt_8xKi58}ά/Զ!UfU~&۹(>ӓ]gSP >]䌳lvBqZhvUPWZW^c/Ċ>y桀,hITt'gş} 1bӦQgM'Mk;u?q_Ċ,{ZphQ }c<=9Fm2g܅QQz>YPwǎ;o8d.ժVhnfR*zR=C[ooj2|o֬z%¬Z\Rh+9t:':Ie\wD$טqv4n0* IDq!oԬYs+{_w]Ic%@ӨQ|keB`G"$Ͼ쐋rZjURzIDATG5y}P{%.Sy y{ԯ_?NO@z&?79|;W|"0cAILLqU"==WjM!_~WuQ}ÆG)UO*SL^t٫S(^ڷkwRz"um, \l{2ғ3رcǀUX PD< ЯoTCFη|ŗ!l\q@Q.ZժW!KMpnG7е>{J6;j0{Lp'$$(: 1UzQw9|9佗|I]"SO>1rJ!_4o,*ΛiӺ?c83Įaܣe;Z|W:P@myb soƍ׼]FmoY{ ߛWgٺ/l{F/͛g\֮]8:dsc.? 4h:䓣Xhp%En꫐soKM 唓O~!aCfDJC+W.@qWBp!#uU=}~U(.]իWi5+WLfj(Q~%"fDe!i߾ݜY7tI.Wyo挳:3E1}ۧ?|᧷j B֭}~u? P}0~T$%oD2.6}vhJ=w{:7D:f^زPfr^Ojݺ/-$SO<1VBkz\k8 Y&|=~רm:'>d?OѤx.6]>r {_e|c'xN;/OcMO=&GZ' 2f;LgHYQƎ?!ܛwFNTLѺ$sho_bB8癧 JֵKBA۰qu_Uw䵛nu;D#NHH'3︫>޲Y *&6kr甍gտwĩĻj0t%q,#wZSHFmvOglz[WM9<Ν71+@IW|"kՌZ(h/Osؿ̝5kCM|dʫSyY4m?<m-[S{d"=;{<ߕQ2NM2^XNaHߌ; V.]l桌N5zk#2䎝*J@&ݙ:S:ޙڵbŪ?=IIrqϖ.K:U!\\?l /x睙3ߝSdul_gtlX4[W5c#v' *9ꉦ9QrONN-y_ǧZ.~1r5;?|i3rh(uOgA|.ų>?/v>a_Y>J8\Zwƍ -NOO¼޲GGe/5} V\+Pb۾s>_|޻l;gSlƝ̖MڬᷱOqY_yrOfssޣS~*LNE/P҉H*GGjÏ>^M6}iSބ]'`WX1j '_ fͺg>]$PT=뺟||/;O[~C@~}[Ttz'T~b<gxgA9c#_qп}̏?^nc+a_͡7z˦䥗t䏃|nzF88HmZ%.Z|VZ5oظ N1)S&6iơ7lxTܿ_TVTTi0pT3UE7|sΟ3hrJ שS'nyxcܹٺu7\fy7$%PErsE084vv)SV-[񙧒)N]GQ]L;ߏ^EЖZQgrZtX3$7 Qi}zޡRzzzRRbb}ѡ(KP?hS^Yɧ+VNyuj$"۶m]wGuF :8@KHHhG}UCeˆ̑GoNf67oU{G(1D$),&Oy?ʕ{ִIX [~ڵk5n8Gw\䆋;]D7o^T4k,䪊-B ƛoΙ3g˖-NڵڞqƙmE}ÆG_"k׮͚ccƍ/WlZzʑGr?_{3K.ioy>?R 6Dũ ]Oi۷r?>׸i7b\g˖-=9swhȡF<(>ڵjjժE QD#>^qCȓ_[ʗ;9X;swkZ2>c#Gw\޽ ~Yh¢QQ1Ғ% m`T7lp삱yCO;h[n]|EKD^cƎ[vmλJ %+X>ڼk었$EvNW/V߰ʫIOO@cZٛfcMe:ڰq G-#n9džUF՛9ǎy[H7>j#xpQ=oP܍V{T(d^b5cꘖپ|\;0ua)Q1οP.qaĊo<[H\*j"MOT?6rd`R@b2jy<Ͻ('/Wk)|y\{j[zG}?Qo_tQ3k!9ͽg죐=GGz2C}gC.OAO]'~I^[v+IDATf%7;o^T4lpg LH<|uX6sTjc8e#2F;ݻWzlYhe7ꅋi{fn Q&CzMrpD|^P^Z;6cE+JkԾӲ="_W=!ǽO_~_W{{e{B;=W\0B ^>;wʿk+:֮] Z68RRRCHWcz&S^U櫯].z7tBI/_vz9iX*Uڼys&1c5!$uji=Iv/ yI2aoj&zjF\qewΞ8hx0[>W|bܞv{(/|Nˏǵ{ϺdzF^>NIKz@'LQaP=Yۧizhz S2m<{4no[{{f}2>u{|2.v :!Kڙybbs ߦu뷦*v+Vd+%%vZowr(Q~OF. {3r{_Mw#SSR~䤨Z z~ئͧKԪY>_3$N ^z~=CSJ(@zNXyͤu{Z3r{d{k}ńrȕIbvg^s zjrHuC4v5W&Z;6)!z+qIYϳHKe˖gY0;mqΝ#SRRSOM˖+@i^㣮i~.My,R}ƌkoϘ٠eӝtQ)>݋ 焐lj̙!5zZy=' ymk?qe;ݙ;hb?󦹃2CC{{ul{(䊞{^IiizLCܧnIĽv.d%{FxmZ..ym{ovѬ;'{۾m3U{V{ufl5xa_۶n ~O,9㬳q}БGP5=hsf͞97|#kUϏTkSSGҊ]'G]~e"nQ}'w˩|MڵqԓOm&$gm٢y&ڷo9Gϙ~Yr_\}ԩZn=W^c/Ċ>y桀,hITt'gş} 1bӦ;vxpCo=cĿ/_>@Q#"IQtG1Yf]⯾*VӚtR,_XMEߚy>,| k~SV:%>rsC=׵ɏJO{Q}Ls%K;v4n<+yQG: Ö~U=Z3O%%%Q3.f{>Mƅ%iz(Lz٩o腞Iaͨ {Pͽp{/⋨_WJ>2Or̸Q qQQH"7yf͚'͗'M;/HRTqߜVFͧy{)S&䉞w&ouj١*\7k{Uţ #G]4瞉Ҟwvum<=9D*_|?O!l۶wՍ5g?vU!:~Ϸ~ns `^oɇcpnK_gX`Ak]:n?@Q|fֵK%Fҥ{޾}=<19{ȘHr5%ΐ~Q=aOK&Oy?ʕ{JILLqU!cu_]M7~kz\}QG ?$<~rT?Xt٫S(Rb;PTL_oq"p%ѻp|zk֬'x9'Ң"۟Okҥ~^}4:>?e/zrtlVX 76ld_?l|{ztm-ϋժV;gvʕCߘ~r_61V\}Օ>pȡC~]ȩ7oRJW.IrmrQEi bժիQ!W͛7/*5k1UzQw9|9佗|I]|d̓OQ>p4l|PTJPP:t8w+Ɗokٺ5yujڵQѼYӐ_myb soƍ׼]FmoY{ ߛWg~<̶gҼyfDruI;bǎ,)===*⊐oMr>11q˖-⫯:ꨣrt!c=dh{Z{ 6[Bmظ1*R%PsY&@R|3n|%LʕPX䖯 97/KԐ_N9^x16dF$T9:PrM'"rժYQtpHڷo7gֻǍ|E!/]ҵKUޛ9 dEQq1(1,MMvw'|Xeˡ"b٧ պu_,ZITxb_7H%QnѼIR-+~tiTpժU PbH%T[Ef;vxl$۰qۿ-,j٢NSHޝWQ?d"HDVVCZqCeE k"]@ZTFb[5fTMyo2 y#9sfan|z5"9:mժ/sL'S;B_v5>$my+ PƈHWk>k֬K,^$F6_?999NO;-͙oZEXgF vyǼO>tT%dpʕ~.G PD$ g}vu׿ʿCűqg<q|Ղfgg0gS۴9Pv G6nxɧl]ȝ^+)Ǎ ~q;nղQÆG~{v {9U>CNLl٢ywKTIu9ְ·߬ueˣ~{,E>3|czӦM7>٣oQ;GVR9}Oɲ͝1w? P2{:lmLz ֭WիX$$U?s 6IY3o|IJP^>vkR(?T>)X;wk[V-[hԨcmtuU&̛7?@q[SRO7\!#w{Oq[,Y$7~ժUՐ;C:lTA(*Վ{*V6yWJDz͚z^ gIDAT5CѪUMƏ_n]2)~"cOZl|㍛ouƍԩӢn#8\xV;4Vl޼yI\|yeCFM}9sS9xF䄁3B$9ɘs(k*#͛'E K;s=m͓*VZ**i S9'7 WaNa}kֶSy?_|M(&"ĕ<%+攩Sc-VKM(q͇8>iØ#;]xtb3&bΉsALdNr>ONlqbTDŽX OڵxѢzuRO=/ ?6TZ 㰻Q#@:!wSB;1kjm[mκnh0KʕB\^b[oz^LO"ěr]w Fڶmbi}:άSZĉ}vظacG/Ztg7P,M|ZE벞O|X>u(&(*tGJ~'̛7\vݖ-[yo̘2UT f(HG:**>a8MNnW/sϸp`^kR '{9|[3hۦM;_eggd{Ȩ(r"yS# {vg kαv9焲ayQ(" YhН{9 dPԯob"" @)jժE. HPlٲz].V7>3<#HPo~#" @;\}u .6o6))@DmƛoΜ֌7gN6-MJ?>%#FFM(Z"@̳33͛tٲ?<^ݾSO-^Hw}e- jp}2OD[(=6l0/KݺvڥJ*!~" @)wߝ}fm~x__}fM5jA6PԲ/yȶm+W~ʕ3-P('"lxw6 B@3gNTj*<;=3s޼K-%R:uխ7K=N?(eM(&"@ZjUTn2y}>^(Po?2:C>͓r^&*Z&'aÆ[zOGFO3to7nИE(R58⫯+WLLL o=fmva)Wai>^-[yS&C ĵ+V`IHSnT|t%y?i~z~|dItuhAzJԙ5k֥<>X0IHuرa}GQ}/~Gj]3Pz$KLڮ /72#ȉHEGLO~'8@'okc„PD$"u~t1Ċ=-[?h[oŊJ+5rtq mڴ鲞Wlذ! u9j(򇨘5ݛn'quC=9#;%'$omMƬ9n;dPr LN4f>4rK_1.׸xLn4:QQζO8[{PL'"Y^ݨdҹS_]գ~E;;?5+*i!yā2z[c|1 {ݺ9m7.i?5++;opąNI^ݟsȧ-}eE|b-sߧde-Q'yNaɈ{=3qI{9oL{p]71~ ݓ s7~_ 2@1IID ۥޥ#?ZG{Ol֦~ Bh?m!:=Գ73XҸul׾Ͷ3&.l7ݶ{Z2q>uz,Ⱥ?3{[F3- 6ܩuwPvf <иAp9;07G;syVvԙҺu(@qxqꔋ/_6Lk]j̽{raQ1m`/L%A&y#Virህ549c޴:@Y"=犌QKBrυ7>8oR9reaO1{ v{-;10s?tb9U8b=WN;F#:ʼnQNV֡혽<秅"ۏzo o@~E(UV}vב5ja3\2*cƂa7S'9C\aZžqOd\hW kI /N.qQYтmn[,;gfʅ7{cSFnG%3]IuxAʕV͚g&e!~f;~BTt9u\}E_7>ޘ1#%3̙q% 'NB~3g=,g8G4]fyNt&^0"׾[xqWIm67Fwu z۩r5ϑ]x#hĒmozN޸d(]*7pΎ?c}Ż;OܫkWAY.5{ݺvRJ(>\|yJU^qyXF/Qu¸_ M{nxq\~c ‹{g Lxq݋ܓ4ddb=Tι3+{bY3J"Gm{tJÝlcbvÁ 7<8vaǜ)$%v:̹WދDEڵ?haem8ꨣ9eXÔ94ְmn];Vi0p7SV6l8,ҽcoފ3& c^l(8itwFxIDATkdĀ83g:^14mX1qahpOw'kvG~ rwr5X;q~}ȉHFR)Qd&9F63wc۞s=v\2*<9w/k9y,WtJ:~?{r/ސi␛]\{ MƬr7 a sˆFrNͽ r wu!z{ߏύon\[좒s~ȋHh<@AKPZ{Ȩ4E{?QxϷ:mZc5;lĚaxjvJǽ.ݟ5.;@s'vB۫Wrbo~?陁_ڹϔ u5X._aWbAO\V=,@Nl$V]v`{Jx=~-Z6Р߰{{,N#Wl%~|-[t#p™gUD1:w_(hmfe;5wbVߐ_ {LQo>'sNT4HI믽&?I]z?Pz̟9?hƾnuQ P" 27|ٱ>e?';ǧm(dΙ?O&%e~pH SK_~hkRzo MD$ujժ=3?ݽ櫯J5rs P'"Y^%]s=9vX{cƌ@.5{ݺvRJBfmZ#I Hq(~"cO];l@. mU_|͙3`>[WX<:9ɉmڤ\xGժM(&"6߮[.׬y?w]wq%Pf UVugoGڎ:HU+ ~͟?iӦ?<9ykjщ~bPV.]%[\s(K/lK/sEEڵ@2$ਣy(*_}E:#^u켱ݮVŞ?mݣo'ԧSԹz͚?kF$E$"%"I3,Ib OD[Q =˗w|㍛o5@!{fҤ~CC*iftONޥsMϓT\)n+@!-3|3 OD~Q IRS~hԨ-[cW_\2iCf q;MYx{ A9CdĀ{QLm%|M;Ğ?2:ڼۤemǰl<),\...y3z+@ZjUTT\~g\h?Gz8'7 u6DOi\Q/o9ޑv?̳bᨳMJ?>  SK_~hsԩr瘜5Nj\ܾ+&M\PHt'ѷGV8Bu\e>yr'?@q0$qjժ=3:FgKB])6n0?+FvJNHNn2fŮuj\T8D8Pf{3Ǟ8ODr Q y]s{ྑm0mڸ)V, S<4Anߺ1m7~fʈ szf LH8mǃ,^7=Ák?\ue(>3زlSj+.k [l+/XṳE!%uN껻aܙ[g&&'V>>εj٪=~qrZGEź}9E{oq;Eܛ:=dةoqąAةAxqgtONN8#&. :u$ g/zUV-@8/0*-[1at /bclҌo\G}'DTw%@\8WRJMC>Ƿ֯‰C6Р߰}'-G +bꫮ D$DznM~L3m411{>'z<ܙ3?hTz͉⚈$u--z/Y՟%Ϫv~m&h~7"qQ P*=zO~kc|}VƬi?>4;X}4y3}ckϽ:Q'/WN>'" p4?=#ゎ?tqlo}c-H{쿞Tne@D$u\F 3_{mwC vuի('"YyрqՇēO7EBqqe^rG(K, P09[k(D$8$" ġH?!*w-~"˖/, @a_DDC"@␈$D$(,w7hHq\ʼ%<ᇶ˒$j'=4[zȗ.ܺ7|? E';XD$u췦YW7 =?|OfM|-}ovzpIK>iBlz??A\Nls@qdzu;qy☗wr;_f_S?wuÚD('ܺy~X? mK&{\Qltz܌dܝ/ f -[QG$m7g1/sf%F;aǖ;LN PD$ymiȳz䬵a]޶D7@12T2gܙ 7v|hiY֖\Â;O< P'"l`0[4e@C[eIj87|駋];u^Zb⛥hϔ u5X._aWbْPT=zY$ xѢ|QG:笳j>*~:jX;:1mW{XP @qlF-[4ս P2Eʐrʥc=ڱ:@͛4n\J-~"ݺt@>ԯW7@A{'kֆ bŜsۤP'")Ϛ5k%/ YӦM?_1uNjrb6)^xQj T^|)V|'"vg]}GVYk;~K~(8\ȍH~%@3ޜ쳥˖NJ#8|On{_},oknѢwMJ˗?ǟ3K/lK/#ヒk׭;CH?!*weg{~(/Yn'U˖!.$$$ui[ѐvǟw|FɿrLy-~^|y-dm6oF#wRrG/t;r ㎨Vړ?Vz.뮹|5j0Pn7@1Y$櫯&L|&Pw=F!gUͣ_" SeggNJ#kѽ{(*W|uny@~_󎡁ӽk%$fϙmڴu9uJOIoݲUT,^oVZϚ5k%(F6_?999NO;-PHaժUQѺUP4kִJ*}]^|gW_w+;$~82^{}=#"E(y:Y9:Q;')w,7>٣oQ;GVR9}Oɲ͝1wc=|MW;k(s΋ڵk]HRt:("9ODuT=J1e/ftTb޼3ve˗NJn]:ׯW7P^>vkRRT>)X;wk[V-˙~Q=} F$E$݈u@ItJTȢ(yzUV-1͛oDz-Zɀ[F)?#w{{hͷ,Y4P_-7dzu(~vQ1vUVJ-[;Z&?|!gjF ㎨8ڡAboʡU͡w(ZE. "~"|:&Mb5k.yEvvvaYfŊJ*]S&W V=+b?_g8 5CWN)Ǎnݺ@Qٲe%\67>3<#BDS|{G 7޸[E߯6vX/:nj{{[nNLL e8∐%}zuM:-MW?CftON>cc:%ҹViߓ\xV;4Vl޼yEͷxͨ'$$]HRڥ^5QШQ-Z~فŗ_.[<~}l>ԥ[+D{[MAIu?Cak)ɑ5j~83xEr1cdžZ2D_ب;vɹSgpm[^+is9sO%ę=gNTzJX[I'ѫ% ɈΕ̜WA{'4F,isvӤq4Ji$W}Exܵg:ۤ TbR)_|ɥ/J9eX sLN ={\rڴiZWO:YӦ'9Y zNkxV:& #26xִ^N~3^?<)cPIZ4~r֠Oa[bEc6mR.jḭVw 6f͊XѴi}gsid.XB3wV{-h7*ٽdz v܍\f8h{{QX ~Iþ͘<.47 {ֶC3ƶm'81*cB nn'BU>?5q#8xxҠaS=_{E+sGjѢBذ '{v;,}pVY3o~͓[>ӻxg'IDӆ؃sRCg/R+g z Oձ^4m7'UF.^R}Zxa쒐lrr4 2c`mph۳} /Y*U(Zjּ?=3a|$Pԯo9Iu\oR`=Bbǜ_!+l4x߶^I5dnS.*V_5v/iWge=s~~QJ}[h;Ob슶>s{̚;QS_9̧37+s5&†ҐIV1\w\ny(6mܴA [ wɷnAn:Y_1 /v?~ Y1Sr1+v8v{ >mܰ1PTڥ?>W]%~ڦ4Z@!;~²SRRu\^::c6E9Q[{VNz孑]1mԤvX`v5k֦PI!ۖN<*gĤ}OIݤ//_Nj"XK/ܲU/~pBB¹ka_wgvkIɃs&z9ۖ؞}QJIC^kJjꑱ)J@޺k#aPۖ.ct3#7>y5Wh;&UT ﲞO|X>>Fv8d;ͨ:=d0q{ɍG>㼔 NniEEΝ_%Y$0tP!mz4QbNS/5{-͝Oqۼ/JB+91ۯ%WBBBz8=kګ~uEԿz͚?kC=k⢔z9!铖 GY!DnvƂM9BG֭[W^㰻vܼyҁ#ciIDATuTT|8}Ν-r D;ݺs̽{4o^ qÆ>zQXv$1$pr?Y9]r!Y_wƆ g5urȉQ歲krvh>ٓCP{ [W\6ziP@*W|߽#N;~\xɠoBH 9W&}?flh3?&nNAIuWZK&Ɋin6e됾ݭ_}2ցQݶM V^=O|E$C‹2Vqc:5ľuA1y\:мd%$pcqnGZU`=ϮK~רQPv+vom1;ZjO>X#c:~7oz?Zmkhăz0gd{b=/;!+o/z/g+{#FFM(Zچ2ጴӺukGժcŊ͛7NOÚ0񙨾gCV=sξ֮ {[xo3B[1jIޭ+WuB+.yaJI(:VzucrJ\+WUQܿȇSeggNJ#kѽN{ǎptn<GĊ毿zێW }毾j@QZv[d4C^iݲUT,^o 9sM6YF臣|b|>H=\z7k̂ !^ԯW7f͚VRヒիZjZjUTn2۷kCzݚuI풚ij?sߘk3_~y7iJHӯ Cqf3z+VX?>3{rֈdCvםժUaO)!!a[rsD?!־v9NT2gܨSPh: hҸq(~tI=|$@I&" e_~lXU먨7o~`>tq(yLbڡ0o֬wޚ0~l_J]:3gy,~;~BTt9gڔ!~5o~JT̛3;o^TԫWZj{9 ghX ˗/+߯f`˖-/vDY$@j.>}v# CȚ5+VTT>W_$~f80T#b5k~qe_^јc~OTz͉Joi/m&h~7ip1$ %^Wsg~З_~o eK룽z_բUJ^>5~r|qP:EʄJ*Eņ 3;Uv]âͬYb-V4mt;cܤu(%LeBգo{0NGƍ;kj~{Ȩ(rf2aU*W>Ijժ}:^xcM~~ez;/>z?xիO:P"HBаaX CBB¹k̯:sƛ{I'6 P'"٭K@qƌ:VT\ POD~ȟV8#VgvT'7o^b%Y'իwڕM st֤TʕRZj"qjDIJH.[<Ӱa ,,bŊ-[4WqlѼyR%!;;{;B shão#~}Xvjժ-[]ksLO PRթ`ݺիX$$U?HPlre=|dN83*"FoQOHHPHyk[payc_II PڈHcƛoΜ֌7gN6-MJ?>@)$"Gyvzfy.[2zo =bdTԯo%"oN+|hQ(jլ9\ueRKDr6l|oQiڽ[n]TR%@i?n]:wߝ}fm~x__}fM5jPzOD~ dgg_m۴yP zzߧN S#Y$ƍ0NJ: @i&"c>XQr'{\9k@?ɱ'DE~8s=QʀU_|͙3`>;c͟؃fMX1uNjrb6)^xQj~دm33͛tٲӧJ;:u;֭=4 ~"˖/jΜ9QѪU>Avݺuy=sL`VYk;~K~>/ZsqJ .L\w5Ο5hë5kڨQ=B͖Jk׮{?M~~i-jv=zQǟxB shão#bؽ_='?YdiyՕc5=[nG͆ dG Z7.."t1m۴yq$2`m}]}/4mjSu9 Sz˖aP[#رQ}u 碎?ɧ@mܸCꤤS8r~tI塨xѢ=(Fk4%UN~(;y챍b͛G]=bd:>,N^cGƷqQ /@̤IQqu*V(+WϨ~_ jS΍ķ6*fϞV!Ļ5_}rʨnݪN{_y0?i}O[Kjժ2gΜhˣ;jJ褓Twwg>d.Z***W|? f͚YV}$Pޭ[q9jIDAT ʕk߯fOpgF-hʭ!͛+?ϽCqfQbEQaÆkĊ'rJlhѢET,ZX1M N-g<U_5+c֞sLx?v |Yf {5+;+Pz|؝3vlOoNJԇmmRRBI&wSozؓ0j;? !g{N혵y~/;V4ɕ&5C")-*MZҟԢf;r`n>/h櫯z_/7|`3|sĽ#;w~g~ۤ5*4I۾+C¨Ggeg莫G+؇;%7{ҦVn8d~D]a_chM63ޤ䖿g/[l3SRr7o:Ț`Gya_r/mN:5B3KPVz~/B ھcv336ULWR5ޓ9sxG4•_G!!f͊(Q.TRN_ҥKws5 .,+o#8)̐]~>$.)ҬP?yԲhBPBINY=kvlN^>yװX%KzXk!,;ZsL㰻Q#AO4|}VQZ$ٙY;Yrq±r&N TInsr7!#וݾN٫=~?03NO 0n\wWqc3v9sP`Aϙ8-c~PA.V;+Zbma!qgguH5ih(EWmMꝜvH5y۰r=s֏.j(yЦ>?'R.VXlْӨQ-Z׼yrԯo(PV;<&Cf3-9LN{uiNVruǂ]opۭ@aoJL[7oQS˗4qg12lfyJīHv9)2B5Ao= 6DGxGʕ BCrӮlg531@dzu;I>3;uֽ1cFT'$$|R @)cmUW_W?jժN5vܸ%UD$-_[fe=-[\rYϵk(*'7nֻ4,x/J=)M9<5ɣVFƍou7ț PLgШQ-Z~@;(%R4++;Op~睔?2:@Vfl<)JF.X]{mۤNi: fP32&=;3+zݙ3ߚ̩Ӧ~zs%RH0/_6Lk]j/F)VJHST[ %cZ+.cSnO0*xfWVrSJH5yݹKoo jgd䞧B3 j<n;(v?j% P"V38#k+';g(8QFojŸSόֹ^6jԲܣ$dLgSoSFWk'=;3<2\*¤49kK_(jּ?MǸoVJ27dk/ǎko̘ DәbdNHޮwŸdOΙXrA9>PIjPIfBŴ! MjճfzglTF@!IHHH=ݺvڥJ*9#~}Z_Wew^^#C9/w!7kBenm0SZ1ltu:1kP_3g?3cS+!;;{;B 7n4[lyTԯWwȓW6}Ԝ*~eJ5yPN#d]9)yʜbZ2GTLKlT;*ZEީ*^J.JFVH98PI=6oYڦȜxrKƊ޼PT=zCD$ XLٟd<IDBDUwD$8$" ġH?!*w-~"˖/'9!9(,7HqHD`~6$D$8$" @a{Ȩ_EKDC"O~~y/]=;ÎSKis9Id.%>/Zsq c)S~!]{oTR@ ~4X$DIDATQ  623~~|$k@s ( mP0;֬wo֬iF; |ڵ>_:mZEڥc^g'@ξ#۶i%&&ënZK老}w7oU+׫עE~(FO{4a5}0yWW+Gժׯ_E[l H?!jq? #N;˕?(?:餇PThcOaY|yEk>XQr'{L>@oV/G D{챍#gϞ}J PLD$qװ;JoYD `nu@(s̉VZja׏G'TJ.V;{"ZUVEEV-\rmRZGU_$eÆ ׬˗O:@jѢET(s mϟ?iӦϕ]OrBr(&~e#=,5kV.SNT{Js(\Dr$@;ok@*1vuQQ P=#~}2y"&)/ բy@AkݪeT,Yo P3" ŨE$ǎjժ@A=Qǎ?@AKLLLJ:%gDd'@֥s>l5";;;pplre=׮]p™g(}o!*3"7 ?ddzuϑoq-ƍ|ˌ7ߌ6 wH DT0{c׹SO=5Vdgg_͟??@ J2vQZl,9ɭ[JvعR'xE)QOEW8.'v7r}nm"'w; m̽ϳ[kz7?moMBvU>߷y'mÏ6o6)) m0vWG +G鄭n TOn>̧37X 3߇G9bʕ+SO;~I =* %VH6o .lvznoH5=vEA$Pz9ٿU ^ɃB?%wFHsY2;ٙ}4Bɽrweeι Oou{ӲFw 9_Crn+[o6IG'L0V~yJN}96zY[?eR.x!Q%]~7q]~Yh&%wE b;_)Ð'v'7d9 Ԥv$”֤B$m&5s$5߇c9fãy:7mtψ{[榛yvH ʘ<%+攩Sc-VKMY ZWT';Jel6z[טv8U4~CF7;GzXk!II0)cЫSSeI^5!)q!λN+_͛ws5jԢfC싮ؐM ni͞ȜTPry~d{dQ?kngoX'@?ɱ'DE2jժ=3?ݽ櫯,&gR(gfy>ӵo蝐70;GNrȠ0BƤI.;p>2gv"/,.CaԲPKDž;N 3fFTh"MZ4V&-jp}2@ ? m/[/>5;%/5~؏ā#^Y;%ECDJ26rpJm}C;=jerLN%}Y9?_YF~Æuy($9s.N  i:<(v)4tSFs/<[EkvMJY$|W:pŗ^ĝW32J*ݻw l/3}#~}-I 6hcP F]}I{sCnoE)9o瓮!}^a% &^ >3 }2IDAT>:}[:HD$ǎݻv@!ZШ|U(:&gF b~gf.B/QݢIŐ1kV22ŲD\98w쏊ų3O' 5~z1adzҦP!wBF9ܧ. _5rUWNHH_ge˗G-E\r]s{ྑmJ iӳ۔ѮC;l[b{grprrBrrM;UюR4+l/!!]jsՕ% mjժW\3A;Hwj!c[1kPE[S^PwĐ;uÿKZ3B$ɚ<(OlT&?v;(M]j)@ipSI" m&I4wFgv4|pbĐb& %m佖fVNOHQzvŽ1ANȝq𤜬de!l|:9hHZM풓˟$!ɃWp!gǶRBC;l=#[tt*-E;a {c.yJ(`Jh]SWYEދݬW$D$(,w7hHɃWig␬ɃPrHϠYBPzOD[ W~U88_nem H%Ŵ)@PD$ǎݻv@?e˗\ԯob"" C( fmx'" !Iw'uuBPh.EB.0 A hBSih. Ă c)H (afEM,-i$MMڤIn﹯sssŧ HcʕgliKgK`e[+I`{jD "kE^`oŊ4"" @-޶f͚@ZH[n5@zI?S}3K222٦MN?㬗^Z OܜOve.Wy%>U$?X{y0,(U'96_׼8TN-oܰu]0~zdUweUYxnvu5,.lj+l( jSP^a𣯯 SQp~9'է{敇wymO< OI`gD=DQqħnTYP՞]rN}*%"W#-9 `gjʦs6oҲ&/1siq2dAr՛]G!T7vmM[;߼7g%}=Z:۞N6iN|*k~>+Բ%G{m_uho ;yw9<#.(^D$%\r]_P7nlSTʰyp2~KCG֡^U3#^R՞YZv̫83̘Uvxn,dai'e=ړQ:^v\W/{&?t 3@zI-}0M;֕WaRƢX,#ZuLV웕LPܲpc2\X2 TevuEvhDlj[Œ^4ou퐬wU-ѐ)kjgs;BNiYd|uȮN6t1cU߾74@zIg>Y;w^۟׼c]74g !Z3]Y45dT]8d)nj-;Ar!jJLQcGNEOtuaSG.MFEQ_#{߽?{Ntdm`L6gۻK0b; KnvB1.xPyo(hj숦 ga򮭓EI{j1XFs z*CڒѼxU}kSQT~l:iuv:I`gKn\mM3g 5XXӼ8sCcy3y5gnܢckeu{gV%SUM!,oOUQzgּ*sc]gvszXUW_5,Sm!WgiKgVvύCvXU1n}Oʩꖆ_{AI=JEuqLmVUFm{=)(adΆ]ײyQOs]+%O GKfi]A㦱Xۃq>tժUFnn㏭ɴ= XaD"I`4x{0NHe#" hzoU"TYP1ҺyhD$I3i&}"ةb0'"s@H16D$/ADHCۣ'?~j&H~bmFE^`H؉',mj YQaK0D$4$" !I`w߿?\rٳgq?ܘ_&.[<7>"j̜93@Za"+YD芮dv$0qхع!;,jX2Fz" -Hя5n5kBVrQ -@۟ةe'|5񶶵?Y{ICFFF`"۴igKC> -OܜOF.kvӲe_rY* 2bXցKRK_ac;_rG]+i@~_ύ߯?⨇ǹšΊA5tlm!J짮8+L,>Pݸ. ptAAt>m;͕W|sGȶ'(*>]PpTQGƷo{f&nނ-@oS'\r]OH՘\ƟXҙu͋Ek Q;gɂXU]$}G }ag}~H/3-}0M;֕Wab,^Ҳ8ԗƙ;[JfTFT>2%ZT†7\^9u1 ߖKD$W?l r޹wƹT̎ΉU]#PѴ5YZ=T4Z5+{Î ,G~=s iӦ}0NCooMQaK@ " FKCNi+}0sCcyns%kCޜ"ﴓ2xeO, #Vk*";mFI<cII 5U5v$^v9!fTюjWwY_H]PVX/ɨeD[fZybe5OJ-kU&iIDATyC`'Z28²U-:^߼>+06HiHDrD. %" !I OD;5^'"s@H16D$ % ` "@J-5>S0ODrm0Z.cDDϏ?~]w7?O>}EE9ZRrrVVVD$^{˿޸iӦk>.~?y`QE;0|~|ɿ`r{_Qti`p{oyO|ǬYؖHx0j9$0_koܴiSuvv5\T?o<2H>Ha>P9=s%U?ڞx"%=UNM 0nY&j>|$l'?ҏ` Gۣ'?~j`b5CíT̋ӦMW}֙薙y'>>>?W~Xg[qSFFF`[vuרqư]:;;?s=c>g?Qvvv`hO+iϙg|&^/ksrsr@?3g>&7qׯOoeK8^0ohKzۿvnET0܊kV{wD;ٲB@oI?SO=jo8U˷uٳvEd^/F;[W~s!z;oQ|ƫ. `[A83`LƳz]`uo򗿄Ԁ?я#G '|ӟTԾ.(DcE/ ٬C9C'D_/ N>mo ?Qo+30Bqŕ߼@/]v/4{ǬC o/q#4$<o=5N>#/MA)wnZpko~szQE&5kD0LGՕ[Q:##gʔ)Gwx?U$G6l52w%-ݑ0vؔ)S6msϽox[uW1J>|.$=0_@W]}MԸ \%"߾+WΞ=;sz9&E_[Ea|ǬY?vvvƓ?4{͵E/V.~e;kӦMqK/K9`\pQfM˖`,]v;WDe.b3:;JW|lG?_ bݕXZy%4(^Q#"Xɂ0Z+b#vb;__{ߛh$~z{^ODv.(#!>Z779adÃJ}tSSmk phlYp|٥SN c/"ymGsIr$~Qqħ;řJKgSWs㡰gݫbI57&*zgUK]=5$YSjWj)[Yq +/ʋ(𗑑_t̙3_Huv{UAeS^T6m馦ͻƢhKr{BU$W?PV͒_DK+ XKΖwIP#dA%'aVSauGQtVo^qeԏ2,]fW&n8MXvuݬOC*ս*%sc;YX+j.7$㼻v.Y@.TTlڶ'!'₢ƪa[y֛ttN{C*oȩhY*[UQvFjA}{нIDAT2N Z< S2q{sk{7W$]* 6/^l=}y O:u#瞟UVlˇ+Q-EPMe[/)jUxQmkUֽ鮽kݺuWyg?#,3uμw0-Mx\at%|ɰ~)yfU퍋0B*}~&@ۑiӦ; UϿB[M;_ۭ*V#+/nF:lSQ\wյQ~&5fts*n̊/vekNf[IK{V"niUjogI \[/y%Eğ9;<ʐu͹ -hlSxZaVc*[Pf\I~mBf~we |LZ+SkYO ?R}wdR!VVhİ^rqsE^`@r޹wB{U,ؐCb{GOL6vNp2N1|um,{ n]ݫ,_ׯ-.9C9Hrhh:񰭎W6n1?9*q!#CO=%mb{8JUKSPWwj9 8稔9ɯjr ږ;Y~HRe;$ى\޸aʲǎh,}t¦e;ґZ:& 8~0[ye  N =Mƻ}r(H[diӦ}0B1/Zw!Wז,(d$AߍdԆvZPZ;`kG謹<ھ J.˗]F79uڢ kn(-(_֕M3ؘ_8/`'A֗2JKYżPP|0;餒O:1֭o۲w=\&wp]7V5_Տ}sb~k8J/ΖTUQȞY75;8C'׸|yT2y3$KF9a~j 5m f._uG'.kU&kuf uR9/!|Mfdc.8*?_=jX饮<% m(PQ1'ˣK ^Bqrrt> fĺ n~ u-K7v}EM8GmӰnKjV'V%KW*-A߹|I)BaMddu֛tl:L[ܜXOxn,֯B۰ On=b^6m]{-7ӏ.(>}s~'㧞ڳu_nc)!%* 26߈1hxxRcocl⨪_Eׯb**;Y K~"Ru=JnsʩͅQlUEvv4 Y>? ϝ& ~Q==㾥lUtى'뮻r>K.sj>Йg3R`wBS~Է:*<d5DX+h/EΆSx;X.n";ׂQS`Nk2 3{d5sJM󺋇FkM6lU4kSվGO3l!%}Lx̀ݵDgW?FW5šTisD;V㿸g]3; ='wxIQP8Y+$ݱg5),6 {R]PR= =}qsOύuyyUE[g\Hb%N{$n8򋽻dAvf]i[yc(Ib''[YW{gTt&1L LRx { Ξ=9C\{Iüs_/YrmF#QP#x,Ci]C-(ݚC[W~>v5ˣG1wH*6D1XyW.3=q8UW_5.0z>s9aZE._Fst뮄G_oQwMf>3HTbÎ`ͯj97nLwmFM6Stʕ+}x.FTORKgKH#~huf$6l%s/N0Ccxǻ]jUc+x2m0T(qgNJ>2K/~[;W\(pmn30eʔ0h?ӿ${,j}}5jkvj xnv` +:BF=c! }SJJzڿկ;=a2[PjlaȌZ9q I/k;l8ۅH`IdnVAf͚QPpp ozӛ^|D{a2jַaCW>q8ۅ:2jY>c%>Q^90L$C{kˆrQO}j8ۅúN>sa2b3%" iSw,+++ Ӯ56n`o'`PD$oɏ—/4 =vjF5֭[+$&a`M "77}«5krKD$Pet6m:^zi]"" <ϭ\2NW^|}`{eAdeemذp|٥SNꖆVN-o-UYKO[XP^߱nr*ZV(5]%vVPTYPԘ\;n}M^bzvY\]TV[ Yh5[(]]ݻ7uʩy[9xnÞnq}0HOtrۃz{^OSEn>!9$###XxwbG|mh[5tTgG⛗4Ud7 -z3+rz5R7'lYZ %]xIbW3+ZR+][QPj;+8oNkjdfi{ܞ!T7&sT#uuY`CcQI:jGs2Sd;qUќ^VVГskWֻxUEn蕏D'tF[u5_H=y3'_][PI< M [7~ ޶#yw9<#.(]'"gOF\ӦM&yfU퍋}EɰcuvXl~IDATWR]1gϭmO+.Ut4_ٓ먟}mjm[YR eaX excϙ׸!Jo a'KW *[\V:ݽ7-9uU0z]w3NU_U_%a*CvuMxvUm`aW06 G5[RN,[ղՐbPcP߶D5tFCK;'Sy|cG.vP[U[{!kVD䶮};$szuiյ](CXPR:ѫnAUB[f}cP]jh3.GuL /0Fҧ$0J>ny{N>{= [6uG#JTȯT1;5tr,X,dH'6Xc%C;S3v_Ej,k^ܕL-<0-I^NkQEuies#"v{j.ҩ_y3uwDެ!i뽫-1Fnm>SCl‚C5;"~uv᳷v{374&%)YrC[Wb2Y2̩hN]9;SL0^+ӳ-QxtaCcy&M7 8MCu/޽3mI`t,ou}* 5,M{|W.lUEvbW93bkhlPoH$WJnUa +6-.mcXq&f}]qVGcQ2칿EuB`p`)H EꖆSS򌒊ΆX~fi]OT1fneU; Uڍɥe ]2jS ;OL흘,kU dvXy4QRSس(^RԘYUPYܜ/Heu}<%Ot~CyǦvXx䑮cfmjo $Z8/o ]RJ2} ܚxntJ}=S^ s!ݘ٫ۛ¼TJ"rm׍K켠miTu{S.>)y>{RHF$07Q%lc`:s;вcLoeqYCgٶl<8-sn]٪7[][9np-g~<tkE^`Ґ$'"cu͋¸$V>ꖆmXD$ss[QX& -B lE_[qIDHC"@J-5>S0j|٥O'"g@-]xA1"" !I H#f=ؖ/]v/4(Ґ$]LzpD. %" li}mmmatk-|QG]5fΜ`8D$-~Qcʕԣ+"" OD$?S0:3^yw=H~xEn';&;;;/ﰨ}«5krQ`8'" ??j,iٲ;ݦMN?㬗^Zhr!" }oyٟ[reK0` ?/?G{{{}KNvX뜂5y.ͩK2j۷MfxEd+]gfϜꖆU6w(!D{˩hYU̓U묺‚XUߓqCh,(j^{cDj+p~߳ݼ-p^yC;'&/]P`ҧ-}0kvGG«;]|oa-nn+JMlhgIkXy}(^rNp^*hز8W#3rEN*lGqjDsZZg4JU-uM۫Jͫ[).(eԶT$wyCneiv:hVx /!X[WXsCt}[itFW.CcQ?k躒ϵlUr~f #5~| ×>>}0BN)9w1mڴhgV޸3gu!}?uMMBvu]qVG㧻rw Jί@97 >o+EFkM:ʂ^j]|Q{2XV+\%ﴓ2s bS+4~AdȊv7sI%Їz]wݳN8Ww.8~{W}KtcGVq<>ʺ $f$a^ЙZ4,i/Y{˟׶5P[U[: I9*8ohkXF4UWꚼڦ0:;BNiYQݧfL쵼*V#+߭Ǝ]:{:),.5Q^rqs0]tHTFt-7/s)gׯ'LTmIl0lzsuaSw09wG}URUXF,Vر8Γ]T7Kf='V,uZQTB U ¨**,w{O+#A"v{j/ ZC/Ojdm” M756?._ŒYKTޓ w e틆5v*S^d"'J,v0^+ٱb%̓GYޣ'}tCɺ~K?N!" L8Ω1ₒڄU9f}K]ih,u6C/Zw0YR1r64'ҼĮ*fFsbK[we%Cީ$z~CKgEv8ԉgW7xnZhrDb:W zvޑ[bN 2xS^5)[+ {S[g&DxnmjQLG2:;;\?օqf=GkE^`W~+CjP/_vi)z--ZE._@74vwUV%?"'+caL4"@J'>vjS7 0n}M^Hף@Jdn˔)Q_lC^0flÆ.| i}mmmaezg̘|D$!=~Qcʕ&GW3ϔ<"j<̪W^y%?>U$oɏ`;DW_0^yÚ5kn֨SN L>SErF\pQfM˖46mtgҺD>&" lu4-[yٟgϞ ݽ\?eחgIDATdd`\tHTa|{h{W.zEv.(LJHB:niwvvvtt,;qLJO<stQo~L|ׯ_w]w3肂˿R'"_|D_zӛ 唒SW_ML>̪%>EQaҦ-f~~gfW =;R*( _ޓO:)$ ~i0>ϓׯ0Ҩ^ӟJ5|꩷t-7?ȣ?o_x!@z(|{?m0<ȣ+V&ǾX~+}"tÏU${5k;>N8cH$>1ѱj&1됃|{Vܕ2wi30jo~Zr?#|o{"s[[o>LSOݱVle+[\yM=ȃ:O2eJ1G4##dȰHW~w=9^{SJ#[\E2>[ꫯ:Vg|ЁƁ-vW.39=jK;}U[Ɠi{U$IKDHC"@Ґ$;6}0޽!0HiHD:7m 2!#+W={v`?6s&W^}5j o)SbW^YYY ebF$WH]֭[~)2"y˭Y&p«{ڪH=&dDrϟqg;;;0k.3!# M˖]|e`AI,#,ۡuNAy35>VXyYgS&jD2Gò.n~C̰]*Շ--@:x׾\cdf. ϋmOWbU]ꖆ"E!tFc}{M%Y6#V3xisͶ⒉ 7⦟ׄh{ڴio]y>{H#Xyήq+f6g7/ZT^+YBaMsuvKShԚv>ic+LȈds^{{9&Sk3bԧ69@pfiuYԚPګ+[-ɛ535mt{[Qqқ~Ӄ<0 dBcڴi='0qiӇO.Ҫ9-ʶJIs;g%a4޽!0M*ҜV&GNiS("ldS̓N 0]E4S%NAyU,V5'$V՞hgl+ψo^* R *6 56wcyn涂Ǝʵ eIAD%oqs˖ZvaMsg>Y$#" !I HiHDHC"T]ˈe"@Ґ$; _y;$D$4$" !I H0NFQaҦD_Ԟ ;VW+j J;3DYEbֶ'vL&)+rcW騟WԜ:P}877ׄ"9mڴ_yǷbLDM!&o~ivhZڳ$z& k;)ddlUO aޛg mˣVgu4_J??6τHF;w^۟׼cJ¦]ۺ4*v찡jA`gϭiM?A2!1mڴϞ}VNr~{˗/g{n L@/Snn,+>㊏ LV" ?я֭뙳f'>+V.ׯ7>si!_2sc=w<ӉOYxǿ L>S5k֔|䣟l_|-Ss!~~GGNw6/v/n50" Xz' /D~׻>C9lKgg>'?i'fw?Ȃ7x``p_o?Ꮲ)Sέwmkm<ࢺM^~/oW&I̋/4_NG=o,:uj`8222rR7CIDAT\qgϾ/Ð}KӽMߓ<~y nv;;_ߜ?W&mo{뼊I@K.3Ϭ7gW\%vuksh駟/Ϗ}/L?;ۼ肂hK/y0H06?_?S#dNG;w^ozꩧT6mJ4sϟG{W MwwOw|7L"DC>k50]5ظqc]<^;šogggכW};jzm֭ L";ƼYYY뮻&:6j?#]wٙhޟ'3{Th2,\KDPTXxam]nx_Q69񤒥MMaَ^hooGyp6@QGtuO?/G@v|U[y$j}N/r:ttAo~DG'>T` Y&j~CgnQ{ <#CQ]a_CD1P?)S7 9Ш׿-Kx&됮6l52w%Lw߿?\rٳg&col1?]>xn1. =naCZۑOsx[r-Q?=vv#>5N/r:Kiۢƌ3@D*ܵ~E+W&G]5g \sz^ڞɣ‹/Z*v]˒{ tHɼâD;bQu?uA/=9=309roDYnݳ>c]&RD9%jrmk֬ LLh7h;++'~(0jJN>y]vI4V|?aӦM߹ڨLJ?뿟xi䪅WG#8b@<|ǬY?vvv&5k֜ugg>k==L4?gs0}}7Z/O4Nznd2bn'M˖]o|6"wډ}%`hSˈ>%VK:*V05?gwߪ/9I@~jozSHN?㹵k$䮻Y/0A$ک#RHgJ0rrr.Q+umVXyYgGzcK?m"E$ ?FqahR[Pҝ[IVN laOW 'wlQ-._x^{/W}_x!1MAݢH&\y7?bu淿Չ=__80C' s*=U/y˫Y|UgWEo4oΧv4-zؒ2^]Ts\w:K.۸qcb}g?2eT8kFb_ꭕS7`T\<+3d**??3d=+5v^տZmެ!̜FמBBv@ff-77M&obGϝ?)D8z;\|aE{_:!ƙ3g^Ƭ֎͒_DK+ Kq=Gi'e6CYȭm*[Uֵ`qsEn{¼ꖚhIYҶڒea;%>Cb0R5JL-oOƆڊjsZ_baf}cP6իkSP^5_kI=gΆ~u윊S/ɨmOTZ]Bh͈&l~`' 8ٳWǠRZҰ7&},kʂ*.ظE}y,#QWnVwW^?;\@naȖ0 NKj¼5֛t$.?^^_ =de9Knj yۼk}>!|w1B[9Ʉd(9KΚJbU]n0hGw~kzBe+/^~' 0νoM?qWE2aڴio]y>{HoM;BNiYhm[eidcCƶ-Q z]ޚI788J\xVV²ҜБ Zy|cG.vnsc3*i-3˷54ꀛ,_ܜ0]h]qV{Є"9y=[n-Yv}**6bs=̨uiC>'T+8^X l86C׫' Ƌmk odB'5jY*sS0!4gz'9`qɮ &+ e{*5Fod$)s+ص0(Y(nW)%5v(YS7n><;цWs^u7gVijrbՕ{E}q8^լopA<1?5t {~CK|2*<7V(9amy}|zB`?O;`8"R$?{YO`"ҦB/w8H0?ow;s=xkJSAc QQaKɰʩM'mp9(nC-QdArxj m\mnҺpk[]nx_jxRҦ;Ա֫"v,سNr0QJ/S{s)cV=i@v޹}6K߿$:*5K3{*3xjtOoI^ux#N`dYP+JM\ԕ)[dbs:2bOyήb JجEkKzGRRa`!i/IDATjI6y.*5?:d6v}y4'h]W543؅V%㪱{ԑYzCyќhXwVoMN[X\疭&5N\]ɂ-9=5,Ʀ:0o[Pu[|CqVסC2\NaMsg*жC EsR=;o7&$f2"RFAer(ԅohYZ+|oXʩ]5Tgw}LƗ\gYoϮjԩC<]]w\$|g+al$e j*]+ix»=/zƦߚvuR ÜIE3&vsgK d#ebMвe+@ֆw*:>5tXQlO+]ȶ6= 0>iI(зlR{׿[6L[n)aSΝwoH*/o簳 t[}~`ġ,&lefo҆*Guu?شiSqItDcƍuq $" xtg}}ԘW17+++Ϯ蜨@ZK7]_3.kliug`@";ϿB{{{>#8ꈮyg^~@/";k֬ =tn^2t]ˈ4=nn`{[.j2e4 ox+_|10"&" 7)j<Ӂ1}@/`o /jժ z^{-jgϜ%sc]1ه>L2y/n*9@>sFqi{`," xTD^M6Itw6jc`+;##LCH>}ͬ'#nt5!ɏÈ]g>뚧XW'cguX8`VqQ5qجdgdd>FްO0ڞ>}j黆7{MNN9u!tk˺g!#PLyN&SG,E# 4S,&LPpNbeAHfqƔ!ZN~EIWG!z6`\<>u}\AD2T0׷WK#Fޯ{O"Mkaw+ӫoM[ֻ=9w "bG&;2Ջoi x^F';rto|7D$㋱;8V4ґ[F^:WO<6 e?qWzwաqgCv.( Dy ]]j[0 ;vqcG{VNNNdž  rz?"͹2^=Gi֭\<Njo=]5+kj_أ!" @$~DgGcӦMgч~$9t f\0fwѹ^ʆW|ɧ>]]Yrʖ?m s]Ε^sҮv$)D]ܒ[8v/xLj? >49ϞsG7~-$v%5nq#}?L{T?[zmCNliS믿}3>z_Zп_|'?={ľ\Qu>l Ιt4ks\yG/h}ˢE#ܕi|w]gfu7~* |AQ_hdkIDAT@ۗ"W49ЋF;2瀜L})"ؘi^u/uQHswg%{ʱvcC9pt|aʚХлF;?p;u!vl|O%ϝ0"7<ܳo\~7%?=ϼgN>t؉km݇/;NQ 7ԝvɄ˿4g>p,se}͇bV:9Kj.q}׷=#Ζ;<ڵ#|d/Ǿ.\E2/$y;kbc_U$ӓMe >CO|y}kիgvvhm_"y!4E$Ww܍*I&~{Gswtl*kbaߑ76꿄>q ?Ș7oL;ܸ})"y4]/_}_>=C.?4N8#U=a_Hllxa5I$ I֮ 'I}=b_H8p3G o`w$8tS5#zk|u&S9;{ľL_X.^rӒO'\l޴ta_ܘ>|,Z=%;kͽUy>~ꉧ.<|cǏ=c=ذWş?VX?$-+2r)ꙻ|7]~'K}(񅅙IK6zz[YD1ow^?CU|~k9Џ :,@ɤ^{m_$??@7v?O_HIvD'" @$e"HD I D$"HD I D$"HD I D$"HD I D$J$ ZT"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD굮 ++!쓪deL {IXrot+"˫{U$n)('<`LVvLXH, *cYIG\6#ڊMjW`r3' n2<6vJYUCu(kg\lJU_xzQS+m^=/2' ]4lJ}R}m/_2!kG[_Rxfu67T/)|Xs׬']&}\E2xyw6޵ѥWʑgZ]55hluGot_jեoy^y_aE|aI67[j|tSdtE+O*eDS Ƥ7,x*VHb|q;_M^zbEv5}q >/}ĊəM/-xtG±Wz)ҭg4_ع퍷[ҪclJU8oѡؔͭsn}7=UǦq儙 O]P42ԋtMv~s)`oz%g:~UŹŋWKIxKW9yxqY!hW-W0< 5i<ꙩMUk Ss?8V4t6Lx4^xLdܩev]^HƗߙn\xضdžO(/ϔ}xKYU8q ۗMN$ekۻo̵.T%su;?95un^kՙa-jܯa]g|a_9^]>(76|SMYt0{Sv67O(쾍;Ҹ1AU[tjqUO$0}tmXR|t&9>Ҧ̓mzn>#@"v'6aj[x^zV^4zx7VD2VPpx̾˧ŲbkS/86}+.^հasSxCOZ9b[VWffcu+˦pĕJ$趹j3ok+V 'd̩֠>_=5Urܼvse3luޙK6swl+];WMݹnPVpt7U&jNncםO"UE2{jּg1Nb7m -?:fdN9#G9@7HK@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@u|핍haSE I D$"HD I D$"HD I D$"HD I D$"HD I D$Ζ-[殕55k<9?\СCyGyd'y愣ss{YD1Dzh%}ɖ= Wgs_=+'''쳆 `u֫f^:IO߽{'kcHM6qG~îc8#@6l'?_/͊΁v&AHD$KCdN>餟vk, \h5_ݴiS5" mw~ޒ\i+~#J>琷=޲egJU${c}d;/o IDATwoID]|O}*9! VTݝG<Ƿ*+N?#w^}ˢEQ! Lgw%_3?|~&;yϝسzW#V^ip x@7iӦdU$kll4N<@0`I'fڍ~o6$H^Gz֭[_xdcyczոqd^h+kV$ ?0GG #w^D\r% ^0=DC1bĈūKGC4ЫVdq3ۇ > ?]&ӈFz!iỳ]-qm'p|ϼI ,]iz[,i'"@4\8uÆ>ӿLc 7~CD_}Wz`ժSVVVC&V^TBokSNI6E ?H}U3񺊉Y3jBԞ.MLwHEe>-6uvqH-tnՃ֔+A@=Tpr- e6~I7Ta0*xS`JwknٚBCMO%?X8td#]-[D$鞚YӪCѢD]]xay<;oYmf\^>TXT4(okM!噝JҗZT]9ԕf-d+M_pq/KZ5߽neQven2?}ydκ9slٲUn\PONiiX6k6;qàqmIoikӐy#CRQnv-j0wDψnKw.=U86iY-[vW VΙή%3NbŽLUL7Zi%n<|zEmuׇGƃh[2UdeSquT*2!w\N6aP鵪[TTo V-+xŤVK/ϚV5VXJ[nk[fdz5AدZ^yj[%;~|>"lY_ã;m۶??|GZeC=4C"ZVIiYͻZ_aTi*jv*Jz;3EK+EM̟`lW_4}"g!w :,uH$" D$A"@H'+VT>'|'G]SNď4(qYD1S\Ŷm۞)kvo}e߽)Ӿ_Х?ssCO^7| nذ1P#I5~}f͚.zq&S9;@vw^_U@eay{[ʏ;.\71v|ǝmhve}ӻb%:엞ضF-_.O*Vm=Se_ᡖM6]w}oFrsaha-ShDeV`&3ݒ3#gZTϢ95J~%gxvô;LW_v53 W7,3dz]iouVlNi]tbǚaniU[T;nvӲ1[;cn=0zd|a>ag/z]ްvm%"jX.IDATv|?1Š!V[TݪR?  E+OiUP2߿qm/i+ZuゲrOHK>򤂂CH}o>Z6Z⫳vG͌*TK'|i ڶT]رtrvvGIێ `FuSάݿsx?=_/z- _=H$>)$/z9<ځv3Y"}uݒw|0o=E[g_~׶0tQq{Vq)@Y?mJGSJ)ܢx*![[JW&2'%[ՖjEfllR}O/O#y6̼}N:#g9׮j9z"2dȲo͛щ2{m2v [U7l!V;"nyN/I+YC vp&>uVvؼqmoWA\7;SYIޗ Co3@ م_Nᆭ!{ܸVK'Ze;~ƜxU2]4vPr-h*|goV1&e MAEeM0qw}.M"L0`埻Ϗe|rsWgN-zaes:+d^*#Ύg/mU:a_^y|}Ed*YR<|f؜^bzٺtp|}Z{Ю\s{$zL->ޭږlܲXw=YYY 𽛞c^ =͈dƐ!C>sV([ix!sKReJc-Izn՜3Uw.;(WY11+!.?t3ՋCO-hжәL-]Ήv\ʱk+^71?;Q3b}(d]s{˥-jRˢro@:շSq~jLGo}];2Ɔ?*wY<]|}k'_n|S/*^S8,]F[:Uq[VK_6L-R \M=-NǚnJ~6oٖNg&2v ׮Laϛ?;*ٜkH].sPLg򛬟خ(JIE{5[? UksZq1T~,+HtxW6}ʁ 4:r.QuugSAE y늉Y]ҦJ{6ұ9<}+șVO*4j} =nX}wVHr7.vaHWj>vs]?w^q/K:nWz`ժs!~X^޻ ugSQbܢeaFδ;vY;g9ugNAEf7Lkx3%ɿ嗯O.ZY;YEs kf7$NO*V}Cw2?4ocTqU?>eaK"XE%ٰv~bye߽Q3`v<6.QWwIe:$xQ]4֪B-uAD95f-O~J]ݖyɝ+RK*Yj36g{>ÜmᅆƛA,c|dgwJeةF:7nբP=G\5Kgv|d)<#-ȓ @Ew >ߓټkŊ'_X&еm!;(ݞ)wXgfP w ϞX1uȊŋÎy)*ߐ[TaPZO]]YYJ2#XoY1dnU//~{"9dȐ;yǷ}zjVq,l39Yu1U@qpayJ"|jD]*˯>-)t0U zk)jOSu.sBrgg[]9]q[6OmgRݛeYͫfwt)}:zgrŕl%*Yp!CNDr͈${d׼.IAvI D$jfE#"IV86D$;YND I D$!~CD I D$"HD~կ~O4g!Oѭg}7[:|7 >اx]C D݀{OccijL>2饗6~~G !o{&cs1~o_'}1GMdGq{ 'Lz7>疞‹/۹/d}k"$]щH4̼֬O?L;}%9W|[u랞 9g,X~/??_$ԗ>P؃NiO??Oou~,:/Y4>c ѹ!S?H$բEo&sG_>}~u仒7xcQEEJN.p 1}i4-ONDr niW:_2Ә)o I:Ӿ׿W3rVe?MYYY{L_X.ayO|@??3cN:f'ܬs˞ WuM~V5U;镼u&on/rC%_[.l^9 @eh7W$#֮_аvOL6< {'Ɵ'?'!C. mC2χ]r#b#GED=zeY_i5ꠃ D${Aggxovš7%?9Mgړ?@H\VziNNNǕ.l$q٥"GD`ԨQ_ʴ~caϪG(Ӿb@d%}C~.RέMMf3ܸ{݀°2tX D$k~S>^ڐ<=9*Y?kXw}jf>?] GD` "S>V\oس|}g$MG1.Ұ}ϯ^HhSE~gO~d/䓡ou7O_w#7U$"wD$ rD$"HD I D$"HD I D$"HD I D$"HD I DU$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HDaEYccUk(/ʊMڜS;=FlJe<޴Y-[;Ln a+:Ѷy[5UǪ)Yݒz.֔]zRoUy_;H6,{k߽om㖦]]zG}ك!4޶:e =q}]v[cSv'&A=:s;H6=/MM/=3Fе,X19Ӟ"-8lH6Z0&̂{bS*7ҜWzͥzzM|ΰjY8vExIvRϛn\Nh>&oJGOڮMLg=)u 3迺H^hq'-:668{ n=#KnIק̹芋ҩ--ܽƖVV_ux}߼%;ݚuH.y_s>eE#CyԢ;6W.3șZZ6}z8K*{[ڸ6kE7[|ܢ;MZН;^uϺH6TUVΜ2','_\>}zA;ujafoX\4S0V-86a齮vZruSrzݩa˦ K6$*t6N;Țf&ff^U]Vtqjiq&A+I=dq'io=⃗-MGqkmJ+FXw'ff)}"S tدz-9-5cSn<]VVԛkEwSf;npbzk""9|xN CؼLV/y-rpޝ[n)[ѭ=]vҪ ė>/ѩJM9t;vkbvu;y̱ɳZ~dAqq݋+; eeŦVZ2ΝtsqeȶɒZW㡌YTKGw疮nĴf=眹_nOp8vapniU|+\tꘑ9{]D:&OwqNN m$" D$A"@Hdͼ-EkvO)+zԨҺ%;U/ߙ{IiX\~“9-[;Uy]C_+-'=L(|@4Vt|mC^j?afђš %u!5mB&N۫ᤊ{ S6V8lj}Ҝ2WQC%NϟZ=bI]eQSy~?+ߙSܿxEyc8UuG-Zx &x䜴79kk${umڹd]|H,SW%Jh\Q%Rgii(ol]aIk4dG&|cQf24 9+;SO9h3= o JWgT.)+Wr}N۰)TL_ܘY-qҜ7\mr'QWmt^3y034V.myEcL㒜b^M8B5 7v(|qNo"3eF{ا_hH"tq̢~ޒD쬦FLXpbnVhٴ)תdg\SQ互ykk;lںs"{.n 9ũ^ͼ!gE9#Kzϝiq5\f CF{pRE0",4XxmabQQqɼ9ݜꑥ=H^Z:y`M m-YkHqNޜҶbWk%KYhX;Wo\HOn9Pd\yuwsz=^,4B^{׽5!ma╵k; sG7Շ޹aoȜ8}u]D¼zN_J;׉_S0rāS7(I+'j:6g䗷(X) SsEqEEX?sԭ[X4|g%Ãjm Dd`ia(cuXnINK RޘUtW"V1,<,ZW$',OdɶM5<8bo.M6tWta#%;OrE!Iźx] ԷuC`Yvya^ckLj-/پkVʎ+ZݒjX9~xEw\R[:%N{G:;OTŕa};'5&DVzTANm۾Kgd?:z8T4cvpD*"yҝ$D)I9"@HrT/`Nil]IEDdG$'˱H޴pR~F~h?]D:_##u;+B?s!M9Q=]D:;6<("(HiMIDRE I D$"HD I D$"HD I D$"HD I D$"HDX,EI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"hP#3s23jtPF;Vܲ퇺fV%|uw-U^|pHۼ,.׷W͜z9EsWm^5+>{ۿ><#)o͙U՛xe dh{?ɦ]]o4={Bxr{8}G8zHn%mc|gRsz8؆Z; 9mEڎ?p+]خþgV{^Φo_^C~!|YYAw<#М Nl__]vƐn. |կv5ґgl^lZnD1fjxƑX8'=<ɖɆ B-Y9pBAjk^Z%Cf͝ #޷Df$__}݉WM2\0ijN[<&c=#t'-"Y0k_]Թ^Ú۫ʟyj{SZŚWw)yUdc|AnUes f%$NRU$ 5wSZ[:&c=#|'-"=mus,\9d3ws"kPpqc?tכW}dqYc:7-{4٘`n";wNX7')z9):'=<@? mV{p𔷎} kS{p겲瓍KJSĜYWEi-#{#!]rWmլ^dʖ9^l<_VV'v_8d쌌U3K9m=zd7SsaIDAT__]vw*7)KURo]Ko^0!~#Y{hv*x&WQE$7W޷+]kVՆ wX,ynaCaCC̪lxdɍ|Lс5Wwݷ',*8Yi=R;7'#|{8GG/qnl*U(1`YÓ]?]02Yl٣ɾwlg'([1n,g-k&X[:M!sI"GD I D$8n fMά-g{Uoi-g̴CBߌnVAVF, ђ"GD I D$"HD I D$"HD I D$"HD I D$1"+ðӆ/T"HD I D$"HD I D$"HD I D$"HD I D$"HD ISOM ܼpA MHt#_mYmɽCX&ޘZXS 4 >"y!CHGupҊp8kjRݴpAGB@H$" D$A"@H*g7ܙYvyarxt~D#gIiX\B!sv;@D JVe0.Vl,j_SP34_Cf^AƜPrHzz=z;v#2pcMM`W0pɁR6܉vɎS[Vm/~чhʔTc?~ObE7*g\SߺUr#&PncQ9C济+ȟ4@'T{ذaw~[O~S zGq"y:0 ׯ޿͜ ڐ;3{nhi(^nQ7Y?oȜ9A'g~73< ;~L<֭[%b%= <]F]|[l۶=^Y~|$A [YYYmXQT㓟٥H[i?~eHݿ>_jן @:KdIR͛qPci;~|YfH'F$~T`rܱH޴pBބ Fccc` pBwK5?GS S}c!ț4"9tptܹӶgxpvM λv7vto;-ξ~o_%9N_xWw7S]χ/~>lKs9S|=oHpeOo|rd烳^Jw _9_^yǥNBnv8υ d$/÷~\MD'n9q^s'Hnv:oFDdO't;/B5FGPIDD"uϾ2䃷|+p@w"w!*bد}++w͊ . ;~;S9пEg T?޽{/X?@]ş]on߾}c3ޖjw oѩ"gZ#EiOٳ+ܴfv?;wرǍ 鬥l;ln޵;ʾC_SN9%p1FIDATFqF>п c'ݞhʔ=999!233Ǐ\>mڵOyGBrIfzw0`Dgú;PUj6D&y:j>ׯ޿HJDr߾}˩v^ބۗ"m_s=7[|@Hnz^73hP` úקW^q;96 O?Ѻ˧M /@:(͛7&M:z!MOO4)o>I9}̣L;7-\pljjJ5&O0 $'FB~`T0M0hP[~饗ݻ7<8i.H^7nz4:/>ӁO>%9rd8X]309tg7|R#pēyDi2Ί/XqˊFz!1bD\ZE$<3]Drz:-ɜD$#FR/@ + bi Ɩ-[r܁ . (vկ~jO4Nɫ?xUzzyT|kִ᪫sd?|kƤ /9RIH{x>{?Yͻ]zsϪ^o7)"9x;<ծy/_qtt?Hw~#### <]m߾}hefN[tI @KdgS*/x'OmկRc?{8 yy5>+=jtEUn퟾bz[Ev7ǟk;5d^}gta2̫ 56nNnNSצaIXy򻾴Ib;hSn_yC^דgϞm%EÿrE"!"qn R톧Z޿rw;>T甂p Vg&7ZjZߡ4'utTcy*ȵtzK+;&w&/^Q-[ݻ7uG aTi4.n˽+Xܘ+wv8jIbΊ~<%ΐh\1TZ1}juHMOCEeK;W$NVzx 6- ՉwuzwE6_3T].lL,o hIIn{-I퐺/l$SrֻJv-#s !hez驧y_˟曩Ίw92?4~Æ[nYjۻHmgO-,Xs]FX1rqEXWN%/n*/nlϊ%\3ovmަM-!+wbju%tS>쳣:+⫦_)9vBQ^>Q2sEzXј-nb^MdoMC#&&r]8z=M'$;;9ϻeTiֈ`ɎʌݎV޵WdVo:*/_o};l䴥y5_槴݊+,)k+߽_ޢDEU6l}ۗvNf}$f󭟷1k517+l1ʰzNr](X,_[⓳f_8yJץvmgyj9-aT[qQqNh߇ůkU 9%P¬иR]D^0s>xh62;C6Y\ZR}iǯ8QSUDSj{Ɛ'V⧔*墽S|kZ>"&-#).pB$^[{ K:eZ*$s]sGvʼn5[l[yg/yߥױРAkX<}}AZr)%ř-)Ukn,O芮Wo[9~)HEBIE[u;Èm!dڵY|ʼn⥡7Sj_h;I/~v3ϖ>RsDKzɆ ٳxV6kV񅿙;IV7 !Ykﺷ&䵕;8LV;"Tl[b;Fp\bhnl;ln޵;ʾC_SN9z53)\~Wq6]1:U SsE|7%&C%{Ѻa[9O]r1~H */nZ ]i\EKU7,ַL,C+Y$rֺz7fݕuULX%,33sqO6_x.2%_7ӱX,@6v]1R M՜;ZZء`f`n⁊KdN E|>q|d|27=0oeq>zDƝ%+>V}[F%B%;zUʱ?Od{]!R"YvD%f^cckLj-/پkVʎl'KFF^FƝ#]8! vo_p]wߝ3g|$ag&UΜT U9LN7G ~7_ldudEW|ߦ9;\"մmdBg;ᳩgKK+±ЋLyR!L[{ ֧$PU$;B~S947km.@3T"m#?O⋩S ^4H>Q?>mobe99#/ש͉yy? {Xہ^/~}?Z׾wwz; uݦ'S{O]P N`ɱc~;sϥ6vrṫ?Tܾܶm?X{_ϧy;#']25&"|[>QG_۳ьN!@o{=^:dy;O穆g~F挜{NN dbn^{eWvEdH$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DPF, Ѣ$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DР6/ܲʹE٭; ͙0rfvFάn.ռyU|d(P^8GXہr>k9PV?36VOѰjZBc bض;'߱-YHg|Kً{Sk5&'<{S'0 RUݻFXU=(ghkhvn߽΍J?dqOm_5kBjӖU5sY8B}H6WȞYrr /6}x{Tc -{]|*h\牿靖J3ێ( }Էd5BصfUm:mUc,18hHoųVmn|HjUӲz*+lKݥڏɧ??6#5ޭK=;dddL6luuC}ɿ999[ʙU]l_G39Hc[,nÌ94qϋ?#4=)Ee [ɂY30|ƬC74g´e_S| VJO6wYh-"=mus,ּzZv|jfvFF̪峛fdd̪z;mYU[ VUv㪢g腾E$;]fW֬mvSM.[5ܘJ:m`ىvl\5sg[]("=z`[sg|jAQ'6.;sLnUq~H,yk̲&! L7Xہr>zaƆdjfkٟ]7@Snmê7Dz⫇3־Ԇ;d!#Ͽlڧl?(74qOjCz<( H9"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DP^#5GI D$"HD I D$"HD I D$"HD I D$"HD I D$c˷-e!nZ @"G$VEۂs8&}DC od﮿C$ҊB@H$" D$A"@ TMA~F~ϐy I[: czE磦/lΓP1:քP?g5L " 'Tں%9!dm?+Bѩ$d=:LT8ꮢF[l3d%7[s`9S(oL.M\ Bۧ}S 7tьBao{)yv7zu{k%+s̩XEQzM-!+wb]$[o[8Itg}vYgy_&!" 'EK*!;c޵Wd}Yc-YEKh/>'쭞#u7/\yxl;ln޵;ʾC_SN9%@gHVrkc^AZBfn!w}KUFl,[8qN^b#GB0~ܸ˧M/@"ɓ&7 3@ښ<5"M (DÊ/p?Fccc}DC oٶm{1rXh4-FN$H1s x: ]555^&վt " @Zڿ?9yW=~ܸK/}_D$HK8GIoddd@D4ٿjx8 @gXہ^xGjk} UUS ~/ ;mxI*?kjlٺc_|10`\? Н4H>s/}g`K?s}eDr޽V  ΜSN9%@/"gϞˮrӦ'Ro;ܱcǎ7.]D2}ȋLoߓ:ʽT>A>*#u;+B?o߾?>o /oMϟǠAi`vɓN moz :t?s|$ГtH}qc@)"yTcҤI: _:E$Rɓ. =K˿m'ڗo[jܼpA_G2bX+3cuo^z)ި}hbu ?#?W m]z6<p 3L5lzNɼ Ɩ-"SD^j^󽦦ЃwYMI~xe&ˣ2>dʐ gq$4'١YzZn;5{J?%'-''}]6]a5e .M˽|A-yYޫ56kxh+$u`Kɸ&|/L?)/w̱/3)Dxq2jzZJrrOۙ7I;QJosi; y=y'z[L<6rO|:ۿuOڼ%XD2>zlohw(E4n܀Oָ8"W/ ӄB8`μI^ր0 +/t5mG{_Pf{W kۍBLo]h!̷.7Qhr|B&{` }c>rƙ_{ɧRΟŋaÆ[.cr`2 ެ 1QeTeXpyR\W'%4!;J4K]L599$?}ps8mO2e<6=Ruw}Sk@޳-k ]7eLhxMFX=ӯ6ojs|B2ۗz hf|N6Loݸ}4!뀶[Bnae H^R^OvL ):r}s =yKnc8SID;Ch 6}6t7nlM6uϝ;7tv(ey?)W|p#`}{iޯ6Qȹf νq4d}뮞zRzy]_F}ק6Bys3.Ҥ Zۼ*oi}r 0 Ҥk3~':thjy'3~aZpynZn5 /|QNu 2 nny0_VW%u磝܁ۚ/|̫) @E*"c97y͵eЍfOXAML~ߟr^Ub|KCOZzZnNZNVNj^WpO,qUkB-Ǽg}JNC^^ZU~~$/A8&^[0kn}܌4wЫ-=p_ƽ7K?#<:o/c{_ ? 67p>Źb[.%lQȴ٧-=wD>/g6{=z y:lɔT7[$I;$߬]m/u/T=9_'-cBTvxVSSS'?Y'_zX [夊wj~c~xq}6j{;4d@ωxɔ1Gk֤ct~?)Ul^yvɓt8}ԒK/>l]=)ͼj.KkMlcB_zxwͽ}Ԑ=_tɄ(5-$I"@H$" D$ Og~_|qժUK9Csrr?@?ܱu!B/=UVs}멧~/|?'zHJ:,s }1|d\|9s@<%lݜ^2ӟ!<} <(t n~V/[[wK/.w m'_>=@Oя2㪙z!K+=2ûu 3;kWMm.(>?@/`m\[h{zk5=!{Ί9{ z{;cR_qU(w9]6@?Ho}7žG}6 ]D?E紷8_@+aAKs}֭ "q {+zS!avN=ᔳOw}Տɸ7ᥗե N^X6sa5ddݳy^zE$>zlohw(E{{3xIDATkSQprf0yefyPG: r~G9̯=SGϏ ] ;̇5j՜5eSOtU#.[9wz™i?8eOoD&R87:U__ĉ!٩tZ]$ uC=#|Sh yP%'m:ؒ[qĈБHbk֬Y ?=f츗^Z~E$k.-e==?xRuK*w[zPܹ%Eߏ n5dȐs.Y_/:{ƋǞxl!k/OW~/_nkn^*>:_]$gS+u]uĈֺ]Ӱ!Ud Q>9?+e?>5gX,~IDN̜Y99i99an>paIɣ>:Dc/8#>: @^o ~❷z#mcS/\Ƌ} :4Dȇ~xWXG\ҋ{ww=GIoΊX;g|={͙3S9gE,^{U|>Wl|'HBko6_1aO2\5NQO=hI?#U뗾<ˏ#=N}z݂cvzzd>3IK @O8iҤo?O?׿{m{c'=r߅.osk䷭㗖\rB!=%"vb6w{]}KO׸\_g^5+B[8T~_!C#ۥO6Wx5*)ԧz#VlLÇ@#" =lҤ_\*i;}/څ_ X|yh@z/* tֈ丣@#" Dڵk+Iէ~KD$zQsx=ÿ+\ǷݚGD/‹R\2>77$-|E _]:8>7o.X|W~7I&c"v/,^|7_}q3${wͿ~Ƿb8aBᴯL@'"I/œ_|fzK:rȑ?<Hbuvk>;322t^z_sT}aq͗`b6w{]}KOO?!^^q2tXXh^g~c|A~qIzy<*NFy":uuu3L sx /_oFW:蠃91cNIbmX!*y9лy؛sՓ}^ )paw죏7"+=d@+@/GO]{]9$Ⱦ(/\}.6΁xꫯya'}_|)94}虗9*{WWgs l]MIz<0U,_"X,nGfO7 'O)q7]~oSK xYg#"mrI$ر-w%"{_] /.>q@8$#Mִ#>: D$!l^"dS;o5z_Ja8c{v;飲?F]{%'}g}+^#Gf.{Ž;Ek׮=47N~ 9c:Nd/~|ڭCV^0yS0ly(^mE;o].[%K̟2)yF{gm1%m9}F̹7s\%2^X8O,@*&p3nvѢvTqڙru+/¤m 94zY8U.(˱ISZ62h۰)d963ύ-yxֈUs:L:4~ɭwuñMͰ{*fWչPΜx5bDuG9]@$,|g}+'|?]m@G9̯=SGϏB #=}RE̜ɏ'ffU15uƚ{NaҭC #fT]p\kjWi>{)޶S̈́Ľ4\ۭ s.Ӻlc̴OVl陉ꠂ#.yn՚%5e7=#nysUǍNMMM:mai8iҤQ.WH{ 2Pz?t#F5 +AU5 Bؘ{Y̼%g& iLJL=ΝS&B][ZMe':S6\߉c̟SlG^V߾v 40]?_{&"Iowх7?fn+joK5"4̝W¨#27L,`Ͷu;i=Y99i[fVͧ'I6{"9jj^fjM1*ien{n|ʥzMmNS0tRrۮ`Ȑ!]u8sa/^YcogA!y0ofŏ aT蔬#F;75ޅ3oYKc|JZskO[b#o^ ))zJ7.$m32g]|[6$-$Ur;ݼ/OÇ@"Ix╺Wv0-3wDO_qS% 6lbf樐X{Λv™nkڼueV<-v9bjA֥}ٞƚ aDnf{~&5Sş!>ҖXdF3D$cSŎ#e%F(Nn<(D[KD*Wl_ON-Z;>\?c7zxIrr؏_6ƐLOrsCs.ɺgM'JD9/BCr[*ogIDAT<2.۳F$\UM~v.Dͳ qJ.[.A?Tss$]NIf Su孕.mXQ"#/-D>HMNx饥'f1Ǎ Ju =,g=:8>7ǫ.t9Iig'|*g4iݿ2dHYhh2dC̽?|#]$~9_-\&NP8+Ӿr.t9Iz$]n@I D$"HD~.|@1y8!t)I D$/??ObŊGyd?;=!,[<@+x`XbE7Y%"!" @/ɱcS"KkDrG"%"y)_Js[vmw&WΙOҗtt≣ś׋Ήbuz EKDruzs]qUvW.|TnMKK E~c 럔vGG оه支Nkfg=[{Oɹ)Y Ȼv‚kύ;wy3;wV ~V`|y5m5qyW'WV)^ͪׯsݴ7-OI{X'*sk>R1%|Cza .!yi%sstE2Z3 N8}eZhQ,=-|uFqlɒؒnL#3M/ Y ׋3; <%?+B˻,y6/T7coܸdl15~mF5'b샵Dy|g'5!u7JY>ɍrArUɝn=uĻK%Gkv矿yVٗRxNlGTK1=#g'|*WH|v[x>Y/ =嚦?KtL ˝X%'|u>5 ^\?VWd\SথaB}O2yYkuy5g:i6 &\cSC'Mt/*tE2nȐ!=0?vofjKI=mi7C8`Q 7:Iܱ_S'O}hyS0#3-M%M,]]S˗v|ޞ7kj:M?禡G4]ΝwmU5/nwH=pDO͖7 ~V`ǗAcK%KrۚOIbmXQErl1M37=М[& z~FK;ƥ<潭*SN-xotHÔ-.u[o0e~HBZaӕ$[Zn.הo.p5/]$!Cz$N#t/I"ODgub1^FD I^)_Όؼs]OD׹/D$^|Ŝ@H$" DPZ,ks`W :,st"HD I D$"HD I D$"HD I D$"HD I D$"(-hE I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"hNj-/WRU_W[V eEyYigdU7֗禥e&4Uf-)>u=͝:(#;FUㆶޡ6duY[ȜQ̯lj,JuBJVVo)n`G5nG$2>:9nlY-{W7n=vF/뙆u֭]6#G_(յ%(nhƵᴑیU7vɉ:cNy冝1)ev@QD`]kň|X»o<=mή/âx1+Ka[(lJ]9kTrdԬʂrK:wj&.] *v45]tinq6PrR# 4LʞQ*H$3 ;omϾmn5ۏjCeM|(O1Rl~F֗2yЍ:H6V>{ҝuYc2J>$Y[,M__]? rZgU\=3nsk=)Q:t gEK.Ie%veS-H}U:H6Aޑ]D ̖ w$>"?}S\2V?y=ŵX$k@uC?/)湒+So^g576&jS1̰{F]9z.-h'_XzwIDATLA^;gd&1&7kᚲTBŒAE&7VՄN\_U}c3䅮R[1g]TԆAuJt"E'C}랹aNW8i3SKVgvph*ؘ(-ޤDl$7s-Y+rZy>sva;!ɬD4 _ќLfn1 $T?0 mґi jX>XQ3鼖O'фjܸ97\0y'eUpʂAimɫhu 9@Kʊո98 ޲(KӒg.l],3 ,*K %&O;뒓 yG]eVwU̯;m0q'^P"xwj?][HzAyI3 &$TU(Y()i⡲fm__~9;zb}=ɤAYy%euMͱػo,TcusK7nuª RG$s5Ex˦ʂ.au%|4ckp_ylrd'dnfp{[BEŕaw՗a 7}Cj차㶐ҳ *^JIUZٹFfd+w-J,,>lZQg¨uv/MKK-ojtPFvQE}KUyk(LXWкD6쮭&6הd7=55s3*鲬fzaŝ's!잚U;.tJvjk;u@SMղemOϯl?D[BF$ }lbssKmS0xFOcEmD:U2 jgIի8!zIfUBkCeմm{]kk:wA33V߬bNW^Zh{-3gT7*x,Q;8eVfIerus&g%f7N)TP1a%7&6 ˲G_,56ke}I* 2xh\SmJ]Wm60|ڃu;8|Ⱦa;C#v"HD I \suQF[VG$k+ZvEՍz}D2a <8?3XZ, 2 D$A"@H$" D$A"@H$" D$A"@H$" D$A"@HnDrD.@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H#sx /_oFQC:rbX;ֿ.n/,^|7_}+߽^la"#?4U|;{k?=~Qq1G]g<`A8a&Nة!" @$u}DrS;o5xwO/Rjsh3/?sT;83+3~7jXUSUg[]v/.+yՌs;"DҀЧbuvk>2{Bv}|; Mo:|͗ݼݍoC9dܸG_sT]xqgg|6O녻?pxqs=/{J_HF_6л݊W_{?e_x1p\^}?;'T}~=/E$=h);;qĚ{rjzfNv;mNo*.{7RD.U9NP} #Š]UvqSU޶S;Ⰱꗖ. @KɵkצՉk)yw ><{JG$g^5cvc>rƙ_{ɧR__W{yO j /vv/[iX^z~r_BoUp)~!bC 9}8"~9_-\z|kg~ $Է#>I"i@I D$"HD I D$"HD I D$"HD I D$ IDAT"HDX,EI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"hNj-/WRU_W[V2,+S kgd;aPFv m\GmIeԦ4Un5)yGru37ꠌV5Vŏ̫h ;o ;cgt{]i&g5&`Ps_moCZθ\MVi]qD(/lƖu r豗. aQyucb.{F-W5wjfSeAGǞ}cou=vֆL^ 43K>L謎"Mx`qփ/Kxg4FZ?-50m~j{Qg6m1zL/?Lbtѥŵ[<)cMeʦn–÷[4l9$nyUee5\rjڼvKgO kPrlPF^IuC_^sIreա lSTRaG3I9ŘY/WegkzV~IUA߁⪚+gJ+ݿd'΁g]rV2+ " bРwdc3CKKCWXwWaBeK&AG\YYކՅii!#+7|5;7βvE7TU>,ҴUVHt?>[D2kcXmk038WGr_2usچgp䱟UT5][zq?:[M ε3HVI;XwGጺS;##-9[?'\0'*~ҝ[ͫ)+K\iFAQ*#BF=Èdew_~Y4f;:-9t?][H֌+=!5ke,nhkMedqjqᦦE%&Uee5ND$eU55bᄆγR%).-aX_n27]Z)$YX]HrEsKb6͏5.TYMqMX.}һ+#Fu}s*(CW*zUslܲʳ I/H6\v謢Mw\_U9+[朖YX\WQ*}lIavdHtX,Ʋ 8;kkl,<㡍Lx꽍U6kgda;77i>m~MoKo*MuYcM5`]eAFr)ɉVq*7<+~Ǎ:̝nTU}ڜԖtN|N<SnYHG]~FvF[Cj*_ 0j;a]$3 F0f7yIcܴcبϺ7GvƎ]}iړUTOߞͷ:ps_c-g@.}Ӏ9"@H$" D^Nk.H9rHڊֆqQyuc0ɝ[ts[=,-h"GD I D$"HD I D$"HD I D$"HD I D$"݈naHI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HDlɳ;}d_9oW%W>v?yx[??1H _$4₥+?*tZ~cГD$U E_m\zdqܶ*5Y Ħq$:}{r掯, ΰids[6v7}D$"8*rmZ\[o'cV 3'?޵wZ~熻qU[qMgXqg?M4lm?mq>ə/'93^3[[Jt&"ްM-.meC/z1s̊$)7BêD幏Nܜ]|eMn prhrM-$Shf˴zds1Ǵ֫~r؟\q実8/HId"[W]J':r1~즖M({soɓamz܀@/C~gi|IDAT-ǩsg"8¹njKwjbKOL'?5w?oK?,S_i8"L+ZV,N4|}>:s ៪-?+َҋpt=_ۼ%zU^gb6w{]7x✳:1v#_  tW31|Cw0ۺ Óko+~3L>&lɑ;ed @Djl\SO[V8}/ =~V؁߽O:h923t)艧~UlyH{k`cO8s{W"iX^ >߯ZG|ztVGӇ~"侹ZzO=m=maHDwy%/-MգNw}DԚ7x_OJmu'=KDe3Cg2dHO|k_=ӟJm._W@WE7zs|+WƋC$Qdo$ @3OxW6 wj@O.X|W~7qArc5᳟O` 8S-DF{v[_Zh[D؁/>ůZQpaw죏ww${HTfvDGw?{]a{%\|$z"DUG$[mwg^[zT w7$œ_|g^~QvpfVf#WWN ~c@&" @T }V,Yg#'dWz'{VfVf5qē:W- Ʌ:seZZZ@{_] /.=R!kiG}t}4 " \*CD dP*bE*Nz[ 8!\NU - N-*"(8A$LHI6DHk߳/Hƍt_GWq ÆGKk"@i5i|IX1Cʕ+ڊQ MkA G{.v&y/W?V/Y‹/ĉHguY#©$/(dcSorvaJRE$^:)=}yGKyUoYoK{[Fv6wܨhԦfؐm; 'sLL4-FYz@IJd;g|kMSM{w}pfҷ|KSyfN2GG!9e}sw}`đ̨hܦf޶-(dh)!԰6zPʇbSj=ھ]צPsxnS#/p0:]7-Ft]xcvNqYsYBͣϼgWw7O+ oAnݺGv}x"PmundضOp){лCa6S۝UaZ(+W!+?kŋ֩sq|_H"sMS/aMnW>pK\ǩ >zljްB4kVȉQ\3v#l֩;6uaw4vØ;GesKJķ+V[<8>״eP0"9򁕡B_˞\a埯6i%ّK;;X7N̙;wpYYY(oXcQ|ӓMgctI(>\tqPD֯ݹ1wwm9wNf͜eyCMSz'9yӄK:o{5Go1ʑ_;)KTVV֯Ͽ 7ٶMYoyk:zjZpX:uoN{=5֌_p)IH5k֌Es=WCߔ0fbEv1,?aE# lE&' |w ,"#_2aS+Gl{dK|²wj4beD}Ɖ3_MyM]rO ]xcWɓ}_|~Rrrr=ԩz٥F>ܘ p6m{ ]1p𝣐m+eUM {"7"ټYq/N;-`%7F_ {dSiD3fuv=cEEuƍ?mO> 9Wrvoݼys'̟??VׯY_2igժW=taOޭUid ni\x3{˵_꧟'( |wM<(@"JKe˗GK['M~>GVT鱇m>2&瑇FVP!V/Y‹/H,O9 c9ho&HraF[r c{ i t;D""Y:L|8~x0-өw8$awDWgΰ;5 9m(;cԹQIJJ Pzd0wU˖- _hGDҾ]}xo{aߙ?}~ulzU߷i:@iH AfffTj٢0VZn=ªhsb⼟&wqǵ=.S۱_Znc֭o(wÆGŀ)JOJe_|- wM4+WHP?9^V_%Svc(~z1Q(Պ>"y.C7EDTRDWr姟ۿX:S5Wxݵ}/MRkɒUV(p-x{~|۶a_h߮_wGRڽ=o^T$'HXя"Y|6_Wr /[r#͛5 ViH-33s1Q}gRKD2^=>ysvX֠I'<Z"^:knoD_')))Z"@xkƌ.b…U~ߦuPH@57Os'Mئu[Ks_ č*UEņkC!kSΛ7e>@qjǎ?HʕeF "/Ff̸7}?\8PԨ^}u7 !HƋe˗}￿F7(}vzp@H"doNf͎VU;]ƍׯ֠AFD/Gm>$<1I'G}~ÆGŀ,6n[M6udY7i|M,IDATITc?\\dY7_v$ɲnܹQѲePT(֯ e^)dHuQѪeBD2^= ETӟ .eШ eVRVVVr] nNSszGb_kԨQ(:wf@1HOJaãb@~{go׮b*xPDT.PլY3*͟ QHuM6yD$Heۙ]OĊc_Z#{06@~"/F-du<唣6y}. >tKcÜk*w%$"/-_-d~w #]zF83.wK"z9Kz3^:5S^аSnv5mX+sQ$ x]KDо]Ĉ-Z͞oR@eԲ+Rv-Y%9x}v+۵õ8qkr?=ߵ|?Ϝ-/ݲϽvw\\7(ţ:䓞̱޺{Mo][dRWcv3J/ y4[S|Zn׾SfzۭۇsWyC@$!5k .l=~=|3ˇ bqBMCqjװz՛thX>o!oצSܣDnW᯽}sS|s/<=(dl } w,.yn6nUrV6czFMSM{w}0LrDsz)շd9"7{F,Kӿ#V =_s&ŖXqA[.ͫm9);qܵlnI8QhV(fV mzM9So0bIJ3̉7n퐝+v]كE']i%qS ;ܫ.8tsxɔﳫ)8{1])Snx-&yMSy}օ-6;7kk(^;]{Msyvx߶t(.甶 7l֐)mMF>TZjPxo߮kSڛ#fddپ36>l> 7 /ΫSΟۂYaM7}n}]weg͉}Κ)7z3/. ru{l2$[T\:t!AO̙yso;鵍#Y`r![7e#)UQ]hVܙGFJvy[Z˾W74_q2ckozw*-k ]ʘ-kozMakJv}yK0[t/dw܋N~מo2>|nMc}օm&\]ߺpp;G~RLF>2ThvyO^*ILwfn{)Joٱ5>+P&fG+W>%ZݴiKό3OW_Ty?d nbO%m`ˎڥ\v2LxǘKӓ{vwt>lX6MWN;د:ZMJ NЦu;u7|s/N5kvZA7nT~ .ZG͛7[vˤ-[xn3p@~Ǽ}п_(}Lf؏s~W%{V)Ϛ4kۍu푝FLsNh7m+?Wf<E(_|oaг~/xF_mؐ޲͛qk5fHize6ů7vMV;j_& œk* y츌Of-Z#c^{u3nt^#~}ȶmzk\S4=Sc[no͘qeKܜ;n8Y!{?'opI-q^++t[5C1%7HR-ZFfZ~ʦVޔM%FTfNؗ:=)}IJș5=^cw,O ]VSE-sbr$U<痝m9MSX͐{񟻖4<&aȳA\seȝ.S}YT7jh'7n4yrT_޷OJNNγg:ub[/h3a_Y/}Ȗ@8;J2wmhn8G;N]ҷp+mNj=`Z|Շ}[TP!'fm;ę=i3Cӻ1^NvxQv2iȳ\c?wyIvzrɶ%믿~QQ}L}忡lܸO%6mr%e1uڴ[ѽ[ %3bPρvwLcR1eQ$Eu%Ľ?#QiӦ[o#"g Yvސ3 kKΐQ=~اw("&?'ĊJ*='b}yhd_$_ ,)+++ _.7T֯ 7 \2VuQsge47by~7:GKĊ:wCM˟=>e_#|s~u3+_g ;~^o|AQ$CMk˗/ ğOVM"5wܨhٲea ŧܤϿ+@-ϧ)̨hղEa ZzUyv؃##"/FJݺXy]̝WסH}Q"pMlrʕ$ΠV(D$ŲCRZQRa!D$ /"@lX6@I@D {GDH@"@$^_yYfe,]4SSKOOp 'v8!qFDH@|eW͒%e+q簓N?999qCD2^=Z7nć~Wv "/խJ 4j(@UzOU^J|ͷѲ=_K.=k @̛?_Dxp_G֪[kءZ˛YJǤ[N=Ԏ=;eG84Z{m޼ŋ?xnҮɘc)z';hk[kIYYYynuQjذ~m(ٷG~!oMVVN /!ͬ2~V%/M}9k%WJ E2^;.ZB)_PXz-|dL5; njn9c"bJ~uoܸ10i({!aIDAT.UV?ä`?bDfϞ͙;7*kz'  nŨ G]>w$EYQ`Nw37%"333*iΩSBڱj6 Ijkvo\*T{=_s&ŖXѾ]צN ć]?yXiMvۧvޭUKCHd|i|!@Y;7c9.Rgxq:u;q˳ۇ cI@ʕ5rاm3$d~gNuଙc֩aw*VBVV֊+|y^ k|9JIFr宸sÏo6>iw4x½olo ŋOI77&LMQ\-Jy}.ԿbG}VaYѽ#=f -裏͛}]nw ק=78 @3$j֨. {)uƨ;DŽ=p¨HU+ri ֩uxsm۴ߚ1 . D$DЬYÈdj{ ꧧ'w zpX^B!F$5kE:u^|~e^>sc3@Ko0\(A/[ykբbf}ud(I?$%%}Nsm[|yPKx!l޼mϟO}{/>lxT /PR*xPDdxQnh @UZ>NJιa%|z /`Șr= *%K2^xMDHƃXvvgkBIYj\f5nᆐu:cTO|MDH|/g:ݟdz==1whV-amղeT̙;7@|+ũ;c/?olSZ5mߴQFSBjWovlf~UߟᄐZ\ /x1z츨uv쩡CWZ/CFnl /))Aڐ~z1QrDb3φiicS Y$#*jժ H cSfxs~yV(Ng-oMvO eEEr$D@:S#HnDyf⛈$9z̘>3ۇ #" m޼].V5hpI?D$ؽknoD_')))@|`Wޚ1˯XpazU߷i:@ xc71}ɹmZO4kSzmyl٧~`N PJHƋ=()o͘qo~xqQ{o"^:׿ ;۵g8*"P|7YfGժqFOk $I(+~}ȶmч@"QON<9/ۆ83PDD$㢢7閿DuӦMn:8$4xlf?XQR~\r HB0_v@2aܹQѲeP?צN7o˖}駁Tvuw\vg(KD$ĽV-[֌ފoӟoy#5k >lxT /r(>⋨8? {￿n??|di{j'eQ$LYƪ>~aFB}םNjIObEJRύ*__>V/Y‹/͛=ڵ@&/խ-~wװ;z_{wEϺN땞kZғҷ, G(1meWɃғ.݆|+F53FuKϻ}$kno2ODʊG#F4oj9qܹQѨM|fmmmӲK:ieu.W-8i̬rODžú>%W]_xaܲ*v<햼1wWK˙9sAڱN;w{wҔ߯[&7lNS{_?e̝бgǨɒ0ޚ1#<2e͚5 pb o233qti;xI:N5X۷ʴÖӶm;oYm۹g1e­!Wܚ>L=>k3wtZ:~n{/yO7&kkF3, i;"vV 5ncڠ^i))aO"3sU !L{aw ~vO:%5i:mP<ܳ^z9Z}nҤrƘ|m]{lcݖB YR5bT.v'k䴉cB]j"57cEhsSF, =y]oZ6e_Km+1ky^ JʤgJ%{fWvKj +z+襯~ ;; {ZDʕ+Tg]y[(1y>S;v|Gj$_U п_("FǎũrO?5֡C9PRM Hvp), y .˕ڡ[Zx_|ܓemʞ:жّ;a]NBmg͌&n;zd#S.rg;sRǜe=qԪ>^$1/ROW0&P M /kvβN–3Fݙ=5.I3SѻwY۬fVX뙙9!ûu?s'nc1AIW7SCHn{!KOvmƤ̾gޅ.Zj} (nԬY3*]nSdضsϜѨ\155-dOҽ}k& 1mPh+&_$ױiK ,2[לk lH&' IDATD$hڴIT:"Ya)}nl'{]\:bʏyN+ӢI,]{q +̜zEapeRQ!'=e\pԊrL s޲cYas~Kp])9}MYB9Dce.*:ms+|>*7k >lx熯\(Aq󘯷JjQaPH{:2qe+U6zC˙:mmNx9]gm]x38@}wD۟ӡ[O?+>?w﮿ )&<(@"2$O9 c9(\^I}u#{4u)5y !жln{])Km-'cջGn޼y`Qݸq#H[K]αzw5w_Z3g̚7~fK=>n{qs΍aw EؽG{F8{3 Ϗ=^mZЌ" !ߘYbvkvB?ܩsߞWL}vjncVnHt"gۤg}ι~饗թN6xGpjǎ<42@`xQnh *WSo:䐃65W۞7jժIpsÏo6Po^eB\- ^Hb@~HƋcEE`HƋe˗H HD(2Wz1}{/X'_^R4rk֬{ovP"ɞYF?~FұSG6:ߜU\/9S+?^t,~zӋ]kyŗZlҋuJoϋZj2(칚5kFż5k֞խ{n>ߞ،z^ѳI-y>2&vNnջ_f>֭o/n3PRޞ%"," Q"칦MDży"tQ}ۮ +SRv5ZXzF$7k$Iܙ]Έcfff(~>ѣW_<ķԻ_O,Y>GgqF(D$Eݣ%O9 C$0+++@1{o޼9V6Lb49N92@1{^k N:)ޓDD2^ԫ['ZB~5쎨^w}bԄ Q^W;dmTvmzXh +UmT?(f\{ݴ7ވwORRR(D$+۵o/Ghޢs/V^reT7jӨ L8liZ۵M̞x; ^ԹcX:lം=یׯP<ޚ1#9<^mZe${k͚5 pb oHeffFEJj|wuqx۵7؆aﴽ⮔0΂ $$:sժEjo kx{x)ᨱMַ@V>^{g9/rܤI%1ԩZZӴrv^1aN-a'ݯ{߿QzwbufNvcRh@~E2^;.ZB)Tr姟!|p -cҐvl͵SMKM-1ŠғZ9NJիymOdedX|yR/[;=mM7׊yoHmc(kZɃ\/yOa][ JJ4yfSvz=;勵 hUr /[ 6o*Vd,(@"II0d~g9o3ro%=)a&f;¹ bά :*LD(5j֨Vt駇٣Ey'#""wv3{Ж1e7u;/hw|ɵjh(5>'))zE_k;O땞4hZ[+&_Ru lBnݺUV @>n6;㢛OO9?O9$#sV=A$U>%%{ wZOipQ綾=dvm:ݑ[DH E(bqH\?=d3~ia^#A.kLunrHƋe˗GK 2cJ\D24h1ۅ/l^zcf yP{/^X5vɋ[b)M:kjUV;fƐ GCH~|_XKqW⾥7{nll|JH`W䮝Іm]wŬ[R.pEi%" %oy㯯2FZ3ѽ^:ǎ=~QC+HBY s69䟟߷ E O#OYfM+_ޟEJ*i -Z‹+Wf}ڵn+6Veϯ]~#)>5Wfƍyb[g߽>SZ__O׭[iӦOWf֫['@&"/ DőGqxJJǓNZMk(D$͝7/*9aAgZ3~c_OX:UfM׬YR^zzzN8 Ė"3xY#=ȍuyٸqӒ%e+q簓N?999NRVVVRf+TZ-*6_ iodff^to;@5j4m[V:3oS$"HƋcEEEN)wNc v׭[77| >\ͷZ֯_%Ξ5ۆHƋe˗ʆ5k֞խ{n>\2/TX18Yݻ .dy_#F~x^˖gv޺n:qP~ҥG1# m6_ڦuhk˽;jgǎ-+yvXOW^3(?}J*-|HBQ-_[V}Y|7oi  ҡzEc׭[r$&L^ZB@_UZ5V&?"" %իW\խZ 6[Gܹs@^D$dffFEJ==պՖiU /PRV^5n\kڤIT|g /"Pr6oΊ *BJbӦ@^D$EPDD$Euމ} /! @iUVoKC/x)HBQYF4gzCktWR*N6%(P*UXnRfPi#˘-9Kg_DvK~|_mzxaTxƦ1slݷrߚn=̳17h {(bqQvm!֟]sgL|ƄSbɏ.v1wvCvKWmt6o I@v!*z:KC7:/'S_;fq.|oe+f=Pm\;Kl9Ts<ږgcive3YխSG2DPdlTYk72Ѷ_g')S~,&ܽ>߳'^4m8>iBN>2WE,mrrf4Ι;qg"" EiժF[WB1z- *QɹQ2r\Җ s5X]Ð+"ǡ.rԌQ/ߢlI@ ݶn̫q PL E+9ӳեc^=|cUc3u^*Uso\;{h[o=BqKoqbu۷N}ZRuk! Gu]6%+ {GDJyOf=9/ˣK6/謵g͘k|x/򼎚G{4;l$ĵ7~O?5tSwtsխ:K8?ܛq7?N>p9[ǎ;0ǎ_^g $įuoҩ7|j(\q;曻o 2f;?N͚5:rJZ5@q*?9/~˪U=ĨioL(wgfV+p@zfի8u_t{56[!"/z(DĖ+eהzuv9B kŖsm[g>XioTXY&HƋzuQb_뙉֬Qu!T; q~,W_Td@~ե!Aqڷ $5jDsWX1$" ER02ԩxٲO?4<ڵ8֭ZvZ6 !sժgӧ|աDԯR^zzzN8 !;R42~{[nVY_Bo-]7n {!33s3~|4Mo1a/|lÆǖ;5k]u_gvbWF(?4F,ի[P)7|s/N5kvz`Ͻܴ&iu05/~K.2ak_|xq?{GzfcWN !- {jEt;s<7g?~%+ۏhޞZ֯_%Ξ5ۆ}gߙ]Xʥ^§G>4/Ԣe^|# TtZ@L|5k֌"D$ߪUg+!'Oakn(9\Q~_An>I&C~hP v`̋?bþXE^ݺ͛7 W ٷfT^?W^(5k֞խ{n ߞ~*V%I?&zΩ{v 2cq/{iBrVvvհKk/W^O~%HqDۉi&Q1o@1 w\Qf{%4yrTFS>rv{Gyp.PR>'))[bɋ}.8o۵]oSM5y';hk=ow&?+Uo[Ռ7l^ehd;Q1z>){B u:57閿D͏WPǨp 9 3\>O? %岾'ZIDATVX1VL}!V}|Q2aC3mPRQylX1[zia/Ԩ]czر֭ %k̾!sDX?<8rd8^svm֠I'{(D$~wװ;z_{=_|k֨q 73g]~J޹WsOC[ 9x1cY}0!*z]k I=6m鰁yD!k7L c3=Yp].Rj4P }g2Fu)0:Wzz>)B<Xbl;PioD$˄G#F4oj9?o27TGVvP(:s΍Fm_v-}(ySl#'6h_9ynQQ={NɽZq-W}ŗtsʕիs榅-4=cQNW'=cŨ GѤ]}%pw&ǴÖu됺]I N;]mF[3fľ;-#^mZMD:dpfMz…;أ9goڷ~;o޼}W^&jOpB(RQѸMؔrlR[cSc[cʕ+wm=U/_~O'բ?4%^Ï{*VxTv+BjjZi koטo2d&!4Ivq-2sUP;w Rݲޱk{])3IZnHoZ›^'tJ#jlӺ-CC1{g9/rܤI%1ԩڧOÇ;okݱqFykJT{]tšmul噥ZKKMnc ;nMF.wtzX-b+###mެ5kRKOOp ;LSR6e].Y[]~'-qFůNkVncفwvlݡoʰ&Nݶ[>|aqòænnfTؒgޢzjݙb՝B1ݵ[U*ΛI@ԎPE2^ԫ['ZB\OuC>8یEi9Դ<9ؔ RZ+U `MKdLy;ֹ˙]Siׯ:W.PHWؿ`v;c. Eq3UBLy /3XN13 rbzVƍ}@D̹νw?~Hh{/^{4d3G>5v<~wm~c#gzG 4c^Aw~߽qGqDiݷSwn7 z2ind؋YT vgVd{C`;tr.rA] ̼ɰ.-%s3V7-o^Pzh,\-߭쳞=WXf?o^aY⨸g]]xA("|/p7zGn޼y_rYsnm;^[v} 6o*Vd,{!; yՕw펩doŐsofyu[h);}zuzOzAҎ]?(G=awܾP; /LJOO4-/ )ݺ~;VnݪU!"/-_-ヒށhT:Q}/<4h٢E'?GRJ޼y-=ҵKxb=2[ɞhB u:5>>ѣ+~|lÆǖ=[smGϜoc}W- =~|Ǣl%" [SN9aXz %뭗_gaC=o1cǮ[.e}/\BN2{.(8|PAQ}}<<=ߣbZ{C)ɹS2Bћ<#n[Ɗؙ_GsD$(d{ckQ=w3s^(yb%_h2~aCխ[w}`+|FLl;z~$:U󵱺f7pC~=0!*.{i B)ɾqOt<G~bzu&''JDҞMڷk^գ|/ok9/u_dXAPRڴns {d5W7n(oՍ:}3My釞qtS\Cyb+WFu-CQ;噱sy[LoWJhpZćr咢b&:do1{X%8ggI&qm Eg+O?9X>UV(hr:ݺU_x!VdZHG??ٚ5٣6N}vj:tc4>ё}_;La֫'WfffTTTcZ<ܙ]`͋ݴW~e×C>\^ܹO3d@~Ru">^ B g{8mݺu\? u=_|k֨q 7`L Efќr8K_~S޸q1G7LMMUfC ͦM֬]re3oIDATO?=TC^pL8o /d?޻CypM׬Vj .%eee/Fբb2c?lY~[Oh߮e)6c83_?K?>g?[fEժU;~z֭ZlcIJJ ֺu릿|?={NnU~˟7@-U>Pdx1z츨uv9ZliӦ~Ō6"R)SuɒG=dlՍ5?~H III7~uφzÆʕ+WR%@&"/-_`{)b˒%~њ5kX櫯ݺ1qv>蠪Uկ:Wn=qƐ~z1C够nfyuo 3v}п[MKZm*+J'|?=f쇋Eci:O٣{uhqD$*HB/5c…|H^gJavbK(V,wZvH"_dŊ/>#Ly%*8@1 \TJ[lMZ|y._|(D$lRnظq7f5z/XvJ*(D$XyFC>8V|ϿC<6WAm?>VO;J5jD5ϟ?QFWb޽z>7y⏖VX:|7u3f̜Nh߮etuu*+^GKT\: ~{^TԪU+3H5k֌yJJ*뙧rT~H޼1 ^|HD$E$bgxѳG]lmڴ;+͛ށRqc5X'K~|aݔwتmMW7( r#͛5 ,)+++ _.7&M^!5}I(u233hvm`i>  htx)G7l+>\_͛=OLkओ~d~5쎨^w}kQlEDۥaZڃ7Y[3f\v .V[xbmd;nϢwѭ}gϞN;m֭[n*@ܘӧ9&Om}c@ Qć/VꫯbEɯ={ι~饗&M-}vM tjǎ?H()/s\OuC>8@iPz;oqccbHƋj-m+.l{{۶ ڷk{y}/n;֌o@QHs_ O?]c*]r+V Pf_F>՗^|aժU%HDFAۗ3%@y?;)SRGEBD2xϢߟe /O6@Q# :؟կ17@BꫯF;wMVv( 'ma{ $%%5> +fΚs[8xB(""e;7֬Y#}g='۫~jj_v]hɒzZguYg󒌥#7mHƣM7jHY|ءFEjrI)@, VrM}tڡ$eee/] " $ I H HDH@"@$D$$" $ I H HDH@"@$D$$" $X" $ I H HDH@"@$D$$" $ I H HDH@"@$D$$" $ I H HDH@"@$D$T.P'9))#+ }ֱHd"݂ 3c?^{^9}›wQH%Ne$" gmEɵo>!^7f^cnkr7lr^M+ޯjM:1}G#u~)?H=&{fNfE*KN\_wX>1n<"1a1涊a#f#SBk˙7\=c>!#?)7N^7_%R9ttEH;v+niwWrtxf{>.H;>>=|S Lm$*Z7 Ex^N& SC+ޣB<=ߘ]zr+ܕP)K*3]0Uo~_~eY߬Y2ߟP+Z6ˣǗ=j^Z1XzͣwդV9.W_zj~ܭI.vKΎg>}U$7!PץIm٦j`{vt`Objr7!ZPũR䜟U Ex^S^z sc2&O^3m]+E;63|ʬtwG7|nxS}nT][)~ xꕶlMMޘZ[w[Tw1V=|аO!rknySn~==: L26VLN#tHUJnkl6̷9,߮H EwI=nfgٲ1ӒvzDF~/7v;:~"nD@QbU\*nZيVZV>_E.]-TlUPۊnU{' }~|Μn9s圮iM݄߰nK*gwJ*WL)?ӌCM59VСɶÓ U/ҽ̼Qny3K2~#笞vqN2NM3n:xťGȈ]Kt?jyS"yHfǮy/.ڼT[OL΄Aqڸu+_iPm9>zUϴɠ7&S6z#HCGLT/R kyN:=k褜ճ"oZ&&7jrΦɛ Lإwt̛nc#e͝8p7weHvnNGa&y9 Vk'YKGޝ7ɹ9*F~uĔ1e:6ՑE$Y[Ru)g=bTz|r腻1dd^rԈIT:}w2dmP22Fnn=twꑿbWvkuMp׵_YvZ옕Zg[GʧaY*gZL*%˲C3K=V^TgZOLi.s@ƿwsX4gΦPąTw[Ru)g1x\d󇍜j]kFx,/@2^U-Ոv[=k³F M ' Ѫu.W>is& 2t$PHRfY ڴf umPOzce59'>+̛44ވ-N8FvN1znkg 10T1iJꕜLN3A: *-"9}XFZZOKK5g NųrοSzd̴gAm0ɠQ$ưG4IVwcolJ4^wJy'{5ZWIyJv)Իޥ87Y?lnoFL2E47N\@bIjCvc[ϸݸucϸ{^xwc~'ɝ[h+ g%k2hčqҤ3<#Yxu؈e u#IGuJPIF,b}ƀ9cC}uؼaH2vΐP\FM<*7)CG+_  \mk{G5a$I}(IFHQG|/92QJ12dֈ='G56)D$& bpv$Q=(S4WL1j=rBXC+w׵Ffw}GT4W ;i 4 )GDHA"@ R$D$$" I H)HDHA"@ R$D$$" I H)HDHA"@ R$D$TlDk>{5o`w" I H)HDHA"@ R$D$$" I H)HDHA"@ R$D$$" I ?)o9w%|I]G>>r6*,gI-2gʜYgأMKK e'" @kꔿ>hA>rеƼdˈ_>3=uS]Er֭GuٲeQx4c﫯{㽨ܩS7^{22$5.E 'Nz6G6nncI7w|"6|Hf'Z":|{63*/XPեSO?=mɕ?uA`bL9>rI:њ̣:̿"v9c~;K1sS>q@R"s̉ G/OJtTBM9B{sQbM;o ^zAݯ},QcQ%\ı&μ_Hg;'٩;l c󡩷ӛ5o?~K.D1$ :+oہC~zkr`fP1GD\ɩ'U5U."Y1nKΎ?ku[!̿ f\p}ц39 f.G&%'򎖉}똜:Kq[ EdT;L;/sԝV9NFv9s?xc!Q @?d4n8@]V"y$&h6v~8/7dI::nnfWLdPC:ZdAPru!(ﶙcw UD֭ueEn-YCϢ{owJe^hXDrNivJD!##{4v2=;MzR̛=/.n2*S66ՠ."yąjG.H`F.|-0$T)~g Out=5uxGF΋EfdPեdn]B"SotI!L%^]Ǔn=rHg2%{WhNwy7wOo׷'8N9rQXtgB|~pWE]dCoxQQ?,G:v(Hq꠴"7|~m(RN\'Nt7E_~%Tx߸so+ki/jv*~YqhX&IDAT_>*?vj("{5o`w(}O?̨fŚ\\iH"9nH$9P⹹}nwa ?SKHF^2ߙgAw7*կ& egIj\]E2rR>?屿{QޙN2̝>7:|H (Oy/v׺@͙2WވO\gVֿ(Ը|Ӱro-gy.׿|/EKѷ_Pjd?d׿YjU~nɐ}7bF4pD2_}hye@ԧϠ͋6mj7IJnG$D$( H)HDHA"@ R$D$$" I H)HDHA"@ R$D$$" I bI H)HDHA"@ R$D$$" I H)HDHA"@ R$D$$" I H)HDHA"@ R$D$$" I H)AѫL.sP*9clФPTaI 3dar#24)7_YL_pWKFRPRڴpCC333&TM '^ؓs6T}P׌&͛>,3--2v1hBNRO"o:ە{qy+kz0 5Ӈe5_Oi4kخꏽg^('oN~E蘑=s'M^\1o3:\֨C:$G@Pd̎EțzyNNtMTR*k׳kJ?yNQSiϛO}lPf3{zQ^3}R9d5{Ȑg/^5hpJҼ2O5A13{wnݏVwie:7-ȗ_~YxPIV\LJ4cP#6onM◭[С}l&#Yfׯ_'ɇ >&M_oG?Pj2@ME⢁5z@Ӎ7Fƍ??i*`ʕ rVO+諯zmivs۷k ""_~\!Tys΍'={v15a͚7on@ 6-nz1]-[u iРAs=ޅ/4P"BxI&M#:{%_} SO?:w 6OM6~|O׮]yj_Q*rܨQ{}Zh⋍-ZܡC6 @}""Y[̙3'.x≡b^1 z!z)77W_{ϭxc;[`GvҴiӍ7Fg>?p۶+,>hܷe˖k4o޼L{=ޜVTsT !fs-/_zxB(qэni} #@t8)]IDAToݺ5 /4њk?~(.Gdi}iiiה7׬ɻx <🏸̞?7ewLz3+e9g\6m޸ic5K-?{Nۃ*n)SMjTӫgCP j2@M3dͽ+ sY3#Fп_W ╯͘qŕ)/%&Mąm_~ȩRڶmoذuо|$P&MGZ'qӦO?+nQ'G8iR\!?;1###@!m۶n|{˧yהW.ZϏ]zu/*$<\؅d*غuq[y[bW}qeهK(V쨰~UV w}7.go}+HD2LeBrz?=`>V&z`LF {P]&>\nrێ;z!b:~Xg ;jzp֙>SevS!y߯_z׬YӨаa~V]y݉'M?pHi͛7?9䐬'գG<S~[^}6l(""ٻgV^I&Jղeh @͍ iiiyrMk~=+_z#=e=o]> 7n/sw۷kw{ $P+|ߺ͛7G8ىO~aη{:s?쳨gUWϞ5A4N$Pե.Pdӂ {?ÿ>h( o7kެŷuӢ{CIT-[o6Z1 ߺN;5з\|q\@YhpOuUkf;+>(<0 |+]xL^Чȕy4?*$ ӟ-^\lY|q/biϯ*PӖ/_z`‡Hعٸ1@S:jРA=Zishy%9Z$@mgaMs3KG9< ™>#⽨άkN~̕~Ƈ HL`ӓƇf / OGx yۊ\Yڇ:ZEO󩂗m22>ȸt%S|j -k7oVb%Gjժp1Ev ч]v g}J(Yv z1fzMĆ%GS8?27njCoWsa受/[O 1 7׆V3BCIRrr?=qR\nڤEw%=@5jڴBwշ^J<WqQF],_iAWӦ:AM4 ۾2$=e^L gpV8'  Yc)Et dv} ѡOxga!,J:PhTI=m۶+.رC4nN>Of,5g13-@2H͊;ԁZ&ڮQ ^ޯF}.{b6:} Zw~571{37,}\.:lr*"W(4m]CIR.\ي!1V ;YfZg>$k'=RԁX2$y:ڣlj'|!'D$Ĥzz=n;׌7DxsÈk>PQ;\3{5;;5 Y/19nrV$z3gώ w֪Uz{کfvqq:~g@j3zÏ>z=>8] 5{3+[ a\; AVƍKv|EKV>uRlQV.xJ<򒥑e]8e,Zdӯ{|?? =wv VIgi?`%K-rwRUjΞFӦM[lUvM-^pu e4c_| ?~hᗿX*pݏB7Q{z*@RE}:~wĈPv/1]\L"=#B[xɴN:<֭jҥ?+W ?7&׈g&=L?.T͛7z}gGxIt}qcD 2 $k>Kh)Mm۶)Zjy)J7n.ӁT@>hݾ]Kv|qa鯏pq'-TYVSɖ-[&RNNN3Vuׯ]k2OwFe IRҥ]۶Qe Cjժ |ӫgJe5s/LJtQGFL#A]j'a)H@[/K#Uf-gݰnM(rx>c'=e cE9C=Pa{~[oFzmddd>MP_w}wӦ;o /~&?*=n]tg,ve־]ہ]*L _>GFoӛjG%FzNΕWӪUbfy#*t߼bn/FSu<5y{WX@*V)({@3H} q۵.:~X^6IDAT/E5gFP 4-[Z-tI}zOltBrI=߯Ă|d_3Yp}Vp3j{?$>3N?-T&I~O=3).Gw 6H8U? K=J8Q@1N$Pzaҥ|꙳ߡ}@)JO?7L6m˷~C9CBy=VZ-]~} UF{y9g4W_\v֭[q'!ywF#2]Q8l͚5̂&IMn%:KYɧڲeKT/:@fv֙ڷo7sءC Ԑʚс@ ^2u_<>n7>Sӫ5kߙ7/*̊D$c'\>WX=B~\PSHGʺ hT-Y4*+f7ޜ駟E sě*G|7ތ~a -[@s=u p/e L}/c=t`,NZ8"q㦦Mqo 1zwϞvQ)Y=\U Vy7.%CVN9kߴi F;B :^Y=t .Z^6= Kf-CaݚPkq۱:L:cn>7o5=‹/4k֬-\(TNGw}ɧdjΞ{n.rt):̪VOd R|Ӱ4,TV-[9#˲k#o}d{4lذKϙf[ QEԡPmk~)%HUHs(ovh9PcפI}ԑ{g(e˖] Uf2ŗ~{ǝCFFFTIR;\2.kvMUCNWd6gE~t UDR'(NG$?BvڸвA-[#23ˑӟ}硺;~؍7mܸ1#uQLd{4hnъy }i-[ƅիWjHG]V\hRӁTHmPSS^2%*ԧNSPWT~DCUFDrfP+uO7ތ [9²}׬ɋH6o޼ڳZ=VM2vu| lwX?˗,at͐2qqa7/ Pˤd<Hą蜄j")PLZZ[>:q5u*+x|qDž2Ⱦo/|Gn9.wUQk'ѿ ?qѢš,Y4^2$u|S OO ѩްaC>3+^5aڵKt?uG#"Y/_>S]+/٭e\h֢GrP]ZjM5_{$FލccG7@b캌o3P/PN<֭"I@Hְo ^fmT|᧞JwEKXjո?'/T㏯]6@=MV\ 0kos+JrT.8*`G/L~q~t;ҁ@@ja7ƩӦiiiovm%PGL8)*ܷYkӺ<)7F͢—_~9qҳ9;{c)G..ASCyUQc=qy+ƛ!\x}z ~ŕߙ;rf!oٲE|; n}w>>.ZBvc' C*{ex nyYӲn7ߜ{+t 6{4R0"nLJ:SnJzǚOv}7;~/B%zmƌOq}/Y"ǟmgiZ$d%S;+X9o_]P?zY“są}r2ysX;qmv#ݻg>q؍}N9mIA̺Qs:"iߡЂUg֠Jh/]&yR>??\^;w:|*<.&j˝ߘ .?0͛G>'oͻݫ"ü]nҥBj̙3 5%VK|j;եqƟYWZLOo UdE_n.CӁ@G-@w3* $\מ<; u/KPz)j} gxx9O=1}fٍնLk^o7'5ʾ?Y9+a,Ӧyר 9SO7~gV/Ux墁刺j !;D`Cpu~ધnMtm]˝(r &LU[yA踼m۶;[?>*y7vcqw2\uֽKnOz/2Z6{[nHvC{wt߶^nſ)$ׇF͢WvIMЁTZށx ^zi$NZ&Mƒq;|Cz0o_%n9rˏԎ=aƭ hLzR>/O9nfE3S:eK[|ɘPdGOcvm/k߾ŋw]?mOWY}5DOt*Sɳ4or(1g >&$Xgӟȫ fnmafv޻YyNfǎ.\8bĈ"p۷k/o :w:fo)C(#?".٥˜[2E~_])td(U81ZBRJdp4~9[N|0Snf¶ wW=򼬓Fk%܉j$ӟ=mRV^h{P5qYI^GʸzB-ozņ[rØ%!co%MįwÒ@4 ̶]uN^ H>^UsK8SJΤrl)-ewogt>y/ gxW%is?Iضu+mf]VN{_ұ=:~|ؽ[ri׶m_r和f ٞq'ՅݾGǜ]lAdݐ;;)ŽGa3ɉ!WkWI=G޽BM81DSѻtvG8cOdNHjB\fo;3o۱Bm|%c2C-ݑCMI]hXpe%CH!f1%H kf#Ynls.6{ s Sb)ڨ5I& B1İyʺ]vt :BoR$~/Y7Ӝiݓ_qH!vdcsEˆuE<,ȭ%tE'+w]25Ӹa%g˛[h9~;GSn-Y=afJYxx׉*1~ ?5o <5`֎nۉ)ފˬ,s<[Q{rwG]GF*2%Ya\ z-^tEFWgƍgy֬Y/[?<昣/h`(Gl+x^xS 啼nwG*3dG7d 9PMFH%*jc|s{͚O8ᙧѴiP;TB,|:\`|j%+5PD"%.)gnDzG'nBi|Ӱ4,T~'ZQGv2miGѫgVYeZ`_YgyYgN>K(r!AQ̾=-@Vޣ^}M-j0b>Ġړ'L7lm𨐑Y0PkL*RBBVl  61~17@*$F;/gV?zzI=8o $*L2@_/ω _ϻ1ak _Γ>WoѽtEKoDfmɹf01쎵vzr}ޜnLbF9 fLWOؖqkySflpuTS9aUw-z\Th:*,tK@\xo{B5/BF֡Zo6^{W#{9WqF(nݧp+}5^sk˻hdٻNH?r wOQU3fE%f,:qq-V`6'?~u+ymƌ+Nît$+d%69qv`3aǜ)D<]nҥBxrMokȷ.]۶߹ϥ}s'ig]lؖ)n{VI:q[IU*mռS]kFU!Ē?r΄ߠo:@*Hv_~wnWo7_J<Q$'OUk,'NfvQh z=xKV^2{y59NYH> *z&zkut U6td.zUhxjyVyܗe^~L~`P0`F<3=A*&YpNty-d32cNvT/+E߉ n4C&w_~+7o8g'>}ay'pt1]nw,tԢg}*f CO<0>֬^~;=?ι wj=*.&YDy?h 9߽[&xZ~_]hHcRhS]¿^T!ĺvxFtyi޽ЯdSpO,7oQ(]@ UvϞYgs}]߾ٳfK~REƉhCneHt=Gߊ2|to/X|$]>FE >EVˬH$>rA; K:rMuT./0ZBǸ/;S;*eѫgVjH Hmз\|q\@1go٧UfŚ\՟ek̙3oWªOW hX;`}|\ g;J3$~LFevqCqm/;s^jIRZlѾ]h ny뭷a(=z'g_-T7iсT6fϞ'JmS;ՓQ-Yl?~hϘ=oF_z#.ϺPŞ|kW_>1-Cu)y9sąO<1T&:=N<|**k\l_}-.4o{Ym "II}vڟx{t;=޻ޡ|KIDAT7^y#Z?7nN>9˗/ =NMQGYB5WN 9Kzuy/&Y4R:KvmF-ZuߵkFr%T-ޣ*O;cJ AR t A׮]g}jl&'4Q[OK A2"ɉݏT@N;{]dqk]X!*~7yj=_SB٭\]gVJO4>8kq!===T6MҲeh)n[o-!-;mm*裏mʴqxouWqQFсTHmФIm@I}|[06FADMFF(mZlYTXpAʮoӣeI}lߟU]- Uw}Ce;sH7|3.ddMThu,]ڵk֨ Q(n{N"HЁS@U"֭ T6gd+Wq ewd#ZTXn}E˟z0V~Y\sUnݺvbR7ߜ{%;ou%N*&YY4]<[E8񄸰h 64kè?iQc=*2DQ4@JIBq4Orr`e˖Ox2!1ڷ eOVY=N7, rHtBe;ą=<hORO}챸|9ʦIReddt5.;Ex1ux Bt I{fbH`'&ڮ/&=ܷ#G%P ~a5kd:wPd8񫯾ze*z*ӏ|w޼+W~k'=TZZZ De·~_U@F;p9nC+~{ǝ>{ ރ|J@RQ$Vqas)ٱ{$m:(TV}g!u%h賸)oںuk D ?qiť`!%TMvݺ%KFKTewǩ+ܹsJ{PZlѾ]hYS@RQ$'r媷}7z2:ky'Gdvn"!="ݺm^M/l3GO{UlOO|m:(dDZ:h5+V{~P^/ 'F /^1`gV5}IRY*8n=0OZ~}NNNOѵ?M7n=сIR? zGqzVSW_m޼7FKSǎ?G 3G;4ZB6? K-PZK*7i$k'о]7i^}vTg}ʙuf8[Fꎨ#ӧ=8iRZhTxЮNbв:{G_|e۶mλƍ߿_޽NG6mBQz=t eoD$ DO@=_G'9*u|U/z>Rœ7ݳ{VSgҨQgy.׿yfh 1&_2%Pwѷ_PÆtEicmټj}ք>/^.ZxEKg{lܴ).4m$@ с$U'(E?w]|+c@[OVg?zn|gk֬YfMִJ % T5k֢yx衇Tskzb0_7+W o؍?wN+q4+W^}2=&I-2.|aC5O;W^~?gI=>lE\hޢyT|"t )Oj^'v?Mw뇆IUdV֧nuԱoTׯo޼ 4+>x2ujJKKӻ͋6mϞƛs_;~4IjnddGyO˸qmXGvm/xETd>z)@!" "SMw7lUid7c^߾rpꍯw Uާd\]v=6Zov`6 @jKZ:*L>^֭[B˖-իgV(@%" "_;Ϗ<f>{?.M̉˧,AK*[nݦM8`@eX`aNw[)ARt u$Pdd3kQyϭ\WV=3Pm۶m+Sgz=~yDf=$@rT.ڶ -[(_|1q֯?}zc=tg}vu+vOUdƱn,],:fZ@&" .{f]wߍʯ͘[orm:ȓzkW_13_;ҡC3N?-@]Ӳeh)M?vݺC>t{("/Yl>׼yЁڵ: сI߯oӦƍsz{Ņ#-X0'۽Sǎ?@唩W_#?s:AjVO?/uֽ>{NlAmd#,/P*8t`T}R'zz˖-ARy;z2:["@=CMe'vcVd:ve<`׭{wtO9B>7st5];vҋu UYD$Z*#?^hq oD*2ֆʭ[p9g~ءRB<[FJOVe駟1wmܴ)P{w-ޣ]۶=>ϓtPڪL[oλ@ʪ|w m4d1N$P(X6PI>3g=z3Pkl`<_zڵ&LJn٢̣>2*|Ӱ4,3:Z닍Rfj2@Mkz_~e<팙6l5^zyJoj߮xSjٲEtRfWt ֋/w @j#IJ}|\D"+k۶SǎQa۶mi@-+S >S~JZp@ji@jWM͝%*k׭[tiOkʕ}r_ob/{~*@V\q:aZ4o {d[n]rǵkt83>Z>q#w Sov@#Ct o䔓-[ą{iӧ&G3wϬOD]2O=beQ݋{tM٫y5A^{m\wNy&8w?Huߧw塚{ŕߙ;wn7ߜ{+ .N>yGDs_ͣBNNNOوyM7n99{UP*.]ڵmZh4HK sA/,77w۶mwy׸׻WY=ڴiZoٲe_}합S8iɒ%ʴ1ۺuP. wϬh @$" P Zl-(^ƍ– xgM?./-}}:k~)١jtV6nظIP$P[ƅ7lpi <:nv衡5Z. JϘ9+3sPyO˸qWZ:e}o^~٥st Eռe&" @%606@%xw%*udh @YޤI2miӣBY{f>k׭[tiTh׮mJaݺu6m>@Xo{&M/8o@V` @bƱ>SPFf룏mڴy5},(`yyW_`wkEf̜7C9l{Ё{w(ƦM׭[xsY`}~}Kث\pIJЪUzNI}|-[ۯϞ-[/xP6/ȣ99ˋ;*\+}f;u [fM\HO77;FPO\XrUvc_zZִ^[e :"s n*Q$*쓖bho}P}Z:?~wݸiSJ%0b#{gf{lm: 1YUWbE\ngR{ꙉΛ2;~YgM?èp!w9jWj*I{]͛ފ+PnݺdҸ+GIѲeT5{Ԩ=/n~n}@mT/6n|wO87o|Æ}'PL @m " P֮]rʃ;u @Uڴiի.]vB5MDڠaz}ٳzŃڴ(xGY**W{qQG5i8^@/zTz+F*۶m3kٲeV^~-[vːVTVR*C+Hʍ5ڻYVZv!rp)k^[iFR$D$$" I H)HDHA"@ R$D$$" I H)HDHA"@ RPZnnnH-FR$D$$" I H)HDHA"@ R$D$}|}EE Z+*! 5>t(XkKMtVJo]%mmŭհY jQPTMPK&U@gD@`r~:\r=A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@;4Tfd,XѼeUei]+^Pۺݒ[Ѹ#J|DfimZWYVZWXV]ͫוnMvY]LsUΏ)j.}wIOi%52"Z[ȱ/|aCІ^٣2 *jw7e͢N?l'2;yekZFY6⑇dT7wzKӼ[+?}wٚ#G^hChYXYM֚=3ccq|~uŇ6<4i+:2sW9oa*&N^Z}K'>ͱgo5Wo"iWYSn[Z_[}sE^[PBoEdfqoVSZV;-zꇙ."ZU`_&"ٖ/uWT0;sccrW;m]6v܋ڣ]ԫ3TOV.+:$;yk4]F$󓡿ڮZD6׮Hð]=4^&sZŕCŲ:9񺾢e"gnyq̒TH [BhYXI9gP`gD$CfIɉE jٿ-5em_d]YhC jIk.K4Ud&^=Ý%=la2h88;X,ڲ=sTw$k2O&9sWIDATחu:mf<\ӿ#]xs74W]vOg볦][Y\T]w.^"/L^_,k&, ]˺Wu btjAF~yKO9'ghМsךWl2\}یc L 6fؖܥҪ9;]44 |koü|$|vE"GD I D$: k+z&5diY3- +kAHi =3lJI~>X,e@I D$"HD I D$"HD I D$"HD I D$"ˈۛ6K>2xh}HI D$"HD I D$"HD I D$"HD I D$"HD I D$%?G}晵/kw\i0pdnn:x{ӆз=rô_z)rM\Ï<<^oݺE$}oꑧ~?oV~3UKsOSDriͲW_}5^ L8wg-0{ϙG}4tN 2<7њYc'ܟ*߻txyK&\;o9.JM޿]Yi;.qW|;&{cSr~΍ӓ\o-bs/SG>+ו?a̙[S+&pUbr_8P8gBwNJMaBgTJ͞4uתd>213'y;>w䎽{W-͹Vٗ/Y_tc&pŏrm{S;?$';;HnDpΪ3~MY~.s/p=WsӍ Y״,V?+ u Ǧ.\0m[H^uǑνλHň[t?󮦎R[.쑜446v2Nۢ]Jpih {g_J߫og̲ԽY/S#<2Uۃ;9?#}ج _mo*LoʚV0|=}~o _ށfֵy=.Ĭ "3sXۀ|ro}6"SBOQ;e{W]sgs1g 旛֮]p2lذFDr̲=Me_<|g?a?v衇aO}YxYbXoo~x 7|OooE]8zLJ>#؇qD2߮ZtW ~_ѣG>OD}G$/D$"HD I D$"HD I D$"HD I D$"HD I D$Jb Zt"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$:`VUfddW4/OK,ٲ¼ye;,j.L\fqus;\X>U[33Kk5HWfv>вmhC˚E';'BhYXbUEi_eͲy<$nٓݗLn ~eSī)~ms,a/1~XWo~m%6-8mifQUsr9ɑSd;ܾm[$+R\:953yiin#͕ӦIc?XYN-,m ;Y7cׇ=Avߺt."YWQP;g~uiNťS0lJIAⲹt^S犝W疮3lYVaӄ$`MD:qu88X0ϱ2xVg]90QSY}dDH6Q&JIDATn"u ̰Ku+PTՒҺAv-j IR8MHwcz+3R [>=jnNpKqY]oE$Ë]5=,{7Rs˪fd%yEB&"10u0C^9.ϲ]"4/7檢ֽ{^yu{H\Hd~QQ{Yeuk++ 2KjYX|Zbh-:]ZU~DqQIQeo !lXTYWv+rhh9sQ" RMYHxC!,ZʜVJ .~ǵ-K9sˋw/!{&@u y5DŽD'Nj-o;r{Kk}MYAn" +&G&W5GfT5'oi,9}Mb9U);+WTM@Z,vEW-k|vؔ+2h*ʻVgM(}]uqŋu{ƪ {{]y3vxwU%[k',ڰ@j7?tsr l:lKܼ]>2.շ?}acϸ͍#^=pA]v"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I HiC|d}.@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@a 4CtJD2IKZx빡ʺjgMwbD$^; 2&?SH$;M×CxSnIbd|jSRutM=;vHm>qm+{6uArv|0epBVD$׭ 9ۥ _钕7ll}+Y;wR*>yϕ_r#BqS̛ ַ\xb=X+~<-ܸxҒI=+n-JD';wrɣWgM,fʹoqKڂ˧65xcm:y{(ɗvLEYW-zDjt$e[Ʀ֞X#)r]b>UYWmopCDso[yMVX>{%ڻHNZBs/5cT`q'd'GTg]򭍭7$)[6[9ꆫ&.cmbxWem36[G{aO칷&:P:;t3G w|j[,Z'6b/Sȟv4v$W,lNPYy6YnJ*̺zs'wm؋H g^1*cF"qvہ'уWxO=Cf&F&.~+yuUd.N5\AXӶmsg;yHF9'[n 2^_^"-u: X)օL9{^>u\d}囦ۮڧS<4@#M/荅pa/>g~7k3_\hno?{v蹱fϞdqD}O٧&j+w)kDzիC;+zy~;IA5/_gS|'>qQÆuT6m԰~˖|~'9hE$/_yfm:dȥ/>B$Kk{娓>Ux޹;pٝN'O| tŇzh<07{WL80⃡9h`z_y?wĈcƞrrtD$σC?SO565566cF;vl9||Sɪq1NAzW_ꚯWy333C" @߷H~kny̲vy^|idnD$neþcN8D!a/ٲyo+/5wtWӦ}n_H.}Î|cU>*T釤r'?oy_-`'>qUӮ >q@^mY:לּEkR>rgݹ1gI]f45}"[J *С}eaCOTvvcyGfϞz(]ŚYc'ܟ5%;!ڰK#O*Om?ߪC Udccc, {䠃ڭurYٻ\30}`^"٧߻EsVv1K, ;=rG766z1"֝;}tvR%?;^ߞviCҳ/K'Mǡu;;}Om#?vdXW.챚YcN}S REa}O[N9%/U|zn /Nj? B_N ; GT);O,j%K'şdc{q~ @{ϧ>9'ƍ00B_hXB9PH~a}zdnQoSw @dg}/˯=\Z,tMB7xދjך }G з.;Қ׏ssN<*3nX|KYg~衇v|$ 8"x--Nj߽jٓ.)KϜo827'---DEݚg}.v̈́3NͳϽZ[[lm!:KR~ 4d?>;}9iXӉ7mЙ oӳ I D$"HD I D$"HD I D$"HD I D$"HDX,EI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"耮&j2ӺWXVݸe7o)aa]yeu3U;_Xռ[k*J r3g32+j䧥e&6.ݻ}1 "{`k˚e.>YhAՖF,c'L_PÆ -kMpȫ1t/ob$r每u+$F?v[^r>!>lEdfqMr[S(8}bKssۼNEUl?yil?="[`ŝ[*v>dquץOdnWN˟&=t܌+z޷Gme<70U_YՔ,ΙVV^LR]fzQ7!-U$־hAea aXa~vW;W䥥%%=Hn]!Yfo?"hZqfzQEɋ]3c9kl 6jI| 8ͱXsEƚk4iX%=Hni.> ekh 3^90q-oYTQ59|hjq!ƺwݰhBZܱ͈dcR9l}%1sݯVn"1 ,))H $3ឪ.2!pA䪇T\U֙.[Q=Y-x7CiX9_fD2gXқ8-9tg o< MFq伦]>"ζdɴw,kL犒N.6&5fZav]$3k_󢡉zCW̝㊊nfI[nvS 5[ž-bu+IlٞY\];Ln^[*nٚKlw^jXKR!ɝM+K\6fc[jC4,XZ1'ɐhXӑe\3sd~E{V+&TTu2=}ҪY &7Ҽ E[@X,DmYZvk5ř8hwU-k*ʾ =|Cۏ]]_`&56}}ivm;~~uUi~FsuqŋZ®m={E2!hA rKt6QPQwϟrNΰCsΙ25.׀9"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A]F$޴!@g>2xhMI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I Ѱ˃d j~D%"¤%om?e]z3&;1{AD"M/Ӆm}$F&O!|өq7$12eyX>mer)[:Sf :Ԟ;6ooḶ=: ;t>ne8!+{AD"V҅/t6;)-ymG~rYdONm;k+OlV6|pC'}(SF䬼c7%oJ@f]@!IDATB;vp6EB$҅osr3/1#y8GBAe~<os獞!3#<:*|TTC.?M ,i۶乳ǝ<$M\eScm] vH/^:x{ӆ_,ps¿=ut/:ak>MSqmWg oɦ_y03N?_?~DyDa5m/.}{rOdrqc=X_M_,i_}sN8aÏ:*C6mjXs?e`ֈc>?ib @"^/<6^2҉va!yݥ5ֽbrI*\:C=4DŁs{꫿_s 40=@/ڎV;b1cO99IHHc"}aO~Gyf˯k}b}1:̉\}?ukqz3OtAyד+W?L{‡㎻?:#H.ߚ[*>kywy_;o]@_z霿7[6oޜ9,P/@H*}ƊTחr͛O=trp/rr>O47+7nJ ~zܸ~~!{.{d_ž8ejG>2לּʏ8ꈰoef?gO9Ѻ<{+B;Ԥkȏ}>r[daW&.q}F$}oꑧ~ojWOsb9s{F$,{Ws=7[w~렃7޿|yzG#?}3~}ɱ#=Ru{{]#uuubvw{^XرiղZ^7 DNKKK}]7{x BIٻZ6jiy=#dgȣv:=c~ٳgpi'rM"X9l#SEsss?QHɍ]Vvtvccc, {[V~v[vݐr`#K, {IUa:C|kc΃>w:W{ bݚu'911SŰa~BCN Aۻ#Lօ=Xرihiic?TXdftv]SE'u~!䩧џHߥ>/ R}?=rFժU%g4}تUUg=/M]pAzG>sGƋ?Κ<+/K٥eZ7OƊ'=8HO?wJ?K?{iiiHƝ}Y_ǫSu.ϭz.|x֮]?+u9k*;׏?ӫiܗ>sgs1g Dݣuk~&#?c7iG$g, 2dƍbӦMe/|L]>ywo~x_~!-u: sWşyM?ݑ8|#f|mڕ׽=?y8. %<4@v@?>b}cuW?3:Ϯ|޽GgYA PVH@ B:-(Xu͈7s쪦g/sf:P ^K$*5UTAy$@HYYf?>kuR:*m82_'[nk<ȫ \~Cj3thک;%809:_ݸ1589N)L8CsXAw?_=Wq_Z}}}7۶%tyoG(}߬9633t=GkfHв9ÎLwީ[og9o߾]n'U<_[91xcӦO'dgO$Ս?GupN[m bj?K[7E3~+9>﷿{i?սSW|E:VR}߯=O:}9tixoۖ9߀]= I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$EDDDDDDDDDDDDDDDDDDDDDDDDDDPݬ)OOkEnIU++2ڒ9ஊVeGUyMKs'NkE͎^jGՒӓ\R9.$׷y,?y#kUŹ-&+2ϭ {3e3vNUM?Vp{¼g+K|>aڲ`Hf,Q5vQ]Rby5oI^ܾw^A4} ;G0k.Ԗ'g5cnBVțZ~o6-hGYɽ${]qVKv};}Ɋ9ɔɢUɺlI L[Vxrnz%,6 qQ}KvF%w7tC‰MKW^ž$;-MzMQRX8(9^ZdӓdmŪ}$+f[RR<顪"y39/dMLWY̛}ׄz흖9jraIيʺmh %%13z.+ݧFrGͪs/^EdF1QcCwi/yޠ[jW?}qޙK*@'%+R{?f49䠺dE[\7F},KoL#wc]MyܹdzoY& |'gWK f{O$wܝ*$z57-MMwIپq= g n^Q2d%u5m|bECVmdz3VTf5n,zfQ dMiҰwKK^%ܾY]劒]KǼF%Z~gM>*9QW>=3--sznߗ;UeM[%𩲷DR=wl佇KJ;%N}ׄs'׵YW^0qnubkZIQnjt~mKxX]MLa‚=<_\R: se$[=2Y9,/}-kh񹇯;tUcZ)Ä^Jcl=LΜ+F5^Te[Gz]t¯n㻪(<~0%y;e]Ī&f}dWl߸+& h3;xfŮ}d¨|ݖ^N?oփ/oGMZE{#"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"f"޶-Zsd6HHHHHHHHHHHHHHHHHHHHHHHHH>3jy螪ݭX.{w=Bu[̝2nX:A$dв.lܗ1s 3ɝ&GZ7?fX_ٸ2y+Riܙ2Ϙ;Sl~BMwk\xfu$ O_fDH_rv _w[ֽY;gj*tKŗ\}\šSKMɸqܚ[\)<뢩)R /]}O~C:F=zD× -f9料k뜕4˯i䢩#V'yG"ںu ^1 IRR6nXa5/6.r}f צf]7gdl-&Ot7_t# еuDןmݳ)~e|}ax2hϒD&W<\>?+7?c8;ɔaz[{J$AۯGÐ=;ةgOcl2d1 _?+_=nk"O!:|'9sveu˃YK8∓Oڴ^r ML.^nyvX_C ѡK$]DvH >=ēO= /TUWWUUNu YC;v _8!BwEl^Cqک~xhM6]{7{pP|K/wޑbIE9ũo*jݽݼ>Wv fc=>zo.6-_ݾ}33v:p[]$H Z޻{JR}0ӷ g{///ϟ:xO=1wz$;xwϮ^8oau3fv>l!Ewh# TxDވpN?e).;i~׾^㮻N/,;o8X}z.spPDHۋ?8ƣ=:\u_}/Xp˖-8"O$-+O 5  _k}I >e<|qժ`٣ٛN)CoJjǦ|O$W6Lzww߾}*D659~>} ;;'v=-+dG~7g6~{8zO=쳟~Voegg<={vh9{}Z~CYoseNvv؋c sQ'ğ\UU߻f{:d|C??.{TVhOiwsyevNN{ Aԝe ,[|f.7X+aa-?*tw9|sw;EkáSS]|ҩ_Ágowt1W7CWH #te ~#GN !R__S1cNoL JoXaŒPxr:j%Nd|}Zj_"IDAT09u W[usfI/= ?$v?wffd H ުy)7J2]߻{oվ"D233_R<)SSr:=çλ%[?,Ig>g#:ɟyV'~*x_j/Nɛo*ݽ߿֭[m۶ׯ]-طo[.%~_n!m6%|GT[SO9eo_1 __$CO>)k~tm=BqM 6VU9I/|~²)\_:5-xc}dBsyQG:SW<`ma??yrJ ]\~Cj3thک;%809:_ݸ1589N)L83ç@\Y~ixoۖXY|o@"Ckk7 ;63aPyOoʫ}}6w>nH>W|mM?-=W7n\ҶEO9o=B3lxnNZZZŪk>/ox կ͛XWWN]]dZ[Iyhӧ~O>ûE׷zm[~tm,"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"V__bI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI B=ںQQ֦Q%U;Z莪%s3vY{WE咂ukĵ%5x72e[<4xU+0 t=BG_zOY6,}?yrݖ]^;~ -lG[]Cd^qM}}sW9oiO:=1[;3f>=`O="ggդWԔgB oyn7d{^kTjzeR-KAvLϜX\:kPp(/aA7(\_Bg,)~>98R%,</tM;h;U{LVUJ w_xŠ]1=/Ҳ`ŒTX]VZyH^:H\2}e'/.ʟNv^ kO/]UKkkJ'g$UH^4 3=Eɋ꒒-W}L$XZyTϿr22GM.,)[QY#te%w0uMa^ ߿7tevK_m,י_A[jW?}qޙK*~)-Y>}bjjb^W)[2|M" DH" DH" DH" DH" DH" DH" DH" DH" DH" DH" DH" DH" DH" DH" DH" DH" DH" D'xgYfko|>Κrb[޶-kʕw3~+:~sCvd>M:?eNqj{w}^ ѣ ?~ᡣ进DOO$H Z޻b}^M_Fo|9r?pPTUVׯZl[ݶǍ/wޡC进DOnH&i-+/O]:{T⣏=:"5zfU|eO" GVȂozȄwiˇ~ 3ZwE?e B枖ya0/8;ҝUV#Ə {FoBf_imԓIv4ՋM *)M FIk0$IDAT uz2sZv#pH L{g?3aN;IƊgN?7xEgX=qJm>grs>>fxjPSS?}ѝvlSvNmE{}%?gؐ5{k6R>>//w;߀&iɄs>]j\.=җp謭Xx>rf #vL9g/pF3N?AU:ߧtG)eID=CgG˾7>X? y+ G"y̻[o[o:Y7θBfI>mq"{-Xճφ.i_wޡkHiӽIDO :I BI BI BI BI BI BI BI BI BI BI BI BI BI BI BI Bi .v"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"$"ԣ[i$j* 3ZYXs]͒f, .@z|i6ޞι}cjbٴ=~5%y;eմؚ" DH" Dh/mM6 jcAnu.6еeɌeuemم @m BI B=BUSQP^ڥ ',–] DH" Dh_ڮ(LK8a庙'4\fvvEarm R3 o,5K xNMh/HJq$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$6m К# еEDDDDDDDDDDDDDDDDDDDDDDDDPWѧUCT}nĒH0uqݻ[k_ܺfq "I$7ua㾌ɟ+mI49Bxmޘy0sƕɻ^HΔ}YzfRoc\3 Oh}2e04+ Drʐ[]ڼKV޺9SS{^* 0̝rՅw_hJƍ4ܺNW[M]:٨8ֵ \xԎYοnHjvq kyqG\0f蜗^669#f?hq5y{W^ϾiMHN]qGrh{ٸCH$[9:뺕nu]ޥlڲq^3L\~چ+G_]>7wmCu5m!i;鞆(ݔ:;eXA-,1toݒ)MwAa| LwsOX4)spk+P Yy.Gr'* [R='9g:Q]_[fì h7=4SԴ.|uaܑ7)M~ݰUd'\$1LyabMvf?s6~EERs^ښl_^NV__m ̟ԁO>zŘ k[ҽqf>+Dͻ ~gGo@'կmMg_giG_qc>]ǟx_ VeN|H$={v7>%tGqDϞ=/rq߾}C,;ܜa}ѦMH\3lhb2t1Jеu˃2dύ]]$$Dgy'|^x:tN2dر'L 8.e 2xN=CmڴcK_H:IDATu.)N SQ{]|߿2<7Ͼ7s8X{c?ۏtٴi;oߞ9(ӁB"٧FjֺݻV|ۅU8|yy~CxC'ٱ}ǫ{ ~vy 篛1Ga .tdO|Gs9h#F w)cOIwyN;wu'\;=B^yբnNG=jl!]NO]~Yկࠈ?߷ܒߧxaq}`7;u?޽GgUFBU$Z+Z8hzTb%V߈am"c5SVSmG֬S#ԩ0{GhNRjbkIl`mt:$K`Z{|w?{}E#/+~n/}azot?޶m[_#V5DcF_ ûaڕ;D몆{0"Ԕn]k ۼ<0~{S~A֭[ӍS8Oyu}KEqƟ>>3q%>Dp">MFv/ v^VaaVἆ^Wތ9"Q_o'/X_;i]]d9-Sg,o g/߼ӌ+VT֛o} @ Aycs{p_'?M4~&?1ؙg&VzE!wΦ{OD_?n|5n|}N 1"9cҍg Da_lhI7rƌ Nߙn} |#;H3ɏ|#|C|E^x'n|G~sO%~{3 GqĕW$x˗~OaSK?seQ2_W)ɄW:DO_WJ_^~OVsǼ__D?"ηۏ?%/~]߻?PS{NvS| W߾ho{iۍ[~ yoDǕLxJpqqH76}2e=?`'/IƵLq} @? Aۃ|x|Ï$Zx'_c˳IN:)4"Gydď;:iSqqpH&s֤p(պƳ, @e^m[^z_ZgqK{99a9tC0"jغ>0& C^zw;{ҙ~xwG0#޺D/v=!%ݷ۴iOQCdȑ#'ca+/C󲲲BT4m|⭷+0"yԑG^S'Yԯ~?vtt=[t2+|w'vaGuƞx⸿}9 Yxǁ_'`hS I D$"HD I D$"HD I D$"HD I D$"HDx<EI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HDzj(H~u ;j* rFGW7oeJ{m)o5>$'+e Gח2뭍{>&1G{m^ߟ?|ic2+f @ $Ӯ鞍[w{vlxMo= )Um-~ՙG77= "Y*iq^>otǪf6W{][+n۰7luDWOiN)kxeL;kCoy'9%;=;ue!ɢ]'^]#~{/{I}DۧtA *{ϰ칠Vl,1֚٘򂜑ɛ9۟Y#"ٙě^R˄diE9!7ܟe=&*??"ٸ~bkر޵-u3q3e9a/Z&kVn\bxGm.]*` IV4AQ.+fcM][45ӿ*ӂOY\i}D$;xcM`bM֤҆E'65^_u\1<dKԬfLWv$5KXZfԺ~/ʐGfnmmzX<_Q0/ض) t\3GpUu nkTUFnutqLoX噟^lo:UMB+koH=I[{;5;oW {4Pɂ7zu5\('gU>Ŋg%NU 쯪+$YV5!t\3cmǤzج,*/<({*"S\61wDz=;jH6~wu%+B5}ȝǛ*Rꂬ>OT~~t2wn]h#cnHm=-\Gڎx#}wGCYvVVvث;h;gVu:xϥ=\={Ue#|P&]!C K7&l\ -8]'IDAT5JovEe,kۖ<]&f"bcWɛM5 V_TV]mY0k̐dcw s[űRˊ{XsM[wsú{kK .kkOɽ⧍5%9]ӊM?mMhvS[g.o抎쎆dƄU?]z׎z\h3йv[> `ɔW6vƌH3~ TTN "xiM0+kGLH 3"HD I  ꢑYSH6,}xG蟭4`h;#YGsEyQx<9"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DP_pKI D$"HD I D$"HD I D$"HD I D$"HD I D$?=O>oٲ%uFرƍ+ѩSCV<q׶G?sT|5_Ư~eĈa;t5ɯ-J7<z77ۭK{<Ǎ~m&>C%}9_>"y_^h&x {<};*{e벼ˏמ{깶5k\`w%>ª{ẅ́$wHV;YpvAՏ>cTĿ{+X4gю7v$?:<0hk˾w#d3f͸ۏ:D{ǎ 2"oֿO?gēOt=(Hj^H4FnA  u˾+"n|lǎw\$ CCY׌孙ټpf^_fߒI!Ƀ:hY[_ 1"y{^}&?RzORuֆ֖c=༶fuț19s5KB钻fՉ û־~Hvuv^&ZA3cǚRrUT !On| v-XX^h1 02Hffl 5n_і[{r~&k76PۥcW]{5.(޼xQ[ޜ+`.ꮼغAKkkj,ɹ~}_L.ܴ`_N|E]*Ô+v/Jt4gTr"i-Mm!/7eʚ)!bc̞>B.]sRu%g^_ڊ4,8mQ.3Z]0rmٴTݻ>vPxmru~{/6WϘLRtdgüh3^?$X'75fc2v0;9whA|L- <ҍ%Ջ?+C|maU4ys+#ysN#S4e;ae!yeCg]͜1pHvZ}G$C\d*7dF]ISBˊ5ڲ ԫ͚<ٳv^Vxk o oNFs ݃mtIw΂Msrum]}Il2V Oeܷ*(wrK>Uhd]d9G*Xd}퀞n>yIGR&OX[=Ν-aDg_)Ã{ġFTErO4:1t^owf)n08V.^>2 / ݾ/^Ƀ>xn?7WCԃO5c+Vd2tn:/{sKO 0" }pu]/k z V^lc/-m/%o{CpSp֭{ g6]~ )pք &Ӥkû'~@_6f̘)7rG3t>}}H>W@uyþ:304e^m[n֭_ˁXioN<1 aؿqD2_qڵ:Sexꩧ!OD`ID$C@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@e-H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" ]MIDAT D$A"@H$" D$A"@H$" D$A"@@ceNVoFWַn^_]r\{cBKa/ʯn @8([7s'9Dہ-F$yśxf'${]41)M^U^Z*o(zRNYîc%9^u/w~ƮFItҹ{ʾT_t$ۖUŁ1tvBvtæh.*H?ybctiyQp}iӊ+U9aVq,a#.mI c]ڰtcƥ !61wgї/;!)"?O;/[Ԭ02e?lF$[f5{μ~&r/(ǃC/'(]Oش8/}~iw #y7S^YwTO۲b6o$;++X ?fڧ/^i@ZHfU5ncd{Wϟ;="!MٕW jk[%u5=W4YYYa]Vl_)o\ugH&e,`ޜWZ:ätLj1Jo]J{kI9"@H$" DA!Z:sgdQus"%jƚ۷҆DI"EW 3bX$+h9$D$A"@H$" D$A"@H$" D$A"@H$" D$A"@HkD׶` :jt`RE I D$"HD I D$"HD I D$"HD I D$"HD I }DrO~C=ē[l DݨQ>0vq&~t{xmah{G?O~s|_1bD5: |Dk ҍ/ϭh|ͯv6q_sۄ }=C9gsh&D$HvDvW;;7xOߎu, qc{zmMW>~qOjA*;onݾG3!" x<+G]P㪣=:p=*v+Y~O?#B8( +?Z~Ǫtڲ<ٌY3n9*ޱcg [o/kY<'p;o1s? 0"y#G,[xAì&䬩g]xo;HIü¬ykк|FVaa5cyk&k6/\2zs6W/K76lhڲeK7"MMM)g˔tiµeVM Cy',j+]>>q-)m[t޿bmٴEa%KfOא}gQ~.cKf7gwn?aC7"[nM7N=^ټdJ935v4ܲ%wNHHL)̤)L_.Κ<6Ź+'3+^Ӷ>꒝oJ7(חٷdRHpքt{C 9}=|Ч'`Ru%Zyc&l^?mQ˔%{!֬ys&®Y*qTE23ccusdVnBBAlXؙ\'.X4,aʪ%&夋+/.oښ*>ze^I\)HeVeϵ1{xxW0S%:[3y9b]仩i-Mm!/7eʚ)!bc̞>B}9,MٵdʔUc3&ٴbɃ/ f%;4w*9EV,&UssiwzKˆywgk iW]ݥVdewO蹴g[ckg>[ bD/v}v};aI/ƳЄ6-VVNyrŴEuߎE]||dw0#g9׷'Sk;duiYfX:3+z*ySo&+;&Syv2sLт#[ xϥK3WZV~yneo #c9&x>KrQɳrͼcoo^_X5ts77is}ޭ5mQ˔%d>rmYaa\=00Vt4Y1)KR Sǎ'} sUebd&oLS^zѤfukW͹;L|yC3zˆκ99c<3HTVolɌd Y/L*ZVi[bIk WEKJCvR:W홪lml KŸvlxc2)Kv^zY,Y˸0uvbK3޾dg58vf)]]YdJb}Zf-ThWDO筿ߚn~z{xma};9h{UC%*K4ή}蜣K_,XvRke|`-g(,{EKnX?g~G3qk8Ur?u+[;zJ[6 KDp3G>G~?HWD^ۏ?7P }>`=|SF؊C4-˞7ܒ d9g/\n.?ڲ¬*kIDATyUzؾKK./|KCᳳG 0T-\u|CMq>s &5a¤ 4vj'7<ၟ=hwߗ3&@G$ͭ ?Ow/ҷ8P~ww䰯9D MYxǁ_[u׿/rV2}O CءFaLxk~~vm@򾣎*ԧ>}?z)awDI9"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$AYx<D*@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DAחd,}ɵ%#z?c9SP\Yߺ}!e{kCuYANvS{im(O7lSGbhncvQU;*Nn;̽W4[9K62"'+hi[t5+BU/N״t21}0wUe;R}>驡Kפ秊VT^k-ʴYK[KyW  )"}MeM[%{_p۹sU7o+u;\>Bt 2vUXQEMS4Ք\-ysnEY,*ܶbB0ldG .2PjKإwָson=mXD$CdE_^axʽjëO4`D$"{.cdOiz>o9=-?J\qoΙH/L}鷶û۾uF3ۺwznO3GIH>h%]-xv%q=t|=]^x|_7{Y;gd'3_}ߝqKꝗ3N=~$L>!S)ɇן%%.K].|{{Ɠ;/93cgb>FDӅO+>^uǧ{wJRvll͓zbC㯩:gOǮJͽzuw_O}m^?tUtN=)7.`ngt|B4"=Q{y돞;%)J6>)_`˟Lv?UWNnz2|wvL_]/Y鳼C]hFDͽWv"Ͽ~FWo=ܷdOJN<[gפf9+Xvi3{Cv|ޣw:wKHģ ܫ}=;9g!! wpJ 9ڝf*O=kwc7:GM̸/ï"Nz'Ӆ!a3~XǦr?#>' }7wVfߙK<[gd xm"7\sS/2I5,nX}O:~{s{az5Z<}tg%3mLl_'LGq'g\|GHxV5o~=Q<0H0<zsG߾=9C>9?~0$" '"IH0<_=Xk[[kk[P'={s?{^eu |/DJDxk %#*,VlLѱ5:3g؞Jliv40Pqz!R%hUEM*dBvLb޵M>T"Y`azzrI_Hކ .k->OOn Ѣ$=_wnvivzIm߸zov "_J^]Æ~!yu붭[feI꺿"٧_fxcsCm eW$}z[tIOxIǦ:ɶ۞}y~ nZ2~ԩ^i}u$H@?-.(?$tO~bwѸ^{o;clW-z[ْ3uO|.u;94qk>nDѧ_eKſ>$nctG$_yՅ~随нp7D=M6E<"dIE,fsC11mk5!Y]z^~}ŻᄏzHJyxYi3av쒕+c.y;rϽŰ-^}.d}}}8e){]?(䜜o@v^y3~t}C/gC:}<̙3Crùܽʽ/|DƯn\SSƿU UE&oڵ-!w1(?{kz@7.=;oEV (^~!:&Iˆvl9N).]٧y!YDqᤉnyzm;;}ȋx;<իEVz,_0Q}~R;9ԼDC"zj^:G>sOXz#?m RDwKE,k^nu&Qr3f$/_:o߾7%$)ɸ|[|phxᚉ׼B/^[ZtqvϽՒ K;^n䡇ޒ{I' ][pUU%no233- Ǝڿ^7_s 'ſeGƵ8=$:'8r#b-_X~1Sm$N@R)"y<}pnǢXw I;3G@3G yiXՉ7l =+;FKuuGdez"-xԑG|!Z˯gG1ꠃjHH )|ry}x† kc'}nB/=mC||`BܜUwpC>3ƨ>ƍohhxevdZh+I.ӧO}:r~}9iXՉ7l Кf,"HD I D$"HD I D$"HD I D$"HD I D$"(-hE I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$굧ʒ=I+,Y\u<-3x^UCwo󑢊Жm5eEyY-7KMŔnsk޽p]ׅy=]W 9 lMo;˓}m{jXZ{1㯚~SMrCX^&Ljd~i],[?'.gXO/WOl*Z->drKb;-hZ^X#HK?7l^k*Ͼ:^e׶&e.y¬ߥ|BVHcUƘ۞1t"[8wMUuyfMkW|ה.o*F^ye"+~%EfL^R073=.ySya/*KdWM{fWXTHf^ymS1fjIiqS2Ԗem3oi H\>0sg6+GO+=DwTYʹs,[ZVPp}SqЄ½K eOr~MmY-XƏS [쩕XrjS5fqݛnFyfq $ְfqq~C,lei-88̙]QvV^vƢWCH/*jo{o]MMUgvn)H9HV_u̎/qy}`ΕZZڭzzԥ `yew7L)H MiH/;IDATo E H5;x^UݶoR5oJ[65ތ).m+)mZnxF2bX%YƝ󥊢& .=$#cmK~O|B ݽ˲+͏QQ?кs^Zߢ/*v}mP"(syڽ:#g̕wkGv{أl֗V6m;{m^Z٘l⒑H){" #" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@HLj[6h́}3lH$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H+Dý_/O/RSO@d5sBjt٪͏_?q "}&.lt]z_HSa7?s7q5\roM]x3ef~Rسe;koѼ2gm4&]NN!}n܊mnx#~=1{R">yέO~+W<u>pb5#o\|Mt慓MS2⩦ʭ;w;eaC7_|ʭmbNX1wms{/>I4g[lJhD$5]xgĄDA~щѝ-ky㥏j^pCVm}O=zYbg8E{M'zsۊ+{gN_hҎ.>ӼLh`OOaσ-Fpt:C4"Q=olnފSv:z$厖kW +N)lNO4#wxz-$׎snm@9bz,"#"mKcְx߭qD2Nk>+V,#XYaZCptΊ;v:wSӑ Axc[8g:Ѿ!Ӆt\L9O%)ٱ#>aL?Ƒ h:Ud;|nq1_3׍~ݼmSn#q ? rgd.Lŷ"YP/nC2miI4d<:tXWsƿziHՈGW [o-uuuǍ$JɃ+>=#8∐6mR~z۶AGGr6=_E$/|\:_ '^pHxTa3K9±焞GDo3g:[Cvܱ/8蠃BT>9w7lx1~޻wOfzzSIIz>I&" @Ϸo<555SsL>|x1g !H/X|~aÆˮ1tO}B" @]$](^l7n|뭷ۺH◿洒_=t_4yrH^nݺm֭YYC)H闙(ܐl۾CY!I_/r{q'~{ұNmg|g_l_>uWfv_!" @*.=Џ~|sK> J ] ]4n^|m=c.t^!֭{dD7:o(wݹΡgM~i[D?".QקtAA~o<5;"W^}u_'kncG|,t}3Q_`ӦMzH.YREơ~ܐe3҆ofT9/}%@׋xDrUUUˊO}cg̊\A?Çb؋o>@xD>Q2ꔽ.rN7 ;/{[w^qc޾فٳF~Z>z|p̙!I9rf@JBޗ >mpX WhOmߪET"YSSB~Z׎5{ua坷Y+ CR/ZԎeov萁GUSS$uaD lҔKxSώ?zj^!SO=5]WHϿBj#9}'^]v}ÇYƃR)"t%"]{ѵ /7,6|17ԆzE3/ҷo?WdwC>8^4pk^k<}ƬʕM׬W7ZraI"ya}k-񫊯<`LKG$gL/lyxe˖}&lYǯ]}'Wziiiߊiׄ$꫉C 뺿X,ě[6† 9`@H=;oO=O}쐼6^pqlIpz^!uuԑb}Mm萱cyt '~Е>~}8?$)"qgyFy?<\y$/-:M{W}ݨY|7#@ϖb]$w%:ܜ?^kxW=3FtA-=3 )!#W./^ذ!~2{LvMh}vEwݽzOWHY99joN>"y'ڸ 54L m%)?}׷QG8/>"-:MZs`ߌ=@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@b-H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H+t)yS*@w번䚲񷯾}|Aٚk5b[Օ_%2G$kr*(Mud2w@C}*<K._X}yu;dvn^m{ecZn7Ϳ hon'7?'QfcN},2&Iٻ3+3U w4̘d{=p}DYM33۱:+Kێcr ID$}YYY{ZPQ}A9م5)W o+%َ{o۞7j:n$$l> +g%,-N,,,3\~UQYMwﱚnI-'/-Y ID$ψs +F66)[i#ENQAv=VVVvhgOމM=&;d$f62p^]l^kv3Y |xuٮhL0 /tݽK Zs2&t e ev5eilJW7nv%ENQPtIǘtH  Hn,?-.kjŶt VS1wyg-kHv©#?s,.@7r+cJ"@}DΟrI_2 iX,D"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$cD-9H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DPG$zǟx_z۷wq#O?ppnn> iXՉ7l =#+VLۺuGg}˿o;`9nvivzI[o};O{;n:Q<Ѓ=/=gNj=D$ΏH闙(ܐl{lݺuܧ}}3~_9긣sÇjKÖu]W[]t`~qrYMKvϕ="DҾ!b/^riK>2ot^ҏ3uW_4w W߰}W_8N @Rq璊D]=ĩoC?$^o߾]R)"o\69W&꿭[_WE*E$TaÆ wzg˿X6qxѲн_:7Qӟ[RD}y8긣^hkG,r@nN;jċwNlui]HkFEh bժ^z)]/"UUUbȨ!z \Y~FmWPj#=Ώkvw~lժtTH'SF:bec[m$]c=_O%%}rNN ӫWgM ]O̞5z=tȓC~flg/.`Ōc,8;C׿^zOv ~G׮,_Cf._hT"θbΠګnz_Y+c+g6/܍d:wztZD2 (G&uaD _mƯvOSvXٵ׆k^圜::QlΞ~ݞKƋ6fR?8I"i9"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$AiX,D.@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DP e"t5 r3[4=++dq]H. Eoyh{}}u\)YH.Yb99;l+G국/m}%s&ȢHS"liMge7V陹UbʩkODr[ME̴ٔ܂yUu@Ú+,Y\uv-X\Rc}fumPgzhMZ,kkp[˹Oe-5e\UFN{4?|BEwo0tUŹ; T仪'8gK|dƘ9zik,nK3&qƳ Zxzɴ_?e}Vmsr[mO5W VDrMIэMո;kd5lUPrЦWMʑhy t2wOLO_:srh;g$JĚ,$>uZH mD$+j?Wy5U.-qes w{<O,}GuUMHޞ#5ˎHͰP]kqhaAN(Y[U-t^fg6 ]iމ;P^˓K+Z۰39* U"?eJFSq) J~M:0t/-4|Uuj*dϭ/-,[ڼ~[ÚWښo76Vd\𚂲 ׇs[)Mu]޾lwUOȪ*6zĮv,赗¹5[kڸ3?g+6^ZuەcrZsɜ%v#޺H}@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A{HeSH溜$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H~zɒ召[nË/guuС>~?DKZ,ku-=֭[gy-?tYG?C-wm?٩ )zRǣ>6"M7D>Nu|Sw~H~}WwK8O3~;83S =;{?Ûnjhh#~9BE؝djxU4p^K\{.?/{;?{uY rkSSf2~eb"*})HWNDhX(3Q 4 7CS޿=& }x>q?u}N}9###4)"lYC{?&ɶ>|`睗:l&Oꛋo<l;͛75w:j5k&ND 8T3o`[k֬['l2Q/^\&ND2UTT . 8up1z&Eh:vi!4q,bdR3m۶Yݺmqǎh>*l;};o(斕&)E$wL"7Oԧamk.qlbmDWϞSf͚}gUviζ}DrFNcEjv|vhR&bV_L{Wh?pMGNFNh[5k,Xн{l,͟*bNٞ{*?|hD$ҥKxTӫWF֣Gv?_DhD$گsm8wNtѝxwRŔ;窱 Mdz䱢.U_|х1G}PVVx0x<hE$ Y#rg\^ ]dS!CSo9Ž 1+l sG=in&u2)7o~ݵR'V MP"WNx^fM(؂͔Xh,˖-b$;th×/8i5NpI9kuYmRlPu.+?#wظǭx_d{߯߅? UP\{xk_"@#vx7sOFGaEݚ5k&ԩS둕xNY={R:Ϟ 8~:бWШZYyԴ,as@PIDAT"S n4ME<=k~…yi'Y>ʕ+@SE;*n.:ll~E7Z3=M0kDnթٯ %ts=6sS߾5S:_q1ᑼ+gyVCCl ^ޮbTqEusGtxdؘ/1aEF >UJV&57j?_9N_FPݫS9OϪ^^ՈmQՆ{;q?o^CojW  ^PB^e^Aˤa|d# öVUŗ^|}3fL 6ozҠ:-AyYF*w٩z[j7%{R:F?-[o?gs_|ᅇ}}ZhĿzmo6.5i[|{ {nzڹk7;⨒-\YY(06fZ^~//Ay]S~{ݵmڴI YsXkD&jfg 'yyK6bv;ퟏj`N!:-87q0ݟhU3x'Ռd[i#=&9/\*Er{|Y#r3+Rw7A-5_vP2e9g?#{G^bBc%Y1e3ןrGm? pX,HLv{zbXYJHkt '|JϢEg~{Է8 `VZ˫]kƏm,b6Bp*93N?=Ut́Ɍ曉u6H`$;Y]T1wno~Jt3ٳ_k22@8߾`$"YmڴI͝a;,D$#Yf}sw;T`G"lk,͔ |$QY6@TGvvHum:]!n:U^&ibo53Y%䣪sB*]$"HD I D$I_9s/YR^$lw}=&HDto ya{r]qW_}hjyUBg>_J>?~ >w Mʕ+SEL(}Sł BqQ%z[g|n:4*d tߢ/JSN={ؾb]bOo<|\;xj}{wzvۼSE,)le}*,yO> mѢW G^e?V[q5&uX^ʟ<ڈd=LD2bX٩׿61W_*vi~א:3 Hw/.irʝw.J~s'>{=/Wǐ6~4GOXf͓&tg}C&nxQv`"w;Dz?Ҍ3O(3UVVZ5˞|]FFF؁HF߭&m6QTTT;?+V43,Ud'sr2.2l 3/ȹ|&Vu=U/裏BygswěS\777D$_7z ^7^#Ov=N{CzL=d3sn VM$ 5tFVظnZi+y'+Vw|p}23&j*=:vͯ5w2x~4Eeetw=>}Bx2?;E6`-:Ϟ6R]$322qDiv)mڴ ;۶$-`Щܛ(~Z/>}Mv< A]Xgp+Hs<{҉${*^.{9lcg60y8[WH#b:Ҟ$igT5ɆUt P82e܅sڵ fo޼yxyO鰍]0uv#??OSN4"v rVW~E{U!m*3NZ`y@DtQW~eE{Uw? iֱꑗ]MAF<wӏؾ||jn{\<>|I*ߨ7|ܬgszz5*NG;m'"Iz)ypC>=޷v r'=vc|Ijp|Yg}iIDؐ$igWu%D$ 5s{kVn! \=أM.3g1Ω^$!I6"D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DPF<Ѣ$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DPMVL:YE;my̢XխcYygedל:3?cw҂XCbM)IDAT>LUٱk%{@?/e2 >ffa+,,*^TUIAV}yKkVT.|C{{+CxhZy^* c5Ϋ\Y=xI2k/@шd,xGkĒzWo&G^6%O]⹷խ{6#uץtnqj`i.-?xEQkeu}Y};,oϽNIYyYmAd,O63?Y]$O) c.>:+⦢).+-̿3:i3K:9ںCf S؎ \2/YzK哇dR>MK: Go|'q mNDr)U /*(HE2m)oJ$[6e\$`tWAUL.fI8Y%w,,04ABДmFDbrQ*!ٵ 7dҵ辢.9W!Zwxtxf0wiChn>7kw9g9ot~t/L~.b%C=)tDrA>  T?=h}˪373axjZ~C3 \nTYIuB2 ВܼҲڎ *rZuHBTm2"YRTTeu8rT16hH*#d!- puT{1'VbCT TDdʼnk=ƆX],)** hm4ry+W27baPcOhSnJ%$}XWT4&غC*kXUg 6%%%YvȟrGMHr)hb6\t_ظ&OKe$cy%+L)k`miA,##<4؀W4&USƧ'Tf'V\q. @Ӳ䂢OWݮ[˺V=X42k_Pץ2^t^;=hAEy?,ߺk IMF"e'/.gn0UPXݩ1<=&!ʌӒy#-\VQ\^Q6yHfߛ&b^nqu&y9dK%G60kc׈ d + +gqn.(̮9(-rSZxGXY{\;S7w:]Tܺҝ.~({ >w=ɃbՋgtgEﻠ(; 3M@muP`soC;_;تS#/mJ#W,ZŇgiI={_ZV^ܤ)$@"D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H`Dӏ *vn>Ht"HD I D$"HD I D$"HD I D$"HD I D$"HD Id/Ҍ3K~fѢEoߐ_Y>z!8;oٲeȈN|iٲeoB߯f~moeRϞ=Bs`G,aΜz0,ZtuwժU@IwOg9jÑ|:tHfW^j뫪jkӦMhjtv4"lo=7[XbEy5~!g4o ='z*ux}M$6՚5k~0th*{>ciLg}f>0Kw@zd?-^\o.MAu͸ݻ;v͚54&"v5q-g~[:*4͚5|뤖-[&ŋz@dxR]n{L~4"4H,bdR3m۶Yݺm)/Ҍ3'.Zͷ޻>z!8bwOڜSv>=Q-+ L}6xٲeoBx<3IsmLٳOTQYN mƧz[ n|hXճWΙYgxqy^hёs]iZ#;Yf}ٻᄏjժ vx<^ħ/ [v;O>ͼd/&N=1lFۧq$]wCZv{zv;y]uvh^7\qj޽6m4t־λ&'޽{vo'aYe"К瞛;bwg}DG&dfe+ϹcS2q%kV#PʒO[}aA7|o9{2g=r+RȌIoԩSCgUVVC8tFY$ 8IEZܮ727uC?d󼳑eL䂅 }NOlO\2ek.r?IDAT{|֬UJﭧ_W9sVYa6[~c?{snj{儍74"vQFVrT= C b9V4pT:V Q\Yz#fUlcǍO|6}<?Y٭GM/̬hڃ3ÒⒷ ػv(k3.AJ7\3f$>K.ZC6_zEZ-jQ;S1*'t{Kge{caeɹ999S7lNFy돯 愍5b!6jB+Y}:q+ώOjbv cu2S\- kfةN[ff}3/O/3̽Lm8V[F$ aIuccbF2}X]id؜FnEͬ!6(6&5)lg&JDG]U7cccp/{(͞uGFh6Aٍ݇M3-gTqqlD c몁9{k؞408ʱ_M$Wݼs$8nF%ZVg׌TL* ˫&N Wn NoeaU48񎃋 [6"٫g@alf_dف/_L8zbh7wnY8/ݽW)qlj{~[Gvvn>H"6MMEܿ g}VxJa*:M$iw"_^ф&*Kw&Eۿdu-\zoZN܏?;33G?l٪ehLϗ>˳ũK .hD$_ fWzMg|/QYfMy~=_C8tN٬yOΛU;77_"m# zv3d;O?4qV[w]W߱s&/vqdw8!ҮC m\> +Wx l{tXx٥a۶;m}IuYPU&g6eՋߞ{㉝CKxRVu3U33^tje3^J-I -}쒾K$kcif>(@غ.ql\zSQe.,CcDzOxdrcC_ܝ֑OQ^2~@VjyE8}`MOJb[vBTƲ Y, 򬂚L‘S'&^V2e@W0䲮bŝ- Wɏ%[7:C}gt/uY%7}33xڄcvޑf6tҒ쬐*Y/YZҒw쬆;MgKHv_'OK;%սc򫣓+n=iE8qȠ!H>6:uȐEfXMKnfd/󪃓W) N0Yt7>)d꾓K˟Y7TY53?%iEY`lMD2!`mGF E']rPe՛p/(<$K%G662miP;+ڳ{yՂyݹ4qŃ:-(-w=3?Ns瓝.{|PUsg[:yPl}y폼n洂ܺɊ)2OoEV'Q>-?meɤ'[w0?ù]v졝ZFZu:}iY5rǗ.[<㺳־f}#Ϻѷ+J6GlH4]-@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@5sқ.@H$" D$A"@DIDATH$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@5 ٻKMӒ{44d'O[MS~4 6WBtaM_$G;M^WbNpxxh:3e]zݸ$u+.v| kV& S l8kD$_~6t[/]}WU}&X`zbVFDuӅ]sR FIRִl\?fA{q]/wHr漻_U}mkxxȗwR3_=[[Zm!zz|TgYguk[6l_]y0<~CƟuw|Z-}٣oMv=2wڗx6FD6ڮ5ȣo6x}|T2Aj^rCAa܏W=xmrɍ=_Ӈ2KgNWoɝT*g_@X{ kg!9~mW.>5f ٥p[zg økv##zd^R!>{$Ssѣ{ha>\|ϾrwaSc^ _^m"#;KCSg[xVz9٤᡽~]vCmo{n۶ޚ|DrkϺvo}3z:od}s[{S+_H8C}{hmťO>UWނʼn\v-Z{kOI_h7x|BsG[.ѣO`kգA.ChG{%f>$nݻW|M5"G3wn+W<=&I@jm|_wnٲobX+4A%|—_y񥗖/_ڥ'iFL<ÏsuvN|n"aU3f>+Iv9:I_ѣG;j劐222o-[h'!*7o5kּ[֭Zu;`H3;j 5ɍ#iҥsN!-" @dHZ#|kΜ9K/ Ծfv%'''#wd M䔻nݺUΝv)l7|_# QGob!Zt m.W*YW;+W|?ڊ]V7l/<9]_~ia%^vٲ˖-:-xh}]uH|TkR~RErmgqaw>~׺M밍,_+{r]U;~-z-]$h }4?PԹwA6ӏ=c8+7߾?/EuZ8T/l|d{1C84u8˖,y-E#c:Unwߵa{i[&uxq."|zOK;1l_{~T}]w-]4/3fD~ǟy|JO^qa+0](֬Y3ch|H-+K7zO^qCᡋVݩSx]w/[<@xD2UM.}#suC-IׅמP7 wfvٙ{oʇ^sw @k.:ll~5ީ.;GP6fךּk*څ]xa^X7Hd2UY z*݉OlW.//o}7򳪵DU#F$N-wڬu뷄ܻ`삵gL]s3æj*QSH~Wcg[dS7c٪V>B䣪 k}wvS7Q}$(Urɷv "Er=L/< .LNRDr]wSOSzNiٳg_t27o(^x:|yE/$7nٲq @kJɭЮ]CJxӯz*l_UwyCڶmڢ'[(Ʉ+(ޫta^>xS S=cW`~Dr|e7|}wA*Kzˤ`hvs̅?!Q/}>GѿGwmkF󞘗>Tk/)yG`{GnƵk>Jq۶m&Nz῟w_FFƕwҰTW\IȈN|Ґfof8#ԯwr=+\pa.Ǎfr/>=QNvnkp]tWS%ass} I1zɉxiܶ}g!A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$Ax<D.@H$" D$A"@H$" tZxIDATD$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DPg*2˟V /.ZSomVQyGi`eYyC^޽GWYQ(U"/ADԊ3EkU,5o`mTS|G7iřh`i-QD ZUM* {rNēk=k콟}n>svɧ,({d|+[G$3ǔݙɹs]rtLg/ijqܖx}⃵?fʶ&;oT]Ro%rO~kuk`?!]$3r OOd'(*Y٭%l/^yݕ{JJfI̛TxJVbҪam)Hd$k+V|ֲk>zAiY33++ZrB7] uUU;.I&$ C^AA!dXPSfϜ(rs@F$Jf'>fd'ëK&E¢%{m j '>\k|IAv蘈֚3^2>!纒IL-.)NgOSHVMFriI>s*woE1"Yy1i;G 6>6|3KwZ4Y2\E$kJdeL(^9g_u[*w󸵴dB2,D ))n>'&=ioSDrEق!l3s9w5[dLvW.YX0lgӳ V?3M=g~ޫ%Kŧ” 8%+1p=_x^z'% |~gW'?3[X4H~]*xЎ.-K6\tUaDnrԴaCzf8{m{AYv^QƼX|kՇ/ @HbMN|yc,]ueuߨV<蕧'rH*-6+tfL|{'wk֡=zHm>"YO1f\=~{X93No33n8/֗_]xm~FMebOdbqŒg*s W>6ſs؜N%[{H:AۯƢGwC6-qӦDhOߖ?/=S:kD=!r>Oھ}ak)y;F;*IR߁ӦMkrbGBJJKK;c>.]\6ݻ8ssNׯ3~޵k !5=@jmGރeۿ )IIR$-&" @?='|矯mc:tȳ>gd]>~|hݲe-[23j_:"٭gF`S]KgGw$PZ軅lֽW^qҗN7߱'~Hzh#[l}W__%+Θ8~ͤI?m_!" @g]$SO|d~}A!'=1~wy?+n}6>~̙{I @8 D+Z4dwfޜUs)k=S8%yO7N~-"{-ɢ[ns:J=xHCztG$yyL7θ G}!t#|/Yϙ;wƍhH.\XE{] ¾(ihMKB]4n=ŋ?xahH._"Y䝙K& }ҶΚIDAT  :bܡCs3E㫯~vdmmm|. 9'g79W>ʬ? }BbWݰ!Kh7zfb3|駛߯ߓO=5mڴB9Cron,HȹadʊWO,ϼ-vy]5QՙHVUUb*|P5ͪkztv"R/{_4F79QbeyML-??VwUUUhvH~>79Y0qQC+e K$ƍ=g{v6יn#82YY&^VTZrye'3]:w^q|S޷dQpn8+!NԽgF߯_Tˍ^wȳQ>"yԢVYϞ=7m/6oܣG=[8Taß+׬M9:SD޽i`nXuwG:SD23F@/3gKbMN|ycHy8}ߪ9*33C{ :Y]g`:椥X}։HֻW#N7ls]]{uuD'žnݺ/=:s})"-59rh^R@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@b-H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$An(3mw3FUmmyfV}j}MT^v2uȂ]sVV.9|bc9OYP,cenغ5mD2&3'qsX-\SG^?Oly^'>X{cf4ϜP59ouKJ4\8>y;~Nw_k׭\kH玞ˍ7が܂'JV|zvki=ꋮW^we"+힒ҭY3&-غ*n+VW51'j+V|ֲk>zAiY33++ZrB7]Hn92Qf7󙺪Fkf$Y! 2,(iugI9ɭu OS6yՕN=|OW/MË 󍹅EKKrk]r{O|dǤ%{%~0-.lFƭ5+fɽdN}Bu%2?Z\RZ'Ig)Hf$Kg r9$Y9ފ $~L;!ԇ*OyfuIN&;K'M,(8QT,svhfD2usG\Y9_RQsrki=ɄdXp!i$SR&˖u^'1c'v/x끋{<0w⦓zuN% j f!]P)$n9?{39h;sBYŝ`b}3ɑ%iK&O)qJVb5{%#xf ezIH{vCro\1{vu^8!y/-K˿ Is.ɞmb&'*2Ovx|Bf+yɜmL-|AL_(ᦦtQ?^KAپ˦}{$fuqLvߴd13gRDnQi" yu #" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@6"rh^R.@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@aUzftyբ9U=SH1QH0n~f S^m"^vM6eL\Itrk!6]?r墰hb;r8IDATW&iL{6|x]Vn|}v١5€D$, 9J6eo ~>.5K}^u`f8^gcgTM׭hˉ^z֘d/6dPeg>9fiK&N*98oc yk _x1ɎYﻦrt$eC굫N(~ayÂZ~_~~rrm5׏6<7o~=q{]Mf]$[۰t J6}~%~Ѱlk}ew:z$厖k O_U?fY;sGZy;ZH&fw65yw,m#"mbĆX{~hٰ >)ǜp4v]Ƅ&V#XY}&P&YvNYGg$oL@f]almhC]Bԧ /N1%qSvÁBnE;Vl؅_P6x=֏AVŃvpiY1䢫}~` &r 3c9n[U rͲ2%^v7ب>|yMDZ,krCg+ìFGc=>}:*tB6o\?qm6nlHI ud /z/׽zl%{ ^OA'4Q!H6mZ?RRZZq{w岱t=DŁs~]sN )栮R[ZW""_{SQ{!CtǿC?-[lْ'P )}n=3Z:g?$Y|B-gmtR=CCٺe/W.Y9wk&M-l>o AI:"~w5#SԴiB 뚾M96;f.~F!Sa60Yy+4[#WUUj_3ubU:fk%dߑBUy"+?;M@E2e_hύ\eUUhmh{h~G]a1"6lf*^G Z핗^I;{Bm"3 GqdXbMh7Ϭ9'g֫\^,2 @LmΝ,&|m\39Լdd!Α}C5F$O=E7H^\pƋ5+,}tih%EwTs g{>}^_ٳĂ+E,ޮ -7sB֝׎v7M)Y_5GGw$P#qֻw{Ʊ7Z[com w7[tYQ2yG!<~_$?SvCxc1.xu`w[_>+i007'---DŊ/lNE޽qz/aßޫk%:|w֭gGwAsHiXɉ7o ДC{ ,"HD I D$"HD I D$"HD I D$"HD I D$"(-hE I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$:  22 ʷ_󷺤Ϭ )͏HV%M(Һ Gf4,O]TVvoՆP{š͕Ohx%UY_U6siO[IDATu,o-SUx/KKʪBkߴ}:G$sEN~nm*+K=d?Qal[ʇȏW}=5$=ђV-=e7=2>;@GhA]33wjK[-t=[.kKޖ~7'&Cf잢32fd~QEafZZz+inZQV2!/#--cByݾ잢Z("4ggb-Hf6t܂d..=sdq+`gWU׆m÷MrXs\rC8bvOUv/Ђdù{:59;tdj<33y_[U#tsv;/dUSU "2{j _R*&e?g4#?F\WHD9<~;aLgl2FϮd;kQI|"&VmnaE0"v;hjf~zZ\z̪С+"YUVt[}miIYU}^GWS8>/`2 ʷbUN'Ul>A)&>!`d`'٣' q:@8h I D$"HD I D$"HD I D$"HD I D$"HD I D$"HDF$?ܼ18G$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@uOª^ =z|o;.?|bXnR۳˖?L+t^k~w5C{ 9mezqyjQKg飏>??7:?ϾSz򩧟zxq֙g~3[4"DRG$Hlklslٲs!y#9y9Gwtvnv\mʋTWV/.[ojdšUn^|k"WzԢJ<"DRЩbo\91wf^/zd􈿥uϟ9ضe[|vکN`ayy ?}ꧩIc{Î<,^o۶Q:SDr$끧 Bj;8O_w:DgH.,xkzsp@'xg߼ Y_љ"y}%MK\fyܡcKl%75S^~,/_[ou+Š5끜7s#,;tG3iȪ+C5zHd:SD6Y >}ph7K^t}Ώc=W8@V?>4GB6Vur)#l@M=3zG'?9\6e#BׅQO6|*Ch |gw+_Un^ d[I}!+?a({؜5k:,E;BϸǞ;g.NHR_|7Qm@jǃ?T󵛜ݳckV9B䞜?nYڣo}.(v:`7K^t}Ώwy%^yd;jbK 8_E7O-,E#LkV }};Nd'3E$ K\2C䜜Z׾^vZ_gH^|хⷿ5oVQsn݂GO^}EJn,4lX>H@GLsG/ޮiMXl/TqQСQu>/~d}wљ"xwO m"퍸5ְRV:~j2yȳ\|Q:DgHƝu5ɺǥxϽR-[|㏿9t.)~yXq7}~9לּS8Uk5*V-r~2^7?ӧO:JG$oZfz]o9s, )}7xD$d߉HI]@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@b;(Dk%JS C  תhDn[Q^:{+[{o%ڷR/(Z"8PeJ![-C!`dy^{΁o@" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"7yIDAT@H$" D$A"@Hԩi-]Q{vaQ.g3zE5*J2WPj['*Mk?Nپa75`O4,*b/NJᚒڳrzM ]IݙZ%^<ʙ3ѧ'Og|B]$sK&K縴:YS<>3܂YK<#Qn̾hn$겲=mn٭EKқZ`MY^ZZZ^"`;<1v|~hᩦ+Tj."ҋ/(Z6w[5sMYÛ|YU!{BE,8 #޶Y*U^nv;`Bb7ѱ237GbB~nY޲95kJNCK$gbehm,,>GM̘ZP{"xE,[QD9n"!dhx4_vҲd1S<>3ʉ}RkͶv axqqVlNyYzhw-^V&)KKK˫߮1oyNDNX1VK"!$FP)Z|YUO,ZX1c@zIբd_|N.&a}< E$CzQ]ꏲ|¢̴QRF+J2UN쓜S0|ʉ}'3K*7;:=m;gՖCKsޖ1z֜3Hb Z:"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I HeS|[.@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@u Ѱ3vxI蘪oءڙD$C`㻛gSe7pȱhHV ; k2&?=Ivx4(>>$F.\\T;3y Sv:Ԛ+yHO\gLY,6e!#7ߍVOOBy;W<‹.8o~aƵCV%fn^u/ oY0kɐ+pщdbjM/[b^6Խ6O[v^mqEN ӿ6`FbFDr}g]ztce_;5 IY۲zcKW-~&FW3.Kͺ|Zhu;zmYak"9fک#/K`!@[FD-._7.`IʺkKX^eY FW5Չ|dC׵L}Ύ@9drj/`K, @ۈF;YrQm,rm֍V߿lșYdݣn]}a 낕շ , 76҇2wβ;d)%w|T2e/u} uHx}ueLJ$Ѯ0PҿkIݬ_ 93+ôO>Hw_'ZE[ἅƐK.Zxwb`ݵ&s#=ncnXvٺ%Sce/M K//@Hbxo˦Q,0{pZ_]&K.R9uYaZEue{Szh:|DzkOL/ٯL=ffrr'ᩛ9;'C Ϩi_'GD&'Wx7]{L|03wIоuȍ#}vII?IZMDsÏ|X> ܻ槧w}N8~_vŕ=p'-7gffhEH~ZinrIk6o[oرcK/݃/oO*zxZ/[nۺukffJ{WHv힑*ݼgeVx/fV8x'1Gy6mWk^[ʻn~ ~pci+X~$Awl~=YzWi~a/H?0?g\pȱ#w݆6o5#\6BԽ+%歞;Εw8u@?T]>D#流ݻUzP¾;\?-D#owko gz}?vw]6m EX,^t3vf3UwQݵ{x,* {_#WHyvEMy2w{WuUHnذ!U?n'ggC !/?z+{_tힱg?i?D{qc?>uJ9sv;WHYb*bWj}[kWH]$bX#浠%Nw;KzC{dI?[ZW-9s @+ň仛7:Xsg_{+/2t yO/Ι5wJIDAT6.}Tvɩ\^*2{ ב"s*2xb^h'O<1{_q?>-g~ŋ+>Cϼ|b8`T:RDrtƋX,vmưo/S/߭[_eOZ)ɸw9x/-Z[_e|OD?"CnM|cWOH32z` 1r߼?9^oz{nk舡??~Ph#XT,x'_}aW>"9erm^7o/lҭ[V][:ߟV:3ޗ;O63*>}!ޯBZ,k{[6vyϯ/}峽z[x뾳2wܴ9=u/ŋc>jgS@{)tgSūUa9eOϿkny熽+珉噊',W?Vj[3b-cUPrmz\.UsLZ#E$9'94_yTqQGvgJ)"SO OUzr~Z/-5z-B;|g͚33Cn=oN_Ta[gss=<3g׍y_ySN>蠃g>:| ފ~g}ǜ7W_]pϽM-N&u VNα}ssBTXw^G}wHbxo˦T7= "HD I D$"HD I D$"HD I D$"HD I D$Jb Zt"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HDN@yQZJQVʏ/[""rU g=zzVyU:.md[:dXlny4vEIfZCEa[͊9s3yVwq9%yddȬ⏮YR]3քP3wtzܲmMyYQݭ2GUllL܂_7M=Qʉ}v2s|. &['Sf<M+o?O~ٚ 5sGg<Xa{Ц +M̂9kB*O?降nމ'go >|S՚HMoڰ!u=/n]+'.M~npBֿxυY \_`/-0YvX4.3ypƝ[i2nKꌜRf<؋ÛM[SLfQyN 4e5 ϙjjnuLȺt_Mf Ƿ͝pѣ&ĥg䎞bM>Q;oFR<@vˋ5Kgܒ9W a؄Drj\+#CgfVAFaXMYdY&Ǻ\:4We̚uFtkYyݵy>++V$NHOK.InRberV~^nS{NȭOP&A.~S`k]Dr&:Xjzz.ykjaܲ[f겲Ѱy 9%SGgO@Zv^QQ1޺ͭZQfg~^o DPE$KY^5cMqv%]+ˊJnԽSG54Do cm,JVPTe :5i-CEʕaᥗ_i=:o^~K.T:;vL*/_0 hO?eU=Hnݺ=:qW߯O>Gyd{p9mܸ_XEf;." s,"^P!;um翘]2庭[.],)_4hЉڹo>y ,_>?\#۷_#J|_=^#w"B/9wz?W-3|IDATH\G.* LOOmGa#Gw֟,J)e*QG'@]u7S+|@ktNJ+RI'K}OG3| A"oc?Oċϟv>ZD@G$o6yF$_|qM8C;wnnzƿsLvjN^\vnvOȖ[^~ >#/)¯yi*J?D۔% ? f핫V̞M͉b_|diywz>i2A?\r΂Y _3}Ko8bРKVFAG$xbSs~sǝSuUE?C oC;$^o߾f=iH^ZcD$7l0w޼T}Yg5:~;53 ^}ߛT/׿itZffy?h?կ߸qS9/~__=^tI2m޴N:LL9:3~fg?kjZUWOi9?SOr̴Fgߧ/WT|7|9c ;SE,KV^hΡ{fٲ.bMeepb'75yŊqG5+5P>e;ʩPuGaթ3{J g f͸oAq枦Jݥ*{x4x¼ŠY*)iW}tk^]0.{9977iՋ|x_% ԝQw_hUG.Fċkx]]ӏXakG.zмN8ˁ]o|?頓lRSSsڰӯ&t%дvErO>ecRtG#Oϟm 6'+;/FFΌ={ߌER},zXs5+{׸53G&sgg]|Uڔ'WQV8xT5.3EO64 ]42d伫 ?5{S\_q?N,}K%r}&l_JaXw߃~$&~1mWKL/5٘+׿{hǪ 'o0?wjE쳋r-%~{Eh{U`}zzNlx#5u%[rB=gK&EHkfNl7N>v)-{^Hy㮟?/>SgR+]6Fz V=_ިZNw~~M+viE٨k^}}WKA\3W8`[r \62T.^\ҥw/p ?9%mpí{rgD=ͻ?֚竓߉-+jp5-orY6c72$rh,@TEa*֮hӈd8E#']{ܫ\]:#QvʬkJO ~<#k0ߓSL;2ƭ}<ܴ~qY*..|56,.#d|dzuNG²LdKiQo|Mrk_$O9{bE-m̞9DyO!0d-rOo͸]ϾzBaScg>;ڬdpك'NYra}OOf͸f7~0y߰`3{[3J[P=jvBeV/ %26E3è֙~vdS#t`^'˧ EF.z,o9|ԟ=|gT\98:[@?U^F uGԳ/lY7lmۆ6NZ,k{[6=ҵ{Fhv ~|(^d1wC3 о͜472^4d#- mJVm_˶͟mOuڱl=rĈb_6N;'<̯~T}UWTt"ߌ7U?ګNNyO>l9gTt"q?+yy;sǝ³/hOm6ڙ_Mo'4:h)vz\_}կB:`)|Bj׬Xx]?ڳg@[k%{|My+7lT;pU^>ʒҥ; -ZtSH= "{^K#3iO-:(3Iy%kll-u{Q|T_Vzw))HV-}4}m+MOg/./3{K?Svov\SQ*?z"oԡ ,/---lM{x겲Mm7ɼa&`; X8鋫gU^U;}܂& No]vVVV3Hf/G |`ZzfY+j5sټQiq}&V..>'Y$7ۮdg:nBEWnP.5r/ [FQ]EuYiqIj.e=ۈdekb[_|W1gOT~nnQF.(ꌜç6۾G'7)-X "IËWlŶ SM&i _&d7xͶSΙ:a74䚲YUM?g͢Ƀꪪ&/-^VʋWX2nd;=| F$g=zzjY.6naqZ+_+gW5vzԅ.Lptnɤ ?:9sͤ9e%s3CVbnHq鄂2 JJiXɓUe}&V6}qaU,FfaQ޹6˙LiY9sGgƫ̓ohlEq?j.=~,?l=|tVf,smгK݉9.7kRHv.S9"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$AMF$۲)@c>խGMI D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I :hXrq]_$tLշ LT"!YͳG)WP8D$ׅӅ}L$;My}oro#. K.b Gܶ슬d u3]Mj`oRhzސcz-D#"Y/{wou$e]Ƶx%wN ]ֿ\wD>!ZH>ugGNt29whf%mDd,69ⶍ F_6̬T2уjƮy0u[C;g ޔܒ;T*uJ u:X>І:H lprպI2&%hn}L(ߵn/ܙa '}rbpͯ"KխpTc%w-;1eS Q17N\l%—MbFOeS(\|a}= .i% 슬Ϻ}z=n=o>"Y'ÀK{D33O99ԓMלWgԎ4ꯓ}"+|+br|C7}~{l$_h?yɃ;7N 7xԩcv=:9 2{_,Aߜ:(Q|/zȠ@\GH>ȣ-_"gǎK}f#;Ih:F勗~O8#?<33g-[*׮{m۞}WvF/"%=rxݣ{ =C$xE]R IڿNwlRZZQGyts:_nα|믿?L%c⃡ٿKzCnyw/w#80KHHj"?~{窪C';w6IH]$5?=K#wh_+|衇>/Oo9333D.mEJSuKZ{yzkǎ^zonD$_{R<4?`zݺu֭[33{V{tmEkT捭=ۼL/K߾8U1q?#9L?0=m[W^['Wu]OK[z߽+]$ھd;\yDһJ {A >.93Fyݸ6!>~YG `_)<%U睖7oI^wsRq'?Ut޵҃zwiW]㿂oH[+G[ZB;H0Pm,ڊwvXōع!U_[7*3VX5"xTԠkE;|[ H#suM}"#=4oqah7o/#˗W?/ C?$>xW?/#uWGNJ},wt\Wث2<" N<<20Gwȱ!y;ooӟ {!ga Y]#G_vѨQ;<y8K~ndTemءFGOiKnhhz{W)?TdCCCKKK zN%!;96ƕ9rn={Î[OF|C E{1"כnL}viZL^IDATLJw~h.\|}}ןm82|E?z]Oc~s@W~h=hРI`Fۇ~i---߼͛.{a90'7][|m4t;lE?Es{{4ojƅx®9s7z3Q.|`7}"#*Sgw}fgVX}O s9kwſͯl/ݷ=sO8C?4!<&S߮mjU<+{>"y5}ۻ?_x;lΝwӍӿ}Ӽo~O_W_®{Onwa?sג|Gv5߼~ݺO|cog]~/ȇ>ɰ?zC`4X\s9{ՓOsw兟~#R9E{񏍮}W믿vä,3=h<SD}}oSF:" +qh#?]ԟ"qO?-ǟ;^DSӟ_x!iq#G^?_zj?9xȐ!31m@FQYYY!S^`*{{'7SO/777ܜ):zKRr!v؇>xG>>DVKKK;zذ75  $" d I HHD@"@2$D$ $" d I HHD@"@2$D$ 2*@2$D$ $" d I HHD@"@2$D$ $" d I HHD@"@2$D$ $" d I HHD@"@2Ѐ@>8+R\d UO=Q^ e r[Yٱe glVmF۝l Qsmi7?a5Kچ?2BUX, (9ܫ?ږh=[^v&"٩XNū;[\=/'+]:qDX o^xVANlHjWWu :~piQ74Vcqe}uYX;l]qWK~\wqYŦUXYYquإS0}-M[}i#>mq}sYkKZ=ly9Cj+v>4y[O ZאӪxߓϨa_ vގ"͵7>nsmMezQ̪I =8̭ɀAaC:XY{o[^״-5n;BhZX:8&=XН%tՒ5MOp\nnu3:8L?>\ƗGWr /(_\uYWaxa]>*um[)嗥ߝ=o{Qec}C upXK[-8#پy-gGrfnmymԶ#ǎ c<\S225}suq5DOhjh5..8*:8{gKM(;Hw_0:V+Ƿl~xm'`}KG ӝԮSÎZa;婵GK O|j}̟qW~yɤieVn:yee! V)yO[okK&kWz|C:;ށ.][Zw}C[D(>w] 5 b ސXc;\U8`vaeYM]kfth!mhgnsGƒVL89:꺆E9Zsnen^R\ZutX}NaY3\5m񞨁Cɻ0x҆y/(K-}ڼ]*һ!92gdcfW$l6)FLicށ%U}߼z[b KD`m;pΙdʆNj_06w-â.]oOmCtδ3BAtA2WXY,e.,/?79|{Yu牺_}WMltrnʊ:_hάے$+_̩:J\zXY4$;g /x ĦմWlR^)V%o%eU|dCmhGu'úQt- >)Ct2jo&*!~f׵ZZ]i1ŅL\sW~hIQݮ$ !k»`rsuutߋ ]PX@uMC {CsmeMUz)3rd؋br![nmﲶҐ}v7ƊY jX>ji}nF@sDrd~~k! ҋNg֗LZ懧WwN Ɏbq5-8#{3~Ng>P]ƚu߃srxl9Qgu5% kK 9#îO^PljvoTZɏ5݆\W& Hd^HO6,9dZN/;5Ѱ_{mL*(똲On*W5%#O2\\VvE7o5Mﰧ-G|ep+ %%.þRR`lIi2@yumC #g%RlZmY#6b#hkCv!NvT1|uck K Fj0F|d0;v5WwBJʯ>6{ے)9m6Wys!</M+O3:Vu}[k*f͎%6k5XSV0rʒDaTu K j/|VA,172[Y029lj>GΪLi1J.V8۞3om\x(iz+W'M<˲✃$5IDAT޾gW섬7Wts1Ǜ򛫧LaSW>XzNۧ޵5S\S2^~]Z_^ÛCθ(PsUz>rԕՖdwu])4VuwRuq{th5ueK-zsFTW_:x%M]'5ϼǫ~YoX=/'^nK,]]Yԡfsmi7?̷T I%}}HCv?a3K>wa[ >ꌩW.g4'mm9;tܜV1 11jGqɂu5V 4m<|1^rm^R3swŧھL]|wC 7_z/&~K7aqKK\dr).(R}lNm_X#:{wݔ]<;ϧS>2Dw;vhr5oՇ;*V[©[* % f`8"@2McUq,+++9nɤH1T2PVKKK,HHD@"@2$D$ $" d I HHD@"@2$D$ $" d I HHD@"@2Pɿ9zذ4U$ $" d I HHD@"@2$D$ $" d I HHD@"@2$D$ $" d Iرm۶-Xv6n<##mv>pS&M*dt/ol@zəHm8a#+V'tWsCzذoyu5s~[o䟶f$d˖-wUOE]x w܇Ԥܼw/hA;RtA8H.n.>3TSO~xg, *~pGܲeK|o۶3yTz뭏8^ss0@rgq_| H.ΖW?# w)ُsٟh|E8~Ag~v48IWA]^z)pف כzhp)t]گ\{M7)M}޲eK|T]G*YSSS4Ɂf描MM jWMAn;u---^y%>;6C5/_>+⃉& |D^C7ɕ-+!/+/k> <ȁ{.~kwć> zXw5]C=~mڵ 蟎яuY_z4xxD$ԅPrmy˫.zk7~ǣ~~+?ohZ7%?/+*i|7퉤i.OZZZ.姟~:L"s=I&t7LNF&W3a~mKIe-+Wvز_ՓO6Wͺ'TS8den$~]Ӗ#DV|``C *T} ;qg뿵m۶0]@& ]6'ja7.-9&)}G]^]xj~oN3u+"bl _??۷ Ivک:d<>=c۰! YX%+7H8hmUۻS47$K67`ѶY1%/yy~WK[Gj'ClI VҲ 4>FR((hڕk;VI9c;wcݛxmv[ӯn}vw N?`xMM=Mߗ]P龍i3O?cD^=xfJmmlx-is/xӼO9=񟰗ҪdkuwGyMZ"/*h*zR'Mt޾jUthlʴ|dDkUGm_Y2ff䊶۫紞rD)׉oI3NL<5!c? {Dļ7$_p[#S͵ތ/&O9=vݲT?26i=câA!l\~}KuW2Edg*&ڈo*Z-y}{͜8`QAsCu"[n`z[w!Ox4ޜP5srtzx4}XҢUL+.-dOpXQZ*1D6͝m7<٘;qsSw#THנ=}v?^(m_B"xݲarޜV̮H|LhQ4bܸ*˳Km_A{DI[s*fVͩ95o,xuJ/׵ӺkܸBB~ڦXӻ1bh9CM}MNEcfbbMUwV$*FV+NmDO *Z1PiU]hvE)u379z~];ɋ%£Q՝x1v^HS=}?1aڧw͛|ڲe˹睿jSaW~k'x…vN{w.V bذ2#YlKSoI([;"T:"gB Mu}I%Cx`QK2:h _F9n{7w hzέEӞEc aηN#;J93H%>Wlѣk)5a/ޟNwy'xyM>X=m]շu}kk=pQ«Od#C^'rU$;y.o>`⩟'_h|EIn0`@]ٲ͉bxiad6#JYb%-fti**w֧U[վSGjN|Ecvo_whz!Qn` +$ӋݐDQ6sBRۮhDII(kW֖ư35ޥ]z[l'ߥN/RH{]v%n¸sO<&`AɦMI=;ֵi׬׻Tzm.`xMN;_zú{1z[ ^0*iI֯o<3'd>yaҙ d;s3~FyjAz'}ܱ|SȰ+ɽ/HΛ5"vmӻW(䦾5OՈ볮O|⬝rȐ!qH;آ3o>ro[Xh/~asF*65Z"y5}ۋܱc/_=?y뭷{)s"q'L]_^ڄ ~'~Eǫf]yj~~@50d>x_nbMti?)7wРA m۶UO=U[c.Nm?ߜ," z]/"r񟐬1Ȋ 3=s~̴w]Q#C]z<}8;/;8e`D2n_n);-++k o{7O|/:?8drD8`HHD@"@Go\{M7) I  ǀ}뭷^oF?UqS#<2}Y6bПdnhv$m޼矏y?O >hPGw N9U?E$999W^ҴK[ZZPe|/_OɃ:hwG>y뭷Yyym?ohZ7%?/+*i|+fw>ڃS߬]%ӦG3 (SSD2n _+OSu@1#JV~]Ӗc7>R00&STs[l7ጂW^}51;{- @`}(YnĂ3ϛ4NRnA0q]w.]/o  /Pį}Woܸ1ژUÇA=p.~mOH֘|dnwtfMɟY=14d y I&-]09oNcjA!vAѦ65I_ȀzNrG{,п *Z1PiU]5tF,bJ݌95o,Ɍ>֥$䎎O^TļDx4Y&;+,S6#V%wOf{-B5"" +[~]e ./(Ɩ֧G-X Hnm.VڳyH,`Ս-v+Nѹt~yCW/UlaEIfv=pl4Vcqe}uYX'4t.ٺZ:uV~NceaVgandvNN4mŋk˧Zawmm\]]^ZۘXKvh~O+ ;APLdsmiMܺi[Ӻo{9j"rCdN?sk2|Cmؐ'7w-kږ7O}}!4UVrIi͒&>8V>tgţ']dMS'+y?̣/!jdZ/6N=zR%GN%[ğ{z+;暒\~kօ֗WMGlۚN9+?="Y;+ԛHࡗ$Ioyg Kl[w˙Y[[^[>uXcG aHW1 iiIR7W\|_S|4ܶOhjhl5..8*:8{gKM(+lLk2:WocRG$UwlMQtg:u/ 9쌫-%lnJzkK&"kW@E$KoBeP3 ̪]Lԅ5#u!}W~QWI|6uyͬה-n>ﭕ%NaqQN윢ū[cvwVSXVL5WM0yO]P305ۍYLҧ+MޕodRmm;Miiiٺz޴#۞$>\:`NjY]Z|{'~w)~ekѹEeg_+K dmYsgwܗ3k}y v,dxboI cVv"Tߞ|A.BδD\ece}탿x؎fmkv՗mn3duʻf+ZruCCb9#?`Nj-oye]nye W %eLsDv[4z򣲺Ƚ9OuSم.I/Z@21} S?j^] n?Z{gS\:{i=z) 59ەXAQcSuMC=SwlޡxUcc!0;4*9@8@ {CsmeMUz՘3rd؋br![nmﲶj{=i.y)7?i[2/Zәeln՝CbMCc Έ^Lok5әTVu=lJL {Ȝ-R͵Q}!\]:v.Ykvk/ЕF&77vwkuQ_HT̟6mXrp_ɴꝮX_6vUkaSҩ96/TPֱdx|wSټngo)_ސ~E9٭,=di)vAۯ2Y}ݱmϫLsW7Aܰ`䐬 c8?G1 j+ *kInXsU~q,dc㿷-SXZ]Vdqks}uiaΙrO$piyFϪo=xksc}Me٬±ĦUw-a[k FNY*=ʲ O,)+/iYjC̫JJ So_dȨ氩72P_SSvW{64x^xdAu6WM}nՐ pjiimsuI[g i9Cvï|,kOkueqk暒g2 Z]vzvƝ/LKPsUF]PmYAv]BceQ&wT]^h5ueK-zsFTW_:x%MOﲒS8'S&qՏ79u/:zSh(\[ZxOj y]nA$nT^dg7lyf>}G1w=̖d%ƭ͝[+gǢ.C:monN]~K5|pθdҺRCrJj_z趎>|s/u/miGzW|<|o. ^yƨa鋉_e}.+j-m\JavGa[C7 {@v-;Qg\y>vTEj"9uyKea,@2ЀicYYY.qK&eEbU80" dYT2$D$ $" d I HHD@"@2$D$ $" d I HHD@"@2$D$ cD/ol@6,_RE@"@2$D$ $" d I HHD@"@2$D$ $" d I HHD@"@2$D$ $" d I HHD@BfxC>K s~&S"!\to_?{yko`Ȑs Ӆu?'%Yi2Bpoqb%?DV>dmEsf&oOn=2>s$4C#>?6{@D$}2.p맟כywvާ|1!UkoO~?{.kG?>ދ)=~; N|Wx?b=yӟz'?||p5'?m[nlM̈HnX9]x'tQTx1ִ$ek~G筭k=;g[oW]{7z=Iv>'zlxk*C WDyc=!3"ݴ>'z}yumy7?Gٰ{JHF?m{Ͼ#Qk^ޡmd iɃ[cg\ua~>?-\nj{.l V>w[_C9fԓ?I:ϭɖW<6IDATyLJnLg!$҅}ްn>!DֆLJ)m;'rM7x&{l~(9>]|C.ibý?m6);'ƔDY---Cॗ;~xvKW]ީIO^w_=6CnOy>N g/}W^x 8È}h̘'~''?hРП =lX`#ٲ;c }ڞ;PqIoF =j/o'ՏLNE_QInM DvWOf&۰1=9-|޸ vŪUO]r7{֕_?͹.O_=_F$[ZZ?s6{̈Az뭇Y׿9ܣsϽ?w;_;ܾ}v߻.(G|~h^~x _lyW^}u6l|>xY;v̉`'?2_l,~pǝ_uU4~g~w9mO?t||q#<ꠃ $~k@W~Ȋhp28' 쒅?_Q>2n4hP|~}|0П"KСC'~Z ׿u4_ MΨQ{]t4Cܵה~N_{~ݺg}⩃7ͻy̟_o(|2I_E;,gԨ9eݳ.~k߿oFs>И1'N8 ?=egN)⃺ի )"yj~>6lpv /WhjjwxƍyϽay1_jᢊ}?{?eSASӟ {>"VA}o |G> Ï"7wIYS?W¾~w^ӜtXر xw^~z#` ٞHkƽDYٲ2+ p {{G[.-/+/~IzwoGaK_73.8Q~>,47lgW?7yea_>}۶mєSxbצFvKϞm S]+" П"ww N9û";\!/#G ?G|4pov]OF%w755=)"磟@C5h|׿a +~ >urN ր}׷3= ?n;G$ֶW4^ZrhZKMgQt=׿u4/wqɉg/:hwG>y뭷pਜ਼?j{b4$W[T4☼mG(YaFt3k3`sg,-ݠEsgv}[Μq~nՊɛInV۞vVlnISzbzx%Zu/mieJ0F+L2W5а:Sw2]tyFn~;m7NMu.ǧtm+8_hcjK}H)زe 7o{Դ:;{-'~ 9F͛sﭬ<-NJxZ{7>xc&N𵿻^~I;'uU=8ofU(xdʖ+/Jeflo)E6VU3hQ+5T71679/BE0vnӷOs(jć>tک -[HA"*| 3~[[ڕkzZVh?☙5`QbmanMZv,VҲrQAޮ0cY Bz_s&ϰ}wsoKpP7ɟ"3Y 'U1lKz~%z|[VE+W+&gͬ^vO6gv!a{Y[1a޵|dh]W\M_1q7n{0>߁Aɠa[ܥ]n^,>ʕm Ӟ [ wRiqħXsDn*ϋW4Ys3bOA^K~?Rv|dVVVۇYMMM`cv9}l8{q'~}t~aًg?6;Nl[ϟz9쟿u}*YnĂ3?3>ěo`*݇'LxdŊnw]5IADT[0wfPVǮbJ݌-K %byaxӼOx4Ι\qݲnSxB}C]}Ss( ;-QN %u3w/ '̹!(IV%U̬S[uE90#JV=J*r tJ-ǔ7)}>kvݶ^Qv鮕׮yU]Uàq +w!H0:-+YW>wvu;9Zi3Z_iL+ə;N,oN蓊sӂ񿅒Yzg^iWOAKKE-ޙ#GA#Gv>ƕ-G+yqNmىiC=nt4hllܿ|y'>8c6la;hU$C4YD-U7{nc1cE#\H.][*VKl/fb^^V^^7݄S%X~LE=k %]c6'1_\bb^Z9yQq?AaӪԑ 7I2#& UUL Uoƥ?ֺ}%}vt]O7n`x~U L~Uupg\ oL'SR0()Qv1_QuAi3ݫ]1Ͻ(^p4!vYڳj{v]Yǿo qaΠ}U jxϠ܁Fns%!yt]]t1xЁɊx554fnH5.bܢacNגb;;쉜eMW$nwadidN1qnZ-W1c)QskïD_Ktg^󹝹NO&GyY;Qj;꾳b{k9zoO͟[ھGvcˍu 'PIDAT<;o^lכnL59voeIzy\!Klsu_[ƅ'A?]p5߼49vKo+:?ܶ[bbrV|'Z'JhQ׾u{bNecyV^ylAr?0!P,z J=è'v=O?>K4>~ndh0|?n]؇z_"9câDۉ:vu%ZKWTm %>&{.wdD"?1]qL^=Nw}6.w/vtߊk귇9a%cf,-B,I=cTpGg&on_⏽/WhPk]ar)ʗ؛e]KxvvUkwӖV̾jojl2*f(87O0yg[v6cm 񗡼qPm_ă#<2?1L%1IlL>%cO&u˝!K:Jⅉs;t.=^^Q1yb\bԫzz%߇gV caaai-o<3ޗʌ09ob[QƶS:|{66,j鵸1yf*&ǟ!xK<!y-I-[9ԅ]h/Dwoц=^{t#Jig,kYTTv{(iIdV23HFkBѢ۞zxbi>m#殬9J_q^ $/pw%_[_i7>#洽 KV& шZ{'3 /n'/] ^ }H;{_VKKK;';ϴw{W o-\xCwGSO?5?Tˮ,ڎN~Iz`7M8nu|p鵗^+>qgF7~z'>qV؇6,_:mf}Λ>[NgJ|䨏~6'" .N?=>hiiOk _bu4[``?t9=]캰fYf;,6?7[1;bv,ZT3lwGqzO_g/4xP؛}/Ϭ>^5S)"y=NK|Pً% 8]lA.w~mږN?}>>~{ۋ-y'Lpߜ418aYbGȲGROϿ៿`_k)޽k{衇tX^V^ _СCC_-Oɰ?:-,^޴)ņO=.{c`#5kHvQD^#W_zH=+.x^r}GQz7JrYx1?O?xQ/56\pT,۷ooljƱn1b?.~k߿oFg~3|p}.ycsϼR2d旧<8nT]KMN wUUwWi [+G- jTq涆j%V&:bV3[+(TbKتi{7 ( A$VJ sIL"`|<Z{}^73lx`@LɄ9?Lou}iʩ>R"֐0MI+W>t} H~3ןK׿y!Zּ诡arۗu!*l;~e-ozw7wgw/"R)O~7o>Ov 7~t_w9+E_zCŋ$ϠH&LFygcC{c9:2X#;ڴiS̲28 6lX+#w9Ά>Æ" AD I D$"HD I D$"HD I D$"HD I D$"(#h$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" DА^ZPUZHˎW67VgdĦnj[U_Jqm-܊mO\[QnϊV54NO|x~en%V\s#U&\xMk7 _bSF[UW_Y)Js=+֮oڼ/0zʽkCx9|@D"o܅MT.o\xͩ#vX_ޚvL<\QfY={lx遅Ӷ[8ۛY͍{Y|cw֎ >((==F$[J\,^\5=/-,mwj75V?*tV!՗On9|Mj|]OɆ'cgה0]\zF\0`ۉƪTqRIYyi:GR]2gݕ HfN*a:tV2yliQN!"X[N*+j>5o*f"ZR*>5uRQQͲӆ0|jQ^ZnğsSkkOeN/SD)Bmksȼ8+K2Ǜ直iavax|]Mqw)m' >KS21ʦDېSVU<*2.(Hk6`F$[kIJK JKG+Z7ma|g @Nn]o7l(O'$C-vwKKz/YZCD2(xUM7֪ڶe]EEKQKUUCXAQjǵ]4_zj]XvMC%%]$[/|"V%7UWܵ95}g넍NMM 3}֩[7ve}IkCx9{"!vg[\Qr{Ӻڲd@2ᗔ&jNMfU\zIm*{۷Q= IDAT{ O+f/jhm̦ֆ9ݵ>ypRiqNxx+ .}|m׳#.x*6+vPCuQ,}Z]sÛ;[Se}Y[v|-͟r{SڱW֕f%?sz[ʩʝ0 rC>hAVnImƕ g_pG6{ʍUEa.hyל:~cOb6֧$34D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@HmD tea lv"HD I D$"HD I D$"HD I D$"HD I D$"HDA\Ӈ-^/y^{- 6Æ ȑcƌ?)S Cˈ]Na}؞]⯕jUx _} 0wn.OߜY^ڲeߺ?njQռ ŋ/N'N'i7D$v~Drololܸ/lsaλycsHNnNl6۰U-M-u5uY1~ߏ=hj\~S*z̲=$0Ž|d,?à5,{X[$^S/rmWݶyEC8!aP֦ˋ.;9{}?!Qdfet|yk>LɆtqqG~?>;iR +u)I =sĘ̽3s˗SDrڵ#sBvN{Ĩ0X5dȐ'Ok׾>v}쉓'/Z8c$'TaISkث~x䖓gִ`H5ξ#u[iΑf~?>»[ @ˆoqv==3O/vgÇTxTѾd:=TC圻 vU].}W/˩;Y͙e@ FtPxg# JF{}2&][OO.Y{+Κl܁vL'L{ F.Y8ѓnk5gɝ# Q?Tiw1.~xY~UmaU(IS&mm=펥#*t[SMO w,{g\BMWצI'SDr_}'{k?0v`裑 v1~|ҥGI6.=ws oZg=7ݓ.9#" }6mS&uovڵxijh9mf:yrIES@ d‰'/KwT/Hشq|_?swehlo7O?sꕫ?/| y'?aLJuM /,r?2QwϽ#F_v~Dڙe{ᗿUɟ?xo9 ׉'s,DCF<r ۟!ESϘu÷>sag H&;3SOἿ?#À'" 7#|$D$"HD I D$"HD I D$"HD I D$"HD I D$ʈ Z" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@ ֺXVFX,~ݎKk׆Hkuazs+GlƊOr;֯]/-(ƺ҂܎iv,2?##6vSvF$ \x>66z+Nˆ⢼0ŊkNWvƪ.+_9eK aUulږزYEd75o*궄_ua  _F]0oy:dʅל:";]muiQkuak^Yձ$0/tnQY]kWXW]QZ/Jm=[kc~XGkR_$g?{est4de6;5|X|0 幝.bmj(|eU5ey]^uunAiUCN>=G$;lJ 4]9z`nyCКfN9Wo;\-'WѸq's폯X}i؜U3v]*ʞH]SlvqvL/LcEޣ\9EW ϼeEo}\W_Z}M[W7=q;nLDKwXqmi=_={lVl@__3>1²mBIDAT9ɦ#N`O xV} bEխ׌J:Z6__TuQ,ښdpRYqNW*]y5&:?}5^L};?Ex}iq$W'uzy}RfB'l|]d*KX>6LNbRamtb5ʒE*/<ЖkjhۓM o{¬ŠT0<^֩xìS~ KV̜wFFv,W81VR;"<Ϊm[ZնvMu rcb&n^NRڶ+⺮MvɟU=mxkW<~-y+ݺfs}t̥g`BT6Hnj,|>Ѵv͝vnOn ıl!Z֭5!]` [W/}Ico7ySrp*`H.w߈Sgz)|mDGKfTm!yIyIluEEǫju}֪XdV5K_~pǎHM:fN~~: >v]. dsUyj 6זdmӘ6 Nݶϼб _VX^xIIW!֪ '.Y?L,殆k222 ں'V7Kg0[۷̟>=%k?_ID=ַ5۴8wW>>2ݶӆ_RU嵳'?ƶLue>>+dM koO\X0= YtR!U6vZ^[YV\_`ˈN9myycY^ƒy<_-%N3#=P]k(ϝ0iƊqCfN}&}Kcݾ#x"֪!pҼǺ>{SceQw#.x(;}zL^jLǯCh}eS 47kڒ)wpW< ; E27ϻ⤱G5wzGiӺ/).[Rۺq4vDƓ0m•[}׏UXռr޴mgd{r},7DmXM>2!yʇ9u[GH0zFHvwm-Ξ2?fO[H8$ .¦ꢽy8Ym tC}Q_ЖLx2b54"Hm " D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@u|g@_3lxH$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$A"@H4$D/_ `JD2{{N ӨK-gH.l.lۗ1ɑN~&5ߟ?'G.EŅm+S }JΔN%}͎+/>V&qlw^^>3*;AD"// cIW|uo'^/|v:>y=/ ᰯ/{忿_Y|ɕo=~}ˎ~)u.(L^!q̚pd5Gdho?뭛|- gBz'gՖ}rM1O\Ӵ}/_BQzQ{aNIʶ-[~g˟_޶యe׎棒mdAn)|}TŬ//8}ɳ򻶥{5G7??G шHvѢzeK~kwթu$e//9m &//9QFt-/$4-$ӯSI@yt/`X#" b[WsVhˣK>m2iĶ-?8(ԊlsY]Cv%t:܉K.[RgBw6DCC$Ӆu:^92Av[τ-k_ã촦p-G3#gTVG_+5!}ir`O.M2 g-/$|y~RXⲗ;$×`Ȉ]Na},~ =ҏ3yKk nn>ydyG}l?šW_?hQ #nj1S >Æ``BDaUѬ3ap\~oU^bo1GO n˖-$~ǿ?c?7~QÉBD2aȑ~۰a;7hqStڲeϥ_ouԑGO: [/wG&F^YĂwϙES0(mg?>1~[??Ilֆ %˖mڴĿ뿛vN:tۏbXk1E‰?`|ɇ+V>Se"{;>RK.,]_VRrKMC o_z/O}OJԇ|ْAq۝H1G/l|eժD;Trevw}7J K>2?ANK@ _tO~ct߾4瞪J`?"++G S=t}ל9SvUСC<˃a+VB`ȣӾ4ӟ˿b^{-0xt1.wo7as̲o,<DҲ$7\0~k]裆tq1DIDAT?}h?šW_ݹaÆ}j1c{̔)rs?{7&/?@ _t1"Ѝ}wĈE<˛o5rdxNhYcY`pI>rCO{?.bnŽ|d,?.0,{Xԋ.\pUmޘl}_;C'N|gtP[ ^2"#"9n<6]_^|W⬒O^yθxe]ߑG},]|/2r?./ox׺\sY_| "_pE/B苡aOk~cs6v:dj&]Vx{ؤWC h<}mƥ\q3RS+OtN:yǻq}ۑn^}և+(e3wZ2g.Ǘ myG|wz%r9-S?b`HsG=dɥ})}xew!]yܑ3n Wܑ }ԨV/8750g JGp1G;s͉O;.3oذuI'_q79,333`E?~PcҥNSECSQdfFHxo'x 3II^->g#OkJEwv#>:)Cn8x`HCCwScs'\zO Es s;S;NL(X333^-~9KlY|⎙WgN&}jIɏWN@}t>2yʵNx>3,S9wU|w PMw{Ot؅Hv?fO;9P2v#ۭ{wk2$w}ϽzǾ|E\HВN{R䦛$pd7B8pb*8xF ĺ>-qNם;7yqݖNz^wc/KJ,ض3|_af͚ǟC/q&'T<0ƥv1*HMn=㈱M/M߸4 Ҳ}v]m0"W#{ƚK{_ƒX*߶b:ẢXxoaCw|,}c䶺~, [.nkEp-8',^?iRFuz9 ?'x&m$u7}{n{+ ՚7nݼtO>^C vٲr'vImFc[2VrccAdT~NW| wҤѷQGn#]/ص̈ЂE@F9s:{ f߫~n0&z}b7>28I]dg/_pn6g۸HnؕvaZ`G.g{oUWpޙHoA.]_>0Qʶ֚o]z^~uŋ4'7g_9{( /Y͙e NvG>}>vtH?wQu^S37i5Kgr`I|-pgM>ٚ'e=vz[߿8Lwv' 5B/KM\{遶5jlϼ?%W liiVvUbE_0.ûݷ B]$'o)vMkjåWɡ w΄mK߹mma3_{/Zc%7RwÌ5sRnk^noT>tw\rotA冗C,]a M˛E,6"{VD2һ5N4)cR~V˩ߤI'%w>9===>6?:;sud p>eRu{|^ɩPͧ͜w$˶athiO,tlzm':=ORk {NxxrR:;uK?V(ӱ~4=$^2_F\ז SI0!/]|S&O~յzĝGn6}ڮw7˒ٸ3nL_ftXa=u,ӏOme7zƗ|;Ko wMc>zHF۰g)MXwkxؽճ?+.F5D$aϲ^{;tܓ}{a7jjh9mf:yrIES`j=ЍM|XIA|W;qoe?HwT?gGI ҦoOfg᜻.3"zH:Z'g=Ȍ5K {~=Æ``L;lذaذaqP|Kg,YMݪU~a91s1G?//m.O=]~eee.0p ʚW/oe˖@7YD '-/:y뭷5x{͚5ˉwl~ğZ<+O5?[~K+Wfee&Kv 04 6'~߮\uIDATyv /8f̧ԧυ=R˚W]%}~ gˈ]Na}?t6:z99g(8K> a"6|z}l<γ' vW?6lX_~;|GqD`m 0i  E;"@H$" D$A"@H$" D$A"@H$" D$A"@H$" D$Ax<D]$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD I D$"HD!O2z%nωַ-j(G$+222RĜ’%9C[qeQoBU-⤒SSeKuHn I0T[R|o* yҼ*Ih5"\["񶢲9[JsÇ0Sr-WWQNHN-)eM:h [lzdB46|z?%#aMagUTOK$ǐꊻ6'KJB*.$3yMaw)iIN" HmمURY'.^eU CS煇kvFrkH2M@G$-'=6 EU)&$ZSLUZ>XPZ:*U<\]wdH{$ }E2$kœseW?^RݼƊtB22.ø[ZңϔW4P89Vegddvk+r$`s҆xhaͫka0lذO9f̘c2p\nnǻxg0=d_+yeժkpuagΏH~t͙e}-[\n~Os1?7~Q\xʼnɓp>$ΏHvxu}퍍7Ӗ-{.}8,{yW76o!c { 6zqUKSK]MݢGu{,;7ߔJ^;ljϳ!"VYAܦ0zha)Kl4j1i]Թ,ֶ&t\YΖtf/33@-& jHC9 #[V͡g眇ZAZ^ki}bSB^I7}ȲO=/9ߺmm?؟~m?/Zor+;ӓ̵ hq>szf޿-?-H8p׿7,Za^ɼ{|O2}(xHny_ SϜjêɓl ̓gK&z/*çٔ ˪70A-G˃Փʫ 3z-?Yq׊dx7|J$.:ý^oRїK֫‰5;ٍEHug~0N=-RU-; Sy{–OH2,lQN]ZKR_EB6anN7KBQ<5y%<2V6%4_ ]ZQ‹/Tp4vexMuUPvj*o]ZrKN6l8J`gP^ִ%{y㎺c*j8r;E{g+7pJ,Zm;3GU3G)9㐪&li}w/nMors7ŏ>6govf]^>?+;-qXhNۃ=ux`K؞!dX~-7p-+ʻ?.|ZEr̙ɰk`W< Psmco"FKHp|J$/,&HƮj= Ӓ9m†VKOWo amNu`^S}`g[U`ݎ'ڒIDATAGeٯe^]j\k)Ýsri=wBٿ+}#\hQv7>W]v̰iݦ8wƸ^_)jK~j]wn쬱q57|+֎#HRř?c ZKo^rɬYV*W^`޿kiI!ݺ'緭m2pGOgd޾u|71wv T;W֬L+.˫|J$3VTӟ$sWG _ᵾBJucGxא;~Q_^i# )!߬^/oޟmO%ˮ[VtIiPǛjOm]f͚H{wѳ{tS[3G(`gu}D-Hk2xihR:>}Now; ˫~u//7/ƾx9NoZ / =$X~' $ؔ$!$!$!$!$!$!$!$!$!$!$!$!$!$!$!$It:*@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@EtIDAT_=ˆIENDB`././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/antlr_grammar_tests.py0000644000000000000000000000562415134002420016717 0ustar00""" Created on 4 sept. 2010 @author: luca Submitted by Luca DallOlio, September, 2010 """ import unittest from . import antlr_grammar class Test(unittest.TestCase): def testOptionsSpec(self): text = """options { language = Python; }""" antlr_grammar.optionsSpec.parse_string(text) # @UndefinedVariable def testTokensSpec(self): text = """tokens { PLUS = '+' ; MINUS = '-' ; MULT = '*' ; DIV = '/' ; }""" antlr_grammar.tokensSpec.parse_string(text) # @UndefinedVariable def testBlock(self): text = """( PLUS | MINUS )""" antlr_grammar.block.parse_string(text) # @UndefinedVariable def testRule(self): text = """expr : term ( ( PLUS | MINUS ) term )* ;""" antlr_grammar.rule.parse_string(text) # @UndefinedVariable def testLexerRule(self): text = """fragment DIGIT : '0'..'9' ;""" antlr_grammar.rule.parse_string(text) # @UndefinedVariable def testLexerRule2(self): text = """WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ;""" # antlr_grammar.rule.parse_string(text) #@UndefinedVariable def testGrammar(self): text = """grammar SimpleCalc; options { language = Python; } tokens { PLUS = '+' ; MINUS = '-' ; MULT = '*' ; DIV = '/' ; } /*------------------------------------------------------------------ * PARSER RULES *------------------------------------------------------------------*/ expr : term ( ( PLUS | MINUS ) term )* ; term : factor ( ( MULT | DIV ) factor )* ; factor : NUMBER ; /*------------------------------------------------------------------ * LEXER RULES *------------------------------------------------------------------*/ NUMBER : (DIGIT)+ ; /* WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ; */ fragment DIGIT : '0'..'9' ;""" antlrGrammarTree = antlr_grammar.grammarDef.parse_string( text ) # @UndefinedVariable pyparsingRules = antlr_grammar.antlrConverter(antlrGrammarTree) pyparsingRule = pyparsingRules["expr"] pyparsingTree = pyparsingRule.parse_string("2 - 5 * 42 + 7 / 25") pyparsingTreeList = pyparsingTree.as_list() print(pyparsingTreeList) self.assertEqual( pyparsingTreeList, [ [ [["2"], []], [ ["-", [["5"], [["*", ["4", "2"]]]]], ["+", [["7"], [["/", ["2", "5"]]]]], ], ] ], ) if __name__ == "__main__": # import sys;sys.argv = ['', 'Test.testOptionsSpec'] unittest.main() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/apicheck.py0000644000000000000000000000477615134002420014425 0ustar00# apicheck.py # A simple source code scanner for finding patterns of the form # [ procname1 $arg1 $arg2 ] # and verifying the number of arguments # # Copyright (c) 2004-2016, Paul McGuire # from pyparsing import * # define punctuation and simple tokens for locating API calls LBRACK, RBRACK, LBRACE, RBRACE = map(Suppress, "[]{}") ident = Word(alphas, alphanums + "_") | QuotedString("{", end_quote_char="}") arg = "$" + ident # define an API call with a specific number of arguments - using '-' # will ensure that after matching procname, an incorrect number of args will # raise a ParseSyntaxException, which will interrupt the scan_string def apiProc(name, numargs): return LBRACK + Keyword(name)("procname") - arg * numargs + RBRACK # create an apiReference, listing all API functions to be scanned for, and # their respective number of arguments. Beginning the overall expression # with FollowedBy allows us to quickly rule out non-api calls while scanning, # since all of the api calls begin with a "[" apiRef = FollowedBy("[") + MatchFirst( [ apiProc("procname1", 2), apiProc("procname2", 1), apiProc("procname3", 2), ] ) autoname_elements() if __name__ == '__main__': import contextlib with contextlib.suppress(Exception): apiRef.create_diagram("apicheck_diagram.html", vertical=9, show_groups=True) test = """[ procname1 $par1 $par2 ] other code here [ procname1 $par1 $par2 $par3 ] more code here [ procname1 $par1 ] [ procname3 ${arg with spaces} $par2 ]""" # now explicitly iterate through the scanner using next(), so that # we can trap ParseSyntaxException's that would be raised due to # an incorrect number of arguments. If an exception does occur, # then see how we reset the input text and scanner to advance to the # next line of source code api_scanner = apiRef.scan_string(test) while 1: try: t, s, e = next(api_scanner) print(f"found {t.procname} on line {lineno(s, test)}") except ParseSyntaxException as pe: print(f"invalid arg count on line {pe.lineno}") print(f"{pe.lineno} : {pe.line}") # reset api scanner to start after this exception location test = "\n" * (pe.lineno - 1) + test[pe.loc + 1:] api_scanner = apiRef.scan_string(test) except StopIteration: break ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/apicheck_diagram.html0000644000000000000000000003107715134002420016417 0ustar00

apiRef

'[' [LOOKAHEAD] LBRACKLBRACK 'procname1' '$' identident '$' identident RBRACKRBRACK LBRACKLBRACK 'procname2' '$' identident RBRACKRBRACK LBRACKLBRACK 'procname3' '$' identident '$' identident RBRACKRBRACK

LBRACK

'[' [suppress]

ident

W:(A-Za-z, 0-9A-Z_a-z) quoted string, starting with { ending with }

RBRACK

']' [suppress]
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/apicheck_diagram.png0000644000000000000000000010531515134002420016234 0ustar00PNG  IHDR+IDATx x7 VAk%R5VZeQ*+[]WڂV[] iť](ZƊes n$nSP|s$! sv,w7gTZZ@@ %7$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ ĒX!hr3S2s$?7{jrRS̙R&eh!wJf ޘ5oCfaM<v[f.]IEW/}-hbpj︨Ϟ&.;pC]4+O옎A1{p!%LpN43˺/Y2mD[*Xj8E;'k_,Bmw M?3uc2L[RtJd(K4aݡuٹyE뫎 'uGw8Ǥ%ʏQkL;pckRQٮ]@˵;oľ=]tW"0ǞY4.MX-{3G Za,ge%_QJf Nݳؚt%ufRw"רΛ%[?&mL]Qԫ-SFL+I:xFIʉlڰ~qe.kޥr%m2p6efMi=ՉbX֚YyMdJ-ܩ`xúwH6.)MϫR wO[d(t԰P)_S?%;s'^;,#?,Y\4mpf4'2O[2ghċ3T,gL\Y±0 Ђl f'/,,7Mi̜ܲP|\nc*9Ր]f&xԂ'Z2c}B ,0pʔ7ӖiɔYcXc쁩U6,p/YR3☛ ml$XU>[)UyUpKiģ?m:wHOO~}#۾:'j4dʩuLvy#4 =-^2}1zdIV=vYZ{xjhNVn4vf.x<(Ogc_,EaNz@,p^L{O\Y8mpfēSm}#m^z윜ÆeMCFk=;1ԁâF7 @KTK0?0~Ma=ݱ:ڙ2OYRl}I~ng&5iܦ̷: wa æLjv/%+'pM'()̟3{ayM8[GJiiiM(;%غ(75qc;,Is%Y%3y'վWp|f+*Miw_3,2ch0dvvg63..= 3qhm˺q]ص 7CЉsV+n7̱3Ƥmک]Ut1 13;v;17Yj]nCயC@3)pK;MdvvjJJJ&gJf.  @,5C&`QXpKnbI @, %7$ ĒXpKnbI @, %7$ ĒXpKnbI @,pZ*5%7$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ ĒXpKnbI @, svۣn{HUz%_&o{z?;Tlo*g}&|*@ќS1gi=oV bsnJ]o:Mg-Nt != /IKdXxGSzYkyɎ{'^ei6\s06Jjp:xN/- $t;t%]R"\nwmǘ^=JA#⃪J}iht88蔴yoƝR?e+U~}EO@j0XHۤK*W>W;ncu ^c<(|xG\q܉|SZ6댲F,/+3x+듿$Ӫ4c]+xM? #஦s{~h;8JoL_̚_^~ VjӣdT/-:kG$f9|la׻?`uC6G-lo$5iyKn괎j5JqvMgWzdG^l^5c~u(o1OC̺ڃg-_L+ӕ'u=%؎]C{HWܽ1!?2=8RT4QR@\t?zW'.K_|xײՕ괓)jfAYeƗUOW٫ǯzg,9?rnc{3v ZDu6So}9,uEA-OwԻuQ$贋g]wxHϘDgܝ|n?>`lY ;=g}!*,,3"9Բ^fC3ptesիW8^tv3|V}o(7>pmsvp# ެl=>1o޲e_UV-Gʫ~ݺuw䑧|R6m`{:鬛SRK}d' /(h=n^ _4.<aGļy/~S|aR(;G^*xqA+}O7ݻ5G駟^_)5]W^}o{KyU;slgbp Z虰jv4u֝pI7 h1|?I'8οv#mpG>c=v?A{x烇vP /8*_j /|i;\v!njo^[~/1~}OQw߆ ٵ[o{hGN?Qyʟ|?%/ur-]ۍO_N;]IDATyO 2'(n׮_Nn@] pYgo&`Mfs-[7p$\WکӁAv /8gN^SO[[o NNonݺ;!9=h `+?blh׀ek_sm}TC}o~Kg/>|eEZU{Pule 8du _Y#_y5?_f]8! 'D5qBTmV"Nw믯^oӮ/׮m{/q]~k7ٙq(^U:իˆ}Dzzz/ʫ 9V|ᇅ+V>и__˫j۶mtŒiOSn/vSO?}˭׿;G@Yv;'4ghM^{¡ۧ޽+M Q9!4o$5} !yO>K/it{3ߚx3yݠMM 6^G^={٧~:f>notY}.]4gyWVi ?dž6lvGUXkR[К4^n4ǡۭݻG:,*߄5"*nyQ n]4} Vtڭ[>*4犗^:~H~O]:pM◊_}n\a(ΟOԾGqӂƹ{=g?ѧ}iǤeå4¢7^y%/(<{ÓOwinc2q,mIqBcv{|j{֤r[Y⸕55p Ԯ]p/8zh ʜ5-rBXv[4ƠeW^1ݺS%9}~sڴm40.z{Ȉ!FM5eVC=;C={n֋.+ SS;Mii^q0׽_w{߽j6Uwڹk>YI/8`?}v#.vmܟ~~s=G|IgtYW-h ~;P>-_枡5i<IXr/ٿm$upthy?ɲxEx,G463&MV=M{ͨlM Q9!"bAڎ^~3Gv{Ʊg\Y4OGDj3fΌʧrJ@lذWmTrxG4/2*4ȟoZጻc\zFzvpT5|uf:=* m IaOS*@o3f4vpz럣V3/`?S&n`k ?~4l͚53>cj_s~뭷dkg^MAGͷ4-9*zΩ}Nl] ;scV}䑀:h5rF ~¼' hmghMd/{PBG}TfFFl疖4&h;gAsێ~=;*d̎6ݳgJ/{~POaA8|?l-l 'OR=CQSLlL?ATXxɪUz*))x/a0EӇ2/h]:;YGswyVJϬ&wDm/_tݦ!wAM07Y1j=C&L/ {&9I'oCz>&99Z"'& vڴi3eļy? 64J_R4tG焨~mƲZm/oOʇF;!5letѢ}7<3⾦bEE|A̞^^ode<.ӳzVާTUl=9+urPKNH17ӹǒ%K–W+WG<$ͭ}9.mCVQaw wc]wPsU ST Wm>Y4bQlIJT]]T? 6W]oܽWݍo2{ym'+9owO<>=oOϬ& #g VROCtS(c-)iC=̡e tY}=lSQNժOȹC'%vԥ&up@'Dۂ,mk;"5v|mނENtDA&]~zM'@%1TB-N& 2[ nϼ&W͡bڧ{NJ 2IZDGrC}vvdzuWQ1T=ο``@!)Z>?͵EgAsXvuQe?")ɣl00MN{آB{cDpuIٯɿfVy~~~3'hկ~֛DC}gOأgg; M?#^?RVeoЀxpE0'g'_ g}$/C'M F&{ Ytd_j\eu&?+T陧NXq 9uTq1zt fn:HT**{-G׮/,' $܄SkUi"Q1+U߭)o$K&!W"m/۞yKv,|:߿c~~rb<%WUk bwy2塿/zl6OeU]58)_K}ݚϺ-H~~@ۿ#G$r:'V|!W;u:z1h._>fϺ?_>[¿`kїEu3lv`V6qҐ)#NJ_߲s)}Y_?*eONv0qQOj e_354^9+ ;Z!7SIDATq6HLq MaOD71YUhax('Jom涓S(|:hfxOA5/Te=~oy*c:W_u#r6m*Ю]s wԏ>CsAS5sBjOON1^ 'Du䄨Fq 41un}{ձHOrOm۵ Zw?65=TAp=9,1o$U:x#??qz^_JUXtĴ ;2WbdtPY3Gu3`nNxkMʥ2FZ~o`.jW'ƳbsʺN-)9QshbDc;Θ{}#O"dd=Z۴WMd&Aq&֩5:|&UsV<*[QGt O˪e%Fi~ɷ>?)1M*m ]]=k}Se8BMHd$k$_8Uٕ*$G̟NDO; u Wx𡇮}򪫫6Brq>'xb5ܢ%~& /-\_'8CYLJ!iaOtKl-S$UI2ZVǶM)S+{UJhɔv$6jˏ ×O=-a{S]w޻qk^ㄨLkejF-wʀ?Л义~ef&+~[TUSI}+6ob'G'7zsjne.Y5g0M& Si3A Vv}~U1+z̷y;%_Ts7ސ{d߭sh3鄨 7m ȲsBT| 4>XSc}վ| W8WPTXlS+UqPO~:o۬I$ny߭U9S$ZDxFd7ߜyu&Ď;%?n2=OF2J]ַλtp|5qso=OP)WUzKJ[Wq]6QaRs^A[os蟄^x-hDp_HDYzŅQcǎ"meٿ#cUɕWc5eez;-/|^AՊ ֥ßiU&|q٭%*$?RIuwӗM=Qߡ>u'vUjJY_xWs'atrTo1Yݻw &A~m Ҹj|̚4vϐTqsӆ -[>ip_L̽'?Kwus -qB'D;~t ]w`P_N `5'D {=g?I'xI't׻dvС}P_fm\jpϸ/}OTXߵ z7?YWvsjǎA+6jB罞Q.T!ח/ /dUGHZSμ䥠,.rj؍jk?%gW$撕 G]Z8x e?^dq<]Nh,L^O:o:Y>vOn·P[v]v?gU3U*CAOTdX>X!iտ)EꍿGTV:s~x]3n8! J>sϿg Z|5i=C埭GZ*/%X1MGDZ0_vvF +Ћ_ZMsK tTM"jSI{/)ёIu>hnϻ 9Q;YH4WTڇ'.;Xn[wZOW=7WU~v8AOdӎ?p--- Z'D (xfY i4 Q8! ,8!<&:(*׉'OjX4c &ƛo ^{P\xbO7m`[ء{GCɶ6&x;2;43J\@:[ Y彅u׸> 9yD.IQHv2%Qߡy.0:eʪTzȞLʟ^h.kȩ{NHvN+GiRR r$2Q^Iϕ?`Τ3G_}k['6zG'hE=GO=9GNMPXuo]yA=>WTxue] 胄5pTڄ?찠$V%KSz$*$$~)7nm?#dnOLx8z Ebj{|m6ޓ ]=\ffwE3a~Dp|K|DwWnMQ~~=%~~oS~V&2a\3D*xj{N>Y'r;'sYXU7T6&ԊˬI i<׹숢Gsoք_߬DWn1X:$k7(ՄJ̻={AqBT( 92"$oP^Ua9!ښ?>TV֘CVTQ,_<,w%A27ㄨi9! Yvۂl SG挊 [[U&JC&/qa۶>goU#n䊞;]\=%Jٸxą-ۀl{kzeK1_e#/ $gdYySnA$;0Y2>cPgq7`gyfT[BHj\$PMrlvvmm$[reQSO4&h;g#`; dtTWMkHϮMۯ=*_1g-ێ;8qr t}uv~vmwsG6vaŒW ": Vcvj g N# ᨮ̾/xyîxa+ ɓRRR̲y鏣KVfhMgH xԩ=ko,{${T3kQo7ա۹̌' πFsBTa%%%=\TW(tzhTW圜ުf~Iz~OF ew͘4 ^ˀ/{fT_~&־hCnw=,[{p?Ӡ-/X.xWrTe}ɲ#oDO =i!њنMkaOc4۹G^~ՀQ# z:*kx88=dviG% !Cn]t_^^6'>~}Q{јS5yn<`&/Q}ݏ3v N%,?+v;6y_WoyJYo?i͝1;p|W^'xcx4__@Yv]'˫W枡5iV;iCs{ܯJ@qBNʲ#V.{nVV V>ྲֶlPK]w? }n4HZO2xʕEQ}уy0 ߁_?~-[ύψ'<?|E/c/>/}[F;gVDEo5/h~' L YvxS~Qv#(enfZ&mÞ&Â&uT~Q&n]4}%?O>ﲦG^nvm;йs­Ǒ ?B׍{PO;u`.rq>'xb|eッ]zieG}S $5i69iC[ڵHOۅM Q#9!eG ePuwߠI}T( }.w}4N^z4p俸篬xk~۾}غ _xr[nߋGX0/}) |Aw͘8;x'^,;k} ˖/hR[mК4^n4ۭCͨ`_՗"eђ-],*ƬոIU}ڠy{ժV}K^{l>{z١Cl]%%%YVōe7Lտiu YvmӢk/דQU{~}lv /Yzb^l]=ztʿ~B@sHy 3xRE8G~)ޞxEV`92* |292pg?(,w=+_+{"o֛o̳?^.i}wwvyzÏN;tK~ضm3gF̌[ora=`S֭58yC.|:v ]_n33k+WκxgO!ϥ`TA0h#{} ֯_ /^RA YѣM6lx㍧.zrw5#< b(ia=v̛7hvҗ*ѧwo~;h3SN>i?eqSn% h3' |K_zk׮YA(z+%%r)AJ-i=_kHK-q_u/| v_⠯=6Q-Y/wz2U^{ ~wzhsnb %7$ ĒXpKnbI @, %7$ ĒXpKnbI @, F nbI @, %7$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ ĒXpKnbI @, j|dvvjJRglRj!δ%k*_06ƾۥv8vv槦Aڬ/ڡby)-kJQrK;Vv7 gVna]d҇;.u}kxkM~N.tڊ';VSb;uҤ3]2&:Yٳׇo:tu{qiîO8,_R݈8nA' ZuSM}_*UN +RcyyYx{^yI~v;/V&B v2͘rBX<;hgg7Vm0wSB.WS׻`lDC١]4/݇M+\pY` D=Ĥ,(bl&JTzI)ס{>¢4mFqp̈s9xP7$Sn 7(0';Le\6s+?jhIzg+nusqYe hR%I+8"Muo\J6|qc9%rK??{X21{}V1(=;oM@<9[c'EuAڅ߬Ӣfrr;IK˝V4cz޳];sPzVѨd))Tɹ]j;B.;`2&-;%LO)ܤNva(벱 .ו($]i5%~R3O+zqbʮS(Ԩ{ijΜV~;d+k.ƚdm﵏_%R&QiQAjWϘIDAT rRSRUf3sfGÚv8Md+ݮCHjZ= ʕ&M'qW<^rO6P<-)р%+_7l|a5msx xj%=gژdK%猫Cֳ%c]|xin̜ǔ^%+piepDe9wFgwȞ1ghhiKJ֗ɒiܼ6☜VǎO&koΙ7@ RZZZ;%>suPC<%>b폙Z?,3(*>UyeջN=}fuc8%3V2cp wd|V8A7{9Q ̇kȒ=+vl3[\vʒD]'OvB8[xul_ޱmpN.^ nAZkp@ S1$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7Tckή55%7$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ ĒXpKnbI @, svۣn{HO7lu%3fۏ),nHꤕ/geuMtI׃ɇ{M{ُ /3gG 7GC4Ug89Hg1T1࠴:i%w gl >; ¿מ{Ap%,n9|f}!~kY!・Ϙunc{ >8|'q=M|vYH/hZ\;e#ï Z)/.]/[\?tKg.M8 _ ʇ{Vd[(O]xIZȸ+^ zgrYǟuC1zt@@ݴ=.^k~kfC*ե_Zx.+?2}yK (Reny喾___ߞ늨ba@]LVPkf)Z^'m,F=+5=8dw)ŋo1$]5u#d,^)~tr1pTQ~/?((ՎPP/;@">W,{y̡$_$Z )kj`lƖ^̎*e?rnCItuOhzأCy &]bpƼ /۹N߿>:OV'L}U%{̹$CYWdJ {.cGa|7oq;ҫ  M曏<Ǎ ƝQד]1A //;OʛI:Z5c?xq|d Z~Unm(M}dsG6m|k_wԎ7B~⥗_x?:H(Z ?/]<,c9}= ZO7lK/?4R+W^Şӳ҂C҃;m}˦wNAm x~7ڷ<ĸqz葱~:eng) [ûDqwYj|Wj_ a5;ٹNա:fҲҷOvmT3nQ>ٖ{x͢Atʙ5mtC _TьGڱŌjmr?6|=^xm_ =cȴ4ڿg@+W /-y)vV,^R;v h q gUxQA;{Th!a7|3 'tҎ;^ZS>l OWK4QҦMAOh q `=>PZZ3潆7=wPϞ)C^{Wf_>lwT/j= a!?߻ +Y%f^~wl\4pyn=w}%D/om:h"qzd0`??),}/˻&=qhCǗ&O. 腊r.VcNW^1n=‡~XƬC㯽&׎^>_RRR ?^A5Rh!RJKK}-̝3[oN;+~~UVo|k~{췿K/r? }$`ۋSը8hfSw5cwN{F8 7,U_SF |a 2mjRλ+^z9*gtP@q sϬGtػWj~mʨgT;tԑ}@O.(8OV@uɪ?ZyUIɾA!@KܛypNկfffּZ}/Uto6@ {ASa|ow;/_[rֽ4sv}T@VF]23RRRbe6|P1מ{|⠾}{wyw͚5[͂|nufpIDAT}׿~;ǻ&dI%P_XpKnbI @, %7$ ĒXpKnbI @, %7$ ĒXJ)-- n ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ u(73%)3(S* yRSRR hEpU;V;"pf畆 PN), eR ԔlEySە!{v%%?fۥfϙdӊc+F)+iUZ.60à뙃6YS5pZᏯe3G>级*wdo=VۿC5Cgf19E3vNlwVnIi3jdZ.Qq/K nNXC9evc&>l&>m [X>K6mǻ^zZڙͨ\;uXʍSqt\3cn_,68].مsV'K'Y?l9%X:jĴ6 P0|a&fl/,.=m/M9m rs7Mެi̜icҒ(27BvK @+dd`Ul1v)*($*=uѾ)U.JTIjjjMjpGϒ,)%vHjNs]i-f & l6qK6o75lXF [4>Mpc MDH6pd%3OIH9(s%%5EK.%%%kJQ(GUgN+4ٹ?$ RJKKk| ' kAf(1ma h{ڝES`Mވn.-X`lj6oƵ v/tgє=U*jp'f.⩗ѱa 8;VSֽxulk3z;{qݚGoMCURێpїJbR@ %7$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ ĒXpKnbƀԮ95%7$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7{=>1o޲e_UV}Q׭[~Gy'i&TJiiio|ڠe{z/ƈ0G^wx;G@bn >1cqBc/7lM$~5׭[w‰'=̳_v]ڹs猃^}-aٲ&O^lk:W]v hbpsݡgˋ^wLMMM z7{ 'x;M Z5QwVs۴p_C\tzh]FS 6|kz+,?{bن8ۡ/Q,_<,wgvqmG nV N񜼇t]v:UMokӦMX^h#@)#~I':+O+Vfv cɒ%Q# y-[oZ*ԩ׭[~G9;#aaqxVr`i"4RN|{h=k Ͽ`+@SNm#h RSS_}0h+9 5^q7@+o~~[>`M-}WiJM fvl䥿w9h%_|;NIc%Z*7@w1tCꪖ.]Bǎ_{yEM[Ozgw {~@}/-yo5Fe]|AnX(xC=4?+94^vtPpyeˢBjjǚ ="ޯ?^ǹ??I4@uQ^u W =Wg}²˃Ps1p~a5wˋ#o{ⶽ;FK?5\^:4zCͼAQ -[֐JMWƈG%W>k$f{fwܱUٰa7v뭷rû;X/~p^ZRX9}A= {Oرc݇-Jkjt,qaQqj{pmڙ hrJ;sijV,#A 8.aѰsuShQd򟍙`ATI)))EO=z I!)C+Sz,2Nü;lowe:/]:;_TXew8QyޓOl6l[i%oZ+UIl=xlm>ƭz8=7DI_9?6YY5dɒphCklRE$u7珝P1zEyQ1l2Hˉof܌.ZTis!ȻQ蕉A&upjvYR&m2C< (0iU |G?Mշ߳.ˀuXɛKbe7(x͢ӂFi[DnT|.UnM~f0`΢k+Y1Pe3tVIC3+CSu{Ehp_`3c/\"Fۿ2իB>]k%qpEuP& Id&ǶIC9͟67(6(k;#tyJH/ij}/ boQ׾e+ wa=r[zf zO?i:iIѶSߩ'7Y9-ddsEAS)~2Rr/wM`ۨmh#m"4L3ܻѡ_]z 9yT]PP;ēkߏcom/T~IDAT*dǑ3tr©Uִ+WU A&cyo(tkƹ4Ke-dN^nF'M)DSGܑYiǓ9}~ys@ѻM~sm>Tsb%v}HKUSY+s+ʻʃ[ѹfUTgO5m ΧT*[6M^Ft.{Z~ÿoҵ*RluJ%d犃C24pQAqqHzNyɄt[u3F?cc%d'YǠgE&^5k6 S&'>rJa4oO A-~g/U!u]׍{406S_xkz-IBrOU\^vx.lj{ <0yJU%"io&j3ַ4.~24htZ}=JUmVuc%d;o87K5N=&⒰㩳H_?kE0`X"]I4]R:*uDr5~2_qʫc/7{;p܍7ٷ)/O$h5s؆ptYtV^f!H}T:`Ĵ⹃_fԄ)F:C֭;ēye/Ү]ܹs5j?lJ >^ZR-%'LC Z }jޤm ?:xګͿ2YOyL0RJYNW4Quj80A s57d[unӶ-[, )Bh?$vܹUS.\T4`P&J\IDe*nV,.oRS;N;5>5ɾ}Dݟ^疖6v:AԀ̑-]!I5U#͡xceTķ=]QV,䶓ˮy.Q>DԲG SoJɶt*O;T3{ul8q+FbKL\k5L|!5g򅈚'Z[xr`ڐy7R TKk]XJͤޢ֫EO[PqcnYW8a3M]~gHý3O?^>jI`V֣G>k/Y8aԄ bԄ;0tv+"Y70fkaȞKjVsc&/^s!v 1zĴ&ܤښ#=d$-̺<1H0鹔U+*GעJgz"ujςIͧ&t\?7hPȔ:)rھs/3ʿJM1$3u *;.~y=0f7|sy?~/AEמ=)SNu s\;s5a yeϊiE?i5$\≷0:=\ *-kQ 8:mpE]Q+* NbҬn[5R-ddl[ WK n /쟟<3ݟ5Ԕ5Z:lkwp嗯 '>c3G}W?E7SFmY7Nuj^Uj^za7}h0wfVzU_ٹ솏`[jV$w7PS=kVioA"Ϊxd!!z٨*aDNsnzکGVL=ܩE3󐠾ٷ.{ſOߍ)T Rǻe{w|ީ{ .]V"\.ISDV]Ww|5uqu_=˗Νӗ>̎;SWgN9ݮ%>k4u&2U-ULWlu)R֐eaÆov[o uy;PȚb\idwL4S5W@.ZR?%=^]iuzwF9N{췃: Ӝi֦MreG o۽d3;۫ א=0|+zb$o-SYS[NWpnk/S=-j=5CƠ7ēro[ɥOYYm` h3855՗ Di|Bճ^O4p;M+6&C>迢¿ /ӂѽ;_6ly睃-D]Qo ZBLMh _{c~6 |AnX(xC=4h+9 qt鲾G:v+D nV` _xrۚ6pT~qҋ/o|g}²˃ƱDK- hjMDI˱뮻3|X@ѣG>,,[gd%Z 2v)Qa̻V^^^n̙QSN ap]23S~4윚/?fM| aq'NCT?sņ V򟍙`ATI)))457lmGw/2%og]O/\xx7rkrTe}h)5ֆIDATky|8r}AG #އѦM n/XPPs*:G-Ү97l?ᣏkGļy@0`2m]w Z$7@+6޻qk^@Zl @7lcwOΟ \.ljpn`{$hv ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ RJKK5%7$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ 5Q065&R;hƾKf nWc)2L[cu켠6rvyr^c˚RUǚ=$(ֿl{; _wz]r 0Ǟu콞c9eZKAf.]byʷllue-<5"n!jdMI_wlAӊ^-9ǣ5շw<-Y{uɬёjW\vaaIC^xO5Kj '5%%kJQYHh;3gvy=jDDIj(_zAQ#R?KnIʝ%Z;%?0}ظdU;w#ް:2yIϙ6&R9 Z7+dm%c]|xi/yሪ)~s(=cY9Ӗ/%ӆym19ALޜ3E%n$7 ƦNsU^vY5SOIP폙Z?,Qc8%3V2cpm[1 JgtÊz'.}|,j6 OvBnqe,I010pݪSǜЭcm;s2uutXZ!7$ ĒXpKnbI @, %7$ ĒXpKnbI @, %7$ ĒwYǟpBDI4T :Q{(ֺZl+nŮ9ۄgjUmg+ V9AZhrQ: AC fMR5 s~<{ߛcI= 7Qܴ2yfMOpɔ0$?*6\'mx©UI JS{¢uSB̕kn)XgԊ>4[s]% k>yO]EESw*UF.YMCIR`OTMm֕MMVl*ׇlrHeF޲6wukv[OgF^j޴]fڡkmZ7av͐VNO͟D%ƳP&]53?TͩNjxӾҊ MK'\]xcaj'ȓ-Z'3aȟQ֪r@o.]]Ux?f{6LWW,wO޲yvj;aQ9SPQ&@keΗLrZSԞpw%ͳ5UO0յrQS‚+*Jx͝J­WPuzLGuו ?tJڤk mx_>76h8騑!aͫ*|a-#眛3abO! ۴ 0ԦkKoXrcQ9}O0rچ}U*fH%4٢!RV}}ao{WEׄELh;]3f?~&ӊחUі3Cz-]'nW\WGY9~ ƍmy'~қk2c4ͿPQ|2Yb+Z6,NV>?{5wOkIС]zHQ/W.{lΝ!/B2{Nlc /c\6a?KY/.3:pT~>2޽{_y.[N((YHOw~駇%v^_a~HM $%G >zd;'犒7d=^H,IՙMA#_oBZ:{ݻw5={ K. ߿'/{tR!dH3NN((x?_yyF in ܴ ~_r暚͛kB:AyyEEE\|.89b=z7p`Gt-֭[ʣ>O|~! }`ޜm{t۶o߻w66? 7~7] "IDATQE_ng?.ezz+7h+'5SWֻGwL n޵W_8d{|G o7W/^e~Ɨtۭm|{}; o}`c C'HZE&ץtg'λz޶%w|;5K nMMϻIu gh>rGR/~֍55[$?|sj]gx雓|?z:H;wV,?5p)Sz÷nH[x׮vlA2Om|nVQQ5wihOOtvNv2ؿK]*58xUIȞOϯwaEE}8O_ex޶m[j0rp,懂 7`P4XFom۷:BisE^'8A ]VVڨ`T1 v5HI_qe O "B%͛ߪ iwzSjCZ۱?v1ל@i}{ѤL m2%KZl}]yfɖ3{}Ӗdiݦ'NoL (-ޢB;sK ;O;ԠzUu8q?>5?b ?^W]Yʷ}^j&{ӗL˩o]tIիZT8~5Qҽ{&]1vəkA}}ͫ}/UTt5^{嵹WM^z8D?|~}&n*?L5Rhwξbvv_7/A2?pܯwR>\ïXĪEw}OӗLۥ'~3;o,^ 珺hTž9=Cyc:VUP0t)V^o;Vxw}?痍7mjmm뵵-w Yh.3sݺ}h qLrBI / @n$p%( DI J7Q @n$p%( DI J7Q @n$p%#( DI J7Q @n$p%( DI J7Q @n$p%( DI J7Q @n$p%( DI J7Q @n$p%( DI J7Q @n$p%( DI J7Q @n$p%( DI J7Q @n$p%( DI J7Q @n$p%( DI J7Q @n$p%( DI J7Q @n$p%( D3IDATdh1kIENDB`././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/bf.py0000644000000000000000000001042315134002420013227 0ustar00# bf.py # # Brainf*ck interpreter demo # # BF instructions (symbols): # + - increment value at the current pointer # - - decrement value at the current pointer # > - increment pointer # < - decrement pointer # , - input new byte value, store at the current pointer # . - output the byte at the current pointer # [] - evaluate value at current pointer, if nonzero, execute all statements in []'s and repeat # import pyparsing as pp # define the basic parser # define Literals for each symbol in the BF langauge PLUS, MINUS, GT, LT, INP, OUT, LBRACK, RBRACK = pp.Literal.using_each("+-<>,.[]") # use a pyparsing Forward for the recursive definition of an instruction that can # itself contain instructions instruction_expr = pp.Forward().set_name("instruction") # define a LOOP expression for the instructions enclosed in brackets; use a # pyparsing Group to wrap the instructions in a sub-list LOOP = pp.Group(LBRACK + instruction_expr[...] + RBRACK) # use '<<=' operator to insert expression definition into existing Forward instruction_expr <<= PLUS | MINUS | GT | LT | INP | OUT | LOOP program_expr = instruction_expr[...].set_name("program") # ignore everything that is not a BF symbol ignore_chars = pp.Word(pp.printables, exclude_chars="+-<>,.[]") program_expr.ignore(ignore_chars) class BFEngine: """ Brainf*ck execution environment, with a memory array and pointer. """ def __init__(self, memory_size: int = 1024): self._ptr = 0 self._memory_size = memory_size self._memory = [0] * self._memory_size @property def ptr(self): return self._ptr @ptr.setter def ptr(self, value): self._ptr = value % self._memory_size @property def at_ptr(self): return self._memory[self._ptr] @at_ptr.setter def at_ptr(self, value): self._memory[self._ptr] = value % 256 def output_value_at_ptr(self): print(chr(self.at_ptr), end="") def input_value(self): input_char = input() or "\0" self.at_ptr = ord(input_char[0]) def reset(self): self._ptr = 0 self._memory[:] = [0] * self._memory_size def dump_state(self): for i in range(30): print(f"{self._memory[i]:3d} ", end="") print() if self.ptr < 30: print(f" {' ' * self.ptr}^") # define executable classes for each instruction class Instruction: """Abstract class for all instruction classes to implement.""" def __init__(self, tokens): self.tokens = tokens def execute(self, bf_engine: BFEngine): raise NotImplementedError() class IncrPtr(Instruction): def execute(self, bf_engine: BFEngine): bf_engine.ptr += 1 class DecrPtr(Instruction): def execute(self, bf_engine: BFEngine): bf_engine.ptr -= 1 class IncrPtrValue(Instruction): def execute(self, bf_engine: BFEngine): bf_engine.at_ptr += 1 class DecrPtrValue(Instruction): def execute(self, bf_engine: BFEngine): bf_engine.at_ptr -= 1 class OutputPtrValue(Instruction): def execute(self, bf_engine: BFEngine): bf_engine.output_value_at_ptr() class InputPtrValue(Instruction): def execute(self, bf_engine: BFEngine): bf_engine.input_value() class RunInstructionLoop(Instruction): def __init__(self, tokens): super().__init__(tokens) self.instructions = self.tokens[0][1:-1] def execute(self, bf_engine: BFEngine): while bf_engine.at_ptr: for i in self.instructions: i.execute(bf_engine) # add parse actions to all BF instruction expressions PLUS.add_parse_action(IncrPtrValue) MINUS.add_parse_action(DecrPtrValue) GT.add_parse_action(IncrPtr) LT.add_parse_action(DecrPtr) OUT.add_parse_action(OutputPtrValue) INP.add_parse_action(InputPtrValue) LOOP.add_parse_action(RunInstructionLoop) @program_expr.add_parse_action def run_program(tokens): bf = BFEngine() for t in tokens: t.execute(bf) print() if __name__ == '__main__': # generate railroad diagram import contextlib with contextlib.suppress(Exception): program_expr.create_diagram("bf_diagram.html") # execute an example BF program hw = "+[-->-[>>+>-----<<]<--<---]>-.>>>+.>>..+++[.>]<<<<.+++.------.<<-.>>>>+." program_expr.parse_string(hw) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/bf_diagram.html0000644000000000000000000001536515134002420015241 0ustar00

program

instructioninstruction

instruction

'+' '-' '<' '>' ',' '.' '[' instructioninstruction ']'
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/bf_diagram.png0000644000000000000000000005527115134002420015061 0ustar00PNG  IHDR@JIDATx x?@JQ⫲*(ĥ+XjA*V[Uh" UD@EE@(ajQCE 0,7fܹC29 TwĀ @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,B'%2`zؘ;ypfZhQ>#yV#r[kzgö 6)uRv29w.+M,=9G N'jڶψ;\AVL_;cpSi;xM]LDS'l+N/r/m{Zڸ/fouSvlꅹm;{_Gv[c>iNXvo N۳ HDCX5?-glj{ݺѣSO-*n}\zk7a݄>C~!}>޹yռ=w~^"}/za7P~\xEwO.`V=4hxΗ/<;߄&$B =1 ccx͋v?5}F?g =P6BmA/mI:6c*,\=vxf궎F'2vvp4j'qGPߙ>=+glyqf[犞C 'rޘ7cH Z X;cPZ֧^ЋVm {LJ. {+/+n_Re:`ѳnD7ms4 U;FH 7ќ^ ͬUhZ@UvuoHjjZQ/vgʶ7;sn٭['CÖ./Trg/бT[% hj9=w{Rاvӭ|ܶ&v(~v 3j}ع|P8kڜ#-T_{c#f{HZ% O3Em}Cۗn~A{<9u_-xyօb` GldxP;? EP'ms׆=/y5F~3YNh{89>rwq/}NU&\;mG=!dwO TW% MGp,(VէiR{dz>z~ΈZ'}@;Ӣ+PMwN/4ʾWJAA.Nrj4Ui_^EbdIkWQO"po۳g W0jy9_Εzt>h}JL+1v-p:GHO96hqmln1 @8}ѣz u;_޶)cL͒9F=Oidɠk7i攫5}@%I `bA `bA `bA `bA `bA `bA `bA `bA `bA v7_ ~5hH0  0  0  0  0  0  0  0  0  U;oڴiSgfe-^+?찗f $ |iC=4㱧ڽuVBr+|Л˗隑ÁTf__]ڵCנa Ϯr 'c%}wc;/Z8TihQ_zQGy!?Sڵ^{NyzDWCc}H>0TWUl#>V~/4iOKUŅ?o|p .h֭T͛7~n׮K/oU8{sz=wOC UU Ӧ?:u<lGUd۵mʎ>}aFXC_53++Qt8kFa p@ZeaF:*6K=ȷ]t5Cqw* ŋ"5IkܸqT,^$T* pq>}@W;駟W5UO=<3PťkW -_[n=k׮K-[8B}FJZgwHp !i 첨۳f ,͛ճ̉6z])))}j(W!ѡ<|C>_j&QF.-00PΒ:{?ڼbCpJS. UL'/?v!=8zT E^^^F76m #p"%{ocďlY?}PqEm3*`u=.n!_4D7K {n gDʅӯ*üF%f\s~ggWۮ$(_{lrwp̕7O<9=_`q}ݨG>w}̝pnuȘUVݭ((o n g_4yUYޚ-\Q+s[wXzv[7lR}yQ/g$r쟮Zxݭ>hKO;mud>o̿0_I ק_Yt[&?mgwtxw:4xy;oTUe@TeI疜lK%n?_}uA٨Q/uNP!ӉyUz[&_?:Ye6Ռ-ewO;sӦOԬY1ݳG(7n|5C~{͐]j\PPЯ۹SWwUSN &ݮUğsJlrꬫ.ehwѭ)*M^8ɊWG児za}A?yuMvϋɠZG}Atjjj(‰wy/MxK̙_t^԰eFׯu8;t蚕Z_a uv>hV4SOwf2 /|}.VIDATc䊝Mʵ./| y_pE[n ɡ@W͛7]7V ,!nعH9K~]xus>Lƭs |jw'ɕ8{9$7/O|%?$P}zMOuyx̘K'F}CISv!s٥ ?OΎc=6PlX ZWH 'Z**:{LRըQSzǨ^? $X~mi֒ߨfR:__(>PfdDwQӣ@}n#o-Q|ax7<@zܨhԨQ(SuHJw3qQxɒ@e[xqT6 Iܮ]ۥb%?գwm[ދG@q֙Q1~ v{T{1MB '[J?* 3^q]Q}eP}p͚5֨Κ57W_y@ZxIoֳY 9T WD=#GwX`aBeth͚m?*$] ް~]>O>e{کv)=cvg@z)_jg70=CzjmI9bg;m̙<{FZ'ms6',]^εӇd/Ҩm;\BV;s6j9xlڽoz?C&n {]by}Z.SWtj;$KrFm},ZnMM^3ԛ_|p~nфv {`rvu^s`A{s=hWggR7}DNP@y~wn:ʜ!ݯx9MCԺ^yB%۳ͻa|E_K7C/nZPbm~ݰhSgl?;}rQ@ky'ݦ>;O v38m'/аǘ'ϟsy_BpŢy1 ?/_饖:c? ?<Vs]б;]a;g9xE?ؗOZ@}=v|~Vi_ks)Eo>uݔ:iFL+[mh5$uՍEM(TܜEUA=Hp}zyy_qT=uA>?x/vlzŇ8wZA}Z2[T5Jԯ))/ :@r%slNA 测wpnAsCi,6RneJ ꤶ9x܍pu&Oɂ=}~ p iE|ՈKRSSӊҧ<1%Q 8wdG~sE:vlwɹl{É-Wn۳թmzE xӄ[9ksf>xz^j>݊gm;`r4_ƼC2ݞ{ |RtljDnss =ߩ[t9U=;Ҷen߭w߶X}' |j.fo:zvE^;Ηwr .?}w:u~}< P9z'b̯n5ddz{/ϐ_?[;n걓igRCȹwtű0c !u(e/fjؤ)WYq̝ζܨ9&S&ٲNs}mz;㹃/Qן6M?vt;[l/5kxn?z~ΈJJI)((P 0  0  0  0  0  0  0  0  0  0  0  0a@k0 0  0  0  0  0  0  0  0  0 S^{iӦ}y_O> eiӦ5k֦Q]ذ~]r?g}[n C(74 $74<*~{͐==JL\۹ըQ.}[ K3ffe%uأ%!$~QT|ߵ{z8x|^PyYuѭy~od1q׮v{1SnݺI|7;kv$`$`*Ԃ >⨮SΕ#uT}_b:ThRNĒ!T-=!g.+K:G4@(O;7ڲeE.={N^^^к5kҡyOoVs  w9JœG̛;;ZjvS~?>gs7n|5C~{͐]b1qnj?z{x5duE߾F<.@wL[? 衿?(%%%ܺuk $=vm߮]i~$֭*M7Ryn/{u0:IDATj?\f5*|$/1ƄR<`~?[=mܴZCG/^`>wugmHV¨sӘ/-+ѩ8!׮O?t≁d{EEZ^0 Q=ĺdugvK tǯʎ1G': $5kxkKj RZZZTlܸ1ԯ_?Q`uze_B[4{я[;6/W:HV:v*SSSjtv@Uм;>uYW~T7q+μg]~씞>IlҬ(`6_J i~}o'ԭ[7PH.0VXO6}/_ʕ|I(;M6=Y6mҥ׏@ʑ?g}[n CY('5By@r{Ǥw{+&&|yNww{@lU๳fy䑁d'x󸳎֣[ 5e'7'wś+~cm֯]}Z4ikߦKNwѬE?gNY3}{vz Y r"S {saÆPN9qW^ C't⬙/~ix'(@l2eg/zxܸњ5|t'rNݺuU`ʉ $rR+@ Ă @,ĂLezקM>y˗/O>$MԬY6GetGg M?3[wءy`tI,*ܫ.8&[17˻pu͛KհxGyd Y=>/(<ּeChF B]7w۸kG;=昩SQn@j[lIuY*/Tz\5 FӾ}Ii'=Z^+G\yEtnފ^m~i{$%%%7Nߥz}2T0@C/^HV?n H 9ͧN0nݺoj֬T<~U9c~;7>44eZ@mZD Æ}sm5jT rG?] @TuYNƳtP+GkHS7>vVNg@yaƋ#+@,Yfk$//oҥQ~%{S˴PbZ3zSd% ڎ0gȣ`@rط қk;ztɑjJNE3/$^nY4=Vvڷoޜe˺fکv)=czǎS`v.mJҾIdκ7m旬Gm*Պ+2SMO֭aÆeg>}y{hsiW蚑13++PZ+iow9J[GE^^^Y$?ȸT!{I7i $hRݧC"6N $=zi g(_]rqkKr.K([6o mO⋪K 5=|a(7ptDW$^$pDkoRH;o:-蜅9QѤI,Qm{I677t}ĉLIMMm׮mT6&mMg88/,*4fK Bںus_>QlO@TQF.>׾­ݚĉLzp $ס٦B9[2w9G3+_)==1 ׅ*eo7O69>}Z4ikߦKNwѬE?gNY3}{vz 5=uӰaÕ+ UG ILQت28^q?>5kB蚑ѧOz䜺u !=Ă @,Ă @,T^}ڴs_|WOBiڴA͚isTF.~tv,T=#ۺuk(zFo. @9½c;}Ͻ~\ '^o޼9vj8zɒ%Gyd Y=>/(<ּeChF B]7w۸k'#5k)[n YIQo(Kpo@RZ`ItߴiSSΕ#jOjժ@y1oC2-TDos6-aÊSIn/k֬TpytШDYNoK.ym_ѥs@2ٲyK( QLI|QuɠAsf>?>\,|W ?2Q[vtœhҤ[^بҸqx#P*+G:wBhIJl¢Л$qRm@l:{LT]i~sM{jN7n>q"SARSS۵kc wRy{uiEu3 @T]cnbmݺu9C֯][hq' N`*Ώ{(˶5x sJ0pz٭YQ׻JII @TGjРAX~}ݟm,%ss9:1ڼb3)ذ~]RvkISśMӚfm9遡${Zs攙;gX&>CQA@=۰aCX|֫W/`ʉ!TN:qO?PQfd?9nݺ1Cb4D0  0  0_6mܗ-_+?Pv6mzPfmѥKx3 4#??xna:۷ $=@PNjpNwsoŤ߄7/v‰7o$wEJJ2T @/Y# $'=śǝu\ݚl~mШA(;9+\Fn~Dؾcĝf͞:u $O7lo}[N5=j=?7,Xx)7mڔԫs+Ͼܟ[w]벳O;mc^LV$C8+s焪h$W @/^$8067܂q~RJ=stK{GOO:aIiݺuР~YjOjժ@y1oC2-TDos6-a>@ۋ}'@٩xG?] @TuYNƳtP+GkSF[l{4ß׿I/z5ko&L.]W7LK %!8=#<=5L/^@_]P~2Hy1,XHs_67D}ZzPbM[,a#;0;;{2e~fMbVA5\}vQYkzjΝ;w<fҦ$4p(旬Gm*Պ+2SMO[hUԧ=s=mN6-J]32ffe*[v%-nyyyKg$ׯ#|˭A5]^to@򉦡,$=zi g(_]rqkKr.;ɖ[lAd|o~aM5],|W ?2Q[ru?r6 0'*4iֿ 6m0ɦqQFrswOlaQMMm8 =&*V4?Naw{8ݾ}Dk6 Jienv-V筞6nZT8ĉL|eQ11 ^Z:u{ۻ[9göf[x ^?%Q\7MO_0RN}efgeG_+%%%q"S=Abuw5wPΖ]rLhwJO@TeHBod?Mԟo|ώ6㌌ǵoӥ́M e'߻h֢ğ3,ޙ7v?ĤsaÆP8)Ļ'&^rX2JpI'Κ駝*ʁp-~ @,r8^q?>5kB蚑ѧOz䜺u `*S۶mo%3XXO6}/_ʕ|I(;M6=Y6mҥ׏@ T=#ۺuk(+ :z47:tvԨQn>JԉH2/xqĝw(sY~s5dtҨwUeZZ(?h -i}HQ=驁dx SmAgȣ`@rط қkڪe [٩hف䐟-5kuP2H۷roβe]3?St1c@)~0M6%itCIu6dGu>j'PVX1fϞ:mz.֙gNZ5 L}=iD5#cfVVlWQI{dܜsj8^zO=17~MCUYj^z8+'|Tgu9-˝#tH&[6o ]⋪K 5=|a(7ptDW$^$pDkoR}!4FœhҤ[^ب=$ƍGoZ9y;,4#7βE75IDtfm9遡${Zs攙;?!#SycK@S N:Y3_^z%=T>qً7'}fM(]32ISnĘLej۶Mur&6oIDAT 0  0!?g͙;{])KM5ָ$25iGnРA+ᇫ/6}fMƿߜ9kvZ׵ 5BLߟx2w?ݰwW||g;n&{l? /@eHIذ~]RvkwNItFo~j#Z @X]ꂅovVZyAvo>k!נa k;8u2t޷^ x5?87Nq-[SG`1dgGuxO~¤5x~46R#Ƨ=b(43+*9?~*V{8f͚?gqZ!YA޶wիѥs*/.[N xhZ~קM>y˗/O>$4j֬M2t9g/%.QSzzfyݘ?g}[n $^7o;1n߾]G\Sz 7wCu It=JUH7 '^o޼9 ^ 㓞 駝v~a[n"Id˖-f%w}ڵ;F9kSQnP}w(jl7 @ |QWޟ4p@@RUV-Swiss${6GRRRB5HM; T-T}iӦDݸqY3_~f͚M:_"|z 2<~+T_czs8@Qf?|ӑGm0lXB5jQq~N:@USFCJ|ct5tҨKUS-rrTOyzjʎIviOZxɻ+V|4h{Mz=[s_W|Dړo>QNI CZ73x'E?|_>gٲSO%ڵkjժHO:v<6*VOkUfrb|gW愓N.w΋-{!o{>}@U֮m5n޼9VսWj PvOpχ&%KOGO9W_]m6h༫kٶeCJ eg˗.g;3&Ϙ9efbO"tzܸ:gP*EE~7y,tHJN:fNɜ̯p@SpQ^\\PPЯ6nw"$ΟxYI#'7o[g:t.Z\疚$PUf:wJu3PNvFKž{ǦM}.3zr _kP=_M.֭[:}t75)=J_9fT3b3B͛xÍQֿס~?QHCv{T{1M4 @9>0ZeG?>k6?QԮS 7ESRR:t3{}+Gع̾6գ+ww.zTwaO0w³3nU3W- Ij7[g ս7ZgK|YΫ!I}f.t{3w{ @VAꚑq//{F< (YeggGőJ0PZZPri?(YCphE.X͗-5k5|Qb{rn")}]b.RxS. +7szt3Ys&^"$ @TY#o6kΜ(*,[5N=KN;vջ0蹽>/*k{}F=3o]A߽0Ew;tC^U_\v;^3^=WϘ\x+0tW7svgJ+{o֭Wx3'T @lTԧ=s=mN6- ]j3vtA0FWXX_tW7cjmg}UօEv/ 7qUׯ#N8>3@9VC#{I7i+9`5kVNP 4*+1ؖpڽʌZ}x٣<[f۲$-L^xPj'.:X+oə(R={ S pW\ҿ9Kaۣi)))!mU5NSj"=-|瀣 S綾o|̸V̰7^}uKLfN|QuɠAsf>?. `+QrB;yȡhѦE$oyT5⎟]00'=1gnݺ5<8soBL0#W>{e9uVaL޵9{7x|ŋuk׮{1SnݺTy֜M;wBT=Ҹqx#Py-\2Ђ >(&;'~ԬD唉 V`Z T>xʫ1yɢ> l ͬ[3HgV?lWv~o˳gu)3W[r1mڵk>YɪE=>:?7m 3Ҭ/?Vn4Vλ^n7N1 ~.|AҜq=k# !qԟ͸(0hA sgf*Փ\7%,Gfk&I'.댰IRfͦOr/~m>=uꄉ 73Nu]r=:oISM=H= T=sLy3~;7yo{a ;]89K~]q/|wݜ|'W˫*5k曲f^dIbaqe=7[nf(=ۜn*Q]זݘ򷨾KC958y'tb2ԨQc샣%|G<JG& wF6P~H) {dYkz_3qV(kyyyK.jrjٲ)'G7>_6!B o惚5)=@.5#_^6I &M+6o7wumQ?*/ϋ $XRu<بX^̝~3\w|Aͺ(TaMf͙`I~93k۵m.mtnN޻yK.Y—R.?z}UE3w TU Pjq qI=3ssGOB_c;P>֭+Z֭wlF%^r#?8z3@e5^oV^toPQz8+DųE 2IDAT[olq7j(z3@yx'~u9-˝#t.#{,K.4hNGSƍbqGفy4T7-Xp>") QUOT, APOS, ACC, DOT, SEMI = map(Suppress, "\"'`.;") ungrouped_select_stmt = Forward().set_name("select statement") QUOTED_QUOT = QuotedString('"') QUOTED_APOS = QuotedString("'") QUOTED_ACC = QuotedString("`") QUOTED_BRACKETS = QuotedString("[", end_quote_char="]") # fmt: off # keywords ( UNION, ALL, AND, INTERSECT, EXCEPT, COLLATE, ASC, DESC, ON, USING, NATURAL, INNER, CROSS, LEFT, RIGHT, OUTER, FULL, JOIN, AS, INDEXED, NOT, SELECT, DISTINCT, FROM, WHERE, GROUP, BY, HAVING, ORDER, BY, LIMIT, OFFSET, OR, CAST, ISNULL, NOTNULL, NULL, IS, BETWEEN, ELSE, END, CASE, WHEN, THEN, EXISTS, COLLATE, IN, LIKE, GLOB, REGEXP, MATCH, ESCAPE, CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP, WITH, EXTRACT, PARTITION, ROWS, RANGE, UNBOUNDED, PRECEDING, CURRENT, ROW, FOLLOWING, OVER, INTERVAL, DATE_ADD, DATE_SUB, ADDDATE, SUBDATE, REGEXP_EXTRACT, SPLIT, ORDINAL, FIRST_VALUE, LAST_VALUE, NTH_VALUE, LEAD, LAG, PERCENTILE_CONT, PRECENTILE_DISC, RANK, DENSE_RANK, PERCENT_RANK, CUME_DIST, NTILE, ROW_NUMBER, DATE, TIME, DATETIME, TIMESTAMP, UNNEST, INT64, NUMERIC, FLOAT64, BOOL, BYTES, GEOGRAPHY, ARRAY, STRUCT, SAFE_CAST, ANY_VALUE, ARRAY_AGG, ARRAY_CONCAT_AGG, AVG, BIT_AND, BIT_OR, BIT_XOR, COUNT, COUNTIF, LOGICAL_AND, LOGICAL_OR, MAX, MIN, STRING_AGG, SUM, CORR, COVAR_POP, COVAR_SAMP, STDDEV_POP, STDDEV_SAMP, STDDEV, VAR_POP, VAR_SAMP, VARIANCE, TIMESTAMP_ADD, TIMESTAMP_SUB, GENERATE_ARRAY, GENERATE_DATE_ARRAY, GENERATE_TIMESTAMP_ARRAY, FOR, SYSTEM_TIME, OF, WINDOW, RESPECT, IGNORE, NULLS, IF, CONTAINS, ) = map( CaselessKeyword, """ UNION, ALL, AND, INTERSECT, EXCEPT, COLLATE, ASC, DESC, ON, USING, NATURAL, INNER, CROSS, LEFT, RIGHT, OUTER, FULL, JOIN, AS, INDEXED, NOT, SELECT, DISTINCT, FROM, WHERE, GROUP, BY, HAVING, ORDER, BY, LIMIT, OFFSET, OR, CAST, ISNULL, NOTNULL, NULL, IS, BETWEEN, ELSE, END, CASE, WHEN, THEN, EXISTS, COLLATE, IN, LIKE, GLOB, REGEXP, MATCH, ESCAPE, CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP, WITH, EXTRACT, PARTITION, ROWS, RANGE, UNBOUNDED, PRECEDING, CURRENT, ROW, FOLLOWING, OVER, INTERVAL, DATE_ADD, DATE_SUB, ADDDATE, SUBDATE, REGEXP_EXTRACT, SPLIT, ORDINAL, FIRST_VALUE, LAST_VALUE, NTH_VALUE, LEAD, LAG, PERCENTILE_CONT, PRECENTILE_DISC, RANK, DENSE_RANK, PERCENT_RANK, CUME_DIST, NTILE, ROW_NUMBER, DATE, TIME, DATETIME, TIMESTAMP, UNNEST, INT64, NUMERIC, FLOAT64, BOOL, BYTES, GEOGRAPHY, ARRAY, STRUCT, SAFE_CAST, ANY_VALUE, ARRAY_AGG, ARRAY_CONCAT_AGG, AVG, BIT_AND, BIT_OR, BIT_XOR, COUNT, COUNTIF, LOGICAL_AND, LOGICAL_OR, MAX, MIN, STRING_AGG, SUM, CORR, COVAR_POP, COVAR_SAMP, STDDEV_POP, STDDEV_SAMP, STDDEV, VAR_POP, VAR_SAMP, VARIANCE, TIMESTAMP_ADD, TIMESTAMP_SUB, GENERATE_ARRAY, GENERATE_DATE_ARRAY, GENERATE_TIMESTAMP_ARRAY, FOR, SYSTEM_TIME, OF, WINDOW, RESPECT, IGNORE, NULLS, IF, CONTAINS, """.replace(",", "").split(), ) keyword_nonfunctions = MatchFirst( (UNION, ALL, INTERSECT, EXCEPT, COLLATE, ASC, DESC, ON, USING, NATURAL, INNER, CROSS, LEFT, RIGHT, OUTER, FULL, JOIN, AS, INDEXED, NOT, SELECT, DISTINCT, FROM, WHERE, GROUP, BY, HAVING, ORDER, BY, LIMIT, OFFSET, CAST, ISNULL, NOTNULL, NULL, IS, BETWEEN, ELSE, END, CASE, WHEN, THEN, EXISTS, COLLATE, IN, LIKE, GLOB, REGEXP, MATCH, STRUCT, WINDOW, SYSTEM_TIME, IF, FOR, ) ) keyword = keyword_nonfunctions | MatchFirst( (ESCAPE, CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP, DATE_ADD, DATE_SUB, ADDDATE, SUBDATE, INTERVAL, STRING_AGG, REGEXP_EXTRACT, SPLIT, ORDINAL, UNNEST, SAFE_CAST, PARTITION, TIMESTAMP_ADD, TIMESTAMP_SUB, ARRAY, GENERATE_ARRAY, GENERATE_DATE_ARRAY, GENERATE_TIMESTAMP_ARRAY, SYSTEM_TIME, CONTAINS, ) ) # fmt: on identifier_word = Word(alphas + "_@#", alphanums + "@$#_") identifier = ~keyword + identifier_word.copy() collation_name = identifier.copy() # NOTE: Column names can be keywords. Doc says they cannot, but in practice it seems to work. column_name = identifier_word.copy() qualified_column_name = Combine( column_name + ("." + column_name)[..., 6], adjacent=False ) # NOTE: As with column names, column aliases can be keywords, e.g. functions like `current_time`. Other # keywords, e.g. `from` make parsing pretty difficult (e.g. "SELECT a from from b" is confusing.) column_alias = ~keyword_nonfunctions + column_name.copy() table_name = identifier.copy() table_alias = identifier.copy() index_name = identifier.copy() function_name = identifier.copy() parameter_name = identifier.copy() # NOTE: The expression in a CASE statement can be an integer. E.g. this is valid SQL: # select CASE 1 WHEN 1 THEN -1 ELSE -2 END from test_table unquoted_case_identifier = ~keyword + Word(alphanums + "$_") quoted_case_identifier = QUOTED_QUOT | QUOTED_ACC case_identifier = quoted_case_identifier | unquoted_case_identifier case_expr = ( Optional(case_identifier + DOT) + Optional(case_identifier + DOT) + case_identifier ) # expression expr = Forward().set_name("expression") integer = Regex(r"[+-]?\d+") numeric_literal = Regex(r"[+-]?\d*\.?\d+([eE][+-]?\d+)?") string_literal = QUOTED_APOS | QUOTED_QUOT | QUOTED_ACC regex_literal = "r" + string_literal blob_literal = Regex(r"[xX]'[0-9A-Fa-f]+'") date_or_time_literal = (DATE | TIME | DATETIME | TIMESTAMP) + string_literal literal_value = ( numeric_literal | string_literal | regex_literal | blob_literal | date_or_time_literal | NULL | CURRENT_TIME + Optional(LPAR + Optional(string_literal) + RPAR) | CURRENT_DATE + Optional(LPAR + Optional(string_literal) + RPAR) | CURRENT_TIMESTAMP + Optional(LPAR + Optional(string_literal) + RPAR) ) bind_parameter = Word("?", nums) | Combine(one_of(": @ $") + parameter_name) type_name = one_of( """TEXT REAL INTEGER BLOB NULL TIMESTAMP STRING DATE INT64 NUMERIC FLOAT64 BOOL BYTES DATETIME GEOGRAPHY TIME ARRAY STRUCT""", caseless=True, ) date_part = one_of( """DAY DAY_HOUR DAY_MICROSECOND DAY_MINUTE DAY_SECOND HOUR HOUR_MICROSECOND HOUR_MINUTE HOUR_SECOND MICROSECOND MINUTE MINUTE_MICROSECOND MINUTE_SECOND MONTH QUARTER SECOND SECOND_MICROSECOND WEEK YEAR YEAR_MONTH""", caseless=True, as_keyword=True, ) datetime_operators = ( DATE_ADD | DATE_SUB | ADDDATE | SUBDATE | TIMESTAMP_ADD | TIMESTAMP_SUB ) grouping_term = expr.copy() ordering_term = Group( expr("order_key") + Optional(COLLATE + collation_name("collate")) + Optional(ASC | DESC)("direction") )("ordering_term") function_arg = expr.copy()("function_arg") function_args = Optional( "*" | Optional(DISTINCT) + DelimitedList(function_arg) + Optional((RESPECT | IGNORE) + NULLS) )("function_args") function_call = ( (function_name | keyword)("function_name") + LPAR + Group(function_args)("function_args_group") + RPAR ) navigation_function_name = ( FIRST_VALUE | LAST_VALUE | NTH_VALUE | LEAD | LAG | PERCENTILE_CONT | PRECENTILE_DISC ) aggregate_function_name = ( ANY_VALUE | ARRAY_AGG | ARRAY_CONCAT_AGG | AVG | BIT_AND | BIT_OR | BIT_XOR | COUNT | COUNTIF | LOGICAL_AND | LOGICAL_OR | MAX | MIN | STRING_AGG | SUM ) statistical_aggregate_function_name = ( CORR | COVAR_POP | COVAR_SAMP | STDDEV_POP | STDDEV_SAMP | STDDEV | VAR_POP | VAR_SAMP | VARIANCE ) numbering_function_name = ( RANK | DENSE_RANK | PERCENT_RANK | CUME_DIST | NTILE | ROW_NUMBER ) analytic_function_name = ( navigation_function_name | aggregate_function_name | statistical_aggregate_function_name | numbering_function_name )("analytic_function_name") partition_expression_list = DelimitedList(grouping_term)( "partition_expression_list" ) window_frame_boundary_start = ( UNBOUNDED + PRECEDING | numeric_literal + (PRECEDING | FOLLOWING) | CURRENT + ROW ) window_frame_boundary_end = ( UNBOUNDED + FOLLOWING | numeric_literal + (PRECEDING | FOLLOWING) | CURRENT + ROW ) window_frame_clause = (ROWS | RANGE) + ( ((UNBOUNDED + PRECEDING) | (numeric_literal + PRECEDING) | (CURRENT + ROW)) | (BETWEEN + window_frame_boundary_start + AND + window_frame_boundary_end) ) window_name = identifier.copy()("window_name") window_specification = ( Optional(window_name) + Optional(PARTITION + BY + partition_expression_list) + Optional(ORDER + BY + DelimitedList(ordering_term)) + Optional(window_frame_clause)("window_specification") ) analytic_function = ( analytic_function_name + LPAR + function_args + RPAR + OVER + (window_name | LPAR + Optional(window_specification) + RPAR) )("analytic_function") string_agg_term = ( STRING_AGG + LPAR + Optional(DISTINCT) + expr + Optional(COMMA + string_literal) + Optional( ORDER + BY + expr + Optional(ASC | DESC) + Optional(LIMIT + integer) ) + RPAR )("string_agg") array_literal = ( Optional(ARRAY + Optional(LT + DelimitedList(type_name) + GT)) + LBRACKET + DelimitedList(expr) + RBRACKET ) interval = INTERVAL + expr + date_part array_generator = ( GENERATE_ARRAY + LPAR + numeric_literal + COMMA + numeric_literal + COMMA + numeric_literal + RPAR ) date_array_generator = ( (GENERATE_DATE_ARRAY | GENERATE_TIMESTAMP_ARRAY) + LPAR + expr("start_date") + COMMA + expr("end_date") + Optional(COMMA + interval) + RPAR ) explicit_struct = ( STRUCT + Optional(LT + DelimitedList(type_name) + GT) + LPAR + Optional(DelimitedList(expr + Optional(AS + identifier))) + RPAR ) case_when = WHEN + expr.copy()("when") case_then = THEN + expr.copy()("then") case_clauses = Group((case_when + case_then)[...]) case_else = ELSE + expr.copy()("else") case_stmt = ( CASE + Optional(case_expr.copy()) + case_clauses("case_clauses") + Optional(case_else) + END )("case") expr_term = ( (analytic_function)("analytic_function") | (CAST + LPAR + expr + AS + type_name + RPAR)("cast") | (SAFE_CAST + LPAR + expr + AS + type_name + RPAR)("safe_cast") | (Optional(EXISTS) + LPAR + ungrouped_select_stmt + RPAR)("subselect") | (literal_value)("literal") | (bind_parameter)("bind_parameter") | (EXTRACT + LPAR + expr + FROM + expr + RPAR)("extract") | case_stmt | (datetime_operators + LPAR + expr + COMMA + interval + RPAR)( "date_operation" ) | string_agg_term("string_agg_term") | array_literal("array_literal") | array_generator("array_generator") | date_array_generator("date_array_generator") | explicit_struct("explicit_struct") | function_call("function_call") | qualified_column_name("column") ) + Optional(LBRACKET + (OFFSET | ORDINAL) + LPAR + expr + RPAR + RBRACKET)( "offset_ordinal" ) struct_term = LPAR + DelimitedList(expr_term) + RPAR UNARY, BINARY, TERNARY = 1, 2, 3 expr <<= infix_notation( (expr_term | struct_term), [ (one_of("- + ~") | NOT, UNARY, OpAssoc.RIGHT), (ISNULL | NOTNULL | NOT + NULL, UNARY, OpAssoc.LEFT), ("||", BINARY, OpAssoc.LEFT), (one_of("* / %"), BINARY, OpAssoc.LEFT), (one_of("+ -"), BINARY, OpAssoc.LEFT), (one_of("<< >> & |"), BINARY, OpAssoc.LEFT), (one_of("= > < >= <= <> != !< !> =="), BINARY, OpAssoc.LEFT), ( IS + Optional(NOT) | Optional(NOT) + IN | Optional(NOT) + LIKE | GLOB | MATCH | REGEXP | CONTAINS, BINARY, OpAssoc.LEFT, ), ((BETWEEN, AND), TERNARY, OpAssoc.LEFT), ( Optional(NOT) + IN + LPAR + Group(ungrouped_select_stmt | DelimitedList(expr)) + RPAR, UNARY, OpAssoc.LEFT, ), (AND, BINARY, OpAssoc.LEFT), (OR, BINARY, OpAssoc.LEFT), ], ) quoted_expr = ( expr | QUOT + expr + QUOT | APOS + expr + APOS | ACC + expr + ACC )("quoted_expr") compound_operator = ( UNION + Optional(ALL | DISTINCT) | INTERSECT + DISTINCT | EXCEPT + DISTINCT | INTERSECT | EXCEPT )("compound_operator") join_constraint = Group( Optional( ON + expr | USING + LPAR + Group(DelimitedList(qualified_column_name)) + RPAR ) )("join_constraint") join_op = ( COMMA | Group( Optional(NATURAL) + Optional( INNER | CROSS | LEFT + OUTER | LEFT | RIGHT + OUTER | RIGHT | FULL + OUTER | OUTER | FULL ) + JOIN ) )("join_op") join_source = Forward() # We support three kinds of table identifiers. # # First, dot delimited info like project.dataset.table, where # each component follows the rules described in the BigQuery # docs, namely: # Contain letters (upper or lower case), numbers, and underscores # # Second, a dot delimited quoted string. Since it's quoted, we'll be # liberal w.r.t. what characters we allow. E.g.: # `project.dataset.name-with-dashes` # # Third, a series of quoted strings, delimited by dots, e.g.: # `project`.`dataset`.`name-with-dashes` # # We also support combinations, like: # project.dataset.`name-with-dashes` # `project`.`dataset.name-with-dashes` def record_table_identifier(t): identifier_list = t.as_list() padded_list = [None] * (3 - len(identifier_list)) + identifier_list cls._table_identifiers.add(tuple(padded_list)) standard_table_part = ~keyword + Word(alphanums + "_") quoted_project_part = QUOTED_QUOT | QUOTED_APOS | QUOTED_ACC quoted_table_part = ( QUOT + CharsNotIn('".') + QUOT | APOS + CharsNotIn("'.") + APOS | ACC + CharsNotIn("`.") + ACC ) quoted_table_parts_identifier = ( Optional( (quoted_project_part("project") | standard_table_part("project")) + DOT ) + Optional( (quoted_table_part("dataset") | standard_table_part("dataset")) + DOT ) + (quoted_table_part("table") | standard_table_part("table")) ).set_parse_action(record_table_identifier) def record_quoted_table_identifier(t): identifier_list = t[0].split(".") *first, second, third = identifier_list first = ".".join(first) or None identifier_list = [first, second, third] padded_list = [None] * (3 - len(identifier_list)) + identifier_list cls._table_identifiers.add(tuple(padded_list)) quotable_table_parts_identifier = ( QUOTED_QUOT | QUOTED_APOS | QUOTED_ACC | QUOTED_BRACKETS ).set_parse_action(record_quoted_table_identifier) table_identifier = ( quoted_table_parts_identifier | quotable_table_parts_identifier ).set_name("table_identifier") single_source = ( ( table_identifier + Optional(Optional(AS) + table_alias("table_alias*")) + Optional(FOR - SYSTEM_TIME + AS + OF + expr) + Optional(INDEXED + BY + index_name("name") | NOT + INDEXED) )("index") | (LPAR + ungrouped_select_stmt + RPAR) | (LPAR + join_source + RPAR) | (UNNEST + LPAR + expr + RPAR) ) + Optional(Optional(AS) + table_alias) join_source <<= single_source + (join_op + single_source + join_constraint)[...] over_partition = (PARTITION + BY + DelimitedList(partition_expression_list))( "over_partition" ) over_order = ORDER + BY + DelimitedList(ordering_term) over_unsigned_value_specification = expr over_window_frame_preceding = ( UNBOUNDED + PRECEDING | over_unsigned_value_specification + PRECEDING | CURRENT + ROW ) over_window_frame_following = ( UNBOUNDED + FOLLOWING | over_unsigned_value_specification + FOLLOWING | CURRENT + ROW ) over_window_frame_bound = ( over_window_frame_preceding | over_window_frame_following ) over_window_frame_between = ( BETWEEN + over_window_frame_bound + AND + over_window_frame_bound ) over_window_frame_extent = ( over_window_frame_preceding | over_window_frame_between ) over_row_or_range = (ROWS | RANGE) + over_window_frame_extent over = ( OVER + LPAR + Optional(over_partition) + Optional(over_order) + Optional(over_row_or_range) + RPAR )("over") if_term = IF - LPAR + expr + COMMA + expr + COMMA + expr + RPAR result_column = Optional(table_name + ".") + "*" + Optional( EXCEPT + LPAR + DelimitedList(column_name) + RPAR ) | Group(quoted_expr + Optional(over)) window_select_clause = ( WINDOW + identifier + AS + LPAR + window_specification + RPAR ) with_stmt = Forward().set_name("with statement") ungrouped_select_no_with = ( SELECT + Optional(DISTINCT | ALL) + Group( DelimitedList( (~FROM + ~IF + result_column | if_term) + Optional(Optional(AS) + column_alias), allow_trailing_delim=True, ) )("columns") + Optional(FROM + join_source("from*")) + Optional(WHERE + expr) + Optional( GROUP + BY + Group(DelimitedList(grouping_term))("group_by_terms") ) + Optional(HAVING + expr("having_expr")) + Optional( ORDER + BY + Group(DelimitedList(ordering_term))("order_by_terms") ) + Optional(DelimitedList(window_select_clause)) ) select_no_with = ungrouped_select_no_with | ( LPAR + ungrouped_select_no_with + RPAR ) select_core = Optional(with_stmt) + select_no_with grouped_select_core = select_core | (LPAR + select_core + RPAR) ungrouped_select_stmt <<= ( grouped_select_core + (compound_operator + grouped_select_core)[...] + Optional( LIMIT + (Group(expr + OFFSET + expr) | Group(expr + COMMA + expr) | expr)( "limit" ) ) )("select") select_stmt = ( ungrouped_select_stmt | (LPAR + ungrouped_select_stmt + RPAR) ) + Optional(SEMI) # define comment format, and ignore them sql_comment = one_of("-- #") + rest_of_line | c_style_comment select_stmt.ignore(sql_comment) def record_with_alias(t): identifier_list = t.as_list() padded_list = [None] * (3 - len(identifier_list)) + identifier_list cls._with_aliases.add(tuple(padded_list)) with_clause = Group( identifier.set_parse_action(record_with_alias) + AS + LPAR + select_stmt + RPAR ) with_stmt <<= WITH + DelimitedList(with_clause) with_stmt.ignore(sql_comment) cls._parser = select_stmt return cls._parser def test(self, sql_stmt, expected_tables, verbose=False): def print_(*args): if verbose: print(*args) print_(textwrap.dedent(sql_stmt.strip())) found_tables = self.get_table_names(sql_stmt) print_(found_tables) expected_tables_set = set(expected_tables) if expected_tables_set != found_tables: raise Exception( f"Test {test_index} failed- expected {expected_tables_set} but got {found_tables}" ) print_() if __name__ == "__main__": # fmt: off TEST_CASES = [ [ """\ SELECT x FROM y.a, b """, [ (None, "y", "a"), (None, None, "b"), ], ], [ """\ SELECT x FROM y.a JOIN b """, [ (None, "y", "a"), (None, None, "b"), ], ], [ """\ select * from xyzzy where z > 100 """, [ (None, None, "xyzzy"), ], ], [ """\ select * from xyzzy where z > 100 order by zz """, [ (None, None, "xyzzy"), ], ], [ """\ select * from xyzzy """, [ (None, None, "xyzzy"), ], ], [ """\ select z.* from xyzzy """, [ (None, None, "xyzzy"), ], ], [ """\ select a, b from test_table where 1=1 and b='yes' """, [ (None, None, "test_table"), ], ], [ """\ select a, b from test_table where 1=1 and b in (select bb from foo) """, [ (None, None, "test_table"), (None, None, "foo"), ], ], [ """\ select z.a, b from test_table where 1=1 and b in (select bb from foo) """, [ (None, None, "test_table"), (None, None, "foo"), ], ], [ """\ select z.a, b from test_table where 1=1 and b in (select bb from foo) order by b,c desc,d """, [ (None, None, "test_table"), (None, None, "foo"), ], ], [ """\ select z.a, b from test_table left join test2_table where 1=1 and b in (select bb from foo) """, [ (None, None, "test_table"), (None, None, "test2_table"), (None, None, "foo"), ], ], [ """\ select a, db.table.b as BBB from db.table where 1=1 and BBB='yes' """, [ (None, "db", "table"), ], ], [ """\ select a, db.table.b as BBB from test_table,db.table where 1=1 and BBB='yes' """, [ (None, None, "test_table"), (None, "db", "table"), ], ], [ """\ select a, db.table.b as BBB from test_table,db.table where 1=1 and BBB='yes' limit 50 """, [ (None, None, "test_table"), (None, "db", "table"), ], ], [ """\ select a, b from test_table where (1=1 or 2=3) and b='yes' group by zx having b=2 order by 1 """, [ (None, None, "test_table"), ], ], [ """\ select a, b # this is a comment from test_table # another comment where (1=1 or 2=3) and b='yes' #yup, a comment group by zx having b=2 order by 1 """, [ (None, None, "test_table"), ], ], [ """\ SELECT COUNT(DISTINCT foo) FROM bar JOIN baz ON bar.baz_id = baz.id """, [ (None, None, "bar"), (None, None, "baz"), ], ], [ """\ SELECT COUNT(DISTINCT foo) FROM bar, baz WHERE bar.baz_id = baz.id """, [ (None, None, "bar"), (None, None, "baz"), ], ], [ """\ WITH one AS (SELECT id FROM foo) SELECT one.id """, [ (None, None, "foo"), ], ], [ """\ WITH one AS (SELECT id FROM foo), two AS (select id FROM bar) SELECT one.id, two.id """, [ (None, None, "foo"), (None, None, "bar"), ], ], [ """\ SELECT x, RANK() OVER (ORDER BY x ASC) AS rank, DENSE_RANK() OVER (ORDER BY x ASC) AS dense_rank, ROW_NUMBER() OVER (PARTITION BY x ORDER BY y) AS row_num FROM a """, [ (None, None, "a"), ], ], [ """\ SELECT x, COUNT(*) OVER ( ORDER BY x RANGE BETWEEN 2 PRECEDING AND 2 FOLLOWING ) AS count_x FROM T """, [ (None, None, "T"), ], ], [ """\ SELECT firstname, department, startdate, RANK() OVER ( PARTITION BY department ORDER BY startdate ) AS rank FROM Employees """, [ (None, None, "Employees"), ], ], # A fragment from https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions [ """\ SELECT 'Sophia Liu' as name, TIMESTAMP '2016-10-18 2:51:45' as finish_time, 'F30-34' as division UNION ALL SELECT 'Lisa Stelzner', TIMESTAMP '2016-10-18 2:54:11', 'F35-39' UNION ALL SELECT 'Nikki Leith', TIMESTAMP '2016-10-18 2:59:01', 'F30-34' UNION ALL SELECT 'Lauren Matthews', TIMESTAMP '2016-10-18 3:01:17', 'F35-39' UNION ALL SELECT 'Desiree Berry', TIMESTAMP '2016-10-18 3:05:42', 'F35-39' UNION ALL SELECT 'Suzy Slane', TIMESTAMP '2016-10-18 3:06:24', 'F35-39' UNION ALL SELECT 'Jen Edwards', TIMESTAMP '2016-10-18 3:06:36', 'F30-34' UNION ALL SELECT 'Meghan Lederer', TIMESTAMP '2016-10-18 3:07:41', 'F30-34' UNION ALL SELECT 'Carly Forte', TIMESTAMP '2016-10-18 3:08:58', 'F25-29' UNION ALL SELECT 'Lauren Reasoner', TIMESTAMP '2016-10-18 3:10:14', 'F30-34' """, [], ], # From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions [ """\ WITH finishers AS (SELECT 'Sophia Liu' as name, TIMESTAMP '2016-10-18 2:51:45' as finish_time, 'F30-34' as division UNION ALL SELECT 'Lisa Stelzner', TIMESTAMP '2016-10-18 2:54:11', 'F35-39' UNION ALL SELECT 'Nikki Leith', TIMESTAMP '2016-10-18 2:59:01', 'F30-34' UNION ALL SELECT 'Lauren Matthews', TIMESTAMP '2016-10-18 3:01:17', 'F35-39' UNION ALL SELECT 'Desiree Berry', TIMESTAMP '2016-10-18 3:05:42', 'F35-39' UNION ALL SELECT 'Suzy Slane', TIMESTAMP '2016-10-18 3:06:24', 'F35-39' UNION ALL SELECT 'Jen Edwards', TIMESTAMP '2016-10-18 3:06:36', 'F30-34' UNION ALL SELECT 'Meghan Lederer', TIMESTAMP '2016-10-18 3:07:41', 'F30-34' UNION ALL SELECT 'Carly Forte', TIMESTAMP '2016-10-18 3:08:58', 'F25-29' UNION ALL SELECT 'Lauren Reasoner', TIMESTAMP '2016-10-18 3:10:14', 'F30-34') SELECT name, FORMAT_TIMESTAMP('%X', finish_time) AS finish_time, division, FORMAT_TIMESTAMP('%X', fastest_time) AS fastest_time, TIMESTAMP_DIFF(finish_time, fastest_time, SECOND) AS delta_in_seconds FROM ( SELECT name, finish_time, division, FIRST_VALUE(finish_time) OVER (PARTITION BY division ORDER BY finish_time ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS fastest_time FROM finishers) """, [], ], # From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions [ """\ WITH finishers AS (SELECT 'Sophia Liu' as name, TIMESTAMP '2016-10-18 2:51:45' as finish_time, 'F30-34' as division UNION ALL SELECT 'Lisa Stelzner', TIMESTAMP '2016-10-18 2:54:11', 'F35-39' UNION ALL SELECT 'Nikki Leith', TIMESTAMP '2016-10-18 2:59:01', 'F30-34' UNION ALL SELECT 'Lauren Matthews', TIMESTAMP '2016-10-18 3:01:17', 'F35-39' UNION ALL SELECT 'Desiree Berry', TIMESTAMP '2016-10-18 3:05:42', 'F35-39' UNION ALL SELECT 'Suzy Slane', TIMESTAMP '2016-10-18 3:06:24', 'F35-39' UNION ALL SELECT 'Jen Edwards', TIMESTAMP '2016-10-18 3:06:36', 'F30-34' UNION ALL SELECT 'Meghan Lederer', TIMESTAMP '2016-10-18 3:07:41', 'F30-34' UNION ALL SELECT 'Carly Forte', TIMESTAMP '2016-10-18 3:08:58', 'F25-29' UNION ALL SELECT 'Lauren Reasoner', TIMESTAMP '2016-10-18 3:10:14', 'F30-34') SELECT name, FORMAT_TIMESTAMP('%X', finish_time) AS finish_time, division, FORMAT_TIMESTAMP('%X', slowest_time) AS slowest_time, TIMESTAMP_DIFF(slowest_time, finish_time, SECOND) AS delta_in_seconds FROM ( SELECT name, finish_time, division, LAST_VALUE(finish_time) OVER (PARTITION BY division ORDER BY finish_time ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS slowest_time FROM finishers) """, [], ], # From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions [ """\ WITH finishers AS (SELECT 'Sophia Liu' as name, TIMESTAMP '2016-10-18 2:51:45' as finish_time, 'F30-34' as division UNION ALL SELECT 'Lisa Stelzner', TIMESTAMP '2016-10-18 2:54:11', 'F35-39' UNION ALL SELECT 'Nikki Leith', TIMESTAMP '2016-10-18 2:59:01', 'F30-34' UNION ALL SELECT 'Lauren Matthews', TIMESTAMP '2016-10-18 3:01:17', 'F35-39' UNION ALL SELECT 'Desiree Berry', TIMESTAMP '2016-10-18 3:05:42', 'F35-39' UNION ALL SELECT 'Suzy Slane', TIMESTAMP '2016-10-18 3:06:24', 'F35-39' UNION ALL SELECT 'Jen Edwards', TIMESTAMP '2016-10-18 3:06:36', 'F30-34' UNION ALL SELECT 'Meghan Lederer', TIMESTAMP '2016-10-18 3:07:41', 'F30-34' UNION ALL SELECT 'Carly Forte', TIMESTAMP '2016-10-18 3:08:58', 'F25-29' UNION ALL SELECT 'Lauren Reasoner', TIMESTAMP '2016-10-18 3:10:14', 'F30-34') SELECT name, FORMAT_TIMESTAMP('%X', finish_time) AS finish_time, division, FORMAT_TIMESTAMP('%X', fastest_time) AS fastest_time, FORMAT_TIMESTAMP('%X', second_fastest) AS second_fastest FROM ( SELECT name, finish_time, division,finishers, FIRST_VALUE(finish_time) OVER w1 AS fastest_time, NTH_VALUE(finish_time, 2) OVER w1 as second_fastest FROM finishers WINDOW w1 AS ( PARTITION BY division ORDER BY finish_time ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)) """, [], ], # From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions [ """\ WITH finishers AS (SELECT 'Sophia Liu' as name, TIMESTAMP '2016-10-18 2:51:45' as finish_time, 'F30-34' as division UNION ALL SELECT 'Lisa Stelzner', TIMESTAMP '2016-10-18 2:54:11', 'F35-39' UNION ALL SELECT 'Nikki Leith', TIMESTAMP '2016-10-18 2:59:01', 'F30-34' UNION ALL SELECT 'Lauren Matthews', TIMESTAMP '2016-10-18 3:01:17', 'F35-39' UNION ALL SELECT 'Desiree Berry', TIMESTAMP '2016-10-18 3:05:42', 'F35-39' UNION ALL SELECT 'Suzy Slane', TIMESTAMP '2016-10-18 3:06:24', 'F35-39' UNION ALL SELECT 'Jen Edwards', TIMESTAMP '2016-10-18 3:06:36', 'F30-34' UNION ALL SELECT 'Meghan Lederer', TIMESTAMP '2016-10-18 3:07:41', 'F30-34' UNION ALL SELECT 'Carly Forte', TIMESTAMP '2016-10-18 3:08:58', 'F25-29' UNION ALL SELECT 'Lauren Reasoner', TIMESTAMP '2016-10-18 3:10:14', 'F30-34') SELECT name, finish_time, division, LEAD(name) OVER (PARTITION BY division ORDER BY finish_time ASC) AS followed_by FROM finishers """, [], ], # From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions [ """\ WITH finishers AS (SELECT 'Sophia Liu' as name, TIMESTAMP '2016-10-18 2:51:45' as finish_time, 'F30-34' as division UNION ALL SELECT 'Lisa Stelzner', TIMESTAMP '2016-10-18 2:54:11', 'F35-39' UNION ALL SELECT 'Nikki Leith', TIMESTAMP '2016-10-18 2:59:01', 'F30-34' UNION ALL SELECT 'Lauren Matthews', TIMESTAMP '2016-10-18 3:01:17', 'F35-39' UNION ALL SELECT 'Desiree Berry', TIMESTAMP '2016-10-18 3:05:42', 'F35-39' UNION ALL SELECT 'Suzy Slane', TIMESTAMP '2016-10-18 3:06:24', 'F35-39' UNION ALL SELECT 'Jen Edwards', TIMESTAMP '2016-10-18 3:06:36', 'F30-34' UNION ALL SELECT 'Meghan Lederer', TIMESTAMP '2016-10-18 3:07:41', 'F30-34' UNION ALL SELECT 'Carly Forte', TIMESTAMP '2016-10-18 3:08:58', 'F25-29' UNION ALL SELECT 'Lauren Reasoner', TIMESTAMP '2016-10-18 3:10:14', 'F30-34') SELECT name, finish_time, division, LEAD(name, 2) OVER (PARTITION BY division ORDER BY finish_time ASC) AS two_runners_back FROM finishers """, [], ], # From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions [ """\ WITH finishers AS (SELECT 'Sophia Liu' as name, TIMESTAMP '2016-10-18 2:51:45' as finish_time, 'F30-34' as division UNION ALL SELECT 'Lisa Stelzner', TIMESTAMP '2016-10-18 2:54:11', 'F35-39' UNION ALL SELECT 'Nikki Leith', TIMESTAMP '2016-10-18 2:59:01', 'F30-34' UNION ALL SELECT 'Lauren Matthews', TIMESTAMP '2016-10-18 3:01:17', 'F35-39' UNION ALL SELECT 'Desiree Berry', TIMESTAMP '2016-10-18 3:05:42', 'F35-39' UNION ALL SELECT 'Suzy Slane', TIMESTAMP '2016-10-18 3:06:24', 'F35-39' UNION ALL SELECT 'Jen Edwards', TIMESTAMP '2016-10-18 3:06:36', 'F30-34' UNION ALL SELECT 'Meghan Lederer', TIMESTAMP '2016-10-18 3:07:41', 'F30-34' UNION ALL SELECT 'Carly Forte', TIMESTAMP '2016-10-18 3:08:58', 'F25-29' UNION ALL SELECT 'Lauren Reasoner', TIMESTAMP '2016-10-18 3:10:14', 'F30-34') SELECT name, finish_time, division, LAG(name) OVER (PARTITION BY division ORDER BY finish_time ASC) AS preceding_runner FROM finishers """, [], ], # From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions [ """\ SELECT PERCENTILE_CONT(x, 0) OVER() AS min, PERCENTILE_CONT(x, 0.01) OVER() AS percentile1, PERCENTILE_CONT(x, 0.5) OVER() AS median, PERCENTILE_CONT(x, 0.9) OVER() AS percentile90, PERCENTILE_CONT(x, 1) OVER() AS max FROM UNNEST([0, 3, NULL, 1, 2]) AS x LIMIT 1 """, [], ], # From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions [ """\ SELECT x, PERCENTILE_DISC(x, 0) OVER() AS min, PERCENTILE_DISC(x, 0.5) OVER() AS median, PERCENTILE_DISC(x, 1) OVER() AS max FROM UNNEST(['c', NULL, 'b', 'a']) AS x """, [], ], # From https://cloud.google.com/bigquery/docs/reference/standard-sql/timestamp_functions [ """\ SELECT TIMESTAMP "2008-12-25 15:30:00 UTC" as original, TIMESTAMP_ADD(TIMESTAMP "2008-12-25 15:30:00 UTC", INTERVAL 10 MINUTE) AS later """, [], ], # Previously hosted on https://cloud.google.com/bigquery/docs/reference/standard-sql/timestamp_functions, but # appears to no longer be there [ """\ WITH date_hour_slots AS ( SELECT [ STRUCT( " 00:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01', current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 01:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 02:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01', current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 03:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01', current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 04:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01', current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 05:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01', current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 06:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01', current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 07:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01', current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 08:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01', current_date(), INTERVAL 1 DAY ) as dt_range), STRUCT( " 09:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01', current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 10:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 11:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 12:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 13:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 14:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 15:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 16:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 17:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 18:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 19:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 20:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 21:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 22:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range), STRUCT( " 23:00:00 UTC" as hrs, GENERATE_DATE_ARRAY('2016-01-01',current_date(), INTERVAL 1 DAY) as dt_range) ] AS full_timestamps) SELECT dt AS dates, hrs, CAST(CONCAT( CAST(dt as STRING), CAST(hrs as STRING)) as TIMESTAMP) as timestamp_value FROM `date_hour_slots`, date_hour_slots.full_timestamps LEFT JOIN full_timestamps.dt_range as dt """, [ (None, "date_hour_slots", "full_timestamps"), (None, "full_timestamps", "dt_range"), ], ], [ """\ SELECT [foo], ARRAY[foo], ARRAY[foo, bar], STRUCT(1, 3), STRUCT(2, 'foo'), current_date(), GENERATE_ARRAY(5, NULL, 1), GENERATE_DATE_ARRAY('2016-10-05', '2016-10-01', INTERVAL 1 DAY), GENERATE_DATE_ARRAY('2016-10-05', NULL), GENERATE_DATE_ARRAY('2016-01-01', '2016-12-31', INTERVAL 2 MONTH), GENERATE_DATE_ARRAY('2000-02-01',current_date(), INTERVAL 1 DAY), GENERATE_TIMESTAMP_ARRAY('2016-10-05 00:00:00', '2016-10-05 00:00:02', INTERVAL 1 SECOND) FROM bar """, [ (None, None, "bar"), ], ], [ """\ SELECT GENERATE_ARRAY(start, 5) AS example_array FROM UNNEST([3, 4, 5]) AS start """, [], ], [ """\ WITH StartsAndEnds AS ( SELECT DATE '2016-01-01' AS date_start, DATE '2016-01-31' AS date_end UNION ALL SELECT DATE "2016-04-01", DATE "2016-04-30" UNION ALL SELECT DATE "2016-07-01", DATE "2016-07-31" UNION ALL SELECT DATE "2016-10-01", DATE "2016-10-31" ) SELECT GENERATE_DATE_ARRAY(date_start, date_end, INTERVAL 1 WEEK) AS date_range FROM StartsAndEnds """, [], ], [ """\ SELECT GENERATE_TIMESTAMP_ARRAY(start_timestamp, end_timestamp, INTERVAL 1 HOUR) AS timestamp_array FROM (SELECT TIMESTAMP '2016-10-05 00:00:00' AS start_timestamp, TIMESTAMP '2016-10-05 02:00:00' AS end_timestamp UNION ALL SELECT TIMESTAMP '2016-10-05 12:00:00' AS start_timestamp, TIMESTAMP '2016-10-05 14:00:00' AS end_timestamp UNION ALL SELECT TIMESTAMP '2016-10-05 23:59:00' AS start_timestamp, TIMESTAMP '2016-10-06 01:59:00' AS end_timestamp) """, [], ], [ """\ SELECT DATE_SUB(current_date("-08:00"), INTERVAL 2 DAY) """, [], ], [ """\ SELECT case when (a) then b else c end FROM d """, [ (None, None, "d"), ], ], [ """\ SELECT e, case when (f) then g else h end FROM i """, [ (None, None, "i"), ], ], [ """\ SELECT case when j then k else l end FROM m """, [ (None, None, "m",), ], ], [ """\ SELECT n, case when o then p else q end FROM r """, [ (None, None, "r"), ], ], [ """\ SELECT case s when (t) then u else v end FROM w """, [ (None, None, "w"), ], ], [ """\ SELECT x, case y when (z) then aa else ab end FROM ac """, [ (None, None, "ac"), ], ], [ """\ SELECT case ad when ae then af else ag end FROM ah """, [ (None, None, "ah"), ], ], [ """\ SELECT ai, case aj when ak then al else am end FROM an """, [ (None, None, "an"), ], ], [ """\ WITH ONE AS (SELECT x FROM y), TWO AS (select a FROM b) SELECT y FROM onE JOIN TWo """, [ (None, None, "y"), (None, None, "b"), ], ], [ """\ SELECT a, (SELECT b FROM oNE) FROM OnE """, [ (None, None, "oNE"), (None, None, "OnE"), ], ], [ """\ SELECT * FROM `a.b.c` """, [ ("a", "b", "c"), ], ], [ """\ SELECT * FROM `b.c` """, [ (None, "b", "c"), ], ], [ """\ SELECT * FROM `c` """, [ (None, None, "c"), ], ], [ """\ SELECT * FROM a.b.c """, [ ("a", "b", "c"), ], ], [ """\ SELECT * FROM "a"."b"."c" """, [ ("a", "b", "c"), ], ], [ """\ SELECT * FROM 'a'.'b'.'c' """, [ ("a", "b", "c"), ], ], [ """\ SELECT * FROM `a`.`b`.`c` """, [ ("a", "b", "c"), ], ], [ """\ SELECT * FROM "a.b.c" """, [ ("a", "b", "c"), ], ], [ """\ SELECT * FROM 'a.b.c' """, [ ("a", "b", "c"), ], ], [ """\ SELECT * FROM `a.b.c` """, [ ("a", "b", "c"), ], ], [ """\ SELECT t2.a FROM t2 FOR SYSTEM_TIME AS OF t1.timestamp_column """, [ (None, None, "t2"), ], ], [ """\ SELECT * FROM t1 WHERE t1.a IN (SELECT t2.a FROM t2 FOR SYSTEM_TIME AS OF t1.timestamp_column) """, [ (None, None, "t1"), (None, None, "t2"), ], ], [ """\ WITH a AS (SELECT b FROM c) SELECT d FROM A JOIN e ON f = g JOIN E ON h = i """, [ (None, None, "c"), (None, None, "e"), (None, None, "E"), ], ], [ """\ with a as ( ( select b from ( select c from d ) Union all ( select e from f ) ) ) select g from h """, [ (None, None, "d"), (None, None, "f"), (None, None, "h"), ], ], [ """\ select a AS ESCAPE, b AS CURRENT_TIME, c AS CURRENT_DATE, d AS CURRENT_TIMESTAMP, e AS DATE_ADD FROM x """, [ (None, None, "x"), ], ], [ """\ WITH x AS ( SELECT a FROM b WINDOW w as (PARTITION BY a) ) SELECT y FROM z """, [ (None, None, "b"), (None, None, "z") ], ], [ """\ SELECT DISTINCT FIRST_VALUE(x IGNORE NULLS) OVER (PARTITION BY y) FROM z """, [ (None, None, "z") ], ], [ """\ SELECT a . b . c FROM d """, [ (None, None, "d") ], ], [ """\ WITH a AS ( SELECT b FROM c UNION ALL ( WITH d AS ( SELECT e FROM f ) SELECT g FROM d ) ) SELECT h FROM a """, [ (None, None, "c"), (None, None, "f") ], ], [ """\ WITH a AS ( SELECT b FROM c UNION ALL ( WITH d AS ( SELECT e FROM f ) SELECT g FROM d ) ) (SELECT h FROM a) """, [ (None, None, "c"), (None, None, "f") ], ], [ """\ SELECT * FROM a.b.`c` """, [ ("a", "b", "c"), ], ], [ """\ SELECT * FROM 'a'.b.`c` """, [ ("a", "b", "c"), ], ], # from https://cloud.google.com/bigquery/docs/reference/legacy-sql [ """\ SELECT word, word_count, RANK() OVER (PARTITION BY corpus ORDER BY word_count DESC) rank, FROM [bigquery-public-data:samples.shakespeare] WHERE corpus='othello' and length(word) > 10 LIMIT 5 """, [ (None, 'bigquery-public-data:samples', 'shakespeare'), ], ], [ """\ SELECT word, word_count, RATIO_TO_REPORT(word_count) OVER (PARTITION BY corpus ORDER BY word_count DESC) r_to_r, FROM [bigquery-public-data:samples.shakespeare] WHERE corpus='othello' and length(word) > 10 LIMIT 5 """, [ (None, 'bigquery-public-data:samples', 'shakespeare'), ], ], [ """\ SELECT word, word_count, ROW_NUMBER() OVER (PARTITION BY corpus ORDER BY word_count DESC) row_num, FROM [bigquery-public-data:samples.shakespeare] WHERE corpus='othello' and length(word) > 10 LIMIT 5 """, [ (None, 'bigquery-public-data:samples', 'shakespeare'), ], ], [ """\ SELECT TO_BASE64(SHA1(title)) FROM [bigquery-public-data:samples.wikipedia] LIMIT 100; """, [ (None, 'bigquery-public-data:samples', 'wikipedia'), ], ], [ """\ SELECT CASE WHEN state IN ('WA', 'OR', 'CA', 'AK', 'HI', 'ID', 'MT', 'WY', 'NV', 'UT', 'CO', 'AZ', 'NM') THEN 'West' WHEN state IN ('OK', 'TX', 'AR', 'LA', 'TN', 'MS', 'AL', 'KY', 'GA', 'FL', 'SC', 'NC', 'VA', 'WV', 'MD', 'DC', 'DE') THEN 'South' WHEN state IN ('ND', 'SD', 'NE', 'KS', 'MN', 'IA', 'MO', 'WI', 'IL', 'IN', 'MI', 'OH') THEN 'Midwest' WHEN state IN ('NY', 'PA', 'NJ', 'CT', 'RI', 'MA', 'VT', 'NH', 'ME') THEN 'Northeast' ELSE 'None' END as region, average_mother_age, average_father_age, state, year FROM (SELECT year, state, SUM(mother_age)/COUNT(mother_age) as average_mother_age, SUM(father_age)/COUNT(father_age) as average_father_age FROM [bigquery-public-data:samples.natality] WHERE father_age < 99 GROUP BY year, state) ORDER BY year LIMIT 5; """, [ (None, 'bigquery-public-data:samples', 'natality'), ], ], [ r""" SELECT /* Replace white spaces in the title with underscores. */ REGEXP_REPLACE(title, r'\s+', '_') AS regexp_title, revisions FROM (SELECT title, COUNT(revision_id) as revisions FROM [bigquery-public-data:samples.wikipedia] WHERE wp_namespace=0 /* Match titles that start with 'G', end with * 'e', and contain at least two 'o's. */ AND REGEXP_MATCH(title, r'^G.*o.*o.*e$') GROUP BY title ORDER BY revisions DESC LIMIT 100);""", [ (None, 'bigquery-public-data:samples', 'wikipedia'), ], ], [ """\ SELECT page_title, /* Populate these columns as True or False, */ /* depending on the condition */ IF (page_title CONTAINS 'search', INTEGER(total), 0) AS search, IF (page_title CONTAINS 'Earth' OR page_title CONTAINS 'Maps', INTEGER(total), 0) AS geo, FROM /* Subselect to return top revised Wikipedia articles */ /* containing 'Google', followed by additional text. */ (SELECT TOP (title, 5) as page_title, COUNT (*) as total FROM [bigquery-public-data:samples.wikipedia] WHERE REGEXP_MATCH (title, r'^Google.+') AND wp_namespace = 0 ); """, [ (None, 'bigquery-public-data:samples', 'wikipedia'), ] ], [ """\ SELECT title, HASH(title) AS hash_value, IF(ABS(HASH(title)) % 2 == 1, 'True', 'False') AS included_in_sample FROM [bigquery-public-data:samples.wikipedia] WHERE wp_namespace = 0 LIMIT 5; """, [ (None, 'bigquery-public-data:samples', 'wikipedia'), ] ], [ """\ with t as (select CASE when EXTRACT(dayofweek FROM CURRENT_DATETIME()) == 1 then "S" end) select * from t """, [], ], ] # fmt: on parser = BigQueryViewParser() for test_index, test_case in enumerate(TEST_CASES): sql, expected = test_case parser.test(sql_stmt=sql, expected_tables=expected, verbose=True) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/booleansearchparser.py0000644000000000000000000003641215134002420016670 0ustar00""" Boolean Search query parser (Based on searchparser: https://github.com/pyparsing/pyparsing/blob/master/examples/searchparser.py) version 2018-07-22 This search query parser uses the excellent Pyparsing module (http://pyparsing.sourceforge.net/) to parse search queries by users. It handles: * 'and', 'or' and implicit 'and' operators; * parentheses; * quoted strings; * wildcards at the end of a search term (help*); * wildcards at the beginning of a search term (*lp); * non-western languages Requirements: * Python * Pyparsing SAMPLE USAGE: from booleansearchparser import BooleanSearchParser from __future__ import print_function bsp = BooleanSearchParser() text = u"wildcards at the beginning of a search term " exprs= [ u"*cards and term", #True u"wild* and term", #True u"not terms", #True u"terms or begin", #False ] for expr in exprs: print (bsp.match(text,expr)) #non-western samples text = u"안녕하세요, 당신은 어떠세요?" exprs= [ u"*신은 and 어떠세요", #True u"not 당신은", #False u"당신 or 당", #False ] for expr in exprs: print (bsp.match(text,expr)) ------------------------------------------------------------------------------- Copyright (c) 2006, Estrate, the Netherlands All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Estrate nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. CONTRIBUTORS: - Steven Mooij - Rudolph Froger - Paul McGuire - Guiem Bosch - Francesc Garcia TODO: - add more docs - ask someone to check my English texts - add more kinds of wildcards ('*' at the beginning and '*' inside a word)? """ from pyparsing import ( Word, alphanums, CaselessKeyword, Group, Forward, Suppress, OneOrMore, one_of, ParserElement, ) import re ParserElement.enable_packrat() # Updated on 02 Dec 2021 according to ftp://ftp.unicode.org/Public/UNIDATA/Blocks.txt # (includes characters not found in the BasicMultilingualPlane) alphabet_ranges = [ # CYRILIC: https://en.wikipedia.org/wiki/Cyrillic_(Unicode_block) [int("0400", 16), int("04FF", 16)], # ARABIC: https://en.wikipedia.org/wiki/Arabic_(Unicode_block) (Arabic (0600–06FF)+ Syriac (0700–074F)+ Arabic Supplement (0750–077F)) [int("0600", 16), int("07FF", 16)], # THAI: https://en.wikipedia.org/wiki/Thai_(Unicode_block) [int("0E00", 16), int("0E7F", 16)], # JAPANESE : https://en.wikipedia.org/wiki/Japanese_writing_system (Hiragana (3040–309F) + Katakana (30A0–30FF)) [int("3040", 16), int("30FF", 16)], # Enclosed CJK Letters and Months [int("3200", 16), int("32FF", 16)], # CHINESE: https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_(Unicode_block) [int("4E00", 16), int("9FFF", 16)], # KOREAN : https://en.wikipedia.org/wiki/Hangul [int("1100", 16), int("11FF", 16)], [int("3130", 16), int("318F", 16)], [int("A960", 16), int("A97F", 16)], [int("AC00", 16), int("D7AF", 16)], [int("D7B0", 16), int("D7FF", 16)], # Halfwidth and Fullwidth Forms [int("FF00", 16), int("FFEF", 16)], ] class BooleanSearchParser: def __init__(self, only_parse=False): self._methods = { "and": self.evaluateAnd, "or": self.evaluateOr, "not": self.evaluateNot, "parenthesis": self.evaluateParenthesis, "quotes": self.evaluateQuotes, "word": self.evaluateWord, "wordwildcardprefix": self.evaluateWordWildcardPrefix, "wordwildcardsufix": self.evaluateWordWildcardSufix, } self._parser = self.parser() self.text = "" self.words = [] def parser(self): """ This function returns a parser. The grammar should be like most full text search engines (Google, Tsearch, Lucene). Grammar: - a query consists of alphanumeric words, with an optional '*' wildcard at the end or the beginning of a word - a sequence of words between quotes is a literal string - words can be used together by using operators ('and' or 'or') - words with operators can be grouped with parenthesis - a word or group of words can be preceded by a 'not' operator - the 'and' operator precedes an 'or' operator - if an operator is missing, use an 'and' operator """ operatorOr = Forward() alphabet = alphanums # support for non-western alphabets for lo, hi in alphabet_ranges: alphabet += "".join(chr(c) for c in range(lo, hi + 1) if not chr(c).isspace()) operatorWord = Group(Word(alphabet + "*")).set_results_name("word*") operatorQuotesContent = Forward() operatorQuotesContent << ((operatorWord + operatorQuotesContent) | operatorWord) operatorQuotes = ( Group(Suppress('"') + operatorQuotesContent + Suppress('"')).set_results_name( "quotes" ) | operatorWord ) operatorParenthesis = ( Group(Suppress("(") + operatorOr + Suppress(")")).set_results_name( "parenthesis" ) | operatorQuotes ) operatorNot = Forward() operatorNot << ( Group(Suppress(CaselessKeyword("not")) + operatorNot).set_results_name( "not" ) | operatorParenthesis ) operatorAnd = Forward() operatorAnd << ( Group( operatorNot + Suppress(CaselessKeyword("and")) + operatorAnd ).set_results_name("and") | Group( operatorNot + OneOrMore(~one_of("and or") + operatorAnd) ).set_results_name("and") | operatorNot ) operatorOr << ( Group( operatorAnd + Suppress(CaselessKeyword("or")) + operatorOr ).set_results_name("or") | operatorAnd ) return operatorOr.parse_string def evaluateAnd(self, argument): return all(self.evaluate(arg) for arg in argument) def evaluateOr(self, argument): return any(self.evaluate(arg) for arg in argument) def evaluateNot(self, argument): return self.GetNot(self.evaluate(argument[0])) def evaluateParenthesis(self, argument): return self.evaluate(argument[0]) def evaluateQuotes(self, argument): """Evaluate quoted strings First is does an 'and' on the individual search terms, then it asks the function GetQuoted to only return the subset of ID's that contain the literal string. """ # r = set() r = False search_terms = [] for item in argument: search_terms.append(item[0]) r = r and self.evaluate(item) return self.GetQuotes(" ".join(search_terms), r) def evaluateWord(self, argument): wildcard_count = argument[0].count("*") if wildcard_count > 0: if wildcard_count == 1 and argument[0].startswith("*"): return self.GetWordWildcard(argument[0][1:], method="endswith") if wildcard_count == 1 and argument[0].endswith("*"): return self.GetWordWildcard(argument[0][:-1], method="startswith") else: _regex = argument[0].replace("*", ".+") matched = False for w in self.words: matched = bool(re.search(_regex, w)) if matched: break return matched return self.GetWord(argument[0]) def evaluateWordWildcardPrefix(self, argument): return self.GetWordWildcard(argument[0], method="endswith") def evaluateWordWildcardSufix(self, argument): return self.GetWordWildcard(argument[0], method="startswith") def evaluate(self, argument): return self._methods[argument.get_name()](argument) def Parse(self, query): return self.evaluate(self._parser(query)[0]) def GetWord(self, word): return word in self.words def GetWordWildcard(self, word, method="startswith"): matched = False for w in self.words: matched = getattr(w, method)(word) if matched: break return matched """ def GetKeyword(self, name, value): return set() def GetBetween(self, min, max): print (min,max) return set() """ def GetQuotes(self, search_string, tmp_result): return search_string in self.text def GetNot(self, not_set): return not not_set def _split_words(self, text): words = [] """ >>> import string >>> string.punctuation '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' """ # it will keep @, # and # usernames and hashtags can contain dots, so a double check is done r = re.compile(r"[\s{}]+".format(re.escape("!\"$%&'()*+,-/:;<=>?[\\]^`{|}~"))) _words = r.split(text) for _w in _words: if "." in _w and not _w.startswith("#") and not _w.startswith("@"): for __w in _w.split("."): words.append(__w) continue words.append(_w) return words def match(self, text, expr): self.text = text self.words = self._split_words(text) return self.Parse(expr) class ParserTest(BooleanSearchParser): """Tests the parser with some search queries tests contains a dictionary with tests and expected results. """ def Test(self): # fmt: off exprs = { "0": "help", "1": "help or hulp", "2": "help and hulp", "3": "help hulp", "4": "help and hulp or hilp", "5": "help or hulp and hilp", "6": "help or hulp or hilp or halp", "7": "(help or hulp) and (hilp or halp)", "8": "help and (hilp or halp)", "9": "(help and (hilp or halp)) or hulp", "10": "not help", "11": "not hulp and halp", "12": "not (help and halp)", "13": '"help me please"', "14": '"help me please" or hulp', "15": '"help me please" or (hulp and halp)', "16": "help*", "17": "help or hulp*", "18": "help* and hulp", "19": "help and hulp* or hilp", "20": "help* or hulp or hilp or halp", "21": "(help or hulp*) and (hilp* or halp)", "22": "help* and (hilp* or halp*)", "23": "(help and (hilp* or halp)) or hulp*", "24": "not help* and halp", "25": "not (help* and helpe*)", "26": '"help* me please"', "27": '"help* me* please" or hulp*', "28": '"help me please*" or (hulp and halp)', "29": '"help me please" not (hulp and halp)', "30": '"help me please" hulp', "31": "help and hilp and not holp", "32": "help hilp not holp", "33": "help hilp and not holp", "34": "*lp and halp", "35": "*신은 and 어떠세요", } texts_matcheswith = { "halp thinks he needs help": [ "25", "22", "20", "21", "11", "17", "16", "23", "34", "1", "0", "5", "7", "6", "9", "8", ], "he needs halp": ["24", "25", "20", "11", "10", "12", "34", "6"], "help": ["25", "20", "12", "17", "16", "1", "0", "5", "6"], "help hilp": [ "25", "22", "20", "32", "21", "12", "17", "16", "19", "31", "23", "1", "0", "5", "4", "7", "6", "9", "8", "33", ], "help me please hulp": [ "30", "25", "27", "20", "13", "12", "15", "14", "17", "16", "19", "18", "23", "29", "1", "0", "3", "2", "5", "4", "6", "9", ], "helper": ["20", "10", "12", "16"], "hulp hilp": [ "25", "27", "20", "21", "10", "12", "14", "17", "19", "23", "1", "5", "4", "7", "6", "9", ], "nothing": ["25", "10", "12"], "안녕하세요, 당신은 어떠세요?": ["10", "12", "25", "35"], } # fmt: on all_ok = True for text, matches in texts_matcheswith.items(): _matches = [] for _id, expr in exprs.items(): if self.match(text, expr): _matches.append(_id) test_passed = sorted(matches) == sorted(_matches) if test_passed: print("Passed", repr(text)) else: print("Failed", repr(text), "expected", matches, "matched", _matches) all_ok = all_ok and test_passed # Tests for non western characters, should fail with # pyparsing.exceptions.ParseException under the previous # configuration non_western_exprs = { "0": "*", "1": "ヿ", # Edge character "2": "亀", # Character in CJK block "3": "ヿ or 亀", "4": "ヿ and 亀", "5": "not ヿ" } non_western_texts_matcheswith = { "안녕하세요, 당신은 어떠세요?": ["0", "5"], "ヿ": ["0", "1", "3"], "亀": ["0", "2", "3", "5"], "亀 ヿ": ["0", "1", "2", "3", "4"], } for text, matches in non_western_texts_matcheswith.items(): _matches = [] for _id, expr in non_western_exprs.items(): if self.match(text, expr): _matches.append(_id) test_passed = sorted(matches) == sorted(_matches) if test_passed: print("Passed", repr(text)) else: print("Failed", repr(text), "expected", matches, "matched", _matches) all_ok = all_ok and test_passed return all_ok def main(): if ParserTest().Test(): print("All tests OK") else: print("One or more tests FAILED") raise Exception("One or more tests FAILED") if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/btpyparse.py0000644000000000000000000001025115134002420014650 0ustar00""" Pyparsing parser for BibTeX files A standalone parser using pyparsing. pyparsing has a simple and expressive syntax so the grammar is easy to read and write. Submitted by Matthew Brett, 2010 Simplified BSD license """ from pyparsing import ( Regex, Suppress, ZeroOrMore, Group, Optional, Forward, SkipTo, CaselessLiteral, Dict, ) class Macro: """Class to encapsulate undefined macro references""" def __init__(self, name): self.name = name def __repr__(self): return f'Macro("{self.name}")' def __eq__(self, other): return self.name == other.name # Character literals LCURLY, RCURLY, LPAREN, RPAREN, QUOTE, COMMA, AT, EQUALS, HASH = map( Suppress, '{}()",@=#' ) def bracketed(expr): """Return matcher for `expr` between curly brackets or parentheses""" return (LPAREN + expr + RPAREN) | (LCURLY + expr + RCURLY) # Define parser components for strings (the hard bit) chars_no_curly = Regex(r"[^{}]+") chars_no_curly.leave_whitespace() chars_no_quotecurly = Regex(r'[^"{}]+') chars_no_quotecurly.leave_whitespace() # Curly string is some stuff without curlies, or nested curly sequences curly_string = Forward() curly_item = Group(curly_string) | chars_no_curly curly_string << LCURLY + ZeroOrMore(curly_item) + RCURLY # quoted string is either just stuff within quotes, or stuff within quotes, within # which there is nested curliness quoted_item = Group(curly_string) | chars_no_quotecurly quoted_string = QUOTE + ZeroOrMore(quoted_item) + QUOTE # Numbers can just be numbers. Only integers though. number = Regex("[0-9]+") # Basis characters (by exclusion) for variable / field names. The following # list of characters is from the btparse documentation any_name = Regex("[^\\s\"#%'(),={}]+") # btparse says, and the test bibs show by experiment, that macro and field names # cannot start with a digit. In fact entry type names cannot start with a digit # either (see tests/bibs). Cite keys can start with a digit not_digname = Regex("[^\\d\\s\"#%'(),={}][^\\s\"#%'(),={}]*") # Comment comments out to end of line comment = AT + CaselessLiteral("comment") + Regex(r"[\s{(].*").leave_whitespace() # The name types with their digiteyness not_dig_lower = not_digname.copy().set_parse_action(lambda t: t[0].lower()) macro_def = not_dig_lower.copy() macro_ref = not_dig_lower.copy().set_parse_action(lambda t: Macro(t[0].lower())) field_name = not_dig_lower.copy() # Spaces in names mean they cannot clash with field names entry_type = not_dig_lower("entry_type") cite_key = any_name("cite_key") # Number has to be before macro name string = number | macro_ref | quoted_string | curly_string # There can be hash concatenation field_value = string + ZeroOrMore(HASH + string) field_def = Group(field_name + EQUALS + field_value) entry_contents = Dict(ZeroOrMore(field_def + COMMA) + Optional(field_def)) # Entry is surrounded either by parentheses or curlies entry = AT + entry_type + bracketed(cite_key + COMMA + entry_contents) # Preamble is a macro-like thing with no name preamble = AT + CaselessLiteral("preamble") + bracketed(field_value) # Macros (aka strings) macro_contents = macro_def + EQUALS + field_value macro = AT + CaselessLiteral("string") + bracketed(macro_contents) # Implicit comments icomment = SkipTo("@").set_parse_action(lambda t: t.insert(0, "icomment")) # entries are last in the list (other than the fallback) because they have # arbitrary start patterns that would match comments, preamble or macro definitions = Group(comment | preamble | macro | entry | icomment) # Start symbol bibfile = ZeroOrMore(definitions) def parse_str(str): return bibfile.parse_string(str) if __name__ == "__main__": # Run basic test txt = """ Some introductory text (implicit comment) @ARTICLE{Authors2011, author = {First Author and Second Author and Third Author}, title = {An article about {S}omething}, journal = "Journal of Articles", year = {2011}, volume = {16}, pages = {1140--1141}, number = {2} } """ print("\n\n".join(defn.dump() for defn in parse_str(txt))) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/builtin_parse_action_demo.py0000644000000000000000000000146115134002420020043 0ustar00# # builtin_parse_action_demo.py # Copyright, 2012 - Paul McGuire # # Simple example of using builtin functions as parse actions. # import pyparsing as pp ppc = pp.common # make an expression that will match a list of ints (which # will be converted to actual ints by the parse action attached # to integer) nums = ppc.integer[...] test = "2 54 34 2 211 66 43 2 0" print(test) # try each of these builtins as parse actions for fn in (sum, max, min, len, sorted, reversed, list, tuple, set, any, all): if fn is reversed: # reversed returns an iterator, we really want to show the list of items fn = lambda x: list(reversed(x)) # show how each builtin works as a free-standing parse action print(fn.__name__, nums.set_parse_action(fn).parse_string(test)) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/cLibHeader.py0000644000000000000000000000153015134002420014621 0ustar00# # cLibHeader.py # # A simple parser to extract API doc info from a C header file # # Copyright, 2012 - Paul McGuire # from pyparsing import ( Word, alphas, alphanums, Combine, one_of, Optional, DelimitedList, Group, Keyword, ) testdata = """ int func1(float *vec, int len, double arg1); int func2(float **arr, float *vec, int len, double arg1, double arg2); """ ident = Word(alphas, alphanums + "_") vartype = Combine(one_of("float double int char") + Optional(Word("*")), adjacent=False) arglist = DelimitedList(Group(vartype("type") + ident("name"))) functionCall = Keyword("int") + ident("name") + "(" + arglist("args") + ")" + ";" for fn, s, e in functionCall.scan_string(testdata): print(fn.name) for a in fn.args: print(" - %(name)s (%(type)s)" % a) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/chemical_formulas.html0000644000000000000000000001244015134002420016632 0ustar00

chemical_formula

elementelement subscriptsubscript

element

W:(A-Z, a-z){1,2}

subscript

W:(₀-₉)
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/chemical_formulas.png0000644000000000000000000004167315134002420016464 0ustar00PNG  IHDR@JIDATx|edZ,5׊U:e(b,Sg7Wpv,flt2$[סSQl1dF 4;y_{z9s^}K|-ڪJ%s"nK7lo)soxrצMxņNɭmP~;Sx|U6ǎmwux˦[o?kݹ}5uѠJ0ewmtKUeQnfZKedYcf,IWV3ե3 K۪rӧ祥fdfoW\1jZce]]Z/Դ̜9%(.+HkgwǞ߼xb}on,~ue%m?啅9ok^ie3wUuM&/*/Ȉ=gNw}y;z{VQQvjZى H\SVLg\Ҳ4JovUtwq^Vmu11?|')tzc 7a*XS2jZGHFnA[7ĉfίٻr:>evA~p%^2! ׵}4-]UFXY_u>Lb6T:-QLtϞ.v@9sߤ CUϟn//5tkSKAc5p}i^k{\m>cN=?e>I0TY9[G\v32ZGkJ+z  ٭LV\TS7V<ҶFKë!&=#'X|.+kǟk{> X9~cm[{äŠDpcC]uyq~~WUnެњKr+Z'k*KbSP ޵̼3h>؏v`}}[זU7X_Y>ReL[S\kJrպ|x|^nF4x2wƺҼ̙vD!~/nQm3'vpD6aysUhukjڮ큹gMfEt65uř{Ӛ6X;wB}{32:Ѷ{rd4c{Go|G5"WKڦw{VG:x%msq̓9kܶrYžK,q߬~zuSsKN%TVQOgA^>;rc/}v4ԤwuKJsy/ŷ̊.~7#2 *>x'mL~U]_oXz^9v,^akin4rJvnZ1cۣmt -:[W\3}#f҂s I-hoG|n(=xVۛ5彪*گN0455E0܍ /&:nԋ  ,f 6 f  `   `   `   `   to#?:& 0AA @0AA @0AA @0AA @0Aa;wr#V{#O;5So:rȻ#?c'd]D\W'|W2-^~_oڔ:#PaMMM_?\^#HB?n~,OJ,|wD) ߶܏Nʌ I۷׽BMo^73>%C0WSTuu||qN;wrHI護zx#od#:^]{Ʀbf$QF3ѣ7~rfn2/ )*zxm|p҉'_O͞5}3s`Ok[cC9dE0\_HO?L|0#5j_{nӦU*{K/OޙgQGM|O9<蠃"6|6jl~>:)sܑGF$Ν;o;~툾9cڴ׮mcYN8aJMʜ&iz[o==3Kqqm<<tA v66F O=oݵkWԲطn~wɗG7cGXӟDE_[%3 #"_.$^Gq#QvQGUܿ//D;ap~?ws/#p~9r䷿uq cbn]+by⃋p"ۈ#JxWbH?.hR__\}UDdN{x/.]޴(< n7S{<>8CcoR𖢈>:s'_+c p {ٶm[|}JDBrm.Ͷ.{~w\}[x  5%+kĈo/o]wLoZ wwӝw|g4 s#n첛/Ԕ=z__RSSӾ/t (6b/~:>HOhGqD|3D%cǎkOH)S⃧!\IDATp `w'tرfoֹʖ}1><3EeNMsW4z /D-EI_kγ3ιi+rW%Xu]9^>ʚsԒ뮟r9//}Z_|mob/Ryy.]qʦK@X?*U+=mESSӧ?%7i'kbʏ]ysΨ|sߨ6ίMvwEw͌?|)ou9߸tb{3wrU裏~iii 7|s;q:gH:k8%%J ?蠜dϥ7iFy,oliivPVKƤ_ZQy_oyҼz}jqTNkpQsZsJflzwjŻ:~o8=|'i?畚^oTίZ^$'3vto3 x) 'kWV~9ej_+Q|mwKVeMQyŶ7YnxҕgLmyyܨ̜.}xf˟Zٴã1dž}l_c}sγ?'|*~3-m5W]u=}#Fk {}pbAQ}.L9𨼾Bٵw}tc}4p(q51%V[7^>ݳ' =ޱ^6He}x |2Qb1cԉ'F0΢~^9sO?{khN}|p4 =Wi]4F-njjŗi}=?}!_0t Knzǟ?b-X<=yϱsj=ZO?cZ p ZJxytA$;{'|*~O0!#*xĈ|w]]s'k޴ }̉9q{c`鲟k|9ݻw#Gn$S2555w\wK[WXwڵgb_'dd|6o^^~>ؿYãF:ScӿQ6m?F2muGO?L&O>VWu>SRRz8rOc#473}9=O<F2]xUEŧ?~jر& }焓Nnhh\h(q`dZ=|tp^T߉>"#G\x#|u of=h~oI%Sǜ1mUJJOS"O<ǝߏߜ[xͩнd pݻ?63O?-O9aʔ:(aj׮]O>TUcZUQ~_+G{ 0CGpo _׮`_3fGrH4$ `$[+~*{_;^ˆl3bĈ+rEsmŧvZHIIM,g\~r 4,,`@ `   `   `   `   455E0ܙ  `   `   `   `   `   `   "?eu  ᬱd~~NfZAE@2/* \2JHJ-kjjvC`Ч֝ҳKXW^9uhU+4/eWZEn\3fE 5퇧e{\JJe3+GDPQ~ةW,۸mW=;m\vũT I[>'{ {ɜ7s \r2&]rw;6}ޑe =pMq̻uжgGP={ln]fGk-uϵv{tj"l܍ynټέΛj,wYK7mꦥqGquţgؾG>{^3e\[U_|;O#Tě:f]fj,7 )G^Q]eUQddd֔V h_v0u=3> z ̼ю;N,(ihƆ⺨rf\[\Y 5%9Q ιz[^Gn.I e/:m\{y;8Mre:[n沶'͝v_f[;'es~ȑ#tF a:&Pp>GwoK;yׇ9GK'O>>^ڵӦyƴ~=TMdž>g'|*~дC/‰Y:樌̌z?-|3>?Ye ;KϏ$|{™',,[xG$/ežf}ioyWZ|KO:5HQRσܝkTƧ7}G/~0H$ +re|0Is͍^223n*)>Oiߪ Fe-#F ɿT|{^\ł)SãS{:` -h~ͩ *:}韼w$H23=c㳚#6e˟ڗ=ܹ[񮛚'Ve^2xrvEtu\=~}뛖_s>oy{[ǟi}ǯ9 8K~bqg˜Euu{ߛ1sU~߷Á+WGg-[K.\ߴ>(mi;f5KfD7[~:͑>n˻4qIˏdve|?>lM_{胛/Cz@Hn<ԁ_${ObBxE[/FϿ VԫWqqoKHG8ms_ zS;P]E_zA˛I#FL>}r|OD0Ajo=cڴ׮zt)F}yl﫹YrY4~{OھTYy87#6\zz4_EW石ۗW|}aˉ,ޞQ|nܫW[ɜVg3k@M=I'Nzy:mnQWWֽTWhysZ1\]hFA3m)}6 t7QFFl959/Y -:1##o-tWv-KF*lͺ矟շ_cs-˞7t眛hytʳK-˰LB7V-ɽyi>/_%yjͶ n7Q 44|GMOn^{ΌevX&X]mTpsdFlZok.㫵_*ޏ}랭u[dw'>1NZύ3V-"\I7j@"$SOҺw^nlN;gv׵/p\p1-WZ}u{2{,_rmϭn^E [xv\[IfzogucFgviǟ->z@" 脛u? ͻOQgpJ.Stev]ιEqݭkJKsק^~}Y@u}讬[вz|;]c0>8Ǝ5 $F2'e6O6Ұ`hd\/Gˮ~kk7DLwƒ}/i-{[f]=h{?<;_sU@$S9r[z껅ߍSl.t~h^ߴ|F-r U3Z:QspctWPյ7̾!r:7H$ Ӧ]w_˖}棟ynsѠiOxY OG_ϗjٸK.zюWwn'>WtG}6ƛ7m褋ԙYgdM>}&G$꟩zfCb+`+>z_|/򗿊ߌS+bXx{ӟ Ӧ}RJwDCo;Zp7ܛoCvȡc" %qǼe~zdݺog? ?EC$ $|``   `   `   `   455E0ܙ  `   `   `   `   `   `   ̔(yԗ姷vz~Y}@9/2ڶs+h,+.JN$'K(hvx쬥sWWw&ys~Y@rn,)LOmݻ*%-3AmWt{ώW{ݽG}yaNFS3r z{4Tv8:5=+j9ƚnNaAW?KPP5RҲK=.eB|sL _>6H7Tdμ{^]s%S*6fD!,6ܵemYxSua@O47:z׶ά:SeShdqǖ='qVT+kzn,+ t {ƹsJv ٝ9D@mcYwN\Y~ohOljsM~(Z?:or]krLjS7oX1oVg[fM==v֥g޽uQXj|ʼƾKg߳▅ӹeś:ωusn;,Դ̜99IDATŕs24k Z4-oV[Qh,+cW|8ʢ̴MM+*l^UY;0`ØK7UǾ}jFAI)WVVGSz9[[dʑe/ٯBl3p~Nf䴎}5mKϾg{6zviɞ%b6w~A36>VWNe謢G=v;6>+Κtpj['DjZ~@}]ۇ8; owJKeҲ +wnΞ<]}Լ^41U\S]?'^ Nw\5Of)nhڹ}[hMYe{jn.-i=vtNvFO +gz聛ck(+Y:foR0,s⟸oTM̌ѲⒺ U'˷lc}eqNFgrvaRlָ&Ɔiln)/wqm-^ OGO}k՜zj6],yPW9an£g/k`n?N j(Hyx󞝭BYuz9r uEfkgL*ĝ.tN)E9hŷ\綼huY|Qjnicg+;oLCt84=6z/^` eVm^qq6UOfίQPb5Oјn^?'YPY/_bZgct8kn^_uԧ=|2`>۳eFE @0A&X 0AA @0AA @0AA @0AA @0A~tCD 0AA @0AA @0AA @0AA @0A!xxxڧ~_ܺukl=п7c>3s'efF .xO|9}h9rnѣ!CD&[a~ݻw7%ݝ|R1tGkcӦyƴ~=HFw7->h_ܹO|'<4 pbģ9*#3#J67oRY^ʇ>/oV4 2,lC  $$ p,׿p%5-gEyxb)b_4kyE.ڵsW/}?Otn*)>*N}˲[F%KdNG>O^? )Ws<꘣z89bSt,uS';w99wAh5/`Æd1L\]]wq=9.sb}oVF/Y[wU]|„oL2}:c}p륀ڰ!`%So۶->8ԁ_#Y=t1!n-ь^-^7#Viq#&>9>޶m/~~=zƴi]S(Qm_\r}5D[rY4~E+_=wyed~'=c)}E풿$u*Ś3'h7M$q]]'fo\NGH$plyfܜyvKW,2{s޻m[vm7w8cþ_=?ewğ{gd&[ҕ2.(2UuZw3W_|eQn'xsoZ}WG34o3tQwݕ||xqwoHw_ nnlãAI#8">Muob3 NrϙlѢ˛Wvqޖ'Ȋg뢞Vth)SϝETSE͌vCm|>6`%SO1j3؉}9sfGѲpmM_=F󧋛*KDXm/ny=#[2s?_cO[[js5Q0x\ië q\wjʹjg,)S^/_vE}d |IcǚHd )݆W^%VKFˮ>xqo˃+;wҗk* )GxѭS=FbS%/E =K~for:7 2HgLv}%>.[R~E Ԇxtљ:3댬ɧO|(ԿPL3=םw/@%>{lB.B܅_/KW4\=O~ʉ*6Oc> 0\tw^}hɛu7?h;1@Iy7ʖ,ȺuQ2{7…?!O(wQm   `   `   `   `pg `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   ` "B   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `R@IDAT   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `   `ӛ6IDATT[оIENDB`././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/chemical_formulas.py0000644000000000000000000000652715134002420016327 0ustar00# # chemicalFormulas.py # # Copyright (c) 2003,2019 Paul McGuire # import pyparsing as pp atomic_weight = { "O": 15.9994, "H": 1.00794, "Na": 22.9897, "Cl": 35.4527, "C": 12.0107, } digits = "0123456789" # Version 1 element = pp.Word(pp.alphas.upper(), pp.alphas.lower(), max=2).set_name("element") # for stricter matching, use this Regex instead # element = Regex("A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|" # "E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|" # "M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|" # "S[bcegimnr]?|T[abcehilm]|U(u[bhopqst])?|V|W|Xe|Yb?|Z[nr]") element_ref = pp.Group(element + pp.Optional(pp.Word(digits), default="1")) formula = element_ref[...] def sum_atomic_weights(element_list): return sum(atomic_weight[elem] * int(qty) for elem, qty in element_list) formula.run_tests( """\ NaCl H2O C6H5OH """, full_dump=False, post_parse=lambda _, tokens: f"Molecular weight: {sum_atomic_weights(tokens)}", ) print() # Version 2 - access parsed items by results name element_ref = pp.Group( element("symbol") + pp.Optional(pp.Word(digits), default="1")("qty") ) formula = element_ref[...] def sum_atomic_weights_by_results_name(element_list): return sum(atomic_weight[elem.symbol] * int(elem.qty) for elem in element_list) formula.run_tests( """\ NaCl H2O C6H5OH """, full_dump=False, post_parse=lambda _, tokens: f"Molecular weight: {sum_atomic_weights_by_results_name(tokens)}", ) print() # Version 3 - convert integers during parsing process integer = pp.Word(digits).set_name("integer") integer.add_parse_action(lambda t: int(t[0])) element_ref = pp.Group(element("symbol") + pp.Optional(integer, default=1)("qty")) formula = element_ref[...].set_name("chemical_formula") def sum_atomic_weights_by_results_name_with_converted_ints(element_list): return sum(atomic_weight[elem.symbol] * int(elem.qty) for elem in element_list) formula.run_tests( """\ NaCl H2O C6H5OH """, full_dump=False, post_parse=lambda _, tokens: f"Molecular weight: {sum_atomic_weights_by_results_name_with_converted_ints(tokens)}", ) print() # Version 4 - parse and convert integers as subscript digits subscript_digits = "₀₁₂₃₄₅₆₇₈₉" subscript_int_map = {digit: value for value, digit in enumerate(subscript_digits)} def cvt_subscript_int(s): ret = 0 for c in s[0]: ret = ret * 10 + subscript_int_map[c] return ret subscript_int = pp.Word(subscript_digits).set_name("subscript") subscript_int.add_parse_action(cvt_subscript_int) element_ref = pp.Group(element("symbol") + pp.Optional(subscript_int, default=1)("qty")) formula = element_ref[1, ...].set_name("chemical_formula") if __name__ == '__main__': import contextlib with contextlib.suppress(Exception): formula.create_diagram("chemical_formulas.html") formula.run_tests( """\ # sodium chloride NaCl # hydrogen hydroxide H₂O # phenol C₆H₅OH # ethanol C₂H₅OH # decanol C₁₀H₂₁OH """, full_dump=False, post_parse=lambda _, tokens: f"Molecular weight: {sum_atomic_weights_by_results_name_with_converted_ints(tokens)}", ) print() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/commasep.py0000644000000000000000000000130415134002420014442 0ustar00# commasep.py # # comma-separated list example, to illustrate the advantages of using # the pyparsing comma_separated_list as opposed to string.split(","): # - leading and trailing whitespace is implicitly trimmed from list elements # - list elements can be quoted strings, which can safely contain commas without breaking # into separate elements # # Copyright (c) 2004-2016, Paul McGuire # import pyparsing as pp ppc = pp.pyparsing_common testData = [ "a,b,c,100.2,,3", "d, e, j k , m ", "'Hello, World', f, g , , 5.1,x", "John Doe, 123 Main St., Cleveland, Ohio", "Jane Doe, 456 St. James St., Los Angeles , California ", "", ] ppc.comma_separated_list.run_tests(testData) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/complex_chemical_formulas.py0000644000000000000000000001241315134002420020045 0ustar00# # complex_chemical_formulas.py # # Example that expands on the basic chemical_formulas.py parser to # include grouped multiplication notation, such as "3(C₆H₅OH)₂". # # Copyright (c) 2024, Paul McGuire # from collections import Counter import pyparsing as pp ppc = pp.common # fmt: off table_of_elements: dict[str, float] = { "H": 1.007, "He": 4.002, "Li": 6.941, "Be": 9.012, "B": 10.811, "C": 12.011, "N": 14.007, "O": 15.999, "F": 18.998, "Ne": 20.18, "Na": 22.99, "Mg": 24.305, "Al": 26.982, "Si": 28.086, "P": 30.974, "S": 32.065, "Cl": 35.453, "Ar": 39.948, "K": 39.098, "Ca": 40.078, "Sc": 44.956, "Ti": 47.867, "V": 50.942, "Cr": 51.996, "Mn": 54.938, "Fe": 55.845, "Co": 58.933, "Ni": 58.693, "Cu": 63.546, "Zn": 65.38, "Ga": 69.723, "Ge": 72.64, "As": 74.922, "Se": 78.96, "Br": 79.904, "Kr": 83.798, "Rb": 85.468, "Sr": 87.62, "Y": 88.906, "Zr": 91.224, "Nb": 92.906, "Mo": 95.96, "Tc": 98.0, "Ru": 101.07, "Rh": 102.906, "Pd": 106.42, "Ag": 107.868, "Cd": 112.411, "In": 114.818, "Sn": 118.71, "Sb": 121.76, "Te": 127.6, "I": 126.904, "Xe": 131.293, "Cs": 132.905, "Ba": 137.327, "La": 138.905, "Ce": 140.116, "Pr": 140.908, "Nd": 144.242, "Pm": 145.0, "Sm": 150.36, "Eu": 151.964, "Gd": 157.25, "Tb": 158.925, "Dy": 162.5, "Ho": 164.93, "Er": 167.259, "Tm": 168.934, "Yb": 173.054, "Lu": 174.967, "Hf": 178.49, "Ta": 180.948, "W": 183.84, "Re": 186.207, "Os": 190.23, "Ir": 192.217, "Pt": 195.084, "Au": 196.967, "Hg": 200.59, "Tl": 204.383, "Pb": 207.2, "Bi": 208.98, "Po": 210.0, "At": 210.0, "Rn": 222.0, "Fr": 223.0, "Ra": 226.0, "Ac": 227.0, "Th": 232.038, "Pa": 231.036, "U": 238.029, "Np": 237.0, "Pu": 244.0, "Am": 243.0, "Cm": 247.0, "Bk": 247.0, "Cf": 251.0, "Es": 252.0, "Fm": 257.0, "Md": 258.0, "No": 259.0, "Lr": 262.0, "Rf": 261.0, "Db": 262.0, "Sg": 266.0, "Bh": 264.0, "Hs": 267.0, "Mt": 268.0, "Ds": 271.0, "Rg": 272.0, "Cn": 285.0, "Nh": 284.0, "Fl": 289.0, "Mc": 288.0, "Lv": 292.0, "Ts": 295.0, "Og": 294.0, } # fmt: on # basic parser elements # - element - a chemical symbol, corresponding to one of the entries # in table_of_elements # - subcript_int - an integer made up of subscript digits # (a normal integer definition uses the one defined in pyparsing.common) # # element = pp.one_of(table_of_elements).set_name("element") element = pp.Regex(pp.util.make_compressed_re(table_of_elements)).set_name("element") element.add_parse_action(lambda t: Counter([t[0]])) subscript_digits = "₀₁₂₃₄₅₆₇₈₉" subscript_int = pp.Word(subscript_digits).set_name("subscript") # define mapping of the int value of each subscript digit subscript_int_map = {digit: value for value, digit in enumerate(subscript_digits)} @subscript_int.add_parse_action def convert_subscript_int(s: pp.ParseResults) -> int: ret = 0 for c in s[0]: ret = ret * 10 + subscript_int_map[c] return ret # # parse actions used internally by the infix_notation expression # def lmult(s, l, t): """ Multiply """ *terms, qty = t[0] return sum(qty * terms, Counter()) def rmult(s, l, t): """ Multiply """ qty, *terms = t[0] return sum(qty * terms, Counter()) def element_ref_sum(s, l, t): """ Add multiple consecutive element references """ return sum(t[0], Counter()) # optional separator in some chemical formulas optional_separator = pp.Optional(pp.one_of("= ·").suppress()) # define infix expression, where multipliers and subscripts # are treated like operators, so that grouping in ()'s gets # properly handled, even when they are nested element_ref = pp.infix_notation( element, [ (subscript_int, 1, pp.OpAssoc.LEFT, lmult), (ppc.integer, 1, pp.OpAssoc.RIGHT, rmult), (optional_separator, 2, pp.OpAssoc.LEFT, element_ref_sum), ], ) # define the overall parser for a chemical formula, made up # of one or more element_ref's formula = element_ref[1, ...].set_name("chemical_formula") # set names on unnamed expressions for better diagram output pp.autoname_elements() def molecular_weight(c: Counter) -> float: """ Compute overall molecular weight of a chemical formula, whose elements have been parsed into a Counter containing chemical symbols and counts of each element, using the table_of_elements dict to map chemical symbols to each element's atomic weight. """ return sum(table_of_elements[k] * v for k, v in c.items()) if __name__ == '__main__': import contextlib # create railroad diagram for this parser with contextlib.suppress(Exception): formula.create_diagram( "complex_chemical_formulas_diagram.html", vertical=2, show_groups=True ) formula.run_tests( """\ NaCl HOH H₂O H₂O₂ C₆H₅OH C₁₀H₂₁OH (C₆H₅OH)₂ 3(C₆H₅OH)₂ C(OH)₆ CH₃(CH₂)₂OH (CH₃)₃CH CH₃(CH₂)₅CH₃ Ba(BrO₃)₂·H₂O Ba(BrO₃)₂·2(H₂O) """, full_dump=False, post_parse=( lambda _, tokens: f"Molecular counts/weight: {dict(tokens[0])}" f", {molecular_weight(tokens[0]):.3f}" ), ) print() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/complex_chemical_formulas_diagram.html0000644000000000000000000005560715134002420022061 0ustar00

chemical_formula

element_expressionelement_expression

element_expression

[Suppress:(= | ·)] operations[Suppress:(= | ·)] operations

[Suppress:(= | ·)] operations

integer operationsinteger operations optional_separatoroptional_separator integer operationsinteger operations integer operationsinteger operations

integer operations

integerinteger integer operationsinteger operations subscript operationssubscript operations

integer

W:(0-9)

subscript operations

elementelement nested_elementnested_element subscriptsubscript elementelement nested_elementnested_element

nested_element

'(' [suppress] element_expressionelement_expression ')' [suppress]

subscript

W:(₀-₉)

element

A[cglmrstu]|B[aehikr]?|C[adeflmnorsu]?|D[bsy]|E[rsu]|F[elmr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airuv]|M[cdgnot]|N[abdehiop]?|O[gs]?|P[abdmortu]?|R[abefghnu]|S[bcegimnr]?|T[abcehilms]|U|V|W|Xe|Yb?|Z[nr]

optional_separator

= | ·= | · [suppress]

= | ·

[=·]
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/complex_chemical_formulas_diagram.png0000644000000000000000000023313615134002420021674 0ustar00PNG  IHDR(QbIDATx|ua/ pqcA=褩4vsw OJpKckPzݺQChݫ^ҰqmI Φ@mxI+M9sNri&m>h?|>W 0 Jr %9DIN$QS()@ Jr %9DIN$QS()@ Jr %9DIN &EOKuqѐ`:i9^+7vS2^26űX'zZ8*6J_[M٪GsW=Ի{GIjsiؽ: ƞ[S6M{{- %5 6մeQe`*mNZZ/pKK%OڜuΌY^R]Tos@Oꀲe]}vh`Xԝ&W_ #epKwl.jVeywwT [P'?+KR;c0o Gz@KhǏN˯(\ݍ+nK-˂Sw*]z~b_~o抜OJٍ|=4=>yq][w&o;߰c색]BVџi[mѪl9^ 9kab-I9pc[V۝%3زbnݱeXdrȞ|܇}_ecW7t `^ܾ2{wo5ۃ髫2,y+>88KR{ieF|3i+:sJy{ki/d^h؜*XuKO}SR^"s\~AFok `DCuzơywwWűD_%ò3[` ֜] 5MW>ԝȞ<}-p+80"*]ߜjY˴\=/|x[g01pƧDs}U$s1Gڻ'-ëw ӓഫ*Xv݉UKUb?p[I[qSy芺&ʦڲ V>[Ztbwm-/+֯M7M-N~Ӷ o<^ې K*Gyj2lvvwgW76>^Xr_sMҝD pX l/ilhtCFK$#׺ 9Q h$O~&e?ȯPrg *+M9Yt3Y>y%#&r*ZxwOG9;I4VƇ&JMU UPw{"]k򥙱t޶D(g߰zrӢ!5WδS% ᠰ!0>0;j{3[q&b_[]> F*洸$lh!**K?tlQM\Ӿ+45Tf4KG߷2?%}mas̊L!_`C:U0Bi&=eo־|;%ʊ*񫨭 '/8u͛Mfww[}eYvP⒒LTՅ#+ͻt))f_W)d[c8Ò-C)V<@buM陚!^ӗmP_Qߓ EZeu:;=cU?{ζʲؔem֕eu/^̕Kr{cwNMIUsa87$O~'ms p֙0 Jr %9:'`kOqEcWL:`o0>ǟlj&96*jה3wI]UYLfDIN$QS()@ Jr %9DIN$QS()@ Jr %959}pZ\pѼDS()@ Jr %9DIN$QS()@ Jr %9DIN$QS()@IN/|]IY?I_)@'tp3w4w+L[*6Yh`` _:L`ݥ o=g7/lhq0ul** NDIN$Qdml;D *nt&9}])mp?vu`Z}_&d[/[ĞQr:F7Tk=yq^4v/.ܢK2bԦ5dW6uXu vs{pMb] w8odheb>ѺxCOϧO)h W|KꂦN<޳2'n^8s*hgٰ2<9'Z{rq,g]od⺁TTdRy]PoqSo![+{Goi ;LN^{kxgW\Qv{n0NSLꭿ06-..scS( YUjy睗\>|(h&HkW-WǶ{lZھнW(h&%{.~j%+{/(fRr|ٲO'TqͲ`7/ouiEE'S4Z_:LK?270vժ^ Ė{;/vO=nk\"m3g:ΊvE&7~cO__l{V . $ J_;|/P/^|cƦLC329M:s'o^sM-_/O3u7¬Pˌt-̒DIN$QS()@ Jr %9DIN$QS()@ Jr %9*ȡ)@ Jr %9DIN$QS()@ Jr %9DIN$QS()@ Jr %9DIN$QS()@ `2TEմV[m(V0u7o&79=$Z `4V6{u0,dSe]Xڜw5VK2͝=dg45VY] +ol)/k[{򜽯*SQQIkTC|s[kī#N\>bՎU]+S4KORǢ3|Dgs}e|r1` 6TQ1ݓڽ|bR(@=}S14E7T-ɼX{ce(GՄ-UpdC[;iN[7>ܛoҕmn|x3/r>>:6e7=Z%n+ &j]=9t)a!mUZƾ17?ٔP34ջ[ƒ[c7pmwOZбLN;o9U_6{uwg`)洽> ؑcKylˊyu}_ecW0ac;{yC-3-XŁ̞d]e^}ps`cK2kv Ok.O}LSXMk;R_<^njȽXm[Xt8bӱ_z^ܽz^uYyY29,N--ue邌?;t#]_\+mjb.'p<fRؘ)֘t::½S{|%3+{$&kw^.?LS(9j4[Pw2nWOoYpය LK7o( Jbv+'Ńo xz%LxtGMC{뚷zwWkm8I㳭)ȥT YEuC}ŕLbԦ+k B8o}{Goh5,N53~6gYEE<;uU[$TW68RjGv7זFˎ꺶<#T(761Ւk"}- 7t0Fiiz80÷T55-V67W ;g&;x}btˣ}o؝}FS{KonmP5;u2ݮ3Q N'LKbacw,FpD޸3"p6(洢6lp]>gUՆw4N<=%%sI6Kj,wfZU9IksF+jbƊ**.5]]{rsq)OػkáVה ֯2ū:{2T_wg[SCMeYq2Ǫh&bJmʊLӕhi*/I|=qIDAT'6ǎe\.S<93ڜ2dڜrxΏĜ$Q'Yss()3=ԡۮ( 7w0ڜD!j u5VRfwWsUIIzOŦI6&9:eUuKS"0%9DIN$QS()@ Jr %9DIN$QS()@ Jr 5jrKGSvEFS()@ Jr %9DIN$QS()@ Jr %9DIN$QS()@LJN/|]I;>sGC j?ks[/OybϞe~eqm&?9OFro`_xx`$;FfVzDIN$QSs٫ㆊES?soF.[m)s{EQ{S7y1ns3m6'i}߳ppgtmKyYb۞bXL k/ Nn).پo`_ݥ̑Gl,6^'i_2֦Ylo&NW`X9A϶U?ݕZMqN/|]._=3|Txez]2늚z^Z̼:nXz"*ik|Ӻ+Ap^eݵ{+[߳5V)hГ>In`ܳ5zkTmo}=*clO 'N ;Ϡm'wLIQ-ȲG,<ի o<\"fNuݲGROmxY/\ZW4;$]w&oz uagڔ$1lpieeo"w ?ɟ`BNXY,kszgu,8XUse^:?QNs<݋DfJ޾}[4moMZBSu2gKoMT>/y Kz+%߱){ MM/Toݗ9UNֵ^\9.ٞE ϓ``GMK$eyMËq=9Ե!S\K%:*OƦ6z67%'†HRo4'p؁a/-5R5!{U@kK׺_MoJu]&$StZJƚk3 _I+Z<|l:ۖ'6|6ؔz5򫙦 w5mcT>~ϲB2K7oL+LiΙS1`a4H a8P1钿֦H70(raφ1۞rL6B9 _q"8شpг3.c L5yf&܃w4 'yHcUή.tj9o&5|%qK6avYSO4iY7ܒxeβjjD-ɹ+Qi;7KzC#'O8JNxf1{3ơ3'I91,TSwaa6"%?]s GMŨ{nhqbZ[}i0 ?sUvs`m9]-aUn\]kQTXu=mhWt$\-A֜e]ْL3MGã|,LBΜm'*}N9t]f} Qan;4oUчcA}nߢmGH>˂}ץu|L+9MfXO [&~};&=/`J ^pqNsd5=LMJ+B]yUޒL("e{.`Ǒ"4~LY[(d=k/ zSl[M#E`mN (ӝsz~T,۔?[Y&$~hf;nYz ;EK+6VgkQ|򶷩G54$9mVlyȱTtŃ;׈;._T bUM+Kշ 󦳲0/ &&mږVī;Z9||C7 7-1dMKW[cMy,w4ƶksOg嵭#ln*g)Ik/}¡㕵M0#^xUCskCyQQEShoX>}XLOƻM/]yc<8˕l9ыt^U5E>G#jX}sgߘN>zg+X<`c&*}vw*XttzrL]HKuqNI&(,hm'9fIMN:Åה&5|ǍWmǁn[uEkvj›G8~M#AK o3O}J<|ۓmX4=^{s}V7"/V7chfx}bD¡M3 64^x߈vM __V7^[}sXqn+ocWvF:9Jr w<1)0#LjrZVQ97gյ͝=9AqUs@OsUI+q#wYMr9}䚣tey8w坏|΃^ܹ:ucnۜHiƇ{vKzfxBR)Xp/8vc(t5T\_Ǒ/ܽ~eiPXeÖ%G0wɖU'ZNȶDua|ކbxMMXνmgjx4IDATX._=SSW񰂅ៗW۪yw|Է@MKW2Tn>ՒÇ:N5=ueT4dat1cBjZ;[j^&9f_iEzoZxU-l|UdQo^q>w\/JS7Vzk]eAn w;a vNw>!7! #y򲒰egq}w1nUnax,wIjs[bK*]R]Q<5AT{:w&Šڛ\[UlykFҵ2\8<#SAT#wn-Xy]kWXÎwX]}(0I4Wųu=^Ԙj8./ywwֆ_ܼ1>:,: &yXmrZ\=轷+_~,YNJO%5ה _o9#zԎsöj<0VHAr7o%UMߘ[$L!(bʚd_i;,b) s2mhjMtG;ݙ.̱؈ g`LzfJFɖ+KFߧ"'85lM 5]yhlF~ykdT[U߈?dס֎w߸jXCNr>0iuY][ϱ#[zҹzmie㩧& jMճV=k(Y`g"ӽ9o|4_W1ڦkx`ow$U<[iG{wrC*..̡"{zFsڇLl k*>ږlw@.lޞ,'R}+I4VƇ&JMTp9g¤'i6$z wආS NL))+Kw*Ox}ׯ\&zʊ%U-=woYbܻjؠ&+}㬜!j\c%-E^2 N3j][|Q-8L7؝)p&Lfr>>Ep+]і2g_O_;JQ; <\WZ_:W[[qj\63 5c}"03;GOjXYYn[[)kO'EWvO ޵=z&lHuFbp֬UgdФy+XWcyVהE;kslWԦǭ@snN%A%%s6r9΀M6wf|)Eqy?5MX?۞,t;Vū2I4Vݰ#[Ӓgq~rCʊt%ZS;涽Jnꪆ3%Мn֙;}OW{j7U&K;{_wgst052|0t1bŕ568CuMm/* ΄X]sXÒ,^ۚ2=͵eWv bU?[rj|a.g89fd5]WܖLao9'o[MѪNp͏u6 ѼlՃR|̿ǵ{;"."<ۏ$2IJtd9K_`b9zr]{*8oLA~CZk\-^i+YzZG:gcޝ7m,]y_.~ܞh>;FWcŕ3Ҵ?Z3,n' _M{}l'Aֽ=9"2ri.㹛QcF*9flsZ^}`G3en邕w<MTW/s5[v|hW/(7t[v>XYr껏Uq.s3佮Y#CmKd^`wؓ&:g 㘲]e⚍M6Nveaxƺ)~H[>Is.o ck+nM_s|w(6 HWW_}5 رc+O/KJO]uջo{pĉ{O?}}~{w~gmN8&7V߸-|yҥX,{M{/?t;BQQQg)'5z ƦGwM`\7=떛o_~Gv| 7ڜJ~ryy9gF gkvWLԒ%䴷9f Q$\OFcǾЎ2;6Y'W_no?wc o%=ܟff$Kꗾ;fgV26M.뷿x_ )..~Ui7vOZ+?jܹs\w;}Ou>0yfOrzĉE ^xQZ?ַ%\3{g ;-]][u's/` f ޽pE.AI&F#**DqU;owtz]<̷.ikz3k9.o _p=G&96 a[OŲ.O~.px}ɼpxzԚ:s^{«:Ag*eP"IDAT T400w/ &d^[p,Biiۡ`wWfRT!SBp[}0NWm?я _{]z׸Uu N__ .@A3fO?.4)&z&O?xSYlƌs:.z`,\X.<3Y3#9mٱ#\IrڲKɿpf@rk}}}qWݭK_`>\'^?^[ p{ZTTw'8e7T,.}Ov]ŗm 8eS^W^|X>0MbgwԹ瞻{_ǫLUw&ٴNNo.zϒ֥4J*M69`[vO}OTΘ 9+؄Ym:9,r?{Сvժ^wɻ.42 }o韾: n]7?I_0~\4/f8] "kZ=W[ِ?L_M.kn 4mAzkz}h)ʨ{L]oV6^#etԕyަsoH'uk'Z6.n]WqCG .wڗ?Y/d$ժ(Fs2/Qm3 .XCr.8Ȧ,tٰ-`af:cVFpqSoְd6]Xj] =MsZ>S&oeumW I+XO26.mj*![_`:Ls.8uHQ}"!n |YQ&(?7غ7gґ/_?wo~Iꪺ2%Ӗt<.]6 *s֚j<Ӕ]'ݖ䅮=Abk3{6NzHlTھuܾ'.xd=_ʞ/ jhMsNn6wOtG4^pO-^pSi_1InsN}\vK>nH2q= % M ^ڟ9ĥN|SlLl{?Y6J&,3UeV>7lIVNܰ6Jcku{5fwW s/{{5ꪺ0- LޞS}'֯?|cQ[}=ܸZ=,Z4|Pq.8hػ8[{//8Tk`hφŋ(x9&\;TdޭUWc Nq-_{2c}GZ׿ |\so64X̙3'OMřOU7k@ ĦpM QiPI'1%E]02l$NsSX `ah` Rpr/1_5ФC'!#%F/oR''șbb7puuwos+Xbxh%y+X޺>]G2'.9圙$#_6S0'`=<ӧWYw힦ФO>=2Ht4R|G Ug>}/r5sc %8\c'`l*I͞.\v雃id zvYv*֫Ϋʿ'.,y06 NoeINO7QQ*k]|3<\⊲O?sG;tg.LRuS~ 0)g魟 Lß`FIh1bTJmcf4Qg\ۦw^jÇ1$Sw@՝> ?^ψd/Jt`}p,zo:}Z5ϯZpy([}LgUw:¿@` 88Sdfe":;;Å:\w7:J/לTY~5,]Ʌw?NGS(L1)Iooog3 Kd"j !0sM~r;&T|B Nbr'? ~, )RxG/jay9kG?zW~.UѼ Y\.>^[&N^{;\L6oLPu`INaL=-'\;^}`*%gn_߻7|EEEdT8 UjeOeO=Lo|֥$JVEYrz.L:`FP[}SW^yW ׮Zk.y…w^p ?۟mm2m3gyO/Aoݛ? 9l.[_sܹLd5{я?}5\ɟ b={Sd?@lcL7&]XufOo_\醺u-6eJ]p;|/S/sّ)p]oL헿T47{w;.Ss/{{5***Zl_ٟgnIy.Zpջ^~e)ʭpgS8˽|ةt؇qN83)ĦhtZIDAT7`VK05f[ӣG_NwǿZ„Q>&_.8{nd>3 /E \uUq翗Ç{zz5o/]`s I7ֿS?|ov>>'5kۜL Jr %9DIN$QS()@ Jr %9DIN$QS()@T@@mN$QS()@ Jr %9DIN$QS()@ Jr %9DIN$QS()@ Jr %9DIN$QSsƺcwc(-Ly+NmXm[ߘi cQM[nnmz2ǓMmgD˃A`s{´pvSfƜw 0=T 0EN[>Vkۛj+ˊWű殾}m/vEbm##u67T2.*4uf1w}ehB;mGCN͝=#R]-ƚŪ>fsɋjhͽӞ֚܇S^_4cjOg[SCMe<6JgY =U}V_XEMï*I:jZj;@ 5l>&TS0s ڞL7;l-F[zwo3[+]; Nx7>ҕmU}lPX=+R7T-ɼ;Ϳʒ )ワ疖LJ4a[-ddvLVloO +ohՃA~KlϽdrZvӣǃ-p{]YT]rwY{j {6Wdt7yd[hG\03iEc@- 9C+ȱqn~^ݱ?ϹM& M+/dy0<w<ћ*jrfj cy+rc[V#|06ML6}_ecСK?3+莍-=D[|tw}iN1i'\r[.,i&<;WH+o8b=y[]IL푭74"76M_Mʖ_:o݃5&,ɻoKm.yNSOi3ɒ Z`X:,nnHIM|ɘKn.W7w^y\wہB*sLוughߒ/jފoM+cDnvՎɅwn-^Ly]kWxGwT >Uë?p[m'N j6L;6זdϾ湩:ӥ*]ٝ\5Xcr:c==a:/^ ݳ}dVUfINWo);(4&ܛ=K8axw Jj_={{ccة}5onFQ&[Ȧ&j'fouM 譤5A:":{rc}o5/K[]X2!^v_MyܱUcxeM}cK[gesO439lip"C_v\vWVDtg|KF}ݙRwoX=MGl\{ue͕U?mKD,_V֦g;;'Nr]b93KT4ӀI[TXeuio[;XmSnCW-L樱.Ch3$9eP!`.,ܿ'S_[]WpM#ux0dۑJ|c JF>|˕G`f!i8P@]eh]ȚLuC })'S"a=ggTD?Қ'I[{΍cS~ rΚ4p#GKz:A%}ma#؊0TR^?[23Cԁ34HNE gi﯏R>6=Tp]mhYHYM}zμwX^W[`jﴭ1%[w5W3&pq%%sVUN<̻nixwSEQQQ>&2VV^Uko;u i"=1ѡDO}`_W26M *y++ۺ3;t%ZKRfm$Cܒ>8cUs2;ۚj*RcvV4uA9{Wk[3w\[vez`|S2 Vݰ#M~ޚpt)ӲX8TW"ѕ}X3tV/faޞewS<9RuI;ʇ =-7>ߺ*[,㯾m5Ev*]yҦ ഛW5wyk_-;;Ħu#ݷf)y斖.Xf};'rbT6uر=s;Э@/~ W^C<8URؑ<bO[nlcCwoY=tVo}Xװ4;-I=E+$cw/xdY]{v`TW3=xjZ{vER.S5K򭞗}LbS`)Fs3TmlӟU ,9l gU_>3-92=-ձ\/L0UfwΜ6zZkRwjǪM S0ӑ^֝L,! $ξNFr %9DIN$QS()@ Jr %9DIN$QS()@ Jr %959}0\pѼ Jr %9DIN$QS()@ Jr %9DIN$QS()@ Jr 5ӿ۝Oǿ7N%k /;z+?_-_pU0Q`4&Y3CX̤c}쉯}mo_iϿoo^pջ~[ybJl' Ng)Uۃ_U_&`:U鞯 .еU0Mih$=^z)Huڝ{5{gV+q㻾{<3=~'E]7o}kŒW2`b_סC}s ΜٓH0ۂSo~s'58K+G?6lST#==Ʌo9'-ÅyzW7,?+9pRi…GQipa];TdޭUW+x[2gάM>nkKIF+٩!L=i |lM5KbଔL%Ym˿jg~^.tѢw0…3jֿ7?|+>YWi~Yvk6{SꫯQpaݛs̐w?|ɔ9YM>Ʌ޾]l:?߼p[D)HkW-W_?;BGG#Gf Q-_rP=UTgggpWzJϧh kwǎK.?K. wm md;TNNѴLٓ>.,=8sV,A~dofiEQQV8 ?qrs]X^0Eg \v雓?W_ `'Oءㆊu[ɽV2ޒ.]4m~^quW"=On-.Py{c,lƍ[/7o}[+\jUՕ}韾zG?/tD <,uӏ2];bD-zktF K5[U])}`|WUlnY}t^~94WU>g -#u//O\i_M'gVL]UĆD:g6Q',|l` OOI~K2,n^R$ϓMpVG>d!f$h7|mdBpӾ.Pɧ#/RסC_y q~ #گkOWMA*nH?|4{U=şQÿRicF'M_',gsŭCN>'աs7PUryg;2aå QSy\[;a>̩ޔiuMmI%9؛ J: 6%9!/nH2l[;w=mk37̦;Ɗб(лG[t S N%~<,*w/|_/͏ &âEs֦EMW},JTtn{VřsmĉdIfs̅lNkW|XcdN}q=k/;{0N|/EƂ a[Oe[.y_u{>,[yY wgmYv09OF˟wtLP?*Kzβ_0N6]m%)ɋ Lӱ.nxs:%[{í_ּoۿ}w}%;=n>syWx'{` a*{}$9<0>oѓ[L'by|KCCm+N_:W?''#T kn>tKWƯ,)k~N=:8̞-_rX&fNk/M2!eXX*Y>;4:|(S؆fyupKT4wB2s-FNpzO&M,]Z??H7>uؿ`jH]Sv:lݞMRs-'\Zl>4GJ@7=sφ붍x:z0i@NIDATvYd`Ở>>M +l;̌1YO~$*Ao5ST_liߙK` _4|ӝkr{7*TN W6'6YfOo϶4G*%9}o ߺ5im.|c_{"9aR#-N4q:S%ũɔғ dQ~w…#GCң^(<)P ַ._?0?Ìw-:S%YW5w?vXr]rI8G'.\tEfmNqx9,X.0i7\VNfos;&T\p/rr/|S`МL@'vu=M.7EcN$&`/[u\V&')~fʒ /0LN]Xvy4?ypᢋ. Mo|c08$Y8#~eĶ0YfOo7^ ^7fW^yAz?q7 <4pÅX4`*Ȼ嗎32}4_Ʌ-?ַ^s7^vtz\4/dfSK]Tl 3я^xap"_,[<\}>3j^LwuUWl@4Ahm=MBW!8:E[^4z Б0#2`Lu P" 8Ж0XiTsg2){“O>5L8&9'"FfrqӦ{>q?/40tЁoMQa?cvwrӦOW͛7-6nxł6=Bzܱv-akV7GKYr**w~Z`Y)Oum„3'M=#lׯc^eQkwF߽0$Y! ?F轓'qD> -''g!G]Q9tQG}3G;Gf}ԧ_yuT|K tAwݿ=5Fx{=~QCCKĺ`wwEM6Ŷ4?}(nWr+~ 6Fh}HS}=y'aya?Oqa3Z?$wȜ`GHN$qS8)@ Nr '9IN$qS8)@ Nr '9ttt Nr '9IN$qS8)@ Nr '9IN$qS8)@ Nr '9IN$qS8)@ Nr '9ۧ[ r ZR][T~'NK]џG[0$Fo CH掊hƊDNL6V,?&nLbRYMs{om}۵;S~M5'%M&&V7k5],麐r}eAsoR}SK}UYɊmZo-$J;/,QRa*Qy7ڶ4qT8麶>Z;{YKmqnmo-oβ1]rҹxDތ ojo(tB=ZY8ċlJvs~t^^hkۼA00LliQUkG 'U2l S=qv6,YV;ۍَn$Ʀ,Yi5KLHmjn1otN1gMˢ]i$7Yۺ5;:8;/in-nٸfɼ'ݲul^J|p+F>L-UG_6,hTlj_;!??d/KN75U׈~UEANN[kK&{k9YVmFT v_閚Ћp(V)@ Nr '9IN$qS8)@ Nr '9IN$qS8)@ lГ`D Nr '9SIDATIN$qS8)@ Nr '9IN$qS8)@ Nr 7{dO>3?sa9#9昢9؂i9=x/oH~> =zt8xlm'_2SO~1^s ''W,_"*2mN6!9`遇f />нq,܃?u&Nx1G/nKwm~VəaPxtB}eMSFa6i~zy]i*<ð%]D3?{=7omܿ?nܔ) nOVޝ3,]|ѰMc.?~[ʛ7o>Srk߯~-S>vʱ_\0=oΔwn7e njv3:gßp|`Nܗ)|uQax{gW=v9DC ͩܗO}SM=\vᔜ655e ǝt\"-e-}֍k']rd_Vuُ3. _|:u7'xF'Ϛ]ay1)l^)9mkk?+Yq7g0k[*-&'3GYr~40d~|r',{-]>'LؽF]CriӖXmW~ф θq|KvRܴ™LX_l4ܳ6^urؙ9%Ϟx V|b9S~pqE r͵+4Y:`bXtK[~6L(?_& 숓NkoVjP+q]k:,~3z!鞳vQ:ajĂn]KűvYk/lm/Л4Zo}k_Z)?be'w s qTꚞu ݳ. @*6dˮ6m 𵫳n"k8%'OJNC{R鳊3+2~L@G~(lMǠ)N+KS'~cW'')~c/W26nWlxaC67wzK4iF<#??sg>L:e ?ᄓOM3O5>'?]rN`O~OG?μ2F:;&`2mZ9G"9_6[߾_/a)9!쀃цqryWj^2 go>??. ySF᝜GHN Q Nr '9IN$qS8)@ Nr '9IN$qS8)@\NGGG}N$qS8)@ Nr '9IN$qS8)@ Nr '9IN$qS8)@ Nr '9IN$q= g0՗f>\99h.>>T=/ v{Mc`ZT^7T$ cs?$˪KsSspf֕&M]9;dkmɘNie{sSK}UDnĤ5u'Ul~$kZ;5~;Ԛ̑c&յtZ[Ü]+ӊ+\yxfL=ꀤKYeyCk;}_ZU߲?Iu=}?6eΓٞ(xRb'4VoK֦߮cv]N>ԁ=r4V%t]|YMs{Γg6{7oukt6]f/-d,{7wUw]`mygSu\Ut%v;7֗~Oݏ­vc6k* (d;yDֆpMηQr8`MO7LH}eQRbi/N?XF~ mm;;{YKmqIG_DM9˚ksmӓ DD)uׇڥ_1lF[b_vv9T[MOpٚ7f'Lܺ^KuRj…^lI_VnIUv/.O3anwZ^לK+nJRe%- qRoIŒ;[*'?fʲ4/vܪn"YИU.2GBONiMk؂5G߲%S& mm(.:UWMO67e1B6Vv=Ʋ`޺Зo;LfaYG3&(HVT7mJִniop.5g oꌗHw\ O\6yDbRq꺆Dyc#fKmUyۄcJ*R\(p2:QnUQ!/Im]nqUe↛+kw"UUDnjUUIltx()})k+9rM5.L ]_xuke:>TYz7'! >tRPWIdMa7s]rLfZZoȗ]`;i:W0es[ڇsgNrDIuN{$$K CcWVtU]IDAT6=q]t֩I[-ܘ]4sL>WUN}%m7&Jw˴46O,-)L$K ZbNdYY::]Դ)j1;ERK9Īamco9qU1Z˒[J-T.w'Y5/;>۫PP8!otlO۽[XΎm]s֧-3}XO|cf~l>Cz ޾ےtvB=_{n~~M!\LqE?mÖ͛z6/;;vHM5j{n7#l+wxvε M=@M'LktL~qEMCs{Gb`tAA"5%g6]?΍}u>ז{C4o.<}ӌ{ 9D}'-E999&+I6wkq榾z$U6b{Uijyi~z˦Dt1ɮRvLrֺfQifyOm5$ss޺J#F~gߝ<33eیn//?U{afGUTg[VpllouwXKMeFYR_\,>;vջS 9}' `%뛻MפQ^}ţIKjj[S76T%y{[_Y{ٱeu'.)8ջ5ܫ1C%jZ:/fS{Kt2AU[de͌9wsǽ'.9>3?l,Gw_iR2U4wݺIc"YY?sU g}3;gGT7eP?kq*;6tVQevrέf.z~i2?uE-a>wsSCc2`/yKSԣoH&ws~r:::z[_3sq,izIꢣ/+ a⵵e5O.|:|KUїqԅkb:5${I0{(:ASe>/(oڒds}qs#gP_RV}>=U{Z[2{{ '^G>h/4u^H{*jm+t2׮n7W{I߭gRWl/5ϻ Csl8麭enlyÃs 9cN1/lz~yM0z^;Diњe goYjt\FM>gᲧ76n$5>Yjl#R`tH:6}&^.>NN~q9|䦭Mts_ci$QZ׺qg>6M}g怱]Wrɭ-nٸfI졏͋>/3u,h|1ni5Isv)iyzf6V c蠞c?[>>>\ޏ ra'F&9' 5UDC蜌ʦ0ĵ֕\h쥧& 0s g(8}N$qS8)@ Nr '9IN$qS8)@ Nr '9IN$qS8)@\+AS8)@ Nr '9IN$qS8)@ Nr '9IN$qS8)@ON7m_~_~'T>HGUVY]ZMozAxC}l0d䴵u^{=z['?04FD"o0w0dttt㕿l36?a;6CɦM۟}?=>!FZryѣG=Ar #ƈn_ [?<asFTr|ʗ_y宻Y_`xO/`9gg¾{iQمV>QaկL',_1óg~ia;@?\~+.{߉x_կёvL8&7Gx㍮5n~L^f}6lrH>8Sx;аd+VDSM۶s{ON3f%ᖜN>憛Hw>xVu ls-W+9}qg/ ]~mѾ{3)0btmo=Ar '99쏝aQG|RQ%,*[z(XzA`ի^vE /Os O`ؚqUǪ[KXE/]y\jyrƊKr.]F_VBh)NF%7^ߏ@mgmG> Ư[̮hKGmxmA}ǑyhۇۺpA#Wo9*qI|R[Z.ЊCm+<,|[ 麶-g5VF0 ͫ3Zl}BGjnV_y ssf-!/iLU!]ǭZ:VE[2ܚlNÿ`izx}LSZ/X( y~ŦCP.f,?!gl(K͜?)05r0,KK,Lҝ2ؠٯ`JV^k+^ Q67{Hdz~FbA#)o?Rm}u(\1*:;ʥQzu:NVO4_s򗦍 luΎtA*){Ӯ{]8Zڷ5Hǽ{u}ߛçl,R}R* ]S%Fw#[}r ֧?ɓ{gᄋJ퐇i\HcT8T[/evڔӢC9H_q >ŧ>|˅+_+J&3}ˏ|Nlc9Cs4%BX_Y~;(U/^wQWE 7'@L,hL]G*yxC_%Ї9m}Ǧѱs^Wl}m_3f~Rh+Ƈا:vZq[K/{}ԇ>99_ >^mXխNZt?~ǭh;_Ŭq̧ᆱ ooٹT{IDATwvM-.sNr͛7Տ?6q?|>SZ?:gH'+~ҐwQ6mʷ~\w~vؾ5bʧz*zk9gS{Jvw̶#sH-l;?[xҎۖ1|.mHyW)O<隯}u*6=íVQ+tzy>)7.^s̻oY|,*淿Oa׳p+ĦN7 V5jw&S~}I;29O<Fe cƌnP#қO?瞛)|aP~1_6<ʼnDv~{$<'8=S^[!cfmG:vX 7!SX Of:G*ZMI')N5}V75FΏ}9vX.cy5hyޕY**^ɪ*Gvag2߼հSM q2;1 ЎKgfʃݭ_7`+D]~A>l_{0cAAx?6D_|q۽:䓊2m>|3}1DŽ:eڴ@{^g6z`ܾ+wT1cd oF`5jCsswqwOd =s莎L!ۀ|ikp{¡Wo}[3'z*S=䓙B"~)^~=0MЫ3HPբq_L}')0>wݝ)~|KEA駝vlA_x3e߷4'''clx̔//X_:=19}N% o>S^_wkO>Ԝ2K<^r=V~+i^~b>iӾ˔]]]tlu`6nxł6=Ÿo*+Dm߁]d?W=#yS~h|RQN~z?џ>r}ׯ_٘薛p eS؎(OG?loٲ=RX:;&f~>dY,GW_}5Sw}8U^ 쀒3X)0sr?)*477wqU[ձ*0k͚L;&?/Sʕ~??. Ӕɧ#9ey'3DbLy^Y hFL<)Sxɧ#HWr: oӔ3HP}gg~#m֟s`~iin~>Sv~}Ksrr_O}}CTwm`wQ'T)=a9?+ ܾ3?ykaZ}œїhVN¢}|~eGɼo}S>D?TqFg2ms򷫫N0_jo^U>. vZQ{ʠ=姏=}|7rk%TT` FhU?H&0m^9'.fr+ o\Xe][Z`$[~s?Ǚ--[uKNix=JPךn.y3곊ֽy-#6ʨu_703|\g.vg,_XY4+MUK=}FIɭKRwg7L54= og~wf(_rl֯+8`y]o>]xu"/Y~k24(͹u6^y ssf-Jh܆UWo?yIcf|'ffï*9[=߼" [Ô)B]uaNfO{6.%չuAaaQ+X>,fslj +R;ufNHܳ8ʢWT>ܰzo_}9fƺ֥VtF s۰=[ ~q;?T]P2.]+ů>0a W.]5/D*`(95>=~'z]s۹_6*t;$}®{q`7q+/ԾޯX)|aל77{eTGOйQV$mY )R*IYپOenMmYy.]b_iۮ^ ȨV,LVBO偤|+߲JUދœL/Ï4vIE|E*?eڴ䀃`D}%9ӑGr q9ING؜[ϩ t#9]`X {IN LJD.c}a+yyo {INW8%#Bn$K؛FZ[i?=OW=>_D:=~W͛7^z饖,>2)D<Ыᠥe߽#Mϵnڼ99# Ś5^_`;-8 %6m~//'[[ۺ|d֛;,9#pzhG׿n޼'^hIW==KUVyT>ȇ {LNg-w'''g!G=R3`Oi[򖏖+kڞ}7CFGxӛtxǏ;=;֔PW! 1]*Ь+VDSMoiJ8xlF`$qS8)@AZkrel~`INa7''29}ꩧ;аcUn?r-O?)p`' CO>TVmmmAvᙜ>)9Ԇ ^zL#ưLNk ث|s 229}>Sv~GGG&6rvaԧg޷lY L|>C̊KNix=fTryM*=aVmmimYEs:/y'h|auK&^MI\j镩BvW *q=\[{At}1brp﹮7vX`(SzժNެ=:JWZU^oĢA^ޑ=Eͩ]|WzxгTGѮ~?:>dJi!~ѻ;Km)vDa.rM ;??Oq`wiHw>=<$K/!}TWdP.ltr>H(>}aYw! a}u$**ɎYx#sPwUKN.I_Ԍ/=7jSY٩C,ȬU=jї&RiYSY5嬢*ia)W ҫN:MוvM%[Svi7vluW UWn)o;,mUk.?G@lKr '9INQ9F)@ Nr R{Jr '9IN$#\f-_"0-2-04HN$0ꫯf 7)9}[?)*)9Ԇ ~gʅStvᔜyG2w`nwyypJNO?c /;::7yᡪo|3Svᔜ o>S^_wY`Y40'zZїO>Ԝ2drjrzəg]f8%SM?|.Svug±(_Ly3n-v@ªUž2{77nb?M|[o ET{D<#yS~h|RQԢSCG[s!M{wU\y߲ܵ}-7Ն_rOG?μoٲ=RXEr[CH$kx=%Qޱ\xgͭ{Q%6.ܭ~ܜ°Uke$^ʞE/ ƕzW_:znëTj{n,9.~[7_?yvtAwݿ=5va6Z?\Wy;,\ty2 [ 7udVg& S:1S g}5}Wgͭ;<<ش3<17FbN%fZ|~AaYcӐ\ޏ8?J< ۺڿ5VYM{>{~Qi7u]{n d夙;;CəgI=eӌ.+z=re`%\`>eʨPxߒSٺpj?,s 3^ʾ_}ÊTg̺9ݶ>:ɂף2ەu֙G+X(կ3#u|)QS)Qwdv.SF% E'wHf'? 4;^Y Cvx^ƛW!jTotdmNN3me& ck`Nh}v >]+ŧƼgw Ҏe9KFkL}f[(:ϱhv'{Χ0W!0u9$RkIu¬>j-!m@S۶ Q{tvk-,y!E zS_ͮ~us QÂd{߲1usm-Tx= oHMpc0"HNG%1Fr #`WINV_9isN&9eh|US/ @HN$q9=x/qc0"s '9IN$qS8)@ Nr '9IN$qS8)@ Nr FS8)@ Nr '9IN$qS8)@ Nr '9IN$qS8)@ Nr '9IN$qS8)@>aT_Iշ]":Sĕևk7~//9m-k#f%aS]Z;::^81fNfo}/9ikmɘ-s|V/}[P2ۛj΃sJ{UկHl_,.M{֚t3όZTݲλ(HVT74Zb4su&m-()UrӉ9ŀ1L`yO{>=aᚦAνy3nk/ۺzh̼CntMqyu=Soz<P>ԛׅ^M\tsE~']h _`cU2#K3eŽǝF餳r§h1L`inVs|yۚ7FIwBK7w;&yD6a0gɚTՎ/Y2gBjSnxڲLlz…2M_}ۜ&M@>g$lbc3iތ>fSNXQMNjNڶ&`N%&M{mOoxؑ}6o?SmB˚ rD1dUk]]]Wҥ VԔ1%5Mf# Kw_=5s؂ISO*i\6'apx1MKoސd"SqŽj_Lw4t5HV44f0x -yזD -;z10t39xUeV31gXԒZ[}o0šY3ҥ 7Wwk$7ٺ#H$K+j6%kZ;:R`A4VWGO* /7!ƪLaM54_mږ0py][=l=et2}OơYDYu.>;sr&J4.!=Ăa46f'|#eV]8ΘyCuvZr:8M/mތd۽[TDA~*;-9)L,O;uSj{z.2RE1I$ӕ[{jtScڰ򋊲wnbj `ii, ŷT$*:1Q99m]̘3gwIDATm\uaR շk}ȴE>S؝vh->qɱEiJ767VUOMe]67<7JwNo?&IۜgR27s"M-MuUD'HרŌ)ԾdUCkg^C=NS*k;YPR&S^Ta}ޥ_)F9=i-?ݶ^T[h,U65W]Іл=PY4gkY\S펖ꢣ/ztbtݣa{=ZY|̛QcŏWn->sqsYNm6E[].(;kL~⵫Os7S??SMv Qc Z{9'v[it^^ 3̻i6v S{jdlTym_l167M*5:k6vli`[Tٸe fvU8V?xİr[6YZ kl[N1wFWM?w:0H{vF&9IN [{}Y"g`U5`@cma`6?Z]Er:EesZ^%#Ѝ$qS8)@ Nr '9IN$qS8)@ Nr '9INzMN_ˆuc's '9IN$qS8)@ Nr '9IN$qS8)@ Nr '9IN$qS8)@ Nr O~xx? Ӻ&gFJr9wN ӄVugÀ0⍐tݯC<v+KQjKo?3ߚm?[wayٚ?9$۱.)7˴B}bf溮+Hkz,cB 4JA&n<>//Lsw~Y~x|?ם}G>g~'S5_zv}>s/-)IE<֎ǥ;;.U6?7>[qO ?_ycJm}2u'|.o~:/qʧ'^uٯ'۵휻z'w\o탡]N|CWio'|_jǎ6[W/{O6+/mݎ;>Ļ;{e^{ON݉eF(>6vc>?7`0rVenk;srEfs۽8xla{f;'|Q䓊RQۇg\Tfm)rG*G5OW/gO|;Gv?))8[GŸϽ0p\u9l}{zk:pKoG)pՔT~? ѩOC<-ֵ ;GO?09}a9^~=!{ Sڻ3fq{ϻ7pO-H$n'9A$~nC>>_2S۷?W_o~{lA ~y KM.|ߍ7|ٳE7q㦍7&yv/?u紫c۷X)|am]o?Qw1m~ۘw՛6n/~X]ߺk˿/ll9X[f ~n۵S~n;?zASsyN߿~+WyWqEDž] JU5>O\Ѷ-귽/ 0#>ao73I&-~j.qbsĝ'K2oݺgh~n1ӫLCCθg~kh~n1“~o}#[|˗ߗ3wݵa g IFxrlY}f oO8 s._8o0L,_X~tu`X}VQaNѥ+Ȱ?]l A#<9]Ԕ)L6iW>Y'6|oIOٛ:gU:V {J*(0|YúKop!h'mmm'E[7ʭpd~L?2l'g?ydwwqUGȰ?+8!U>hn7%o|h|a7W=3s^ݦ^j#fTvnN\j[6&J5 Qޱ4uKNliSl].h=3fՙ۞}\yyi5o{YVopF%g-Ϥ[vHF%Kok~1l~nɳ'xcuó6!? /éijdfQ7~G۳-MvvPgaHruwEI>GG^au[!&۪ Gͷ&KDž(,uR3xF_Nі!˓/(,:ku,z_)sqՙ9U]ߘ(`m'6FR:g꾚/xfխ%W_]9ŭ%Wg4jDхx q~asʳ~u%_4<ͭrHFW:Kgb]9,# ^va!^~kVkGVsOؾ^}- ʸ,Kul)޲TN+X 4QS*>erwdaE-vQlwĂl)SF-;v֍DT͹ Ri͏J8{K.HT/:k[*tr+SEiS 3;Rlg#雪.̩lq{=gF:N^rSr7&g/{] BC:vjIDATY}OΏo?7`م/ok4k{wϔwDwSO)=a~f ;[0j& }9D}WF3Iݱ:Lvl)c+ٶ=;^5(&JݺmW0e ?m0f jU4M-]Ի7kWyya$=&}WWUTޛi_ ^Ug>OҴQsEr 8$lزvSWt˵e+/ 5jqŮ*=ji8o(JXeϭ឵aa ^rz[敿lρ>2/KGM87ߚA ~{g8雫jOs\Toy|pU˷԰V\|7;ϬӞ)J8xl>ZC9lNT+νAx'N |^)^ـr(ʼ ;s[tqMh'Zpa+g?U ?yg򣷾- "04,_ pO!;s;UT rs͇֛3g{a׻;~؏5hʼο-5v|uVarZ.xfUzɦk;n=#pZ!jf~s_7?w}뮩M|N:C ;n'~"z5>U~Iŧ&vĕKW]a'_6{v!KQ/@~][y"z]/''}% s ;p˂0~nA;?9ϘIN>84(')S.knwkw{j^F9vhϭv=h8szQ)<ݲ. 駟c}W=+J9Y~ڸrp9N+oz`sriwG^z/a,.^^s[?կ3xG_jpJN;Т;`#_~:Sx1Ǽo {ᔜFNya/%V_~'CYNGGG;^ˆ0?#sG$?= `Of}Nc~GL|gz$yaz_x᷿ݴO:蠃MR0NNi|4q{t~9-zgɽ55D*3&S =~nf0lMc &䄑'_{C}N;YyIE?/?޵7䄾=[<#c=#+DlV=E+8)@ Nr '9IN$qS8)@ Nr '9IN$qS@7IN$qS8)@ Nr '9IN$qS8)@ Nr '9IN$qS8)@ Nr '9IN {@SeAU-a/Gi}ع6՗%rreحHrJ4B5حHr:i~sGd@_6`0* Hү>M5ɂĘ섞ɲ~unSvNZ[2&gSnjٶ^&R_U:);&1x~MI99E-ۯ99ɚj_6/+sIeu-0ilFʆm)~5 3g/?SϷ ,s^_V035>t%ݞ*74Ia!E'~ՙw6El=UE^h-۞O7鶳q~I=zaSY阞.,[gݴpMSEAMU>T >j2 .[[}ۜ[KԶ0sinSꐧN 1qΒ5mi܂7/NǦcϼiskyqͲy3zl*MSmg.>$xFKkgӢ֎snƦҗ٣7O\Rug]'tӛL]O콛j;*w?j:IN[[OTVӸlN'w ',\\SR0eF K7tjiY_TT^KnAqe}©QyjIQe<ѭGKjZ6.fDW5e//+zzt'Î0ouK;-kDu9cdiEUm}ӦdMkGGjFΰ.->3U|sUmgg'.NNn"1l~u]Cs1*t¼m׏)8sukSk}!ݪCF_XS 2 7Wn P4QVw>;sr&JwJW\C 9&Y2=]hljn*vخ ڞ.:c̤Zjn\SlQUk߃g_UQBҒ%;}Wշ͛qB؞{/:%쨉=mNdGҷuErk[^pcc7?ݧ N{H^ϓ${9ai$wRYe}SK=e7͛];<;چ榦&u5:&#s1ksᜩ6^Y%dG{H[mmOJ0T$.HO*.o~$=Sh}|"eۛ8WUm(_Uo?4?eS}Y"dMkIMZ|ی-6JFvZsM27'C7]iu\Nse͛Se[wIͦnwrܐZf%뛻bM״ӋxT0)3ci]Mmk֦ġ3oo4k/;A%3o',)Ɖ͍F:/YVy1[S\u<6٭ffFWQVpymmͭazc*3Fϱ, qteuU5ntҘ2d`'}o}iŽΛ$ꢣ/z4e⵵e5O.|:|KUїqԅkb:5$Ri{(:ASe>/(oڒds}qs#gP_RV}>=PwӂԞ6;aƼVM#/.7}j>xO2k-e [ĦDAQOSΛ8}eOolŦ/kh}.GڿtlLշ]<}bם8s16 M[=DfcvsdN\tsE~QIN 7IDATBM9Pk/9:')C>qV Nr '9IN$qS8)@ Nr '9 ua?rr@#m B4%/G䌴GB#)#Q0PC-wP!J3;{{s{{߯{%|;3IS$)@ Ir $9H$IN$IS0)@ Ir $9H$IN$IS$)@ Ir $9H$IN$IS$)@ ߼{y衇xɧ~:4{'p,h<.A?ܾ`|}}/g? ⲿ''OƱ6駮]w|쪖R?-ҋ/7~}h?pìY}=ays%}Z )'ǼjZ{KmoN;^R[_{‰'湽쑟tl߲ξ]. פUW L Z )^4yecկyuP7\y5+׼p|/^מy0&7ݼ-nZ廿\ѱieoэ}o/p(TRrK/*>̓W]L8??ٿ|0*)9vcnvҤ k0[s?{{/})\% |‰'f/n}*([۪UoJuG.;vx`lURrwzΩCwoZxg!\kEek|gMKq?SN|]`lURrgϞsNkn[;#8'NşOSS75o |`\ϖtҤIΝw[GWM+ν{N9;f/4ck{5>oZz}.'iq +S!iJv=9w֋?_jڕmت㎢koX(1cI] 'um2je+k-'k}'u/]+yMc-{#P_{w>[^q_WUWF3;-}NA|Weg|=ѝOBazW7uڜXt[zr]dtZ7UQ;Ӟ[J}ST+W)K??K}`URrzG]g? R#zvut]8~˼]0\%%ν>wo\o|w88?}iӦ~K_ CȠҬ{ ?;7ןW?Y *'v?~?ξ/~NPtU-eZ;Ewo0s ╯|_e^P΍sQ@*s?/߮?o~L .\x' }0}& NNC߸v*o/?KN =)^e'S&{Bh$IN$IS$)@ Ir $9H$IN$IS$)@ Ir $9H ȡ)@ Ir $9H$IN$IS$)@ Ir $9H$IN$IS$)@ Ir $9H$IN$IS$)@ iR0volJjj &mK dd7 =7nh ddꦶތK`L@s TLӃmKMK߸tJuݼ GPCX]wyUknmm_e C۱1SUմֶ{)_[ݶ%Fft-j>`74`Szӂ]w@-s>A?y|)l8WuEz(̾g^_puj. ݿw=j^23([qCo}|mmKgn 3Y>z zߍ7f05tƥ>GotF֞;Զ7i_s ox\9+|-Z`\t8Al Pr7wooWj9z^Rn mZ{~L_#~ޞ?3j; N/诳;h 92W44L.@oҍw̸Bl aԣo-[y աW7.ӞO7ⓝMO4hX1uw>powGy5SwաW/]vV'74u=[맅^v0yq-:sFKkS}46 T[m|@SwokC=о5vO5U2[.+kwv`S o^5ӗڱqQups}cÇϿKwo\Tsѷ^y?=u̠to|TIC|>q}GoYӧ;u\=Ǧ)feRlk]T?y.zs͚e{Y_|8bSPC98П Ir $9H$IN$IS$)@ Ir $9H$IN$IS$)@ Ir $9H$IN$>IDATIS%mN$IS$)@ Ir $9H$IN$IS$)@ Ir $9H$IN$InwsC=ēO>0=YN{`ܫ ƷwbO?38=F>9Ե㎏]REzo?ׯ7x6iҤ+_+^\E|rz̫?Oq  ~yc/%'xBM]M?ݝO:g7tYw~QGeT KNñ}/֯WP v?㞎M7*(ݨFnƦM˛|ŦPA_[zK._wl ƟJjsK/i?<8iR%@_K{{̚#Jiֶ;tnVl * >u^DzmN0TRx;޼'xB0 v4͞]ko u7=;VUGlU`7:C !T>MeqkIQ}uq 1JKmU)Mu2}[;ʜQEYZyiqz,Y]ѯ~hΙh<a,ut)-p4]sM|M*߼9mm8l5-{Cn|qMi(Kj'"Ts~Pl ;#y?sN$]1/-v$ Rۺ/,rJK8g.[Iyr|v4-߶dVMz^J] k9p?XҴ:ٻn#0*N_jߝgQUl^\amFT)e~JZŚ]Cצcن'.̙^޾r/" Vsr6}2QI={9-(K=o}$Nb]#tV2)$t V,ѩpT Z>ɖh0\cmXn kF#S553 aAnɶm⒭CJM՟FOXUZv]flkpRq[yMOOas@sǯƆ`FCM0J_Xq)7R7Py+z/*4v|<'X>tRs2BpxMjqo[slM99:FRGji5o7]k.O?ưؗ%QQjE}% R,~՛u)[z mʶO"3MG)ti aA])o=$8S; nF4i~ex!)6ENiT5{$TsJF#:rus3R+x}dTsڜtзg/qfc^5m_OÿƷ#Gr)AnAr;T9Qxi>es~#D_Y)YhNVkaB:cnl۝b9"'L~M;2j$5jۻ c5=9GksV/=QX!WRZ1nZ> h)l79+S7J}8fзt .);eFR Ů P LHzGq"$d!*~Ŷ).UƈQfۆF`$&(vm ֬~mF< t%&APp7&"gȣV l2S2 T[' A25{t#wǔE=l5U;x$(Ӧ_i\SD$bO]V75 Vsɾ k_DˋhRrQXVsPBA֝BhwYbIʖtt[_sMeKTo hנ!Co,t=]r ѝf~e>~'q,L 9[J-Yy%C=:3GaE'ӳkUk_CqF)5T{<5Ә-xCy׸AvL4(ΖpԺ*OrНǘ)uEf#sНmMDU30kp_:uOtڔU k>\MݯB)?hڞ57=ն*3ߚ b>#pGCeϷ [Jv'w.#09MRA{Q dO9}O{wCm&tSP[.*3QM:[sVȾ KNBG W`[P!N[OׯYdD6k~MQm;@ćLŠQ]ksQ;늫64f,׷e7T"uGaׂ̮%y\`N%l+RjPQQɶX,P19_Xѹt"[-H_vnI:fNgGKRQU{)uA)Rvj%J2'$pS`[v[ '*}H#!ztwwk~]E 7baEsڭ;wXʔqR_OhkoR`wJnA ]X˿K-ĨYoo[MڴfMtGrV={l4.2ȷc{i^=l5 ((Ӿ~LCe\;#h|MW=TvAu332[IZ[ruz]_k Wu郫zW-S,̜\/ĕ*$) 2hۖ7r[vZ|\j￶rkJZt1*GmJm]edif|[ҳ%5!c̶.\W!wR1M&=-Sȩ=l+]mN˸&aB*[mG/Чk"ԨOclU`lǔ&1 "1*=kW!AZ.~{"K.uy38qMDUK]9L[˭.ǮGP{6oQV%ck?Y5׈KV[WDaktbQ˷ kxu%7wF&j-51Rꊰ? eRuhYm+'[&)4k] X7)^ەisGjΜ6zZϊ婕'|?5?R30&O5_|z5syjĩPhϑhƶekEeD:p7/xA+,-gMMcڔoBShJJ8˨ݎ+\;Wr} 7}Q-Z7,IDATZ{IW }]Î 6]F*V"K鿞W`:9C<(~ΗJ0p[#s.\땾 v_ms;"M6}6nޯDfQe'μ!NԚykS+P->_s!\)[M43LTҲ ~aN_ɄCVHWp8oa6IjsUkΖ6*=a6/+Kef~,鐷(m筈dZk)cWr,%CAi}տENeߣGI5կJ{e׸WSiM4ecQ'J*M|W@|veV:SJ,S.(F;A7è l۸ly5C~瑖(cnHPiAŋ2SWOf;)`=hj ZMaqd0jv7d'e؃4뤠tQ!\?ޖygÎkKXA{`4 hOjNKَ[Eum &/sv1TX·EUVJ7poWV2WCы6^R_Nn0w7d^dGƀQmcNvTsFF#eUMJ-6ϥnBBzZeݩ,hgsqf1Db}!Z; GiՖ5϶HMc\k}7g_fzMDNޖ:.ږɻP9┼v\H[_5zT,g,.sG-ЦQpMˎy .6!:X|Sjm JAdR|M0HbQjn+crS[ۉ}b_6~#Q*T$g]$Uh^mPTx=/^_]wK֕3-k篈e൱#c\Sk7-*B A=U6d.ZNAfS*k<2K]?錢;],Ɛmf5 6˩MљϷ>pmCa#]b|YwJEys>7r/"ݗ,H'XÖtJn>}@a0/د6w\XcA9]5"T#6lVOhd'GMQ]B]@L gm)!O1i٘{Ta+S`Gq@Ŷb綽M!,xm#]+ݝ-:s:~AEy; s Z+w< j !-}v(Q X^6}%B BR˨Y^p#`FQ,޷=OS3xOGiYys|1S鿞yx|U])Sn%mūLʑķ7;]jpqKŃ5]I˨?oY@ݘ1j7}2kǰZ -oe,p5zwg4홋܅8WMRr}6P~E&~kz^#56> ѱ@ }`]qFs[Wr[ͯ2W|`,mu[t׋TɷOk-e3K$,E+xߘ}vauTTegͮk0;K]ތPW˯ U Cj#ϙEnGZ"=˫Tdve!u;>5#3-ؖs>3E>x7"{jn)C=6 [όӌ[WX&Sٹ5Y5;j~[NfΜO7dQWAjƗ|v'OԯTQS&0%BdD888Xex׮\$Xi¦Cߚ:#saoedۢ{牄sќ9)x5sǫU1Ϸy|_ri/ ub{nχqwWHX2s>OY<3gۜZ}~=P@odVxuo`MVY2ۺ_}䑙I"ʮ8gN|by4Kߴ[b/3$V0b+c).5}+=l\IݍtEIڷki8|9ACx3僪-m8!QW|zKܼ홝Ϊׄ.u˚>YS_/#1twT>ޜgΓtv]Jv!Vue2OdGfUlܵlNΦ>SMV%ki`цFvՐsxa 냉{gku7Oz:"-a[{ز m9=OE4NY,5uh!ՃX\'|+񶮼c{v2 'I:y˖l[^׫g0}[T EX)vX5n5AzoiG/=QϮJR qSFYT3C7 qwLXxGT.HU?+S7X[+fgy[2s&s ^P+mc!Qr˟Qf{-}G܃n">YLg~tv͂mEŬt(y|tzoSۆfu+_{zf^ßv*\jSߝ.(n_>C*b&Q*9l)E69=3qw/?/(KMd˸Zk[{)iW#-@tSRŌ\[ѓ2V](}Jx\?.X\RyHYk'5;5K J_y.w.-Ʇ)B|ŕ2~}nCZ#1 [Xe(c%-n3F̏J:=clΗvMJxdcT FU~c?R7qvcb@ʘ`jcaWW=}.77aPы"ʺZ[zr]t`Z*_;\}K)u~"HK]c5sx ߺ~XO 2n=kJ>`nE_}K\Zz #[FΜ?e~T|^ H*m}n:AS=B2zù2VqO=f-6:}dcQCW֦5n$fnR 8n6/r{[ش g*i{i|;MGC'ʔCz'f`4Y9<)nj+{af0ġ{qWk>sg߈휆tEVXrjj'?/W4_ɠ,Ӥve_o?~ֹf͙O=߻o;9 V@F5<2ij)"yǷ/O_~_@``F56c3_7P9~կn_X'o;'@:oܦ%{QG[e'as P$IS$)@ Ir $9H$IN$IS$)@ Ir $9H$INz{{rhs $9HGIDAT$IN$IS$)@ Ir $9H$IN$IS$)@ Ir $9H$IN$IS$)@ Ir $9H$M  UUU E*Tꪄ1PzqvoYo`)_a<9 ^C޴à|0*>{{76ZΫA紺yKoגoܻx6mlkm?{@˿?gJZ13q'm_ڽ1yСotcCKc}4l?*7.wm[/M뢖'76CNfB?ijX=h9tJuݼ 9˴܅Ѷi^]uuvNK }~_ƿ_J"JLj-ɒNLRtK֮`{[+m[0-տkӞо}i]au }k[74Nɼ \tg^lؘa0Wѷ&j. A~>ќ3AwkƺsC| [ j>\ֆW0ߧ|); -Ҡ[E#_Bm[Z<=~19'OٓXSlf{+(ĤR}Χs:}=o(8T!ڜv΋3_m:<+Ύ>ϙz`y7zڻwr}|-L{?֪nj~uI0mMuq6vG]_8=|kϷ.kjۛF~7<́Tw]9+|-^0//]55. ƦۃҘM^x}zBSK s]cӜE]kϏ=[eZBw~Y\yîǟ =5X_Ԝұiw6z{ߦ7Ul/|_bRC__IĦ3.5\Qu *8TiE-&/{ƺT4eZ]ckkSY؃+fYܽy^u~/ݰ;7.]i_Q{֧G~ٖέKmߦEX{꒭[MSXϖ-8۽}Csck4K׷Fa;C=k#.mFًagKSfET=y{{eleTB^=1;V/:!L=GwǿSײ0<٢L[Q嗘>3r3+ʴEÑ~ŲyPrښJnm]TӮag_iZtvvukg0vo\%yƍ[R¦-ګW>:vutCN<gZuhUUU5qi-;AcLE:"pTVo#[u5;; 60_V zSI9f$f{%&쵏v+;ywkC@E*voO]:]8XrU=oQ*=mۻ2k/[4ttss:ھѢy}g j({7.:9_c2=Ȕ ;#wݼҳ'DquK5 /@o/jvdbKo}4g<}Ӄa>%S>X~k܇m[Ψc_. [/]i#45馁wl]_~~sSMP SS>ҭmҏAcZppo0-}JS8C55oh!wM KƗL +b쵏wnXT7c Ɣ=ۋ+_Yb@`-释/klݾ;v̫C>uՃ<'¢:]뵧^q3sR&Z0 ܾy^V7^!nܛ KkN^`bKlkRб=={;65s1}O7o醎9ݱ8ݞPauQ{y5IwjMu;e%k{){YFPz{{ {5hU{֜w\ѕPW:o'l[Z7Z~Žwol|Ew]pmMlko{K94T~۷dNbEʽ%vl\Tݱpr oN{s9"9LOfg}t{iWܻ7=2%-ԽmKH_y 4տkSkRyUl*|_d Ec@qQ P꡺in]d-2_v:scKn<}YK )k:%WuCVxz 9G+oexz]s3o8z%kS{wx+/[DA4 !a۶n{Jv7 JMC/p}[w4ѰAi&&Fe6moӦMO;ԙ3g֞tRpXڻwߏO~[78o]Kڜ0UXr{\ sοxCuuu@ƗՖU {izg®M7gc/[;M]vn /?/@)*K/?O?wI*>c`۶=?%3ڜ0UR862e?pشzE_җ>;⎷m_3 Z~_vu<PJJN;::7MC7񨣎ص+VI={⎳tVP&MtNq=URr_:8k"/hGL\SL;'&9H$U}NiǼ *SW@9< x?շiƇv=Чu,IDATR"9I ӭ8SnN]DS~+vӎ9x!ϼOg ٓpCcocHNб_u3}>{ĩ[_>>ݷ,g=Czgoyr֏SC(JT!C;O?5Ӿ=QDkk{w::[sZ:ʹA_`]uË3>t_xV?+.[}}E>k|~g|8LK 2߻esmz}sU1k%{nI׷^|ꕧ](fYox]!9:g~r X3 <|/MGo?vi?4#݇rsDYdOըYW7 `.Oҷްw̻=߾﬷o.ʹ]R}ܲ8\3Zr"^?TW! Y.td0Es^?O88_7y'3|g_HN`4Lllzک=w1GT:Nx ':ԇ~}3ϨuZ >>w7멧~0_bP'83&jl8w;> 5qӇz8= Gc^5-pjU-7yfogWף]rђɓ'H89 'pBOmqK۟?93F'vu1䐟ǔ)ÿp2}qqro߳?=bҤ㥗^ J辱͝)TON)^SnrӧOagΠ|__QGEv|u?Y??/^`ZuUǮj JwScCdG'p"&ihZȟ?S& (&?wkt8aM뼔weso9-|\:f? IӬCtx? ROzkO0q%}Op csiH8ɩ)H?w<`D7wnŽR?J7 fW2NN+N03q+_yL0|OM &;5q<{=qw0B&}Njkw>+صcO<9L8Gyv={1njpS8Ue1}AYko:+FLN:x`PɦLWjԩ[uӎ=5U~}xu9( Ir $9H$IN$IS$)@ Ir $9H$IN$IS$)@RUooo@mN$IS$)@ Ir $9H$IN$IS$)@ Ir $9H$IN$IS$)@ Ir $9H$IN$ISIxPUUհ;8Mrݶ?lRH$IN{}ÔbL:m[Zru iyS}˛,j>{rPg7/ *BKOyfYe3q @!t=! qx=!  QIS$)@ iR0N4.;;E5!UIS$)@ Ir $9H$IN$IS$)@ Ir $9H$IN$IS$)@ Ir 79ܾc@Ѵ9H$IN$IS$)@ Ir $9H$IN$IS$)@ Ir $9H$U|r}==O>Oc '̚us]wR;o?Ųg!O+_>Ӄqc@F>9Ե㎏]REzo?ׯ7clҤIW,WAFuIN$#iq-b8p_;K>zIm} 'PSW'c}_{nso:;n 2Mr %4.hk[[~no~k^"?qOG? /IDATo{ۦ^UUNr Ǥ|i/C_[Ò˗/}URӗ^zOv|7IE/_r%=X=sf̓G%ƏJjs86ށof/Ef_ac>vҬJ9wL>?~q ?Jjszqǥӎ"ۜG׮tZZ]==*٤r~z}&MN<d^q_W'lָw3*Y%%֓Žڻjɪ!еfaM;]5{ኞ}-mynsawI'AT|e)IGeFmm44vSh4tܹՇ6㐍MW4_Q^l +4v޼<7:w֬91qOǃ?x0ξfKS? FڪZHw.~!u_ 0|4mNutg>oCw_+z_E0is %4`ǎ`̝7wnӒ?^=ꨣMr %"IN$#SJ'9H$IN$IS$)@ Ir $9H$IN$IS$)@ Ir TCS$)@ Ir $9H$IN$IS$)@ Ir $9H$IN$IS$)@ Ir $9H$,sIDATpyIENDB`././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/configParse.py0000644000000000000000000000400515134002420015077 0ustar00# # configparse.py # # an example of using the parsing module to be able to process a .INI configuration file # # Copyright (c) 2003, Paul McGuire # from pyparsing import ( Literal, Word, ZeroOrMore, Group, Dict, Optional, printables, ParseException, rest_of_line, empty, ) import pprint inibnf = None def inifile_BNF(): global inibnf if not inibnf: # punctuation lbrack = Literal("[").suppress() rbrack = Literal("]").suppress() equals = Literal("=").suppress() semi = Literal(";") comment = semi + Optional(rest_of_line) nonrbrack = "".join([c for c in printables if c != "]"]) + " \t" nonequals = "".join([c for c in printables if c != "="]) + " \t" sectionDef = lbrack + Word(nonrbrack) + rbrack keyDef = ~lbrack + Word(nonequals) + equals + empty + rest_of_line # strip any leading or trailing blanks from key def stripKey(tokens): tokens[0] = tokens[0].strip() keyDef.set_parse_action(stripKey) # using Dict will allow retrieval of named data fields as attributes of the parsed results inibnf = Dict(ZeroOrMore(Group(sectionDef + Dict(ZeroOrMore(Group(keyDef)))))) inibnf.ignore(comment) return inibnf pp = pprint.PrettyPrinter(2) def test(strng): print(strng) try: iniFile = open(strng) iniData = "".join(iniFile.readlines()) bnf = inifile_BNF() tokens = bnf.parse_string(iniData) pp.pprint(tokens.as_list()) except ParseException as err: print(err.line) print(" " * (err.column - 1) + "^") print(err) iniFile.close() print() return tokens if __name__ == "__main__": ini = test("setup.ini") print("ini['Startup']['modemid'] =", ini["Startup"]["modemid"]) print("ini.Startup =", ini.Startup) print("ini.Startup.modemid =", ini.Startup.modemid) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/cpp_enum_parser.py0000644000000000000000000000255315134002420016027 0ustar00# # cpp_enum_parser.py # # Posted by Mark Tolonen on comp.lang.python in August, 2009, # Used with permission. # # Parser that scans through C or C++ code for enum definitions, and # generates corresponding Python constant definitions. # # import pyparsing as pp # sample string with enums and other stuff sample = """ stuff before enum hello { Zero, One, Two, Three, Five=5, Six, Ten=10 }; in the middle enum blah { alpha, beta, gamma = 10 , zeta = 50 }; at the end """ # syntax we don't want to see in the final parse tree LBRACE, RBRACE, EQ, COMMA = pp.Suppress.using_each("{}=,") _enum = pp.Suppress("enum") identifier = pp.Word(pp.alphas + "_", pp.alphanums + "_") integer = pp.Word(pp.nums) enumValue = pp.Group(identifier("name") + pp.Optional(EQ + integer("value"))) enumList = pp.Group(enumValue + (COMMA + enumValue)[...]) enum = _enum + identifier("enum") + LBRACE + enumList("names") + RBRACE # find instances of enums ignoring other syntax for item, start, stop in enum.scan_string(sample): idx = 0 for entry in item.names: if entry.value != "": idx = int(entry.value) print(f"{item.enum.upper()}_{entry.name.upper()} = {idx}") idx += 1 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/cuneiform_python.py0000644000000000000000000000511315134002420016230 0ustar00# # cuneiform_python.py # # Example showing how to create a custom Unicode set for parsing # # Copyright Paul McGuire, 2021 # from typing import List, Tuple import pyparsing as pp class Cuneiform(pp.unicode_set): """Unicode set for Cuneiform Character Range""" _ranges: List[Tuple[int, ...]] = [ (0x10380, 0x103d5), (0x12000, 0x123FF), (0x12400, 0x1247F), ] # list out all valid identifier characters # print(Cuneiform.identchars) """ Simple Cuneiform Python language transformer Define Cuneiform "words" print: 𒄑𒉿𒅔𒋫 hello: 𒀄𒂖𒆷𒁎 world: 𒍟𒁎𒉿𒆷𒀳 def: 𒁴𒈫 """ # uncomment to show parse-time debugging # pp.enable_diag(pp.Diagnostics.enable_debug_on_named_expressions) # define a MINIMAL Python parser LPAR, RPAR, COLON, EQ = map(pp.Suppress, "():=") def_ = pp.Keyword("𒁴𒈫", ident_chars=Cuneiform.identbodychars).set_name("def") any_keyword = def_ ident = (~any_keyword) + pp.Word( Cuneiform.identchars, Cuneiform.identbodychars, as_keyword=True ) str_expr = pp.infix_notation( pp.QuotedString('"') | pp.common.integer, [ ("*", 2, pp.OpAssoc.LEFT), ("+", 2, pp.OpAssoc.LEFT), ], ) rvalue = pp.Forward() fn_call = (ident + pp.Group(LPAR + pp.Optional(rvalue) + RPAR)).set_name("fn_call") rvalue <<= fn_call | ident | str_expr | pp.common.number assignment_stmt = ident + EQ + rvalue stmt = pp.Group(fn_call | assignment_stmt).set_name("stmt") fn_def = pp.Group( def_ + ident + pp.Group(LPAR + pp.Optional(rvalue) + RPAR) + COLON ).set_name("fn_def") fn_body = pp.IndentedBlock(stmt).set_name("fn_body") fn_expr = pp.Group(fn_def + pp.Group(fn_body)) script = fn_expr[...] + stmt[...] # parse some Python written in Cuneiform cuneiform_hello_world = r""" 𒁴𒈫 𒀄𒂖𒆷𒁎(): 𒀁 = "𒀄𒂖𒆷𒁎, 𒍟𒁎𒉿𒆷𒀳!\n" * 3 𒄑𒉿𒅔𒋫(𒀁) 𒀄𒂖𒆷𒁎()""" script.parse_string(cuneiform_hello_world).pprint(width=40) # use transform_string to convert keywords and builtins to runnable Python names_map = { "𒄑𒉿𒅔𒋫": "print", } ident.add_parse_action(lambda t: names_map.get(t[0], t[0])) def_.add_parse_action(lambda: "def") print("\nconvert Cuneiform Python to executable Python") transformed = ( # always put ident last (def_ | ident) .ignore(pp.quoted_string) .transform_string(cuneiform_hello_world) .strip() ) print( "=================\n" + cuneiform_hello_world.strip() + "\n=================\n" + transformed + "\n=================\n" ) print("# run transformed Python") exec(transformed) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/datetime_parse_actions.py0000644000000000000000000000362615134002420017355 0ustar00# parseActions.py # # A sample parser to match a date string of the form "YYYY/MM/DD", # and return it as a datetime, or raise an exception if not a valid date. # # Copyright 2012, Paul T. McGuire # from datetime import datetime import pyparsing as pp from pyparsing import pyparsing_common as ppc # define an integer string, and a parse action to convert it # to an integer at parse time integer = pp.Word(pp.nums).set_name("integer") def convert_to_int(tokens): # no need to test for validity - we can't get here # unless tokens[0] contains all numeric digits return int(tokens[0]) integer.set_parse_action(convert_to_int) # or can be written as one line as # integer = Word(nums).set_parse_action(lambda t: int(t[0])) # define a pattern for a year/month/day date date_expr = integer("year") + "/" + integer("month") + "/" + integer("day") date_expr.ignore(pp.python_style_comment) def convert_to_datetime(s, loc, tokens): try: # note that the year, month, and day fields were already # converted to ints from strings by the parse action defined # on the integer expression above return datetime(tokens.year, tokens.month, tokens.day).date() except Exception as ve: errmsg = f"'{tokens.year}/{tokens.month}/{tokens.day}' is not a valid date, {ve}" raise pp.ParseException(s, loc, errmsg) date_expr.set_parse_action(convert_to_datetime) date_expr.run_tests( """\ 2000/1/1 # invalid month 2000/13/1 # 1900 was not a leap year 1900/2/29 # but 2000 was 2000/2/29 """ ) # if dates conform to ISO8601, use definitions in pyparsing_common date_expr = ppc.iso8601_date.set_parse_action(ppc.convert_to_date()) date_expr.ignore(pp.python_style_comment) date_expr.run_tests( """\ 2000-01-01 # invalid month 2000-13-01 # 1900 was not a leap year 1900-02-29 # but 2000 was 2000-02-29 """ ) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/decaf_parser.py0000644000000000000000000001653415134002420015267 0ustar00# # decaf_parser.py # # Rudimentary parser for decaf language, used in Stanford University CS143 # (https://web.stanford.edu/class/archive/cs/cs143/cs143.1128/handouts/030%20Decaf%20Specification.pdf) # # To convert this parser into one that gives more of an AST, change all the Group wrappers to add parse # actions that will result in ASTNode classes, or statement-specific subclasses. # # Copyright 2018, Paul McGuire # # fmt: off """ Program ::= Decl+ Decl ::= VariableDecl | FunctionDecl | ClassDecl | InterfaceDecl VariableDecl ::= Variable ; Variable ::= Type ident Type ::= int | double | bool | string | ident | Type [] FunctionDecl ::= Type ident ( Formals ) StmtBlock | void ident ( Formals ) StmtBlock Formals ::= Variable+, | e ClassDecl ::= class ident { Field* } Field ::= VariableDecl | FunctionDecl InterfaceDecl ::= interface ident { Prototype* } Prototype ::= Type ident ( Formals ) ; | void ident ( Formals ) ; StmtBlock ::= { VariableDecl* Stmt* } Stmt ::= ; | IfStmt | WhileStmt | ForStmt | BreakStmt | ReturnStmt | PrintStmt | StmtBlock IfStmt ::= if ( Expr ) Stmt WhileStmt ::= while ( Expr ) Stmt ForStmt ::= for ( ; Expr ; ) Stmt ReturnStmt ::= return ; BreakStmt ::= break ; PrintStmt ::= Print ( Expr+, ) ; Expr ::= LValue = Expr | Constant | LValue | this | Call | ( Expr ) | Expr + Expr | Expr - Expr | Expr * Expr | Expr / Expr | Expr % Expr | - Expr | Expr < Expr | Expr <= Expr | Expr > Expr | Expr >= Expr | Expr == Expr | Expr != Expr | Expr && Expr | Expr || Expr | ! Expr | ReadInteger ( ) | ReadLine ( ) | new ident | NewArray ( Expr , Typev) LValue ::= ident | Expr . ident | Expr [ Expr ] Call ::= ident ( Actuals ) | Expr . ident ( Actuals ) Actuals ::= Expr+, | e Constant ::= intConstant | doubleConstant | boolConstant | stringConstant | null """ import pyparsing as pp from pyparsing import pyparsing_common as ppc pp.ParserElement.enable_packrat() # keywords keywords_ = ( VOID, INT, DOUBLE, BOOL, STRING, CLASS, INTERFACE, NULL, THIS, EXTENDS, IMPLEMENTS, FOR, WHILE, IF, ELSE, RETURN, BREAK, NEW, NEWARRAY, PRINT, READINTEGER, READLINE, TRUE, FALSE, ) = list( pp.Keyword.using_each( """ void int double bool string class interface null this extends implements or while if else return break new NewArray Print ReadInteger ReadLine true false """.split(), ) ) keywords = pp.MatchFirst(keywords_).set_name("any_keyword") ( LPAR, RPAR, LBRACE, RBRACE, LBRACK, RBRACK, DOT, EQ, COMMA, SEMI ) = pp.Suppress.using_each("(){}[].=,;") hex_constant = pp.Regex(r"0[xX][0-9a-fA-F]+").add_parse_action( lambda t: int(t[0][2:], 16) ) int_constant = hex_constant | ppc.integer double_constant = ppc.real bool_constant = TRUE | FALSE string_constant = pp.dbl_quoted_string null = NULL constant = double_constant | bool_constant | int_constant | string_constant | null ident = ~keywords + ppc.identifier type_ = pp.Group((INT | DOUBLE | BOOL | STRING | ident) + pp.Literal("[]")[...]) variable = type_ + ident variable_decl = variable + SEMI expr = pp.Forward() expr_parens = pp.Group(LPAR + expr + RPAR) actuals = pp.DelimitedList(expr) | "" call = pp.Group( ident("call_ident") + LPAR + actuals("call_args") + RPAR | (expr_parens + (DOT + ident)[...])("call_ident_expr") + LPAR + actuals("call_args") + RPAR ) lvalue = ( (ident | expr_parens) + (DOT + (ident | expr_parens))[...] + (LBRACK + expr + RBRACK)[...] ) assignment = pp.Group(lvalue("lhs") + EQ + expr("rhs")) read_integer = pp.Group(READINTEGER + LPAR + RPAR) read_line = pp.Group(READLINE + LPAR + RPAR) new_statement = pp.Group(NEW + ident) new_array = pp.Group(NEWARRAY + LPAR + expr + COMMA + type_ + RPAR) rvalue = constant | call | read_integer | read_line | new_statement | new_array | ident arith_expr = pp.infix_notation( rvalue.set_name("rvalue"), [ ("-", 1, pp.OpAssoc.RIGHT,), (pp.one_of("* / %"), 2, pp.OpAssoc.LEFT,), (pp.one_of("+ -"), 2, pp.OpAssoc.LEFT,), ], ) comparison_expr = pp.infix_notation( arith_expr.set_name("arith_expr"), [ ("!", 1, pp.OpAssoc.RIGHT,), (pp.one_of("< > <= >="), 2, pp.OpAssoc.LEFT,), (pp.one_of("== !="), 2, pp.OpAssoc.LEFT,), (pp.one_of("&&"), 2, pp.OpAssoc.LEFT,), (pp.one_of("||"), 2, pp.OpAssoc.LEFT,), ], ) expr <<= ( assignment | call | THIS | comparison_expr | arith_expr | lvalue | constant | read_integer | read_line | new_statement | new_array ) stmt = pp.Forward() print_stmt = pp.Group( PRINT("statement") + LPAR + pp.Group(pp.DelimitedList(expr) | "")("args") + RPAR + SEMI ) break_stmt = pp.Group(BREAK("statement") + SEMI) return_stmt = pp.Group(RETURN("statement") + expr + SEMI) for_stmt = pp.Group( FOR("statement") + LPAR + (expr | "") + SEMI + expr + SEMI + (expr | "") + RPAR + stmt ) while_stmt = pp.Group(WHILE("statement") + LPAR + expr + RPAR + stmt) if_stmt = pp.Group( IF("statement") + LPAR + pp.Group(expr)("condition") + RPAR + pp.Group(stmt)("then_statement") + pp.Group((ELSE + stmt | ""))("else_statement") ) stmt_block = pp.Group( LBRACE + variable_decl[...] + stmt[...] + RBRACE ) stmt <<= ( if_stmt | while_stmt | for_stmt | break_stmt | return_stmt | print_stmt | stmt_block | pp.Group(expr + SEMI) ) formals = pp.DelimitedList(variable) | "" prototype = pp.Group( (type_ | VOID)("return_type") + ident("function_name") + LPAR + formals("args") + RPAR + SEMI )("prototype") function_decl = pp.Group( (type_ | VOID)("return_type") + ident("function_name") + LPAR + formals("args") + RPAR + stmt_block("body") )("function_decl") interface_decl = pp.Group( INTERFACE + ident("interface_name") + LBRACE + prototype[...]("prototypes") + RBRACE )("interface") field = variable_decl | function_decl class_decl = pp.Group( CLASS + ident("class_name") + (EXTENDS + ident | "")("extends") + (IMPLEMENTS + pp.DelimitedList(ident) | "")("implements") + LBRACE + field[...]("fields") + RBRACE )("class_decl") decl = variable_decl | function_decl | class_decl | interface_decl | prototype program = pp.Group(decl)[1, ...] decaf_parser = program pp.autoname_elements() if __name__ == '__main__': import contextlib # create railroad diagram for this parser with contextlib.suppress(Exception): program.create_diagram( "decaf_parser_diagram.html", vertical=2, show_groups=True ) stmt.run_tests("""\ sin(30); a = 1; b = 1 + 1; b = 1 != 2 && false; print("A"); a.b = 100; a.b = 100.0; a[100] = b; a[0][0] = 2; a = 0x1234; """ ) test_program = """ void getenv(string var); int main(string[] args) { if (a > 100) { Print(a, " is too big"); } else if (a < 100) { Print(a, " is too small"); } else { Print(a, "just right!"); } } """ print(decaf_parser.parse_string(test_program).dump()) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/decaf_parser_diagram.html0000644000000000000000000072513215134002420017270 0ustar00

program

decldecl

decl

variable_declvariable_decl function_declfunction_decl class_declclass_decl interface_declinterface_decl prototypeprototype

variable_decl

type_type_ any_keywordany_keyword [NOT] identifieridentifier SEMISEMI

type_

INTINT DOUBLEDOUBLE BOOLBOOL STRINGSTRING identident '[]'

ident

any_keywordany_keyword [NOT] identifieridentifier

function_decl

INTINT DOUBLEDOUBLE BOOLBOOL STRINGSTRING identident '[]' 'void' any_keywordany_keyword [NOT] identifieridentifier LPARLPAR type_type_ any_keywordany_keyword [NOT] identifieridentifier ',' [suppress] type_type_ any_keywordany_keyword [NOT] identifieridentifier RPARRPAR LBRACELBRACE variable_declvariable_decl stmtstmt RBRACERBRACE

stmt

if_stmtif_stmt while_stmtwhile_stmt for_stmtfor_stmt break_stmtbreak_stmt return_stmtreturn_stmt print_stmtprint_stmt stmt_blockstmt_block exprexpr SEMISEMI

if_stmt

'if' LPARLPAR exprexpr RPARRPAR stmtstmt ELSEELSE stmtstmt

expr

assignmentassignment callcall THISTHIS arith_expr_expressionarith_expr_expression arith_exprarith_expr lvaluelvalue real numberreal number TRUETRUE FALSEFALSE hex_constanthex_constant integerinteger string enclosed in double quotesstring enclosed in double quotes NULLNULL read_integerread_integer read_lineread_line new_statementnew_statement new_arraynew_array

assignment

any_keywordany_keyword [NOT] identifieridentifier LPARLPAR exprexpr RPARRPAR DOTDOT identident expr_parensexpr_parens LBRACKLBRACK exprexpr RBRACKRBRACK EQEQ exprexpr

expr_parens

LPARLPAR exprexpr RPARRPAR

EQ

'=' [suppress]

call

any_keywordany_keyword [NOT] identifieridentifier LPARLPAR exprexpr ',' [suppress] exprexpr RPARRPAR LPARLPAR exprexpr RPARRPAR DOTDOT any_keywordany_keyword [NOT] identifieridentifier LPARLPAR exprexpr ',' [suppress] exprexpr RPARRPAR

arith_expr_expression

'||' operations'||' operations

'||' operations

'&&' operations'&&' operations '||''||' '&&' operations'&&' operations '&&' operations'&&' operations

'&&' operations

'==' | '!=' operations'==' | '!=' operations '&&''&&' '==' | '!=' operations'==' | '!=' operations '==' | '!=' operations'==' | '!=' operations

'==' | '!=' operations

'<=' | '<' | '>=' | '>' operations'<=' | '<' | '>=' | '>' operations '==' | '!=''==' | '!=' '<=' | '<' | '>=' | '>' operations'<=' | '<' | '>=' | '>' operations '<=' | '<' | '>=' | '>' operations'<=' | '<' | '>=' | '>' operations

'<=' | '<' | '>=' | '>' operations

'!' operations'!' operations '<=' | '<' | '>=' | '>''<=' | '<' | '>=' | '>' '!' operations'!' operations '!' operations'!' operations

'!' operations

'!' '!' operations'!' operations arith_exprarith_expr nested_arith_expr_expressionnested_arith_expr_expression

arith_expr

'+' | '-' operations'+' | '-' operations

'+' | '-' operations

'*' | '/' | '%' operations'*' | '/' | '%' operations '+' | '-''+' | '-' '*' | '/' | '%' operations'*' | '/' | '%' operations '*' | '/' | '%' operations'*' | '/' | '%' operations

'*' | '/' | '%' operations

'-' operations'-' operations '*' | '/' | '%''*' | '/' | '%' '-' operations'-' operations '-' operations'-' operations

'-' operations

'-' '-' operations'-' operations real numberreal number TRUETRUE FALSEFALSE hex_constanthex_constant integerinteger string enclosed in double quotesstring enclosed in double quotes NULLNULL callcall read_integerread_integer read_lineread_line new_statementnew_statement new_arraynew_array identident nested_rvalue_expressionnested_rvalue_expression

string enclosed in double quotes

"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))* '"' [combine]

read_integer

READINTEGERREADINTEGER LPARLPAR RPARRPAR

read_line

READLINEREADLINE LPARLPAR RPARRPAR

new_statement

NEWNEW any_keywordany_keyword [NOT] identifieridentifier

new_array

NEWARRAYNEWARRAY LPARLPAR exprexpr COMMACOMMA type_type_ RPARRPAR

COMMA

',' [suppress]

nested_rvalue_expression

'(' [suppress] arith_exprarith_expr ')' [suppress]

'*' | '/' | '%'

[*/%]

'+' | '-'

[+\-]

nested_arith_expr_expression

'(' [suppress] arith_expr_expressionarith_expr_expression ')' [suppress]

'<=' | '<' | '>=' | '>'

<=|<|>=|>

'==' | '!='

==|!=

'&&'

\&\&

'||'

\|\|

lvalue

identident expr_parensexpr_parens DOTDOT identident expr_parensexpr_parens LBRACKLBRACK exprexpr RBRACKRBRACK

DOT

'.' [suppress]

LBRACK

'[' [suppress]

RBRACK

']' [suppress]

real number

[+-]?(?:\d+\.\d*|\.\d+)

hex_constant

0[xX][0-9a-fA-F]+

integer

W:(0-9)

while_stmt

'while' LPARLPAR exprexpr RPARRPAR stmtstmt

for_stmt

'or' LPARLPAR exprexpr SEMISEMI exprexpr SEMISEMI exprexpr RPARRPAR stmtstmt

break_stmt

'break' SEMISEMI

return_stmt

'return' exprexpr SEMISEMI

print_stmt

'Print' LPARLPAR exprexpr ',' [suppress] exprexpr RPARRPAR SEMISEMI

stmt_block

LBRACELBRACE variable_declvariable_decl stmtstmt RBRACERBRACE

class_decl

CLASSCLASS any_keywordany_keyword [NOT] identifieridentifier EXTENDSEXTENDS any_keywordany_keyword [NOT] identifieridentifier IMPLEMENTSIMPLEMENTS any_keywordany_keyword [NOT] identifieridentifier ',' [suppress] any_keywordany_keyword [NOT] identifieridentifier LBRACELBRACE fieldfield RBRACERBRACE

field

variable_declvariable_decl function_declfunction_decl

interface_decl

INTERFACEINTERFACE any_keywordany_keyword [NOT] identifieridentifier LBRACELBRACE prototypeprototype RBRACERBRACE

LBRACE

'{' [suppress]

prototype

INTINT DOUBLEDOUBLE BOOLBOOL STRINGSTRING identident '[]' 'void' any_keywordany_keyword [NOT] identifieridentifier LPARLPAR type_type_ any_keywordany_keyword [NOT] identifieridentifier ',' [suppress] type_type_ any_keywordany_keyword [NOT] identifieridentifier RPARRPAR SEMISEMI

LPAR

'(' [suppress]

any_keyword

VOIDVOID INTINT DOUBLEDOUBLE BOOLBOOL STRINGSTRING CLASSCLASS INTERFACEINTERFACE NULLNULL THISTHIS EXTENDSEXTENDS IMPLEMENTSIMPLEMENTS FORFOR WHILEWHILE IFIF ELSEELSE RETURNRETURN BREAKBREAK NEWNEW NEWARRAYNEWARRAY PRINTPRINT READINTEGERREADINTEGER READLINEREADLINE TRUETRUE FALSEFALSE

VOID

'void'

INT

'int'

DOUBLE

'double'

BOOL

'bool'

STRING

'string'

CLASS

'class'

INTERFACE

'interface'

NULL

'null'

THIS

'this'

EXTENDS

'extends'

IMPLEMENTS

'implements'

FOR

'or'

WHILE

'while'

IF

'if'

ELSE

'else'

RETURN

'return'

BREAK

'break'

NEW

'new'

NEWARRAY

'NewArray'

PRINT

'Print'

READINTEGER

'ReadInteger'

READLINE

'ReadLine'

TRUE

'true'

FALSE

'false'

identifier

W:(A-Z_a-zªµºÀ-Ö..., 0-9A-Z_a-zªµ·...)

RPAR

')' [suppress]

SEMI

';' [suppress]

RBRACE

'}' [suppress]
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/decaf_parser_diagram.png0000644000000000000000000246746015134002420017121 0ustar00PNG  IHDR?0[=IDATx|u?$+Y2LLJWi:%],1Mq 7R0 "9epVW͑C?93a=yl;ӣ&H[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[ԭ+gdm3t9ٽkg)uyɬ~ T=BL]^5+S2!묟4᳟+Z{Z{tiռѽ4Se(Y:.]ܻRq9/q %P/ژZ!MFQzݚnLް`Eqwԥ~㹥WO-| *?}r.uwCf?ME-8{{Ի*u>4\S81c.捻ά;co^D<']QVwԊ+kZrTб'']Q?WU: wș6(U86;rk5nYk/gtQs)׌-Zj^azpxw(\3Ckp0!{Bil\Y2kj_g+zioKս][̻JE/nM}_Җ^W̛5~flcf:YpiԷ/)eEEFAËaÜ%wfVq:*p| E&= c|B+x0r펋cf.ui;[8*]([YVCl4ݲgMcu֗[Y[;SvŃm\4mfe˟wӲ1FFd ~"zVBC1GuIгvwÎUu[ϟTҒE67MZSZTR]VW*O7 aQINVqLV tsq{_yT.ֺD/4hǼrV&m70 %;,.),|0U{E٣'MwL@OiWBJIQ᳟76_m{om1%j(+M|u'Ξ7=aK-8+gtQiU\eceɴg-?O uԮht΅58;g(+K'gxO˪i~i4xwL#j-h)rcECU;hKˊF7ضpw4_e+'nTG5A/찛'׹-\?}iZUeȍUu!z;dwUQUWEU>tcKqWPkgN랫ޡFGk@0V!.]4Ag;^zkإ.^r/>K.@'"mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$5ֆ}t1$I$i @-I$I$i @-I$I$i @-I$I$i @-I$I}9mٸqӟ_\ '}e-/knN?ɽy No-6mZTESQ![oL iKܽofÙoTo`>}N/yuZ USSwʌxbQ2Ue+w\C9!Ӽ;?7}}F@}K룖Q?츐g%*k\>DN8>>vt\.ۧҖ =Ჲ:#>x7}:}*m3Z0:1xW9{t 6⺗йk6g 7w?TptN9gC/tATݖ}G?תWй%?&ѷn~ݴ.I!)=DQ\/HV-"fK;NהN)/+/.4yfn(.|+C:ziI@|ݖeŅ9?sY-^2^;i @g mHqØ1>{37]/.`wj.,+)36C7Z?йiIL[v,9b#˖5U K8>xڵ3flJҭM,;&n"{f$f~͝~UWW7}v@;-z뭰ҹI;fNA__^HkϫikeiIϖnY0ganz*ySY*,UueѤkXx#z,.Ӗ߬yf}s&ƻ{XT<ٯ_߫޽4hP= <݅9傜PGne2▲<37Zm۶Xjm?Aux do.-_͋2%QMM.>j9W<_23 F7˳ú!SV҅T)uKd [GN-mdnݺѣ^{4z'|˾tY}J ]ZYW}u[~|UaMeٰyk[Z1qH؂c-\ѰF]6$e`am79/+/.4W%.|+{7unx?9~gBus@]L&-[lLJQ97w}+eikٶmI#G^:*~য়Zѽ{FHV&$ZZ`?ﺫQ˾*:~oNTxW?4hg#z:z@הDqO_}p3>vm^{7ި4^z5nqI@I-Z6`!q򷿽þ䩊OJ <ꔑ' @'-G~#|٨̳ϝp|pigz޳>sˤ1ZvtPTxw_-^\ S#[n }}[nq_~C{'׹`)%2Cv\T;.wB&ۺukòGɣrяˤ~[um۶wnwIDATe˖}MS0>}p|aߨ>_ƌIY^OG/31??@&ۼyig0d9N>)J۳gϰڴiӊ*+{eKKJGd=:`m ʼ%;\x~0,[QM389O>SeXKX.,7ͺ ]tڨL["ݺuUWV>N ]FVV#~۞{fu:lIDВ.3v -I$I$i @-I$I$i @-I$I$i @-I$I$i @jjj Q I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$u mV69;ka?:kGK@'n @Q%C=qR IRr䂜~=)\\Zէݻv~C4z7=ty++ʞ\2HVMMMK˫K z ͯ0dMU;73*-6ZQ5kKg Қ@grݖq2nÔw[z׮WK>s /=,5k/nAuxyf[U s6 }-,\;5w袲f^ptԊī;oqd *6vN &V?wc  s[ U4_E9O= cӟ~L6QTR7M-g0mT߀;=̚O[֖Ð!G7Q$g^f,+Mw/|nʵ\؂M<}ҚyZYfL&e <8+O[_[T?J41`T\8ls5-wLih>m=v¹71c~ +fzв3yd!h˟UKg;v@Y u]8d{V헎2`E p왗N}i+6ZR/(^sKg7 +ިZ$<2.&=ɑ$I$i @-I$I$i @-I$I$i @-I$I$i @-I$I$i @-I$I$i @-Ij6my vObmH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I Ylժ/[+2r򗁇zqɟsNϞ=ujjj\[BēON0k/{#:'?rw Д> t hS]O!j.u<]oزeK 붼g}ΊOœK_Ǐ9ÇydӫsO,-)gv'wi[nZ 'ſoKF-tADG{ ?tix׾%hQW^)Y:lqᥗ^ [<<󳬬@g$7$m ʰD?iӦOm۶@p衇,Y|Wē,Yޟ:1&1vIu[l}嗣rn?&1:L۲~0nݺ?<._@3|xmg &1bmV]&uiyi^{p|^^`J_$zr޽{ꫯnٲ}{_ssh#Ce,[FqmZ 4)-)no̳ƅfyMy`/w9.*++C{]/qy`/jgڻw~/R!OGۿ\2vlˢ0% kM9Oiy)ФiI3uiˡE{i P7@qh dPr '|R`_tyq5kV^bN<1?.%In )iSOU,-)˗~s}pY@ Dž^@y@$7@Ȕ;rs~>^J~=>ꨏٳKF!#Җ^;-~,.-;(//k]X1Wf^^)MfLVziV^y!)79>Xk^:?qjATؼyg.y&t+aMO*7[5:lޭ~ߋzݖ-[_i1h7n%kΏ y:uēO;~iS䱟soT^xJהfD]w*waYyMɏ]՜9wx`׿䑣m77mlʕB# O?6ݒT, {U˷\ktmټWo=O=g=J=wu.YKRqjr)AU k\Ԕ/>q?}RgL[[Ef^fM<3m׿:Qy≁ddggYYYQy߽֭uvnkp+QZ5!,V65{-e5e Ox ۼ>T# N`܅E߻7o|%kϏ͕ RQ>!ɷIDAT6,F^n'v }SYڱtРA/󗗕E1e00wP^أ#⩞s~Ync};&+Zς³/ں}imX&nbJILF;oX{bs餬5sԵ=߬n?!ʼnl]{ҷo=\t>tG?ᬳF c9g/Ͻ; /X|ǝ#$`,KW/ cVI_c ^[g񅮻:'jz^NÓY3ͿȆW9ҳ*7iwؤNͽO9C=؏8O9gϞ WѣǒſoxΒKGTͷrE[U-Tkk4v_U?LZI/Y?f[xkԿǫk7ltXS ,, hR^Vzj6]=r u'KN?c{lzm?? хFnl/D^a[f0P_^nQ dwS:/Hgf=qqMwU-IA]]&5OUN\Z7?y ,A ޤ:Z NԨÁ3)Z\ZzmZݧ: OTsjlNڊЍ62Va`z{,O蠐7]ՊM_k ج'约m 4⨥KQ5޽dmQ{< .Yj}"u3fnJ=ǟ}=7r OEŕӷ_7cݏ߭_j߳SW'H&(5Zq]ӡfb7z6='uEN&b Sw{>7L׵ҖgZԟ]5dO$\?e(jb˺/HS~A]ѣ7)Ϙ{ zllZ)'-%[=l֞?їlښ5齥KBkI=DC{{}~zGx'%~u3ݟv;S7uHWHC;l&MDߍi7vD[n_g|I!{ͽ rzَbuF>鍬}-;{ή;}co1▉ua\,6*g9{K+mxkRWsXCIӿ/Z5^n~W]8sl uꧤt5U{3.=K`w[5vxſߣ;=~Ɖ *6O%z^ؒ7wY_'ɥK s/*Srf6Kܨ.>OV9+-Fi(tWۡR+ ]3}5U|WSqRM_nׯ >^Ғ3}d?=w=6zoќoϩCoL}ڡGNA}97g@(]_?TCe?aF C|֭ߔUVD7ömf}G[W_Õ/?لvoFvJ[x/׾Mj2;&,^n30Kc&ێ1Jv֌dfǶ:u؊]?{/7e=n7F )wX{nD2En+""շK S1J^q\3Kꞥ]Z%Osc9Q9G׷M6NK2O׫ꪷ:m)bک(BUx-՟@1;miP%Duk6%]dkiӣxjy[u۫yEWP?jjFUlRqFt≗^ٷ{_tO$owrP[I*:Mh]5h"g꿴oUnpä뎥r,7O@#n7KQcȑG5zkcFwB<'/vׂ˩˝:P/[ՍTR * TM?TU]{Q"3wM^A#K+: 6~kEX۟r:掙^rXey{KL(-jbe[rZ̦~_7(2)x-!4xr;z+rs;K>wE-@GjOwڥ+{nK g+] 6Bi{]٥V6QW.-jjm= +Wb͎>ZW5oǮ,ڡVڠ^$m隷~=mowHugn =c>u^}5*#*V<٭[C.ϸxEs1Ҫ;5 ugBtivcl/A{i^ry4Uςm\{-ޖM˫o(e:kqG<s?3Zo+m꽜:o+v쾴dm[;6.Zijc ],> 9wh Ik⺚#;Ϻr3/RB *7fwE˩ZuDi;]ޱ>QXm];un]ߚ_t_9>pG?Zu[Z}}tѴҎ%_/?.(Qk:X[?EmvQWʇ>Vt=d4sqڲ-utpӿQ-RpWvK?~|ח'_/>BH[ q]%g /w̙Ju6scc:7&1RVB{lٓq]:/_BEW^y%Е 23:=&#կJAP@vƢs~ Qbʰi׌zإڷ/.I*!Z'%_ث-ht4*_@vsNj>yٷ/L֯$qj͛7_TxwO:=haO/m\=%In=#9g^/oN4ٯ_%zĒIDATd5W6{^tqya=N:1?yQvg>TE:?.7gϞN%Innݺ',ǖ,-w~2tJ}Ͻh??~ԂYI[BgO#shsyJ;s]-tj+W>?}=itи|s_:=u[肤-t i ]^$mH I$I[$mH I$I[$mH I$I[$mH I$I[USSH-I$I$i @-I$I$i @-I$I$i @-I$I$i @-I$I$i @-I$I$i @-I$[D%bKnZ9+'k۬j$gۃV69{ u[u[4tZeMd6mǗi{BC/;1̺-Ou[ߩR ˦e+KM=4;_JnYvj9ƽNXpҦfm{n/`BqYuHƵ%E^\Xr &[Y1$!Cw.ZYرLNLQIeٴyUhݖEG]37z5g-uyyɄ֯o?9𕳟[99'졃YsݩflXO<'3νge@v.6ěo|,ke߻l W9 74!B[9&6HkIf~ { 4W%{Tsnn ǥkfUJi44$}_RavWq)SV5WjQ kwjAQehyGQK KeQAg7[>1U*@{=~GM f4j,R5oRæhX!!t9s&J6 rKX;olNolQq݀ B`\eRg0oq bÂJC{TN8G:󞵥 k]0lO_S8'\p]2>< q gw־6~`1r:3]x|+f?Q3& ]Y|]T}/'{Bi$`\]c~lh~;:Y)+*z!]~;ə;{ݚV0nc?x჻R2>MsV^5\+ZY\Я]ǒR]R8;^haW/nKUZ̷X*_p dV~M>{8W/Oz)LZW%2tmϚԇeoTu!}pSo{ƅ=3ƊwMBVwU>ji~׾©g;} 2jճyw۟@d_T^K~m> UTܵgwHiuZG 9$I[$mHR$ULjET-Fټm⒵L-FK5pt&Y555% I$I[$mH I$I[$mH I$I[$mH I$I[$mHRi;omta}S I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I7x&B~ ~t|z64\yv 'dQ?>=UnGӓwU?;EEQr7ffp 7>M~-JͿdîx3O$ҖŸBP$|ӿo'+>6Zd3n z1O^<룇 l@kI[2[ iӗ?;\TO~a'sGOl''m'mh5S“AϞZJRvLd~s:r|+v&mh;ɋS'맼iw`?cM.y!~\օىDnҖL8I <4?/T[尫~qӪciONI{=𩻮@瀾h o?s\w)>ZX_p[ZX3v?OVܦ=gW^>Bڒa^}?<>|j+fCXtHaW=UHϞ=E-~[2?gAmRg˖-pA0gy6ߖg]' <􄼼<_?+ +**~Ç >_.@->Ze7r^}G8"TWo𷿽z_8В(37۰w.ai?K/h%3|j9Ǻw>Scs:4C-ݍ;;?7E >6(>M->o2׮릅9j֍}@xꆓstQO\R?ӎe.Jkdioǫ:!- <#qᯯ)mV]U&+q:~}kVlڴ)@'G.tBR_i*-/mkCFw9ЮD|cGGַ$_>@B6cIDATwͷŅ~erh̽/J:iO%#7+m6溗^ N:1?@-6'K[h I$,7i:¼1sC7wLt=~--<{Ŕ^SUN'}nKA881nj&^:/;/Ң;]^n.IY6lSqޕ`N-aIJ7G3G,^9ffeFgəc윲ug"ʛFnm&m;@Fw붬%;e#tk@bڊ6=[À&TV=z@sMJI5$[6 gI (-]}NWsS+*5l>Qh6nm68ŗv Ū;ȸVBmgo]p7Z]2~fK5< hR^Vz} JLu+p4Id@gn-=mJEtnGJ;ΫkG.'su[_7.:nu3&^:0_sU̜x9c_+HCQZz㑂צglR^|EUrNk_cH/jt&j>6Zۓ/;Qቋkjw^m阠wL}2/6=LX\[G6T:|ʏ+DҐjs B!m3\t]F}-Q2̺K<t:uOխ+Ʀɤto,.(oPg/.\k:;W^w✂yT4x(jIp`ܽʽa]q^mn8JO]{-fsLJ@J%w=RRV[=(]܅C_wmMT!h:AغbEسV\9o޼:UkY038"]ӒOWKRӭ'>]ο_t*Sęc{l]4=kŔUaTs)wι+N;=.nOu5wR_?w=ޞm*}80df_DM( (;>c9`#e?[9)KH\-TW%kz+tNjOfSmaSaEc7wY_׽ɥ-zOy3T\:A9#rz*u-2}i!9j]Ӥtk˶ӵKUŃNlآd`ӝ(ۚ8lzP 7cT2v9$mF>gذ->Ko(.|+C~[_Kk[aIm>Q׆(k aƃLIw@t?ͽ`nŦ9ew^]?r=i߯ےQ7m\_#"`t .\ٜĞ#zĝ2y;tO!uBvҌOWKgm3&?+oQq^~^]-R1j+]?6]LjM-3E\&]zP_I!U=$df_˳9u{'vt{9]h - 3d7gn~jĜE\6溗^ NWOҰAPNr]wNмL||b[7k)eL6gU/di -b-vlҽ[Q۶m {Y@O[b/_K%<0.-w2D;}@[%@ٴiO?W7ߌ|hgnKZTŊ^|~0~jۺrnݞx>G83D-Lڒ{?>lEʠCqCO +Җu֓N7|x1Of|҉<x`o Mo -I$I$i @-I$I$i @-I$I$i @-I$I$i @-Iʪ $D$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mHRV8?+++2ВV-k?xq@ Zْhc[MΊ~͚kj,{BIKբ;,Vx 9JWΛ\ݻvFVV7}H+M=tCT{t%C˾jglX.=ppaK^vӃOo_w 9GӅ/ UD=$=9d5U;Z=v~UMBjUF_K5x.]ܻRq9/qLZռ^xKӻ^eKޕ`ݖ3J\S8aq^Hz+*ԦMX;olN* .\:oTjQx;/g켕aÂ͗$[]T<*]zpڬWΘv0d֬tMbެg]4kxY7gx墒7%oK 7MWUˊ-a؂&v50NnVVFMi\%lԬxჵ[\{ɭoNpT++gMEEMVl a@vvSų 8d$oNiAEœk+\10-ϟpB%BK8ls5-<8EJ[zנ9yW (h~n_cR9(ϣ&<{Qͮ y*mO'kJjl,-\=y^QTr\5GO.XEuݚıMHo=x ׭m_t~C{CVMMM+VX2aY?YW/*o#Z{~v=QU.} F-C=d+"|`ɒ<е鷅6۲e˿𭸜;Y֭HݻwM7s1 {¤-Ғ_~лw뮮Ģ30sq~@&m?$.sYr }q5$,;13YSF{ʕ+ '_.|dٲUVn+|SG|'я|$'^*]6[~}\~a<䓓./_U3~'t0| u{[ K>m֍ׯ֥t~7o~CwܡCC{Eo͍A'=cy6m䫿.֭۶m^}-[} {7@gwe oY֥-֢կL{\}KaQzG{8+^jIӫNyJH? y9+V<O\j:b{g`g}C9zL>q׭H%GQ]z󳬬vrHZi^4&Ѹ Ώ>mvq]~v=KKJ/=44裃~οz`ɒC<>niɃ/rTջ׍ n֭܁ё|ogk_&~TNNTx/0{Vٲe˔k>|y<־M?P%)|ʡG_>z׺yw3?].usFpmҽ{ٷ=S[$1A@הk/͟l֯:'|2w9'f'vYre\8]v"P);8㶚~vC,/f~ GUQwm5rĈ/UqGy{ꩊlxE#2)m}#tf/.Rz*o%7HAjucnH5d̲[u)g+M6=|SO;rM`Q2ߦ'~|W~hPH>~RQ_^6 ]X|}]~ڱt,k^nj3JӾ0qb+t޽}ɪ>f'uΘW؝d#SؕTDR!YaGŅvܢYti  z[mk׮v?oo: -왅١=Q5勯o0c-e5u^8,pHJ++ag͝RإM/&'Ґ(.Rׁ-~z-\ڲo-*HW&7֭[o喇K~ިn+?vY˖;^Jݶŧܭ:0{9?vѧ9uʔ={g}ΊOœK_Ǐtyx#?Oϑ:ʊʸpqWZ}~z9,~:@}-hmyOmҁO뒥/G?csEYLro]7:!pO~/KND-555O\~u3Їj Ϛ΀==z_}Gg>䓗^&zlKK/7^ݫm55'푮Pj{.EjGsnj,žSR;du+Lsc?;!>8ݻ[?O${ &;;;:y2*?zhɒW^qE<% yu:{/{Cj??WY:˯obF.,+o|+t^{s/-m˖-~÷r4 |?~K.zIx굥?]ԧG7wnqc^:߾OG34e%wӦ^[?ο ՗oD,-y_wݵCs_ڸF_9+//N/:Ӷmۦ]0귢#t\޽Ő, }և?|K}-q?< mɿ()O=*?[7dч>[Yl0Fё\2.eeeBΐ!<#.׿}+G eR2Gh:(.lٲ%Vg'ܖgNhr#F|_o<[l{^Ӌp/'|M9UԽFY&2hࡡ]F_r'O Z~}\~ͭ3o?|SO ~/9S>uБC=cO:6)+*'t >6mYo|ぱSIDAT릵{io|#e+¾G߿-$jÛoƅZX%\x~œ?Dt}_ǎ>:.3o:,nJykC؇~q7Ceg3&t&KX|vk'9ѿjT({c9ۿ_^uyG-ӫNyJT0`iM7rHZzi.}G{,YQ'ܡYUBvo- :t̿03m(w2rD@IQrg V賻^O>.$zN>mvqIc{OŅ 1w j-:S ЌLJ[g~Q99Q_d(l۶K&TW:3r䑧͐ݻϾGzݖ-[B&ʵS[<n i 9bė媸FH@{H[$mN[r2]&-/.LfuHB&-^z)tnZ$I$i @--֍}㬐 vݴ_7-{ I$uesLh˿q3.ϝ߼w6zU].mYծe*iKկL2)mwaZφ.N[?nׇ.,z,@Ȥ%%>_SSm۶]|Ʉ ].m,{k^)N}lt.:􏊋Cs(>ܰ{*˟hkY= lv˦,]<ʼnkW..(xdW$t.oK>}/nutd^^V( = UBa k l =s5X;U&4{{ɍ|++WtI'dԷ$*/%/S#~۞{fu#u^rC/=ZX[M5٥/.*|#(}mEE[Rz 6,:*W4XP"U&g;kҲ-E/._nׯmX6Dq[M6Mzܾ07w=k{Mu;iJ4dMUfF`$I[SW& йeR2hsӒU#슴 In(.. eR2r~ݴZ-Җu/:7-$mH IҖ/~:{ I$uesLsKkþ"/+EO?*˥-ZL[WI[:~er`Ii˸ mժ}6tq8B4v_>ta˟`A:F&-x/%m۶K&TWo@riKd٣^;%Mvc˗tT\sGqe)&n = fX6rbaQ0Ƴ{tKnl=|yjˋs XXSēO^y+׬ tJ7Zt 2n{a7+Q0 ]XZAJCҭ EH#=¥Im2 N47z-R3M-/L-M+_焪cMP>{y勢\f9[gvz}rb~~:F&-^z)~>',]ֺM+*ׇ0 'q≡r/:GXhnV*hŊ,.i/.z ֚}Mƌ%%gqƯ2ҧOfxA⼬1 ꌸ^6E[h gfGO)Š[CϜ[ߌ({w~y߽I@芽FxՕ+:ZU²Tr(sӚ*5FnXXbj\?3zSn)lJ~:id?m=Бhҕ\>ل_,ylWJOE;~[ Y~Wcsia 6Wֆ/3g`a:5͈^`ɒ.d @iKklKJ+9z⋩jze`->bT‰١jy7LaH#Iv O ;g;fdjy c9wֶ7✂[KGw^pFIDATLJU]*otØxN.=noIZ. ؃jjj\[B'sEq_h M_Z^SQ(Z~mlHEGٝۻC9o-z#mNUi2)mwsˤeC@%Q#= I:U&-/.LfuHB&-^z)tnZ$I$i @-;}G- l%K`o$IWի9lrCw +2NJW\QpEk|UqaHTI[9$N[V:mه=6mΖt_>!Җq+7wy&*Zφ.>mvqHT9 <4~;?/w ^ TIi8ӏɉ %>_SSm۶]|Ʉ QyȑGv't}e>zB4Ń Ŕk>|y\n @J9bė媸aꩊБ&X>gn tvO>;O^3ͷŏ@ˤ^r{_\vv;o?|yTY3Գ:䓢ax&.:k+ ee?liII @ȤeK/.s%KFȲeOymMztKnvlJҺ= )eDc.jY4)/n3]; {QgqOs^:FjIӧMn}>لgiS]Ѱa=ºš{([)Y8{Ca&R뇋^6%?+/6UaIl|"tݺ-k{Bw_,S ZTU_HY#&yYŵ{Y0ganj?VE# K[Z!r/ݑT ,NyyyعKn˧tu9ax=oHM۽;=Ôv9\s0?N]),DcFtvqWKrD~մc|V=wP p;.{E)jumǍЁDZ4Ű;hURWٍӢC;W>V,EGA0>.T3O\)mxa†/I?zU'])>[|ޚ7iQA.ua UW;ǎvju[tjx٢Aw(QS[~$stY>m!jq7 +|0gy 3Ʋ} g\uJ˟0&4j}mhLIՐ]L^rKbC}+Co8ŹyU/x a9ioB I̸w賸~4@--Eq;͌]}\>-*ꄾ0h5ZyY?^jʲ}mK%;I_E՞2iiWY7ijYD1`Z*[V+lju[ݕpi%;9҃\5 v-BC]|(*漒eQ5*]~T"ZK'f{&hN,WK/ɚ)GqCn=|mVM˗gIQ˂%ϗ\}?N,.,G~`}nT69b](UYMr(]ޭ"IDAT3˞zB?}?,mk}I[x/erb@#YKR+o.4@NRP,}J$knVej&Zcrx9ϭ␔NdHW2- $mjܰ81몟}?VeLgEVgMnLRb7TF S[`f%iK)_=uҼ}:OJ2$&<p s1}m^p#4F9 _5muԯʩa',cǎۼ6[ ַCFwJMa5n/mMڲ-ܯo,8mٽ'}oBh.Z4V߳ J>8_kq,2m| Ǐ1\\wKSO_t֞=m)++Ge~=ztAΝ5>7[SF#!KۑHmۿrqqp {tɓ9+塃Lsp褔m.@urtիC)3aa-`&:w~R>yFmyXg , +W,w;RvH{4x-KS mݸI)L}xRe2԰k,ZSΝ;++fmƌE30)LQ>^0v\@YR-fgrK[nE#K%]@M-j u%U\wM&i3KC8O!88YP9 5- XbޕVµE wIC~A^{#&c1EȌ 2ć d$B3JM Cjw>[ޥykFzJaT)n#y[֊iK.͘#F#-J֓ b< LcpC`Mt4t&.4+e2j#m0 mdFF}++| [/&LSqr?v\ZE6f6mL.7kj.},]& Tp^{v=3*'z'W;)E$^D$U]L@UKM֟S٠;`l%QXGڐ3ц#a;Z?+ܣH"M?]7XZn"$eZ2'WZFτ53ro#>[*/eu>&ߙGucW&3ݸE ڡp׸~B5 Q E-fDj"7Aa VCދE5AJQ-H_gI$BE~Ӫ_˔>+ȧN>5%߃gU'bɮfGRLʫ&G yk;D\}Ee.Zة4TF(5PҴDBWn٨v" CFzR,쀾Cy">[´(FuqDr]Yyo|R*m0+1\@e ߥk,ϐIS q"˪、(*yk(Qf8bAvҁMm#f\(إFҙ̪ky ]ek;KjO45 snK4p@ߚCH ܄'+I71Ed&$u{J"P$J+7 YM!ׅilo@$7r)7> MϾ D1[Ov-gT;@ nԟ',U5yu'!DG G^2W\1$\,8h#%1VE1߯t*}_9r/e"kC㯺_]-^{T -;s1i`C6_Ak<з2UQ\J*TpX|-oRwJšp↞Ps ާ)^\ZgAj$ֽY;_YRqR$Ѷb’I;8toPVVK뮽{nTaaOҥˈٹ@;/q}˯*G:K귥>?>r 7Odfe=v4%x;`D--]t/ˌzt>ӨlY}b/,4E-:u7f={Pŧ-rrZ=ޓ~5x;w.2s_p\FSmTh 7-smY m`SPi H[D&5@M-j"mPi H[D&5@M-j"mPF -j"mPi H[D&5@M-j"mPi H[D&5@M-j"mPi H[D&5@M-j"mPS,\5Ac=':DIZF<孼=RŎT15I9ZM | hƧ-yQn &+.޷YAӄJX֛>+ش%oI:OrNrcY&Ԑ~|]H;5I>KSD[*{K`so^h䒃K~QɡQt#- UD[7U[G7!E!uwQm\$ۑIr1.cB{k4AM1 cj&}vHIz,DIDATi=8hW2MiK~S79zI.ws8&=~rPG7!کqC?d#̥+MSw%( .Ö9^d9I\2%QWCZx[oR#%ISX*u{j]'Yt&T3Nh}Ӿ=g8,wis Gy؛w79uoPT ;h8m1(כǪGy!yJb^\LAl>"9W徿(:TOyCw㗶2Zh}cClK8>'m)rjqnCHxR]=N$6tڷrpXjJuyU/x IN{~ƾ« 2ePnKx-Z6ڥC0&ׯ6/vw 8y^1(Ŀ~eTUokظ• QqƼӦK\6e_jxZTc1h.yY?Oㆉftf4F^sLPw]v@5$}eT!%%a&OK3t{MZ|+Q8fjcF '@ /yϱZZXaLXL}8!҉MZrd'-ZnQf''WI)=%]bG0P7m1P]"Zjۢz>E#?dC\S =|j}ɋ U 3huBC}|(֣KEWYxhRcIs;KݴŻ߸Es׎XTв.;t}COA.N˫Qǣ_RM#.j}⢦sh4Abmz=^%.O͆v6yNhN,ni_F{Opb'0;$:1I?5|TWhavit:]3kiVg@1kW[GϪnSddžhy,8X{>_ϠyIk678`u{xگu34qv;j޺oz 5x&Z7oT_7ʩWYͱKi.׭S埒V.5P\]a^ΦEImh{7dJ>~-5װ)ϿtXJ!:ت, 捴@M-j"mP$B$j5M'Y!m1i?(Msewtq i}M4MA᣻ `N4:N@% &5@M-j"mPi H[D&5@M-j"mPi H[DzӖ.lSgh"@M-j"mPi H[D&5@M-j"mPi H[D&5@M=v|ٻ#=so}K?titgjڮ4fafafafaf_ŋ.Oukdi={3M)wo]E-/_"!57FfѣvOZht:]3~pN_~QF ٣G]`6nĉ|Ө-L8 u,Mdyi˶_~z>bpGGBXSOgeOG_h Xx)j:qD-D7tS}םʨ-7! r˃ポvCtX1FC)'C$R ]r%z?RyÓ<݅9%4>POHI/(8}l=no0tqW@[ԩӝwxg˹IU2Ժ-ZhOzl^`@;FouG@[%3n 4_p#Z:Ia _׿ hNԪkbIu[b7nR S$4˥KFWuqq~ݣG^`ˏ侽jUI῀ HQ n 4%-R /8Gh:>y#II:V+N{fTetر>HU- $lGbZfoߖH?kLetkB†@SPeeewwIoۡy+P!rssrرdu`+)Qÿ֭#j }@ֿXy/o@ !~kR7vLϞ=W~<|8?LMەVCoean%9:::;;{{ի]5zϿϘѣ8-V lx+Wd؛%).\y ۥKp_;8foTҖ,h V+A4|?Ν: hXiiiߝ>}zQͮ2h!,.IF/E)\<_R2RM%lZ>oo;/p#_l>e$,/_F];v0aBVV2jgg7sxygHJyySb^QQf[EgfVekջJђTklĤ$<;<|[VZjpwwOJ5s25!a^R|-`F^YR|ْlBݱcז/ݻ2xɒ]fHbҶ'OJ[gQB:ߏQ}/o#m35A);gBx{y5R)`%@nGʘqœ$n'0@lCj))99Omopw۷OС Zl/rvIDATiO"M!m3R\\  ZfOzᇏm={֬y%r#Z` CT\XxFA`SoIeЌ`JKKϜ=+'Kμ 9K0 2\P[f0uӒ53 D~ݖ%$/ 7unæL$4˾}9JM1a%'{gf&gvyJήK.;.3s2ťs~{wM;^pPBɅ7ڹsWB玎\LO)jJf9fP$KjI.4˾Cڢ՚ubZ~t:OM3 l2כ\EےBi Ը.N;[ٓԴg6|FMw7*GNnnSS^#%+4CkD3`߿L 窧>Ĥ$L`̸hɛh4uv!&\[w[\ U՘C)5?IHLQ"H׽'0#} :t|8{{ H>_}um3k &w{؟/1?{O2eۦlT^8QXW2jD 5.)MU(u[X mdVE2V"Mgn݅ZQ-C'aԩSY6i Vi˦,_8Rl~%^&+~=Vz%fz}bMnYXWoWOObun >l~&-FXd(,pUm94$b&[1wҏ!n=+x+jrgd/zX9_TbN}x'mK*ƖD-:c g/=j7ne`1G{ݻvJLܓԴgΦ HgDJT߫oQ)4([N[-»x?')Kx^/>; "czn\E4$jn-(Q lGk\R@==ЃCN?MB1<9H3-b(r,>`Yq{@i %L4Qᣏ?IL2gVS f7TqwwOJ5s25!a^qFlE=cauC%- 3g>|4z2xDeee,~U)Kw˗-? &<9IW0g$~?4]CzmҔ]rssKL4Q(ڕZ{F/-cn=ZfV>&Īj B,n˔ɓA0l}hd+ ]xtJ t?>+5A);g5J/Jyw{ߘh:`j"n~4OypF[+S;h45=jR6GehZ-+UΈIT4' ز־ ?:5]x\Un˓m8p` <r۱| h?i>l|g2œ׹ ;2Gs23 ?-3 o Yk if PUqqR4p@},[dgj޽r~8'O~};h)vGD}+oA 7!? ^ifDѸ?Qf]*xsoΉfyu2:9q"}%Yۑ2f\0'[ l惖:wuQ ~9Ӓ=r J3ŧ[~{'ka6F;99շor :uba._|把;kbgzE?f_ +&]RL[gĩ4u[QZnܤ>LGSF-k]\~gp޽{׷t?٧W^?/]:3g4رcǕ0_/=//c0:#ȓo_RpssjQt~[ AMB1 {v㭨C?aU%r 7Z7꯯RtM: k3 s, oݱ{hw>>߿_*>՗wrrzzZ4gQ_Yi=mgQw"t}ݜ[ǟ -)fk9c:3?m,Fǎ\B)#,s_+5U}gF;O"@#mKVFG ػ7KX=f2œ cM\uI0O"@\sW3zڥsWhgjrßw``нcnj)?IDAT:D^+Wdݛ{WjZbRi!̕Eְ+5Γ ő%l}'keJBb4}-))ŒչF_?I}ۆrhI@5g!)--i˦,_W7^m6HH79SN⧛6Ih3TeIݻw}s3tZiyMtٳ}*vFiعk&`ЩSdGGGa!,;mÒOw6؈}99 999==-Tҋsz8*m SXNNc i 3tu9`zIV\lITD ,)9W\37ѲY^rٳO>]_k***2Ynܤ Jٹy lD[]ͳ~[ ntf{4n`MtQ Ak\yq_a]ڴ->YǕ+Sk#'+]OdgWJZ_)hGڊH{g~6A(nw@}hI@J1S"ANH[o7bAvrnA"yzYyRq&h2+5ngϖ!Ẍ>+dF\):*;DIUiBxgWi|ͨIOwS2_m-d Z`[nMHLK_E:Ȯ49BHRΊ+Fshczy^Vz9Ư "(1)4:j>4+A,O''-n{_~X}rJfRVbTuH>u-&O7>6HE.WW(bЊ{y/Ϝ1]-ԡCgg;?ފ:dh/Dpmiex7 BV? 9 meR%92nDy^r9)ygp]{o:j)ˬcVN~0+ti+b5է~MJ}IGGGz-NgtІm!vEsS s= -aZQcDb">V32hC3!""v@lIXb68xL54*ȏsS^H$dy">X< O-*@3qCIIXCg,lӠE_(Bz,)m2y0oxz  ђc2оք@|HX3KJ[b7nR S0S QJZh$ kcϗ%-d}Q i H[D&ե˖,]&,˂@M-jeIݻh1c a~}͚EkDۗ#6KJ[<=3Ӭ!m1;/8GmDd}QaH[Rw,v_&lUqqq "XTr'Ct&UTT>[VEz̕;ӝWl~-Tm`LOm1N4v4_ZhW2b#ȮJA<_9E^emH_gyy~ li YAa2ؖFƭW,>Q0x>q1Z(ڳڂYf%*paۘmEmQbRitȑ}*hWF)X>qrr˗-D(qIO딆?F+ti+2wV\iD@ J/T%Dffg4W7^M 6*{v㭨C4~--ir {\!e._/0#<#qaFJR9B)sOЧ!Ϝ!@kprrzzZI ϗ4e=C+>Yv({U*_ٕ&G:yE;}<«թCzQi 3QR$ ;Ʈ/.EsSB!OdE1 #j<Њ5&<~EȪO)S)S /Oqn'y#+EѦ6A)JejIY;^7;Nnl) },ϨGnd,?\FjRu^˒Җ)' fIi^zq-Ȩ;j!m 틊x`MH[?`IiKMJa4yfʒҖB@2J)PKmDdWwc/*5!mPi H[D#%EXx#mPi ,)m2y`~nᆟ~Y*ݻ1{Ard~93hfcܷ/G) 6ɒOwxJڒŊ1-Z{IDAT-ix9hC$ kI1~/rrr{T8Sۿ`H[ZRwÏB속/0ǖ[nؠ?^hTkA@ˌ1oop'Ct&UTT_}2( B_eGJJ㷓5z\\Z{eOjHla#mEi]Pkr\Q Vn'n#<#F:wuM94 \qrr˗-D lIPH܌A&FKCkrPHə!YkDt}_0م5ߢ47kn(PٳgoE 2D)&".d\iEIJqJQo_vH{ 6=cGET%w#m`~V#.4k H˨xeIYR.h^#6DK"2ZH[Ȩ;@"X`3X)KJ[b7nR SQΜ=%:u@Phe.\ҥެ}9Ra=|hI`Wjyw̰gZ@RBPEEŁ-7 M0/(_BjZڽA`IL*8;wWF)+A^=J!co¥޳7;[);mV6dRN;RJ)//O;w)wx{~ۭh+$Pi`s%Tޓo-}םiwgnfv\ SƏۡ9}rX;F #SvLqz+\Vѐs{p|0Q 3/ǐh-`aO|k/cOv,MdIu[Y`q***2TZz>>v$ZܗJMUzxmDٓ>ky*/y~+D -vޕd8/"mfD7)Oj*?ݲ#%%''7hsF_fXRRPXO~\]{9| %VKniii_I-0 `ꔇ<;<|DƬnKYY+_U>>/["ڜ-IN<)n]VUmX I[&(qcCI[@;eI -..V ĒO9{V) zZNso ҹRxDPSgh"7)`zK.OmGO˝>-xw<` 'Vt+*i\˒ҖBe0q%#֕MOn/n^<7nwkK%/n!Ӿ>.JM,OVKȣ h KJ[ď˜O|te⪇"#-?}t6VN@3@5G{Z[̀ʉ,Q#_Gn-v(eGԬڢwx̚W_=I@-FTL1x1W몟rc2A m` URɍ뫶^r&V>T6P0-,N)۟KJ[&]|廔?I=f-ZzBx>V@kZҖ?gΞ%%N,+/sk]~k]\t:gvᜰ(./|qJٹZֹkW;;B~~CZ7h5R /8G.D-ں-.JhCk_*rp̴P'G!mf WjnSD-mo`ponܤ>LwM╎;sOnm;H~a`~’ҖW *ua@;N Oʹ"4>&Qw;Rƌ h[ :ŷ|@3Җcw@sF^ߦ?k׮6}&%puZ._"4zx ?Tݻ`~&+Vb|K~O@ 3YNGAz||eEiˍ7*iKi `._BfOﻻu ]Eh->>߿_*>zmyJ!vb'm9bRٳO>@eIP܎;rRNٹy `B0[;XOiWc論WϚ௼cGP ~ipyюx/r|$e8##C@\ŲKv*!KA3f f)Q]E 8OO_=9\zԞ!mm,֖H%l}'ke4!1Qˎt=44tǏ&wYs;MO.5U$L.vA!qEYb:F6\߈ DK YE#ox!]ЎrŊQF(NWYK7%[F袪{[՛`̸:kڢE9O9%*w ֚U02#~aDmHЙjǰvkDݳjzKDk,UjvS9KÓOqVΦq x)۷OС_zqX %O7/_lϊ+ƦpJiZh@IDAT!ʓ3C yϖ!vgj}4*jɜ۩zԲ8/05ҸɁro#a;|yaZZkxLҍRl]w%-C'oHZ]6^3!Kf7hmyvCދ4]}0]^LҁNX~#E br=V/a8Ά? ɭ+1seC?j\lzkx?i Xv4aDZj-qNXdHY$E+D'U湞&H+<#f-+ 4,m'㄰hmZNC(Z2]PEX6bd( C]2=uX^L7$zA1ra{/> S.f<9'}[!?~[իטѣ]; LܓԴgtJ]kGjlI;Pt Q2 )'ͰĔ{uy5҄to7,>RklB),EEEŐa}̎;^l:uq&n sO?+boE[ (j\ŖH;j-աCmD;`,\+MM ݛV ^c2Z_yw顯ܵ4Q#?"^*oM3zX50ْQH-ڦ6 ϰ,R"-0h@%mkGuhhXQQ!ڛ#2h@P\X;kU ke~3)VYR2e$689:::8\|KKXRghJG׷@);=<ܽzR \-;eWwձcGӬ{./h+{48;7#mIJ-!m`{wzs/^~Gȱx[ZK/kAYh4]Av% I_*^KqR06Ckc\"t0t(=8)CטnSNfoVNQ*'89: @-,ɏ6,0`?hw;32Y w^_w(777v-,I־}gNܹsw ,-/ǐhu-R t V%ۻp/Νҥs5M,,o[nœΉ@=ŷvNW.f%%>|k/cu8 @QhE?D-^z ~X;}yޮTΪԴ`H[V'=}gTF_`-vޕd(,_KJ[L$h[v>}Zmnȑk KJ[,=g>rDW^9Cl$*--Y]í0uS(6FS_$ۅs]tiq{Q{O=zKh .DVUEJxj)j2x?Xj@[%v&0ẻOLemYRRPXܲW}|-_D9iIɓR_uA9I[&(qcCQJ%;;[) 8PEXK`'m)..V zҖ3g*KI[nᆟ~Y*>|wlU.C%?l<oT 9XOO)䐶vcIi˔ɓι>0^)nh1YR u9bB]Ot:欧%Qǎ\B)iۅs_RZ^t>l@.JgxEHH[`2?0ڂp]|YBU͚izri"3It|X.DSEl_J9{'Oy$ꭷv!õR2jH)Ja4{Ew%ϖ {b)(+"-_gDj"vrnܤ><Ŷ%l 6&$&JT ؑ}4J mtD^H#RR*k#'?#Xaa6":,pj8`}'d[oիOL=kMTP^u/{=Ys#~$rȅ>q1u]$M[9zλAݻ7Kl%mi='qDtI;Z[)P]yt?aW Bs-aZMt̄-T4y792E,k6XmڢS&O(5y nB[ߖ->)10a!\}'f0z`:tќܷW*)9WQQf[;wJѱ^_^zqX8{QB\E Wvٕ&G,T41lW^cFKw2x2qOzSӞy+CEbO OwN믩2]4"i`1ц).A$iS%R+/ &qmfTF&$l.fڕSK ]0K~^hITTT +} ۛٱcڋw].DmZQֿcoo/;`H[5zH5Ai  YL$ 4h!m).I%-p5h;T EEE`,)m,ԱcǕX;Q Zmi=-`%./seJ[|kgIiKMJat Q\\aR~pxv TTT##h'7Οr`K0m)--YNyxÓX[rҥQcefUF]\>}zëW/ʬ*mtO<5 <jXR2eOLemYRܲW}|-_D9iIɓR_uA9I[&(qcCOHI/(۾۱Cxw} : ֓dgg+ٓ>}FXӔnU6tSzY6ӿq,MMPb0h\/U2/`Iu[ {Y0O4˥KFgz=קO=zx%`3:tќܷW*)9WQQf[;wJQ iIB:!uZVH?IØѣ{iLߕ*̆͟O>h4>$1)I)߾-7Y3g*[6lhR|-W}|-_DF-_ڻwoxɒ]P?YbҶ'OJ[סߏǎrv@E5A);gZOHI/(۾۱CZ=pw۷OС Zk/nj-8dJaZ>ON[{>}Z @.N.kH_"wohAYoԉEV\\  @U/ON/Ds dH[ԏD3g*~~sҥQcǙ.sӻG^z @k:xѣGsrr^\EEśQoܹ+!sGGGt>)"@,)m2yˡxj)j2x?XH4=G]Bߴil#F#AԒ]X>$1)I)߾-څt5s25!aZ @(++{eJǧeK]|i޽%K~w@P.sWp|h uG{\諝ty0yXZZ*7mmSm{Sgh"@ߚƍCfkJt@uKnMJat egg+ 4p_K,YRRPX(B+A4$h9sR'fç_?PTT$h-!,2J)p-j"mPOFlsW].uG}WLs2Kxw~ԥDՅ+ÒjTg.퍴4isf,x{ 1b]ɁeKw/x^Z$NLzJ~(],= N|(Niz)[6+뼴(zTY >mK4@"mAsQT-AmnWF ǯ_YbĢ|!|DAѪ۩: Z>S*5U|7VU#yt;mڠ)eCUCj[P6n^YB Sc uOTIo]\i CUGNo5g_L1_ն#ԯOSJM_=bI'h=8Oc?m}]g9qՉ?8iI8gSy /-o<_0ޟ+u~iC er&1|h'qhwLܰď9/=9KYl)a9$m,^79.nbhPceҦ xJ?0Օk %YR fer?.Tjjx|Djo8]h@M9Nx>UZT6~~mvsɇ,խԜ*-ϭ;L[8wr J7'5qh$*(5/?{ |EeUn۔Zk:TۧJ&ؚ>`\ʢq4J+!b%6M4f4'VLQ;FqU6GҦ0E },]_{ 6%㖟j1AG'hݴsF/J?4vǙTW~7`Ώr}랗l~"v12Γ;X?(.Ne{T˲ކ-]o]l4?]وE^|0q(U>uN4޺D(X>Nso "}eT ϗ&jɺhO?Pmn_aZOWOJfi.JM?u|[h$N]ݸI)L}rŋMvt+h`̼2v?mMڲ%.<;|Fg''Tw" eMl̢  ,9dѝ^{!6u}cg EJS7\i]irz˾Y ӽeggI 2\fa.1,nAa@;̙vg HN:m/*|$w˗(ʔɴm&.K2 mGωhȯ%%_ܩSGvm=^*ϟ}Ȕ6cǎJٹt;'C KU[,e(M/(ܶQ#h".K4hOFCR]4Ƥ~w(“'Mu`;F o=={}qKZk7he/%}q mAC}]ү!ュ_ܸ1ztﮔwX~'I[|`RݰkIKn`Z.,:wl?8Av^ѱ2xRfy[.vXRq29wwx{K3g>N+**2TkL{]X˦͟*Wzh[7|KxI)oظܹsU37.vXRRPX uر+W(唝;_jۓJMUz[X??_bab<=,g{論WϚIyiye5uaILLR;_҅B~W]xTϻDSW[1\%IQu6zIXtT?xy;v̘C[AI?8ޕdZE Im2`Qvķr/a0dA33˅w,^N4>\uDE]NQ| 3a??$h.f{nX2J)Q.XkK[$>_}2( R3?dHIJ\.kx]1h#EtDiy闥"B EK,YLJޢEDKT]Z ʅ}P[rrA嬘}++~d|93c_rTe?)ưbNӓKmU,NED߬qozSٽ{ǏwRvZRH[`hWVNt?\7!4USu}j62\D(!\X8e;vtww?qD3>^>^W]f/S4g;|P ID7:qmf~ol̺<==0tć&D ''>ݼ|믻Nכp CMZAXqDX\Z(-[,6LZn}F<:amNX oD7]%M>,y3 Qg{=^^{enzkqݤ,K?6_,,>R緵A׾4?Gp dʓ?WMgiDyrD X(*o"rM2H_]#859P_\:Q-O ϒt} KT~ W 3䃯̪s;E>k:ͪEx=b7kir^QnݯL'N qh.\[t>u={֬y2tZ__ ´EYy[QC * R mXe{f _J|i"h9LѶׯ_/Zc4Tl` jjL#sLYQ>hga!vqF 0>X;Q7wEkb!a= ҹ:Ⱦ~ёszEV`*z cmWcu_y,/j ¯J몊=cªVWU{Y!8i0߈R7N*vvt_:޾7+ SoS|}DhKjOlI[4w3vFwΓr.]5v\f^eӧw=nή h͟n G4]ܑGI׿OD%Zp6K99oZURrN2pE;9xѣGM{UQQf[;wj߽%>B1pa寞JIϿT:_G3W,|@jpZWC fB MVȚg[nt[w/pQ ǟEVb '.':uNZnGJNZE*RSbe( . ,m~~ٙewٝ<3fsc&R0@+ZX+vMH v NܣЪKL6ܠ+}6=Gck'^d2yt[2$**{Ƈ=zԨ=z+jtY)ht٥ƒf.43z#?q:iGLٴy.'=UiNƱ C);kj1J_suRzlHkJ F鷵T:c?_rq=?sfʿˬCԼ1`9H^8>wvBF3Z[ ~ lgJReÔ?T1X@B|J2DűG2)n~KL֥'ft%=d]Z'nˏ~y kG sgA | fe`C2oBrO [ IgwB壈zzm17!5K._r `rҖ]n.6eð]4ht钶:V~zw^W_WhgN o5hB&Y,PA:7>Euo7xCΜL&X9BEvnaT 7fnWJczAwzyU ӧOwۅ  ë_:O Lth-7fClfӽW*۳m۶EW.E{ R^^>d۷Kn݂nnѢp:*tPOZj",MhN{ݿ~irj]*&$MZt}0ڵ7M;(=~EJO.h`rcSSwMW"`(7]4<;]fJ={+1Kt&uDAMoմ#+.a QoKW)#V ƎnB HǫN<)E->{qޖhGN̙4Gx:wB E h'E{=Gg¼3zCZ3F+nt8vMMmaۓzŧ4yt(?%77W) 4HCK^yd-{M|ypO^>u&h9zahO3x %ȱl=A:E#f5~ /JaB=F/y?WrÆ{QJ~?u[[旙;*:<0kc]4aمGWp--sLsFԟz=ESӻ'>n@"v2kf]4RpWh)I'3RMҿW]jIDATЍ.].S {9?\'WcDiQ“8oh @pa^![@lڼYڑڢfiQ YRۖ+?T S'3\.=())1r}2v̘C|||fϟ޲%3s klӥhT-|h#Ro_2e5M[9U9򝷗y`ԲuJI=Zn]L:usҮUxuF?-m]7mmPg!zЩS&O,&7jw^&͆Җ)&}M7ϘpN;yᄻg @skP,VRR8d2 EGO2yIZfFo=GE}׷[n={.f3HeҔ[m [KF @=y ymQ˽ _}41-mYC0urKKK =xT ot%M-ZeNIBZ^~FM|R7vWt%77W) 4H@Ӧ]Ј?N @eϽH)<,8-JaM;~\)\ݧp-;u:rT_+2e a@3 tY)l۾]~ҖPmi p-7xRXbm\&q[Ld3/wݕ:`0-](7s[h rƺu?hr&dXt}#w-y=i0%7$T6saRώ^Vi1/D΄)9>1K/4UsfH/yYsdr8SB\eK1c9xj.@)89% L/,IJG%UQcK2WqJr׈ي51Vg@#ZzU??7kH7an6#C흒2_Wk?Ә--#x7D- 7#daNjkLLx>GDޢ \3lدwuҿCoy4?ZeZn= @rfH/عf+>!;ɷ̛vXo?%s%wM*&d2:thMo,I3nzpffBKi[] 2DO0DDf݈,RfXf&dY%coa⍢ yaCI yλ@ï1,--fC=lZn}8&G -H+I]zy[mə,+0Iaqs̓즏c hj-m?o۶mWNu֯NUV hm @MsS N缻LNgLY^i>kfgcF~6_7$*Jii+TH{ar#m#y|i!+sSz˽Zl8'J'YaPtAb@Bd?..&0]t5}rիW@-]ږ?,nWv' y*//2lۥrn[dhѢb[+@@жp!//eo&H={+;Bz=jRN|i r R 9wz4!-G@ﴔL4Qjc9 @ﴔt " ڳ'_) ѓp۶)tEliKxY-k._B)t wZJ[P)LpІ;+*:%{1buwZJ[8 M#7lPʯ`'6o޿ڥ}`Q jZaCf2פ&J9'QϽH)0\.Ӗ>^6#c۶?|ܨ#y{4M[6mP \>Zɤ[&KuIaW}q{6  cm:)j #G.R~~7޸o-7- PɓE۶ˆZt b"="p- srBUIDAT_-i _~ݭ hѢ@=9駟mܱ3]vٶ4_߾K{􊊊:w$\om߾-9BrH[*.>+ec`@=tԩIi;~\m۶}ʕO<3O=;n:x=oMi۶е&Xo{Jkr̨-[.%4gP ڷ7tɓE %G*y 8>jin\V֮[!sϿ:}Zm[*..V \^v#G?qB{u>Wt҅Kjd:p/ޱs[o-+Mꫯ/J8\M;<<{ iժ)WCJƕ¹ske2Y Q@H'2=s3OͷA뤰,kcȣ%Ma{-^y?E AfkY&ZJ[L(ӹS'e#,3@q}JwwӍ7蔟K/3|wNˢAv*!QQ\/u*TS](7x??_eܙϿJo QKs0!{R;ٓ/dSOKvﭥ3jQk@ut|Ԗ,rܳG=OA+&.\$9Y'>cF5~H[4SR= w4~~~R+O>Lߚ5i&8IڷmT5*Ѓhڌ1 :^9~DAAROfXtݗݮ];Q9J!**Jfd-h⵪5]jRڲ|Jad˅9r p];\B >I~}[j\4ȑgfq:jZ+h)m<Ϲ8뮠r>`nnZlٿ_̍Cz=ܶ 0@kO $SБYtN}\A?=:wtQ}} Ä=u gshvP ^zh(=L-ڻӳE\v٥Jǟ~~Ͱ4J*J0?d^&M)OCwũS''} _OʜYC)vqH̔īu'&md/V~~\*wWY#݄ڌ&9Èfh4nzǎ23cV#aMλˤ%3RE%5[hH,YƊ:>Sm8զM?d&mŤIJQ:-5kc͍5&&IntW aNIO/╭q~Jn%%Oȉ7Қ΋7׶my jZqqq|oNsS,x1V[`x{CA{(HkroiI͇ P9t _ոpۡX΄KbnH>Е߲$tNXwAR"-ϓS͈QYOw49cmvdnx): k^at0G-'*^u%XhDصAlJkET4cTn!mNҶa0 bIOAy;|ЅR#'J>J9GHa1v<)_-ĢL|o65+M *1O+֦"v#PصLci 2ENvO$Tg z-j~7G[W#'DzTZrbJwb۟|FeM{,[7(Ƿ cF.PIxY+B$jodTCt&ʾ%Wd)0O$݌KkQ Y9Ժu뻦I7k3jjܝ!cl~R"& 1C=3? qQ(x#Y̭܎C( ե3˰թv#G?qB{u>㦕RUdH(x;lb^o#f8#V-]Ph^I]oC@[+a_*1jħ- kU}+?2V:q\@m@r_5l%1>e 0ymrϗyFT" Mtz9yh-mQ3gm3CCC$9syЖ-y%VJ׆3Oaf+*k̒<^~ BE-WrHQhE)G¶nKcD&v Kr؛ojP+t囯xv3'Ml۶m-.yXzܒ•'Z'Ykp9&)JZ杏yNN/aSѧO%om-[`28{0(0urƑ#GM^*tk^mֶ%|x4F6Ux>U] ?o!ծQgP8T2V>]mUQyJe}wem[f&{)M7ޠ2pL)rIDATH`13岴eWq6ppE:Xy "Q.{ ksȂJOUeU38UJƯ *cV湶V3Uֵ6w_{wv<}ÁU)q47^yY4ݻ (//C>\rq[ ׿{=<TU?UƵ_Fɵ S.]b]Udw:ۦkil697?sa?B n:peڶL4-Ѝ:mq8V @=i)myEJg c`rԥK(64m_V׿hMsۛʕcBs2] 8gХ;`<+vW)ڡQQ֗'U=y S'O bu@ E:Gg337+nѢ dϞbcL׷ËΠ)9W\')_U,xU&wgo9Vuc[SN; !mR(7x?_-;vӎrt}w˖-<!cY!={ -󴵪M|I׏.H*˫C _w ' s-wc^ٽs߱}3O?IǮ#G^)Õoy֮kUeG \GK={aRxY$k׭ܸI*\vYSPO[DmT0 R8x~fPA6mz QʟKzg{O:-\PGk."pw{?kK΅ ݤgU z݃ Цuo~s~Xѫg6m@3LGݷ8XZZLԱcNi)mi' I*]`A|ۭINgvsVvM>,zfafav—w eBl-ylݐ@Kiq>}'.8ۦnڜu} '2YY]m۶nTTT@+Nx8S.p. 0 0 7~.C%A]!*ڶjr U\/X)OyBp“nK5wmmvӢ@hmo{\ѭĉm 4VӖ-9|ޡ}GД.@iϿgݯe^z%].LC#7}Z/@iKiigov xso{|ꓚYYYYY] _ٽn@lG\ӺUs CX9/ ^'N())5 ,_߫w̓nNqց=aa|a֭-XH$j$pD&5@M-j"mPi H[D&5@M-j"mPi H[d0L*m H[D&5@M-j"mPi H[D&5@M-j"mPi H[D&5@M-j"mPi H[%w.-h0Ҋ iK (|kYp>;@㸤'9J}vFa5թ'QQY1!F?" $&nQJy&FBbȤ|iƊI!SC'hwECܪֶ-Eiq!cR*[|\LKCE#dix<# QKۖs㔨kv,6Ɋ,rKy5SS֘L]^Pibӆ:i:gAf=jI[  3q2L1!qF%- ӖJE@;jI`bVLd ;:&&fYihKclUKc\ҋm~K:&VclRWck=Q})^lrиiLⓇYQQr퇱@-iK~R`0β&*~Fcpiy/*_:}vqo-|)v" -Y&_Z ZQ1,Zf\Q~nʢ~Rx@4kq &iS cV<;pڪeg'Evgc ^yJ.G6d|&'oNhݞ}q\-!1M?ꑥ9' F-̓OY7PzȴGu~Q>;Q p+m[P?!mPi H[D&5@M-j"mPi H[D&5@M-j"mPi H[D&5@M-j1m9{@Z@Ӣm H[D&k~IDAT5@M-j"mPi H[D&5@M-j"mPi H[Ԥ壏Wضm>,عfذ_wҥ~C0~4d29q)e6o13Aj0,:Z:=i{eK<`@pb'KinC ,]t}z:D4 imKIII?⤚$Ig+_7Ĺ-[*r/ԩoU\\@QeL780f߰A;nk0<U9U|f߻}z\߮];:~Dm㕏S>2xz*my^|oBs^ P7?1=*̝us7{yy x0̽XCƅ _WwSL`T[eߥ%G)q]6mx.'wTs1B_H[[O)尰g<-Pg}z~}tlT{5*Ӎ-Zgܝґ4G*4h`נ 04*qcZULhVz%1>)Sl"gϗ66G[vgy-+m֌674D{i ^xqSq}ޮ]D)g俄*/KG9y;<\Xv}EӸ˖4*++{"?^ra&`%5^KI^h"MPee"0)#*hMs4HmSWߏ_? 俞0s~ vҔ[rƍ%%%-j-ጚ+*'x,OBrSYż2yIBY=/6!y9`Q34ƄƞϽH `3Di Afxk׮kc/z/Jo.%d8NH)h2_@1k3F;~%U'ʤ}.T*s.qo]zi#3f#;|YQO39s3Ϊx "aWfN cba~XbXEK/[)띊rq9\=5WY?mT5*X ֶJlbh;*TǪzni>1 c3iP+Ee!=sUf8f2jff5հf[6נʏSh~16XJ޵֜ffِ*6ҳŦT4R:+fذ_wҥ~C0~O3R%JU)Uha`}ޱ ѫMsRˎKX;&czyqA1홫~4*p۷7ʪԲe[Uʞxt3T-ZiV:3Ų|bn LD2cq_.]w2BWyKnrkc]v3u/uoٜtmдtrh-Enfon)-=j$gՁnGvMO%'O%ME0[s涂ZmޙՉ̙3ҩWN>67z+?iĺߏ;VGz7^ܧ3#}wZJfZVZAu IBe%ԉܮR5cYkc%ù*sVZBqcdsS- [O:!_ҖK6t!WĒE+ZXW~BPAeV"bZ$*_ioILaܗgTn0|>25mR]S m.kŧ)X-6Zh1IT3)ViÐ^#i{e+G:-tС6$θGUкuU~g:o/bRhY9Sf(UVc-[Bz6cRk` !+Mږɟz|_s3236TOQϏIW`l:E-u*[lY 10,u%d>L S?6㒫DKۂy!K*V/M7 }؟OI Kx'r[c, D (H[\%c\K?q…^~eP䐭[U㪫V.o=sZg >!ҕ~79ݶr|bU4B9נ;Gyo>%R]Kr&$HPV-)x3@ y"ֿS1Ys>hr$P1Wi "hgQJSznO~K\=Jg:u٣jgm# ɍkO1jIZhńxKo03u9x,#t~u#U 2D((bzU9<\˵=ؐ>!f31vI]"fRe5[b7j&͙=n3|Ns^":FM*o5ߐӆDX$`WH_vrP%rƲ [_˗p' ]ayvٟÁ`JIDAT~n 2*D`um+x5X5S{Oak*Mר أstYEEv/~4afs[Kߜ{SCCK>'zO?@JY"}x{O/ Ww:!~)̇{]Tǐ9U\?57LSzIgrDzs 8lϡLmI;Y,AҼZZ9|w[QcegoQ}֭[=D8?Tl:h"A]0AH;!QQ+ tf̴4]E3GŖ?UL0_. 4ԹtwVY \REhQIEz#\y9e=;;6*gzzN1y@gڶmz$ڢ|dfna :%lk8ʛ[.v-p3z#?q:Z6o6y.>Mr}a>qW3b?.f &vYj`j&U$W9gl/*(7c0nDn#EfmJpQڿ4ݨrã5=S7y&nO*w߻uMHxߍk+mIFE#mѡH ');nTUPeLOpd۷Kn݂nnѢ-K\14vyvwU*'V EyjŭzAw6C-zboV%*s/ֿPe!_fr={+Fi*U&/kҾP??.U+j*(Ç x<̽XCFHϞGTʩ`bw2RMQeP,kg"k 5mƎn@ N 7\ݪUb%'g%=2om6R5*GcF} Ԇif9++OFD\b* R{_~}`g5-}д}a<.ѣ9WD_s2ݐR#Gmْc2v̘RMF#a2͡ʚ6dfn\!sMZmT_&4q[H[P;|Yy5r;o/kI1n j?Xqc URQ mArs;~'aXt)LԪU+emA#mi _Pi H[D&5@M-j"mPi H[D&5@M-j"mPd2 -j"mPi H[D&5@M-j"mPi H[D&5@M-j"mPi H[D&5@M-j"mPW]_b0 Y_G-`3CbI)M\Z`0ƥ &9mSI w} S5eޒB! Z)'䚴1+䜥39'M;׼8E:'\ȥO3ͪiĜs/ dMYmm[2g Uek?sil,eNo\~cV(W> RڽةB.ZT11vQfQ4G^(wAHأ&H) ]Dy"{=~­_<; s9%\Bpc]X_+xbF'Dň=Sm\T`bOVysF6cQ6ƥX3E?ē`a]^PK6o}B)N,YY'͑SR4l{GF6,p0 _,F\IDAT6Ҩq~5xXh>=3_8jO" 0 qJzT;:&&!#:⚀&x\5"X>vTa/z _謴"vZJ[D{ּ8mxO*so}iLp\9^J[$~g-K+2{q`ePSo-X^ J;i˹8`YfMTƐe-eRPTqK@p>9$-yO[oU.r?&2BcFOY,1)U o¥O4`2j9Rp* "!arU tn8y/LIXã ӦkLeKl4U ۓ_z8=мhm1$2dçfOqèEyr)}m ?j#Y|x~ƭgOn"jrڶ-5@Mn&QޢH?CҊ4}ڒ񼨟·e h%xt`_Q?"L&J%@M-j"mPi H[D&5@M-j"mPi H[D&5@M5-gϜ5k_ڶ@M-j"mPi H[D&5@M-j"mPi H[D&5@MJ[m\!C"FE0 p3_XZrk=u.> "e^BG>ݢimӧ?䳣GJ}t "c`Җ-[ hd29q)EEݐ=n7V}Oh׶}qʧ^^ou[j4֓H:ŷÏmQK^Fi@:oo|ͷ_wjXڒiҁH2aƌQiIRhҖܭ[rxXؠp~N:)対… Z%sK??a\s-Zo=|̙ݿ-]0 , 4hV+,,{cp̍Cg ()D{~mi!p3}JJJ_#rs-[ ܹCڷв]?u{٦ʛn!ϽH)<,IZFKm[Yxw[ޮmcGmV@zJ,*.?/3j.ж<֭Z T 27* 7peBSh QE7n-$ZC0uD. &zG^T0 Z8--w?-((ԥ}8V?v]p? &ïd!π_3և\tE7ةcv C_wvZ!s̚94*v] G 6f@hkvoۿ/w\kڲgO_OJ[lSEG OyymۥX)ߕҖֵkW~:Br-9Y[r2̙3B .z1zosEBm'O)'ϸ;aU'L z]֩S_{%___P{h8D"`SNOM[(V~5!E-#njݲ%G}׷[nݯۛ}۔Mm_}ȼ%|Z11@+@sfOߤC|Xd=ƾ8 `@Xh.ܹК]ܹ}z3z P=gϾ-ǎ)}ߞ45ii!QQ{kh03oؠ7vmc4C5C  4kCnӎ| =?4{ۢ{]𴗗ҥKG<ץ^bSLv0g}!a15}-#אNtmN;z1~1O:ojzо}T`W+qc\qE7-s(P>iiܖ)&zUk32m۾oÇ&q饗uҿCoyPCvB#8]$e˖¤[Y}ҩ={n\uDk\nnR4hPf4gR!Z1--:hٴy -!6$y7yI4W]yr}>xFֻdP) 4P@;cGNg(S߹())I?_[Tŭ nsk7_D#I,ߎ?.c hT_^^^G---mo/4C"gNvJ+..5v\vnۀw̾gh.ݻ&?):L4pO[Gshz2e aP ׬{cJfYNlݺmȰkB``o쪾nݯ:rT\v"]ڥ˭ TD?OnZBC\񒎢iIt6~ظi677Ciio ʖP)L\y<NA7m۔(5;wVҖm۷WO['Z&tljZ_mj䦏ZkrWX@5Pn %| tڶmim'?{zg֟4-ZAM~ XoλRa>0+0R%艖ڶ8&틃J_?gV<)oMz%OTKy@={+5sꧼ;㊊z1buZ3{HcǏw' Oڒjp͍t^kEY!"bzGanYtHG^ݢEWyPG~d ^}E/P)g[#J5[>"&%777W)uA):y]*ТM_?5o+Flzzg^w 9 ]#K{Ǭ\m1;rXzY xLb03wFzIJ+ΈYxCRA)o.w窇Dzߴy=5o D̺?*2R4\mF6۶m[OL،}շٛ{ ɰr+G*')[zҀ<7<~ڶ*~Qj[P!BE'C6ee-wgu,8r`Q~CY_2aS⊨E0ӤL_%ASVBPA!Vef+x7Cy@2pYNIDAT3kCf{.&j2MfcyKK+PKu=n^F 6W6=I^C?m[`H:1鋗W]n1eyjhbWx OHNme>1>[OIvw=;˲Ѽ"77Pz_/kI|5/dIȱ$I|<$=)EĬd 9GH1vYwS1ks*(f+[tMՏyO6qg"2FJOj{ѷGDeU7TB^FVϸ-"e+ Hqh e)3"5-m%)UFCRx[#*\\wI~C>ГX˖;^f$Voe,o];qt6_ԋޘRQʡI]zeU+DM^cÅa$9氻EOy$xO\|)2r]Sl3Z*m3ۓ8^ԓH:0SnvY)'M0~Ľ!Fz4淹*zIl-J ƘpAkk${ [=ZM]-ҟѲcc]V>,"z8/քA MoW\qʌ\<>6 oCS5e*(_ر,UDeEZ9zynxDgNcvnMZSB@ǀۗw4wَF;VplRIgHO>O!ɶޤS#EXTYws/߻*wzo }o3~wη&I԰Oqgܑ_+$dg^^ѱǦ1 ^ dݕ]><,, _@t۶rEn;t g?|Ћ(-- .ʺ5w)>w&IBkKʤ%۵k'kon [rr@3 #V)?p ?о̍*kkX߁'R4ޯ~Ri2kϿ(M$_. -]D  B}QVVk׭W yՕӻrڧʫV6d~wSZZ*m0~ܕ˻ 肞m\3M6VɢvlܸqsҁHr]G]';&{KA'RQ~|G^`w:rJ[beʥ\¾@O fXV??Kߪi8nomϞV}"jd _(/rƍ3UUWvEqg7vs;W\!ѣo]Q!뇅ޜ%ren }jz[(#} hҖAo{2r`tWUݻonPDDh~S;[uVeh28BfӻXv h=๤3Wv~Brd;ro/Jr^)̡<3ڵо]^~y:ҿ_]?,=J@ 5C>{lqu&j_M(q s&@s¸-ZDi_~ǟE]dB*sy___^b.9r4zh@G~uw?nz䉍&mY拟vTI=zo'h־$)((Tʛn/<8ɴ|37J݂'k۞='aafafa[juͰW!M^+*rݯXn~`k@{4(:uts=ӎǎg;@o1c`e]z٥Hj'MI<=pD&5@M-j"mPi H[D&5@M-j"mPi H[d0L*m H[D&5@M-j"mPi H[D&5@M-j"mPi H[D&5@M-j"mPi H[D&5@M^uX\~ڢ3kYnK.13&Kd2V_eѐfń,_TU,E\H>}IDAT^ڢce -m)ʜ٪ۘ~)ˤ󅻾iz%Bfۥ~~>bVdY*&}VHMGrņX?4!%OImN5uV; W2gRF3y%s士ybBP?aZDKb|9Ե1R(XZ,6),H37ez#iVYm("0f/)LR3? $FΖSMc~T'RS)ýEJR!I`ʴ4V v"r̹Ξ?2&3a 0&. >CLy!|B…Vx7Cn>av]-IEKq@-.L[8]T}ù*++ry3gT5'7xn`QxK" [%,~=r7oedKĈ7*rݝ\G<xqs۶m{`o엜[^)i'tVppt4%.rY[QQC&'PX%)Id7\DȽV1$4]: UhoQl&tyoe)ΰ{1yO:JҧwoC-}G͎[/\)u nX8|xq^11 1"2{I*yn%Ѳܢch>1K[T pk{άԹ 3MRv3#P'7+"+U7[bhRy)|g'$}@FNXy>Kn3,֕8On#2Sb~a]E>a}1(-aΰ%w!'rsjL //+>ܢEj*T]'rXؗUcYsk+U'?6n/j/^ʕ\iMZ]K@4ܦMݡhy\З۷>tGC$9|!0u2mP^Rs/ Ɉ h Y:~ۖ ܿ!TN;"T=8d0Lg=sJhm.]wO=g4t8Guiq[DM-ڶ@M-j"mPi Tc12uH[%tT<%%%m۷dG0DΝymٶ}yn&cڲD- -W,,,<\bf@i˱d2 ;㊊N htH2֭{G8^$7DDorgL,ࡤOYaAi?IIClмTSV)XmFت,S֒X^ZK76m,}_cfC)!Kޮ]b;f!Q.v-[237ߐ&-6]nw:L[Xw믿Q^FIak32/gyYsEr׈LUڴ pQ#GNK{nzՇ< xs"bȝH߱l-R>mI$tӇN;>ܿ?` s //{]qӖX)֭_/!'xǬ]܍='=/|/cv2ے8=t)LԪU+͆N5=N 4u [x>K%Y%gBu8]$p ^jnQVqsʄw-\I)hd29q))4[p[d.<ސTPq2 ܞE Y|bf$ey4zC<2]*?aP l$iꌴs6-nG9-M@M-j"mPi gf@M-j"mj8]$hH[D&5i.@h\@M-jaڲ}} O)KxClݺMٻCOE2S;wQBMgLfWEba-]/F&jQtMJzkR r7 Lg ]%眓iN~՞99yp0z #mԑ@0`ڲAbIDATyF ȣr-RӖ/@b8ŝ'-w+C{c-ғ.W) $961?(Uۻ#фp]5ي eHܰL@0`2iEh8|81=D޽ "Q93#:l:"9*+ Upe2T{eF:fv*C}y]~DvǝӦ$DTM@ HʎkkOw)#nRPjjDzV]pW G7Z`D=n1g65_$ XeĈ/Ck<cV.)h('iju{TN`9ZTUUWSUs׮pOy V+ kkOw)#n&U]չbWJrŹݴ"3OFIhJ2<9J%ee Z-eY-GJI\&m)ڶz\QLQ^+ٸe_ht\Mm =㜡2Gmwq)m҅G$kycS@ 0`ͽ,[-[c=")u..eP t[ %tGIM 2ӱ׽Q)p/Z{+(ɤR)QXܵJ` ˶S[>B$ DtoMB5b 52,Y'\>(]f%fgrR@ĵ**¹ ֡.QX~;q æ-B-xQ|DJoϪ{Q}W*tW DLOێj%" jOpEn;ǪTpW*[f VLdEߩ_Ŧ ޓ(4޵E-z`YIu[d dl!өTIDKOR;g5 te6[Z#eqJ}.V:Jp{+u7Ū<\Jud,DG'DRyhfe[oo`%vom.ԄZ 7ڡYu2thU084\i[Jk vr)&OpCS:6U7à,C+nlP÷;*FúZɍ\PGcdZ:miF$Cٖd9N;q(=F2zdĬcҖFWn  ,xZFi8ڡ-/(ۂ.6hv:n4KH[Ū _o C-~#m25oXMV@O-z"ml_ʱ:,A艴@O-z"miKJуk~~+wJ@i H[d~„ Kr}4Geu<& TC[ }K|] I!W!Qqќ88Uh)_Hw~Xyƌg4|3`M#Fҋy1cta/|30w6"+KWpT|Q^ORH6+P,8EΧaڳ/\Myet4[msjE9M W~eYեeY퓨% AX/UR˶hg7o*xXSs,2}(i/Ϣf%֮*EP 55j$KiKYѰBOKZZJ#˨dZ]%E#Bʱ{;n>|aشE\/ʗ~ԳZ0jTmUiVaX8-f*ʰ QpiM9ZP;ǦT=hr2霒t>-PJZ eV$9n@&SPpw/mdF=:rl_w#1e:U甿٥N@?艚DHs՚MJ5()n%-H`"DW4sT $0\@r!mb6ʇF'= c| TF7Z8uYHHIz8wl H[D'=w~?Fw_W @O-z2`R__?aK|aشE\/ʗumV8J =_sfT+hQ+Ok wW)޿{aIo\m[< m"`򲬼'3n kZ}=]/+ or@ڂb5Yj rʪ<sAɪ\2Li+/TщezZcH\&fuZ.mr%=j&~3rM" %;BAEsaV9Mࣾ/ T =艴@O-z"mAmF#="B9 T> ?͑)EsM.ywv\Y tu~ꊲbjJ|{qlyEʋz b}RX:y"]Oy %k46ˈ##.Zܬl!jJ&)r=6[xU-/"F\H׎ʱ{;n>|aDˇ@s{S*GZBjԢQ 0 &(;+]^dmxdkG6ޓ`Yie|RGih ޢemb@(\_l1~wӵsyZ|Ǯަz<)DG'DR Nzd@l-ؐȎ1VcU@: nVqnz&nW:mhj㸑fs4wXrq1qpq29?t~Z}ԼYԱTP8q(=FڒrzH[z@*0r-@O-z"miKZ:mz#mi H[Rή =艴@O-z"mnF7Z$S'@O-z2`R__?a DBCС:),a8u@9TG %1m#mi ae󖭍@"G-[-MǏ/_p̙ OHL[$W/$+TU H .FפIQ;VXֹo歎Ɨ=K|:o.)*) >q8x󜴩8߿{2 X%/x9iϝ'H鎲ϙ!.,mi㓏Vmey24;2FтO[NfDvǝӦZlR˶cw;wʇȱ+^*\Mr\)zlyLc3}fXE΀iˈ#^~ş>9$˶jQSpWe4x_9ӃShfQP(H\d$q:Qz-z"mi H[DYI 艴@O-ͩG'=艴@O-Tzgݒ+_ʱ tB'=0m0a ʾ1{gH*K- C Pi `ĴHD-RӖ[666 Dl 4?0q Ù3g,on>! 0mw/_qSU% 5O\e\&YRmѰBOkiyejrM.W*[dɎLhA9Jↂ@ICEt!ȾsoR˶/1=D޽CRsf ( |i*OKK(Bf^LE`h쩪zuq76`->o]tΝ!;rJW`ε79*;(~%%)n(,vy JgQ(ĸ,5QSB.#sM.Q=6\]E=n1g65_$ XeĈ/Ck<),֪ )EZ}LK-̢ͻXN\VU>rWwYDj%kycS@ 0f+ҽ,kx<H鎲{jzۄ9OE JʋƲ(s+b#ADc'Oz%Ra[j!ŋC``ۻj8*|ʛdf2Y]>բ J~PJژnI *tuma7+cİe[VERkVy83(^m"DV 4, ql C͞BUmseu]α*['ǚZ-Y\E7Zš'%R{E0H[0Т9Hm~%hh3Ձ.!A'=艴@O-A͛5Vn@O-z"mA})~dH[D'=艴%%վ呸aca;@OdBÇsfϚuSm))S\AE@VkCSUU]wOU]=q( 0:SM>(ZXyhC-^4B^ Æ76d;c c+,oSe-ĝkr09=`3PQ1(BԮou tBչ07sbU28E6Bxyfc@?D=n1g65_==uY$cI4bĈ_z5?f l|ey LTT:d/>#83`ա2PZR[4jt{9]Fj"ӬDN[]*l&WS^OTlͩ 2_F-2QW=KglFG~酭 XHs=߽yVؽgP3KdgUy[?OWf_;JVi} J܅JWZR|jBBd z_ }c9w>|p)ðiP ,^/3svWJ+9{ZHQ.cI^2='ϷeE=j5ʨ`YzW{ka=MymčCe[0ؼE`% |JM_l Y4ݒkٶ1e jJn5\\kKZ;.^ZPZɍ|dv*jzZ 0H[%IuD.Ei4}h7>s5JYB$JB;ZJ-Bڂd@O-腥Ӗ i H[DڂQ!@ϐ艴@O-z"mS-#- S'$ʶ艴@OL['Lk/d5С:),a8u@9TG %1m#mi ae󖭍@"G-[-MǏ/_p̙ OHL[$W/{ju$P;f5YǠ\mqW]7[W7K[dSͩ337+TU H L[']Szre[/+;UU:XY:4ʗoHܰL@0'Mh!K9igͺB?M5r斞_pW _J$Ɔ}cTUܵ+gVU]- cw;wGofP[4~樬.+5Y ۔V:$;ZxqtsץWV͢(EDou;mA_*uX$ڇFZȑIsexՁ鎲RK":X\/$^c\/0r=H1Q/bW8*VZ_^L[xg;x;i6J@O i"fwD>yƌg4|3`M#Fҋy1cDz9}(i,ֲQ*ȯZV\8**$XFI2GǼRj$a: UPVt_ 8gGVhkڵ6a.:VB]aB[MM*=%k\ X]iMs*boOq eE3XJ_wzSV%) 6 im-ݱ7mYF1ic7 yimZkB"bkhs)O㮰-- bM>TXy )MFBڛ]-g?y;.2 X(LxQ|TA(.Z6t[У ))E6)-;c%ˡNf\V{_%isYa7, Q.^ "05$fk*+)̰h8uY@J2lٖ uHJ1c]~wk%Jz4IgzQmZusәUyf9QS3(v imtj+%D%16Z^|Y`,1cvS s6au0Zd&D)99È,\7e_\JQoQA}* IDAT^-Zt%y w$|lm qBJ$e(yܠެ )DG'DR ^zxw6 ] hD6کQmhA5X9V'V:M@V;}h/ lF1+s\Yh&f;J[cZ?ݴs"'1;o]tΝ!;rJW 1sݫ* yhXyƌg4|3`ٖ#Fҋy1ci~W>mlFG~酭 n˽,kx<H8%yi☻#``9v~;w.]" e&Q!}|42S3NF%Zڢaeۺ ]k-@Nl ÖmA³H.mZ9n0- l ;7&vU^>VXަ l.c+4Y]3sDwn_Xi;neVGV+4,R@ uI%\J"C%>`\N2T8q(=F=艴@O-z"mH[D'f@#mi H[D'Җ0f 5艴@OL['L /`VU C Pi `ĴHD-RӖ[666 Dl 4?0q Ù3g,on>! 0mw/_q@B-faEݏΕcw K{c-ғ.W) >vg9ƾ呸aca;@OdBÇsfϚuSm))S]AE@VkC uȞ{w)CWљboGIFk4o]zrJW6_{;lMvUoSr9BPG(k) xXxfg"taaZM垶K p4Geu3Zk-8Qps3*VuX+sSk#tx]YMVڢk7Ϙ3ƚ/Ҟ:,LjsG 1$1b/К3F *4q GWn5(,p|>)4jm )6Bz԰ܓ[UV˿Cז-%"(-ŸeeFW$ETWKN[]*l&WS^YT:9R˨E6 Pufd}^*M)54޳lqݛl{BHiRɝLVW8M ^!8"[-;]-rPU%BsqKvv([uUPde~(Y)(s+]kK(/"鸐P0Sʱ{;n>|aشE\/ʗլz$>ޥgde05jyepmaiYp%k4)k!Ee^%*b{A?yBs>Wndy44wP[,ܰk_H G↍eR=iE YqL=k O٦ئL0@@SUU]wOU]=q( 0:->o]tΝ!;rJWEOt:uLg.UjE?4bg$mг~쑵slBe-79ʵu0;v^̺%W 3f<̦k1^|h̓#;ʏZ瘌Zdr%EJ+2_@t4aQ' 83 sWkRÎL6,۪L:5˿C.|،< [) l{-ο{{ R(%G Qjjd "ԦmR0)տs~9&;91@Z,풝&j8+ ]wνc>\@0l"B.ˇ@ۻ 2y]HIsTV;Up[b ғξ呸acae$ppcs{{VkCo0A.=쩪zuq7#Q9fL7$kaay^{9v{+RL<b c+,o8'-z[0rFto-Ӧ<7;hXU}^X%bZk-?&ܹ&xiR{g޾5NҾzu"yru`ң[:miQRzפ}nhiX_'ǪKZxGӪ1*V\ИZ96yw@xl9(չ"<.eMCCNw8g{]ʪY"({FjGg-E=n1g6 HI1b/К3F@oGB}Wbۊjbr5)=Tlͩlvf*!H 6նv~uYfQ"8EHO1ȼF]ZQP奉V\8*Dy;4IhnΌ8j8ufd}^*M)e[4޳lqݛl{+Ԯv8҄#jkJBkd55BX ] ϭmRF[4t|{ +Ψ12Y_&&ɐ%+X'!7k&}B'=@tBq(=F=艴@O-z"mi H[D'=艴@O-z"mi H[D'=N('=艴@O-z"mi H[D'=艴@O-z"mi H[D'=艴@O-z"mi H[D'=,viܹK ]fɜYi l~QƧ7U 0tId03m9,Ow5>Zy#l>'VitMcɑ]hę+7h2\G|p}r=]J$k74uM-ڼ#VuvɊyes^*_9sC;9ّ0kq:5k9gb~?Ɔɏ\u;;I^ixu]K ~.ݿi:¬--:o S 3xWi1My:lXg·ƘBӻ<'GYJs#Q[Q_31T-{(sw6ό>u9qچ?ƭ:8qͥ^n3ҵsPy2mXw*)HT9oQ1Z{"Ӗ5ƛܝG6C.E[)߫v^*`lDǍko^T{=-Xq2l﷝:hX9SZFݺu鿾sZrҝ58O}Uw +kXТQ7>.rqTW=_c3YI:֧ CߞA+c^ꯁ>ushk|tln82 F-ᵉXÏOskj[ꦬMSOl9ϑ_ͤl(djN#[imm3)ʬs7N;J#V15qNJhNYkVAշ;@.U74Y+;r~pimAi56\Vjtshl<-3 ~vun՜ P46~sߞ7"sϷ4>Q7eX&ӑ`*{]hPe $iK.ÿ0W56F4z1VgnojT!-ui )e;7_;nX_^ۺ# K[8KUwo b8>x[bNuΥ3ih|) =1ͮO߫ݹ~fh\S-BkW].<}g_]j[y:G{+'mٵN26e[U[9h|+l2^jS,77Gn9UG~ę58Yyflo]9͛{B̖yٙoGF&\jomx-|qg3Fosgj *49^QG9lQnx̕1\Ȯ+7 qD'a}X+3Y73k+b[9eVV?brq&uDDV8|ݦ%s9B00L@ ְ]Ysƭ qd]e>{)/6C4gwokؔ MJn4V8mC,W=^}λtˑMь<5Y#_Иk.K;u-1_q_~NZV Uռ&W>i +'8gKccq.[7o|OYݖ37yocsۛ6~l[^e|s-Zs.D;;]@S.FOh_kV{9[}\#٦~qrc|JO:Z%_+ZʶTܝ4L t&R'ջARK[>9T[ތ7Mrv~ݽfL@8Ka[;if%[@J.@"mi H[D'=艴@O-z"mi H[D'=艴@O-z"mi b-tB('=艴@O-z"mi H[D'=艴@O-z"mi H[D'=%}~n|ǧN3Sm7LSUȌȌ#1OySyF=qDHo|WDR9K$3yK0#FD>G$0S :Ndp^:~gƌ=J?OZxճnd2ē|5ZZZ ~:>"ߒQo?g4Ǎ"$YMcc)M_Ժ}j{Haؾc?,_~V`\ki˟ W~"j8)}ںbD-@|駏?l:T'`}f(EEQBI-弾-Oy-55G7q5.첫RKo~_Wl߹k#SǴŜ[ p8pOD1>H0C)/jmq s:>T@K Ė* Җni5+~'\SW{x{ۋO_2A⵻ϻMtCShtދOwٹsW}oA})'ロy%^{{KzziK\5>uS/ 7-=yO`rxXo_Y&~W2wo{qE0[S_[| jv~']Μ9#@ '}6?O=iE%UI_\و>ٯ|uZ,g=|oyp T%4b>USs`mO\O߿4}|e["DU?,WJڳ#"+'Oio3| 5K^Yn=;W\/d}aQA'~<غw޳WÇC mR2eY䯈W~]m?z2Y~n<-]\E-#Fxx̓R@ZZUW^)fΜy^J߷݋ϙL&DB&Q7 V,-JeW'li^}olQƑ~HA~EZZZd\M 5]r%vT,[T{}ǎ-[K ׂER>{/W^!VO~uȕ4Vss0g{]ZW~'L=]@V_2-soM{AԱdr+5!ɗ~qŠ G7ZF-Hfŋ_}_8_Tsc] @j;묳6­ZFݖ񙗈O6?z{ Nmun~[ouPҶJc|0s=.mS5kʺꪙ7կ+dwfv̙J7<7ͱ߿MeRҗrr~\ro+h&0h%7?.)xB/~@1ja-twU#my ⊇{2r|#O:vG?æ|OܩYG]Ȍ v1GM,;޻O_+_)/E 裏;v<Ò{;ruZR{|*>|T{X文S?wOd05^5K}<$ ad|ZЉ5L, (IDATg>#wvx---Z6Eֻ/Rϧ~?پ}3 )S: N>}߿}b4[AO>iGS603#/<}N %^i:~\BybP%Sפlyy-55rG7q5.첫4lf'~ؾs.^8=/*,'j~+yd͘5Z饗~֯~.qƝ}HIܻ?g3g<ݻ@1ANy Zǝwܑ՟:k[>p)s;w9 0#|ĉ7k&@уk~W~~A~кg^uUc|G ̩Sii?f1:^}<-nJԩSfl/V~{Pkkgv$֓8:Y ZOb2Ҟ2{_>Ǒ&Q2ݓk10f8j/b۔.`,Q_F-W_;zle$uc]7Mv52/jȑsQL޷ [_|I%00{/83բ| ƎjVCoܻg? $%\kGŲKwز0)mPuD0vWr'dT,9'R+0U]7Z8"M`hokkw2ićX/^}Ojݿ]UY}Z]C >0at駟 @o-A\|LX;K[`eN-R~o #F`dP7ȍr]s3O=uY)})2cM_7OPV&zE#~{Gz18/-X}:qJڇ<ruu A:M>8(ۂ2rK.ֺ06mos^aQÆstبuLnZ}m`JX=_ ˶(KvQF D$C^nD%e#qхw۩SBWZGgt1jPegg'j6i E;>lĉ@E;>wH-?B?С:cܸqQGؼ;n3_'?ظ񁍱9Rhmi}KDH%*al0^ݐ.`l0m߄y'xdddj51(9,>ss\|EZ[o2>t=2?~(Rz"Ē{#]&&1>os9G;>w=78}o4Hv[v_ a|vx!/X \pZG]kGpԩSI:9q|ߚ-RQqbo+;rd}V2} [hݷ~+fҺY Smoɇ  MmU9΢qypo'љ3g,on>!I}ZGGw ]ysOh7D9>΢ftژŁ@m9~qDȣ봇H0O[SUuOL&V:V$*oͤmNcXd+<%WZE\w?M(?oAvȏ}_]MsܘwWEY=K>E KE!{T떡ǿٟjk]`zΰi˾'OٰL{5զgi!QpWMKN藣]U-G iz%R;o.ڣ@$_7{oeƬ;Q2b΍虻:4A+%)5sC޻ӧO?7:/ѣ~^;=uo%qD/]p>-->ges6gQ$ze~@cQYr`Y3s"ʙ\;{;-8fJArLoNs2-t |ӍvYwCa%Sڲy #82uq75>=$qTU@+ʲ.P#ztoCHrDDm\|e\گjmmmk}b_Ҷ> TxsoM>d3{z%4;v<ԢJ(/T? *Ӓ`ιBLLS8>1r(BRN1K-=ħ~*{ĽqÀ"1;ʴMWbPU]'#]tʦos]DV2q_6Xm 18vLܱ屓vy4RwG}z?+8 >˙ v9Z[["?4/&,(1}*Jo^=ڵUu\\O,;D_u,L^jߊe:8yrO[x("^qyS䏮_t_nrݬY3:{K/[p,ԛk6l ovlFrh7r7ir(6Н9ھދ䛾^L&?9;\Z[>'KX<|gՂLksyO. tw$1VU87Z]%Ergs,-N-S[ݏ#4'rqADpxԩKx>2w_žEmn%O>D/9]Dڒfgp.<1.%vo+ D_g#/S¢ÅMя}^FuĉXCعS>YYdğIiʹi9ڙܝ+Ĉ7y;'rOÃQӷ7G1)ǭb}yQ){svbOCB'Ue5BӼm^zȑX_{}cv[Z J6?TXrfA`^"Yj[3!jQaWS^/#pSR^*,ևRtI0us[+ʴZ90X\QRp?c^;ZBwm5eRQ(k.G&\pTMߏy៑~":8^%ҕrj ?_ ;KudZzU.)ECIMw(SU]KwWy")["#; sqeUYyF+/-Z&O+C'*>IDAT.]=kۏbZJ/NVV3[Q>iKKJ!;\heg巵v(h]?qԯ衳n9ayFls*3i4,TJ]Dǟ_fϢq@åA;ŀaIkх]%YeˤP3d1.ۿSSy|rwSuy~a~jCmEJ} *|or3yOeg˖`[b1x€\駶hmkzoXd>|e%;Cz4uCڢشiwDTo(D9i%҂L:q苁Si;6ڵ6Ua^8*UTYM)_WB'Ddװ9駟>O]P]AW^q͛K?fzJ"u(WZ5uCAI^Z[{pCǿ6" _?:PtוsEZ${]ЗU%rd M45Y%h;+Yt Y4~(`V5q=ݩ$zp'q/D$_%k\_y[_ 89 rk1Ld^w%@\vxT!-}DC_Ph/u)bD%/Y>V+H]]Гgq[,=uچFߩ|oZvRa2} ԚtlCޅODr_ǚ_{[fνeW| Y_=z9E_/8sLTW>+zIi?uң*䏨ʯS"*g?}ͳo9=kpe]Ͻ'~Su'r\{ZŇ[ਲ਼R~yr(Oۢ'(EkA쪬bBX/ՅNjE܌O'RA@(eS޽n~G- /z߾~-;ĠY]YFе|Ȑ6oӾ9(/D]mELʼn_Fp-j)޻j8i#Fo»Lhs֢9g^r-#IQ*ɨ˟XoiuQ)mBV'hZ&kdGUg{ߡ*AoZY&]US/Ut EwM5.7|ՕWɿf\-jۿE_?⬳ЗZogr~N]ZUoWsLE=ܪ bf_9v> ~ oչ cĐH}^?-:YU6֭./jԒ;}RqFZ:x!5 -55p;ܜE9I);&OjXZZkc*n=*Vtz.vV)~eUg S|-5D吕VwWkvmU .,rtїd _٫NjBZKwDmlLON[{A+[ZZ'O{}ςBFCLLj}ԆQiu*WQƴ Y&֌R,N.-(n q"T[iUMI-\Hkt .]w̹Vk+|U? gPq?|B%4,jf'B}gj"W{~alR^@ࡡ./:ފ:tq1y5^P2lЧO^LTR>b^tvZgs18v~PlgukFRf{Z$Wvc^r%vT,[T{}ǎ-[K N95qk].~SD^YȍuZ}&u+ "bmV]n붇~Jf]c*0myj֟59).=\D{~=T]7V[9wUCMWH{E ъv`TM+iuS4unjUxe䙮_KAsH|7fد%$zvy=U71|QWxU=m|7rm 0k|1$bkl.{rmAmWEv-2"Pqx-U/z#ZwkW\!tg3xjt=( \{>,]f{ ENȭ<`>=TtV1.:wimomL|h͏g۽{˧oS |Y5ֵGzF=<ҧGCmW>j* wy;~5T q׽nzލ_\_ڼmG DlB birk}3cM_7OPV&sc] B?7g$ ΢hW?ʎs9癧Il! wznSW:nȏRot̥=$éVUd1hB-7rWie}lq0e^rSmї 0:jk~CK|V20[oi7~nHX y,*ux`[̞]éj3:am#IahZUn&HϋI4ۄa*˭0wy|$/^}O>-rC( %s=W^ ܜ,x^$j]w]oSW9 >3;w)}^$Wڒ<Ҝj?oxdwcE/e2iIV<톸wol Uf"t5psFY4QL8rL'L.4~@?m+HI}H[=ܛ/g:RՋ^޻o[>}~s匛 `/l!߽4xSUuOL&<>-պe|[}{1x5Fwĉȑ?o׿L~Y3 )}VLK{g|jpӟ` ‹/Κ9믟jr .xu=U;w VOAC쮪BÇsfϚuܿlS&Y,xIM~nʽݷo'ܿb ҖSu|KW]yŗ7F HzWR^,j>_jaЌ:Qn@n2ʒ_k?'I]"I}%_ஏ?X(rm(3}f諁 j{H~ξc^{uώ;C%_*^$_6C=/K.xr'N裏: T$d8#_rŹg]9&ܻǃuu;q$euY(iFF?>/=zΉ'b+D|sU!0fd\ܹt臁 j{nĈ^ޝUU&|PT\ln`Hi[M&:5٪f%3%T28`Z"Z {.*v?s{.gygQ_|Gj X%wwqclNfɮW/g 3'Ԃپ , o5aݦ,t BS.w)ٲ=_e9$^O }jHݺuEżƛjKF?gjuKmm[`zI9ҤI//O{Վ-~Ĩ焾@U5Kǟ W7 :'.)z1ڕ/QzVΒҖ' -ZfO~[nJi] ݻO  +E% ݻwVRw۶ ;8VϒԩSA_KoOTNXk׮:~5%`Mnݺ5q[ Ho1- mVV]pڥh'Nؙkmkʲqw[TKjLH7ŔջLxl!m ~2^>wߢ>PddqF;m_k588v*."m`+>̵KaŸ|b?ަukQ%. U}ի'IOE8~aNj˱;)y?2رT\mfn816_۷l^UH>=`ɚ4nG.\zFZ>Gaf,)㕫WҎc^^(oH(/5LN.[\`ggҽO }jHݺuӖf:03ԓ3 -:us-'n͛7e<݄9D͛5kڴЏ=m{G,ǬT[",+mz=Z؝sW6_23 =rE-͛5nFrrr6nڼUWXcߚ5kB-_˻7Yyin:u}..X[L?t'OgaitUk,:v,uيkЀ'L¼<= 7=z+Le*ST2Le*SfR9[׮]+@ۇ?:1)=O)mKC_\Lε3|YvJɭ3!zΥC =<p&4!''3.SMJQvɟaI?*}I; ݰ>߿aZ er֒iEYPek=pI_7ځyO* `ش$82=F-bhyg+qCWrʤufw9/'kIߑ5Vxt$-@ŕLO5(5nBA);B'QW"曦.a 4!yڸ܆yLLJc_DLd-6!W+4e׉ )k 'q' Qz*{k/%|V|B C"Fm,J\|'%&@+>2s9I5&d>a~]uv|]B}(ҖY.Vsτ--ũP`T u4=u/s%lVd<\\0"#VEaBčXRbө`rJDOD#q2,>DQ+%Q1UIDATQ}RfINM5ꢾȬ%յs|BM86z|s܊O[R ̮(F/,OQ;蹎(Y4,y*[bxPh >Dqjq㋇ ^[/%Undddܸ䟯<_f/BJsMˌ_k6#&2" M023𿔯zJTCl<7L.%|)i>]x$cvR(`ñԡT83Sf]b;dm4׵ŋ cbc{*Sג8ݸcfs]:s>Bf4c⁒ \FF&_׿3ǒ~>a="(ڶ^_heⳒRf {Ҋq]\z,%2 }똞#*8mⵤΏw3bmj܁f^8=}%ZH Gup<""cSoFfVROƬ'<*9ХzfjrlԤa=8*ajb%Eb9J !3SbFz|PUpB_Fr\|Zjr̬a>u^!**oX+xք0?e$%Ny d~Ic'MU0?.''3c#~VB 痷g ΌwAtח ;ҳSbav}?c>\;1,(𞑔21AY^HܮJ'%MW>tEb+W_O V;+3'~mQ߇Ws%"e~% ? ͸(.aQPFTuΛs˟.L}S{NQog4![{mIM;q…s/;wݺwlu{Tr+7pqqiIP N[.^nӧP%.efʛxܹsg[] KP<"z9K7o.Z߳g~Cj ڴiF 5l(Jq&=߯g4oLzi"ի~ة~կ__ѣ+X`^<,i T KM[׮ի[W |fE aZP7jᮖ7m*гv}{U,={˺&[ΜIwwk`c8: q%;SKg& ,izGSl%mI;~ɓ[_f:Wp&=]Pm[ޛޞ<,;+[-pgf:ZQv{TIdRd-GR o:9%R]ZH_Zt%3KVy5XҸ-援@K-@Eh@K6DFڇn;u=n竨Y5Zcbr:Lz1q7?aUS*Gt|Sr?A>;!,!՛#tH=E N+gEGy=IrWe 3o:cx}]uS_"P9FR?.z|vSm[\h[=-Q ~A55%Q;8M3}Lhq|tO$ϙoK%_CC돼&2x!&pH']V*|tE:1UH^[ڡm?]+uLb]MJ|v=4^`A,mKJz}z=N`DiKf\TݼKALf"Gd RCs;fL":愌'QWEEHmlq3n] %}j`Լ.5JwJ1S 7QID20ofw"*.J_261`M*1mYxDVD:b(lք䎟ZDgJa<,LJث;q;cKt3PD}Ads=%iЧfʪ]uDafI?,Q. 4y]\̱ m[ZXR_6ڭ\;sP`!̐@D@9UNJ[0't~fmIwI,t@~:e/"&e9kH`ʖdss)t>Ja/gQOR88ybp֫liK|J֒!l~zNNN!Y3oӆTaQ +Uʴ+^.)BJrMN3ZBj*.jTMV)۶Iv=kKzf_WORe%xPg!,]'ߘGX-.a3sr2)}L.P$gXRgő_P O wVliK>&(5O^tB }zR9X -FF}&J;ϑC\OO?ҳ+{;]>D7"`rrr| 9AQ C,Sq~}Vd5'% c\`ݴkۢp J=bD:{ 2ԔL3| ̡艪C JTx *avy7c?r܅p1q{W\6͠J5hvڣ ^>qR~??7\Ia9ȹuH<ҔX'8dg~wI(ېP2S&J9d^}tt6lQo vV%L],kj(Ck^f̠ܩiyՐpWŌ5 h>$>,u;;dl}#9+5L6"w'ё`/T3}]&( =ڈI'*~Ō:L~i2eв+=JH9 Qqʄf`zM wrh}J C MrYN/h8tv999E>pr!.(ş78N֏ :8-*>٣V?>oE\^}gaiK[> {a)iJ٭kpƻ[~ϔ_b /lڷ&۶Ǘze,k4Ή. mͽi %D'N\ / 1Ӧ x_Npw{j aI@ ,/m/xO?ٻO РAan޺6vݡÿw}lֻ03Vާ h@lbܖ3c47WT<yOvƉ 9-Eȑ&B[RIQKo-ڳcߜv\kgiS NK#sOTN/u}X;+O[.\ljo6nXT&͛7KJO@[V]ȹ߳DuxbNpΝjV$%'{V6,0mN{3-jC!S(~UC7_8{VVWvtr)ǣ=BB6oRCnn6o6m(#o{is:_ h]]@;M\▷ʨOhE Q.j*U=ӆ*opO|B^-`Oq/u`,)m۷n߻Ryg4|[7or̘\,<رG5B?ڥW2=m[JoGJTgPymK&M¡CJѶ&T :WW%-ƗR>S'å˓hǘtIfIW>qz+SWfMY8Ў ;Du#*=j׮7V͒Җrprr5r,ۙbSϿ5-ܨ/s?dzrXy"}ꔆ ȂZsDUx!Ԉi&S~[kgiK |wo=߬oܕC IޒޝUʯIӻK|&Y,K.=}tYٺG߿kq+^~(6@ɓhɜeeE|{3"ջMD峳"y⛢.\5l(ʮ>P2"z9KEK{)Y>7e'=%AQ%?{D:VB֭Ÿx\z@,iܖ-W RD+1aDz  *SC˿3~[`xIDAT 5jHaI㶴]}YT@߰0yzvvvZ${m,miؠAvoϞ=y)3hNToeGGG[߼uVjYv.`٣Z0J.%%H[D%-h@K-Z"mi H[D%-h@K-Z"mi rrr4B-h@K-Z"mi H[D%-h@K-Z"mi H[D%-h@K-Z"mi H[D%-hNtvJ-vⰂ 3B-UoۖY9>Wmݰ9k 3D-mKf >:`):IS&ěTxք0?.Y wۖ~O0t#cϺF@gqL`?}1uVpWx䕾K"GM"=ڶdQ>r~̔kg~snܢgpROd|`ޓJ݌æ +Wr7)|Iyڔ :T]脸3am]=u꨷q'*S)eƧ Vb '3rtjs09EXҖԔdCxX72Ni2?qQ#C}Ur()Qa6f|##K؈ڶ8=Že.oF-ʀ \t}m()mх 1+2& qvvQ:?r2ΈB= E\QruQ=7 ;̔Ia>}&Ď8e[SȍjY|zC+dECb>(9f(eVpR*u\B]f\鳂RfO+L065U%4*ځZ'owHoL4y:/ m[P4J@K-Z"mi H[D%-h@K-Z"mi H[D%-h@K-Z"mi H[D%-hش,@ի,F-h@K-Z"mi H[D%-h@K-Z"mi H[D%-hӖÿIMK%WBn]w 6ݺ=~x*ST2Le*ST6 \\\xt̞-N%nәtVM`7ggXjr/`3Zyy .''^mm;vB;o/O&4mDIO8t3g7k&R4ÁME4n,9zt}l둇!ml -F-) i l\ aQnܸ!5n]-oںU03?q2jW?lX޽jժ% gϞJ9k:|͛II999<*Z?ӦԴ ޝ$K_ӧO7>v ~Ǜ6r@ԯ_M?B0IOW mڴTSN{~8~}'_ o{[twޙ{,\մxLXRO˗P 6TSPӨ.]ʌAϞ;'Z3N-q`N,m˕5Jm+_͝gq[jΧnݺ@y8qGi VOί_!sڴ!3P*͚ҖlXR@>3F--ZfAA~(ts&N~+B߽(|-76h"Xvh̑#G'M~K-wuD-@eppp租|njjڔ]`rrr|,af>dZx J6l,899%کL4ygB͚5N,Vam.^\{Z*Ѳ,ܹsgNtb1n EX6Vm٨aÆ Ͽlܴ)1115-aÆw' ؼOn~|u7mDTøo9IW+L 2XP%B׮]m;uԸ_2vN;Ⴜݻoҥyg{=gDt RSӲ,%$rwk,##C-tl#~ͷF-@q.]ʌAϞ;'ʫC_3ΞX&zP/:[ /-8~\@@@Vڵ1Ɲ8qG8`r:oXM֢jժ` vs7p-<Pw UIgƨE,Q~noE5We \D988۷,$9rtr]wnJԂɈ䟟~ ԻiSweeM4Ԃ7 9;; ?qjo;*I8yR Pi.\ljt:MG˖^pΝ9DO"ڵ99ʰ56>la\X6䓔v*Y-egg li '##C-tȸ(|8{V`{H[@>/^T ;t@ժUs^{7G-Ԫ][n߾#=-`xu`~H[ĸ-@q6prqtr^~RvtzNK,H_Sޣ"BMI|^|u2jKkG)/3rqT&WF8 {<OpRk*/T_l;1pPJUH9}}n3SG´‹z`{W!Q2+^ire;tb}ܤi hAs-jzu{Mu8(  [n3lhyVcUl[®."jzݺom,Xm4oܭE;t>hQMUU'жMkpʕ˗/sQUBmڜ!<\kצ;E}q]Q9Nع9LwWѝ: L}2K-0\.`VO[ޛޞ<e..uU߸AւjwM`o_Sؘ,ŋ8)o7.Gڒ{s;*G|?N),2 v\:uYp)Uʄc7h_o}~0gϞ9n,4mzW-gq_haCc{Ա_ (?R2۷"Kw> S-AѲߏS'{zx{jߪK}Ԕ8|ۏyݻ֭֬_2^~e'NaO vkQ.V-jԨZH9zU8v*%$;4jA®߸"Lt}]ߧaPǎ^vM-\]-ٽ;酈qj١k^0FT{o)[ĝ #F=d²*[M{2s0p` X? g^fkUײeԨ7nB#F_lST>.zsGhɿȻ׬YÆ>%Pa:cSy.f&~%j!՚cL[0jfֶc[߹sGW2Ͼ}K\YZ`&H[wەPNc-e2+sOtUT5jZ!re4j/\`&H[.0.0x@0[Կ ._je)' VrzG T/hjy7u:յZ~gEuj/D-ZF@ :a gsWs0-*gNhma֦ڵ9A-++[T#-ETʚly}\ݼkWvc)ztɴ–׃&|nPN4d"Ի ջ;v2GطGV(mmW-$%' hQÆs ۲uk@`gUsi˶]i2X5ZT2ۢOHX%×z+ϕ-bՔ|g&D9j4]>U 23>gלp5:BfRQo_;z؀֩oԨa[I3Y б{{yCx<#J3Cx?yju}=g4ҧw:^-_xQ&z=zaOZW%*~c6%k9:!!l)iӦ͟??55UDٕ0g&OOϑ#G_GPVw3?S$ȓ`=nݯq1ƇĀ11+t:o%gg>'~^aE ywpRtz^Y ;EGQ馯6_/9]ӥ,P G1Cč E?T(( I0]xG!O35Cqo{)M MJG5N5R 35Zfag;▮c Ov<(4P'O/

ttt﷖{jN bY&l33r+ͧ2g ꉻer]yrĝ~__٪ h}TEt*nYQ ӕ'3z~&kGN?zE,QCgSC11#LxX0ƿ~BF-_ӬI1OλSnڇ~7{S:Ǎ=c](5;*ߖs ҧFl{KTZE)ގ~WT)Ν;n墎S[ ޞl<߫J: ䷨Em}kEKp+#Jl9y*r$#ywLSvWZb.Jeb&JvLT\6_*7}j`Լj?2>s<-zu}4M庽MIDiڤܠ| vTbr%;Dc"-'|k׮ݻ_ggffu ZuF6mR&%_#{?gp2˜"Jv#'ۥ. RԘ uB}E\\< jo3.J|rVh52 WW̹kWSx'OʂeXv,vY 텛G;d|ە_Ȱh%N2(nW~"N|1^ROKWR/{ ߟMӥS4{? /r>_͗o^j<\FcZjծOskptQQ}RRԂE峠o[Ӿ_?p0F6_צukafʰ^RW>^ջvZ%&Vﺸ8K:zyyym+ʥ3aI=їS߰ocn]LH1С%%WPҼEi0 [('Bw3ψx.^.tB wMPP3)K2^uX,ƆER(Uf!R,+r\<'B(F52,dSڷvrV_ޣoJ#qT"Ǘ>5w+U6^ gƨE?_A䌧 ɿ'?6m%w;R]{8 N*̆|^?n_F?: ]Tgf'dffլ`γ#FysǛo֧Oʂmv׭7vzw5KWUE2`z/2ef!+aW +ALHnKqKOjNB(3Z//`eh}-GȄk펮^gZN;0b.KÔ]XabL:R@y_A8ВVSq3K}H`(2] k*eg) *_]a|HyԷwqe0 4_\UWCiҀq =Cf8PI3 Sr55^ DDז6E}h|m0vt>ѹ?w{%菱M<՚9r՘Y߹}k Ͽl\t={sө]&)׃(1m Is988Ozz755m.,q4NQC)^~Ekc W!t:zOf7TbO3l۶O??d5k mB h,bΗaALC/JG@WxUEu/W RPS{ (sGbz bX}UEPw^a/i- ̌_QTw]YprrflACw ֡=e]a̿Lޒ3_vvvrUɷH0t^@%3{u0ԓHm\.;U,3V\ bFŎ[UWͳeilt3njU_t|3 |ן}a i_w{؁cW&58XXu RSӲHɁʔܹ`!,~U.NFYN͚]B6(##C-G5UaHY/x"jgd;#ǐ!ԩcM7Iޒgͫ6'ʜwOq bܦ؈|֭{2qٳ-@*y уczn߾#Xj9vlYæɝlpaju#smiqjXj(m,]MǾ0QÆ Ͽu}ZB&ZvtVJmʧ:x׬YПz\*.\(o.n-DŮY%Plm+WOwGG+W\z͛ks[?̏}jm6UU mM ˎ Y`߯u P~Dm"|Kֽk}9jRX u|zXq>o:A0?$MQF?F =4qRu??P3̄L>j>S<)WYAAs[ݶ< PV-*wkݸqCBw۷KmYSq-{AF%-C @%5oݪU:u*_8ޕ2`j44uVioܴewrS;tf:WKl\x)5-ͭ2d1N7nn޼k %-t@85?h!w6mNؕHrT>r4j0 +#ҨQ#r0呇*Sd" YYٛl-𨽽+{xW7fe&-l}j GND@AI{T^Ϝqtt`HhڤZػw=+7jبK砤=vܹs'NtkagKvZֹ Of i P>>NNΝʺ+.=E+i޼`Q:uS Ʀ %[O!݃d]xI}0'vXup4nݦN'lޞ{ՂY¢8:ƨ)@nuJ/f ؘw>H]J^}i*SG:f۶^}g0Kԛi O،z.ؘw}OZԩ3>bXRrI&@) 4<翜;^f|xG3?V˓'_EF FB-oٺ5 <vN4d"ԻE!me֧w:^-_xQ| ?egg X}ct]N.,Q=I5@yDx]XJq"X/>ժeVƴ`PHrzk-`j׮y/-zիף-Zd57nF[`Z~ܹ#uNͫQ])r_ѵkזcR\^% ЀUY[ݻmZ޴y`ԣGhѱc  P1VQ ۲ylwPko>* `H[+3!a "mݪ`rrrNع9LwWѝ: WrrZܹmlwPXtYM[r`h X7oN4G{@ar-Gn( ХsUlwP&yt1g{ M0'v2{.򁫗YjUZ)qڵ>3^^˻m[YROC7@ow#"֯[./hB%ƍ]f͒@YAY`,mKh[s֭ mg.D ޽ۭG}ɲ݉5k(5[`rdCA,u. 4bڵkc?_/arcS>dz IRZF-{o˖^J;Ool\v!m,UrrZܹ蒻H]vĚMcejaS Хsp̓qVvĚMɓ@.@eP:lwPAyKJ[&T-<l i H[5X9:8:=^s|vr74(DgA.6y7CM]&-[@QH[X3d_L6m'׼3bɨ偄We1x|(A/L_6MP[u㒲|r4bƶ@lE!m`J]IW<\F-Uk6C>.ģl!4@k:ӻ*61ixoA*SdJbQ}t)2V$C;WmVcȢ&u`Ii!՛lѝ{?+t3gOU g *+ٙ&t0c䮢%~8>/X>edp1E}er3hrN$60[HJ Sd?ȝFl 2no{=0鰘4} />xdiJyj"w}'[̤-JS/ɿVڛ=5-%QʪI.ir~:z},@Y)򁫗EqtrQ W3`ks#_JQ7N:)[~*e˿0";Gb:AEED1niKa6ݶ%5xFF Νpܹjvܽk۶Sʥť{P@'Jsʕ5fo\i-r=JrX4RT.Ӝ-P1iOlYc\e6_3W!9}6`q}ٴo._卞[}YFpNtyomkoOq%m/5TEʽxRN@)o.6o=zriӄoReFZծ]@8yr/\(5v6`kT}&RW!7'4U*KJ[YT؝;wHؕ( Z*ÿ]w-ӉB+ 6(0e{NjP ?11)IX7omܔ޷Oo,iܖ{$'.Z߳g~C kӦ5l԰*MzzƙtO9ӼY3Q^kh֢s`` \\hIT!.Sra-jת7mٺcr鬬,y%ز&z5n0ߦ[}͚5OR-驖!0 4ǭ)j1SHV-[>sD-`l4m]޽g?жI&a{;I&դoXo˩iذOvg+=6nrL[ yX-q_EF36t{ئuk _NQ}{k'OUfD?#Rr2;֫OB7O2_xՂ~fˬƌNly٫O?qӦԴ4)//s О- T?qɓ 3L窦-g`ڶm-ϜP긻^bsԩq/O?JsXm4Oy/?L Vzege ,w+W`\ xqB2Ξ=~}(SPJZ ?%KDܼy3++;==Cl%m:dp 6mso>__^~]-<$ۮ], cE K׬!meg^**z߷//})˛,<y+ xi/h/J[l*,y ~k^$>uT |5w wnƭee[q_~'سmK~ o}{hﷇqBiYTT˖^" h"k]kX(I'kgt$3нkzl7׽ղG4-dߒJZ kўEwT4.ylvu_GRo9'W ,Ƞ,,NPoez/I (;eeZァ#F|*N _XW3P5m,-{j# /\rrr`޽翌̒emyaevLly[]~e˿Wo~qƢj5i,]%PaYZ>YRڲx2V5kjy֭oN,km߮3_vvvlvvf+]yv/_{zO+I/@]svLly[]˾vmz8ȹ߳DuxbNpΝ*"k\kX4KJ[N<ފ#$䥿W˟EEuٽ[ܝ׷L=2MzKɷGhaOt Zg3!A~rz /w 12 oyaBgQ_o23>'B'Wt՛VZ,/6i8:'g.-~,lUvk^wٓՂ_=+o&?;O`wUדs_*"k\k-ya==T3ɰr`Ї }z?C .4rdRsԝ(E9nnYh؛yCv~t]U~@sE\6B>;yNOg ~jCjuJ4zPy̪= qc >DTMh#oBfUsOm՛\kѢOL*_OL-\}XY/m7w̷մ5 fƁ9:tpʞAOQz=e^:t3g4R5Oef<+@Һ56]v }yKUD_EMMI+ZyGuo9> E!L MqK5X:mc9^~L~85])}5n YELQDYY_:ܝ1_?'3U_O,o& C5ꊻL^?Ie 6&:/QH![6eQ򗹸_ȼ\ /vYZN oc'fL^[Y׍ 2P c*OGQLqYs.jY3Wd[*fͭN͚5[hV=4wpvjaɛ(^%Zٞ[);n>ʼn"G-}kzS-klhŐZA DFzW o̜jh5g!?ehTU#B7s1Sf<&)E=d] y&r_9. q>er&'ΙeX5E/}>'q+nƥH+>{J/{f^QK?"4}qc| WjNkU9JdJ3E21qqh8&_W|;njPN)͔dj#Bsv~fO B.K1k6sWqyMDƔ.GyμӡZɿwT2jM>61_5mhΝ;ӴVZW*x{޳N: ䷨jUcƍ?-G7¶-Ǐ{nKme[^ ֘r#f]1Zg%wGEo#@})tkR9>50pjD}Czdrd':C2T^=\\Ev6+996Ar>< !>E]hBD˯S:=;FՒsGQtee.[kŭIy]~(n "S+C1r2s[DO)zYJZ)CS1W?2tYP!U9RUH5i\Y&}&ʤKQ[\Zd;U$E { Чԭ[WXV}#F{,_`lc{M.?&ѥ5 \ 4דJun\\eT+z\s+m6|j|mFkޚ<ɓv+]$}Ԓ)=b8zA ` w (k>|{sop$N488 o:m\/Ki{T[^(K^t޽5{zPsPКU=uު̺Qv˫U˖eQ˿_! Gҫ&G~; 4WYзȬ<%=F {GWkn5,W۷TN磜Pq_Щǁ,U$ |{r=Чfʪ]uEdϮ999ώeֵkozX>`utnap8ŻM7{IJjaXRs3!{~a9{͂n 4==^9F o}chCAS|ߣ1)r!_OjLp`MtV%l+y錟EkCξq|UUjۖo~7v*#">|F CZ-WPqlXJ}/Eemy/0+IkT\3H]R "d#c柡ڊz{癯kGVh#Y)zEs,;|owF!~8=%^,gr>[RύYEKM <P%PoMTXzZXߖ->qɂ*5-MeS'VXM x{魖kX(KVvawIDATS4l@d7/$ʦr!x!Ԉi&S~[XSe PEI-ErrZܹF1F{~/GVXϫ;9ҹ~X% IkX(KVvQÆs8Xd݃ ~W=OTsWe]4tUewokjQ׸P>-@ubFFZ9HXm޽+6ӥ7#*_%mw_?rօKg/ҫ߮9'4G{ʄ )P:yVҖz]zU\X^qՌSY%Φ\dhnWB5}ۖK%W/,?d ΝĖ?P\;NNN/_.X3ޗOO?MT>;;)oM4MQF.^T 6`"sX *cI㶨#b X&jY3]2PQ#. B;wPJ8&,ٗ/NJeU\}9aajذ1yȒuDLye׼N-ȁ` CyQΝ?jqEK6of< Z_-KMһwĄ˖.4pLO ,m<(BFVJO?P^4lPIk}a,yy<4 [!R=;oO$oU֭[{*ҧϜnFul-|v;vBvvyڶ sVˬ*g+iKfMfcsP`s_sң{rrrwi)jiVi& tnmǎ֭ZJ[fI=!zڝ==<ɯcߣf@/ r'?ѽ-2T5Xl^q7zM8*u֭ jkjIpw(n]: Tm;PzxxP:.^sU&//OŴ+X}ʕ,[M4nҸ*SN<;k͚5jP/!Zj +UnQKVVZzy T7nHu z=WI&x\fB%լYS۝kc32ζ~6I]y…#GtzI+KD&#[L[HQZ޻Wy3}spݣǎ-_YQʥ;n& rrȠwyƍ=\<%%W g%&%蟟֬Y7-JOϠrY+c rrrԻmZۧzJnBcN'Ji=~Zz*ԩZv!O=cS-xu`~lqܖN~>5QLGqvv kAHM6U {6Ν;/PdB(_&u03{U dLo|A\򞽷n65-tQ#ݻgdeeefeæϳvTɩ~ ==q\ݻu}6h `<ULX_gϞ̼w^ Z::::կ[UFM#;cS^fjA= kcc?5Lv)&dddt ꜙlW~G@%c<(^}g0KJ[ޝ;wt~ E>ҽ{U` ؈woݶmb~lwlkFgf͚~2S-oٺ͉oݺ%X;K͉U-cS>dz i `zjn!w' kgB+^,v6"ѓf7o|wӝMu_vmݸq#q۶ǯ5N5*g@alwlkblbn'l%-w\̺vc}upJիO ~*0]ܼe`-ۯ׫WOU-`c>Ξ;ФI># i l%$:z,;v9tNϊe rF kפq?ppvFΟW S̉%-MJF/sVncgg'O5:۾/0>%;gH[6m"KIv˿Zj{at:uؤ׮͛,4]zYRhܨ_dn{j5jҤIw9+@tW ?[tƍ˗P QŽgaIzOĩi.؎:u zhӦMzQ{0+4n֭[ -1۶i-zedAn-Z8;;'޼yv,1n l-BN9n_k԰s#b~ر+V,/OéLe*ST2Le*SB+t5-q6w/mE eGe*#6"G)9"ZPS` ,'ѓ6΂۶!-h@K-Z"mi H[D%-h@K-Z"mi H[D%ж@K-7Uߋ*06mp?J&(w(? (u.Y%:qC% Ap#?DK(-Iiz&iI|9'>hh hh hh hh hh hh hh hh hh hh hh hh hiHQ0Z=]dmqu:}1RoUa]CQĞ -A- DJH8m-]e[j Jm,UmmUjwʊF>0J\ZYyؔ(c֢߼B+d6W^Aā[e)ճ:j[_Yj6n nZh,6L>pwl{#mLW_?}c/ YTnL=a[kqXE+{7b )9hQ,eWs7\lۊ2l -EQnv,[=dvi@i ˜^c(źY#L˯8*5! ^h N se̯TY2Reʓ !ӳ+K ?Mh;*iQtRH+pfnr:[QJsbűRǚ3~iowZ*MDt7틏cwS̫pk*LY/³tYj<|~-͎ם7D:oyNP-2a(=kz)\Q:Xq>@.ڶ䘧KO8s妺cL[ɝ+'-/ o/XEWΘ^dsۑ巛WW2Ym>"  "T;tR.\ir)fWu9LDJh_E[K>}dv,2?2)R)告F\43|o̯9Y Uގ·8R,_ziע 9A-{kUlMX/;++9 2jɘN.jʙYLKUjx͑Ӿ'6- #=!EFu_pSIDATuEixa1Օ!nR?R.tm;j[K8ǐOכm]zхxf}0U.K /eLtU.@Sj-U*/}nKUɢ]J꺕uBLcae}|*T]T$c30m8I~9-u`X]PŕިfgUdMeEfS!֛K._<`xd2U;r'԰Exj#hs+]5 bdYq'96~8_[ݶMՅ%0B)Gj%NP|$ ʿn'Z[=c4eqmEXʊCz_xxl/(+z˶l3TSVGiU..UZ6*ȝpǿ7ɾ;=wG]AWM wl^tތ WK)utW_l Rz5Ur؋掿ZC셅p͖B$іFGa؄ykv U .nG}V3ÂQ2 ߖmKqM3-Uc5 ggtzYOBJ691+CN0EzVhіYO)mn|ɝ˲Ā,LEJ"SyxN#QeS:J#h.YqjdE@niVJ7XJ+Fߞ~d疊޴HÙ9zoX]ͺ3}MzD\&u.g-VT;ă 1E8jwcBoPylU&R YSd}Q)a {Z_ꅒ⎓cvMŷ HQtҞRroRG6<6[_ mȱ;{`dkcT&Vw[rziAQhA$v:}cP4RJɷ#ǬF[+Cc4z֢ri RѿyngԒ)Cf_B.6X|Hz2봚 ^\ lkUeMMUOm_8leEfl ^Kޫw-2W{WVF0 cA OZE9Dee1ݒ#/?i[|0Am34Mbkkk4Ql%r̫;:wY{UdKZ۩/aN:-NE夣H*OYL1kq,dK"UVS}Aݤq;E]rY/j>2C*+7՝VPrWɺMڇM/Qb>m Ncdvhi@ڋgjS5p0Ѷ@K|N-Zw/ ݓu/!i\Ig)m`G[ 4=Y M" 5 Dc\-m-m-m-m-m-m-m-mRh˹ꆏh-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"d\~E@2Ce?T&HimВі=^&¶b>/kwJi_VЭ -?Oіm_zLQ?T9}*DZ"%-Z"Ab8./o3奭vIgʫ@KhcstysH \ZӊZE$2SF@qpI"i\t;bwz`M^Ջі˯Ȍc괂ݵZ4̐C$Z5d*ܱglN*R57ʦN?#jst7߯gZb:mbQ"m kPqyr»*/oUP&%/.o$1ļ۵HB)bG)ph~x'ғyK=nHcȐȃ:e޽W2ҾD#mwAFunUJG'T%}RV<+Hn'm/\fI!ujMб+l 霦vZM-vN^oPio(deBpUyX[Bnb˹q k exԞʾQ,V2poRclx@rD s/Qo(D["MֵaࢼZKٶp A2/ -ZB>qErycssm[D^< mВі?T?)nZAHN_?`M"\~E@2"#knMѓ@Km9{Q$6ڶhh hh hh hh hh hh hh hh hI&ڶhh hh hh hh hh hh hh I'IDAThh hh hh hh hh hh hi-bN/vĖm5t:#<6e{[ݱ(ҩD{c5v DJg,a'jĐ;P7ZcɎNĴt\ZY[U!JoVWcȒ*k%G(I䢸J5PVYtuՙ,hSUlfCzŕ( 薲J{YC7-DБ(ЕHˎD2ӰouV]=T [^0a 7W^xk]O.=XXPxMjUhxaC?j0c'wl_C#{AQڒ,ݼuo^4!h۹C759(>Q~םg Y дEnbeЬ,nyy،+k4IOY/OܷfYyx+M9V>g'|v-<|Ԩ.<8ɝ3>9h }-SZ(o#o7U &dM_XQs䴲p( o\&7xBy+-!]EBzVqUh]fY,|5rf Qt'ڒYa-REa[ZAߴ[=r1] :R1Q~qpyaq !+=9\t%eL_wīk,\&CMj,}Nf..+oljG\X\^^vYxQ5LFoM;r8'Д;'`N`2grEdZpYJ->j-1:) 3;Θ(c~irbj3WNI*Jc DW]ms-HQ// 頖[z'LH|(wN'r,e6ӭ/qI'WAߺmj]Wh5 -x\NNv%ͅJC:ebJy.h$4ܬ.wG]"e huڊArc}E{;̴j~FUSC,7c•sJ|Ve7xLAͬ=c]GɕG{i &v]{bSZ>9qJ-"%q6.dS' +ӌ &S-mQTYD ',%VfV<$cfvtnT䑝[*櫣6m. Dj兒Lntt^Z>~Xd*.Έ2qBdWsD?V,x!ܤe5.}Za#^e5l(ə;g*zE9~]x2j5Jc/ n(6ჲ*^CD7sIGcݎ25!+fϯ8,5 h@?mKm>RS1bo=}aEͱfwp%-j~iYgZl#[Wl,/?++{e[viKRM˂Ț8s庝G̏:cslkJi֝l8cK6¼[P ж%Ƹn`"Id*^%DbsL |BHZד(%E6k^x2H6$m[D-m-m-m-m-m-m-m-m-m-EI$#2@bm hh hh hh hh hh hh hh hh h)-~C?qɓM;qƌۦv?9N8qHlJ|-)<xyԩO H*Gd6H$ϯ,{_P ={M?}O>|m[gξԗ|o?~| 7@RTK/ukkkIa h_E[~cC}9uʔ_oޤ;|{s{'sssz AI9 $K.M6Rzx  5$MO|>K45j(5qag/2[@S9j!-@O%GZMW@Ss;VU?+rH'@_t{aYoۿ6o|]rǗp㇫_޻W f1{֬ۦJ'[rs*z,'X-_q?~RFE6SA<:w#("d*"f]U^59pK?Z"ViAst7ߗ'KCR+%76c 9]*AؒC<nڂ" ͧ΋ҟ/wtsuC$:t߳kݧDDF"f;d.:\2֦;j`}߿_}FؑbIӹDTI:I퇃HC,S9NN.I'/LvMs2H_\p=K;kj? l\  ]*..4xHcۏw";Wuj>t 1bk!1GXuʼ{6d}ܜmwSvrt۩ J~jܭ.i rt߶dZܵ}7K-;I5 ujN(Oб+l ҽh%#.֩2kfi/$9H]"nCi&!:GyPޅèஂ}U8YH5%άp&wQyg;Xܾ*T\bYz--ަQ\v!DB-t+Lj+ܚ@}8P/U&Cf>9wl07Ԏ-}S}cs ,aKUwn-ywXf;g[ݚǯ*[8rHqm1 =ACu(ךrSBVz[HʕOu0{m\e8p?m {B>`r1iEsF4Pn_<DT]ܷkV91o6]^ׯMMw+Œ{ d{&pDb%T{B{\V){z2T}=Ӧ+{gݺբnRfoΥ#I iqhJ# !/t(E[q{-]=Hr1EH]Z=K˔;:-,emߞNʫ.\SM [T}H7qTKۄA@,Tӫ}j;.Z$ңFQ _/Gݷ3T}vMӖ)4o};SusSHP|{i.7@ipi5Yǿ>bI#H*GowU&Ub &A*jyp w=R6KCTӽcƌql߶zJzh7E}]6R%ǁJ,Pm)VE6ikkw+ci/l.:)d>~i_`[G={"}Z>6sk;]SipԡH>a={>,|?׿6XA ڟ˧7q =+7%stӠA*8twKϟ$4{KF  7- Oyn!*jzwB#l'&vky`ʃoO(}I&c@1fg[fޡ]h8F'PEOr{EM1BO $h4ɓmR^h8F)' e544 )_/?hhx_h)'|o|=lyO@kjjR7N%DJh>jBS99 t|p….Ląl*-nEtӴ^Jtw*@j>pxým7v\yj@ <&33Sh*==}W|馛ojӣGn´/DHYFRCjB _tH/D[ b@=(0OUMg^~S~ZZ^+PgGrss^_ġCn 6555j:o$n HYz^@ $j5=+_ZU2 +pΜ|YYmԉT='~WM/,tҥ-nl~ξo_QJ{&0Pt>35 t_D[N' nMJHUDž}\.\{+ݫ\Z5-&!sC/,^f@ѓ)G!%^o?XV$W^}4ԗKM1"eVOeZAy@M&}k At}$G_erϏ$Bk79ܡC 'N^ҁ7[⦋9M"lS~(%-gW ȟ҂9w޴ݵޜyU#6[_KDD:XCFP*O}S[gE>"C$ItW?H_޽ٳl9?W%"$O].z@nMW_uS8q&r )Rמo!Nng~_vQ$.N7#=\r}]E 4_XS@IWs=:=>:}FIDAT_Cg"ʇ}V?^J_nX.zė:m[8AMu00HA_PC-F]Cw)肩S 6-``xiv@J=zĈRMcqa7qOnbs@Kq["yͷF]s_ xoywi؂q[@KhKsK_t)0cǞBEd&sd.:e)_R'Qgj'@JQr;3ڼ[r\{#:Ot!/.ʢLf29q2_pAHT?n H%$/{1-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%][[Fh%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"Aft&;YE:UCbxԵ]t]%^jg;Z"V@}6G ޓ`⨔6(2̪n }JK m͙`{ oє- qit'Qff>3=zGIjɘt[[ O_j c-TB-?vzo=,GLuZZf@_T,DЍh׌DG訬n*)+b!JZhqWV*bfYQʓi*;JLQ(2]Z<k٘맔i4ۜV ^{Qpw*ZOY7K+뽝r{ C`ɽZRZ]!Kv;}$*U`reBu孲:3YWQ)HYЦ,tي͆@+ݍQ-e:7mQБ?*MJ$H*3 ?k]G}ڼta2Wت Wlom8X|x[zrQaRgSnJ~PF ˧pmV$"kL@qW4eʳ%sҦPdU03xv%Q~>dRI[ۢ84VNXKdͬy7Hn[}+-Kiݨ#;T,WGm\^/۶-L9r;[pa<䋯R#a,[ٖ>RBI&7:JJ؏ȸS<$ RCJT\)sy*˕¥-8J陙"juaŽc#t:90zޤ4n7m-R>Zis]x"-L%;Ǭ*J\K6T.7- ܮąg-VRQf6R:e̯*FVuZ͆yr{Uf9r_)$Sﰕ 5&Gt$l!Z._!ڭEag%GdRQ[`uYN[YhK]"qoǘx.N+=AtjdkkkGUyĐu'Ǹ9|#uf6.ުœ/4eT/?yQvm%9z',"c^e_(g^uCُ׹̈́VӄqU-{Qp{Gal҉[e`n斓EǺ]e)kB+yW͞_qYj~uOLKȦeӯK󿓑=w@L}heXZrgGiY.Oi<ٽGjd =}aEͱfwp%-j@q&W;ϴ|XJo8ځ m $SƱC j&B-'ZU>Q}cӟR<]M9{g>3>ƹ<{sΞ;%)ۦ/_ڳEf2dG暑de]3n̘kF1;2?qP~fY,)--jbɱO}̙ bH`̞>`Ĉ'OV-u2dР&'ڝ1cq9>jW=O@KQr/"SM=%(:eԨMMggd\!$ɓ|mόkg---W7x3?4(Djі/ͷ>| ztcR 7L&313-DRjΝ;v zo~k=`@IQrtҮݵjzԨk&ߚ'\myͷH.+_4(ĻG iԄ1#z}Fh7c9H}؟^y̙ɷ~6ч8@`H {>+K5I)yD}ۖ=^&~S{ٳjb^/5׌T}tZtߠA.]$%.\pe `KDO˸yࡩӾ %~h ?yª&FmЛt{'Q=YwRk)zyM7u!G 3}+%'@M$:x萚(H>FRHiI3Jn 2[f Unn8t],’mKCCCUu3nOx~UU& rҥ-nlǑɾo /O0ĩ?[M@ HhˊܳwD8G71iyy9S¤3ͫ8H0Wt8@I.-[ZA}tI-/q+Ŵ{Ԟ9J; SLo8u|T%j;iZAy@MfZkUrpٻڷg)YFD7{<\nqpIB,iYFMQ+{HcGN;Z׀n~ǫgЗm[19ӜpaI$H8H9HI~?~{ igͺm+KnСCEqp֋і˯Ȍcq?})#"]իo/^,zjqp m5iXn.J8yQM-|xlN*JhXe*Sol'(Q%s!E{ 0/Ӆ,};œ ) ҭESvu]}%wvi'w95vaw.]>%"ʝ4Rlߺwi8H#덃 Ӧ[cnj8nʜ;;P;{wHDhDrݸqex&Qb4h|gZ!Bz] B '_tApmtvQHKmsMnmȶRϻjq2i*"`:TVy˶%cR->f6f.7},%c;W[uʬdt+S.ֵ3zqgVoER-O;/`h_P1sƀϵ߾W^Yaŋn͟ҹ÷>5_}UpĀ"U"$Jk[]랈 f#XVK/~̨tH|nţ^鶛v_ڗ̦iC)\{Vv<ۣ+B\ Z@pj}m|Q+Z=筲oPUkb7rR)i[Φf)isTI[R#*GUj:ԼU^kr\j%=16}4ͷޚۗ}_e]xРAo/~V{y%Xp^ԋіg;h;vjO YS}۬6byA8Jj:v aS#W{c,}MH '"fFvGn^.*y;xM}o}c聺^/ :mWށ_R/7O:t}|I^SAAڇsV:tg?ycc[oݾÆ x[oKtRɗ_yÇ֢brp$ƯXߩgpC_ҽbh_Ke#ܻfqڗyLn[qVQ)\yWovRv]`i_i\(UTq]D\\8f[eZaV?}U]M9]2emmm,\:eʯ7o5l.;nqEomQ۶o/][S""6c^r+odp}M0_,5̮K۰t3:/&ʽlBg&<7>PRǃWn'Qdž_Yzx~'+˾ԗܰh7eؗHu%DB%ixOԤ^I… 9ޓҹ9PHݘhK U益.]:mÇ񆃯-8i׫ɓ' pF?yMJ_24S(u-Ǝ@khhPo\~T-KN#-,} 0ΜQ?%[jGF5qiܜA]t>pe]&uĭymimy8]H7|nֱc5)4>ꫥO>qHFRYYYD ( $QFCb|I>dtHvzbRgܖgSE 3\3Hx9RСwsǩs"*n%l"^8@<@@@m9ܯ~EMTU?@ߐj5=+_ZGRCO" /O02 jkkĥKIJgpQhɫR  <≵j嗿 .L:V|o垽{՗t:8W -@bVPwPmZk^yU@{jeSL&;8tdҭ}sJtZ2I$s挔(Y#F ;wn/ux_1V虰;ͯ*i?ضRB~kD8<@@IDW#,g>XIN֔?~UW 욑4IDAT#|wkߗp$s&l:і1cU< 4_XStirOk?=Z 8B"@wNONRFv.\qR?=' +|kބQh?RC-Ç'R'">@5_v]M<]Qθ-}GxWPӟ lDRm[:5|1c7賲,@7}7vfp/.(uݳ70cǞLf2̟?k^;yn}f5o /57>z[(D=o`qU{hș?Ç #إlOrYS^N>:(3 ^)ۓ=&G{D[D@KD[D@KD[D@KD[D@KD[D@KD[D@KD[D@KD[D@K6ж@KD[D@KD[D@KD[D@KD[D@KD[D@KD[D@KD[D@KD[D@KD[D@KD[D@KD[D@KD[D@KD[4H3դL6o-t,9F)"!(hjLJbjz<>}VGh[c+~h_h=%4Pir}G[ 5m2f4eA$nnǖ@E- &@n$LSgWMɦ;Q79GD;0,Um*nD[f$z^7 /Kwug;E {;m8fcR\lsz[xEz]*ZOYF+,9t•Ι]ejW˕SlZ*-;PEq*KPbG\*.oTKÚz  4; ۽鍴pK 薲J{YNbXɬ_NZ%z]L%r%c3ǔ==|ו(:u; tۡtnޣĨUf6~ͻ6j:k\a{CU/0kyֆgכ+;=+W.Z`CJ #:F.z_փc5M`Ҳ%PA;TkIkZX!rYڷ kf 7۪|I}ǚEbE(R,_oRҔcsfLyRiע 9A {+ͣu uuXd* ʽJu[:_Eupyӗ`2#kŠ#KE47C^ա]q-9%QdTW|dݺr ^X` !nRK|rʉ*Z:[eʗ4woʷrf\w-J<ce_l:F!%v쨽O=+K ZAߴ[=rQYlzbukRտ0cfn8KzuŕjCEu+<V̗C"7]wiuBm]YYj1Hf,>RU-IR;af:J4o⺕GurD ',%VfV<$cfRSfbϞ$nV:ݍZ\)\l)ihv E7am-^ 3 ([D+i%FsQi˽I -yi*j8B1sȜYFU-nG٠>e'c~Uyf: zuj6̫[?e,5'Jn_@vVYK-9h+:OSoWqFIyQ[`uYN[Y.}J&5mW&(}+lquQ+=R{+KWN X"XR(RFiM[UոAoHtYAiq,&O$7TF/7>e"k@m5MWQ9ZņY#tZW歲-'KntY [߈6,x![o:m w+8PVm[KL BY3˒Cm>RS1bXF5ǚVKfYoQGlM˚8_o͟n,qzO\pzvV{O3\WSw9,K]6- 66CZu;lutK_VU*7fe]'CJ&hSiGYZkrjmKԶ%7* 5 =0XJg4$}$B?ڋrUwYȵ$#zh-Zm hh hh hh hh hh hh hh hh hh h)bM` h-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"%-Z"nW_]r_ɛo%1IDAT /yW=& !$e~XgTx$}4qh+-3gyǩe>x7?>Iccߎ7ko¹h+ɢ-Ri1Awz)޼I $|K7ϤtZZڟ5&" moB-iG dڵQ\#[[[xɥK)'ڶ\p7{R:77/;wР$O 5m_s]m[dV8v_mD qǗy5Ԇ 3D$m/nWwΞόe~7jxgϝ={6JΩSLM1^׵gd&3Lf2tȡC-RɓGd׫ɓ'ǒm97ޚ7)7ge]&o6l:\kuuwmdР&'K~>k1y;ܼkwӛ}WkРASLj}@jIQr/"SM=,Oo 㮺L=葧+G^9r˪_DUJW~+FɅ'Q,ZZZ/ǍC,ZxO].;g>+ݗ&.~ c}Gtw:ܜo/*1bŋJh]9{ܳ=7Ç 55S.@ԉx ?4ƍ s{ $um9xȝx_aj`] +cā{Puk=^C['%Nzϟ:t+RJR'爫@/oL2dȫK&-?gȌ>'DW/}qA..\Е][+%|aZA}OhˏS~oCj"+++l5@"^Ɓ?\~z3}OHqՄ$;H::SO^$:xmܨQ!{y&Q 2[\[;?{ $GZMWᄐ%I Mz>77GMORH$t766In/6_C'}w^:4nMEߒkėnbm RBmY{Uӿt:]l'R@ δV$stys# ܟ6(?V -<6'Og2pDŽJH'_?}8upᔢ N)0 O)@BIh+:oP_./]6d}ChSQ3]u+zJuHKW $^1KXT_cU\>U'W"Ao7W(z  qJ)H`mٳw֯h_v=)Y>c6CzgƑB+zӤICP:8ט%DwiݻݺZT+Q a۶-_eW'-D<bȤnJ]k1^C:v}TU:{7[W .k..XjښD+kvS6ŋDEnޭoVɓ'f8hSJ$^+2:nܸǏw~%2`wmm#g/J,_ScK="b08TEʝ4Rl?)R_nOu*g[J ^{]Z2GglB_.eˇ#o8ϫiuwKfojyCZ y_yE\C 7?-iN 7z߹DTIC̻]k %/n/P9<)BYm_XD:-́ͯ2' ixDZ?~\,:i}im,Z~E9ME(p*}nЖOAg+:~lp@:,ӅmDiʷ@;GK* |}!AsΫ{ۉ|*">Kfgi_Sv,#[#œ#^z4 ;uĈ~ӟgMgͲL0;dʜ;?{Ν;'GٞZ/ MqJ8D{W }sP<KŃZi =(t"߶_=sovТ3:ݮ [bMꃛ]iCdgzO6c}6iӵUDH%[* OIykNہꤒ, .,Qkh#jCy.0޿YWɓ}%#K|-|S?,җ29Q5sMs%̔S&):\u"JC0GO:x aa5\]Ln긎E(+r Nb;8D_*=pԟ+H!v߻tQNC.="cX䓤G@揄ݾ3۩UJKLRF﫿MJ_i.wlݨLR}΁啾[H4}TU ]S zq\oG"|G_ܾ}տΟrYչЗt˻w9{MR)ŏS (D12 GhFͶ&sYW7K6N$JۋŊv鿷-7Ei*{~[>yk#בu9mIODּqsc%z5RB*PBV b݊GAr׾d6M}V䪟>:IQaEbCOSQ ܮ/vn7|Ʒ(MEڷ媈Mmqru,=o}X.hH:ߤ]ZKT~"%i$mf(=?y^V>϶^>G7I{owR&R'|rĉ7O럭m}_7=}$4)ERqJM/F[Ξif@ة='fſ(5[n4 Q [$7y;³tN/~_')1 _:w7N-l'?NM'V_}-n4*^us}` ]˅%p]^:m[mK [`+~!$K^ksɸOʷ~_yyuJ a>z/"/tAh(UF*_d(D]8.BTv@{H/_H1E/bvEP)S~y^㖮=jү:<-Iķvp#/gJQ *E=/.k20*X%7S:ȓl|7R]W}E]YO1]E)D%)ԯVLR?9v?=_X{ac.o/.R,O>ƍ;i-"^RI:9K/8hAIDATS {JÇg㋊ mfjp"K+!ۏV7a+$'*)fb C(|O8gB,Ao]U?Bh]g:໘X|Įط4iϑ?A*(2Zz&MM<*䰑GUL,=JJ֔xР*)'8pJǽ75jG͋7\Rі8%)pm7oDP}0ݛohMB?Ѧ?$jE .c?$7P,a[iOF(R8ٶֻt_Ik][;3gXuO A2Vou=J)}wu6nOtGKsR)SJMǎy:B-HUZ 8v{R"==W6j qǗy5Ԇ B;do_{K_])- )A; sϧ7*pnW};ݲEJ՟(E_5iW'O>Æ knnүݩ]L 3N)Q&Fa@=$Р&'*Z4hSnhxs'}yK;\2x3@Ҿm#?S˩=1_%[^^ә3jdO(^ow:ӧ;O={);i$uw xіIt ꤔTimy8j<^t@ 23>oM7$Z{Lk?i5@_&>_V 7{$F&>,CjB @wJ-o}$ <_)/,]ShcSoq4+c彮@OۦDwx`T|/RZ5|DCIlW& O~|뭚׋z}nnNz$ԉT=' w|}S~xo"5asɟe}P~WM/,>8 %u-'}WW|s[SW]%=V8qvY/0fpKnNOB-/}wsl xJRI*E[|Y3hРy`oדۦNb̯u>' _lo_ˮ[BH xJ]$+':m[8AMu5:RO.:eРAiii?g{ٳJ'@1CFy^z̙3RNz[Z[/rθ-[Y /qjii=񙆆z H~mTۖΚ[ZK.:`?^}[_(2d&3Lf2\~_3{̵ IG[<)_:cϜ}_a'ţ-c\wK3g>ST"3Rhˆv˯n @t?n 1n m[-m-m-m-m-m-m-m-mВM@#m-m-m-m-m-m-m-m-m-m-m-m-m- m5t:#QŎQ0Z=@r=9D5r%+zQa'jv #\h\*uŭWգýB8|_KH]G[ 5m2h8,+,Ad`=g4eA$ݎIa*z]]SԛJ^m۱G14hn$LSg:K^l6~֚  Z-3ʿi"vL U-YJaߓ3^%cWW϶c{/zPnSK @rFE˯cIyfV<,e+Tn$0]=R[1S P+=y;vh;vo]c}e%GvSJXP} ҿY_Yj62ƘY&W^!Zejq;Ңyڂb"x#Hk+-#)q  njtcC'R7"JJP ^F(Z.II'm~ޯs9!yNp?*_ـQDu۵Ҕ,gOXҽ .;j)L "0w#4/ wێ8kJL-T](RUne4ޏ iӍ%5#k[4"/9;]~p{95{#hjS5xYchϒ߲3hٳy٧fm=.\4Xp*H?LeE-f퐂)cgrةs>.-3Oљa􂫕'ϒfl~˞zfVy"|jn[DS-pIϔ Ew꤅>-^c7D(UgJfd_M }ӳn "W\/cB'qܵ-f_} "TiMiϬݰ[Ye:S]Gvo{r }C w--MM>+:a܊j6ut$4cUvQ:{ i. \w73}g0;=c#ُZ[;-1ㆵ?yx%vNOZ˝wuCaI[ҕ+6:E-^ԀQUô)")K 2VMcwqc)*8sCܠW<ǠWwc*~\bûj[,ձi[/0krƪIDATC= 7}tCAU::MGy -Sl>=NC|{,SEE_|?$(7XANqө>M3gez^^ JMFNI[rSV +U{2VW(Ze"LL܏`ӥÒݫ&zY7/ԬEk5x$`,mQ]@4vX7}/ -8@)wkisܭ+$=hsIҦ2`*J0-Ż5&sd5W]EV䛲u:~Dt?'=hEMUyoZxގviJճ;\EL{1B؏NkcM|[lݚ2nPonM_=q?F[faʾG tQ^>00838VP")EJOESN[U+H)s75֔<=NJt4MO G1DN{qgfW8ݧ$m@'H[Fsu>2]iT܁88/|[l߀+pcUj ;˩MZ UEc_eK4FZVi%{wt6Ugݭj"H/;K)CtoDcPڵeWZ˫<ݳfɍLUّǐ8lKjz@zfZn)-R) $ t)KH#M| JWncV퍬AT~)M_O+[m7WYU{nl/͟߄"cjS~ȷLÒoT[2e!߆%{L1{CCu'pU)7D{ϏyYP_pС3dK.xȐ!jwo_G{1NSSZ8Scg#jĂ#]OV}"R d>=KI_4;j999;L^qC[[>jܷ믛asH/=\*b3zW<$ BZ)7S'%%Γ_Ҧ>X^1N=U/55U-@I\sw|{yGv+Q vH?Sۖ(1o裏.;VD2Poq@o=bKJXR,=7yᾹWM2~A/"#qҖOMM5rK/ַ%iC_ |lo4}ɉ'ñi v@hvkmTya>mM<7-;vT ~'0dHjԹbO.WDo=˚_Yl;y18Ղ⠊M;0EvyJ \qӒhNwڢgoH4sF<'yGps.7w-9_.sR6P3LpZطoѣGbL|-MMM׫^0,G1q|7^"\tWG0{ZXc&K mYůoۦSӉRȨU)W\D~Mw2,q#6wcRNmZg8:N{wURr͝]}ށ @17sĚ ’&<83W;m49󊯐kj,h"pxkJ''Wa^Hom6/daÆIә7e/Mh mcoAԫq٣r+7L$d0u3\a6GNNH6/3ﯫsm,V![Q9SeyBA:(^I YoMu﷮J&r=?u9d_{ ]KV]u qB4pgW|;rs|6wn5>K~7I_`:l#)y@o4f;vذaguo8aC yz۱cDŽr"kUTd7wQccnMH rj-;|[U'=* [:+#8al/VG3lfe{aEFy I\VaZW$e(:<:rD.Hu|TgjIz'ۆ/W'05Y ;TFɫE/;,o:K/]bzMZ ʷdnM-noߖzһ~WVwxkY]^;!g.AJ#?{sӡhWIr]EQTOB|:NmE-K7βJV2|XT?j!e\HWLCÎ?p(-Gh>N ެ),E E(%pIλJޖk8^=Xz]wZj㑈ǏOqoO.wͳE|%<\|w TTx녧km9}X "p5CVעnJm|ynC rf OD+\jG֭eU"5_ydhm2hƗ6ԨCn퓳 n4<(f|Ө%ᇓMS.9+kxloEPTrPx?͝wu3f̼nƅ^00V,޷yJD}Bn7 'J@W9+GMW {u7Pw4I e2CnIY{)˃ Qj[ e.붹Q˕&m?٢iD﹛e]\ԝߩc DRn&e훤NIGG-ʽ%Im l/{tY,~TΔ͑ދ^gH]ڞ4HwYswd7D9ERO 8eYZ9#Pz7UPSO"YJF9۞U 2D(UQ~4NRwRr$%8>]rࠊA[oi^s~ۭR(j},qZU?Z(M"J<U\ħRυe)o|Q|_#O(ms/<]޺`U藛egYq{ˋ:O/;s7R&}WYO/or2m[ܳ{>IS{V.0haܓ&9Ҋgbҵ| &Aak3a/&g^'~vGoj%Gn7OgĈlz / $NڢǎM3n w=.gyKdeZQM4=⫯7#;+:QW_tz%^',zg*g}Ca~t[Eqбn/+I@⋟XnY( 8[oZޒ#Ax?|ɵ{6 jb-6ռGIԧ֮_z@upDENxwjnw &q]#Jp7 ::fL?"A蝡OnLXM6=u)5{ϏB}}áCO׶٥Tqq*0oGX8-\*A-L0Ac J+\|!C?.ߪ3Lp׷wJ2hG,9qPf_jaذa1cUmAkjjR '\! 6 4hqZnjDh'zKFg 6i_%w1@h p%qmͯHrcM*9rDh*''G]ǽhIA%E&_äBc@O[&;_ou9$?W*bC 8i6G[fL6$5U`9v؜[o_2|r^Z}O~?|gID'}I /Ȑ+qZ{o;{?SiС#+>WO[]Wuu3f$>>@%Nڒ1B-ՠA~rǻoW]y"wj>. \tU??u|DAbJ$jܷ/I*|[ZpgqJJ &ٶwwge<;֯H $WmGށߙ:%';[~[$˷-~NZw ^ 4̛_LLLߪmwkw% *Irr-pEB sxO QugG`qÇ $L[Tv wiQjb`"x훉3F1q玒~AG-4?K6SJgZ>@Vx0)5T uSIUCs(֥ k~K:_5թ(]ݬ"k|[uyl}gTeݗW`z.N[S:E .Hٓ5Vit~,(9,0RWYKm9@rBPj$i [forUIYs^l3&gr#-Ks`1l1mȷBLzgڴ_DEYvQcMkzӊeJj46SfWVM TlěpҖL)ML1e6qC8-/SvZ_mKLҶ5&HjEVWWխ?2MU@"EP=!HQYS{'NM44vZ^IĎ%CoYE͡7ۻ cyVZx^^ g=iQ+6(_uSo}YU"r`S-ڞ9x(Ff)2::ɕ;-twzx?ʸZ hijʺG̚:!Y%5!;XV\!$#Z-}ut-2Wѻ{ina1Ϝ`ݖ=M-|Ĉ@1tνV͝2&˘O,8Ed*MAzlڎnv2kMfXFcY&8wnW[`-r1mNr]ǏڻzcǰfT<{NT{mY)+K[UfaʾG ˻GYfvo }M 8m5VP"XSb.Z6IOOZx?HLUD%5]7 K쎵jlr D-miV/SFU=Ŏc EVzl*pd*^b%5ufU~u*uz}E]gZw tتKV53m 6ӽ BÐʽ2+Uݳfv4ڜc(|k-LEU >[]UL Lru"rh)MW:ujomjz^? Eƴ6٧Z1mȧLÒoT2e!߆l5  <86xHFkabc/OzIq6`GguA|G/rAUm=' @Zc\덌iW؏_{_G)-^[Yc{?F9icܧL_ԹgTMuyR}v9 aӖ6-oJӿbrq[_~)OK.@T8餓f|駝&aiHbmyqF5jg$Vp?v |ɧR!99dg l0YgmO| ;v22F_{Z/%Zڲcjatf/D7 ]-|movjq^k?/ww;>裳>{]]6n|g]l;i{߻~g `ѮMJW|j /ڪeKKǽEĆß}&=vUs~z[oGP-[۲vꩢf~{+Zb֑#\pM|@u)H8qcЯt.c_AE[[[r7Ԕ#"l\6ud.yEsnjss9:N7-;x|=%~+^J=G;wT?ғO>Yĕ$J[zȑ櫾}Os="bUkk%WIif湵[zji h$%)F-m,G-W=֩O-/?-{g? ߻^ĉY7jxzF iK}7RaEj/E\6FKR~Pi'|ZjU w%''*mZ~/`~׶٥GKЯDimk;pgt: BOl1O?.64]?⌞o4 f76/[.̭1oK=90IDAT@)mQ眓[VB-ԤRSS/rm_%Zwn:gc]=׿~n\vٸ!C?~\(IPi ЄiCP ,) wl?r:iKhm4V̑#† k,Trַ5o!?Ѕ\ y B7A~WeZ83L6hq̺s豣G]8J?J/޾?|Ci+&W(g}Zx|{1Ę޵ݶ]8=_ВmǎjAh#Ggx7jPhIrJTӕ1o4^ E߿v˖SOM;׈3F;w Ν/4%۷_- y_))KV/y䏏O-/M|Yja.ilmڒ(99yz4ӼVW[-wDXC?G"z[4|ǼaÆw|T4dៈ>|H4rʼRrͻG?L5ӖO>ۋTbg=@)d{ -1]D"%5EZZ~/ 4/ʖvB[oaѧHqfHX:Z_ Hqo1M e~ oۦ>}wi~ϝNZ7i\m|F]wn{agOccYj_#󮺱q_|wO; \k |JK\nß=!9F<8Sz3qATRՋq%_9(=N9EUBݓ(55esObm7^?zjza}Sg4MMMj!%5.ef5w>1&3,K{.5dIvMޤO>9%ukwPrwx;ߙzդI&\q&Wy&rwᆼn I$ v!B^'b@lbr)MKKyy[kk/l\tIG>|UCdLAzy$[IR.!۾]z/?|9dk9 M\dj_7/2XNU8.:Ⳝ$2edSEl| 9f,ҝ]Ҽ~yƥ4V7)T0fuv^Ku}-AMnꑯ""}kߖpc˹*)siYy&%5EĊ$UF$r΋r/&SNz,n,7A*_WQ$ ꨊgN _L3Dn)IlUa2yT6:sm(.uERu7:Yud-\ױUJ.y+˥im Q=k^尼=, U 8U{SC ~gf w+R_ Ev w)N$z,h^kYS)'^uPY*gՋrgYnnYbom TPa ?BϊfT.)"S?)E3ݯ.{jSGE^{QG;ǡlR)chie$(-Gh> XI{{7߬-.{']vO>mPԐ: cϞ+&JFG襬̳D4Q ߼žz G@*[-%6JJ-q~y Hnp$z[u~{}PXw]oO:ۢt|?sǎSt4481'7NRτg.͋W̵$.򯽶_ˋaÆ o&ȼmm|Ԉ3F[;$"ueu]]uHuX:j}FIr˝a di^8-[=8r@˼U?wc)X`;!(w}e퇥XcD?K:m"*O}-[}ԶN"-oK7RIgWLF-nH]+hK/U6}D8S=wZ~=1XDhObȑ#O].NtңiozSNe2juYTeF98`QN'V*gOEm2JQEyT< Yږ8 wO>mIicKT(FWEvMDǹj]_PwoG_z%!ˋs9GD]S&yYН7e(O[z@We=N);*f-[|7xB{?OKK?v7jv'($W\>r9w}daɽOEt\p?Sxmyl?ܒ"Jm\ű/[D9w_4 a3h0*mH( U%m> ZKغ-.O?{Fο't_|长?ppa f$l-VCZNNN93ԏ8 ĭO>}A{{:I+'{~[o$lݖ˳|ĉwwޱS&M"ϭom(&fX/wČ%==9W\wN 򔉙8.&NJJ8[> f$=RSSLSsyGo4!CNvӇ< .8_z*1&am@H-}@K-Z"miKu[Ǹqv/sٝ![5kqYe]@8v)}">Ӗ-@xH[eR& 4R~L[Ew\.'|ͭ57@˴ERk?_irTnnfe/JMYT/ӤsdmxM[$k{-NNaF0+#bܿ|S:GXS!}(.}jسgiӯr8dH+4!lXֶ7^fTS.!vL[^y9>}y&!&m]dlk){e[Ţ9ji[[G%`M⑹z'$NwU072DP-*;I10<Z+%jt"9<:7SdDӵ"g9KNNxg_KJXR*8'w4 1@mS9Mt?Q$mW{o-@EH Q)6ٸȧ㑎6JXۓfBgXFڒxW,R˵iˁCʃ3!-Ҿ!,-ђJ&T.h%b u[EF%+Br%t4'hGW0ĥ5Z#==-Z"mВƱ/[D9tpf L1{ & P@K-Z"mi 'm Q@K-Zeg|Ra׮]ƍ 4YNR.7Ш;v A"~1B-ܵKǎE'm芧%;;K-IǛ\~DS<-7|zP& 4R~Z )mk Rg^tz7z{QssTsEW_xJ[걕j~xk\]qVY\qQmS81zrGU_߶M-NhE29/߭bɹb[oE%U,d#V]fk78{nyo_o)#OP.,o(QOwVx7mۦ,={&Θ>+'~t±],Dl3@br⍮b'[U6)gy׿ؗ-"V;vlέ[ 2o,|kH62l򐤂 wP9*r3Hs~qLٱٵ@yay>+R%*Vf_T ɋRNn,'dQkQYT*6.^?83착`4ϊ%W\_l:\ikМE}ݞdZW[&Oyk'ڻ+Y7w'}gOv_,]jdsNo\ç]{:tIC H q֒H%]4Y駝&”n) :)j3sTR*LMOipA2[!xs/Kខu |L%#Cmó6U3O3hm/Sg<`QI`r3DZ2yjwIump7jZeí>kKH6&eV^L _ˇ&窻r|[3\iäjJy7;ǟ.fH<ג'w/hnkּ"ٴ\&g.l׋ڧkR,[;@mqm62X瞷C \WiZ:vԊG+H36ѣ%V2 Ig:$pcGkz}n$bTl] HFr<1f0f핣},-]vKNNZru+^r8ILgu7ت,Ky2˭eJQ^b(!I)Ohr^^C >iP*1HzHNIQt_m rBJd>JQ)1xYOŨQy|;ѤEOW3\X;-0李w&7kר}S09V gw;v)JIẻ޽Gh~-B,R6ۭȍ8 J<).)Oc͘t¶sYΞ~ h!*/Dۮ{oc5kQ,׷Q)E# "6o^|^NR7lVح4>W'/vƺ-<{+)7yWO|F\뗷nKH [uVK_N] ,ҧ֚YZRi&.A{تfei:g5>ݯvy!ht`$icٞsϫ/0,H~bي%׻z:7kֻp~v{\xgmKn|m\ f-?J3{GoزgO5;ܸ˜:dwmzqš>_?/{[7mc{rrjG^1-M;/>v>wϤwUKZm>CSRSbuxfT?Zo cd0PdHxm#]6//{c;Ucm&mʪ͇v?,nY;rFY;ٛ\]͙fXyWMIbzQu29&x %ٽaW}*U^5<`t!=`#FK~fAp4fjrom/C XjBe+GIf9k w TS;;RmS{i*yM@ bP%jj$5]ڟ*SDq˾G { )jv{Xh xsE]G5[KJސ iEEFbO%SX8l6ZǢaN_$K)_k-ro] ,kSUot/D%c%5fq:l%Y҆wQnrG-jǸR{pEe(48N[)szWrbr\Sd%WX͹fZl1;J;nc/Ozgܷ-VhG/x#SۻmʴgI4٦:,[ZL"oI^YY &eƚ"}W2a{- ^6Mp ے_ոwӪ3(rTnnf8CtH%XiKas X!dHI$l clCl7o ot/$(r)Vh ǐ,Fplb.FU3\J@=k'Hnx$^Nc *;rTgvu4E@n ٵQMPkUYu~:F%*Vv-sEVW1djZ]Ϣ@u&V<ugߖ* 7v+WTI 6\L _^W&\'oe n8QJ3+T<(y:H!HQ-;ˣˏOE :eERhSE%M5ݓ6m*cdiյUe2"%5ߖav/^cD+;WȜ]EtjQv.K7-7L` ENi^O앯kyzF//o-5ʕDlu>RS{Żg$"Rev)L)޸ܚ[f?=Jnesؤ Hc,m6 S@os ceSzRPҍ/λaV ] )4Y=*cdAD-NEޙa6[: ˽Ȩ9xqD}ˌv|-]mkO6-$ܝTΔ )Fɻ%/wxL9EROvт.r:D#gvYҍj#brqt-zA׵^f|:i$V:.`/ho<";]l^6^Ybikco9AzIEnKK & g -Ŵ?5m9HH-Җ^Ѷhչ (!mV] -iܿ4!vz D[={ 29(z'$$Zh)ҖXu[D%-h@K-Z"mi H[D%-h@K-Z"mi H[s\n H[D%-h@K-Z"mi H[D%-h@K-Z"mi H[D%-h@K-Z"mi H[DAb@h)tVbtrGT504xݥ {պ&!UلWF.} hZސaiӖLCZc42ʤ :IK!e*4T-SP&o"¨NcHj^.ݥÿj:_0r^ڋңɳř(-dHwSJ7,6O-PPX)/{fHg4TTR6 gJkVu=p}AӒ,wCoDyQY8ZY׊W|]W=5lq?R' "Sfw㋪AyVYKt:QbUiODwQn>QXz8diqjٳe݂g1_3v;<35Xphۚly|^C %@q1u6e@Ӌ 'exfj,7:ghngK2j.; "ُbI m٧>y;8ʕw<2o#;xj}ĬpI̐͌R.=Lߌ((7MzD76mMeٽ龉7dRoޣ/vJ1kڔUsgh2olOpim^5%M&[ .5){˃[/vgMA1eM( d ›.wzrǬYߩٚ;nl~7d'.Fe[O/8J* au!+xZĺpҖt% Աz׫Oxscڵ^c |ǡ*~7eFۊ|CC~} o̴gm%&:G>}ZfW&6W9m`ڔջ꼆ҪIDATpa5VUop)"KRco}%8~n n,ZQA/Z;7Yjlܧ4 z+ƶJs&D#%hJSLYǪ7YIӋֆHӲLSDɘ)Bӥ˕]CIjbƞoU]g(Kx2gZ|RڲQ1W.o+x}$8{EIr;8];d(2+b9f8͙I[kƢ!4rȘ[dd1M_ds5EthFMi30ߎ֛ M5.TT-ZݽwQ(S:YA,-_6릛ղ[ou[$xJ+6ռF-O]KrpDEUI"~l|ep݌7:Y?>t6쁦rIFS&fb&KS^`b&t]swF㖖/N}*Q8i$sٷ?w  4tsT>@b>my|=HMM---M(iKk[Av_}ZVqr^޷'5 &hHӖ;v u:Ŀ\]2Nj͚ekD;\v\oNN:I-h;!t駫!"iĠJ~Ia%c"ZN[^-ߝ;j g-4bs./mɹr٨HP ?z @숏;@755U_ozT? q,G'Җoۋ[|w狮;~';pXQQ"θVSrja壏վ@8H[|۶t?U|PhAE)jUI99w4lWK~1Qc/eQЀRU.zgF׊Iy;n~UWI5wޏvG.!4 L17sĚ ’&//Jq7\, )ֶ }l߁rtQUg?7K+BXXKCAfjvs)ÛXib߂žk-x9UW5j?'K3 V{qmK"daÆIә7e/-I0xbm*SƱg:PYD6da[(߷r'K? g\kW9僼r+Ft;zk[zQV2]a{^J>E3Gֱjl2Ϩ(.IDAT- aS^:%ׁM @ ?]@Ҍ~6:'L?`23[o;vPnQdyb4 aí|嗎={^z_.8uo+^-͘!0^ q"Fa_#5]ZJ}ТDrÃeZI_^kWZ^|O8`P<ݥZ홸xVO2ҖX/DF5?WWM}{_=/IaV[<#E_%,y¡l\!ܻi Х]\Z~xmxtig~J>)ON>G8;ľ} }sZ0% J[!.i3qզG=l#͞@xyAR|&w!'>X;:_oUFxOHwWhI6-WG)KoW^dƻr[?U_?5x; ~nva88 }7NC@X+/z;7~XIWd!vUyY^nZ|_Y ^2OЕD~)ۭ&UIEF;;;oRm[[Xn$zۯJ _#]yX|}E|*?~|ڌoK}v=\vٸo-"&[U J˻i/1>4YҦ2xvn'WrhK'xJ؂Y_tq}"'`7:n+M$+|_uprZem2hƗ6ԨCn퓳 n4kJ-B9^4-~?.?lwYYc++4cD4 /i;O1cu3.xOK~E?g5&NqHۆB2_OY l'~Ӽ$׳|SU\x"{i=;eUՆKrn;\9i-ʟ6M\6,':8? .ql!0~HqqQ`?tcKm2fJ9r=\2dPhHҧS48 4 ⭷4/PC|gnV)$ z.oR{ϻd|5897W-ڊ2W#Eu&7TUmBw!G!O'vʨŝtyg[Pʵ*-#Kn]>YOGWQHߐry֞'i\3Sm3>\&UTuѮ3zl~do <{[ zjUJ}n4Q'i`#K*strvy>:ӣNO_57nu'ϕﱓdZnJ*?y)[|T߭NOM9WYOm~ʢ[NQ: / |]yV];&M2μO>%zKN>oш#^E^(ї8i˨HjTpKVlӦ Ww ~m6"w+(:8 (ؠl:+W~!%/j#[A,k3H{[6|Zˉ4 r[QMZM#K.;릛Gvo-91pr'ۨ+,ZP9Vply壏> O]ˏzG.ПΙډޒ![S;pm~W @_I-qHn;8?O+~/Bu3wh }A*E(.Gy{ϏyYP_pС3<#9IF a8 :qoC-Kq Ŭ0a b 쒋/2dǥ[uDF<'&=. aP{Q Æ 3#}(qZT?jjjR '\!  48Q-75}"%gÝ=g h_%2Yn}j/¥\d2NY5C 풋/fT8rTNN4@B嗋0MSKpD4Җ)D-mS?S7N@st:K-x;׮]s}{rl,@pO"`1bZعkرsZ3kC*0!(iK/Evv#vudRDKKAO ܜ8xmvp$czڷoѣGO:4{^Qpnjzss@C}10+224Q]Kq4L{@|!mkf Ew\<6۶?j{QPrja壏վYH[g[/^W_ ΝScܩ)7|ODM7~?磌~\oμ;~i 0M˻wXWV^8~ețbυ|+UDOV6lTp:ySbٯ0I,8OF41PzůmԐűgdӧ_u$qBGku:]'m8H9+̹ViQ>^ՕDz"zzi(;NHˆc_CHR?< ǎsm]OZ[+ "'|O;SMA_ݱSnsw8)L>k4 -qZM͹Z :t|dçv-z#jøswկmr݌G!  8}/+DD m6n}O]x'noowzn?u3.g^疻Ov,mӒċֶ>t -$L[97N  /IT׿z v% h8qBo: %Zݖٽrmw c.kvL>$qǎn~{KCN>$fߖo ;|tfM/>޽/lx1B8^|G0o hu[rGIƉ׶} &^;q %`ڢ:3_ǎÇ?ǾMBs={Oe('BԽt =D hi˄DsrVU7^o=r$''b5Ӄ+S׮#@O3%k= {}v\4>i{Ult|b"Fd#㔟aoUbT Nh8 ۃG ^uWV[fz둡侀%!K&HM7-|btkjOY=A:ӋC`4v/{kԽ^MmճV=MB(.;|[P#܋#?l%eիo=B{o'aڹj!pkg)e@{C|uulo)%oIpC^6g-iT6d.{W*4tvyr:8ljR)~@ZHF4xW0vRR=@{xǗ\0lnۢ6)a[ةG\=mu7eSzxtd.(ٶlڪ'Tֿ“ˮyAr :']j[+sr/u7$2NH; w-:s-Y 'ն3v}k137:W[K^[#)icSJ/ې5yBH+zY Fqƃ V Y*KF^weL+ʨ#׮)Ik_8CPoҖ f1:v.--1 {M2mݖS#ܳ`k;]4/E^v5rD^-=֐[v|!ic^Ǎ5ҍYC.q=lǁGODo]0CmˆUiB: 55iOT?fuqԽJJ t5$==ە݌R*e; $C.1|BV=tn6 ՁDEz 6y*hA`#m0.]&[۲23rL+V5h+V ,Gtƻ8k\yuZ1L!ھXmZl?L,ٴzx9C궔t8]6qWJd\cSqə2'_}#{cѐ?M-wƃWjp;}%t(D'eY!ck^zc竈OSyl*(Pgm UhMҚJ}W'<jǻz*{|]kniu<Y_S]=am ~r-+[[A>S Ǫ̉#%^7g'eQKVK8GJ?<۽yiH[yټ>ޑ+~nvm\Z66.q̥wT~hb׫NNTnnz8 p{*:51 mb-cVV6#fKDmG3 F.Dy\D$2g-M:dY``͔tLXaq'̵#3Θ &d$S{զr- 1@Km}[D%-h@K-Z"mi H[D%-h@K-Z"mi H[D%-hӴOQc%-h@K-Z"mi H[D%-h@K-Z"mi H[D%->my55G=vDQF]z%W^yy ͽ:9Y.Fx͜p;{筋@9jC.Ӗ漟7;;xzO?qu 0T/m9}7WU>k']q5n |J_UV<| 2n@$!m`iIDATY"m <}ڴ=htP߿]H14Dz]S1H[ ]yQ6_EL.}k'M755-9{|_v?Oi:%ewi0EަN;,@do CҊ]eQßz @O̞;-R (}y:qy_=YGE3OTVhLcӘƃK_җ?_:\#g{Nر/XFOiՉnƟ8Q7G,#S)1bZ.I[ПթSof_|^׾7U҄ܔ 6lyv;& ?JՉS'h#yЗ))]tc/;V̙~η%>q4u?Ys@J.CPllgKF>Q@W3Չz> Erȑw.^4r*|>ǏϝmDHZ`ݳϩ%Wn4  `e][Coǎy']6_X%Xa}[w?~`OX۫U~І?A ͽԴ|A >Tzчamyȑ| 9#G/D,!,׿\z8xRN0T.m g\^Q^Q!MY,7YzD3Ӗwiˁ5Dbb>sFb;n[ &xelVqnV0Ӗ'N^ #Ud7FXR혧tD3m9PO[DJZ--_|!z颋.R'jjkПtS%N"襩7\NSN #m+ٶM;hLIN?c7:H[Ξ=䮬Fiz׾vMBU  yI]6}YzHVDU#%5{++_/ƛL"MqBI9."ϱ>F| ҧG7d^zOl4&D̘!M|. ?Dtƛo^?uB齫4l`}u1}}/WH󷾪%Wƙ:zGELF~vWi)喊:p/d}Omhzc#k9GSS*h$[Yr[UV),?Xkm XcD}kƈTu)fgqg(歗58ig|jWzHVky^I$ۺZ1xo}JASa+dq>sKw!)MMѿ¼vKf%} &oXtB:6HџzT-[J>TCC%wJts*=3gsKŒz[J% Wel#GM]*o!F^!nwU8E_>[#?:F/H_J}' >͙6.);\{V(]"3y ]֧,8+r$DgpH;җg&Y1G^!ZiEg $jVj$vQʅlZ/b+U5or+>O&Ѱg_e:D:Zvo;Ė-Re ^oy#v#Qujsq&{]C~3M[]NYE h|4wQ?:a„Ζ~駞C^޹3:mƏu+oݴUxuV$$RkMu'>KٱShk](͙H &{f=]kϒVJ u459 =֚.RW)㓔ijϞz᭗G?[sۼvUs!}#rwW\uxɍ|R^Ԯ+P2:U?Bޜ^#](4asldl/d'۫*?KߟC WU8:mw6s}Y}嶮Զd*}ǘ_$pxR&+h{@8Çw/xzO?qu׆.UWm/yvO=ϿpOvPɇ @[:qfpHإaMu-.RkYd˽9NR3 qméq9ozK}?G?Nm Ź F0V@#+";wr'V _V->k{εÿLh'}1%-Hz͠oXbM9:mwuR)}Si9v:u?uy=od*{*]{+TB`{G6 |[pӬnyc.ˇ~λOo??W]ի_#*>"Љ3dCD,1Μ- \'ExW3eg$ qQrݮoQZv:A4-!BRr%؟o,pcs`2}ڴ7rΙ#^{&_޼[.}uL~nT3үlvw1EXK nӖJf]Q搾ڏv=|)V']RRһ|~{1bPkΊ7f@l92w}7{JuzȑǷ<{םKȯφH| tA."w6 2"j tK(=NG(9?[7J7I1- c͘gUBGl=J֎A@֤?0; =J2RI..Sش8%ӑswc]S~[{ld`1#(0H00$E :f(Jz*X-#;X 6gi $BZv/UQ`1r2DM.ܥ"])*Nmkzr2ӦӿsGԴ<;MM C7+W}ii⢋.ze_*o2([|]aOu;]oju]- ӎvRڬҲ|w>\3aLEr-Ř[Vm~U .u $Rus_-ۄ2GP\XhoK[ߺI3Җ N7V7ϟ\!"|#瘓(vj5IDATi{'y[WE4%0EDucǎ ߖ#x:##"Ʒ*;p Ѕq}kFx/-G >TFJ8Q?@ԉ7\/ٰaæuu ߖ>PFJ́@ӾoˏXzG 'O׻h[V!+_?vJ'N4˦O3RSS-x#PQכziOiK@4>mIyO;msA|G,Mo4igx:qˤK/DxIm0,ңoK@4c$t.R'jjk;PSNBSZUr2E[1| >Qʑ~}'tv3=wzxCn566^t:JL2pzW~-Y??|(P 6z"5FhmQD[ud`\zȣ7\Q;SR&{GZӷQ/:mAG̘Q`0zwnP_=qw;9rie}ןť˖Ko wC`H PUW- Uwym|@س5|.Z~+e6jeVG.3rEMX-]p~ߜQ H[0Y,?ovt[oU zp2zO|+1]؏XmQF e欟>MMMC6SP%\x]$IΞ_K Df Yϛ7c4yꔔX t{c޽;w=zTi0gsl={So}җ-^//qtԋ/X@o}$;ٳ-"#NڲykIVd_>}٢%wkY,@d~u?ߜeK(_&M]UW/ ׅKC`Hɇjp0T D ˧J(4rHox±c]ɸvv:p8M{_y|*0tҖK/w{հa{ݷӧ MF*+ʟSW}*''NJ >^]ug+rh^}ItJÇ벸8B^t4_3ol#Nߖ/6=Z8}kr Qy睗6khCгfިNsJ _ &7R n$Rz~]u:eu,*{c`$CՐ"IN& õk{7\O#;s'>}梋Oֺb„[%#ŽhLcӘƃx4ifPK[T))HZL[::}0Hb0Fuc/Җh+ CJ.^P%h@K-Z"mi H[D%-h@K-Z"mi H[D%-h4B-h@K-Z"mi H[D%-h@K-Z"mi H[D%-h@K-Z"mi H[D%-hiq,h0zMEhiK!Lh%O QdKeBdub9Yh0zQ%>>N&!ÅwgjoEc(_[o_vdpupk^ 70)L68&⓭7dۆxMe0]L\kPeWQzXC;qlZ-mXg-mm jcn<R1{uKf략se-ۖO5s:՛%^IB(zctqán+gJmk&&>tpqd6gB9hܖa+ 35Շ3;2s˿m۲;O(ޯ6[]r uMR6#տLCs'dxr}LyuX 1 wyY7Z7bڌwm6bT)qrYkhsu&mM >gV $v'ps39- 1æ*.9T-{EsXtbძqgY[c3upV}>=e~D h;ʓZ0 F A;J[#Qk%sEDDsec솆:xVųV=MO"Dgx۵q̉c-i:b9脦iKH6Z]ΰn;բ*י +) ̡4'1٪vt9U{+5d\u9XIq{"'y`}=2|NO*ƥS*On( te-2W+V8sS)a6ՙ- gmr_YsBf9;\At ř. <̙,`Fc5su-yЙ!x|aqޫ; W{@~rF{*1 e}!ھXmo̲ggɦs'V}c4NP~6w8߱)3yʽ;5٪rl*_u6F'|kחYn9*ܝ=1|>1D5Νp؄"qfR,0o[J,+d}YәOSߐ6m}%³|u׹";2+Vp\]JQe zz%X}aN@ޔ|Ž]:' @}[d ǪQkָyKćv+rL#}V$ÓmNݛ7(`ͻWN9h1F>ͻ>5'\'*7/.xDq}9籇0'\q{]D-9IDAT}[z߷eX@#- -=CA/{+ @ѷ@KT}[D%-h@K-Z"mi H[D%-h@K-Z"mi H[D%-hӴO #G0 %-h@K-Z"mi H[D%-h@K-Z"mi H[D%-ty ou|e%۟?4q4{20P uLSӘ/HAbcC4GҪ?:3<ۗb;wϋ;\|>_}(ICCc<駟Jׯs/}矿]8v#G0 RiH?3gΨN^niiڟ>ci"66v))v]U*?? H[ɓ'Qϝs(+1񢹳NKƓ)qmu &~*ӮN׼hV' q>CAχ祗^ZS[+۵&}ᇗ\z5WOfwsѸqQL￟6chE?:񵫾*o(^ollP-پχ~;,VO'MEHF,c/@Z"։ [?ch5zhͧ>Lc|a|RsT܍hx\Eqp͡۳G_'N_ lһo'|J:? _+W}\;@jjOn7/n1D-ĉ7Gԧ+W|{'է?@#-/s%%-Љs*uwO?{i9),gJx߅H\!M|EEh!Ӗ>dO_áN2|p(;tIƓ45'?So'}J݃m4pᅗ\z5WOfwsѸo4za>ɓ'[o˥7Y͔ßtect!ӖsQWWN >zD{ccqQSS[}gw.Y*^;iĈOJ۴t}6?y`moO[RL61YR.9+v;2XoNhvjE'/}K]{k>i]կ `DoCiϻF!}wU'.._={npW'}uW\}vG^;^?Er饗oDlٽ%՚*aVZY== m$j cbbgmNhX[Q߿}cHߚ=/exQƿ|/ >ZHq辫-SL͚~G_~ZB {`Ç_ӟvxʔDM-i  mՑD /s%%[@7zP3w8lo>ڷ)!m鋺e˲FYa={V<ជ}+/&¢mF,k4-8-/+KM%.7.'?:/~I qҮΚ4o .JK^@S &9BA-R\[73{=jaoe]?&l|zI&u~`ަEϕd0V]>ɓ'öpآ-tŞ= |60JKfɼO^cz rۛ7ȾkO3K1G vDÇǍO6}*]^ӟzݻzVM]]:7D1Q-zC h)y{SLUUCt{/59Vxz -oU'cKpі/yjW#W59[DUBcͷT) bM):7.؟Flk7m\$uQ)ƚtxڿ.ͻ9=?]C u[]+\mG&N}q"RJB'ͤdn鑟L eqf!H~0nH+O79!HsB*y򢔂@{ۖ.;u?Q}6crgzTJaK+_jPɻEzzxUcD,u)j.B9{lsO7]͟sp0"9)pӮ`tݐ}E.R'?i<11H>j\11Q U2kh}0~x8RT,(+{rˤz,fkE-?Q}!QtB>By\sקu:'Rڲ%=]r׫tuw_{*\se;iƎǿi/rp߱%))iPov/57.'ǠVC:}E&%ПRyP&gߚ܅D9lM:I6[~nUl@!UrYOk^%,.G%E*H%g9ܵQ˸r=!) zTfIiO>6QH;Fpλ{5smwKxgҾ6_8Ϟ=/RoV1ĥVW y\98MX@UQCut8ЧK [e]v^oQiHʶ2.N[~?ĀyiB:m+ҿKW@ߜ?x=CIIISnjTIDATֲgzw/UXshѧhI.(+vB*< >_/ߗJu.NlU)5WDG_tĴ fI:gq'N}{߳fXqݵӮ꤯ 5{k9K:±cݓ@G> L?]_җD%Ӗ?K_> uU$MM\~r;wXzz䩗zYzwWP8c,OS3 U_o`߷FaNhx7G۶B?-[@=_1cƈ~3w~zyE@riocԉܽjpN51rT?^ *^:%)+џ<.ٶo_;eu璋/X[#GJ9Q @зܓ@KܪPѷ{WboBN<=r􃫓'ϟ'-^د^ye^rƋƍn}~x~E9cy4mJr?9qB(w~A\:3rStWu)8KHv7PU|ŋ2Ov`)i111So~_з3o4N}w=x[MCFQ_N0!K+П@Kmh@K-Z"mi4w~zyE@?HXv :GaB>s 477 zx&M$Н-ZSYU++sG@eߖZ ԐNӖmH"]%۶ zL[+k"ٳgܕ( 2mTs9Q(J7LüZ ~Ӌt%޿foe7mn7Oր~G'K}nf-0C2xMJܲP:eJxJΚ?oތSRRbcc~T[.׾]eeuXr nL[^%wkӝvIi"b)虢&Qg5Rl&cM)DE9M#K**W-ĿkF.J7I6|ƛ׼z`Bx=́6.wwI?:^Dڜٳ~xM#FyxC+WGrkhq9EFWhμBO79nOpV>BuU5y9㋔I@.R-yGH)Q̖$%/J)1嗦s>_V׎>#xIצׂÆ U˳l.=+W1r&}}Ay&S^k*)HiEsc}V탒(ue]HHT!oJJRlhAuՑc24 I׎^1 32޾F! }|Y1w~zoFTXq%D-rO%C bRcE6(kJRT9ߓ${Q.2>0HG qzZDE*Gr?;=ۍ(pqg ܦz</ OE V'=uAs-[voIvҪMXEH7#dek9vyZ#TUuYCuN?جR7،zG#7jMt:a#rCc{ i2գSzJJAߖt1iԳ@s--@K-Z"miPrJi H[D2,`h@K-Z"mi zB'Nl -hIiKmmId0 jDaBjjkstԐNӖmH"]%۶ zL[+k"ٳgܕ( 2mTsȐ{;@n݅[SDGKIX^r6gwkޘ_o;yؿԵ9xUw9tHW/xiY-\_Bۖ2!..hjFo9BpfHbiSQQU|6@[YMޞ9oif˾-|yђ;_}5]4fWTº cjaIפt]D?:^߄̞S㌗nL[Fҋ/o6HV&s;4+o}=Z9(K}g\B5VVɕs*ϻoM3O 9:1 &k҃UD!Pi˯˃@ eYC`@h0]٧"0Hd-")!,{5Fo H[D%-/L$Nh@K-S'i H[D%-+.wsй]/ޘf -hIiKmmIP--BWVZY@zÄ @ i 4m!m"i -%۶ D*Kmt?~Wr'Dg.+Q@e"س5!5{++@wݻ اLILչq9sc2 ]; vo`1]."לl&l#ٝl0ƚod=vf$o檻:$ ]m +4./] &-IXk6Qv4̻u%K )3G-h|S,D]`p쭬|l[oϜuӷQ4Y@eߖWvhɝt]CHX+*tS^MR+$y܊Kכ $jrҡAQ.mݜ.ڜٳ~xM}[Fҋ/< ǎΜ.]s*ϻoM3OXkzA!w J]mD]$%Μ Uot%nZ( ]zʔ5d:f5޼ӧSS R_fO)CJkJ׮L: nΪ|i_8t:EK|5HX+*[R-^`qS¦@zRn{0fXNe+Y"Z*(ƛGl#g})Jl͘.]樌66@UW8a9g?T8%S'D$9jˑD#G|Ѕc .]ѮKTviU)6R[:]o/"OZsL:kfmD-R̷H D`(t[LՁ[zEJm(ZХ3.!G~ۥkS@H"=wZdvg^fvIM.UJn#M7TlVf `7ȣܔ.uO:R W봺J^䢹kt0XIV$MN}[yZ+ k-l*Hi "OJi H[Y+8-Z"mi de;Ki H[D%- :uA:o H[˴vҤI-u@1L-:pF@&tV<jH[@iK i H[@4m)ٶN$UYm˴񻲖|> 2={v]Y .IŞ=y@D&!H@`Rrݥᆳrl 콽\yAuK(5{++@i7v{SzZh(}HNr܅u/ur\n)plƮuNhƛoJW▭LIQCϡCiY͛1}N}񔞷>8Wr$:O>}M{+]ʂs͕.˴啝//Zr端>ݹksr1rWEɒhg8rLeI}$[bJOcvMLFkG<$UxZTwdwSҪuixmN5#PZ R¿nw/2;5vZNeG.zBb})omRŴ? }{OEgZ?xbo l=63[w1# ٔ[ߍ0ٳ~xM#Fҋ/< ǎW4>Ǚhs#u2F<"}}/.UG4;a-Gc}-Ų+RQI@R5`m%-lsXKHG:;-ͽy݈fIN.6tɺR)nA}h)؜Ӣl}Iěg .i\h9l|hK쨣#$)RĊ=آJX~_|ֶr(t9(HCeYC>t| &GlTRn!CtNmԶ3xHX:9]Vep#kɭs+R{OHnw{P$&N( ”lw(=չ>B٥`19 ֍S'm]aFi,җ"hGIViqޔ[rTtf]QZ6}jr;b-IDATx~LK ܛ"JNN_ű*xmWQ{ɝMt9ڃ'a}0)e&@9,ERޔޥF]>H޼ݸ+rW]N^y۬UzTa8D]|AI9Y ivg6/җ.7Ӧ\A#hZ1]QZ}1ZuQUأڿJUm .~4Pi]e{_tZ{5dS kCi%fmJ=ԐM n*vwf=Ni1 !Kothwc*Z%7+guG1xt8oY*+& nH2r" ӖH"3(! )4H[k LJD =ZG3yO[$;$ѷ@KC0m `ѷ@K-Z:iKщ-Z"mi H[Dڂ^8t & i H[˴vҤIsd2ρ50C5@9PC:M[jH[HDBiKɶuuu@$ʒmD=]-Ǐߕ ٳKjhhtH*@dȽJo"ݞzԷުM_(<50C/=r rࢶ۫^`iHƛoJW▭e2eJ:9t(:붅6=K׾}n]*W]G(t7HOKɭJg Rn/efkI6"6nY7}[ՙfQ/F+;_^W_}M}s.!MY,^4[ G ڜٳ~xM}[Fҋ/< ǎH|QxD%$] dgĈEN!,b~yZH ˗eIѫ9rɕg6 )fWT/tt})O|P:uA0tܷ/5kH'viq䩃y1ڷ!G}[yӜ-BxsX 6gs-겔.?3tQ)JJ?i&S`CGz*g|#XbD0 OE ca` n[D$!,{5Fo H[D%-/h@;-Z"mi zD%-h@K-G /`h@KL[jkk'M$0x>H&I`8P# :TS[+D5-ӴD- tl^WW'D,ٶM@eR]Y}>Ξ=䮬FQOibϞ< 0DL&a^Pz_^$r_RH~c^?t/vl Rv>wa*\ot%nZ( ]~2%E Y<Yg͟7oifTԩ[Yr[UV)]\Mi+;_^W_}M}s.!MY,:7.ܘ.]'ƛG[|٢?:^߄̞S㌗nI4rȗ^| ]8v@Qa-V)ҫ"eQ(Œz{\.q >.]asYKKm{1e%IUUӜ-zfd.}1B.>*!},!0 4<'-TQ!'/ 9;E9uA0t|O"DuF⼣~EMjEXwrYh Evg6XA| >w voSA\?Zm+HJGB׎vl2 >$%bӑ--eБD-h@K-`1Zi H[Dڂ^8uA.h@K-Z"miqxG`@G-Z"mВ.ӖI& `QoСZ !m-5-@$"mӴd: HWeɶm.ӖZp%we544 zL[${ܿPg2LK- -[Y)M[$S[=R%~Rܳ7ߔ-[ @;@O,CҬϛ7c4yyTH]쩒Bڷҵ,8S'}qN|pђ;_}v , >w v3j_awH1rQJ¦5(o nhÒڬV.ڴ1ZpK[X]{Ok})Jl͘.]樌66h2;2L"̞S㌗OOld1.G9_xxC+ ٥>waFhvZv[#HI.r 6ۭe˭@*J;fuI^,;Q\)^g-,EJR6尤u]"lg_K>d^P8*WZF9 ]q >.].G{%۶K={ BHKT.w &{kzOR\s%8;VoEnQatYoqsbvIM.U&*U["֚NQ㐧_#dYNdTŒ6bP8mJ'˲zaV=kYl03t0NBwpಘdkp:%9Q8@ 彎ZG!e\%"Idg$ qԞ\ [!"b,)FE`a)mqUeO$]8V*7O+ٙ!EyN#BQ.ҡJn!jT [=ZD:7.ߎ5.˶KUx\VBvYܐY:GN ` =J[0o0-] mFa(+& a$ * m@i5`E5J)hj ڑ 5`Ph@K-Cĩ D-h@K-Z"m".ws@z4H[D%]-&Mԙ[[:X9keJ "ρiRCD":M[Jm"tUl& 2m?~>O gϞ]rWVCC˴ERgkБ\d2 nX4^n&?r;4-J/0[Y)M[$S[`)pl4>vܶ$]x7+qBPS!С4͘>lj:U`.e D.׾]eeu(tEK|ԧ;wDR^Q!p*riHpIDATi"fvQy1]N(y@̐U1)gmV^`q(;6ݾ1ZPhf]3t΅̞S㌗nI4rȗ^| ]8v!?@R"%nwћ[-^g}Hw>/PEY?gKp䤯WI6u9J6R..-J;f^vK MKHx_vtٷEuݫg--ٶ]zٻW@{N"J%rGҤJARV_So"#&ZҜ5%55F8QDGǫN6^oK--5k-FdsG+yۦ?:ߘoyVnHݘ km֧g2mk .Bv.t;;VZY!ѷ":9jAEzD3ҖsGiH[Dڂ2KD EڂMH[QU&I~@%-D,N6ПH[D%-hE\^1t,H[D%]-&MPL"0HVZYP8P# :TS[+D5-ӴD- tl^WW'D,ٶM@eR]Y}>Ξ=䮬FQOibϞ< D쭬-O}jVlT4d_$]wxMJܲPL[LIQ'<YgݶpѦڷO b5{z}:`iw=[YMޞ9oKW:s, :~٧W-W_k b)Q&ufΖV/08ZD՚tdv㪢&@$H59[F4[T8uSMy֧DQm.Z*oߺh]h5ekÿwcHp:¦nY+.6g짟*gD}zd$#G0 tٷeȑ/pX.pْhvzV>*9%RNaY }|_.J&3Yd3*MWQR[ .. 3bB]D-un̹w|ncǦ. ULIٝ)-9Z$o-*[UuPg{G%$ՏV]N9&C*xSSLR>*XUDTu{h'b\xo1b(teYCD?W̻9]QE!RcᔖĶ8 c-eJp愧B_pNOF!TW^.1m@l:'Ήe%VEVRFݔR.'l.i`ױV ǘB׎=֙!f]ws@^ksf~qKD7]$9rK/.;V@kG B>;3V(9^Q(ϔQV'TnָGŋoMQO}[TܽjyҒmۥǞ{]`Q&1q #diVU%DJ =̣rzkYlzչq9jEǏbkˬ /%&.ؤ?'gv~FQH۩$[A7GIX2޾F! -B|Y?W`і8B(}ODRrHEX }r3y(P!`Itq%8jI1\#h-Ns6XM]/ޘF0 ߓ,>Khqޔ kLi K7ign( |OB9 4TMؠ+mpJPr/ aE\WtW! Zi@]Ԧ6HSEIAl Hs$iޛNڜ|蜙g3o|_AҖ}c<63kfi @-qC>p_l$m N8I[$ma(?pռd?^GH[$mSF-O>0n 2\Xc{ڵO ēOس i @-OH[`,.c˖-0e}^F-OT^OSY{`iKhC}eѥcIә3 /Y5Uf͜5̦q璯,zxM[Bߩ>Y?=C̹<d3|Lţě{s@JF>,-ן\tG{I gΚX޸&}<~V^Ս [~'0&5- GRVB o+lز^ WO;3d3TNv&)EZƦֺ_=Y~gR2'Q9,|?jwBÂM(qeW|d`C2m cߌ/ϙJÅ]|N5uI9]GϜu Oؔm[;vy{̙WUV,s]プ|̬ %EGٱ&3gvՐjd=^Egy&8ׂ 9tKQro,x~Qrp"i X̚.4V3sEG"3۱'3 #&m N8I[$maX{ౙY3`W-qIP>p_laI'i @-qCrm I[$mS&-o=?ēO>y{՚513f{ڵODj so&x{>љ$`ߕIiˌOH[`,N[Nx{}U&-g|cD;lcI],>c UN3kf:kчΜxIS@xtW=zu4VVVVʤ%t9__S]}‰|o:p+e%'7 Wә׽ڞ%uݛWߵyJnn<ኞ[kGK&<a=;ѵz va}|cpago͛ג3S{W'*U,z,QQnCæ>kkz&eXOȁx򚷼𙛋M%Ԭ*vE%RYϗܜ,zgzx]XssɄ}{4Zbf;VR(ut~JϪ5cy㚎DqCxßԶVD5WtE玤vpOnGEu #ڻ5 g>&{UɊ_{챨hrgc^n"Z#?Ⱦ7 uvz ޹# ۹Jp<½t 哇땆v~zPw|'-v7o?2mK3e jz` 0jOZV%0ԝ?z?,hh8yԼ  V}UFL17s^ g\wEW]lsgۊ0,h W|-Xqyy-,йSU:ZZZlr'|Kd=a>7kq3«J_w`K{{әzR'{OivF~nнJx:ntUm=ju?+*<9ܽ`Ɯ.kkN3t'p@@J-Ag+ _Gz0^ 'C̀KBrwMFM[7ȜNY}%MAK+n 3JivWnP3DϚǞ&ھ4|gN8{z u`;YskL>P3g~ORJr*0 \e^~=`/ȞDkƗL^kPӅv>C7w9YrΧ2vI=w9gg^'KMc-hB\ѶNX+|*v4]a} 'LK%!% AWґltU8|rUܝ!!NVN^|05S.B#ݞ̔15-vlt 5(wmgQr{cDIu OU,лα]']5gZ;.uն&VֵhAg5оؑ71||΁o N~vcёYߵCFd"i-5mazs[{8k}2ヶ-Cg1! | mIq[ˌ2{-#}[ Г N8I[c8 `h8I[$m N8I[$m N8I[$m N8I[$m N8euttD8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[_eDY}{0JK"jHd_d{1&/Qӡ4W鳝c8e4޺%ZG'Fl ::mX2-p䞬w{|O ;c9-i6Q`7 mK{sMEQ~"s Ҝ=PVS*2oY~ټ7VqqRz]PVڳaѫҚ겢έNմ ~*]׼4 $D~e}]9Z!IO\`ɣ^j+M wv(k1Z?Ս>%0+z^_Sy@?o.}ЯF?)SǏ@jcj X90:::,^_?/9r5Ut o'λwͺqCcy^׻Nf=juKOd]sE~Tm{}?_L8笖 iAϾMƪ΍ɦ]}io/7*MX"o{shrϸH [ºzYa_`FsPWzv!YVWFWLlK:P롾;!@@u:-i^ijo(/8妍(5trCov߯cH㫑3T{?cm[זE7/Xmmne@}$-!3DVۡ+j`m/,?1|ʆ=DEf-sj뷭IG-WVчJ._0G>%hm4wIזlIyo8e$ﲊ:n}tk[F"<44um{Ӎg䆳}N~iuŴ<IDATywo{+UyX,M.ݵ%q(k̛3nv6<˶xqK0bi0iqE vv(m`R;4q|zn-HsOӹҴ,/Zrϸ1xou/?=%F?ifDZI]{]NciK[['DMuhi\ ?Ew\֚ znguEgU.NQ]S@e[IW6>U]pKiIn坷vyDQx:4ӮYZSVеu-+'o.+);(+f{my,jj> o+/]ڲx~ے%jZʢ+S|c]Ht4y&_PY}EڋKxw):O5!4/t5VޚxRW]ae\1i51ߌ֨O^aa~^ K۬B [`Eڒݤo]vde'EUۋj?&"3+I&Q~DUa{WґݹͭskjR=6fUVSpenjnfXSڧ~EMg@emk7YUOYTۿJvIE?mV/^ܷں ͏v,뾧UwXyMϾEQէETEKmuFgNqMnvee﫦s7#v]`J\_Vc`^T=츩6\!K ]U7E~&rV[ja$9(@Z{$ W5$6F.ҖDYu_Rvlٲe7\|μt:a,S_Y7ؘMaZIQ مEڃ gƵCJoYSnf=yZQ˃k: tJrh*-ܔ좒x架66Doi@E%+xK}Ck[ ؞4/4DLtz;j ߈~3 `g-k 91^ӮijY\VWZp-'Zj `i_y7 Lhu{U6}?kjH̾a@r/ZQP퍋g_;=Ɔc{lo..p-^RjK ι{X&q{k]iz\`fswأbwQڜt.Za[CE;]wrE9]۝4%K ]-5E;ā^_7ti8?A:^<Ĺd]QCm/1r薦ZBy/qqR'憫,Xtuit5$ǘѓ]d'ލJNquu˓crRn/Zr{x\wQɍ MۣQmQ2m/l~7'v]}'ӽb-sT7zYٴy[%QZBjKv\w`\IwO巭ݰ_D_ѕN]wO ӽw]Qˈy +-1Zqg״eI]eSq+NyL7#_8PD-g ݶӖlX k hBk{[}yIjI,.iK͕Y=pD4H%ջ1 06Օ&:]9/.sOJ2eHϿq % NF N8I[$m N8I[$m N8I[$m N8I[$m N8I[4hחHx}-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @ HO/iO>s!9lq!93 nU~ƩӶ_ޝ)6=y{Vמu10eAoj3|{c4 霹']oO81S廚gu_9ɹf)^Δ }qm[޳'o'GҷcOn > HIѣ'~lJwYCW0I/6?ڵjd'x*!Gf}aKNy:=|1'=;'FO:'՟'s/L '&Х;Iyѻ}O?7xSpݮ*Mc ,|;?D0^MƁdzў3|4(9$3.9ΗoI!S>w׉'tVr1O4}8?_W>zKw>qgW:kxO>lt*uiC݋Ι<~vp}{n^`\p__d|fA_=orgo<)`m[~>Vȝ7y֚IDAT}MnI ?C|oW?uYaVx>4''М)G} ` 屦o߾#xÅʏ9^7 +g#u+dSOws0޽cƶ{nnk'N;gphNNֶ%Q06o>#1ɸ-K[~h:1}}o#mgdMw9G?"j7=?ߚ>aCkcF-y,(Y;1`_u[2ez(1#Җ-mNsOow7lcC&=(-tЁDw`V=ēlڴ9KGy䣎>=s`4|uOG0d3F/}ϖ淿 wKyg7GqħΙ%Fg߶TF_tqKW^y_B(/~C} zQHD// m9萜h]wm۶|s/iG㨼ahmiMO5?o~;{VF7&KXm >+mUa Z TQy#ɧ˛W5 e?+++.IT{ǝ+߿tK>T;o/t{Yv `I=F=[q~eR0f~履ZT8=uj{$gVE-'^<|YYVlfm g^V{?y+_ԯ7"wÆ~;iKҊM|8G8p̙YWý} *6^xGJGU N #$}}zP4;CJA|鹪:ƾN j߭> wΜ5ܼoӽ }&򳪆c2`Ԏҽ N9t-cҖhxH2RfovVQ^UFx5K?Xs»y˾磻oRMynթoJ޹_?ppRN:ܯ _o. N-}LI~q UUpw7zy2Y[uI=a^>? GVS;Ƌ,9kJp7]%umqLڒe˖h=ߓjyy0$Ⱦ۪;0j`ow/aF-Cn*N ;}翔n[W٭8 M0K/zGk:~/ $yG_)ww?K[ a}>[.Y}. )_[pܔ蜦]{澠+!MZ[xRG*:S[ O2P;ܯS5`2*Drf µ>>='unƻQL[:$k#(\+C/}Oݳ=={ U蹺6ޝWEӂw5X!VsaIGVܕ \}O;dYT>]YU]6PVn]#vnv^Yӂj:Ծ[^ltRxSq׹y['zT]]TQRcAuiy=7Unpws5v>}[Ior1aa2NvǑmNRm1RA%._Z_m&!A]_>{FиfV5) :s*u0v][i c>1ll 2_>s6aW\>&]ݣNP;yeFwͭӫpXRaVD(iaEKS R֤0-%MnV=8UrN%{ z yMF Oa\.kw!2gb]x/{*;o) $mj#\ƒqXzen2ra~%{ S`ʗ*mIu麡rZRG Ğ28 ]-8Ut7/Tvv֓Qڍ N\r>g?5<+OOSaw_xFv򎯪?%Ұ7`Uz k0~7o<_skw.>5}O:kCT%vh8`|9\c8$+v5JLU%ۆ =mT2 R_꾅/9N fv5_]|R,hȺعu`<A J*OM }H{hij&rsswO<䷾z{V CdRۖ8;zq{[M*T(C!,6h׉A 4c (C1U꾽; op4j0vaJVՕu5KI^3# FTՑ|Ԯ4Yl,|`Sg$8rjТ"Ju 5JY ]OH 8YqzTGDqa7&ܘc{ztu-')QGޕ^pAܳ@쯅}ik0"CڝDge}ٟ, 'r˩}a ܾXqճ;J7wCƴn Moǯ$mRd4lm޾'S8]3*izO_ ]抯I'}'S>źF{?tIFM:>6?/WO5 џ R6I\%b6S2ns<gٽ#u{ƞ9q~zjj}p6#TgL:|}4V2}=D601YQ2c>ۯ濖 'dm[:=jUGNKXz wD?~vaas>; IDAThE8Q߿տ-5Զ;W0 N3 sO_uH=d[\\qЬ/hjn dRۖ=˓Ny N.O0 ͫ>6+,?o}V761~oj 2- A.tus>?Ϣ?Wn8S5H㢉2AiWS:Ӗ<o?[+|6 6Fd$?wa˯7Tu :yΜoՓ>D4HH[ m<ϜW7L m`ڲeKe؀egI[^OSY{{yӎ9C`@uW=zu4VVVV@GsoY>z{qE ëW76>ƕ3Ük92)m9zQAWz'ٴiSOQmO_<-o?ŋR~g40myW?n4'ϙS:?8 4Җm۶>ۜI} ySNv1(ˤ;O<\nGG?.8;j9i{-D"S2)mCmw?s_TX2~zk_g(`?i{߇}-_Ǎeŏ&>yo`o?iKsss4/LkݸucS}̙3=hnh?i˖-[Y;1g?`lu߼Cwogu1|hp'myO&w!~_-_)a3c7Ι??}ׯ|zW/]RI[zÉ7|c+.}o۳b}w޴w|p΋/ S!󔫥-8J[(my'-}Zr'VQy|\apsivSzWlJvNu> bII׀Kg(&xƶw/,.Se~koKhgbIiѓ^.=&j=b.MW}ATyG&)S98׮& V  5\?}#1Ow ʷr{G//;غuk@|O7aEӫz+. `LZ>J'eG>~!V񓶄N3 swO8q70457Gs vYҙ3.{۞ -?i L;&J?y`e*իeNȼy?ivaYzp^ᔠy/<2/xIy螇?'ҖM>;bs>?Ϣ\T˗W `̘6c.?@dSZ`JaK]:c;ߝ+m_,+GnCrɸI9]V^791qX 6T #(d ib71{b(iK󟻰׿IIڮ _3H,GVuuq߅h^}QI=u~漲XOe~Yk W&>qY5쓺;bK -9m魇5x`Yߴ>HG{{1 }h_T0nm1~ oxC8ڧ#ⷿL$i irye ‰ۃ=/+,ye|p@|-W\C '¨+g}?)ßbqïWbIiOpoy|S4?سOUϥ99bI=ƋN= s iӿ;f}x֌g?7 & _5zͯ_\q)EsDT^s!k*ůW0.ŋ@{饗@~F15F}ү^޲~}G㮹) 6޹.xۑG[`,9`=Q9Jn_2a8?#wQ{?O~S~6DG`lȰ-n\ײ//|ΞokYWںO[zDbl.ڶ2lܖg6=]hOz7c-j`_a=>pr4_1ƌ K[ܓfF+W;vlX$g彿Z.>]_/_m۷~GamgednÍn|{>6lk݃>5/(QXaVۧN=3v?Vy,~ӛtgc`aF?S޽/b8簷%`$AX.7q~߉322m$,{ng> . kV)#ێ827ַM=ƪIcD n0I[$m N8I[$m N8I[$m N8I[$m N8euttD8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[_jz(v_kU~T[~Uk°ª2';-㵥U-.__u[dCrۜJ9Jyʪ*z.ˤy︩Oڊk*,+=[$ʪjslaE}K{4ڪₜDY}4;/U0q['Sx팼\nף$QXU mD{]Hd[4cwuV!^z*zѼ杛\_(/9NaukLVGG`˚+g\~s/o-Ņ>uu޲9zM{}Y@JY25k[mI9wrgZWH.7܋VԸ81^e]Բe[Yr{}Yޠ;P{Cy)ٹK6tw /In4oo`_ۖ߸`܉s'N?mW6m״nXds]dyLDi] M\ԣI/YAfNp&u͙½޼3j ;L.:E~Qt p#'͟65oַ]m3 q iKua=>o^v`쑶@f-@Z۷._|`{>c 2ʎ;`N4}c(ȤMVs/RoѓyE IO+55utt|E}tHN_tqZ|ʫ 2w,u㫯ֶ/C U&mM@>෽h۶|ozк f{AE#W=jU8q98yNZK-W\i/Mu85k^`|_?+?=޽Mo&۶aJ-󔡗#2i مo7i @-ϙ|Q'.&&m}ѓ _CLJ[`4]2WzJ\fAg^ַE7nƪK OnxsքK=h^gUnBѷ|5$9_\QovnC͞Pt՜UW,(p {W\晅ݳ=zSJnn\>ϱݹ `q[_!8!dnqݎ5SwkքmW^*._ 5E7tPskUlkycfh= 4^zW.<)UD6;'֤ tO깹h]z)씺U2]s1yl=gc(ڋM۫Q.\(h8^! h S~CŴCr^?r`^%J™/yWZ_wȯ]1=+,K]{´cUf^~Wu'50gasX!Nʀp Fs>5g:vwےQJlZ:ȑL6 'S{dr=o{7};@fʤ-[ztu[0aΗwvhbfk{j|튆W&ݶpƗL6pm ?^iylW:h>3I6*1-y w%K7+1D` 8da0f|M|j#>ɴ商f̚Y()z!jk0Ssa7` ]2 W|mkL.ՇG'w'صm2Im~]|уS7W$J (˒ä@0{k 'G58Kqw `Ӗ_lzig`sҲC׼k%0OQ>3+5IA"^w4=|0LQFܜӳf&Xgt#Ye>.]}xy(]4nKr0~=wo)Ĉ}GzƕLj۲gW0CWv1h֠8m~~:wL(j >SvGM\Ft3}V׶sk0~JYc`N3ۑrN>}#{@/TOK&nɱHgf/夳FGQ;dˋsU;Gpî{%@!LT \=dcdካ6/*p~W}JXxs]QŢA~L\!Htң|r~t@'KoNjN rzgtG={k^ 0bKQQNCCw5öpE‘}?㒝I;#}NͿ|M跿.ui ;O-N'i @-ϙ|Q'.&r٥Gthdgo۾=رcĉ+63kfSwGO>*|#r9ѷ8Hw)>"C)_ݍeRΤmmɴ_<`sȖ#2'ѻ=vw Ѱ`p__NkƷ7t g\؇lv7M'9]0 26la{}K/55 ڶ7#ŧ%06o^^ÿnNO0 9nӿmoQo;#8mo 6=ֵlhNufɈ=ڌ?w.w?t݆ w-{Vx~򗿪'= 9XIDATɳz[ԥ-8=7Coj^H3^o!RXq\8;;=>CFS?3 s%|mzt wL,'M ٓ$Ɓ n0I[$m N8I[$m N8I[$m N8I[$m N8euttD8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m~AFk-꡴>ƊDVU^4 m[m[VXiÒih۲k;:jm[ˤ>\SQz]PV׺J5 ٝ$ J[TXY}ҢDwAh{k}Uiۂ=π1C V[s$tk6>Y/ Ӗn~Rn-[d]sE~4F ܽerO,yd]cE~y-5E=5nkʟz dCKEހE´sΧ$wywqƐ۶VFctLY|ݶϟY{qeCjn[MAT uLIryڬ ;qiniBT~'=rqyMVaFQ˴77xFn7tӱQcu{{-R;۵k/.^c#0?J VZSTUqIEE=Xe4?)fō=J5Aʲ|dZ֣]T27/Fxbo>`M޺eGD" 2h 9Ⱥ!t?yqWԒ6#79_oD^4m%774E[bK[eQLҪ]6Z!9mNgD)(+K=+.kG`-m eKRn^|laE}K{4ڪₜDY}4;/O- C?<_\zkguPUteiG`lYseKr͵%=LR]\x[Xg-ʒחE*O= jK ι{kL<ֺFriH̾a5^:zR!GtW;n\܊pιgyޝ3-mI/oh| N˝=wbnn,qemANqM놕KO.91wK7ʹkOֵtE=*;}n+G`lm ڛO-qIxIח%ғ]Xc-5n ҳ -m),[g Y11J.@-qI'i @-qI'i @-qI'i @-qIAӖ5ؕЃ-qI'i @-qI'i @-qI'i @-qI'i @-qi\-7|;`KO]مoZFPkǎ}q:m|_ho(tttn|e=A8xS6lX_5?_P@ X̦gÉwwGO `yW~qNO !ڶ yGJ,0OWLaiSOym4<匏8u!|y67yty{Q0=nN|ƼLJ[Z7>/dghn'=1ݍ1+M?:$'_Lt m|晣'0eRۖh%yS&]em5W/]ҡ=%S>[CGx޷:::\ח#_cC/ZyMǚ`63kf4;}m1w#3zЁO !m1\0eR0I[$m뫢REIiKwF<;2)mnid j͊˃3 ϯ{okY䆮eln΀U%;V,^zzVu[E7n.6]wmY۰,=zf~[@E:Iû z:SS{~>du;֔ONwYJ]Qxɪ`p:ukߑ*s]cǚKXUlꪪqaܸSOxl3Ѿ+I~dbr7ڑ+*Zaӱ,so. NNw!tHNKWGNlQVCCÕW^9ti$3@3^ڻ\y-SX:PMmMxjXuIaV% hg+-EodC_k8w+ t:gnƗL a8Sm[Zztu[0aΗprG&LO$EvE+n[8ĽwF Flds6Uό]ر [%W矐z܆/Ȅ`S݀Dӱ5]'J.hQe|&+ gLM%6ܙս/nx_]dNY}%M_77',_Ȫn8wi~RxrfByYhu %J>.=iC8{x++ zǓ4Q6i/maCUE)>7PqOC6٪kÒwګ.Yl}367l ?/9`ꪏܸ|Wͼ:y%qChKSH:$=so\z;`Fg!O`Fw$kϼ ٙŽ۝'@ә ^pO0xh+ tRM\Z׈cs4ya(M9@89͚c:W5ӱG]"9v¡ؽ`dutt /m FdEYۖhb- t?GTA'Nh:Zw =D>:!6W ql2 &u=pk\ɝBq(9=xVVw=w[s:<7큶-#8>@ڲٻI4JOm=`l' 0jgAFټmƼ۶\v/EP>wakÉ1IDATpWֽ{.Ac0s.>M߂-ڶyo}Ď;^aŏ&>wc[=`4xs/<xwlz6>3ƶ K[zQ##Ӗԩyk=gfC!gQk^>sD-'x2m $m N8I[$m N8I[$m N8I[$m N8I[m[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m NZ]UXѭ},wZWH#AFdSGO>itkK=>-q'Q[mIvV9osK7 b{sMX4ѵrNW[ƊDVOō=.-U N/[\UX^>vSzKڅ- U~vם<Zu]{0\ߣeUT%9Z1l<.eE;K~QEMs[u&Jkˊw==qe㶬tޙ޻vkۭ# F4Cgݲ억.w==djKUS]l햮 ߱eמwkƑV{9gw=WV즴~`K>G+X{ũrwpތ#ȯhl㗝7[ظkwl^+3-ҺL랑{-^ѱm3^\[Mܝ矲`dюm/[`Jr֖{+7/jX 59m=)lhZzsےC'jtƍMSܚNprB];mɆjw+,J֒;wA +_w;zk镍S0c▎'h/tpi]L&\3z-M`%G&pI4iʖrv-ƺ;=$?uS_RӼr~V~ҝ] &:6ԧiE#9omݘ70?UnMqe}ÒYݸR蠄UWik4<Hœ '?햆]o,.!js Eс hECk/.%+/\JTL8Πb}sk猶S/,vNquubMU]扂T# <$/j.ܸ6U ?D*^:'u -0)i, HDp7TDZsQ"gj֍5}JW,J mʊ^"hn0컆۶eNs*9UPX1^[uS4 ƪdҐz7 +k )[lY{^x)z@vAn7( ɑcKu. F*㘆aWϸ6b{z?bK[F0ueGcccM]swTUܘ[X0[:׶mXdi,ٱyyp-E#N$79rŖtÒmd]Z*V+,wmUi#=ʒGn4mI+ihiO3yo_`V4Jnc^[r$Ӗܿsl`78_3n6T02-(&xmi0ElL`hkkA[vDVVVQ9D~QiEMcK{5n ֚Tw VWulpjq²e)S$JUw?Š,c{{[KCmUEqArD;مwV0kqEqY;gV?Tg+*inU6T\JK&]+QX(v}uUC[:- E&Qј 7ZmGsCcT&Yk]UiS/~dmN#9i(zѼzqiQ^r` kO`|xI[mI9w1'wڒDseK3).: f-ʺCٝq䳉N3yGmI0BUS/^?YK5Tynx܋VU-UL<ֺD]穽`M|Eۓ[Ҹ81-}>eqA[]i˶0;Jnv~yCo\0wZsss`э+6o;/(MEEc酻3hK"?zts]dmE-](iݰ#N WђwF/4һxCN0aWn[|is{ <)7ڒ_}a)?m }#m N8LQ^_JOvaUKW-Azvm),[g`oQr$m N8I[$m N8I[$m N8I[$m N8 xqA8I[$m N8I[$m N8I[$m N8I[$m N8I[i_'??C4a cM8g@͛0:::\חcޯ֭g3 ?퐃gǎ~[X|ꇏ1' =n˻=6oʔ<0è%'&M:zQ I}>sD- =1'? `4eXڲ;ъ_|1a;:$no_:QIiK[ۖ?O=[qGz_4ē `dҸ-7&sL0tHN0\v^8G[0_GF N8eR2gc +IDAT[&-_;}mɉkY՛p؄=Z≫nοw&=xݜ*;SgO|\-dWy(m>k oKM\Hk'E7wY|'g\#91`e3}S¨Ս+\`4bۖғypժӗ^bKU\U>& 8k*W0V|o;w7o^ ڶdU剠}p~VukV\N ^{챦oJ4T`B~Q^z饖|=W땳f˯رcGc@&-eee «J&^{v'Qԇ-uWZ A[w可nDnֿk`oŞD/fwWr)`U3X4+-Yca4].M{ dnJN#.tW/]U[O?po~ۓN3K`ѓ(C͸gEÉfpXD3>dI'͞;joXr?cH[2Onx-ڮ)|7K钉:'m93R,4da|yNr:7cf[?<ޱcg3=[KhDSt95v 4=n;g ե~O7h8q>sn9D/hy L>ꨓfp"ѡ'ǻ;ضm[8xSG8O'Mڶ0~~ gE[!!-]xK ̚0R:!xO[:dH[ DNNN{C&b viODDnlzvӳr]N/{nl*L <¨ՍI -i 7y}4O `o0N@ ߊ/K2)mhgn `Jl@TŦX mmEAY>ҰڸJ a]IWATT-(MA$mAR/$M$M¤M߽rfܙssbYMMMQ#gH&-[nu|뭷BQD#w=H7n|l_?OD o[طyryhٲbƍ/B`:C_uYg},>5hӖe3@768Ӗ9eW63ۿ)``li֭[y+W&Vcw≁c9}J~\?U3fF-Oo 6f1+@: "?Kkj%%߷Tem˛o}qy„ח_LJ[n.矏 Æ n;Alt?ƽ?i\8wܱvas{.G5 d4Yzu\Ї>3Q#u+\? q[6m& 套_ MLJ[yW\(E`@ʤX7xz DfÍȞ ?׌CXӄmHOqڍCʭY&ACͫ.*uwNx ae^ӋӞkxMQ޲'.;Q'O81&ϺmsI`АS cL:|{?YXy(jYOEϛ7'H*͓msډd-{[(':  JR~aD2'vZ؏5ғ367>ӧG%wOR-S.k3a]8ả_E?d%Ndk['4mƌ>&zOڶAgM[RƞLtӝON;ol:kòa >Җ^kn26ՙkSM[BمCTvZߦtֆp0I=ץZ\:#.+9z㶏} Q!NL>v?~rx'W^(.;UsUݽlc#`jjjt_^2q6lqO>qe7B3­߆m|.w r!#Qrgmh;o]{y7]<}JNϹpOryǟzY밷DQK3N.~"mģ-5Cyaoz.$dm=r衇\-l۶?iCwv/u;.@ʤq[yW\(L'q[|_y%<'6c=d! g;vo9g}씓?Akݝ Զ%ߴ֨{>vAB':QU CH{qS4Q^ I'JXF1N`}L> /(˛7o ˉ'7zر#}Q?TcQ'~/@ttv:._Uvǟc˛7oْ=رdi G S#"?ɦ-9&&i (aI-۶o3: Gx≓O>W.PiE 7ߛowsWKvl7g-~wdL%'i.ݯy$Y׭;#?>%?rɁL f\2N&-=k㾟۟O.^!e:]e޼yiQ!1*7N4;;={ZVec4]TRuEˮ?#RP u2\kzvܲ m(Ȫ /No5]-Nk?W]9m&mؐ[IC>.) mw=_:]}ѢCt!򞣏>'s !{` T=b|}};,E7XUfPA=44ܔ^T21h u905T(QԲvQKjʗniށ ^9e=uěMWpMM~ڜtsmIsS`%h&}XJdҘwM?ʽ%+i6:tԒl|a/x׭O:M᫯} L[b_'߮rUUVxZ^-MHvə@ ' ;WTx1{tHsw)vvOhGme-+[U,zQ,@Ε7pи0skw )aM) ;vD\oԿLꄖ=)̾7e6V/l4-wwEhΆ}ÂbꭷLJO_Z&$ꭃ>fF J^6!J@ҝnR]x~畢`bs],;=+յd"GNڢT]1.i31P[]8sB}#IDATN^GL'//⡖ES&j_ =rUe__/Tw[\OdiMM4xGF۷~%]}1Oɏ^Q!@= ԭh3+hjfaK6v[0~ߢ`6 [Үiݙ(i_t3Ԏ[}\pѧCK7۽ژx4MۖEw^pLތ҇7coArK}Dۖ=͝1`-=Z; |qЫwVZ /uQLJ[0ht&rٜkW{M `}ںukTͪUI[2)m/Fܸf]8`J_>P7mzq 6>c}\/zq/rT6)kR``?~|O  OɗOrŅ_~%Ɇ vV}AڒrxK{~:Oe֛n^xO>@ԓ şIxܓƝw0_Ԕɓ8]g7^[V^?ymw4Զesů;_\~GȖ-=be\8a| 'QO Q?祿oVa;6@LfrYcssG^~%?~Ws -?s3>HKjhXr?|O>|xx&zOY]5[ߪ oGv?dmaxo{\?C}$ڶlIDg:x'}_y%*{gI4ڶ nǍ[oE#QFuZ9 6v}̀E0hIDFڸqcW&*_xwZRk=ÏEӧk!@?i?e 7 C~mgԠM[3Er?Z&-+.k)?N9C&-ۺu9?oē#݊{N<1AՓogjZN2ߖ ޱ&._^Rr}KE-^6xڶ7'L}u`%?.'mYzu\Ї>Mǧ=lYmX{ꌩa_3? eӦMqaN I[^z?@~вYS6W2)m鋺Y#|O O>Ͼw'L إteʐ0QvS_ ~%ҖGx-?^H[D6>Bz\Oc'L^qa-qa;[GOrYg755.ҖEw:]wcn~͹*k L5maW1mRVTaҴo.ȏ:z媖5EcmȤesů*1u?q;O߬ 5xmSTz,PЊM& 1L(ݯy$Y׭;#?>%?raa6GG;^[3Cg۴7DO.Ot-_Z,ˮ?vg4ࡺvӲ*[&r]q5fTStv۩$kR|QwY*TXuA%5,}k].m}%%rc}ރsϛ2uˣW. Qr[|K~t?찰LiE'!E(%݋疂Ϫ|y~jŗNʿ`UIz#? 7nGZIEtG-ݼ{ʊsx,f=u-EX8f%GT^Q2*Jvc(jIoڜk`/iKK_Vo>0`,l n'n;2ᆹ9Ulg;/i6ldʕ+mno2q␰~e;V4V nR}B- j0eOV|g͌^!9v#I vs4@.Y\Fv?7ǹac(ˣ9fcz7[:]}Uׯ*j) ڶ-/愍|N5uI&|uꐰoa}y>.Jj[$.JX><%?z6jm[UWvGT{Ƥܻ"L4wҤE9EC66Ν_tK]S޴ʖnS KR-JNK*L + ֦n3{CIrJ*Że.=foX1KZv8nTP9)+~CO&ܰ}EKLʼ>wO m:= J[0eRb ަ3J.QrُDQÏE8s`#oV\8 ++@ѥ4i^~p^:cԫ* ] ~%Җ߬Z?!a.i_15zm)L卿e lC^ھ}믿 ?2m[cQO> L?ReG&m9}Qaǎ?h{نY?8a|~aO>cVZzƅ#8}'7}QNmlݶ-45_xacÀt!#B&\{?Mu@ۨgu; /8__M:yQG֓(6dȐO~ 8SN9͊<+{R8Dmiu챹k۶mgfE׵,t~2o0hdpH$i @-I$I$i @-I$I$i @-I$I$i @-I$))m[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[Wj IDAT$mH I$I[$mH I$I[$mH].i\T4,E^yMuY켢.Vܼ*Ӳrv⊚mmԕdSVviYՍ.(v%ewanu;gqMָ /^wջVkwnR!z)n_WT崞,Vn[n93YO ЯzضeU^fr˺%dI͂KՋb/v֖Mk_q+Fs[m̼4TtŚ3;S>ci}Uav7k9hSؾ ]7Wy+6m5cӒ+-mX&5%G{{ǵ{۳&|rںҽw^uۖmM.:c}ukSSsj4cemh*89j;㞵M[_]{όY_\ȯhlZ:#]z#MMm_ԴjΨ9wl"k-:sƂ~G{Gyuj3tz<9j{Mpysi9=7Q3<֦S,3Sz9sn[l3-g1?zeM]:j-3ɍˬ;OMNNNw[o94VwQ{Ԍ{jKZtS;sOmOrrVv"aV+¾FP@iۖ=Z]7l ۿz}-Z5uaۢÞM-3 ƇX[9 o ar7/vJzh+W:S $7++;l]3"3^F5l̐XlX2ww+5K#?Cl,9#M[vvb\S{I\ߚMmvDDa8\Qa d-ðFmYԍܖUrӁšGljɼLa_l^TteQ,xy\Ԙ/<{9a/[]6ۥq6_J݉/.W]YܰCXڒS83[__\Q߳uīOG c,irnM>+ {߀ITWջ%ʚ/ %QwN.) g$(I$I$i @-I$I$i @-I$I$i @-I$I$i @-I2m[7>dd$h$i @-I$I$i @-I$I$i @-I$I$i @-I$I$i @2>m֭tP\#u?RUӧxJ~*{2WaGU?0ر`m[w|2\a1կ~d՚ꌩ>8!`%.[@>[';}'W^}{O<bZ>dd$d^O_5j9\^EQ @6`P˰e~zu\.xOd:hذ/`ʤg=qa܉' qχkC/e9tt ʾ~UYV旇 _]p>RhT~rmG`0ʤeJ~1~dc>:.Ӗo/ްaCOx+?wtP{?1N-OZw%%rĎvhBCO5_?vI'eSgG/*c uM%9QaGeNgvN'V\Y)*R njۼޖ9sjJiyak Iߍ7uKAdLt Wޒ~hƹW.K4{C4y[[5=əځyƫ;Jvrzr+^*}St~,^Bn']R/Vf|m/\%GT_2i>Н՗~( ?K[krL˥ʅv~1;k~##떢P{ƴ Ӗ#wu4z~|ZWjkk͛{ dOC81nMݫ¨8}Yxsc$\6.b>!s^Sv.U͓ߨnL=]P VJGU\VcH/nzog8Avԯ']zt#]܀w8!ǣ~ϊ>|K #9ѵiW^;&6ma̬i-pZK-_/nKRPkkm^ve;smMf%+}#YԭxtZ`Ś묺Jtq1w]]Whl9Nh;iN>bH==흯ꄯNɢU{RgԶŐԍGwMY{FsTct H݇@B^ee0dT9soͽG>6.ڽ71ԯɪ+m g0uv?hҜKwvlN2J8kΞ:}$ MΨ=]R% M¦I Hhnqm--^l\RMRKw?IDATVI*sq[~n%j%T[3 +hSmj!:҂spTyW!FYR-󻹘׹]QOyf:fzMC)ijn~>q7TQnT%,NrlQ&~U``Ӗ&07-70?Փ(CK՟]ݎ904\M11uߖܽ̾h7ͿGwbGt{ZTM+/aAhۡiY}IgKjGhaa0㟛{}{NO>jԦDh7N* p8Jm}fkKNv_UQc,z׆{KnT92v [F<"usR7$6nLzݔ41N7*WMҟq\4L$=mˏm%=%[JƈI2be<edU?֡:S:k3,:fGȞ@l7`ǮUuf'҃qz5G#<݉UpZM֮0*gECz2bN}-7o; [ڍEvh ^sovL邿%IxϹ6>ƌ>-G7 ]l9-ѝM]=%ծ|~KKZ۰}Bj`ofenӫ}kkW۷=>)kR\x;?w}S=:pY6?>ch9me뒽pt항MέR{K5*(zcjwuGvno]O m?vk;;}f^ۖ/8Wn3=ֺU: mܭ~'wnDv/Zq_|UBۖ> LJ[z{2nWv Ϯ+{-mZ Mv*m`q[vڍBCe޾K4}cz!=(OsZ2?է&~dϴ@%`Ӷ.~)5oowM`=Ii˝w *E`@pz(`wɧ-Ww;ս_ysTwj3g:'592޹sK/|1"^O $(|m‡]qzi s=~tOTxG3b A4J{>*.ن@Zqc\3ftA*!0B߱(*4l%_5t@x뭷*o^[O_4f1a 9Im[:*'u۶_6Q[G-Gq@Z AD>r_Ņ߭]#u v;_~啸" V89G~,}ltZ^?<,QYeUVy/T2dȇOr2/mM0Ü(| 6mi*bMpꂵ U3 KWX^S9k.+%Սk<87ZR6ͻV, Y}Ytb}7[_rtLk]ڲq Kv[]\:cTf,HM6V^N=ιvywÙuWu֓g}EEms^DvOS/EqsfIYyi_T%nI7iK}MuSP88  SmXkKgwV;ҡ’q'-Z{;<9)-WƎٻ6|98gXmdu4^hum:l E]U/(n۲$4@ҽZ{_^醊KK)Lܛ%L;5ziiq +.#$gObX5eǁȦvfD +K^Dt$䗖ï,(+mE4h5:3BA̡ڋ-@?H,miIY0mޜ;*C[yqoۿ}{:=W^VfrJto;fϛY^F˜1MnҖ=h2ꚺUwD7gfsoJrC7Z ;kP?)I7?ȣMڒ_T{_Uk4Vde̬Ҙn-EqgZXN^KoEY=<:juHVw= ېWRYXU<6ݾ6:T\:2]W\|_0n~yYJ93RT+{SRyS*K:E:>nw-i6UTDu;nF,м⊚>E6הJ?h%ua'άZݘquܓXzmeyWNayUJyaZIvUΖnjeh"d555u[a[}eQem|Wy|P㢢/UF-UFMgPW3.ޮո{Tݵ宪Hcy~HI4,qڥ f9nT*aS/Xvkc%S\sjK塣N=g=k6T @&czaH 9$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I]-y}K|tA$I[$mHttIDAT I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$??|D?d7MZ %k2Vvb2 I[?:ͭEүY?OI !lqb43p?^&{ělBsZsh[ [|fᄱl$mq킊 7~j$[,˜/| ?ݟ쯝xk{޸cvEw_4'[x R|ބS>O:Ek9CU=ϼScNg6$12H[6T(ۡsۄ2 I?ĉ可j0K'/*5?ˣв]wIwY:_wSQ4b墻nzgOsrܬcV0&np-{7^/OiӻM(Ґ'2DjSO)llY'ڎaiw4l_-KϺ5.洫J-<on\}a?Y~ycwGEm_) 󿔮qׅ-&\11Ml}MaJ8! Hڶ@7-?>|_jʕ 74:ܱcL43?Rpf3Զeѝw 6t'|;C=}~_oNNNN\mn$߶ׯ*mz;vg_ߴqS4;we%`; v<󇲫㧎_~Z:5wS+6g r7^~gF+-#A'q v9G oҚ0 eqa{pIYW?z?̛4)Sw_ݲ?`5ӖM6ŅSʹcø䆞;:7JQz^|1Z?>z>,=cԇ-tQnnѣC 4n¸=9:ou:RIO wW:nU? qԶ%AXGzP{3tmˀ͝{Tx݊+G}w'9&ʘ91myͻlYw螨'0aywąO_taխ {A>J|w\xjS:GʺUBΨQ2'Ѣ;Ǘ-E=\l~J[օ_loti՚| Im[6>\*;xGTxjS'{~67cxߦzx 0 D#F5sFThjj_RcmeJO^j|gzx-.Fs>D-/o;osY'1)'kĻBBk~&zOο)83Ӗ*1^ z@Ͽ.Z=_VV51Z襗_y%.~aS邿% 0w,=|Tlgst_ׯ_._͏GB=ިp{/'@r!D@2iܖcyO\xa}蓳>kGsх |]{oQK5:92iܖ鷺G zx-,^Uu[^|Oz:.;dLJ[;:)o}6.#92Dg|B#uIW^yk[ G䄁(Ѝ kOl1yO޸`"'gT@_~zw]ft/ӖGOn܋>U:g%]mjT6lX_LIO`ܸOk͝dܶCsO=ڼy7.dB}[y#9wfv. Ge0J.tCK $I[$mH I$I[$mH I$I[$mH I$I[$mH I$e555m @-I$I$i @-I$I$i @-I$I$i @-I$I$i @-I$I$i @-I$I$i @-I: dm53srfl4zVy aPhX襚K&K[jݾ)MW'Җ--MMM.ݱg؏.jjZHTm[ 5GyMuY켢.Vܼ*Ӳrv⊚[DK v+YQ]YZU*.qʆ3尜ߘH)5a[c6~fuöu ogstlO:e[CM'jucBzF{ FX\T_SQ<>'3ϴK<ߓ²_=&NaVG{ÇzemϴI)Y;ugV`KA۶ LnY,Yvui^z=lj;k˦58wEIDATιffas4_Wtz<=}iSu%}ޙh8ju΂^k]!H)-<޳W>4NTs-x,}8^yYXMJ3:ko;d@o/s5٩=j̗ҼgXpfjgºo>Uo>ªh.8yzd^^?;/odK_mPY88Oo <8m3-՗ߴյK33ӫoRH}5_+ us{L''i= rsg.{#/#=%775}XNA{mJf=.(/켢Koq,..k{=2p|nvC}AM‚7ܙe|59qŠ]I{W=.<3:/+??]XW|ެn^Yܼg&04ͬ83}5u a//+v9sGCm)(k>k(j }ч ,ֶ.:(ũ:&e抙|Wiv!nff.H۶oRZN ~OCmya뾷=-E>Ak[OtڳAi˸yMo֭nhѸrI0Ҫ} ++I|ְͭx :(kXNN^AqiŢ R Rcl>UVom'Wt+]$I^93kíoVaMUŻȪ`{}ҋ-[q(T-:~t+.y]3ˮgmp\5/9 gUVulՏߤ]䊊W]^iMj]y֜^$ZĞ6>J>Y^|_KurfVi:}Ӧu.;!c)ۙX svV^QАJ_:/0%5HNM.*,k__SVVe8mVWWzڻV\׾܂Ɩ0t>iҼ[̓_;cyii}um]'#c+o|/TW-JöU9Ən'|Q*W7j*ˊ rSQ~eC_`G7G->Lڊ >3U>lî7ץN fVn4VȂ]٧oRWOYvD.hFN_Tޗ0he555uqQQK3j=.ϛ.hCZrm/6q_~zgګqO2y6Ը`;^)ٵJtzٌҺGyՕL]h.MS+m|ၛf9`CGu93ܴt [y;ȨVi-{thXi{3u[] ֪mh<-xޥͻ3y3; dJ^]uۗ >ɸczHF/sءmy.lغxmw9*:ӿ3kzn۶y{j5Cwp:}gַF-)9yuJ]3RRG}&XNqu](||n$ӗm_h6$i @2Ocuqq-.>7+$@i$m[zas̜_QhoǜEMhҖ^}SV4qԤ-?sƨ;C'qԲ 1J.@-I$I$i @-I$I$i @-I$I$i @-I$I.Ӗ%dm[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[$mH I$I[t@G|4!=r7KEwo~[ ie^{ O;10hD$mYtxS|59! 7NvRsf\33U#dxx[72wNkms}a ό=<0608D$mǵ p㧖k߈^O̿(='?Ƅ0K+_?ݟ쯝xk{޸cvEw_4'[x nqS[vyNNm[>u\|{6oPuiO3{Ng6v% iˆu| O?s6J'N,|Us1_*?yS0ɕu^ݾ>Zֻ/ gݶKcz*mnp]O7W='99noXzfN\taˣe)mNm'n O-?m>fh;Ɔuj ~}_IDAT,=TӮ{nf`؏ QrۺVYme,?쏊ڌmQ)] [n4/4=mI~cCGN5~вgKcĆA ux^ zs^-Ne /k>ua\W\x'lSq[??fͦoϚwڄ-8NO-yf/]lI<08D'YMMM.[B3­ɺ?1oex?ui>|eÍ~.%w|d|ڲ~e*χS0<}JNr5M(,R~v5s MU{oo0}q'8dȠhpD 'm s/Jsɼy&]4oE}oznso<~%ʺMyS翬 d>()SӖ_>U cǎx9gk\IT;ꨜQGuT@E^}SO?vmcnjE2Ktғط2/mv_rOD#F| =0(xͥ5=ɓ?³2*Kt;u1ě;)++; Ǿ] ;q'[?hrСN?\X&mYt]Æ 3zx;{?e__aG曾:iׇ%:@h[ɷmz{^|qǎOp+_S?9-=Iֿӧދvm[n.ў(۶i@Kߪ KXznu򳥟}?ǽa%m[w5;[_^RRˍm=+VzcR֤ݣD.ڶ~1nwZcGU~g'~o9sٯoڸ);Kt% 0gCUWS/~bq?vk8çƓW~m% 0 o~3. 1w|W[F:"zǃO~vdy+unG#>;ܲe=}% 0 eҚxl GFs{p 0uLl@ϽK ?Λ쯗(>Տ3N}hٲN=W=4o޼K&cp¸v {tēz,:䆆sC L:SttiTLͺ$̭llt*KVlN47URtˮDfY-Xp&iZw Y--.k0MKjw||Ye>eWQ[,Qѓ ]ə=K:+uTʬIfT,`´Is+/٘ZݛÂgFU!?os;K ckwkӥ=QOaYC~`\Yg~L\EVz;#[V:c/h}7V|).4޼0\Ӧ΁y[SmÁd%l^C(>qOK5O]j]\5* ;Ð_M73Yve=h[s?faceChR˦qXD ѵ9QIcZoǮ>J T6k%]3Lԓhѝ̓w6y{iK8}ܻk>qͽ̿IBz٢!թRJzIjHː|cڤfC夬vpSQ%mFɽaiqNnɻ6TJjҝ}&^k;-Zue^\rUHp6U]toHԕL q&]tr `\ w cC(@fjPϿ%I;ƿ~".WJ{kvcz뭬voN횏?vyT87ddwyO#F̚9#*D/<џ8;,;/5tuqf>6u_m_߻8]>G-.Q %^sءF>k~?l>ʋ},~G[uIS\5H.]_״>"r~a on\ͯ~sI? oɭK>}ҧW/[Oz74[8fҤ^zLaM- q 24Jns~'*oyy??y㝓Ϛ< 'O9]#-^5ѫguOxu_H7ȼP?DӖ*1^ zo,]7Ǔ{w+kcK/J\8:+{K }.&}-ʾ[ِ4qU_~ݺW}7? ͷvh CD{2iܖcyO\xa}蓳>kGsх |]{o?1 rI=47'v `fEM}kòw3l>@ ˎ; Zͻ~}zKKrЃϴfIT.USXY1=W9֋'@tIW-Ѳkxyyo}gZPx~W5l a[cMIi͍? 20D9vP!j榭kkXmgP99Gx[yiYr^o}g:|a˒YuQ~w}9$V{TuLL>1 jI[w=Xeu&Tׇ=8"99=?uxy{ۭ$=LJ6ԡ3,ؓ>rYPP~U]>;O ZoҖ̂{WWR-™LOEo_\\ǧt3ȂU޶Gm?m *JJkj詅e-]'A-)$ffֹ1rϼڙês.Xyju):75VM þPw?cm(׃Դ͸֗憽Yuc,*..Y"8kvꂵK3owiC&teQ*\.1*w?3)վ z^~ [>{#Ú+J~H[ҷM Y Jrw?W-*ʉN̰ܙ* 2̐^ӻqm[\ݿ/ՍRV™8j29iP9oI0 QNIť#S>꠬dK8uALGڲw+Yp3S߶Dm+ # 2eohXTax\O'=g¨3 ¾[P<.3yA7drgriQnHDI$I$i @-I$I$i @-I$I$i @-I$I$i @-I$I$i @-I2m[h$i @-I$I$i @-I$I$i @-I$I$i @-I$I$i @2>mGϟs-<)//N-a`{lKXg ;/:?$ʧKGTW_U{DҞ@2oܖ15j?u|GuD'ڥuοo}[۷n澝.@8 dwKkj-|hZ:}1B=%`?aiwn 'MP} jZ&-}srʔ>=ܧTkc>jrax+֏]C8S?|j\~=|Dv1uC˖n}`B^bit⩱ 6,?Vدy7 h '++ uēcQaB\7iܤd*٢cJN>)=]zQη99퓧=__w3׾6z7<@:mI6u}E#< G.zС#g+]ȲG~HTn^~f%O[&O*z|W~wɧQ=Bqۭ٢YGJ6ZTHu-e5{o ?k~o䓮tPv?I%{͙{gn<}l}K_=+C=i +~tg8I[$m N8I[$m N8I[$m N8I[$m N'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qz 99*񴥦wL˥9%sj;,9JNV&ViP[ھPt#-E1EMd=k_ՙwkEDŽEKtJWN8+{nKY ;n-g tҷe벊gַ`\r-*Cbo]uinzi @-qoޖ:82I]׷%gB w1 N8uݼ-JᄳC>kBQJI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI6Ӗ^v?ѷ N8I[$m N8I[$m N8I[$m N8I[$m N8}2w/Zg}W^v~}|A̘1Ńd׷⽷׆'8revi+.,333tcğ\5uZp餲TvfuAr-C Ȣŋ/ G:zvڲY»oե#֭[wOxɧOe;3 _n~nءޮ{{VZj]Լ_>)Q>5%QMTeD!mxټ-Q6ճnZ FLs()z͜7moÆ}:=]Vnߴlfı>{E 6|s SJ|ьBvС]1d/+WӥSڲW^y%*d͜:wj>1|=tu™'$?t锶{'ߠ^y3K^3:p+B*Lh6<{g$ ˖U^:=Z:-UUUaG֡ .MҥsFS- Խeh/^4U:(sdeУSڲf͚daȑCB>6c5,9ԻtT>}54Y^h]xѣF-Z8lա# d՟Cm hl鳖L)n#L 6 ߽4zN2uZ@fw2N/?.̽v>/qޡ t/5=pg ^wznbQy4ly'M_n[tJqHޡ ӖwߪraVn݁~ +^qCR6>B"vk%4i2}̵O٘DKb+g|kgiiIeN*kk-MH}'YXQ"t OD|Ych锶~xAiC[]>W]xw־ƻ) 6,=Z:-'d[9 Cj€<-7O9YGdg=\:-{N)uM7 O?)c)uUItoiڒў[Lۖ~d.IN;͘ϟzkK'Uy䜥KNP:oiFN_:J˫O7) }蘒O @ON}["Gw,Ϲni<υg}3ӬҩoKҴSO=,*gq_8`tУ94P/>[G=Gr~33@/2yRYv3ÿK>wn=jTѢBk/f{{mޮ \x#tW%'t?8B7kO-{o;t㡮/} rX-N[vW͒ НI[$m N8I[$m N8I[$m N8I[$m N8ebo @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-q 99*BW,^Y~yM*7,WYvNI]SS>'&ۤ_ڲp5!=2y5g>zlfEMb~iKXg䅞v?} @ǙG)S_?'@ϗ[Z]_l2kGeYOKֶa]լjNY9+I/-X?hBfiUD1sL̚m<4˾9E3Vљf}mU̲l>wZ:jg6/%1/M#n 7ogYi '.Ͷܴ[LC6Z;ciqn:NSii )7{zk*'lvr̪mhocY Z?MSy+dtdM=5{"5Gٰmx4 |ϚjgŠ Vuђ1[߰%j4zVqlxFbL‰٪Ц/VN1fvFxrfܼ3Ú5)jܠx/?q j WGo}ւ(x-<66CDis^q17T>iyhojfQV#ISﴮȫkuyh [9uvz+߭m{wT\-wmhoKb֎sd|oҙuhM}/ku U׽g lX恳 oz#s&$\uΗrVk4to1H'lfӨ%MF-d\0"ģg/eًwԊ '{RCpcԆk^9yFhwd4;T7kږQfF\8fpc&|ߟH\0܂8FDWQh[PVESle7-YƓrweQKcw1[mzcDvn<|~%g2Vo<lgݲl/77{YroOjS4ݪ/?ϙx,Ud_2qe-$T[ܺ~qAnVoNY Ί:MrSU6gkeEiQNv~qy3LX]66of6PQs _6남uX|崦)(-/M\3w'&dϩl<}aaIYi Nݸ xs &ίN[ϱ4{:]IfaɑSTpm${4Y*hH/GnX= q܆;o5&l.sK&6pw[%ihZ^UӸv{oj(x?+oqm7+yv)7''h|iEjbR<ʙ 7$_:璁&~WWlZYw,NؾaK(.tUVNjjBgt ta"sOPΨl{|O/6"im͉VbIDAT'ύ0Y89f56fK$;<=])(P6s꜉wAKz =360k~"0|;U _އ ?llVE3af#֬Y?c6\H7+ n$7,,Kι7WveɶLMuUibu5UmlK`s6m+Iس% l| pfiaΞ_9Z> 7WQ&XBʟ&bJZ޹gO=6YΘ=&NwZ8mNs̓_2IW1l|QniW8~mueÇgMUUSעdpٿE'&gdE͒?a~cKuΘz)=-'ww՜ioA4. 3,.neum]*gv53 c?,+>B{/yvZaHE]ń*]_pܭΛ9S~s+ovQbBn}[JrGe9G^cl!n.Q5Ͷ:ͷYJSﴮbb`6ѺiQS[I(Gx~aV4ȟs&%[VNoX8VLЖxg?qap1y-zYܰ`u-_4*_r˲7kgq܉o>zø3f6ϯkq&pZ̈vۿj1ܲS6*Usf=5mpXw_bna :Z^vAt~AeY9dyS Zfmń9_G:Ӭ5랿a6N~^λKN~ak%? ^\W"jIz'^h'v۸s6ݷ[c/n9l{)@z9i @❷iƉc_x`FRгw Vm-)ա./웑 ukU׷f[nܤS:MڒYׄlxlfEMj*f>!fY!w @I[RP8쐚sCO[6Z3W=̐ϽUt-u␃CҖU/̓"7,II|:okXrCN7}&evvê>yU?=fUGf{h}aҊ'*|Ǧ*y&z~%ʳooXAO󆵉31ڤLNظΛ8%Z5[_ظj?@CҖ-o+׼Unxv+co~n~B=c})}جLCͷ/^?fuשNݭ{x7$ {s!O\ya ;?߮juJnޚ3ΞtijɅw:zՅ\ mkMc%脽Ա7\;=N0铇5BM 6igY![gnoVZu11CiqFG1ՅMv=#myiWl|ϖ$ A -.Q_³L{iM; K9xsO~+Yw෣eEhyĐcoy⼁+'/OƪǞ~%%0ٷGh{a# Fi87{!~(46E(T\ _No%K'X!Ӧ>36k ]"']ĐW7 Ilxt!-tWYxFOd%k6NɐEB?nBF}}}+{{mH}p9z[[W>qvϾ |7&د?8U7~˶kukzizӋq+aׯGx<+$Uxޕm.,:'J$*[f?~w=^-? z~>W~>7]Gp?}xW^E')-ۇzy'YfUՁ<Çsg ;n{d']:,k^}7=_W^i{|||'ydI'}aYԷeΝwyv>򑏄Խ+:sӜI["H[^%_^!qͷ̺W]=/gԫ_ =-}߷媩ӒV/ɶvomp~~'Җ_w K>3ӯїǍ u׭[ mխ]~X߉e͚5_?_fogw| { ff/ YxQaQGZ?mSKl7Xn_ח_x%Oyђzsԓ~tʹT,E/ ~WZʨpԑ#,Li(LIwN/==YխbMwu}1{Ly 7?0*7}gw_T׿uM7i˂[\XzBgL^Rv'n!qͶ#t'vt)3ʅ/tf /|q@؁k8;+5tMͪz+tLO[֬Y, 9rHs Cs[]Wq/iF)JAЎ!#_}ͫ᜗.V׭9+ȨW/#4}3rp;ssBD={ª o=??t`xh~غ]2vЅwmN=jԢŭ9=`Y+ );<:۬dփ!͗74] N߻G-Դ~V l.o:1cfCׂMqMv.ZTQ[jr&Ld=qDo'.};^%=os9{/6QmbqMmfߣ_E7n;՗Rx䐖]yfc;oIWӫֶ?!uљۧOpyO[,90{+,r#D-O5vԉvt]%'a鄎zGTهe`anhO|"6>&=\qνKo,9pPhEEa75ohv5qDpиÖ\dIUr^*mhdk%76آ.OH75dZ?^~S$_N.|ahEa?#{bSO̎"ypn:܅_ b-Gg%%S \ZѢ8sM_;3TWW׹%tmJDž~y].ҭ_xVWiyb@y}Aۯӗ[D34w v.}cړѥ}K]E->dbƆgnEeڌ9/lc ?ް4mM'^kgf qgT6l0䚜 WsXؼI/,lMgMι|Ms.o<+V??Ɏӡ37 8qUeMTa#ԏ ͺ0my-6 jumΜp__G;"tR8CdSκm}WD:+Ž0MjyT Ms:kK'.V|#Nؚꚰm:l+W-O=!76iQ|E&z,>ŠVմ{,_xekkMl$[ޟި7k ͻJf QBtcGp&7ԋ/tvysJň}{kxݻوl긡V_惼(,5g7֮^:tNŽn9{n*׿mX!Yf'/ЭH9w6/;KvpOq϶-6[Xs鹡ӖOӡ9&FArJO̹|f rMS6Myq9\>|U᜗&ϘbsAI!XtND3Snl: 8r$v9-&|}zqIy /,{J%7hv|G~+yiS Ͻ|_ŐD7zyQٛ:lϏ9*D|2yFJ=B{־6_ܔ?DBѪ%we)ٱNͽ>̳Q\.xҚ:qcÆ} @*z~z_;IDAT9oiT^+μqG~ؑ!&}?>=*|ns/,Em6KzާOFFP_Zsn~͆bQ26lQIУ9rA3/<=xw _Nuʘ?0YةO<*eNݺ=㭷ފ ovJDMm~iɧ~ZFFe{!EF]m0|u`h>[y睐XpJJ^|&z[Gz>3R7q~ѣF%IFTGi˥[S.ݖ_dViKH=Ç te˗S)W}?Ri^{ 5QNRw^5冟,l/($߿3=zѹ@N‹5BwܱO>]wSBWiFxE-HcXtoNN;?+e'4hP2p٥Y|v.jy7k6vLWF[3)ͼ替evH|qz̾d3> {竗ҷO9yko~_VDps_̮ C:͒מ{{zwb]ZvX|У}/oҩoK?>Zc 7߬?ǾXrR~m#Ӗx_WO#V'Z_|$86lxw->i$і[Pfͫ}yDDNNvHCї᯽ʿu#w}zޛyا>yGnx핌#k^^,ӖG+pWfk=%O]u}-:ztmݺ>pHYԲY3<~}7F5m;Tӧa~*:@B:z3yy ϋU=E|?h==#~S˪@4۲מ{1#,ӟ{սYW׼v&#l-ٱwm=:hG>c]}rء?忽 +я~tvs=}>(4qO",}I'i @-qI'i @-qI'i @-qI'i @-qI@Lm N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N}[./(YD]ń z-5I+B*K0KԆmW1XkBj*f>z|~M]׶c6L5{MkfZbޡIʺ庶|mS;nxڒ_,T(+ i¼g~UvyBA~nH/]ێi0z=s Ktimv?_Ԏ*)$LM̟ˁc~`MrAYwm7+';3++.m4nxKFd'k)?"4n>_֎>)-9tv]Q@puճJ:qx nvLiгU־QAX>; rddQ:c{mj>T iK U7x܍oVl:ffaߌ\#=oL4nzVaiEn9qϚF/ݤ{ƶ~Ҹ;`;vr\*$m2WmNNn3;7`[y6L=`¬u/"*-Gl+۱Wvq{d%ژa}ubj/ɀzVInksKJGdQZ997mK4nonI#b'̪W:V?_[Z;nzTҖ¢ᘢ-VVA1v܉;b}vPPtL_TO4nNzߜҊghZ|هY0n6~Ҹ|mE[X>6gKZ }2*ft5^/V{c1sωRl}M\g?3fLtx{{'Ŀ\zv|/ خO[:-YtRYk;߿W 3:A~9떡CzdEGѣF=zTJk;B@ڲY»oե#֭[wOxɧOe;3 _n~nޮ{{VZj]Լ_>)Q 6%MTe!mHy[lg*v紽;&QqO7soX!Zsq8}BZ;TT$Ӣz[Բ~|^7ls Ni|_?*Yi15d㗤+B,RM3e˪V^$Җd# ljС2wLZ,;H:-k֬I95t?C dg [ϫt}zdy͚Wtw#kGhU84/J+0m,Mk;=zS~3cI4¨onˎE~Rwo ~ǣw/(SL=Y]05=pqO\X1y^&O<Kv (4|l2s [:gd'_=y'NC&ofvlY^M:OYZ?%`c҉^*-2Md.z -23J`G´ݷ\<յ[wࠃ_?ŠW2VjͽIDAT&8|z%%N^zz2sI}dPȣ}[2O[xmYu3C*j@4yR٥Z +>iKUiKR2sI۲1sIoKR2sI'\ZҢf^9gؼ-˗-Orr=? YҖT9~ o=FΉvqaՅ=%Y6EnhH%Ywс坵yMÇ Ni'}!Y_}c%2m'Q2y['Q9K㫥t7O9YGdg;L:-{PZq _W7;N:-;ӌ?NzkK j2gdJ[Lm-Z>iܤd٢cJN>);N:-ѣF};N\7OBo~ݙ\iVV_PtOiSGzjYT~<̣pt股G :rhj_}e,{䷏D7gfl.eNg||#b- 5zԨ&*h)f{{mޮ \x#n%'t?8B7kz4N["ޜwF?.Yz׸/}g|eȐB'mHﴅt!mHYr3i @-qI'i @-qI'i @-qI'i @-qI@Lm N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N}[./(YvU Fҷta]-5I+ŽV1XkBj*f>z|~M]JX3s¤6D O2Ĭ[Mxڒ_,-0/Y( %v\\ڰ>-o =D #2soVNwfVVH7cNNns9 D;MH!miFvcǒTڱo4) ڽ;MH!mivs2:$gb Ios6%JD暇L5CٲI;MtD*$muX8gkB٬f~ybmh}t쒱v\Ӑ6}ێTҖ5yS|MfvoN( %#2;T=sDiI)DNNM۲v!>OٷX9ECVQAkϬ:,wbavܲrA^<1J;mt@*iK(,D΄BzJMv;+ ];MGHe$lYr{ܒ#_EqLN tҖ=Kn;3fL2x{{'Ŀ\v|/ خ >-WM,\:,յ_+熙m|qРAuСCBg=hŋQ=*!mxşGV[uu|~Yθ헛v^Z8{5/O)99tJOMIDT'mQm}mGH[ ^i6oK }Q{!~C'y3Mhu_?a@O'ncAEE<7-D-;qg^QyÆ _;锶|ë_4нtAW̺"Yʕt锶,xW^ }3ΝڧOQc:xcztJ[d蓎o~!fK&g \ڊÇg&t;#YXj)mJ;,wns՟C :tP.S˖GKe͚5#'мCCgQC5k^ @օwmN=jԢŋV:АVÏG^P=BL:-z{´eG'M_[+ͼakӘTtIߖ󖶜k%-˗5&@99D^,DiK؎>lXztJ[N> Zka{9g)#C'_~FOƟH{%M:叏>SˢϿxg F =jБCUR.{d#}$*7/?3c -'uzm=p}_>?(ڈ[}lQѣF%-*2ښk׆p5?z7BwUrIW^:(tcqy̽3zqɒm|l}K_=+C=i +~tg8I[$m N8I[$m N8I[$m N8I[$m N'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qĩOk֔g$@ʙ fP8f+k崬3b}+7/ G<*Wb|k7]X]]/|zekjjBi~/ s ?7t2sn% QKqwY_Ż: ~5%e׿茓wão.KJ H 4t#YzŊYs7D'4d!%lz TeQӷtޱ4Cn~NFRےJԁD55U!5UCn'%fG?sڒ1fšYKIDATChKKcɍ~ft/-Yi[BQɉ˯, -.(-+%'Ǵ-@Jڒ[X?ST^}ڹcPr>}a3 s@wQ__͜[P3`~Ѿg!z}Uo形xnb#0nee;E*}[:vƨ%ӱ$:TT5vq[ee%QK$;4tpSU~>RS^p`Cڒ99%a~+ٗ,I? cf,Wo-;Uoon%-!% +s߸h)_;4U:tΌZtoڒ[Pv Eye~sb F$~W̜UOuu#J4,[z7TWNm~Ť悚"DYsjcf6-wg549/Z68z'7=GwvG'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qj3myb~]'i @-qI'i @-qI'i @-qI'i @-qI'i @>m-^3Ͼ˫WŀoC:ꨱ_<%4ɨou{o O򑏄vvڲY»oե#֭[wOxɧOe;3 _n~n.jk^+Vzo׽\#.Sݤ-ݤYi㾼"`T;a}/Z\|z??222B-3 ihZƟ?E7%Nt ;.{K-|+QyݧOH>3>}ƊWD}'wi"}[gH- *HF-}3ΝFԲdrkB *&Ͽ#ꎫ>ц)r_| @oNi˽ݟ,} گZ歚^$t\O"l8QaztJ['=ڮ5k޲dGsӿ7.}֒)śm&[gBk˷2M673^L[W]x&jn;w<,?&[‘DUa2ݺ?V<␡lrC Ͽs}UO72U{1>m鹡clzYume /tN}[gdaEՊTy⸰j-D!/7w5'V͛e當7iaƄ%'';U:-^,t,mNCJ]73O  7lQs2ӟ@oQ__^:#b:1hAEũ_Κ윽snw%㇟_uozͶqW-^}]vT?>Ruٵ_lԷc^CsraZ#$.SO-k~z.]0CG E⪧tsѽF9VҷzC&O*z|W~wɧv;_ `;߷e7\s͏^㍰C{]Fm&Ӗ{7gKnQ}iܗNe]B&m&:HMf8I[$m N8I[$m N8I[$m N8I[$m N'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qJ]ń ;V0##pfMH_O[j3Wt~kBX3{Ž53~=V>+7K~yGl/O[r % Ha$QVVfwNV߰I H iKNc75Cn?RH[uDC $TI][:F?sumTҖDmi%'Ǵ-@Jڒ[X?STcBНJMLXX?!t3)-C'i @-qI'i @-qJᄳC>kBQOQZVF}}} &FI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qĩʹ彷z]vo @-qI'i @-qI'i @-qI'i @-qI'i @-qJeޯ^x3:KMMin{d% UڎXn?'J>+o~ay//Zq뵷]vrg8{.NvvfiKt򂊊ӂQ{NjqU ;n@'n9jݴH91^,|R+D~|v>"-+^<0駞iBm!,x d͜:wjQ˒co )<<΋g^ࣨO!B|TO XW ڇ࣢5޶_-JbkŊD5V|IB$$ad~3gfgwvvw~{Ιnv!r|sc3g@kՒҖ~$*kVW/VC6VmэXd 8`7NjIi˼yгZ3_#IDAT7yK9?KlGQl[]̵+@7~?:)x7>}z1m47Qli;$dU:~tȻ_|葇_9Ѽz4Hyˍ'c `܅Qso(h݋hIm[gxT?a %Pi'Kk-[dfv֪%-{ K[p?:msQZ匯#Ѱూ{1Xn׭nό?͈g~zV-)m9{dg˯vUEEVI6oǒ[JD|g~\qX~'h,>xe$  䆞5+Ӣ?.aF+4v}vݽS- _fYK_K_:jದE-@ham["ϭ_WzyGsdC̛5oyacw3ڶ@jh+ <}᳿"_/N&`|LԼe)cnOtј XMfvV ;DKM| &W6yhʒ~1ҫ`̠d1@¢GEcrX`yj S(KJK+Gy}( LlMܣfZy)ab20 +3"sӺţvqG$7\ %k ha²LV0&/}z {|{2~FcVTh'/HY99VnFWQ t|^NA4<Ec7U<>j7NΨb32s̬ZC6_ΈKQRiK>rܥK3<}JYس KJF)_X2 's^ W4LSl:VS4eX2oYyU|ɼ sLX/ΙnJo1m=~ƠIK6%1jˈ*G?_VM۷zu|iɄ.~%W=6աeϗoPjm[B\u _4f˨%Q%o7g4Ε;wtM}rl YJ?1zP;'յ KVGvqjF {|uغz۶Hm#m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[Tg+uuN1Ѷ N8I[$m N8I[$m N8I[$m N8I[$m N8I[ 5]yf֬ ^~9য়y&R;蠃r}y=8i28{_ra@6m.%? bSu֍._;f*6l7=:|mԱz:gߣ.8pЁm 򕯼k=<8ئM'M<3mRDx,5곬c ݓ233󮉅W]Ưa}3gsT5I)[\2jԣ3@t=|KAr.?؁mT~ÏlٲܻwN;RU{챙g=+*Owzi#c f?E-4It҉}vT;v5<̬Y o/_IwyQg/GNrϩlVudAc0=b ֭[7ʯ~V6lpo~{ϟ XbETtu3rrm0|֯_NrG+ A+?`|`3֓(m)_ .8CU^W_y҄g\g Qw^A+6;/z!#Gn>7,x7'7g{.nzۓ%a *;*~yWTwbwFׁϓ93rdA@ԉ$zp)'xA|?*̝;oQ h})cIDATw|RT~ordA@$uI4o޼pGo9z і~aK4Z=u}ƨXYe܎&Y‹QawƋGPX[()l5y#~!҄؂~tM2Rmˊ+B${ Wx7U}T߿2wvd,h_߶庪7j> Hӧߞ, ֐5[.*i&hʪ zz~{RQ—AH,hgf=3kVX8n:n`ş\_orI[_:w\͗*^ Z?A|yBu&Ͼ1 Cߴ¨{=:vK|175^{{6lXpaUŽg6[ {WT_A#5Ȫ_*}IJڏ /` ÔUWn?,Ez_Pdfv>D/=@m/G4_K[vzKORT+\wމ} һw`W?YdFڲbŊ)8*է[}t~[KتÔVwJkG4/`)|apWj(¯~}g H-^O<5D~N:Ar8"Uj# /`W~nMZZZf8'oΙs=M۷-!xa!<:w/?B֯_EYsGBs`5oO|W]}K/] XlٖGVX9#Nu[~e[5  gAQ/Ud]U?x~ω'@KRu\'DymY;?sKLY u~s>JFe=!} hӡcF憿>3V]v}뭷|iimzR7"*-0A{Gcrb%%ɥ³(^Oٵ᷁MfE__N~tPNO>9/O;uw> 9Bq{s{ [6Y U$~<" ѳ~z`B\urzܟum܀ Y_ 67elpVӛԩʕ+;wPm?:j'rç_?sqɺzBy99^{ڝ;6TL5 7nj^ۛ&oUr.+JJmR?5V>nC^V?***90wϸ&? ~=7?Z;~a9wɝ~;q Ps%>qe ?k{)qL]u5= ˄ yn{ao_/Κ+BSe1߿oɕ=ȻME^S6 O⋿ٯ}}ۉwޱ.1|#nė8zVٵwf?qM86kx&>>aᵕ=!]Yqze{:d6m Q JgOl]/, QwDj-ì;!BZ!y:m}2k$^lϢ$mϷ{X1uG}BGbnY$EwlI0i{ʷ6~N @4ߙ蚟Wn9=Sل̪_ى9;+Ά no9f:CN٧{A }i]Ʌזm~gc Ikj@߶OTAWm[.VIP }WQTJ]6h{gw0I.rSh`Z m/޿zg}8ɹ5l4ٜ9 f^[ӧmn`G gׯlְo?ݯ߾* g8aٵ&[?m*Ϳ<*sYٱ]FUչm?~m8PVb$!S +I6˪OrV&vkakQ jBTw- ?Mgzl5MI&[1癟Ur_z_Susp ۿVU}nnݠnRvIɪ-'V7uSh[]NoT4#+ Y+_y^_zxFqq<:.'M<3*udw~뺆P(YmTfkDfQ  Ov T7FnMfKmqF+N l7A✳}6UՃO9uΜG732:]qD8۠59kXh'gՏ:Niz^Msݶ7q&ηyd^#as-~}G5fԩS–Y30wad_ML69K' U9cj{i`΍w@KAuwD< jU+|9wy7O=N=C#[}To;R#Ͽ |E7m~Sh3%|'(e|/9s+{ޙ82_Rɏdia ɗ^ hT߈~)yLz T^㾥lGW~gvw99丫~kM^МhN%>ࣛɦ.I'[o:B~#/6c 8ߙ6u7_mذ W}j} D'!ap9~J6 ޤo#MkK~JܶoOENsEv;&h<˪ेӒ/D&'oqei_C Û?}SooIb;ky6R’Aċ^'Y)?δq+Xwc^m. l𫵣µUʼvBb͹:d*_V\0fe]r8KoU{6ǹ5=6¿;rd4>茇=䐺j UAm2_oxON,iAMZ9%~aⰭ4v}[/]GqvyP5?ϿD[fm u9W@1sϿO'wtAn&-eSiU_D_j_$jLYM'b޵-;n=sYAKQxo+nj},a S ^U*VUo&N6q`^N\~⺨ܻw0 b03UMww u8Q[[;CmfOזnmڴaY=/7qg N fG55Y?NW4`= *~\ߛL/&nڸw]'撨|DŽ۶[ZMZk rSٮ WKcCuٽno~9wtI'sQ;h f?lٲIblf(ܿ']:<~l̀wok'4d/ -X4|?*̝;oAUض*le衇+ =< >o4Oݻ >)*W/^:]Ҷqŧ˪)++?/Vm&6)w +͎D)e]V^>w|߰yH:bn޼yQ裏bL_ sYu1Ė5`-B /Fw= Vm&6ub;k_hv-)kvoO+ ZF`+VT^۳Xm5l_ÿMҜY|o6CK"_O[sw}64s> Яo̯?(*իj)ts?[~;4IzU%}:*h^zEov+WFzͤzvwU} } ruy_tҪ|yBuzDΝ;q OB۶{׻キaÆ 3?_ 5KBg6;{xZ7ƕ@uisg y-X *ӖZ'-HK|5 VUT>ڧ h:4;*|Y 'Z_7rooĪC_>YUjӟ¥\bhZ1 &mIq?aTկo(/O&~'p҉'N4=x;⼺Z2z7&*_-Z}#I[R!xa!<:w/]=|T-IKK mڴ_EL47 |~9>wP_Z16-`Gw~w}:cgڵgݼ99縁xonԥXzt>0H\֤]wHc(_zo}z_w似c9f@N}Qs?_Zsϗ(.,?Vlg]vydݺu_7gߣ3o};wܦM~qK>#3riSoAWQ$~zգI!-[7;f{|6gFx'w>ӀgI'`8C}ーP3={ he֮]{~||f֬/nvss~䑰7#cۏL#=Z}gySN hN޿ 6uE-}'*,0BԾ}[o;e]3>mZ ^>w(<=>wP_h6-*7pITu„csZzthlNwĸ-Z[ YN9c޽۵kزeJ_x{dFoMLKK=9//fmZO?oǟlq>3kV(۽qHO"hEvu߸{gdg|}%IN;t%/|y-J^2jp4Kzzĩm@|-qI'i @-qI'i @-qI'i @-qI'i @***bm @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qi:MV܂^gɅy2ӫ+pf5H%@SXkW,z摽̛p˹eS3=rܣW?qg%k ՕdO)1,yMoVTYѫ3.N\Ȝś4qY8׾g?",u;w嫓Ͻᤥwe@3lF7o}U7@-yK_ȰQ]]>?Q8WL+3=Y?רe_0H]I]0yt'e -M[Re{' ,&HUML[רdןK$IDATʊ'?13j1ƒ'▜:A3{q90r3iK$K[$Ö ?/rrsϛX #oJyEEu)Y* mAug#QK\HY-U)K݃).`9K e5'ѦIA[ӋKZ$^@jzR&o?qkcV|Jk3FHYMM[J'.*KN5N£g_Eg?(t[4\Ƨ-kNEaӰ)E ʙPzS{d<,9˚yOT4iznD@*KmzμoE}vhƼ y-7%ֶ\s(m@ϗy1i =w>Is?ZE>죹F>sGڶm#m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[Tg+ͮw :h'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI03:tlַ[Ĕsg3GVL}h2ܶ4ZgWM_zkʚ:VoAr=ųC@˖"iKTt$xo̾aU'cFỈ_)v Y0nyk'cڐ+-H\ܲkw6 \+OO05k;b=+~Ŀ.M:~תQyeӆQ:R-F֢̓r~w_5Z#lH-Z0BKz^̹80aYT-7d';[0s̕hiUV=񜞣{FjvuO¥FRKndU ѻF(SՐd7\1yˉɋgQtqSXn5GykQiU ['NLweY)gbՃ-^ꌒ[̑ ˉʧN,ɯ1J~0diC2PKH<~KQ(L CW ֿj:@jhDPqjo-Z7*{ѡ]Ns`#<㕉)C}ݓhRԳj ߘ5Wy^!IL/MF0'׻cFUGCƽhxk 3E^5Z"ǹ$ZZg|ʠy޹Ļrιx^H3G[4f;@o2']"I->mY۳ne9K=5s쀜>ydTN״1JN1znXKFTk>qw^G/}߾-Ъ/Z+fhb]9tH,IhyiK3/N;5=#H ֯QNjؿۛfLC_6h:vڵm6Zvm Ui&6lXzH81hfvnuH+@L]v{TYҶ!mѤ-Px՛'SO?=gΜ%K.Y4duڵo߾;(ZԶeiv+A-[K vNo5333H-ڶ@=orآp[ᄏnݺz&-~2?ONG_=lXx]zի33;P۶t>YUعO h\~I7)8rH?0}خf7ۯ=SoZ=Q~yCQ#WMw@W巿:jܥsԢ9= n{X7' ;s^p&x(RNA{7 **뾗NQfwG{dtW^HuBi`GGwKt׏ Ti~8D+nb}v/'QSWlvWziˌ0twN _; 6(~4RZ-s͋ jvsA}URU-+V G 8brݿ4~Ya+k;{_Ҷ;th|f֬Zgeeeug3fLH{wj^gM ҭWѧGT¿‡dɒo=UԶ%AX`v;7^l[NVOovlҬ|WʻQ+T[n}$]?̘؎i'ʷXݱֹ偰+o?yG<`yֽ%w/[4YU}KiEQ!sHi-'є.rQ^ަeU-GuT;A#vmڴٰa_x_kRg_>hx$zkR'QǎG87,TTT\}bjz_9bwoq|-G-^{͞{¨!W|GUE<|K^}uO[s;=*1?>lN|g͛5/9;32:@kI4N/n +?Xl-Sؿq{[݂g?;?+}^~ye V + <~;v\jUX5Jh׍-nvMG_4~sϠ^VQQQO?^43,[/_x=6ʫYhQC~ac4_ |PO]w% Ԓm/G7, 䤓N3iS ƙͳbsMZBՑ^{-GKzbXX`a򤠹z-~-*w?h9ZRڲ{?GvSo>}R-D{L  %>pgR}33(Pֶe3(^Dff?7x̀vۭzzZ¨%,lYteoi&$Xɛ%.J,Kn=Y:>wRʦORVPS51[Pǥ痿ծshݶ)m)陹%K  J7P}菞]f(er',ܤJňzlc\eǟ&Jψz5aJ˞/-Ο՛W%D6-']yҭ>r lST3`V>uq=ǭɓZ5VL2ʥii9l YCdL[FnHu;pܖgPfFCf^Qϣd q7uU74ъJFI6Y:nDZs)w xa%mKVEOi@Җ5e%#%G=#?ok ' ,ϿGkOQ[.^˥2O1S|VNyekdYnO^%iP^ &hl]ZEEEsʦu}+6cy\՚M*-fź߻xxe×3ϼ5v)ʦoyǝG?_V ӫ%*=Ѻd^aVqKkwD7QKdO<86y^>wGvT5}pK&]44@@ݶki @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI:ӖO?^@mvݽSA8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8uѡy3im[UR%m jA⹫hR$mYZyPQZ$7Ĕd޷o'?';39frFT綥:j[U ׹z l O,-ZI[ &A[|c ? ^;4JbNJ7?ktt΂qC;[?ӆd\oA5䖥_{մP^9b~"I!\X#&ui"ɟ=V e+M6։jI'5ҖmTt=v(.LeC|hт^Zs}eQn ji7$,8i݂c\F3-VN{3jV'}-{b~t .5ҖZtd'o}D=5B$gᒍ{^NL^<՘r^9:[MjU=qb]L+JA=hRgܚfLXNT>}Hԥwj(dK~W򃱗&kLR,ZZDv}O[}UEaJRtHP-'VӑRC $Sk~kтF(T#萠UwScqaLL2dDUk: Kb\m29qL3:2D ų_V1-9%ҥUTT:ӏW- &ݔ??~nwśB9ߢ1/ݡz떑>qM]wuhiҷޞuc&. <̙]ỳcT|[{5H+4'rSrjsʥ=_57rX[S?z!=mHh=~睙? ^8fLx}3t'&3q0J1}G{o%]sTL-5mۓO͙;7H9֭+y鲲=?۵kwofff7hV>x^y5kFu͡CfIO"GK[ /x9,w!gAJX~GfϯwRSޤ-P6cdAvЁk׮m۶aԲnM6ݰaòeooC‰A3sCJ\:eڵKߣz͒-Pi &mzƫ<'z9s,YtɒA8 [׮}4Aʴ-SNKOoߵK_9|woٲe_'[CpWۭAjѶۖE,lxuֽ{dg7!mх%uz=_a kV^9h߶Cnjɪέ/o~A#&NyN9}xCxv5׼7~͟z闌mzo/ڶ@ZŸ-ݭQK.lapsX¿g>iIWsWo0xEv R믿QxUQ^|vZ6׽=#?bҥo@K]:tP4hN;J=:K]~lO[>i%*_q{wc}i/?MreO[f(WSsj4Kַoo=Kȯw!,lذaFRZضYlg[wKyAWp ~I1@˱ӖOVo9cKsc#aWb ?_ g 2y]W{l?)޶e/[|q]2;w֒Җ)S+Ǘ͡ \䨣*/LҖ:*RZK%wމiڦMx!"ċ#ѓ]v' ֒Җ&ر熅Ͼ} gI(y#G _7H%ks=B\1䊏(hsxd5b(K_ ե~ڲמ{yQO}h`{pg8kެy͉wݙ)R]_(2~K~[V?z'}\zq &YJ+}W_^p?m&ϭ_ǎWZ>F *{}uc|_]>WF3hUTT:ӏW̽;˖s4cͼk.Zv;=ׇ!Ӄdu:q[Q%K&9~a)Cqf=}ὼX\ӢPu$^{@ђm9/V8'<)h}E_9$Z9}ToƛoF:h}-G &qa?|rEiIn?نTml̠1J.ԣm3Wxw/9a09h>>x73`v<~-8my0j ,[]~#oyֵfR9=== %]z3ݻ#{ZZZ*_~gВ-{i|̀w}깛0iA}[Cw}/wsQrB%%@-qI'i @-qI'i @-qI'i @-qI'i @***bm @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qiff%=W^%k6.^g܂ʛz^g͒{efT<-KGk˙$y[5slrnSkWtܙ3~a\#{\}cVyIA.|}W^yr[8AK8ՙUTTyS7YQm3.:21sF&g&3cX53:%.lk,Z~[MkknR^<<NFxѶ9wҹ79xm)gduiФWԩ)m[ҳ&;8Q\yV1eBKu ,(vyV0K4h4lƒh[z:[Q^ZǙ04'Q(Wnd% p^m} 'OY, UXT eS&o5SܞZ29/cI5 ڔM0. u:qҢ)0aQ+;k+UJKF$R{kk/?> [5<3=KǏ/٤ZGQ^=d*(%Ge{@/ozu eM9YnNG4&J*>{O%cik}ma>ko_s%K%ntPo_ZY|@50mYtU=μp&/{,2oTI6l#FFrH-S b q[n=Y:>L6&QO4(qQ`_4qe'GCt+(ȩ[P-YDM_}jWwrF9n L[ IV iO[P$P0ikQt\=zSDQF7L|E9zSJ/ޠ h|ۖl{d7be²z|:-<9%O^hŔ)\Z3aU=KveD\fTהDçF1D7A-\gPfFf^=>fJF&Z1~BI`ֈ1ɦ4KǍuJGݼ"^0}I}ےU0ytCScJk-œU_#gkC)+)1.9yA׾fq/\(c:EgLWjKM5U ի(۬`-֥UTT:0s@4+Oy}k4hRiɈmZ{a̛_YlJ~nVˊru|voz ;=\E޾g?Z+=ni&_(2'Lڝ7QvX{pF>s;[2iեzζ-4AH[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m Nu-~2{-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-q)H 31Cf-zJC/dsW-7ߡвHڲ`󠢲Ho)/o}+޺O8-NL9wf0sdeύl/ѡmKuV!Zysi$׳jY<;8[l)AEMnV$”0y萠j[N#A Hָ֢1:y#QG!A j9. Ǝ;:^2d'=,E=QsuĄRds~;fTu4:dˉ*g60cZ4-\%A]%rKKuƧ ZL)~>74sdEcfIDAT_C-#>}-D)Ӗo=ƼM\y3S9ȩk(WpiNFM熕K{knD|Czh۶ͽт{;3~tp̘3fSNNMf"; Aa֕c$ʏ?J»hZj'3wnr֭[Weee'>7r"{?63*kwo }ůk֬&vC͒DP<_rXԱYCc=nŏ.~_͞_9<臘I[m1ukf)--l׮]۶mèev RE6maÆeLo߾ffPt׵kG%m[MhWyoO>sYt%KXp@V];hiIm[L޾k.=r;4޲e.O<`8ᄯ[333Ԣm #-׍- W_Yع[֭{_nB?' ;J{Æ>ի׬^:3sHo/mKQU卝[_8>* FawMT}s?.t9w ;kVyo?/575rex^mzq[~[]:M-3氾|Ұ>o:ap _ʫr{l&{{GF7|K Tiϯ.*tءhjnv v{t qD7qHu)|KT+w`~_o:ufw' ^)̘Q iN~Ԡў*oUA|};t6l0Hi)̝7/*k*W=ɴcx7[K}w>j{Tiˊ+j嬜nAd _Vok8Wnx305YYYY]tygƌ4RݷZg|€tzߴ/h!/Y[sUĮ%m sh&ع ׀*間:@۶4+l)/h ֯[4I3h9cɪ-'Vwlun;by ,O|A^QᬡC&O+u/'۶}y/΢BfZR2ejÿ9uT套IrQG@JkI;_9S۴i_/_x$zkZR;v9ܰPQQqWb*on\4e_5|{×㣿h9Rj\_KɿyЇ~XxVa/]{R?mk=>Їp=8z5oּĻ.ůI|I?%ݭay+ݟMej>w=w[g+//A ğ\uea֯cǎV q@ >\E/Ү +F^{4 @***j+fe9ÿ f^y5 - v;lם[ڿCaᐃAsD@ZҸ-&^#褓N3iS ƙͳbsMZBՑ^{-GKzbXX`a򤠹z-~-*w?h9ZRڲ{?GvSo>}R-D{L  %>pgR}33(Pֶe3(^Dff?7x̀vۭzzZ¨%,lYteoꊏ>1ԲɹVGB?zs%&xtdMp'}'G&;Dk6,^MnN̿=֍<'GOͫ3FNza܀ k4io>vhGK&g'qIFL5QPzFvy3%R`} kf #J5FʈgM(qbBE5iR]hF-ozuᄼN,ɸl|N2M.Ry& NV>xw%}LQ^N:AzߢyKm̭ͬ-1xM% NYy(ټ%} 4AҖac k5$ja-qU6P,LI[cܴhВ>Ty[NK6Y:oޚ&?5ԳO&"]^<ɷ/|kBYYMN6 󨲲4 шAbW+거; > Ju'ǑmJJkf^iW"uilg-y#㆏o%7pr~v՘&kʃf/3D|6~[m1+_/tcv`{-m 2GL̿GNAhܕ5e K/땑985XXR’ 9{| #;})79m_{ߙyKʪₜ+^ȧ***7(YMɯqi5 '\z4iyɈ"#Mt|YQNP6%o1_2÷z͕M:T>-xɄ.~ӣ+6]W4|p#n ӠI%#7Nh} IDAT4N|m[ҳG-suܾzjΝ;9ѷ͘|uO^挛Y]}ν遹O4YJ?1zPʭ>ѓba,;A;UMx~fYI4iڶX_R N8I[$m N8I[?{_W]؍@S@lT$h!MPZtTi#" 4:3mҍ[GaN&N&#I[@;$M$Mړ67ssɭ'i @-qI'i @-qI'i @-qI'i @-qIӖ^qq-qI'i @-qI'i @-qI'i @-qI'i @-q)ӖU~?ē<_'xꩧM{9%C^F~+>U񋧟0*̜1㜙3u(-Di˱oIBpΝ;~Ӌw5tIqxŧzz[˶ ygw}sũqѵUo i (aD'_(\%ǿR+zU5^tO^SN>3`GrǝwOˮ,[ Q #n7樼{ˤW^|5]tƤ]xioR_MMpxe!w?t[n52)X҅s.8SOo eSf<>}a齣%mK6)pz'uú>qڄN tb ~b(IݵL%_$]شiIiKSSS=} sƺ@Xjcٴ' RҖ سGW6| ȉW_p^/zƁ?{k0Da0c]dƭWOubqńg7N=죳7m ПLJ[Ӆ:=Z^ ,(XE9ӌ;+ׅy_8{1qӻ-X:qT %YO]^M6F(+Nre-K/HJƑ;_zGq'ПL[}cξF?Цw}OvZ8H-Oj󲸻Lia]mO Zf5f {Z$N֭1yQ?ҍ/'N7ԺW0|vhYl]W,^%X~Ez+9?HV'8Jĥ4O?^5I篪u l ӍfG\?K[„>&gddֽ_FߞJQq]-kC42T@VpZ~h2s&l[>WE-eZ}w( -C=.;^CiK0+,º+{}=/J-^qU}=6%TUݝR/^3$ w~ceFJ{7ӻLϞ>o.aSގ&hCmWC]H]i`}mO5xW jӖ?бcѣ5m:oM?×6zܻlB*H5h8dqp*=JvJjq>OqE~ф0oơts60.&9PO\!x'-?{_dx7NIiR%oM_`eXtmUzߨ0V2]&m9҅7H2"I~?-&#q[Ғcli <l[Z:#d=%=nCXzQoV^3VqK h*?H[6u5Y ПLJ[LjDC2!E#sgQ?ECg/}'I F; -G/[mU,K%7nNW_5E>ss7Ңyg&ƚz^HC qGˢB9uOw6]}ġMr֡wsO˳'梁EQW,wp`m?=qJ ˿oGy?0L_aIzEV>:7>0 dRۖDrtv,hHe"=Y&5HJ?T:-ռeWma<ǾIIm["__+ˮ#K)-{ia3@Ϝ1tnyGmYkҩ| 쨐iܰG<㛢-[/=s>|NgO<}r8=d㓛<{֯-f#`0-耺HK>0}F-j0ܭdm9dO7k>+{_wa3n (iK䥗^[ > -o~~|F=i (i C0Jd( N8I[$m N8I[$m N8I[$m N8I[$mSVggg &ڶI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @-qI'i @hCcU^!<yU'Ѫom ߨ:L[uvvn]V8\vQdT bmP{j.+%mMU%yEnVW{`qE5յ%z+?FZ'}Y9tYYŵm./N\ hSVXS^u k$ze*{^䩬)*_9++d%Z:憺EsR/{kS^=nbIFҪ~O^:;;ZemiLY}/==ﶆQy2p=+'|zusMɸp@:Jκс+wq=m#Kr Qr֍4$gsz]mIaBp_v0i7om^5{kk{%=g#sO{27Qrs޶Q:sOOVl^PRܫB[mۺ ޒڹ-wOV_VTgFڶ-&w-O$@N"1kżwj=%4Ww'<餴S{k{}UӒKMhvޞ'67:+mT<LڮS^MoXdKd瘷s/}ӍG<}*kWzWxz&ot'CZ8IDATyCM[&|剜d1.zyɵVhunj-MRq9ڦRʎeU}IT6lS\QUrGrq} K[Mye[s:;҅檒Tyw6,)9Ʈ@h~g߸8/C|IU*ʸgu}߳iKN%S nGkGIInIq"m %'kg%K;[-ʳz%ק^!-UŽq9饖֮5mu5 ٟ%&΄TュqYI|ˍ1Q Py0Cuթf-{qW%[L+-Jgے?UW$*oN_˒}gޒtco;:k\^^iWqOrp(%}SsO0DkjH7l o97ko[5Qٸ=[lh37Iؐ$yťkoh &T<3%^Jkvz]m 5ʼn=&-p(Ŗ=C>Z]Qʦ7ݶɹ{mi344kvgn}Ǟջ{/LliKata-hkώ>Sl=cT4$?_tTtpMNa]woߺi jҳjIc8 u>`2X=o[M>֛ ![ڒWR[X6$Z{ݲs 6dks$J*>}OE>Q_Q5%eeeUv'*r K*7?A&j\$ur׶WwXgW\-z2@'ўI6/TTYܑn'09Hw\]=GђϤxImiG˵M݇T[tك;B{cs[Wթ5QRuU]ayuKjnH~SiIUo›nھ3]=mcew[7pIGgv|}:[x[w6Z"yevnYlޞl̚l֝7IRxZ'OMϷD+^'J>egg+l|~mW*Q8 dAڶ0|G#m N8;'/qEiKcaxv?ZSQ Ó=$?Y% N8I[$m N8I[$m N8I[$m N8I[$mӀiK/>9n|i'i @-qI'i @-qI'i @-qI'i @-qI'i @2>mYw?~O<̳n߾=Q;u≧zjѴΙS2):;;ҋ;؏|ŧ*~Ӂ1#_}K}1;;;b7>O[zÒto!z嗯/5<&O>=^Qa̜1C!m`p-Ǿ1'] :;w<OO/s%\RPXpҩ''Ŏ~m-V7< $JBEV u(- .mO̿'j)Q{KeMs?9wUͪW/ݽswW|ꔓO>4GrǝwOˮ,[ Q˘qQE?vOxsT޽{_^~E Ii+w_jjwEV͵UmI=N8tM?Odb*n AzX˓]z=õDC4:u]o]7R#tweJv;g Oj (mCzlmyy2J&-S -'VJͯ8=gzN ښn}s{물2=r2"YyeϜ4}qz:Ԕɩ9WiAӿ(Jϯv(%].$|aلв*ɞA왳92y\N\'$/٦+3I{+oÖ?v?53dLew }K^z|2${uܸ8+9PzyLCO=!uD%_!T.3ssm dRۖD"*tcѼE%L=nA1S/OEW!j{{쇏}ᅮ._udLjrG.[oT~㚛 wMTo1f,cÀqyצssgν @ɤ-3f|>.-Ȼ>? d];w-NtvD99o@Զ%m #?)*oݲ3/=,|'2J3mO6>MCQgob2Tiˢkx?v'~#0&2YIDAT opfΘ5 /kf_zqGݾO7k>0Vν/;0s%K/խ^ц]-o~~|F=i =i ˼QrF3i @-qI'i @-qI'i @-qI'i @-qI@Lm N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m NG bku"+%QZS9d!-#uuͣяGk[@=v1biK~esge`PIXniU8\zi\^ayms@Ǟ%ز`^ϔW^Oڪ¼CgU7:&]Y9rDjS}Wk}uyڦ}VW:ndWs}uYV7v5(sQ"rM}V,\OŪnlHm+}_Z[2g9 9 ?vO{w[C}yso%EU%gh z8=ٹ}wߝ`5`m[:l]V0X%Qŵ;r!X9nW?>nt'j-~[W2a[҇~~'$WYQY}$eeٹe祝~t%?~Zn:Iyew>]QK׾[nHޱƌМDmi\RJ%ʗTR{VׇS 7֖&҇I6Dv,V[`sD*'2.9zsUYW#jޡqԆ *jNϺyK[zDUU!̪( kȤ-T3JSkk8 mu5 ٟ]Rw[NIMM:BqKu:i}0]>zcuuѴk%uanmHI5i(km[SCaK}˹YxڻziI>JkȕG?}>Ʈ_ZC /5@ 4 iRX<+]pK &KꮾaC574&(;]{^W7 Җq9$ж N8I[$m N8I[$m N8I[$m N8I[$m N8e|ڲ~x'xgݾ}{4w:SO=h{)H euvvwOUXqG~>뾘Fcğ|%\[5ܭC/__Ǜk:SOvm'Cx0sƌsf֡ O[}cN:u(vy?<^<.KSOOLbNjO?m ^p~ KEZS֢kM:DeCYOR8pCƊҢ*O]UjKw:8=(GrǝwOˮ,[ZrQE?vOxsT޽{_^~E2M&-}3&]0K/~;߽#%ҖW oXyGdXÜ!:{C-IŚߗ.s9'zRݙzQs݋eMXT?CT_ԵKNבs.I6mjھ}{2G&-MMM»zwzb=F K[&\Tzbxw&\Wp7vnwلus/`AzkrK/(нa¶N>:;]~|ӦdLJ[Ӆ: 'VZ>/ĮU%^3\}=&T< C8Ćudy'Ɲ]a7qϞ.:cg>9u_uڴڔ_4!$[&i槶 %^>;,fsw,BKsOc+&$Oo 4m[5U-Qn2`ۺ5C(HjJRxc~w{% QL5Wۜjm:gjy¼Zy鵶yW^~%hӖ?бʞDnS&*|9WJ6![2y,XÐ$ń.G6>W}+gdaep|Ѣkڪ#!zp ϛ~>`ӻǵ9(5KQS%0+liHW}nmaQ˂m.5 s 5BiCؽeSW̑Ii˔)`iK?->$=*mb[Ԯj{h>[^C:l\\cl(:~ξSLr4?vM4392iܖ|;߽#*.]xyW+H6^O`Nz9߸sI/0 6nӆC_K3ն2I&mLJ$;ucѼE!v%`۪υmX2LX/'] dRrG.[tF7BaV %-M-λ6$[|NgO<}r4mϴ=䦇6=E+u[ ş,ꀷ}c|?az1)G+7uwwnq8P3gHQa[5X/#nƐҹ\}Fcdpy饗V~/zhÆ7G?qO?aԓ 2;mᰐ 2o\L'i IDAT@-qI'i @-qI'i @-qI'i @-q)3m[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m!mu(ZHnIJ6g:Zks.n#`W}y^VV^y}GuuͣяGk[Cno>1-yewuvvFP^Y}g}+=80DdܖjXg|SZmM]C/m³gT[UR=LN^aYu}sL@vWt|\^aIU¬sₖb˂{]u^yд$kMqiq^W|E+,bՖY^^9gtFȴmYyٔ{vo{&֯m+ N[]iijG \{m p&-xSՍ*Dž`'_yͷ_kKFڶUu*fζ%E.iܴ07p];\#o#L[!VvnZ6+; :V)۵tٺ ĩm]Q˄woI[?!ˊf檒T2~͛җ<څW:`ξRIaUsaG|2*;n_RӾ%.P6uƊ"[X<+cwcck?[[SYFAq>,ϺmKԆqՕՇj]uLX4>Dimy ;VU=R?LdI}òiQyZiA<]X('u:ﶆ*o h4XڒWX I67>7TɯjN.65nN**ܷCNIU^:ASkk8jI?]ﶜt{Tplk&fuCs^Ec,IzbQj S?W7]uշN-mnH- YŅaijd-fM^sk80EץȤho|7~s'qG l-Q29cwcccm=kwR]ԘG[T^rJڶ]6V|ӜCkiK~QQv%߹t둒ش{ę-[:\ܸچ۷oyeG3-Z2xũ۶pA`C-Qy%eۍe!v󲲲kq9yyI:m #''';~ҖqE%,M,)gŨGW^,}L*o>vu57UWDiIށikNzڦ\eWGkSmAa{VEE[jzvjn,N7y>GRH&c%k{q}!`$euvvZbY]νkqɹZ3κTmuY+{y]κ65WFG;A<^H[uQ J3@Oٵ3۶7@^ZeӖmiL39po>^TMSZ̞{Wk,λtṂ#W/QteY*?(^5hT#2.Qж*&;77wy޼v?%sc%;`ekl7jISImֻ5hyW-;:~x\8(?r=ul)jCcm[I'i @;'\]4.kx;^iKk}ͣ^N[K*eɝ_^Qr$m N8I[$m N8I[$m N8I[$m N8I[4`ҋ;Ҷ N8I[$m N8I[$m N8I[$m N8I[$m N8e|ںɟwv>gG4nxQeUVyX's} c9&iKwx!*ʎ_= gz_-SӖkD8϶=,9^F_^ѷaT:82/myoJ [|CnKs>?!*G_z1GFi bGL9ᔓg]pD-2)Qp?vqqJu C{E~o?p=|0ZiX-  z(V_O>۷o_'xꩧM{9%pоzÒ7, `ѵUsmհvqu^l؏|ŧ*zO]^|斖엮bvvvFӖv;wo{u{]].l+2:jEo>Qyy}N+W.O:cˮcO{j.駿;0ʌemկBVpcNK?.reN$ \pIaQԩѣl`ڽWԋ q 65m߾=I[҅w}ԩ;L_ya6n\>; S(YTZvj6tftʊޫW$<.LÊ{<+;|O;fN¢_;w s# ~=]8W O /MH6!L8-ZGq'#do.=*g.g6ޚ^L6n|8"a5ھ՝|qMT'×S;o- WMpєSw/xE޳5T5r~a'B Fpcߘs[gΘnRBiN _4!4YP6ʕ„e<1dκr6ޙriK[W]\\E,]!e7w^4q鶮=>!6tƤ~XTU#F3>> VDK+^_|uW\}ƾ;LjXzE{ KG+NZlҊjڒQTqsx /'./튆W3I<ƻ¢+Vp]z(XsxKOMaʔdybWLJmnVOmD1wyf7Ww~+Im[jkk?L()OKu|Uɾ]7Bx}~F-xcߕ=z0&_7Q tb ,]&Lض+Cf/\|<ӧӅ> g쪐e;nط̊뒝2z>GV%\I8/oN_|?!EV͵Ua8~ud=65w qFOyLJ}vb2ɾagYثgP߻_o =ݾIзutW7k_ս2%NH~pJOM!4/tJEс]3]t-Z҅0J|eu۞Y7:Ԅ/=Ϥ_Wtp$+ &3zO'^N^HMCQgo2#?)]81b eѵUupoy#*<|Ǜޔ3P.~bSD0V opо=2W^ݎ;҅LJa9cFƨ0ܭ(7)siKΛҖҖc9_k_a ){_we~›0L̜=l+0 eR7JX޺u?4C{˛يG?|w-jQ^.Y͔ҋ;(̳\R}O{1`Xn~ɨ0ᔓ?Qݹ 8Զ唓O>DW_y5G}tP4mZ^2mKW=?,&۞yvO¹aѶ K[.i bItomV?{כrrƏcIv~Zm{?S7g[f-4D57ub~~Ygn]u=JeUVyy>L%w_ojdkVVVŐ*c斟޽;m[>x?o~K/ᥗHz^wǼ|&%/qFC,GU-qI'i @-qI'i @-qI'i @-qI'i @:;;1Ѷ N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N8I[$m N81m ey㲺T4v1(0Fh9ՅloKUSƂ‰ɋ,X2?ld Cm\UZϻ{(M]5+7ܲ0f #idC~[gAy㒥q9 CUƸqT[U3˸’h꭬>jk,N,,_zAv'ǚu2 jZ{Ke\&.hI-,W^yд$kMqiqWV&ym}tHGƂmi[]Vx+65WHVWZ{#w]MzҖnUu|nwlKSe"I hyw/<䬛k[kSm C0~ڶڒdI0 kN/K o5M7͍VDY}鋊%kt^Z&̿{-l^!P3ɨeܛΥs[.gd֖vWXyQyҊϷ֖&ƅY!^UQHkkj_THK(YR߰lZTVZtpG%E9!'/'|m UZ~)=mi'35U{)[dK+WL[${1@)GgeWլnhΫhrƊpPzbפҖS?KK\\Ry}@Gw}e"4E߳} ϝVXmTwr)kۺvYڲ{MsMҖDQzhƆ6754~N.: ȸچ۷oyeG;-@0JeU޴}?|W0E-0 ڶa:*i @-q)9Q_5<㊪a1Ӗ~5>m)**~IDAT'{ZEI~8:;;11J.@-qI'i @-qI'i @-qI'i @-qIӖ^I7>c-qI'i @-qI'i @-qI'i @-qI'i @-q)Ӗ?O>g~x9*Y#iT9MeU>QYeGMe(۶de= o;.ZG w1L8eee􋧟}wK/"c[[+Xw%`I9n|ƜK[6>#,|z /ٖ-Y3g̩aaцG^~厎YoМ˛ZhןַO#/m QZ=5gu?a8$2)my_93kq㲣Ž/w #/z=S”ɹ'Ʈݻw}_O>xz03s/~N<g?׿>k,YLJ$65mO?ǿ-`eR}%.ٻ&Ʈ~+>U}YSO [ggs)>طn]m=5{o)Ӗ3"2' /.7Ƣ_~yaյٽ?eg_/L> c,")lwuy02i_Z.D-Ɯ;w'sr_ϟ~'NxG5aOwOs֓O>'NO<c,H2(dI?cƍn"Uˊ[ 0Vxϒ~iuFD~k_{b+%N{Yܨ3^'|goO?DM8,cQ{7AטM[T/~:rϥ:X= ?m K҅j[WK>T{嗯/5 |(EqϬ+?׽.~w Gy0DWtGOo~+` 5hƪ$iio;gdʁܹ~'?y󜨐ղoL׿MTh~p\=g)ӯn(E d $1jL%GYOR8_OЌCDyO~w=qWt镏/hhn3l~t!//7E'pBDjfYt޳_c*mλקeWxxo;>>y'E0ҋ߿ユ@_=x{X4eJW>1x~W^|5]tƤ]F/Tᝓߙ.e?nu+Ws?0ͽV~glQP޳0c'mY[~=.7qhLzW_P[ OA|0&%Q᷿ݥ7{h-k_ptIa48iH{5W^nx?~syVVVkSH]ׅyϔt9~dǪoZ/r88+N!o &sS«?sCW\%|1WTң|10rFk\03G? tnGss`kSoH a`M;-O2"i{冲Wv 8꭫.OۢÜ+%^޹xz^'& L:cRv?Ws]'Ok&|E+3KYMaƔ|;Sy}?8qL}-<3a5rTÍQ})zԺͧVO-Y~}܆{ _5kR}\ӖV5ݣ?w뾵kGMQҘH_>W\w fO5φ7գՍ{=޳}LŒV7J|t[uߑ.;ճ&kjMh7~ݥ 8ʵwx-ˤ-oB E}l׃k N(5􉕫6v.º(j<ں|޺oT4f2h/'H-$}8<*L9=_L @[͗v}ۚF7ϩ/7ԬoV_"Z{W?GpWV][F1~gk=ۦkENy_oSF[v7IݵjcgD!cOKv=/+R-t%dLJ[Z[["PVUJH꿹ew*Y|^XWw0(jKh^Ͼ%GWW_PwECnE%φ>)ɖ煶H~K~yv_'.+Lv]Եzc{t-ɏ{}}TӯC%jyջAE8'd>r,awv ߻߳I]) /4VOI\+qQg3p#=_Cb{ᅎ}W4wx;~Do;'3 [A~~Mυ=T75 _-.'GvOMH~IYܽ;6)]{Ѿ]=!_ޟXhhNVx%C䯟a~h9|CIݯ/O};Wlxhpnp޳C,󣤩4j]CwdTt3~V 0-^k쌒{ ' ?oyguWRTʕavű ֲ+a Ŧ;{g#}u{ug0O%ajj[Rf>s[eӅixytHbtBI~L=*Q<ǫn0옾w{Mg{⚍_ jjooPhPIDATuV&GM/?'ƶp@O(V|;ŕ_0lݙ`iW$3Jn]fݸ$ >}{Q//+{:HL{;[ޣפ?deEF][.zjta+uQ?yA뚯u}!=$gϥzzjtړ|mmݷ>5CM5D?cO-n'~ϭkξ{6̵;;g`o>|{'}VmwQr\B^ioW'Dz龄vWwڶo1ǍIiK-](_um}_|,*SdyqL߶#>bNjQ_0LCrOnÔxs|E;dܵP-4Jl^˿PʤDG[g#;~۱hޢ=xӟ>RZ }θ-Gy䲥_OoT~#_M򬬬┩m5YS0c; @f93f|>OQnyݣ}w'/n떭WUTSf0c; @fSiKd #?39.=s>|NgO<}r8$7myge|oƺӖEV)'s?7 TK>0<=auvmCA}ruck2^y^zi}ƪ$9v[[_\X:qbO7k>Vo=]O37rs|~}X\(6F~G2'I4Jw֭~gOMgO3f?,'>j2H&my_ >}'=ɴm1)ڶrIN99*ַʫ`Z=LjsϿ? uOg*:0*icR-Cѱc~gӋ (+=80Dmzjm,N %'Q\^Ӹ mu/eWs}uYa׎y8ӵӸDqemS[ 5v57UWu׎U׷YGt~yY}䕭n .y9’UYYE5+6Vxₖb˂Y{Hyv\~qeq\ayߓn-Im2r^l4--מ;ϊ-n~]MڭuIѸhgYk[Jr+:Jκ;noy˦tYU4V:\uѤzW.r͵%9a0jiiN^/?U^ݸ"\8pvm޴=ϲ am2c 3Qr ߽egr476BH'K'l^nOG-g-{`-7$WXy}]WӌDWU#u\rӹ}&/*΍~ΚlS;wnmnve>8l[]Y]ܹwmOlHsUI*j?Mۻ-k_/L}h3{;L!z;n_RӾ%. ;uƊ"CM[&/\[H5WX^۴v^2رaϺyK[Ceq޸*"fU檲ҭ7λ5]#uʆeS6/i&Y5V$r ;%kg%K;[:ֆ·}+YH ru[g~QQ"\r%KMJI%E9!'y5TE/M^US*fnMɝwkCE'wH% 婤:WLl.@څRԵ奓jtٍH޵)bT)GgeWլnhΫh5IO220J -m)))wT8@QPu}@Akcc׀.~mYrc: -8gдe]wW|.E߳} ϝVw5jHiKA"ݭJfb\Ss?s-;{ap;n:1 $megk7O1 )miih/;hnJ20+(;]{AԕjuԕÑ`%el$s۷|~+, Ƴ +b \T64wcZ6Zz>%CItt꨿~IK0,? [QyyQ=xZ$5P]q99aO/ir[zm_]yYYY=cKU66wM"ֱo@ #''';$jvR|usW41gee!-d9ҚtbWGkS}MUYq((iMOmИ,qL(o3^_\X[scr:/+.mju浕קbEWTa67T'Ûp ̀VW6:E*'FRVggg?$\۲߽'|Hm /\>H65W^Q_Q8m3G:C6WMB=em}N`TbYwaEՉ yy-Pg]snEz ň^)sV:׊oYΝwwS]so)^Ym IC%M[.79Jv޶Դr&kv|nnyW--;QKH ۮ5(I!+,- //Qal֝F-q%[{k{?pP+>)z'_84h9*i @-qiHs]E㲆'# ൝<; O`%bZvE`Y% N8I[$m N8I[$m N8I[$m N8I[$mӀiK/psk-qI'i @-qI'i @-qI'i @-qI'i @-qiL-7}^~偶N?쳊zHGUǍ?~|oy[ '~j5FIDAT1޽;;;u i e׮ݻv!c?)<3`nGH㣷m/{G56QF~70Z{_F?{׻>X2;0EQگۣz'^|׿]z0sk^5{ D^~yw`:'Di=i{(Z;N8/P3LFsTLK[j7]rsRLRb& yaQ'C^)5gfyo<<,w~-?|0#sR~z =N™{N3-GxThP@$ ~]V*4h`#4n,TL7ΜQ ;]m~ … ,ƍ6Y{xxw%{;<~s͕~DV 5Y[3g*okYE˗/8ɭԵk[/Qn?rm,(*(??z'O µp!+?YçowꨥёW|ַ `M,qʕ+{-ܥWW"\~# |С}R:iKrW'̃zxz[=سÔep0I$~FyTv×#hשOtAA ''E=Ϋx##qʣµJ{m_b ;TU#U)y5ETSNM= Q.Cң}|| %%3,ˇǗZڤқZm׮__ :mrssB=/@u骩ՠA{*_E=:]?˨nJO!)yҷ4²ܔ,\0Ƶm/m$dY@i+rVFa䲴PR{vGsTpS o[npٳSͤ\>DuDZY FhX|n'1ٟTh2erPrPj|mں&f~6l=D6Vץ HNlId+'k@񮨣WgF63£,#%kg-spoѽiҺukSOvJ4f>k1hxhuۆ ,Ml$*AAۅ8Y͘S+],XCiFRj}Dg*@aGWm'MO7DZHN:#k-'  )'cGx;%XT:(bݶc\:~<@{S8Q㾴}f|ŷRٶ<~)M{$ \:3kU/ǎoMGdUb_ۖmE{V꘹@fNY c&?wiCVO<5%B'nܢKKN -U/kQ%AkIDATg)%Nsڼbr1% BDn^#ߛٶBDpTݶEc4ɒ(-QK έ!=3-&ռԘ($A^D}xu^o~4kD K48 +mxRaT(WZ.ܔS`:0O^zvQZr'>#8'~AΦ=ͧ]{ #];X>#r㒒W}LrbJ" P{qtn`^zΓD+bm[j|@?'Q%Ny ظR6152DȁBDIEJ.,!3y$uxt}̯SS^0Fh=.:a#ôe+I6$EԆ6gG^?o%D$%O'4~|f$轅[y>xyj#<ߜ) aggC\6"d2܇(nybS\/M7τu٩:[ sԈaY6魼NQmjTٺ]̬*6.3ʅPfrDULݡz$mD:ST^!:0junEcbE%_S9r PJfWLXgHh *ϷwZsb3m1rUvdR2G_(TcΦ ǧ 3'gsY,4!K|pAɛ~ȴs3v9xMcӅh*.I>a{5uQQUثzH[D&5;'Kj㩏5FH[쐖"Wاhg\J >>}"Cp$FPi H[D&5@M-j"mPi H[D&5@M-j4mt!_@uh&5@M-j"mPi H[D&5@M-j"mPi H[D&5T?߿|rek﫷=ݶ#m4*Sa+Tᴊ,i܈:p'sr֮[./OS-&iGe,/(,,!i \_0ۭyh. Gk;.uh +W_Rnv2AZx @ ׶mR!ߑ^+jܸsD~ ,m{#=8pQzAWJQ-{S{t璉9Sڒ}ŋBSOχB = 0C*:u֍జilEkT~n֭{;zXNNp!m۶m׮g~|PC[xy줨Ez+}=޷80gJ[N=:w}":$\I}tY漹 pQ~+iҼ O[ޚ^mڪ>}F)~[*]|y_qMnzPiCO^oܸо'ֲ,t!_ԊF}=^[5ۈU(((?]v~:?B )Be{oyӦME~:tᐂ4AJ.=\Vf-gITpRr̄% 8 ӘVmZ W$Gc& {}[3Ԅϯ^Rp38 U[ɪ>%<~KF-%i}ҙyyˍWonI[\7R]zuye+1G)9wk\'mINĉRcy TjI֪7=|8G VycsH"5ʣµܨ@Nإc`lsʣµJ{Il Ҽ]AONv]PM^v֫eLC?z%ߴ,׏(zI7:mrssB= 5d_~mףssSE2SzizU^8(=W&r, W^պ8y [I5D7z޵X; 8x֭={vT֧N[%ÃJC|n'ٟh^"'of#S4_24D~:(9}nOt#dmʢȵSɻawxei]^JDFc-pMmF![QIe/$2&!#}Rr0G) a$?\g4W5μyei=z; G %*,D^x5EwL]eg痝]&^o%@5l)KLO?Jqdb_ "DʫA'+-ӓt zUf\S ;e9 kޏ8R"ML&^9,~&Ri_zDx~N~:9/~6gY/]%x~H:i(&i1X'2,^n962- i"ͧ98{EV<+Uu:poؓ m*\[wĆ镨k;vSR=?QKF5~@'!à|||~9KةLl]I5(=n\!K-tr/]QKৃ]jTқbRx+6&Gҝ~ԺW}äuI*<;V݋@]ӶuJ̟zE )~=ٟmKD~~%FiGčaIXZQ?&60OcrStW7bF~p|:.ʭrӏv9Pm[n? em[c_kgyn;N ZmN=mJ܈*C<(hHyWvzSt>?bEFhXveVJpt- Imwpʺ;UƖ>QO^ߐ2]? .HgY$dٺA];IDATbs J y}Ȗڐ^MMctF& h͎abiP,9-Y.ș^>yKcQYA2e+!M8\E4&.Za$R HNIyp;q_b+m+fNO? y>NN)]<]QH5d uI٩.gW4k%%8Sۖ1O>QA>E;`0{u̫KRh46_ds?$L㶴m<*\۰aÅ +~7]NO5S)?9N>hrU+MP\pM.5RN\d'LQ}i3>UNWctqd޹(ysر{܄~гϞz 5s϶=lb[(,o('جY3/[:3kU/ǎo6\)k4[Ž]>PH&M8_"iԨQ؈Ǥo}wYLTņe&`2N9oHBrefMXX)/6$,D9gOdg jFm[f>XjA~&7w2B+,;F9-xAi}ҒC+ݦ&VO컺YQ$yv2LYrt$_=+s9)0S^޴ůg(H3O%m[ &I:LXw@^ZxȒFByEJ5pᦜӁyճmM3Fuc yX>K퐈ĒȭEJ˜dSi~ ѡk @L$S+i=G9;1_sƎss[wst+b/b=)OM$0##;!LgnN L2$B?<9p.>`L z ]tT)usၴy"bqdg1޺Иԅ}r0}[H{ o>ߜ)#Y񻄘ҋCcc\A/Id6 S#u#5a˘(]瞖7M5o6 4":.)ՠLS5-f9pP5K[B/ԆE42 n=;U#1^g{ZҲg@TJnFi(Zoeq^^p;ޡ ' *h{CJgJҖĊZ$; JH5G9i }QrK c Izy;^y4&. ǶeI.:~huGwp?^*G>6w Ԭ7Nܓh@~W._;ZvbFecWZ~[˖8q.^v]RnR;xixhꕓRTT$kެوaÔ\N:w~f)m9zxܲi pT^}~nƙm/_+#d2=Pjɓ=zNw;UT+Q%RTV[j;Iuv/[vZÆ p6sgG[n<6FjnW{q_`@p.YӦwm|9sy[qtnIDATD.n5 ѭZo["cg&;}R(**ڑ+lI:\e$ڳ wLsZi'E-nf{ڣ{NwuMz 7ok .]R4n'oۦ>rɓRC;۶9@rD@ =vh>Æ֒PC[B>0{۶}ǥ+W]4vSn]H!fjۤ||Z?5qh4=?N _E6Udg9}FQFFEv}:ݩ9zǥov} LsI)b*;6^V 6_zcts[vmߑ&9@rDRȢ<Pgi;w?Bԟk׮ٳWDpGk~6asÆ>lhwwuNwBO"heD{=;qifYo_FzKܤ{2vUXӑZpq[?]<P[|lfu"Q PuCJgJ[?<P[K?P >3> P ztرJyɲep$1WS,ޏ$'СC'N D-l۶SN>Eu3jTiӦ\i ܈+(fR/XAA%ׯ_@i.\0deI/7n9KozCֽ]6mT.wwF0:gIQnnR7k|1Q uڵ~}={jРA_/]nn÷]~}C*wBg*=zwfgdY :|Ν|xǟ>ņ/SRy!XᨰV)U*:uJmmޗ#&RhҤpKwg4k1&FL@iR֯o_1g?0 ]uRz\=w!-?;qbQQTnݺ-ZPI?y[qT6oe#YGѬWŌHʟ4҇Pb i 5<|}\wOPҐD2f;G,1oK~OXSjtֆ-úVnsﻛ;+YjW*Y Pi \J]< 7ޑŁJŌ}l9>-7qJqotWGKgvf4gocq≄?ʮ,ayBX_B h$uQ*/zڙ*OO:RzWB|#fwOǼUߐ kc]^yŮ?Z*w9z0w/ {|͛[sqjhݺRػoS]K-+?YçOop!=d/=_=7i]yyZܽǏWAz wr}W9=3ϼg<9Cz}IDATH[)H?֋/6o\mm3"8ǎ3H98@81O><*\{ʕRҫ+ _.nwR>xп>^)Pc[@)߻{m)?JLTOZl~qQ㔲rp@il{S݀mἤek1k &)mQ6˱䔯N8!l[=Ag:?g)%˖ ̦ͱYZ7Lp'7ܗ-ROy7]'ڵk5eR۶ٳiDܨruClU]@8^)dddTg}"&*sT=20l6n§7nXpR*R^jxb 8Y&>ϞAX-\\'mT vOtAAONY)x5Eԇᕧ3)u;uC)dtr)ڗj߾ҏR!~xߴn2^:),rK~[CZ;A:iKnnRѷGuu׶ĒqEcsSzHџdW'oT9KfvŷnDn:Q S)*IaFTr˔ʅ"&C&mαk\j3 Ry9e!"ur֑_lxe}oѵkהK-'NXٺ2hn~=<=:\Mm??OV\~YmdfeK7Tz ٺj[)*{wn3ϽuiOF![H8%UqϴYF!wLTtʙcN6ih~rL.K Ss5ջkoٺU޼yR>DuD҇$oJEĔ)啃熊GLaNq)_Ku5ͼ4Wc FhA",%sD^];(!nৃn%ݴ/52L?}7|zhԤx1iRu;/Fz{-\µO<. } lFˁ5x-t;X<<9D;)t|U%2xcPI['_.IWjs",esoWd2ܥd&_A5eiԸ); H]T#G-Y*=mō6)7.n X6GpϴJ5\t!^v>9cqߜo:Pomm*:X{2ݯoƭ5)17{{!Z+}77+Ң?%.גmW4% ??Q-O ޜ%ea1;%}5W[Q_ }ê-qT=rC_kƙ_GJRWO3E|5)0zʗF&Yߖ`pm_^ER[oRswcysu5tM63|*cDrwKqCmHX#^L,]IA WdUйQA.r;~~sM5tq4Ar|ތw^0;Is''͊_K2,_;+- R'kJ602>hh7k| o+8k"i/MŮ^Wm 8/K9nsa.Y9gMjeVIK?ycmt ޚ$]9OSTSiy:Uj,U tSO{~=vJ *mp;GgG~8.|l*ުeln+U!~ݩEbLzSL6hך5PڮWΌ~mfǶiw͞=__}z)wfa WRMz{I6Ӿ`߭Z-L Y')37K :|ΝUz# R su#ԙt_ _&XFnذ )n87W*o9II1crjҋӷ䠟i}b[GUJGҝuZO+KO򕎿QŻ*<;U~-:nZ)pUOT V0cd,2ܝAm.}./U8%yLqUO,0OLa,_9D$~Cڽ;Yf\ާ-דSEȲEʡZbpKcn#] j:޷]s ܉2rcxTggRwz7x~Z㢾^6%H7RUuQr^[7ıCŠVt̫-Ž#?+<63}e>)2)姞|B8z۵zI|Сzf…NjZ?*ɉ,Aɫ^^Qm]t&y^jPqp/[|mv1'j'nV x)w5pێwJm;҄4qc*%˖ u:iKÆ .|+ݽUOVf13 a#G֭k1O>!=prߐ7PՌFZ)R^ץ)?JZ6l__Z͜gV+׍zMyJ!##3'pKE;kcuMaA7\ڵkSoo-(V!GeLB-tB%7lػwT~ץejcW/?ϝ9o뗖1Kz+ӄSQ{vmڴiAATޝ1Mq8ǎ[!k-8S2#/̛mǎݻ8lgx쁀=ٯp6ƣ}i2omy%>3 _neeO 4`oF%\Νg|Ѻ!a!c=~P{޻}m{6|Eeݶ_+26Fl& WRUu&E-I[[Q?myuftV}˱*OBzWq-ZC:[ץC72gϞU ={(EJ~vС”!x/G_JQ:u?l^^R%m9up6놟Kkn:ӖתS^CRC͚5[51t[亵J&Mʯ-.\oo5w%F*"IDATGߙ3ύnk)܌RjD [ pӹl;?x/Z8n"#wlݲ_Tm?&~FzH4lP*?q~^y?̻;uF_^`ցysߪ]rSO+eWO4 pBͶi1tޚ3w^0چ YM==5 37 <‘#G/^ؼy**7hРGnc?w̙"[FSFhMܤI[7oٲe:v|p{ǭ%i j222;.Y5٪{{GƏ 5 ݓW CH[Ruu2ew_/5=v{;.Zx zLiGR`=>8q .HFMk3v.d7QPPy]vMzFlۑ}GTW&mʙz;\$nի.Xf!I7J}ڴi#*d-mw۶oߘr1eF_;gj̥K-ܲj="жp!ܘ㕉GyxۖÆpa#Gl6&F- YN`N"f͚f2ťfM Ν?M$3sGfZeTomSO=3=n.\ذ1Y*H|F3QkkHƍ}}eg{s )=Gڧ5Q \3$:v@z(}o ,?wJ[׮p WsWǎ髮]ϔ8 ) rwt %=PR8s멏W><6$TpAwj5|e͂_yA߰AJ[lK\ovg)M܇3--oAϝk[oڴ_~tRe˒k?$1hlc۴ڞUFc.Le*rK3g,]5ilVm'=qDք%_&N(۵KU&h4 M}TnԨ_R.]?ǩڶxy6>ܱӴCWQryշ2JUuOg#r-pE2\/cW{Thذ&?߼Y3Rv;l۸qcᐚƙzmסTh}W\!׬K #f$߯o{{pH}dpBFƞ{tnҖ;۶e=;SN_tKPc&U5LT𐲕ou;zvN^M?l.]Y Gp(-j"mPi H[D&5@M-j"mPi H[D&5@M$ڶ@M-j"mPi H[D&5@M-j"mPi H[D&5@M-j"mPi H[D&5@M S"6"%Ofl3cbq@%5qE+D=߽M}-P'um0IصІVM^/c`5ըmK^fBTNi[-R1!\ej!eG6eKՒµ% Pv+BVrh ˟k\JfFNPwZku座ҢuMH2&iK_mxQڶ-y)!H)6y\LI5QYW[wgi+rO"gF'k惁bGʔB"Q{yiѡ}Ynxό)1zꪗ"+10"ܳ*LMX+MQMۖ%j Ôd,P8!rK㘌I6'U K4kS}Ǭ;g<f?a݁۩vr3V^Y !Jv5pFe$O#vߐXC͇rZXڪ#}F1_7@5iѨ^?o)6 "!-yD KZ?mԔ0hy^-n ts5jf/:,:UԊ!:t_1ScB-օƦXS~gZXƸsux[%dM~ڊғ6c+g2cn rI[<գ4xjĔ$"ۻnn:35.L7R.-M̈́HiGƆyYJYln,N57k0#1\en'L_zoFx\Y{I[qJ ܬͫߛ6vHh ;M/3$livNK-(I҆e妤fҲTnHkהpT;'.*\{xY./._WbN&4R)ѡH{}՚I إ&3@{DĤd Zsrg$/12Jnal]AVjfEu J/O`wZEKKQڲ-񊷷GR%ɛf(m7 2%;NhQD[ I1X&*+Co Iٱ: ̎1"}"B#g>5KT&]dHQ١B5MxBb2,(+,y/<Ő*ך^Xht!zw_gHN'CmI ց] 3b<&$Nqw"kf]Dd qa!I~z.LX(!1IiBcS}KW1Oٷט}qCI.q3"t]&niNTjX>؜Pf@miL&SkS5CVWg:CBXd;<-1}eYؑh{?/PIDAT\aG( Um۔b9Ucbh_UU9)%F5&-u6SbCK_FCB^U*gƎyʡ҇!\L커&#We3v.->-9xs _dڹ#m2aM L=TYܻ]QK9Rs ya]+mZjId,(o/&.0Z}1GثxD<\Va>xUm} @M-j"mPSZR"xc @%)-Tji>bGP? dP @M-j"mPi H[D&5@M-j"mPi H[D&5Ҵ҅|iK-j"mPi H[D&5@M-j"mPi H[D&5@M-j"mP+-ۚϒ.]tҥ*Wo{mGiT2LTnܸ-͛{y{O߼Y3=WH[n/_,7֕+WI#Rп_&M5.];L&S+~ܘF. GYn}mI~y^^ tɜ#G,xbԨ6m!5k%|=֭/H܏nWYh޼ݝ:IQbؗFzxp!pҥ8}O~ǧ3Oj}ஜm7o٪[AH:0N͙ҖߤBƍ{AgJ[rX)aZ(**-[ݻc-[Y-l۶SN>ESv~wС'O*aWr9>Rч C}"QoEU4lY{xxޏ[ru~骺_;v۶i# s9Sg/*6ZU1]|yḞT2jv{qߞ={Jv[/vϨEUuq[~G۴pD Ok)((<<- f'; bŸ^䘱_߾Z\K ѯV`%=<<ܫ}vxdphQQTn֬cM ܏Wխlۑ}G?y#'3-GW } +?݋/)"#ߎDN_Owwꔱį]^g y_%yO]uU i ܙ33H!+Wͷr``Q;k%WZ*Q+ +>Rɲ*JNĉRˉZĠA;V)/YL³ό䑇Sp܁ _nT Æ뮎nc˿W 999NFqJyꔗxUיu]<'씙~a'׾Nՙѯ͌y{vmڴ2am{N)hBoϦy1sgp]Zb.ϙڶ$~Fy@nnRsowҠA>J97Wa';Go D*~ۖVUgkvq|3gBÆ L^)U*EO"k>:..W k<Tvv-[J k-O[V̭CRCt*4AV0(VZ5jT+]LK^*jζmmB[;;˔/0xnUq+S U_̺L!')Y:3|RZθ-(i޽JAp?[V {vS\Un9\톙 6Xϑ#G/^X [%PB*wCrssWV#{Lh@x=[*߻m[JUnH[\?/pKQS(.غm[M6ٔ9EJyꔗʩUu[G߶#MzHrʕ}sF#}Pfx|3{H5JF}~K.SNW)p~Qzoek'm0"BUoHRaץҗݸ?_ڢE `4>-***_Y rY驷j9k;#ZlR{5PQ{%|ş3?J|.ip/l_]2|(lӆʷs![t,DNn379$ϱ':]*Bɛ-3Z/ i"oyWuuWHywX0|QCV\Yfep6JWf$uy˖)훮^A?.)''ĉk?[?ޢk׮IդK[NﲻQR-6rDcqY>=h;6|X[l%ue`Wg-kIW+z*Mըǯٛ]l_{_ol={_ +\FIIb/59 gO:ɜzUZX4?\g'!J <'XXe}G-|GZmD5!ݰS$%T2W(]kFa)C\IHЭq{)wöu}o$xe@G\p }(x~D|p,.H)P,߄Kg1itϜ.E)[o4ڻAn$w$зYr e [wck[d!QøXmN[˯uzVusa{&r\kiUnFM~C so*27PZYLR@[ ҫH߫r|P&R,RD0w&I?=˟]l?NN~.XRmXQ].hǠ#^[R&-G*YFJIJ|m֫Is]URjI{PCx}NHMr5&海 g`Kk9dGsےX^1pC]NU#W֟t.Q9fu%fYcseyo7 n"H9mV_Bt1sҭ`Mtkƾ%څ(%/V;ViX|5 \7I+54ZPGx|^1;.UF1|IG#4qTP~7$s YrߘϤIDATdjEPz.s7U /`avVz{{M}=~rLv Ar/*aH(l|lg,]k@HQy ׃CֵL7xA*ٕM,?:yf}/6|,iذ )n5k?ׯ+O :|iio\WK#op3|U߲G.5Kzq֊ޱI]K|t3J}xz-cTfu?̥ M:>۫UM:3en3OH$k߈ݶUߢ{m[*P~\D2Ima%sgs%zXn܄)5g20ww;顃۱yM|oႦMJK]l?o"_Tf͚s{&~3}۵咯2{T-)q~"/Zfx]ʍ&$eXʇ|m3VnZFic~gK3_%Qu/<vr-Q O=!jr_&g@r~Fa6AC jRa6kdp46׭#/ϸ?}Rd1s4E\ܰ|)r9Yqҭ~ײ^ÝZG-ڶx4\UVIw, |##}  23MbNPe%KkRZ~Ur{ P<oH,/ it,r.E xh瘛D;0$QZ6Lz}SEEEMZDJ%8Qu_%yO^%䟵1iÜY%9kcz^ Xnj?.A(1ru[˯nY*lO2S*]H+r)_{Z޽G'Y]*j*1v)m9v3|yOU\}C6yr/`7yʕR mb|]Z+2ɾn+o6 kW٤j/be? &^+} 7QKޮ],~OJ僇I37VŠV"jgTN*Ԏk^cpUEM~+[S( ^N|۵g@TO+'JNĉRo7A7vR^l}f#<,\Mo[ nj×°C=BFFfNNF)/ r*"3^J:Els!9{vmڴiAATޝ1MqN)hB/\M\ iU }-YY4hWRU@w^GxUӖWgFz*4̧QB{ﭢa۵ ;wN@Jk.UT[ץC8pUcǕ}۵wYH{@*?mAM)pݻ 8_y{{e˖rnUuIRԲ}GTg@ [ 8FuS[V {pB{U Z\s*:\<'PcA*ݻqer1\~~qs IP^ sы/6o޼fF;ozN}e˙ڶy !Pg#G<Wjw({񹡭0ZՕ9 p*LiK{vC=hN*>sوL&ؔ9EJyꔗ 5eR۶ pӯ*W¸-naÆ W g̼r劀ۻw߄J:`# ǃ aL>*WBqq~wg8f%x`șg=ҡC{x=}ڴi#^UWui;Bzm!I^OΔH˗:dpSOO5\tige޲u[VC&m7q22H : m@}sD9|_O Yfyv 9b뷩 <۶l6tpruU]#=ㆆjWnƙڶؾ) )/K.%Tzl۾]жHYؘzf=zt'3sGfZegW-oΔd9ﵟIƍ$H[Pߜ'_n]*\rE|8 н T ?~+k8{ W\\$Ow˗{9|`AAVӸqc:YGxzzuԹ{0ꗓmh4a#U+|Ǐ*ѵ֯[ťi; ]9(6/__}۞xֶÇ?+JèLe*SZV;b[oU8*F@}k$P&MB=є\*PJSתy^7L[~~,1 S˴2]ƍoiݺ'FO"7'nH[D&5@M-j"mPi H[D&5@M-j"mPi 4&I@%mPi H[D&5@M-j"mPi H[D&5@M-j"mPi H[D&5@M-j"mPi 5C5ePoyeж@Mmцb9pn}p4mPSڶe&D贞1A< 0F&jИ.ڶo.$*!3MSbޥ%):@e׹}GzڀؤLc#Btb>Sc٩W&"6ŐhB8"d11,`J0_ZwL)1MS"4CVTJYx -JWf!VeJW{־] !+PҢC]Oݔ]jYU*;\vPiےS 7)ٴpJnv[Y sX=nȲ7 ѡk 로;_hTB!RU 'Q篈I4֭zh+635?C)\e9ɊY6Jͬ4Գmh<ȍIM^jFKUYxx$XsYXDh5Mm4YVfX>ؼĘWXv0yvl*/)&dmȈ_҇G㖯fƐOPWU$Fƙp-Z=Jb(' )ѡ);S ~~ZetXCjкԸ(l`4ɋ7O H̶Ia^vfBl^!zV.:< ̑" }ScCuV z.,.X`RCQkCs5+G3O>f` hd2UY!/52%G*]3rUfRȘfWjW夘k]ŹJ";VqZV,<kgu{Ʈ=F6_HkǩJxMݑ>3$P2}fH{ /;gՎ]p<֬Gb/8gL]whBczvay l| tvbgu{iÓ2O-qU|zY|`՘{ʗq݌=}J #Θ Wm:PP"jکƜe{+@%;m !3!B/*1L*a\ \T%Mܕ p),Ld2ͅJs@k]J̺(^Mv͢DE1(sM4p2saGaf_U̙9{<#$ĉ/W{nAP=JrQꊿ(Bц] F?nK0(Dظ `/_wvmUbKE @s8{+V溺n׮JL>o,^1kW~wܮL0 *QR\xIPUO[斛̭Fv̻¦o|J|;'\Ti )RڲrY1LX%[J[2u')ېQABĄ8G$hK:C:yĔ+9!1%nU.T i ؂% Ѻd]eQن5^; 7-B3-]Lfl%ø%bv|aDe bƞD ]TamP`඄K5kVF)*{+}u6"8&91x[!SѺ6jq<[EFrBX{9v=]{ p C 2.L%. ,{"o^O tQ%sar!lN;yݻE<5f=^{pdXi ة/r8J`HC.1Y?";RV ̌K%e^l#}/r5'KJ.4v *um,Zy'㶄 vxyp9!>"\'WdQÔHe1b{QBP|jЇ(&!*Txܸ>ޠ@V[ZZw} quvv m[mSՋ7W-~bb3dm[u*2cԶ*n?O8vZRQ3BqVSǎ6uʮ{ȅN۶N@-|%I!J2!>WhD!*_lGxrFhXCA>!Bem^\g'ql2!]sss۲ycĔiK.UfoذjFQ -UfKiګ KL-m]Vq_lϛoKر#==]̝;|кu ̀DԩG1NN Gߖ- m@mѹSu  m@-O{ ÖmYz,F`\TE%' ̃Bi;v 0عII&NfCc];v&nܴɸPYl)m9|_ۖ b͂Eep*ݭNJ ~ZeӧM ?N`~vؓ(777W_jQ#G1Y`\rRR&M?s]zk׮Sǎ*mtO>= 宮Rl)mYz,F(}/V|ip~bx7 ˲%3+׮]{m'MO8t:u%nY 8}v&Oڲw^Y b?iKNN,z J0YP=9{V>>O` H[L1r09 ۧ]4tiufXn2w_}︶%^.kE܉aPy -l)mpw`|'}ղ C;t~h31yo'MjE-Io^lyy<[eIteak };=>:٩bKi r0d$7V&Ʌ=D-8t\<Ÿ9[h?E FL<h݀|gg-ƣnYi Dfo" zV|qqPueDϓnҴ~@IDAT@e5rl_AxHPSl)mʒ`MRڨf$iM[DGߴ!4.Ce*,DjDі)[i8t4OBjgCĤ̈́郵k<+QaK{ʒak+y $\ߏ._01)qz5nn0IN uڵf~m' Nߤ#pw3ή\#oIs&a޾l\= ع|AB ~ݯ.B0kV͝&fM @LyazH[X3gbͅ  /̻'`M6)<˾}m۶mؠ`~:qQXˢO-._ X3g~b֤EոKWW..dfs/Vh| mjШsW^^7qQKP=, -گF $W`^I)yG Jby=es*qw`fԶea Qn j.`qwy?/-A.P{P)s]]8ïAʟoGNʕ;v{`6JF-?nK0(D<67(^JڢB`ȶj(Gb:vC]/ i M/ fcK=V^#Q#J.U˖N鞞@M;uw?y}̻0))emؠ 6n"dK*? --YYmժL[H[իlaa]=nC)nnx`63JWE)ҟx\.ϸ-<,VZ#j-sg8sSct'm[ۋ:af!j dab<Sj3?r=ukua{ko)/L Ac?g;q`'af%o P[?oDexAx.jR|$!bBޖӦ `3J4ܝSkm?p (=zubJ"V+@WDhFr0JU{ߟ'Zt,B,xP{[ڢظF?[QQ$/Ki۶1c>cǎ=ZԈza9h$!!?(>O8nm\%2+\uqx1!QG'Nw$9oK\6'g:89hm^aWB"p]J0(宮ٳf*umWOϴtQ XU5?q3 >[5,0Qb^pQ>Q6H-)%x8\Dɿ1@YfroP#G|{5!KDR j5oLy^ ~[LJ# g 2X[,U^;ڹ׺%j!%PԒQh2''(l">Hm$4#9];P*9?I|~rbܻDGݕ %&=d+QPg I'B٭|VIR.ʣ-Q,w:_L@'4NIDݳH+]_g-+k2&,F{LJ."OcL%j65{vV+Nhx$[ 'f)gˊ<"[h}ax|SZ*lVY%UPaWXk6\#¦ˈUiQExgiihP33!`pȑ+׮]+IPUԓݭR+xόLq[B:V(QKdƷ =8&,62F?;[0 ˋZ乌.H C}fG8x~Ύ">>V'G%R Ά4#JODs *W^#mQbQ ng2K>GV~vpe{ǕG`V} .翽wll'{rFC1'Dۖ-Qao"dW ]kψlxKe0u@}UZ7%Bf(3xanJ(e!V\(.Ú*\*'Z_!._ԱMkr>l`-׺Du١c`9^Y(گ'/>H=VN &0ڼEkZFq иٮ.$!1Z=t[4lڧIM<=eo v\|1\]'ʽv5.1,{tAʟF{2`*빼D>ᒫ*\mQ*RQ_9!ڀq:VV)F(eܻi\ܰ7fp|iUW߱0q,ܶl8ax9~ÆU#0r(l={{/_*LNt]TִՎ,a}SձMדhK*? K;]ZvmړRnݒGldaM4j,6–mQd1jDPN:]JѪe-,*&$#T^BĄ#[:u>(&WPnnѣeˀf`KiIUl&MC0\kMZ:w~&No m--pC^K[^8)]B3m=zɴ%u^y0up狚fzEN)y0MlCx̫[7Ydgg ̃4pvv_u_Դ7.EEuM-dqAu>tgd DftgND;wy}Wݺu |邀IM={2ܰawQI6 CfƍՋ _|9_j#G22K 2`n-wPR4oM&?aæZZ5j$-$9|`k:u+n#~W*u.z @,Z, T--0ئŖo^^=ٓ}rrNY:dpgg%:|رA~>%%q6ucҢyGiִZ履dѺukyԟ~0ڞ v;gh~Jӧ--s!m`i]:wnr/uJE;zU37cݽ<t:]+㢰2+WŨ JwE>@X( 5aKm[2P%#N;sع31q׎7m2.Tr9*0';O[~n[BBZZzFf.P=د~\668.mڲ;))l\#Gj-ZL65|8aڒ+/*=G1rpgggE[rʕJI#g4isuٮ]N; 3E=Xc3 O KeaoŊ/O _|TƂƉRIDATEep*ݭ׮]{m'MO8t:u%nY 8}v@mǔcǏ7klϞTZ{wϷ 0I[+ ???V:qĄImqIF.P{=zLq[ْFfbKmV^#RȢP|}{Z(//WR̬ۖr֞9{V>>@-Ge]N㽽;,P]r_>rdQK)K.]6~OJ*OO"ֿ}r?_ڸ%tKF 6!c ڷo7!|L mGK3e3 `D-(>Iܞ/g#N;~-eamղ)rzzP 'Yz-F,~wk)?/lAew]+3PԓMNmժ,ZcW\ko F ?]^Y-<,VZm8{;Qn7C0I[{gJq٧<ڜדSR^zmc--+WSk֭Nؾ}Zr傅ozƴ-](3+ RG/K'N/lڼYx{ ;Q/,>Rq"'2[)uqvCbuNёUE9Oܦ0q>r{Pv&b<|2mxL[N/!?(>OyPys%OO"ixeA wMܵKM:.c>(4l1jiެ}RǼ^Mw2]r:̌KE;nqptՅNE;*Duɳ[;o,w-X"3*d t::{צkݩoϘx!Wm1%sRۖ ڼacۭrvƍ$/[Ӿ]ߎ-s]mzzsU֨(1;%R/{-UzEX33*Q1CRC;JF=.LXQKaJ~6>>>{[5ڶ(4hWkߘ?O[ɍszfW)Qڝ5؋GmR$1Zhhȋ$p";#:]iC'tABʹM v-c?E!?GP0m&M~gq='Qx<>#=} =QdDċ P{9 )xXgR`|\J@%MyaUe=4h1$RΌqPي9!Q*ޑ>Ԇf$mQx[uKGƗq9B.ЇHUl# ܴ!NXĕ+W~u#GvtҥKa.xs,n۶]I723N Zx-\V:dB|cP/܁(%%O8uٹ{wÇ-7DE-Z* "m+QOcEE vȫ/.$,[ 9!5E M+=h_4ZlmK;],&/6̰}p]@ãsGm޽,`}i@`-3f3~fF "H[vӣsYnղeK/ )/LTO}Ͻ}v)g?0Iڶŋwڙkwٓj\[Dv?cJJʱǏ;.`f8c,ʼn'&Lznjt7>'ea>2m)`F LP% -̖w7Gˍ&NS';?0F-nnn}WِgG6}Ƌfƍ0"m`f,\\\>d9Q e55rs֬Jo-|URڒ%6nܤ锢yf%"In+BnȢ!`9-ֹsdqO׮,&''@LyazH[L@%KK3KڥB|V7rXmVVl`N4"m*|# m̈́y:t8tP>5? eoK._J{á)CiC(o OY>cm=(8[I4r0V`4yÆزLp3JԒ:C4i%; :LRFO P,Z, T-mpwq@ir2_}EVnY!G-<7"l=&(mwj#>ߪIRIIo6#mJ*}|[Ro_!c5%72A`H[|eS3BkI\p_M0-e*e5rPLxϻ䅜>iKkN]yoz$lyFYeWtb7V6~.[J[f>sjv-F(h}Ff֪){gޘ>vB6Ԟmo͚=3)2GlߙxiyYW{OhQLִiS8]jAyyyAj6mRx￯v8tRWEae,Z,)/Lp#lKHP Ua_~8y]]=vio0.;B% A6 b 5A(Ӿ_-Z<2yfJԢoҴI[4XRnn}/۷( }-[:qs @霜5[om%d`GGZZzF*;m'J- m2h\ \F?g' O#`q -1 +9Zm6Juټ_s 곥-nrڤS8z CnխuWIDAT]&`7_իz-Ve>WJqpVZz{ T[)Ǘa`vUVHKKD-YYJ7)@&Mz+EcX=[J[V^#Q#.uMiN[`U7v饥-MQrߙ$B [R,–cV N7gϜ=+H[س#g6kT)O>sFؗ!>>>!1jFQdT -Yfb:avo+W ;.1yj^ &x/`&;`~c@Ϟ;6.|￯W@ ׸/]ڱ3Q)sd@UR͗))ʤe\h̘1?Yf*ms7S-b<|2 88'>>׸*&!*[288:q -uXlrp]\(tG{xrFH-q0Ϊm nv݃A:LRwuQ4)uG9vسu6>>>{[5DjgL_?;u43.YHPfD+Cfت횭 ӅjiʄƩ]#"QZRr :8'J9%pa`G5Q#p`GVɻ ;?#tW][.+钣=G *OSFu v-c?E!?GPH[MIڵfʡƛ6m:x.dlbΎ"oR옧mgglsQjCEBPB0yaj#j"{Kb"cVoD86HɎ?W 5~_Z%'e@E5-!F[)QKX-T=qnx.!*fHjwd|cPQqQ!sB .H+c#)15\W">6>[8::eGFJaWEC$Ij݉c9GTDP` qfdfK+W~u#GvtҥKa.xs,Ȗڶ>LNl6qZѧDۖ-a/m"dWّ>C6+ZC 'ƣЅeH0cy.?NK"x=1P}H!sVsq =쇣{^|%.ܽ׈ZD-Pa -l)mpwbu "E^|Yxhz2|<NBNFنQ]-+԰%uq ^uKՄEG!Bz+ST=Zqkh/j&-!9X} ;hיV}W;sB%x1.K\^}Dd{̬g@@91uz٨56\8GKU;;jآ 攄Ќ2-DB [>`jf\r,.,XXӦM>d=}._Ι;/zX@)(өSeP[*/#*Xs-MYZŋڶ@)N>_*,$&!pbz #8uKYTO~b.]~MG!󳥴EYF0P.ZKp>RBYW*SM6qc^J7Jw^X--wf:u-EͲ|ziKΩSz@)5m*bsm8mnГJ,}Oowzj܆M=*g ` H[L%uc]GWfsܹI͕Kz-a'BR2r05j˷ߝ9{UIk׮-e퇍K>Y;88 'jhѢ Xh,.Pex 9'N,+j m榛nR[oOipmM$X=4h+_P],Yj 뭷6pvՖO[w.pt돋[}!?NNNG4jԨ?nK0(D)7m`=4j,6-3f3~f옒Q `&\FF0\.fF;^~aL&4Г`.^k][nϞTN~ SRR?~q0ӧMe-N81as[~'P ե˼>Xi Z>2m)`F LP%vg-"m`o??hqv w~wvvvv`R-ܿ}r?__fC9/ʺg@+7J̋=pqqD-,ҖÇ έYZF,Z, T--n*lM:N)7kQ,DV޽fsgLit v+''G=!m`.^(.]@i֭#k׮ Dl)mYz,F`\7ִiSY7a~^7nָJݤ[eռysY>>CR}NvcXQd.O ;oj)/LH[س͚D/u>~+VV+pa.UTԋdZ:;9Y'PQLW׮~&4l*[&T=~>{\ظK^~~...‚%& ݟܗ'?#KY\GGǕ_|{ϟnڼ/dРʛ@eUR͗))ʤ閻 MLCl/:;9nf$9'*0Z=88'>>Ɏr-qa`9Q/L$>ǧ AyEvbPp wdSy:Uֵg9.mI.]Zʤ۵Qtw7{ثG,DjgL_?;u5&4NSR(I֋'ݸ\A|r{sdЌ`'!2VmlH9zу5\+cJRֽ{--Q M=YڭI*jNOP| c-&dN{ύ޶H5t'Oܵ{蘧ƌ{@IԶea_ʴqӦ/WZ:aRd+HNxJ"AmrShB]CIJpgG_QejHȂgRR u]2vQV#=J̛n-,Z, T--ng@%ҙIDAT˅^^0Nu`"x ı8rFu |ϋ34cS;po{]p1??l߾cCfCO"I^ t̍`EDN"/vUsOt\qa< Dj.Y ԩcG%a6uʮ{ȅNG;hq: .LT7 ӖLJz,^%1ڸQ>j XkEx[줎$,Vo]Uν{0ޑ!Q)J73\{B)x:/u<D`{nnn[6o0~]aêCY_\1$ʸq TزW-LГ -F׮]۟ԭ[fV;nKFFRۖITN?qrrRGoyRڒ%'T^N?Oq7̃q[PE޽+@ԣ>m9%00 uW uKYdgg ̃ѣdѺuR7Kli jdZ`-P-/͘L`#iw m@mr*Y?C m@?1.\TN;scmڲ;))l\#Gj-ZL65|8RڲrYQp/(N'P9b%3+\rRR&M?s]zk׮Sǎ'N{ƨg@g,wuuRGؑ/V|ip~bxZOۖk׮6uY{yu{c\`qlܴĉJQ~O/SǮ20YP=ĭ AoNTگmKHHKKp?n&`A>r{5![`?i޽{e'gwRRظpv;n]t:IͮݻEǼ6{cwX7n#~rssMq G-7+׮]X1irYY*rʃ/ ݤI{kWvuQr{5!z:w~&Nh/2\FF &w^Y ;K/W\`Y:fˢc^=g1ݻ{j'ӖT÷8-uʒ0Y`_RRTpZXG̗_v효=XzΜ=+ _vdگ>/g|}G?񸟟omofq~---޻prPz{;۷_gggQy^ݺ";;[`}֞='Ȩ~u˳όnԩcO:e׎=IIO}VӉʫ_}~Sc^zU[jxe 6Zݡ'ا?cZX7ߘcGzzRϙ;wuVc COb>SOU RN?qrrRj%ߖ-Bv(;;+ӹSu Bv(qnY4jH9`}z✺w0n ءY`zЧ-99ŖҖÇ @;wNt**yu&laM,Z, T--nP:, `ׯ/S$0%SDEy7i un3JLOo/BķOk ]|;. ol [-c(MO ']yf:z/9nxUoE &aVɖҖI]t!uZG;vv(CziӴUJ27K.?C*OSߡk˾/(1(]O ']=\ZzLJI{chjcy*%j4O=R]+8$9v裱5:v{Tr~ JdfeISC:)4xv3ǵ$mᖱJԒ4Inf›]36(wkg 3\?}l5;ƮPx/9nh}&j :xZ``rj6 ![PRwf(o-rF;V_2XZ? ;kPcq@9[x? *$ * SAϊѺ Iʷy tU恾m @-`r *<37M.c 򘔲fZӳa?63x&myy<6<&^Z#26Qw>/mh> ErGԅ#k#|u|}ҳ(ئMP%}pُ#m 2L1?z; (WOCR}\kya#`nS^,'@Um.æMv&:?zN}LF:m.% &\;L?gқ^A?B5kL:^P8ti=L3֨ ]̈́I]vIꠦR?~}K]hTCc>cH零 ;Uᄇ~fhɶ90``cԖ)̪>1̴tٸG/}T_ҩ?#OTWLO"K.:|zGLEDOR.L*T4Iϯz9RY^􎊾&ʁ8miϷPC[ѣǎŮ]괵b>-kOY[ oݾ3qIJ7v\5ٸR{ӵoP`WkgL[nVŚ߿4śdݣg CB{҆k +ĂE+Jmf{E반ϜE<._˾_ݹ&k}mg4]CLylb6h i lîI{ 0p֬Bx%LħpZiӦ(ڢ~~IDATkwLJQf ЖUfYe.yyϚ5X,d[7|0gm 35KxuL0jnX3[J[F&Po6l8vʉS^9rfM=W\}{ZٳYN :MfVǟ~2h`6C7lڬSB5oެؒ|+)خrUJ]Mi?E|邨f|ŗgϝNNN=|}ڷkȥsf')g}lϝ7_)^1E:uzW[ζnݪmrkÆ Q/]:utZY'Nhٷqn~>>M6mҤIݻx-:! lu~ڴA#)`3I]ƨS}qv&d?b4nX9MԩPG:~Az [ĵ-[Po֯򯿉{ǚU {Yׯ_ovKp(ENΩqhX/e+AD-ݫ[zdy˖ׯ &-Z4nqu:[Zic̓e#3gΊjߖoe&M?=  S^vc;'ji m=PH.ʩKkղGZjF~|TvQڐv;uuy.خ&#UTOۖV-[鞞O?ɢuoK QU?,{uٲYZ۰aCY^:^7n8 +R_/-ZJfHjpi;v<\=\dgd?xG/G%[|ܐw&ؙ(kUv@'s]]Ո7 /KFd!]eRYߪy[͎ҖV俸iM[ikkQSTm<t?Z+EMVe>_KM p;Soռm0YP=ӓ˫,+ssx)?+ŋY[Xʴ/?!7׾9fZ Wތ%3rر3_~YG^d.ߪy[~ҖG~H+Wɩ୔-WZC } Z$ ?_4}rx_XPa}?G jߪ[~Җ~}ٹZ?5MG?5uN;cs0Xλ~rPUN7IX?vףcb[Po&-f?iKݺu^P ۷O67:mΝ~wPI1>>>>"RJwP}FC}#XmR޽ ZB zҟ3Vr{# K*6VoMN7 Wrײo 3|vB?Zl1!C(sGBJ ` TIn R2r09AP`s(}{SIIڥˢ?'?_>E~c@H .5&EUM o^gjOOzHlݣM.LԅWb0Yw&*RdF*NbB"]g''*Ε+W^|9wIFWzFUivv=n4VC|.>)*nӋʑM7xǎt钀)>;fé;kdΝ^ObvrܷqۂZV,d~pOFsŶ7|Q#!"&S˺\.27rąꬺrKŋꮶ4)2p\Ms _N8u/DLSuׯ_W:88,[j[6,կסklݶm'!:uUT\ۈ6wwVu\ON}jӖ8 ϤVSRDΥD,jfKw[~myF?[속I)<<<222Jn31KUZy}"R.Y6^O t߰_buoCʏa]F'q3S#U&JH3b h=:{^a'm w5kVF)DUxzL>S(WxgbkJ 㬖ͬ)9.tGN? ̈́qVԫ#<Ԉza}NO~g_=<\D'kxE]T>w|e5x|.EC=88'kX((mO:{/CޠpFSp  E):u4:yu /Wۻ;Eeh 9d=?Rݭ0`MuS"owp:>>`U^{|*twƷzq`'>uEBxh߰#Sk:LԞ(_m;v?J9TPøW)_:D`)3nQ j5oLXsj]V1e$UTv_M5xc수!sպ7QHnR1+r+']NzخLHh`'{X wVW)t[6>F E-)CD-j3)Nm"t&RS.QJkݒ`';nٮڷ ar>#33s o|64JTEejf*oTyV>Aa _kKPsQ{EGD.B꫚ j$RSpB-Yʺwٚp4jeŷ0v;BiFd{ύ޶H+(Wy r*%tjի_O^|eCpsFJ9˕vn?V$W$jZ)ZODrx0] AWJWRTsFΑ'B*iJZ#R: \:&(wU͋O\v?!%)Vi8Zy5{vث+c #N έZ( !TvQ[|}/rEɖNV^#Q#Ud <3v21I?#qr}-TY~^Ifg6}~S(koE,,X$^cci?)'9W|0 QFꏨ6n|#Rafh ~ SGI&;=8&L=_= 7lI+7tt~ 7*wpmՓ3B^1Ӌ-ng )z&\*muD%)b7lhyfŠC ;;٤Ism+űD:W?&׉z P7֛HWDWᙝ+ MC %:Hj4Dáޅraew vnrtrˌR?hOFKR Qfe-YÚNyas_shO +:yiiޅ Mk 灃7Rwo/~'1q׷ѰT-mʒEGZ WvQ[+A8nA"ߪK<7 @6o^UImg3"(oQ䂝yK[b c6X/d2^XVp4^ZC ζum+2u/\@8bV[WO81.|ZxwYrSOVΎ*S4o֬UVJqߏ.PY~˺zRxRas  ~Ze07lƱ3 |b1]lS옣6jt5T_hGZi 39ĕ$cUe>Sr}0!O:e׎=䒝6CN;"_%0'Idq=kUM+@ߛ y Z}½rрi;yTk_򔯼u{~C}}%6(8׸؂Gz&mdSQ;jMg}y TF:CvtV iGeȔևKbsGooÞ KNgy_9w*|Uom a4AnM}n~T(:*!mndf\reefFtԱ:(k`r^{:vÏ1%>%xp=;J;#?,6oOJ2^nǚ1ĸz*+өcYdeZ5%Q iK%hٳJW.2+p%Y6ӨQ#Y矢ڴGꐙ^޾7_ǺUۅ q=4i"*iӦ8* o~¿,&*s~F,x8}<%Vyf8{`RF+f,Ӗ?CT^vm~a‚o?3d5k**#P>c_ׯ j[j2r0ZڞR wxxx}ŵuݺuS'sssD%5ix79>V>rDczr-"ܹs7kV[ c˻3gϖÏ'N~W;5tvY6ĖҖ wgN;wt(vŒ?uWs4c2 %^/~ Z n1}2 +cvY(1SVk!A oI׮]ۛwPY ѓVJYRqR9@ xRRY{{uzz/x*G-6A937^lQ%zYJ4|YgT)7mV-@"m PNz)? %orsՋ*W۶mjw \馛F?X&oo߾uVUIƍUhc5Y&8xhO^Y׆.~\֫QFʯڶmEΝ?.*J5?ZڶQ a_6my7.PLܱ3QJpF@--+WŨ [[_ ;tHV-]\_==j\2~ݣ[G߰Q!s7q󼫋k Ο:m\^O#s…ϟo׮\zuwr/~5^3SQbZ߯Gf%Oiipum-M6^9.^dl:n$/ R0+UQm пc;9Dا~8~< 6,g:ut[%3ą Μ={UYrc''6lڴup0 qĉ/(*cO?T6ƽz͚ X+cݝ n1qQXb {j;DkˑL-''߅ WʯZ}hDT3J(IDAT/](js6hXl?\@m4(·=^N~~ȨSǎ}/l?q[66Qt>^\]1uڎ;K^@mCG15jف{y֫Gcٝ3ph9 jz@-umE/z:.//EoYv@z q-%Mٳ'1q׎7m2.WrFN-P{=2(vF?_ EQK) ܖPl}Vxy~_)ukK 0[J[F&&}oaf+7l` -[>mqa9\Ԯ-\P}x ua{矯Ys*OV{5rÝ2-ݻ ̃DUn(Ӣ دVi jOpRwرOAZ!b;w޵aeҖb@ENJ0q?'?/0[2P1;vLLܵcgM ek {jݶ]{_?X`fvNJ ~ZeӧM ?N`~vFKt:@8j䈑#;;; ,Җ+W<8pPJ9ۤI{kWvuQd@Uڢ|z1j']]]v_eF`aӶڵky]^^ޘ?WX-7m>qRԯ_Աf;VR2rrƭ AoN`bY0\.l)mpw+g޽{e'>oyzqfL@-f?=rrrdWI[Μ=+KI[Zlyi8|7qfva٫˖Z&VڲrYQpZiKZz:i )t̬,9˫,@ |<,VZm1'm׷; mܧ<ORnݷ-uSg?$R>~ *ᅬ^ս[1!QE7t735^X|nj:?,6O)8"G9!>rUh퍊< [S^,i"͟7?p (#[λv - V2q"Gh.:I>t45;?"kpw-L)\׺dy+En Q%QoUh!lW%ޖ,E3- n6nT&|ٖ )}Q o@-V2\:;c,h;>QEw1Q"<\TyI@M7(#nn5WXmQ4h־1^fث(eR. ,>#*[8K/<3(2cc 6t<`&4#Pw %)lN;yݻE<5f=^{ ,i wS1$$/$7>LKa2%RL8 /PȎRS'}؇G̗_vl'*} ;FX׫FW{ûmدO }"RqSĨƆ8nT!d3˼ЌP8-uq7l/͘. 8x~KKK.\wo߱!ejŲ`\@Rw79 @!))%0q[cn|% ymads9h";'dv꠹"hj>tq@ӦNٵc{πpwRctQrN$DLPP0r -uO|QGz!@-poϢl_opg%dONHUDwP .N#湹mټ1bʴ%K*7lX?Fi X+%.)יe湚\b˸]J.,d]b}{y ;v+sZn](@au'''>zl--+W*sN'aKiKfVP%=dw<H%'~0m͍|Dt:-(0p#G wvvX--+WŨe{ʕJI#g4isuٮ]N; 3%3+ t:ݓO5F-=>d:Ž|K÷lH,~mvks^W7g?iMO8t:uĭ AoN@9ufgb_U,ܲ[_?olpGWRW*`bYڙKY\tAŝ?׽?!gǏ z hi3^#9۶m~hڴTLFFRڒ% wkI[ԬqXB+>쑇(a]ףzZc~+ʔ _ "mbK(!X}ro?Z2d#&Ngq1%jPtJѩcWg"P6i߾R\~=:&FvLXYL$P+&Ԕegg˺_en*~ܖ0`PqX{_cǎ_tEvĖҖbԈaFNN,ׯw H׮W\QSH[`gl'QfVXl}ݽ{:мn鞮]e}/ӓU˖NVtOOO˾}[DUy^TؔOOUrm_~}o۪U+Y ~JkӪ᠝A~/n; KKӧ-ݻw m"rI[y!Y\8b%?ȞDNNN?(P1!խ[W?xVc $*I[{gJq٧<;QF2vJ>rEE e}i3өӧG?5FZ|%av||TeGLaIRH/~rfM -%bSϜ]+> *۷Ǟ=f~;v}ӤIcafC&ċh]r6%U<ܽ-&]y5o,&Z&%%W^+W n߹S, ozC@5\x1q׮~]0/0<ѺsiKh.TؠS2LIDATRR=w.l\ҥ_??_ 7돋ddfݭF?[- ܖ 6lxeQ%]z4K㗖zNOdv%NWz ^b /14̸'gIdԵ9nUnGӂf}SSDٺzzVCy@qoP#Gk`^CR.XX6PnFfoD 0[I,r* |7kެ03NG MdO"CJ.Q\:‹ED9J_^?#o'Oܵ{蘧ƌ˛>q[ 4q}?ŽzP$|+Dn|~Hݰxuv9 QRd pC@vȑ+׮]=nР3c(+p=wN}]c<;㥙<T :s _͝3cO>t߯%-7vw!(~---޻pb~~ۋپ}dž:;; n۶U9ÌQqa?>~\n݄9>$b'DҮR5?pgKEyyu4q¶}ٳ9{/, mټqrv VG`6ԓ(3+K :xЗ+W&㑇[:%%)ЌR =3.yfwUqC?2i>Xԟ}E /kVxy ;vkJ3waC֭+0zEG/6zE;9oN)_SѦ1`nu'''>zli W>^~˷oWVsN'Auܹl=DWL;~%Vx(NݻW`|h999_w%j]=\9N=zӖSn0!mx,tN2[#M7Աc~Jկ ^ݺ#mjڴ,=&jɢI&FfƸ-`^ZŹ322Dp1ٍHںjڶy5kִM՜%-=ã{/_ Oiipwwg6>L ={ 0[C~~ۋߑl͂Eep*onr`S&WR$l>7{m))J<P0n  yX?~Xr·d=cTWWW2-` S"յRtgBÆiW=qƅYoO> /z{꘸6o 4(]]888G?ˮ]wm͛5O~T\FF0"ӦǶ>z2{ҥ_~LJ3-=]ؠRulF?hZkO0[13+KNlSvm~a7tGNNN7~^X%%]]I[Bo&M/\/i{g8oBy./|i_O޸qcʘxw.0mpm͘>MrrrVZ%GzH`-G?5…Jݩc>}i jv){MyazH[`v'%M8ir i ӎ;wؙq&B%gګseW%$gdf؃}3۴ewRRظGz-[>mjqst돋ddfݭrss#_~%Qe=5AF9bچmШ[jR~"]rRR&M?s]zk׮Sǎ'N{ƨg@g,wuuRGؑ/V|ip~bxZOۖk׮6uY{yu{c\`q\FF +v'NP|y:vl [J[2Y~, о};P'޽{e'>oyzqfL@-f?iKNN,z b?i˙geq]w ^74],_k~ҖV-[:}Z)>){eܸY]Xe }S^,jny\5=ZEZz!xyuEZi 1u}{C:af,xs*cŲpZΖw7 |JATw4{w/&uXl^EBĄ8DeuvrԈza%؛SpՅEsB|" Q)1I$͟7?p (#[λv ^g*xd2fFI"4Ne:mlHWݵ0r _$Q(z"F YJܻgcKm[*h~o 7*ZlKH`BGEm"Uxkr[Vnd,uvtaĴ&0"paOT(qL5w|ePWڶm;vl֬YUХbֶEѠAZy͛5`(' (eR. ,~l/-bs =뉁"36`C3 fB3 uʋQr履e5rƓ&NؿWϞlwJduڵ{m vTC~0Q )LL!Z*cNI7$PYԓ(3+R7hcI5y}mdb;!"!dp` 7!?(>OD6 nu0íNIZ;G,f$magLit6:$2v |B9kv{Zx5:)/>($))%0q[cn|% ymads9h";'dv꠹"*@Yp\k6U(eB 9nq@[p_Ѯ^r+P \fDF۳(ۯ6{1\Y YS3C%>>]-C}{W1 CHseqr\-qq%\XrI)H[UbH[LH[Lɖ''\zW^We$V#//̙ 8{q*[J[曛7oFs:)m^*7Oyj [J[|9s>jm"bNvqv @-9>WeSQA+g.\2ܷ%'*XZܦn:Ul=v(!aNX@{y[.\]kԔU.Ćݭ]uކuYKB +M5 M2 fRbN )1E)=ׯj%0-J߹߸~Ⱥ3|{v4kΠN~_AuKQM^4FItUY%-;`rbu:SVrZ9#ʼ0hv98}A3WMͨE`Vc+*8f"'3D,P" `tHSڊʎ}Ekڨ„b芃9BHI&}[!-6VwWX.Խ>u*\xDVSUw3NͤҖܴ4d*{f125Қ2(+E"BB 5wBF Nͣx.j5bK=Epڦ}2@hy[aalF\R5)l_[cĘ^O{ cM:9!gڧW2Pfrh-2`cnMp1pԹ+>vXZDh>v.3"GS@o = |H[D%-h@K-Z"mi H[D%-h@K-Z"mi H[D%-h@K-Z"mRiEځ.h-Z"mi H[D%-h@K-Z"mi H[D%-h@K-Z"mВݧ-iGjjvSN yݺuWG 7.x8Y,Zw\<_$ڶo9+ѣvcǎOiK ]\\JtsL[JKK۫u]4u=0 _t)F𢔠I)~~w eVaW>#[2'"D-v-'on꒒'g{fO}[._|'OJ۾"|ۏ?Z}[h˞Ҋ䔭jϵkZ}yd4^'gX$mޢƏ~gYN-ga?b5v.f Q owtY. ={xyi+Kcڌ WԷ@-F &X:t? }[^.bPk׆3j1_}$a$jhciRm+M)ڷ/[-<<}.rn^/Ϻ'Y-:I; 2領tKz\HͦnnݺIl5/ZRR":ov0>pQWhMTRE'G$ڵ{wZڞ]ӒSRle*ڞpr-q}b<.8={kg)=D3+1 QUY5cҵ{'//v)#ٰ#dRi*+oI?Ii1>՘XV7uztՙ\fJ˟I'{4ɿ]u\I r@ uBxFq.’t-)+KcGuvK^׏>n\ oj 8!{ŋBYȸz0NFݭ(ߗu,-7Q .p:Q|*2Uo!s+Uq?z_7Y[t*/|U~o?}?YZyuI(RK"8(Zb8|y0|䳤>"+KU'ZGYTִҮj6hy^E V7[*ܭtzͶ[kf"y:zT?KmgfС!oˬfZ4v#Ym:z$̕~ BDdjߘZW|h>犯o,uz]*a2_[_/z,k_>t]O͞s""^{C{$5t&@;4mA3iB"?L>my޹Q_h̩MfOM[s #izFM:}Z o,pڧ-D"7E-zw}'pV x ;H"7|Zd/pe[)i I[.+g<ϻpB׮]~ XmNQW_{]$_֓_C#mAjSwpc +,,s84!SCwKb>L=?j[o899 ph-h[ލ_ӭ[70AFe_KJJ7{ zMȹzGdXjq|ZgI=ٷoqwGS۵{wZڞ]ӒSRl6K77!mA[_N{/ 8?uEI-H"E{'/`nW m6jѷmZV־ƍ22((tS~s΢mo mhH[hY@;-Z"mi H[D%-h@K-Z"mi H[D%-h@KNE@#mi H[D%-h@K-Z"mi H[D%-h@K-Z"mi H[D%-h@K-Z"mi H[ԡ scޱB[Ft^}lh3̦PS9w'8ҘV(SZΩ_q NՅXӖ擛h#cLmBNOϭWPbTTPoن4P6qI!9QMt")>{,sQBx5K؊BS,咧 @m̱D Ǘr\;0jQU\ݽ|bMaમַUa4c:'l]Na]!U{%]XJn/Y뢂+TqƦcNq~՗rR*cх> \>rL ҕ_UzzHi]t@pԺr"ӚNDwۅx"zN؋i;8Y,KHʂ*8Ua.`YA=gr^򘞜."izص0oQ״O+f^qfbvMP뻘K3sS~9몼ѫ]zLsxVhx }ÍFJRBƭNM$ z(Cc:ƈ۬\;M.rJUu{7Nrp򦂭3)B/U>{5jqBKE%Ex QW$<\K.O%%[x+Զʛ䚛N)-KZ*`u4o4iܡ+xD)ǧM^RBČJw~fo*!벒*7ECdۨUͦH͕Q!:e.$l7"S"i]d I;J*/l Y_$49)E B5 /vNYQk\wplCk6o4'mYetI(YI OuchulqMo[g%/1izө;SysqүfFaQrDlP>2 i=Ҍ1կ;2a~j}1y86edh]Nngrd6 s27'K;Ԡm]]ҨkM3)aZR&`[{1z8J.U\RPTQ^^My{ qH\6NhFvҷ0J-?hG-%i0!dNk)>{تwuW;Ҳ~f}:77yj/i;A>0Ѫr(#h\'DJ]\m ]pOAlLbk "\5$ldWhkMFSTH[tz2;!clRai999"otaF9L)dmh1%FR.VA$˔^ܬPSFeڒRr̅W)ϔ`oeI=&%hw|4/㖮"1{Ђ{1z8&'RδH]Q/ͱzm.`YfDC}&/rK)a^+-QkO) |^E՞T2PkǝBS5cGYƍxW19Fi;5'UoGRBY2`Gļ-rm;j[7])T5jyĢ>jG9.CN*YjuL;;նMw1`lh^4+'"fi H[D%-h@K-Z"mi H[D%-h@K-Z3mxHCM%-h@K-Z"mi H[D%-h@K-Z"mCIDATi H[D%-}r'cH޹;mZ۞Ҙ4ּqG>owK^%;N[223KJZ?|ЪΜ9sl{;m3*--Iڶ]Z$'sRhmg lĽѣ'R뎋D[ ?].'O63˶ mRnnfiK뿖Kpc۩S'-)*:99>}r^=-$[򻠻3'j 7SqԴ}vҖj3tȈJJB0過;J?!}5:%Q#뮓Rѓ'O1h 8<;%ĉy]t*p vgRyaAԋ hԷEٻmiKcԢwڏ$ Qp{bl_D%]5]fH"GH"F;y'O yǓ=- 6ES;!E-vIE`@{`Oim#D%#sLSiMqދՍΆi˃Hi*6xFL,~J6WWW*LKyKo̯t*=Yo}-ψa[%fU@P'%g%뤅OioyߠJJRaQ D딀F>Izv0)}A>bu{Afmz!y˖E[E*a$oSN0oXZGGjL[gTuB7KnD\˫ \7Jo˅s57պ~kP"M,4E} 4-"E!yM/Cnbȏ ϋ3t*3.Oߧ]opn +W޹sgu3ged|[Q}<{R!pX,xH4IWo 4d"V8úIJ!E?&:Ͷ RdQ]bEo(tgVk)W%z5&?駟ߗ!MnnFN5,miH[|ۏ?+-hȴij:.NH[\gZdff:uf;wI4DKذQ-Bf\;:w\\\,ffNٳZ'vN@&>SM}mF#Ժ'}[^wJpw;fg hO[_]\pwwӼ-ڦ}jyhH[ک ) hH[\W_{]-A mp Ǯ|C>hfX,m2 mK^Y[o_rEK#nM]={ ЫvIw./mL^u&>ܳ ??;wڒ"ն7$ vK77Z >dӎyN4uu}m@spؑD;sVđG2E/nJ0m)--Ko2m>=:d`Җ'dd|>uww3=a~ 'I<{f%=- 6ESjm`X>뽵:Nh=RԲkwԓh)mQy|QrJZωx1e9H˗/mj,'mINzIpuuڵ:t-qҖ[bqOI[b8NRPP#qҖgΨ0J'mh H[4/޽j!pX,xH1y'Ԣg-l]ŅsK77Z Ѣswg?!cB_۽.ti:.*7=[gTy =-f 31^n=p;;e1.)jY0ls??OXztJL@CnrB<a\{}+=?~X<ʓgHQާv}g}>6@=XV:ϰ8ҖH1~ &')_/>])0lcV:y ع;Mzئ^fOk%lبO-F2Cbπ'E漧o5Pg{W=0]?qb4 зK otϦ>D k<y0k зa;WHFvI+&z~ܵE]D=XQ԰9o0a> p -WQgӻO5/skbr{?XY9j؁2Cuʘ#eOu{;W^s^sV;X^y]` mӏǎ&~_rۺZ۞ܝ ZGc5cn/ߐƍ:5:d=8ҖZfY 4~ѢB;ȴs_TqRg[Lp{9u 얓buEyXD۵¹B$/_iNF _nݻuvuhf~Qѹc26(K77ZoKLmQˀo{;w&di9/E-R/xp{*!ThoK^uZïoˉ'?Zj-{`য়^/]*jwwO@3o A)dQIO޽o!j]XXvȞmQvIع+m7RqK^>,D́y[rhQ/..{+'¢"w 4敥1נh-]v}:Gɓ' ٻ7h)mIذQ-B"ܤEI[.?)jM=E|M?T߿1[k,ZSޮ]EiIhY/͚h@qF|jڒ-o>:ȫer-{8iw/}D~5:QLz~HX@I[3fT>saOX,'mرחuΝ_ N|'yJw/R?^Md~^j[IDATK&+/<&ƗoV~Om-AAiZc4 vppyq!m{i&y'vNy:{ETO6[GRǙ%Ww!KΡC# Ǐww`^?B?b=?qb4f.wSZK]!hAZHq }Hn<ǿKd!/;Rk4h"B*DS7۞"]':DSmW4E}߬K.~񲘥7phAyq!#I; yX4˻)u{!BRѠ%cJ"0b<gl#*|72tRbo;9..(BRA@~~9S(i$>:9dqƉRtkZzeR,^ӡ,C~M:aWy]m*u6|(yR鄩,QFo\&?]zyϝIrx%zTf]%UL3_EUO,}&2WS*=NgT(h9̕+WVp}}P$ҥ3¤6]_2CH 2RC³I7#MK &U”j[~-0 `߸!a;wnrC? ,L Qf6b{Yu"ݍOTH, 22b o@ 6F)8IHRya8JtR{X^bM][,(*>ھnk\̕#ϒ//ju5&`{![%OSeZ$ObF Ғm_AϓOleϞ=ŋsL]-ʒR,K;./mL†jтl#-ͱ^<-"1tF`_׬YF4HY/͚h@%#ߍZlIT/Z֥Sߖ'ԇКP›w6GyDB{܆k*Yu*O˪)yGBmgށJh^^gϟ˯fNоy9ڶC~dV8=ih8Mi15|o71wKڼbHДo-m¤)@[qZ/=Yo<}TH+u5w]#"z=Vx jq 24Zǎբi,?>,Ъ.Z%yw #dص;M*r0bDU]8C%%{hDI@onw={ZIQѹo3G!KzKNSߖM&(01[5\|9Ϥ˫C`Io=-z֭[1[ww_?엳gէcT:ږG|M/*7xFf֏ǎٶL?^GiiZ8/NiK?,bԺה?؞JaǛ>T4qމe¸+E={-uڗמo78ݵkW{/;[-t:{O8!r@{`OiK†jp3Nkӻ-:e.(:w:99Uy*9i[&wmRQQ %Ll E- zS]7./m̫Ǫş'Rh+ba۾flizіt&@k&tLcWs}FH[4Yva3q B&= BtH/F%h/HOFmPM߹kזm_C|ɦO:%h? 6mfޙ"=*4I,z/vTiKiii_^z{ŭ\oa?أC -m)..;~BFƷSww<#o@;0@:\<_$ژjdz{6<4uZrJ40 _tjӥSߖB>̉x1eSߖ]|!>'Oj__}աCuo 8$lUWW]KZ-Ińn6?!OٻU%aF}xJͽYYYj1|p-|#u܄A Jْ$e4!O\'mSڢx] ba8HgΨoSI[n馟~Y*92x`[mZ-B O ,s7E8N٤-8N2"aی-qҖƌ-rb-qҖ;x}Z9ΚDAAiΛo#_mx]+~,d+Y^qgsi*9$.modIJ*;<#"u~|aG^Hڵ8(5:'|0F_N@;0@{2)꣞61K_+94~hؕo#\“O%K8s)-]mCn3僂YB,̊-/E-R.#J,VBIiֺlǢ =ݚ6Vm{/TnINB#5Urji4n S*aM[ʄgD_x$wzI6Wtht]fE $vwhnݺҫW#Δqmҥ˧|,f7 JM3t2,^X|С[DhD/,.))0mQ==gv΁\{w`@+$De^2Hk n_#2Aɣ=yn1cZڕ+WVp}}P#ߠvaҹIDATCIޑ:nDh+rIs2Pv*&ΞL:/>_%w)?*T0 zUy:L}%I1 !GnnfO}[Y6^WÆẄ́Dni{7zi &?=l:qaTȤ@/yeo}!/E5u5?Btɳwoh)mIذQ-B"oܵkKrT۶ǯY]ό-RԲkwTI[<(iGjjvSN >ߏ6@9I޽3gE9zTh!X_n6Ӗ迼*:y'mx S~2dhiKqq22U}鞰_~ ̡%0 _tt?JNIQ9oM&j-q\|oK^Vk__e18iKr֓'OJ?׮{8iK-j1a[o'ڥsؑ?/?nzѭ[[z߿~qy{ ƳwZhZ&"P>ܳ ~T,Y٢fޙ"=j22(HJ^_ǎӜ؏.h͞H!uoAAZ>L3*G-hIW\YƛRo_oԷ~]Ņs=)..;~mkww<3d~VggZM),,:pG>Kl[ cǎ}wr${@́žI_CSnZֽnyx7K]\\>OIK#mH[|9j='"bY+,Z?p`~ǧ|'I<{9h$lبO-/_s۾uߟOZyb]ӄJ8QA9͹C@UZ\]]v-QK1L֫]܎%mޢƏ~mI-23N:% ر,>|h$+Q/.jx;︣stffNSر1|@СC.(I{UZZzر@a$K3nRݿ;x0G-z1ݒ.PÚYhh[zRNr7Eؗ:@[~j'mn_i]w %itϻp3Lz~HX6}`j=Ng^}uyR!y[>43`N3gDʖ$'''~VXX$ 1>;}RAw-ڱ>vÞluݶuq:u/󞟿knoᨡ]ԄbL~&pġV̟;F߰~)7{VS>97@v$uI?/GdN̳o5ݺu 4j_DJ[$1K_._9thaCSŮ|#ma[]w"vá#)u,K?e9&89r-qjϣ^_?'O:%bԺ"a.^8ǿjGHmLO>yyyI-Hi*9$"hT*osK$Y}hd+Y]\fEX• ^Kg=b\Î4Gϣ8myD8BD[-NOZh=TJu͚Ek֭-z_?bqrT^'2]n[K77Z- 6uO>^nhieƜt)IDH, KOapehK)zP"&}z\icСCDkZLiag(0 OD6޴Ay"С[DhD/,n()jٵ;Mz 8<{J[[5ѐOϙs7W(p-<#ʻ/q.KIxwݴЩ,zby͕^wF wɷ%BYpOa^uww3C ~ @QR;:9dqAA=*^Yl)xGϒ6'[:vw'LOaaс>b@=8w@m\TfX>d|? ;')K]Ph g r.5c9yamGX'}tsYLe|ļ{Le rD-3]tlH/1[b?hPoDib:OO||ㆄ+^ܹPt<9sSmWNU@$Z9r|Gs""żҡC5琠:.]6*5Yww^NFe,B3gSIK_2ѿ|ckH.3NF,-?ܽ%_T"dw},KYr߈+irk'%%%Oۄa@e26 d-[Z4-jQl mp-Ǯ|C>hfX,m2ZyW 퀓zTE˷ Ǔ{65/yeo}驻۷{aD] К=m!dZW~~7{wڵ%9Em׬f|$ǟlڑ?/?ԩS>xU2M[ٻw欈#G #d^ b@5F奷W뚒>=:d?Btɳwoh)mIذQ-BRW'dd|>uww3=a~ 8)jٵ;M*-{J[by| [t:R:%Ϸ&8\|oK^Vk__e18iKr֓'OJ?׮{8iK-j1a[o'Z-YYYj1|p-|#u܄A Jْ$К-j1b0J'm9}Z;BA qҖo駟#G K&Gld+Y+24V7s~fbYyr:O?Tٰ#myuf':A9ዅګW\ڊ'vN=hotϦ>i[sH臦N]Fڞ=aaR[GAfwyIz}X]; "q%wSZbDəقYB,̊b)jrUbTu۱5ݺe/է[PzHMh^w6%&Ƌj{L9ei4n S*9Y[ʄgD_x$'u>\FruU"w1^4c]N4FztO>~Ug~E%Λ(e%!QKidX!K&sȣ.IKMΆ}Es)q/?D7R0)ҩ3 Mi8V9{se݁O;G*z(l#,:)yqW>:4R9$ڬn_c G{ y xub GAҥ3¤@|#u܄ l,I E|cq}XDxD !dEWL7qTeByҮJaDj{a^/ujy5׭Ƞ-Io4,wu^X₨@}[*qy͐q6%qNe ]/2箴xy:oUȓ*._ڔmx24XDՎ*ΆI~ CAJ1h639r%'$)}ɨK8}գ+M˯К/ŵ:[B^CjNdd9Dƚ[j:@;PE*L}h`ox {J[am#Dڂ؞_rF J-Z]-t,؃6\.|Ӎ=Fv֭Qndh^h-|tzƷ mޅ N?R/gwvҖK.}9tѣ\\\F]8W(k7=C-yرv{Fr_mڶg 32za{J[$>CŁ9;w m/gn_UN'}ggjkwO/\(1;wN}:zN6ҿ>m!ߍo~#I[=29_?/&u&@ktήN Mڼ%/Em ~(SMRm=Ȼ#u:n:]B5 hsrs뺒B0AYШEky[\ՑA:zՅ&ȣm~jԡJKM^a4Ǘ2KZD!sUZ~-\2–)N ZkȔ9Y}*,M,G2_*ua^UFEz 9Y,C}&/ 05Tkڧ%Wm6jm)[E8؏NZ;&&S7e%XBj<(R?n!Q+"]EVU15ْpըo-6mਹ娥ACƊkS|*sC=7xHW6Tqh-hl'[})O5rO"0 ٻw|!~v\uB.ֹ{`P>`~u)C1JjIq%POQޜ>J#dgZy:fٷ/=1[mw ʏ2diڽO/ZX{Lxt#V{EmG;iK-cp{\4R(Sޑ䇽>"ݷJ-_yvC6wlQ{Ǽ+@$X& `g>aMXƬ-L||{M[Q!'!_ KVZl|<9AZzǨ a䋷1Gҩ0E }._s p AńJe?}D(dt5?ݟ1XlȂ;/<2G3 HT|D?7|J3f0n__7ۤums9;'R뎋狄-cvQHvhާ[t}fllXK77`i׃g{R }rdzZ۞]\|Zn~dfϕڝ37˷g1Yz#a#O3s"xS-RcmV%iOzKʿ$0O|m{Ffp8_qck\@Mv9(ߟ{ԩmڳNճC$/]*Q7EH"aitվRֽCNC(|99eO2os#m1&999N:9;;KQu]'Eǎrɓ pQ1qq$h@=H[h-ԣ=zW۶uFFF㹹DžۧaԨцQ3Է%aFWW>{o~x'O3_~h5t±зzh߷1j₨_O?>rtwҖ?Ϗ+ZWM*Ozŗu:H-i߷kwwp{jlsxw#9N=oVΚsҏ8߮}`>'"տ4d~[m^bޖ7~xxzl,;m}S{ ovS8=cԂ'gT#G>zP?'se/E]c6\vh)ݯ.b箝էK^Y*s/l~{!ZMnV6dTxcF&"c}k4CS\?Dsfxgɽ⇬59]hCB!CD ˆ>B jČnݺ5W_UO[$^xK+/0!=ݒJp_R#o)ptx qۯ2hmw?}hCYYw&Yrl}=9oT)z/mxkÈ1#|G|]F[};IH?`\цQڧ-/,juܹsRqFM"YtKcԧi?//ō7 P?'R뎋D;qT<-z?_œCD;=-G>,I*nK7DP'{w[Xq$7&cdќ~h*ߤjZ"EB7xÞmAi{s΋k0.8XzsZVχ~8o]aOi _1|co&쇝I4@Hүswz=͒[ә_~RvQ{2{ta\ag}[ٜRPS[n8@ &t:aΞ-<} lfgi=R"'NTWה?؞xǛ>Tmw#gt5'IDAT=I8}ٗ/ `o _?qw駟 VKaD}L6ڵknz7= ,h̒ @=I%-h@K-Z"mi H[D%-h@K-Z"mi H[D%'"h@K-Z"mi H[D%-h@K-Z"mi H[D%-h@K-Z"mi H[D%-h@Ksr҅fk;99cs@S_bJx@֥ &HSr@HK95c-1(+۩w)k][jm\U}sBSbsťP끺ش\M 3xW;h2cb^ezqN荹5Iaֺ prG%{s\"eN UVvx cW Mɡ m\m9`X7ھr^͍ѻv4|\Whm Ӣ{퇊*=;Үu\)];c %.<.$,Z\?ǚW. nt6'*"IZi[[Oe!m9zC M$?b@ Fvrph"[БkXGi1?z玐wY`4ܹ5MMTUr SB}Z\SUiUb}\q5UH1%s~_akfW:*{ yzڞ=irꂭ3ͳ @C$;?3w]8WODbNT7.z/4ŁF:h6Et;j\)[SvD?O2uS)&znwش+O=+RBظrwK ռ!)M8E.=PXU{\s1c{Ͷ!ԶҥF5NJL@ K[\ZSu{plhuLBt)GPҁ-iJ01"66Ľځޑ)1f&0'?U/-_yBSrXR>6iqkpqRmEQʫ11׀ϱkok4jڢ-!u!j␖UD"QlrL0Zv !ʘSh{HHm.!8D5$F:,r:2[9f+%G;p֣rrhxj D]\X Z4<OD#"IY1Qj2"6֎-9֠ !+D^%[&sȔV[PŬWgM3&ˤN{2T-6d}ĢDccS1:hcP;Z%@԰DǗV rb"V+cFDG(O#jStq{*">wwqU^#p&#"Cruo[4hluЈEh Ug[5tM} G(P.$y Zt>b]XS! 1ŁyǚjK9)Q/u=! m| j.+RanVblAEE|]Aa9 Kuҕ+K!IWnq:^Om$]1ҠNm8؈?0zm.sL >5q=%̜,K{SBƭ{ص0`sbufDU]fǜ3Z879-6Yvs~ڍZ{|գ´e{jUJ%U5:ކjyuJ]Uc>G"rۋ>A}[.ݖv86JDDsSV>NJsjZ$^igwtбvR)pǤRrʕy6u6U:Dy 5uMkD-BsbmTU&mWjM}&KB@ՠ-WcR]J u^w&| gQcli5.n$TWuے$Nz~N*,ѮEl:OԺy9h7sݡo %C-h@K-Z"mi H[D%-h \u(TSЁBR捅yvkxYifzPiE Z33 0k= |w`H-D`H-D`H-D`H-D`H-TmuoVꈺ-D`H-D`H-D`H-D`H-D`H-D`H-D`H-D`H-D`Hf;~ ʕ߯\RÖ~>}}}SRSR٘٘٘٘٘tzwRPP9+|{wI,K3aΤo\`V?.3g6nIJ2 *FS/_ 7/c:qm`6l|T~{Facc[s uf~i˵kZh!svٯw~{9eC<&Li ԃ$ךOO }]{Pf9|D,-YfnȠ]]r"Sr*73RyN-4tT|r^~?sϺ,=ukժ`6oٕwYX;Խ{7} S{8ZhdݥV 3巢"Х˽@MK &=a i43Z{]:{]==K_?~D`1̩%ŋaڶi#ԗ9s}l Q P%OߣFII#jKbNu[tiK^:h谌}ʬCۗ_z[7WWW]`JKKeee/_B禬wNNuh4UEab,T 3gLN{=m۔Y?_FV ':tT*ʾu[#3@C| }25,lNNNLn_ ֢n=N>-=={ݷ͚U+++ 藝-]];ؗѼysdu`N=Jmەe˖YC@YIo߀'N~cǐP;收8; 5^) :sg[n~>z477/w&VO__,7ήm۶n]ܺviпqnn qBC3@C߿_)ݻ-]/3}_TP\|YM#WJӅ_=~o8WO}zVҖ?6H[kQXXUfRņ^xߊL#'fʼnp*IDAT١ջK>hԚ9 !ZqP W.UwcQyrCONӾ};K˗=}jf8;ջۯ?]͛7^rSݖ ¸1t 4mMG-n`+ hI`_?߄_>07/<&e˖J?@Sڒ/4ǎ>sF*T=pmxаvٛ&H `@'9uRѝa_pqq)#"mԘǃ}}}` ~\FG@nI-Ssڵ񻒒swv p@cǜw߷au h0]{B'I~}+,F9gUvͿ{4S\\<{GX9j6^D4a^xPFA09W^4tXF>e/ԭ뽝;X쥻qYVV+.q_ىzyGJZ0 ¸1Fy ߟQ HA[׮4dg~j‹))Bۢ /sJ%GK"|ehj"a6<5,l{V+Zn->n+r-YL`̩n|•-o7kfx}gQRrrvv4G)-i3xg'e`m?}ThٲgkXsԢ>D+@8q;`hI&$nkR6tHήB 4P)?K.î!Â)Ip0+޽{ Cشyˮܼg w߷'GӻW 埏j3R?VLHaaRӻhiiŽ;&֞{W~s5S4@>쩰aԃO"U1|֢Jᵹs꺶fP pAh{CԗtpeFMM =忽FļnMԋi4kܹ֬s%%%>N=(+uMԃAN"U1|vy H[B qǢL~drFbh"?mly}zꠡ22)Z?[7{:wFq2dѼ#\tYJ+ދ|Dݵl;9w?ƢTDBK"*ҥ-jI-VI<}7,vQ"HS@P{z$ii/LxqT*Qw۷WR캦3gLՐ&sF1N"`L"*zrG)@ӹi}mRqѻ^ؗ*[oOO]ӪlaD |]S;#``=H[WXX~R~b*qqvR&&RT7{3i{߻v杖)uI !kg rl$援peee>?TvڵGLANS¶O -ZX~Qfr[_uܻ'ޱCww /\x~Du7ې53R9փpf'(W,TRRb5^)IA7l[.Lt| r߯<|oٙ6@Sn0p&==uw?Y>cioWﳮ_TQTۗY,T&Q/~]ÝCI꽎^`%H[KQc=@B~a IyqR S aZ._[)-(P*d<^T5zA]Viz/}"|jۻ;Gt(tͺUa/==>2zS/OݳX4n?RW7IѪC=J_!J{'jI{˵epqqͽyyJjGWCBܠyh}AB T T*UH ݇<$nEHRAV_)㟀'$H_U>p1g'ݻ;#~1 Q˦;}bFGi潯^^v]斐Ռ7{&iM E8E{_: ?FhR7\R{zղ!SrI B ,y$=onDB ~VLtG{:m֬ٴSr} #WqFOvjK3N78nb{zی7%+^9HuekĖDW.ݼP_ʵʒeJSj/t:oEf׹sg?Je˝ܲ2EhbDhq4=zo0;<Ʀ߫W:,#c2^#tRد&-9rH]Q wy+?^b2赤w^q_ىF_?=ү2*++{/ݻo~W'&q+v9Q3rӑ Gm\xnrGTӱ+zQءC?n~E]]]ݺo&9RK RK.Zҁz[B~ɏV,*LoL\Uyɧ+ԉ [!QFy X?_ߌ{f ~H4l=lp2}}|ܲOOY3+S;#P(j+ X3Ӽ)8;zoMU_U QXXU6;%e>?xG@}w.bH+n~TK>_0Ȼ23R8vպ%Ժk4ӖWΩZf70`ڒ}[X>X. KJa[z;Qf$Ԡ6xo&Lg͚5+++;w\IIm&H=$J_zy[2`(%E)3|Zyk-eE66˹sRѣmfooM+>ZK.hR̞6yR͛8qR)888ѲeK;>?3''ϼf&uFꡖ',СC&4`FBvњM:%ЏO4?X[>Kdj?/YL׬H=I0/@aR76W. ܊g YY<}'N/MԽzyԃɞDn Y^~2 'bowGj%fz”Xgnp|sѐxScNiKG0p݅/Oh4=R٭k"?s3`|收8;)Լy-UIwϚ=D3Ϛ~bJ>`'hI$NUEEۗ)޴4j2}}|鱤ओիD#\Us71wJsp@#C '=ikk+Lصk2KMݓm~!LY!9%ʓّo}vFY MB[ cWR0aUA糵66OYơD-sjIa2 &,$Ţow/;9k%nz'b>sSNL$9malZxxxT6].,ʻU?#YfӦN8iwr0*ʿoqcnj3N CٝD%ή!mO0^7sta8|%G~ia匜0A-d.Nbo:kUXX~ [д̩\& ϏhU*++{EEFv5{N$f'VD 죨onQ={zn UTA-yawnM-#|BcK%&*.!~fe^ڝw.7-mi9 %"`m ٰQD)w|dا"_^BvȹIzFVuRq>p*16%sK`y0Mz<ϥuע9kv]"64ha -PI7iB8Rz{ƌ{}#X7|e =~c'$3ϥ'FHIRR}5m.UBbNi^GXDm8[,RSK"P oߏ>~%~Uԛ3IBHY{`U"|F-P֕m bԺqY'T*Sg'eLUfͦMsޏ'%&L]\.&aujC?XɓZZh 'z[KE>2rnmDiNb5I9p][w*jj)ɨbUfx orԥAW.->n "m`r] :d ) Oҭ H,u',fF0n˽rH5!m P,9-P L9-P L- @xk-չs^;G@퐶9-7B-Su4IOg?VJсYu%ɪWbad3 H[Ǝ6@gVi hf2CZƬ_/;*%i&@_FXg_TtQn- )iY >kvrJ`hI>Vճh>- \}mI>a!]MԥAb{ҦLsIZ,R)PKA I4>^rGF}*{ܒ@ML5Ҵ:P$Dy$:.(_^"ju[EmԳ2 MR!WR0bQ`:n2ZX*jʈ̕bJb:LS̋[=/.DۋK  ֶS-#*%1 #h<_n޴⣕ᄏ¯ )M ֕mׅB8zUn+322DuQĞϑx9:Ι=+l$SK"g'eLشSr}a[9KɋOa:?`OZ(hI'N/M5lVUsn)$7,V󛻣H<)zKdTZ!׃qbKfxФSܢWymC/JRy?rJITm-[VDz̕; -U/-PWm`#@WEw#-.shP b舂&AC?61t XyV/MT&$7,!qht收dZFE%z9clha8; t@[U$Ri -Y m ٰQ)cr_;GX|SSђH[4VmrHH[ ɜP PW收0B-`ⲳ=<<[I[]ݪFK"Ucb%d3 H[Ǝ6@gVi hf2CZƬ_/;*%i&@_FXg_TtQn- )iY >kvrJ`hI>Vճg] oX,l'EhBDt*-mC_lRSA =xwT7Oou;V9,LDE{NR7-mi9 %"`m ٰQD)w|dا"_^}]BEjMzfXXZi T/U,wY(C]{.&/\,JHDDi YlZt>)VeJ32j󶗽9j̸GG->>u#m W&?+oIIDAT>Xl|Bkn̜B!:k%. P] \0sĔb%vњ,ljs7'lۦ4pWudY2 3eQ$${{/7ozg;CԍDy)h~yHFiSi&u{'O-ha Uz Q*l++!oFh%n޸AfNi2 &l)9~Ⱦ~~sK V.DHKPm*hH,uKϭ]my W)X^uKpms}S?XɓВ@c8a\*~.W}"Pm s7TWū|hSF6qNM5p[|EhkT%9={ʁKAOxRv_2bD6-!jQ="S70!NH[XkQ^Psy~c3RyyLUaWP_收4plZ#0z9clha8; txXC"mX%"`-d16*qc ]KE i Y^~Mx`I)maZ`)maZ`hI`H-gР]IIœoP=C2F0sJ[0M۵9Q]>c@/a>2Ϙ86[8:t X%Zh+iKV v Kդ-b0"@ӳǏJgVNx)X%2g'Q_O<>\*Ĭ0܂0fzZ"XffK.!CIC>}DiBD;!aOQ/)){SRm/~oCb-dyo}vFOH&+)[*lW_[Y$$ ܕ_&011+ꭴqKϽu# 8TC 8?ԝ 0DcGR&$y;ySL 6uJΡ?x?0Rr!')!+VV "~s#Ym!M:%It Daa{ ?P61T-n M.Q*(y:0ئ J哳+5}K*Jw[QycDk{i [QyΜҖP .'7-{og{ HJ=icGAΐ:W5Wfxi'6m];ud0qngY>jÆ6kfN9XBq :*ϳOkӦ;,J_ kU*s߸˽rm ÃZYE&mgNu[b6lT ].и!O9sTn֭+guX#z7СtrSO[zK&UaT<žz7_ncodu[:=x%jqڵGґ(|74X$QMK2uZ+_nc%!m )9%%5uOrJj¶mRβue-sΞ=+4p>[+VbӖiiŽ;&&qYa' 587>\U@c 7v1XZrACedSfھKݺyu*dYR\收= 4s/LG-~tZbNiS| }S–X$*))ys[Jӳ;Fg9iK¶O -[l͚f͚ %nkR6tHή)SaR7r߯z-9-y5-,,T }zMrZpA)MrS@43 m0f8jyfܪDiG^+Ni7<ҳMZQAŤ;@}0O#7^T8`MQ.]d>%:NMi;i:jw/I[^$'6>&ɖfI^.ثr>g=: hfϢ<#=,&\4e'&#~>%ER?2[8ꁴ:&0?`D)n6%(8@6.nE;[8Tm4%"I̟9;v(JՖa7wSS܄ɔJOZOou^Tmʜ궸8;)`*j..D;WU?GsӏUb 4-X]rciڪ-k=ӊ&Cմi s}͔[;C;sa/uI)c)qQ_#=} j6U@SaR7rkTRRsH~vmզ^ӣ';Wѣ*w$]@j'o]u:n<|Pw7*gNiK ,\!)O9R"N,_zR.4-.l򫢢 ;Fpgjyؿo޽˸͛_0ގDXL-d4#@0]){_njIb|~>J?}P -L 𷵵}G:8 ݃/|觟n=@H[f͚2qgMD:Nܣn~[V7,aWҐaA#akYIDAT^==O ?<OASF]S wҥ6mDz0eQ*qY P3sJ[\jX۾]_Ν 9s&~/ڏ>үͼy}!L~drFbFuk[ٷRҖbQ_W@|R`,%Q해%0\/`2y<ԱTh@,'mvgzڱx|RYP4sJ[b6lT*0~wwp…Oh4)mW*6oeKrݳf袃T*od- ־ɠEHo5(Ս#|[ -J,%$NUEEyo ?!qՁ¤͋Kn~}^EZԶmhBrCD+̑' GwWHq1/̋-[z;QfIhkJJANƏvړ'ORs* I>&011@J -bV4qxA(p6Shu/ ܕ_X]R1R )J^bC mMW!Â\V ϟ_nY٢!*pxӪ>s;\7b:8|ua$EիnxRyGU _M*q/|Dr6-TwR;&eݻww#jRXTK"7xѝw!X5ϥʛ~h:$*G.P Q]:Pȫ<ƞ[VMVQKFx룖A 0gx|Ԑ0v4u9>*o>}҃RlUC?t|)jߪtʃ&I!PEZ:[.x>B@'$N{xR9QJO+ڗ}κ_[ݫ˵W\e]tYO\GBc*)}_=OZG[.XNWh43gٻwOEvB(Msޏ'kJhNUbM:AӽCyӒ-!jM+}#Bilt]"=rCD!Ϟϐ.Ц81Bd.^!Ԣ8&J<:㼰ƿ|S^{b^^G1ڶ0{~:6px.P Uϒ|POX[m4#C:ByyHl0X7 _9խ,P3/.`wر~%%%`5,%6qxi,jհBZ" -58'dApthlDX@0Z+Mys5M8{G-Ϝ[j@MHLFc{n4GԓnzD>rqclب2v(g'Q5!g?MmLDyUຶ0Y9~xVV+.q_ غ-q^CcaMu[ToR־bPimF*qc^*V*6QG e^k}ō*ɯ&Y"Uu?m|M=cDm+ڡ}7 &n]v=30,1彺[CjQiBzw@]ބ$(ZXzE};0J[oYn$'D ރ{`etR*xkp7Y=K@_$"1IGn$;W~>KUrt&(Ҷ*?Ak+*StPyumLmo ԔUˏ|!rg.7*W_ZkX0p899؞0edevk| n%"I̟|W u[y8caprDE;lcF;2ɏLH6iDW@|R2~ځ\];ؗѼy7,68}PGo ! `=~ܷK=H?aTAu§T`5kh߾'Nzǎ! E^r?]SjR{ƪ!w[ރlyw6mrxx-%5󑛨($7Hi4@޽%s~t-LQ>DS3|`R KgNiK̆JaܘQEەoVfgxG& V=z(t收Mήe˫իKe9kɿe`M 0IJ#M>Yَo#n~[ݔmɩ{<zyU_T$`,23/49mN 0Q<ړv+WdxGnMcJ)CRВRTw\0~+R~lmm[n ֵK__^^v?q".~۵kפr֭ @ܰC{o-;~9[>Fi9N [n/w/ol3ظsX8yqd):#m`N2h|];9{UV<;K[Ӗ%"0eQu{ݽ_r¯/^֪TfXs =ҩ4M+~|Qhžz7_ncodطn+uDK"=x%jqڵGґ(|uj 0S-@؛6e괜ÇW#VҖ ¸1t '9%5a6B)gY?:Sڒ/h-sΞ=+4p>[+Vb[MK v14vsf 2zS/OݳG SKYKʊE4U,_I0炨BxnIM׬nVyk6E}uAOx`Qu[>s;w~'$H|ٕsJ$uTDNH3RR, V/M|:ZTü`uDT?3kj B=p1g'ݻ;`},n͛Y; _P lݽ3O'!^IDAT.P].Q4`4͙3gݻju'tڷ/S-iS# @ƆzUu]D xʭBԢ zDdžPy{屮;h=vߣFIIX lIgoo?qxi`rYYW(*XVV^w'}eggW^KE* `Nu[ƎL`$Ǘ 0\yhSjD zn]sʏ?VZj1Unfu[[:"m Q˴ Neee~k27o~f-`I,\4kl'ѶRĉ_!h\nn Tq[ҙӘD16*qc(O_/N*d/ΜҖ|>}z+_ҙS }g(t-@;qRСX:R jui hW. ҧ-^={ #mWaaaJґ]n]X:Ϛ?\\R #m޴)S>̾2e_6^,R)].XsJ[Ǝ%Ӗ'9%5a6B)gY?:S$h-sΞ=+4p>[+Vb[MK v14vsf 6rk&{())Ԃm9R-ի ^խkWqȑǏgee/_bYY{ޝF4Fy ߟQGM OMx149%Ehۛ0_|Rc}mRc{Q ;)'+[ohKE*?Fr/ \n^۪RrHQIIɃz(H{zo@zeee~k27o. JD @S ,$ -av%jiٲgk2p'ѶRĉ_!+aCt*qlڼeWRRVVvn^^a.h=vɩ{n}|rhw7~8{2xT߿_)[@#؛VGk޽gϞ!' 3gKWۗ)Obf#U"m*>{ 0s>@+Vh"EߣFII>}tiKa/SK ¸1ApA)`8W^4t~ty/Rnn] @c:|dzXQTtwNNԝgJ@P=sJ[F Q?]`4R-MC~&"M;_/>WTZl)Z@c| ۶)aa;'@prr.S&OVfǯ_@!mFQRR·gw-Mwyxx(o #@@HضB[5k5#&&]~7ĉ_aR8Ϝ1],w(+aCt*&mJYH[Q߿_)[LFrf%4BЧw/0}Җ_ B/oo0=z(@ miٲ0IKE* `Niѣi3I6$BتC6w3+Y5*>꥝uh5aqŤRZYy@3ChFڂzʥOEiY#B XSthX*>EW.I[ŊQ/7GĢC'cGuU9b)F>3_QphZ-S?wGne&M`>~c/? سtuPf+,קtPjGUz\^"=NWmP|AEWBW#(/_^QB:);#TP_z )mٰQtV[{k?'7>oOmM{qctK|ˮ8@n'VOh4C|qKyßʦ'7t+K[!\qO/miT9ipOF>tni==vʟϕ׺(I]c^\_z# )mW&&ڳ|g"<=jӺZ6ҤmnW-M}eJ=S> {r>svY \-9ˢCSm;N#|Ļ&'֤M(v̟{Dft5VFmY逧=f{(jT_Wz7&.MD+سrMu/?sWq&Ԡ]TnZJ{*=oIxwjţu#iOXiiVɮ;L^+(SbzU+7&.MKT>g~ٵWvp WzlSh ԁ1A XS;|驭iu(*n+u,MnqdyFsjHnc.ni*&;WhIR)9(? K7:.Fڂ[b`KOYiǩRHE*7J#7oysǙ7?ލϻ~h[iEP19g6eayr#]h]o\џl^*+!Α?*U./qqӕI̟JTY,R)Tt˨\*uԐ}ю/O>5+&lf 7 ra_~~3ƿz6ͨu72.@-pX' @֮\rO?ƦlƇߜhY ò*is~#7Nu:9n<5lR+{{\Tn^=?q#kק~vwʊ(6<}1A8?M=W859%GҖ߬xnΉ>СҮ]ml7ȐDgc.6E;]8!;y|#sa r7S$Ϝٶ}ǯ&\B5ާ]D1ЌF^%}D{yh0.F%i nGm/))Yw~Ò=^=o6wgdf S\\gϞ:x\K1qD- xP.NovZ-=lon'̇A.,۾ޑA,}~_wݥV;}] ]\|㚲P=J^D7-.4kmB`N_'r;n|;ܢEwRTtQWcIDAT r˯;Z4o\)mFz9kt=}|𑟥yw41:ݴDWv$`,_ةTG&3?pJ9i}Xp@gW=kQKevAD7-.收 xAA7F7l N5r<Ν 7v(.MK4i jbog7x)C۵k'D زe p哧r`A ~ܻ@p6\@}WymQ_v-[ްE^Xq^+{߷{<ةc뵀&g]hwCFFSN<% Uet~pmd\ML9-16*qc.֥k[3g Xr'}[Ѓkbs)^oE9q4%~.U+?R>\̩%Q^~2 8Սx5+P/?=w٫OF-7^ӻ׋z)..xRAAhp3iIԾ]_Ν ,СCLפ V_%ǃI*<Tfޘ4i$CVyWuJ?t+ovMR_X$Jήewʿ>Y}z~йs;Ѫ?R 3gL%f\ K %Z4ྱ-+e5m=y(T/]R93i0MuaÏQK7,i')yiԠckyr͔:wv6Y1q65\N/zXΘD=BVVv]x(S2 &;v|Wr7Rr鵾8EݕYO12 hS[3+?I[x|RY-c;xbp ToZix⿴06^Ѯ2ELX/zXN2pݥ ?Qrg_TtQ*uڿ.,~uJy֊Yw9 jwwT7lxSUF 4oeKrݳfϽ.f'(W,WTf')GZ(LVUAEIoեw?K Byiy[5MuaIHئ񷽳熉[i%τm%DL= /zXN" SGQQ^W?{ҤZ̾2e_r\n͒/MՄI M_w*hRY>ze(WkӵSOazRK+=nq8dQ{gֹ{{;s.MKqq7v_1;%E/GOzӧsjԄmHa(9k]JrM|# |F(վzFF^_,'1.,;o[nɧP'Q{wwSNwjn~v/%K^kV}c[%"0eQl{֧}noi ...U !='j ()' T.%a8sK w17KQ T]ϟ/cV[*l;$&U \}m_N^HT>Hgݬb(Z}. VNnʱ*NV \au^Bvɓ՝{]II*Mx?u&pWRB`ʟaĆz+-l约Wן孊 0uk7zAP{忻TwRra5oԩStt6wzM-~IZzsh.і~~ťɩ{n}|rXsjIL5ofooM,^twIsdj! w!rjNQ@[׷ jQJCksy6+|y5ǢA4aJd-R3I3 j?KK7sao %}Wsj7 [ރ}u|ۗ!2 H{M^q|µo{޿(MHY[(#*wB:E)TH7 Oms˟jibFvj[ph_@o{u1/.]r}WV]~[xGWFyϬ}ha&ֻlov=n]Q}:r-[%J\Dsn̙3{]:{zERٴSr}D YhS, (@C*3~)]E?Rk%mosҌ a\_vh`z5\5o/_2GߛDwڧ|| ئ46BCf"'<j# sW`U\598Ut -MuwN_ {.&[jR{X6Yjh僊(?گ7eN<;ZpCIbk.ιOTa\ҒZ|]?]i[3%%^/ES%K4vر~%%B̑Y|SO'&0 mg$xG-Ϝ箽%ZPNn+kW5Wyma8oծ޻\!qRAKtH7^VN()+"X)<E\s֦4/*JAcuAWOeѫbtR ҖmYj[m"T\IiW:,#c2^Νmlp>ݴyT8~x2<F%f\hkDo|Ŋʒ޽z}egg'#G?WeeeE{wrӾ+1Ylݖ&Wy Po=ܟ|;wson1ܣ )B@n\5Q/֠UH,}X!swyNCtߚj ֎aMAOJ(?Y* "cp= sU2I]w^#}g[VN)?ʷ8Fy 7cY3ֵkIv‘GD%C9yX);t&K4h.ѵ`6!Ϟ5sOnB,ٛ„$˸ +1Sa2 S%7b/+aʮfM_*/K2+*FU mV<^ SK$v[ՓJ(vgK˻ 㪊Cҕ6-½a+QVkk *UV__ [fP$f[9)?KR Ut欯$Q,ar'~}y?K`Iߤ6p%G.}&[qu7rG 1ռL@BA7 -œgD@@vW,@i.0SD} 0FS¶'lUuCr׳n-'Ogl{]Ӗ={ %z\D[%i[|ܔɓ٭7W45]؞`j `/_&FWMפvbXBK n?VJ4f5IoL404#|8BC؛nFސaTIi8}Tw6kVt_tɩRV|ciLt&rk.z{;R6ı֭[%f\hTI)++ 藝-]];ؗѼysjLvhmhIdISܾxպTFfÚFml5k*G-ӦM _J=ZzCgIDATČZuܫJyuZ eMKtpi.k?2_|ɯw&4Qխ_ԕB]Y]r(յ>Ө.^/o5UqE*P#`A+aCt* y7oߤeYl|vw?I˯:g%i߮]k s%ND׀KIqwsyq5A($Nc_V޲߿_)[ȝw'G~7Q3ޛ1a}ɗg.'vp0:\Kt D>{+Ff]Z"@CyqƽYo^ޮL41G=XBЧw/a8|S?#|7cÊ } Kw`iJ:PzEcWH`?amD&O]]X0Yo5@jL̄U_<{ym6m.]$._\׾f/z[-m'{Jh|*jޫs̞%¯*;C4q6/\ Hi=w0wUPP!f^rQ;=\`h* 66UmK/B-&rzD-E;ˌU Ԭe˖J?&CրUd /\&&~_kp)Q/H۳qC'G4f(U&Q/9+;SvD.f$+1ٓݺ#?>lh嵯͝#MFQRRr 3gϺu":ڃܟgTt>u[ ,M]#LչY)]{\MhВeJrS2v(# 7F#OGvn"?$wվ};+pKzncǕ½;]'\MhP%sjILFѶmݻI_ 6 D_nȞ=}->j +P\MhPZ&~>m۶S褯SQf;vtqw*`.럥Z7uյKt jFڂp ^*h]'-vڍx|)&,Cf͔aJJJn[n Νsvr:.=vaZ/K;.MKYPwI7o.h -}խ}qwUu_q]7K_*]wȠy q_ΝBxxxIߟn/M7uiԓ'Nleu204.\(h 收lبƍܦx@#]No߮g=(`qڷo-YٷL[ܺ^WKTadeؐhmde)3 t{70R?_ӧOo._WջJTD66M}|.`<={xT~[l,& "xRoE2wZjӺ=wե}D-ghӼs6}ū'oJ|Q%"mF'M&w`={.*oeܼ ѪRrdu[:2b 0~wwp…O&Bдʞ}~uڿ@Enh͛7oCrݳf}t QRR2{))+XQTKBh/uR(*߾Lii҅UW#h"m&?NIQBÇ:dH_?OOOO[[[޵k2KMݓm~tz鐶@[z;Q'$H|ٕ$իR9h|>;p@7R=5%4%{{-Ewq4@;G.ywKVazRդ-`MYfӦN8iwrԚJw1cnjJxY&;4)m;z %};qxiSXX~R~bpt收8; =R٭kKGK"Ϛ?\\R #m޴)S>̾2e_-!%INIMضMPY收lبƍmw6oٕwYݠZ收~iiŽ;&&qYa' 5D(F#?n옱cF իا:8}upuuuU42J[4s/LG-~tZi9cXf‚| }SvlO jFf9u[JJJ\RYNڒmӧB˖-?[Y3̅-q[°C:wvMrҖ+޽{ >83qR\oɲH@w`)m;zT k B޽@1٩/\P =h"Ӓ}v;'=!Zk҅IVy X=۷W YXNC)de&cNiK̆T'l}FfNiK^~2Uv mwϏhYNK͛lRNڽ{,gL"IKI叢G) UTuKlw.RpV4q!Bd -_cRU53Ehb;,H'kq,YfΘ^fۗ:dH_?_>>}\8(G֦$sC.IqTR%9:uDxGޜ3Zm0;|7ӏ}R m,nb{֧}noiښ/mbc꤄LRGEdHH3I' BڤFQIQ<p1g'ݻ;`},={{/7ozg;C?TUjAuD?Xj`3CmD^ltUNJv*6&khΜ9gU?Wj+aib)9~Ⱦ~~PY^[X.oFS[!,]׌(:6O }F*{n QCljnFc?7JJJjX`K"={{K+P9~[V \C* )E/sDܱ”/$z0PڍݔH[X2~RյӁ}͛7y3$$Qf~mkk+O8`H[6x@5^,i 2KgN#@lبƍ%ѧ.m),E,9-yp+hP `)mԉ'Bґ@VRPI[rHL>mٳ fΘ.h\1+'KG4g_TtQ*uڿ`H[F>kvrJRprJ%h{ҦLs2}}| '9%5a6B)gY?jkɲH@w`)m;zM_IDATJJ;{nlX sJ[\j޴IaG@i8gɓX`KpeF@S7v1XZrACedSfھKݺyu*E-&?_FV c1%fF0nL~ }S–X9-y5-))ys[Jӳ;Fg9-m?}Thٲgk4kL-q[°C:wvMrҖ+޽{ >83qR\o`),'m),,T }zMrҖ.(|PVE8_;kAh\,Yfzo_Ν wyxx2DtaUJD`Xּ[:{ڷo@D=~Rڥ?3K[rMܹs]70gśc_*o߮f¬صl!E-RǒSR`ξ.RHX3K[ڵkG)NIMaVn͛7 ]=EPi4*W~0U;.sܢExE-`J$vv%G~>o[[:2˴E7=+st'Nleuv4`6fc6fc6fc6fc6fcoG sk)W;;* 9[ \ zSyyiժZT*6fcqSl\RR"\[0Z@=qD`H-D`H-D`H-D`H-D`H-D`H-D`H-D`H-h4BC"m0$C"m0$C"m0$C"m0$C"m0$C"m0$C"m0$C"m0$C"m0$C"m0$C"m0$C"m0$C"m0$CjV횂qjUb n!uNu۫TRUmyƷR͖ʡxhLޮֱȨQ{im تO[1iwBYPyUm,Ok -,tHj1q(뿛ܢNEF&^V-*c4>7nKK񱉋1s"_ȏɅ/6vqdVZ{&=☓I%=x6n)L]?bcZ>eLl-Y֥ @#0^"NeKJK F*aK}DTėoT6j.ҖȵB}[V,Ή\G[3gOG;gq-+Qt21jsmF$1Җ? GX/-^ nbd)m_]ux%n9ev>2eayYAkRc;hiW\U]S,Six"l\y? mᦡoe"&AiKALJ0n[-6l-'.\D?_>e҇3O)T;4QWO(J Na|Ai// qqԛ׹wBWܩ[ǭޗkke9)kgN}uim]&rmGtG"tT5zX_(jal&fH}eQ~w=UF}[iA rJݜ=\_t- }N@Sn FpH[ H[ H[ H[ H[ H[ H[ H[ H[ H[ H[ H[ M[~|QUoVjPH[ H[ H[ H[ H[ H[ H[ H[ H[ H[ H[ H[  ˰cb6L!өf@9KI[ʥOqJ楬wF*yƠBW[D;M)/(W^^+>C옠Rv .2VR?r>R:);#TPq$Mt(yE *ܮ *rW<+Ҕh '_"˴wFN'W6=qì^Y򖗲^QF^$XNa#HG6C>xlOwJu]Q^Ң'uʎ s{e+ 7ꦋQ\SEb̏e-o *\C8ө.J"ɩ.m2mGyiVE2(v*%,GD~7wMIQ?jnO{Pm񔎕fUʽb2\/\aa&ٳ^r+1A XS;|驭iu(*!JݯEӴ[lYќZ9R[E[ںJ6Gҡ0E }-"ʏB=`lasg H8i^ OK#apߥ&X }`Si2I^`M h"ӖXT&%ƎIm/-Z{>:ZS/;~;=ofd Xzm͗ Sَ'|l.ݻ>\vꌡFӝPXT{M{iC-?֛C: ?Z~GˇO_zrɫ晗zKw};;b~㨟| 3#s |oVœHQ3z_x0±]w!gzsxɺNm}7yTiw7+pݛ|žK?{8TA$SL97~WdꯆF~?[owY&%30 /m|zҝivWᄰXٿ?_~{;ko85ƒ'ػ'LJEEE7~cʔ)řeDܷoߏ2'Ozo {1;@pj͞=+v~YԶaH[8f8w7w /y~^QOgٱX,~]j[{/N>yY~{ݏna\|_%%%Ģ#ږ,[oyczx?޽{JKFo}/0^2NY#w5W]]ݽݻw ËSgoX޽7[1o_>̭sfoɿ;o~z'zb溺{l1>Զa+mykG-3g\9sq n~+[|;?sgoD7~?T('‰|~8E-ɼ?>?h[Nt'~z'O?mz/_ʟ.{YNt'xڲɧ_=3___̷]&NO@Ne eO;?wyx'6|)V ?}ʩd[NW*;࿾:6vs_.<4+ G0W>p:Ӗ|Ur֨6}p_y{ek|d i&cO /{QrY.\{'}3ga8m9pB+ږqT]~{L޶Kn?_c7?I4eʔK/dNh'LSO=u3t:}5wϬx۱-/7,\#O[2aZn~ޞKL}O^_||+ w݉q-ͫ?'>=֣&O>9B (=((^_b k[N.w?OΝ;sՃRpPfbr)}?gvJ.*p*)$m J(I[$m J(I[$m J(I[$m J(I[TNQ%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @N 'WWauZ hm҉Yrt:_=7pTW j[tږ^ِX|ue=fo+;رxW# ~'=#JvHc}K}]rॢ寄H=V]rKn;}mÊC$5WC_>>K;|/9dx֞FN.:hՕz6z֒Ͼ_4:Bmˆ_ܹk +L|z ?= ?кak]2#Lx;;_{6ӟMG;Vg"9fg{f^+g[_[^~dyVgg~ћ ;vږg;C]emo(_ޗNjܾ_7WhtcuU~''SZ ݏ^Rgy{gۙ_,vwer崋:uW/>-۷uǫ~/u:[^>KKU_[}Yrz0u>3wGw~.G-~׻>L#Wd?}MFԪ\VzĪ+{Q/e]5X=QwV>j_DiKɂd_oaΚqrĢ ƚcy$CsAӭqu"yss!SIDATs/ν\|ޯ^G垃kCz_2_GG_K:K&;GdKݕ*lFyjF^|dtt6ې{N|ȂK~so,8oÜWڳl sŏ/.eRrA+^}iW0^㇃(μ=JJymW-?pɃ+֭X+=;uغr=ϵN}eyS:Vϫo\}[1X^<\]+v{ڳv컞 ;u嬒=dO~[;{[KN4D-J${\ɮƈ(|c~TV'^^ِX|u5~t=&:;\Kz}#= Z{v>[}|cY\:&8䫗5gW$ J?p@Q: J&Wy}⒏ssu,>?HA訛|ai^ޙ(+Kg~{;Xtf[;w熺Sc8^޹O.\MxnD{Z~z/=F{O>lݿС_? nݖ|^ի>4s|cs/k6.;7Dꭝ;I.^qqy Zqf%vp63+_G_}twG\ESp24(L]tչ$~뭃;.iF?ܡ3u>y׻~ڷaoGg{}=?+e?q%–qֆg\xBp-Gqxo=v|2Q`SWzE-o_!j¤H[zZt/zF( o=8CPCVޝN ?>0XSVTT0u,.隧E%Wn2$8qLUrha_}0&d&ѱƱE-{6%6&¤O[\?3]rV~&@AJ.@-QDI%i @-QDI%i @-QDI%i @-QDI1ӖlW4} j[$m J(I[$m J(I[$m J(I[$m J(I[$m^lO]zyU(ֵ`BI[}e;X|Wyx=՞J\=*+*Lrѧ-w6O`Ӗ]\&/l^_ J&L;*LrfDI%i @-QDIεT%)=MeKb %mK&vԥjr嵭^^lXږahw?qu# DmKD4Ƨ $?ӒmgR!t0td2wnq۳\qmŔ}( Җ]{Yqm--I#'87v9qlGIcsicmrO)il[&ݻw/{ك}m߾}CAֶ +=[V]y5+V>бi޽{äPӖLwe+vGkHוd.M4+lmM洸9dÍI?O|b|()ږg=sg?sO׭_92ʊT*Lz7է:*;w#ӧ?۟:(ږiӦyeg~z(4u)Ow+kٱv|lṳF4O^L~|^<)UrO:[n>rE^ ܦ7ٰ4Lus]˩59g1*!Wr#SN޹%mucDx/ݱ;`(ږBWm DHrU?5-@kCKvLM[AyڪdT3&t({:8]y:ٵrP-QDI%i @-oS(!m JҖc;ؤ-QDI%i @-.= 'ϴ}"ǟ J(dځ?ϑIDAT=gΜp|ڸjn|n8!,hsrsImRa-[-l׮]MA-=D`{MA-wn t:06&_X ӖK/vqeK `,Éw7nl^80&)K +m54mm͟W^i8S{IX7;,T1smIw^zھ}0mWznϻkV|cӦp|5+D ͝Q7/QTՒ*V<3w9ޟMhh2LRsŎƒ\2tKH|XͶZoϼ1ʤdnj'Z/>E-pxYg{3GQYQўJDZ-jnjˤ0Ce&\(q/6 G%Xw7\zyU]O]QCdm˴iӞ~{/;D6o!9w䄦Sr` YeD_(&dmvpmF4O^L~|^<)Ur3n]xa(T3:fe#dg2uu/|}vP\ d]rYձBafg]! dgϝB!wGyV~^RO2C^3v]Emusg=ϴ}"_׶L7%Դ5 V-R?57%ڲPT3+5w.|&90Qst$vme(|ψu+c%'5:XmQ,{2s\%tvݖ 2enW+&LJҖ݃p+:ң_.txPH[$m J(I[hޢvI[$meІumDI%i @-QK/ Z0-QD Ӗ9s5⹫͋09 Ж0)fڲE2vdO&νdڲ}ǎܐNac+h 2mHҗ\wܸHc)Դ%ぇ6|{]a-=[V]y5+V>бiS(K:!4vvGݬ\|RUTYoޞPԝZ=l+ 0z{{|jXH{؊Cz |s=|t#ӨhOMj5|[f'ěOv͎%>Q|u )5m=啉5mowTw?>}k+pm6mO=yeg~zL3j{CICSY>vYZ6bܹaod@(.PQzf7OQU}ŧS/&?>/-|S^}p劋.0L33Kp[7սj_osCA$6mڴ.y=uU}$>69 LХ͛”ҹWI02Kg{g-;i]kU4i*;K++*6k *ږmsz{CfrDoqG/ûTU&fյ \a׶LKb M4 uΪ\[BY[znXQ"[Rn/[3sce,;-n΍ʮњkiSP-QXy=tcͶΚ$i @-QDI%iXQ, J(I[co3i @-QDI%iˠK.jO j3m'm Jtwwϙ3'6N-ڜqtR(@[Tii۵kWFSic?8wFSi;[pC:LV| )ȴ%#K~G`m}.Kp"ݍW%?,ٱDoQXZJ;*&<27 w@_q<;>_^:pYu7jFn᷇)R5a`K^C_۷o_P-J֭yW^u͊tlLD-Kwv;WW7wJF4BiK7ǧ䢓-!YYՒ_#/2٫dI['&eχLX'Z/>E-pxYg{3GQYQўJi0tn]XJʾPQܚl]jyp_CU˒XZ-T4=R]^h {.*Dg鏮! eڴiO?=˗qa|X&kbXᲒ=kG5mζ#O$BIQD-%u%/1e͛pfi1F4O^L~|^<)Ur3n]xa7K:ӝúXQy&bـ6.vtIMcuqmOz*G`溺Sks>;c(UrC内 2Gx.g! !D}]HyK.5dUj l#Ɇ3Cg̖Դk˸Y{DiXeEmي$ܞG#ҒƒЛ8j%) -Jշ`37ߔLtOR4ZN(vmH5Wg Mb~y!qs̮RiF2٥p󖲦=ě4Lq3ZG]v=[F"m J(I[$m9آy%m JҖAֵwL%i @-QDI2,[~;i @-Q*ȴ{Μ97x׍Ċb8';LJlL]v`4<s}`4l߱7Dؘ|a0L[2R/twݖ-/X(jڒp"1|{]a"Tb٣~i}yQUKwPgj٣jOJen]Z2<6eBWQ^1v}gßT\CA-_olZwU׬X@ǦMa-%fu;;ӏЕmu%!W?T1򆚶ƒIꑱIKUe2T7g|hiavm2ěyŸ}򩵟bY#y߾}[q(@Ϯ{~ϟ[>sdT򆾐Z˚Jb Geu_onmhO 1!97"U4u쟦Ҳ+tvʩ31}G|SWTY2mڴz80Jn3VsR-lIuIH74 ڊ)!?ch\k/+'M+>z1ymz~+W\tᅡ@tݗ%K2͚ֆ`%[%2к-ek;:) e1'l\Wr}ͷyg` 9hشinX sH}e-?ٵWqXu{J dÔZ%CeǷG!J՗W&elo3㮀k[&X&i,<(hAhik_(wVuB_c}W.^Yy@R:7 nTQg 0ivm[ֹ(+,U)i̯z2;їZ+\BV@,BIDATmCp%Yjl[U?67Q[T]pvVh_RRn*jձw_LNҖw-=LmG_tCogtD@DI%i @-Q?]9QDIt:=ꅟlWdN9uF;m&_dN 0AԶDI%i @-Q:Ӗ,[~偣`axԶDIL[̙э_ƻn "V @DN hKww 3m"m k׮]MA-=D`{MA-wn t:06&_X ӖK/vqeK `,Éw7nl^8-53%SU׹&ev,ћYoL?>Q{@oIcgےϮ_S5Ɂh9(xcE&]Z4ؽ{һ=1dmpҳuke|ޕW]b6wbI[g3]W9=Mex6MT-͎Nq0%Í̐ts|J.>piOgݬ\o,k(Ov)1*:ҝPl u_2[ Pf}O>_,}$=Z 2myv3;>]~ %Urꌃ-Qkj (U_^T^ꒃP̰52I&shmh~rCpM6i(9o/s,\9M>=LiӦ=ԓ=ȟٽ;^=%u!Rᾚt.NFu(#M*C?ev/ǿ0bdmCg,mH-,&[%Cƚ.i\r o۪]_s>;)Ur3n]xa8jCo1̪}O&R)ŊbCSon6ِ<{]knnX+cD*{R'2푷ToN4]kR!Kꖰ~Xo3L׶磫D!ه[ @(\:7s4ǧ $?Ӓ$;]hQ|&eH6r'fSBKUn;MT hN:Zr9g܌P?5{lqJ=m01)?d4ٱ=#lMJЗ)i(} ՟lWdN9uFqL^go!bCӔs7iN 0A {F%i @-Qz-tuǓ(I[TNG )7|cg` 9L{i&(I[$m JҖ#x=uUTVTlX %m Jtwwϙ3']\&/l^_PtwI0Ӗ-Җ k׮ Ӗ?0q Ӗ;v\t:/X@FSiKF꥗n۲ E]0BM[2N$~}+LٱXQZ:Q; /ft/lק2Q}Х16i޽Ά?80L[?,ٺ2>ʫYM\K*4fOK~aS{_,}$=۷/c+u\=ugL=5 }-5'#rpM>58DAֶL6駞g3N?=L"%u%714T}ŧS/&?>/-|S^}p劋.0LKSB_cp[7սj_osCA$6mڴ.y=uUG=xye2z1ťQ[m׮hTbúLm׾Z3+[93Ɂ)No㤰k[&U!Y[V5:XmQ,{2%D%USDQ,1[f'2?ZkcEC H[?eM{:GgQ)hHQ>((I[$m JҖͱBcDI%i|7v#m J(I[$m9S^^ AeEņumP(I[TiKww9s{UUaEEN hKww 3m"m`v h 2my'h 2mپcu nHӁ1Š`4d^z-[_Pc)Դ%Db/몟|T- -s-gOw GCF<~i}yQUKxwᄈO*.x Ӗ/7znϻkV|cӦ0;u%#5ۚSXR) LwvNj3]ٵo Ɂ0z{{|jXH{޷o_V г랹泟{֯FeEE{* ^WO3KsRYӞΣ-rpM>58DAֶL6駞g3N?=L LcmوtgےD~Pmԩ]{Y-UKäR}ŧS/&?>/-|S^}p劋.0LrҝGULd48!L-`溺Sks>;c(șDæMv#7/.*L9DdP7TVTlX U-'L2rQg P-ꪟ av8+.a};@WfMtIX=-tC_IcGSE Ba$dF?f[gk;#%m J(I[$m9Z_+ÒDI%i|7v#m J(I[N[N9uFxcq-QD Ӗ9st;Én^}g';LJlL]v`4<s}`4l߱7Dؘ|a0L[2R/twݖ-/X('ݸyURU;8q}嵭aJyOS-cYus[2xɽw4vV7n[2S:}k=AKb }օD掵w^zھ}0mWznϻkV|cӦts|J6Lwfx>*[љ+7wn;tnɞgbtgݬM{6x{Ͷ} U-iIݞ벏͎od+S }nlz'Z/>E-pxYg{3GQYQўJ$nT*+Ftմ=__>ց\eVƺC[jy(ʚW&싒=4h_^ThZn``oml&]s[r+J/ɥ6!$)ekl-5Ffg!_xfME3\^?Etz ?ٮ0 Oy! Lw?]!D#aEʴ`m J(I[$mɊI%m J7vHm J(I[tb-\V՞Jށϴ}"Hm @-Q*ȴ{Μ9G3rUssGmѼEv Ж0)fڲE2vdO&νdڲ}ǎܐNac+h 2mHmw[t_` R;@?H|wU/ oKցf5mvN7iznW~⟼v %u鶚l(їyC(TfK;ۖ u/5dN}ϡбiS8Fek;:ӝ\6mot ao]6dӊYuё+κY}q5m+Fd?5mܽwes]} o^5_=?I>}ϖ26G=>,,j+ȴu|btw6'~\Vuʩ32G{*ޱ֛곏ijkL͍%aopREɃzyK-Nv4zCY ʚd2-l/\`͙%i ӖiӦ=ԓ,_v駇dJ<>k ىl{A)sD2WWoHw4U vTNj{[:m-u)OwQ:֎NUӖO#*죊bjix窯t0B]%7㖛o\qхK29E744xi6_&gui:1h!90%%mj( { GfK&e'.e>ܥc n{9վ[<0N[B内 rú7ؙ96k7*+*;1RT/9-ƚU?5V>DJEDhdY6:ʫYMP$tvGݬD9xf2V4%mLUҘ-ar}򩵟bY#YW-Ϯ{~ϟ[>sdTDZ۫kr'0ޒPʒ U-Kjˊ-H/{]O]QCdm˴iӞ~{/;5L'l0tes a{AQց0Q˄өh u܌[n>rE^&x{]ɱbɁYu&Wؒ n{9վ[<0^%7\nX srʩ3exM[zh2wnqh]pfiEζ%etUKk2#cq&m)8ekOKLʟ/m(i*J lciUcn@(."U_^h{>n̑iTVTRt/m=(_zyUPӧOtͷ?uEuQL6駞g3N?=Dm@QԑӈU_ԋɏϋ`4Jn-7W\ / kV]suTe^N79W ".a"\rYU$vtϴ}"Ra-xs(vнXQ"t[M x&m J(I[$my@ J(I[޾ -QDI%i @-Gb{˫B!p/L8i @-Q*ȴ{Μ9a|ͽx0l~aL';LJlL]v`4<s}`4l߱7Dؘ|a0L[2R/twݖ-/X('ݸyUZZk;sJyOS擵̎%z31nUW-s;n*Jww^zھ}0mWznϻkV|cӦ0Qu3UIcgg:{4WjՕdGKR }ؚKd)%'PooO|b|Ϣ8myv3|s=|t#ӨhO„_^ť\;,9d@&LU4mMKw?>}k+pm6mO=yeg~zLbܵiD$ $+cXlj}AW{dYO#V}ŧS/&?>/*|S^}p劋.0L%!:tggcI7Y[+?"rU7sF[7սj_osCrE.7,\9qb{˫~|ڎΐ_vK5W !.nMW(_Sԑ(cje*+*6k *ږBWFL afDS]2Y m5 ~-s;:ƊL1禢`gy[M%;7+J,`(Аm5_Ӗu8P-QDI%i @-Gk cEpX(I[$m9UVpt-QDI%i @-.= 'ϴ}"ǟ J(d=gΜp|ڸjn|n8!,hsrsImRa-[-l׮]MA-=D`{MA-wn t:06&_X ӖK/vqeK `,Éw7nl^80&Uٶ$UO7i k[4.$x{MOebY.+C]CO ݻ޽o߾ k[㕞[++ش)_eM{:ftggh,k(O=^ >:sGX7f!lhi푶ts|J6zTHVVT4uJ2wM4+idNwSk?_ŲG2߳ k[]5s=?]~}4*+*S0nT4$Ru5ْuu}5ٺ4 *7է21<˫BtOo k[MSO޳|&ND_(!3wmGgnOPcXͶm5hu"9J'Ĩөh u܌[n>rE^dmQ,VKVTQcRxw7˾6.6"P Kx[7սj_osCrE.7,\9;veUG; )Nm*lmҕl1Kȯ,fԬl Ln얚0KV pϴ}> 6pmhhMn oKw[zCɍ0ZXz9T-b.0H[^WXv潩5"LBbEgkk~y\^=Ke[rL]\]m9Ï*K,5k޽{|k  e8^ٺ2>ʫYM8*[XKR:;ә9[Bi˴0.\U-iOgݬ\RW2i2֤Ï;grgSk?_ŲG2pbgUAֶ{>n̑iTVTRabl;/T&[Ih%40. %ͥϴm5#O%掵G[sʩ31}G|pm6mO=yeg~z`X(s$Bq;5 Dr TG-{jFT|&90%޸ˊCokg&sSJjNT_ԋɏϋ`4Jn-7W\ / fx&QgݬLR^?\[ӛȥ0ɽUWN?hHKko(ڲ쬢2kSS[7սj_osCrE.7,\9Bl˖cT(ѓ "w>s[M-mRs̠tv%캹3úd]Zkck[KY붔=uUEwd7qW-NgKڲ&*kͺUuG{xoaAjZZ0yQ/g$3m7x׍e_v6=xЬGʫYMd=X7Q4QiI 講”xs3{ԕd56i|FͶ{&P?" IDATooO|b|tRGupg{3GQYQўD } U-KjFRUuCsKN՗W&fu~g{g-;+^suf]続sCk__"doy4cq& WeMǏ&*{fgIk/1tn %r-UɁ{SW4=R[;='z7xM)^4&|"۞Yz5rɧgMJYB̷tySESGz6Ph-QDI%i @-oS(!m JҖc;ؤ-QDI%i @]iˋK/ ذ-Q%i @ 2m3gNx^ʫYMB$udz)Toji;ӒM~Y7+b;;G]IzYӞl|ePkHw6WS}]ek;:KrУz3Wk)%ꐬj=-XB8Ifd?@8Έ'Z/>8DA-Ϯ{w~ç֯O>񻟼䲪SNq˫±kjJKUQ,-//fTΜ;֬Ȥ'eaT tr šu]-qO&smO-ۓ?dQ%-῱Qs[pL쒿k֓N*ihp\?MSO޳|ƺЗ}H<7Y;8'[lSV:3 lu_*;;%3KK{ߩ9(79ҪDo(C2\zJR-lIuɈJ%mu2Pm]7E:W|:bM'rM=?x+.p\4VgKHvggՕ:a@RTVg,ͯᒭF6Ӯh"#2de,V5W7w,HMd2II]&חKsKT)4rBS2uu/|}vPؓAMvaݛoֵci;痭}$>e ِO~pNW|hm*:J]{Y)sQW+ϴ=CY֙[%־f+e'm9TKUee0ȨhzdpGl%KbDJnM¬umCYy`JVY;q J(I[$me_YeC0Li @-Q*ȴ{Μ97x׍Ċba\۷/8餢 9)-݁6EpfڲE2vڕN=Ric?8wpԶ~;v\ +V>jUB꥗n۲ E]0D76J~Y]Sk{*il[RU;8T1-իc3?0%~e?k8ͳ:Մq{w/{-* "8TAֶ +=[V]y5+V>бiSWeM{:fe3tggh,k(OմSrH:$+ZndBLR-j4?lc|>,</Ҵ k[]5s=?]~}4*+*S0QT4$z!T]dP䈏KnnSgc鏮g>(ږiӦ=ԓ,_v駇Ik~K_(.]@(>rRRXzUKw4rTͶ F4O^L~|^<)u[n\OdDٛ-Z%uAHo"V04k/ M&غsprE.7,\9Bl˖)Oײ]Zk8AeM+νB`,i*uT+. -o[W͹Dy[r<;5WƦL͌f7uKdeWiYZi%2ekni4M_4%2-h5m' e ֹpO>$"m J(I[$m9:s&m JEtz ?ٮ0ɜr|7v&گ]viGa2L-QDI=β@RibӡCI:4(L %.-ie$TAK+J&8))@# 4GRF)BlAd}됤oiV{W.Jw=B(:w ]"\_!0 Jj #4г0cSvԁZQwo@{[GcB8@Ҳ466^{mΝqGGZ֖;sז_:p,Y;3%-kK{UZuO֖'/Wq?O_o?i{=唙C;cݵjڹǦ[W-عGݳck f7umYTEW5ϥ]QYuR Y7ߓ{,"Xc }E76>7VҐ)wsCm۶[nocdEя|$5h߰avٗ^ZͥC8o%{G5ssV6pֵEc5랒Ue˷X}[\*[R;Ln퀖ENEV|Φ].ycKI%5y@ y{ ḊԧJ}n 7S2w_|q43[=">Ҳ =V^9 %Yu䏻=[w"\jqYZo7_.[ bإڂkz_/R)?WIG=7oN|{o4L0!}DGu#?Xqw׿.ԯsIDATvE_u#RWN}w-76[ܙ}lCS-an7lVL3}McK* W6s=O3wels6Nin=IV=:e_}J.sWP}kϿ͚3f։agUw[%)!컝¿/LC2Sݘ 723>}0u?z>@ +*~ҼH\W]8-vI"FcΙX4 3˚4_l">n=zmG;ԕxYvAF~EBa^}%Kb5-9)CYx}+W|ITzז(\6Qh~+dUĺWmMAVe}Nis o-yn7ﱈ̺koFwF #!o52~ofjL޽&2z!vfVǯSv{sFFO'@zsݬcKiyxR}V){>'/߽ݐ;ē_y?>&G=1ArXGmHgZj @(-Q:kK~F~8HmC]`3 Jj @(-Q:jSk W @tm~;5@-/I'égzwp^]tu?|]zWz i^lS#<2=ҳ<d[nݱcGj|{@-ڲeK{Ҳ~bX`xɚo. @Ҳ5_;_J ONm~{=唙!J.Ȩcآ- ];{usº jx{ӑEX4K/FnJs\E+s,lB+c9Y?cFٶm-;?9[rnKo^i߰avٗ^Zͥ-<1we잢#$$4;`YhGkqɐ9g-v6sEcE&y=Eq׮K,\tWIbg%^-qQKv6}uw9䞕l]8ʈy?xx43s*圐>ҲYÏ}ޗVʍ|+~o ?0|3T86t6ܲed_p˞x7.[hΦo 㭆]u䏻0Tkrϔ_ywgYy{푆#-kQGV^}_ÿs Y%7ltU>I(+{/#nablon _xdxuaƖT$j9D{N}5ۈz\89(IUrϵffasm~F~~UM;*b+w퓸g=D=5lc?3\vȓʠN]tcVoLCx|EO>*!9, 6f⵷\cgcu+cs^]49qغ%f4\sȪׅ}&<۾sK,n5Yf@7n~퍵Ͽ_bg~=>4qD'綼CnXzsV\[0\uzwUgYΐ5g+}'Bzm90zX{enbB +y]Vg{מxrr:LH.:.119J܅ ПK,Y_s?[pNrcÍʹaʛRv{?Y88?y_}ݰuw[ba aG2j @(-QR[t֖g|6 D(-Q:j˙ p% Jj @(-?yAH W ADIma?cdGZ֖^xᤓN S:^]tuxS:*=Ƅ4 /-[y{#=kjAu?| =Ҳ/wb7X;~--)X,8hzKП-q?񗯻>{(RS[x➻kO9ef8];{oͺ"X۹ǶEk[e̯ܻenÎHu}m۶rmߺ۩g??nSZm+6.:KkgA5XEn殌StdTZ?,x,'(z^r^-:Il+~kifGTj>rn˚U?O?R/W^fmn/mhj%̽aG7_[0iw73xy{?ii @i9娣z+n/0*\ohJLWYwRYw9Mo͵P%vo#Ur槚']Wɍ?5g̚Fx:ϸigVElܡr\Ahw4_}(HUrCr?\Y Ska?+s-Yes_LcE-', {;ӏمVJ-熕7g͵@؝M7ޒ|!CfjK];.  PROܰ,ᆕ?uZ~c~&MnN{JOmgFzI4$sܕ|eA  -QR[DIm2T>l~F~% Jj>9 CDIm% JjK?v[U4gq_8((-Ν;SGT[˿o~ 'tR8>~φ/؞L4)=Ƅq1ǤϿB`[AVH2sf^jjAuOjN9/h˖-w,N >Lln N܏|znn|obቦ'k45ft-GqĒŋR]x= W_J]gUr&͞=o};wjkOsw)  2j;lͺueѵ0hmˢ.*n枳,Dss[_ |'m۶[o֝9_nNs[Ro7o0KJ/Җg 塀+cqڢvU%zOI[w=gwN;PrO:? [6o޼/f4wN'VllnKʚU?O?R/W^ ə/k;.9ceRݷݿx%eW5ܸ,;%_aҩɊ5}`vsØf=yσo. @7%z+n/pmM=iv-z`/ "_xd1??#s>oɨ(6^%i~IjemI?5g̚*znew;ÑH0s 7_nWhGBeAhw4_}(H;zuQpey'DkUz[ЏpK]9验M7}rA"sQ=D[?ޕXzIDAT{ZCWqiV82rP<zsm~FmHe̯MLl(hOߵ^" hDIm% Jj`? CDImRF,wǛol :zb(-QR[DIm% Jj @(-QR[DIm% Jj @(eb@Dm% Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @8 eY}f5tVWU5>g|V^qUC0wV\sŶ+iF1!Z%Yykoّڲc5_4}Bv[/ M]뷶d5bzy]_Wu-;QYB{M.}dK|+]ڶQmM(wJظ$'%g-eYGU:tuW7|좚p 2%~BFSMͦTi*>1Ŏ*:_\2#>%Q6WN/`weW^lisw ,YU:*oOlRMl>UV2kkSמ_YotݖeWK v]G謫y$9ZYYXdo*ZeUk=Ru,,Mil >V-LHMݮ5nkIN֔-`km~܂Ԣ.- 3[-q=UxI/[:6('@Y-I=ޕzHpgm{K$2ЅZR冨uuJNvT-{.wɖG;tW\X^2F#Ҵ%; k Pjn|.ْUQs`ͥE5}m)tMbs[uYA2Ϊ*Ӑjˮ[dKږ%3g׵u&pVW=}xY6TEy싖'fXR[>" ˈbC:b٩[Bz݋WKϞWj&L#r@j LՖՍyyUO>:7wp mm'?xFFF>F1!l^ٲ+eإ_,MU_8Tܖ?O}rޯ~x}cƤY-o_~/)>6-{sqamQ(j52nۖߖ%$Wڃ_{ב%r7nx=t +*58sΙlx<0#?wXtiӧ~05j@KֽIc_} 7??W7%SÈ޽j@ǖ-[RO?y_N΋7{Jn:3'"[:X[zWiمkàN<İ/SCˮO[N]K?6ԫ_6か-ޔR~Vjjsounߵ[ >NO :;;2x'B4 w3?s-m]か3nX<'7Ċ.[>6/#u _^@Gr)[È I},>ȜYBI!%/y tqG=1×Ns[ǧ]w-,]8P'J ov%UԒs 78$Sm9#,^?swT֢yښRo߹4###4{/S%hEH+/}ל^PCE:kv={fg̘1kFښx}kW,?Fʺ-0 Q[x}ՈњU?O?R/?!ݜw^]綼c]_7~߅t&U]劫?F1s[`dҸĽC:]XXVO]2a„0-02][8pm8-QR[DIm% Jj @(-QR[DIm% Jj @(eb@Dm% Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @⌁wi(s{W-Y}N˪l ,cHrk:@gm5 ]0ڒUKٸ$'%g-eYcJ;w; ˺{KAMgե=cΚ]Ol=g2%$zKyep9P%U-@Ԗ%Kf$~{Kb=N a%y[Ăܬ6ܖrwq%+j((dWiI-%WzwYU5rIDAT[8\u[rꯛlDonܐW[ʪpkK_=11pa֖ jSpkK_}֖⌔i7$l?{Kq}gQmչX~~roVYCbAzKKUV?WϪj m,+X,-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @-o5p8-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[e^/yk>2/8_<=77X,7FgW}/F#8 xøq(vknN r}pΝ;o~ځ>^ݽ3fFꩵkمg.ޡP[ Zזw735w(mv'>ϥ^y^sffꍮ7^˛6ljjhZrmヒJ. #S&&Ju[mW\ٛZ IatG\/\Qb;oW}wꩧP7&xpuccj\6le'⊋}?;aU8 Smӟx,YF}55/.j5կqݶ1cßq'S't-+*58sΙl3>9`ݺ^{-t-mmmIc_} 7??WzӸ0?#a>pǏ0.5~nݺҩlٲ%58u15v0~'3f3R-[~C|ߛ9 67Axډa_ =7u^S5K?\9Szn Zx}Wh/0JӝDsLjRK`DڰnCj59t-3g#-B'ݴxZ~~FO/L.g97.3?g0[ r8~!an4SO !-mpV}g̤Iax\zYZoUk֡5t|#<8ĥܖs?鹹A] Kb0G?okj|ͼ/PN#XxQjSQyG6mT:謒 PN%nvaqK_">۷m_奟n̜/|7tZ%[<ܺx?ϜgΛqƌfZ^XԺwm8LD_[^_5Cf/ӏ?xڈQ=yσo. #50Gxe ol ۝߹_o0Z\8禯?0uD'kKܛoYϏ~:~SO>0--?~fj @(-QR[DIm% Jj @(-QR[DIm% JX,s[DIm% Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[DImҘw6eek|VnQe][j*s|^qUCݏhY-;[*zܯTPf]m;{YaL[6<+g/ͼ59~/>!3[S=lՖXluiEΒ~kNoܲʂ=}GGSwkےǿ '7mܢ@Wm\{Κޫt/OJWb{/⪞ޒ~Rsګx=am[\%U_XbG]y^Yy ?yeIu3P⟧pSCcG8'QRneuSw,)O:*oߔ`SenL Woko&Ʋ̌䝬܂ܜ`FX[BȫL`19qWTeUWK k0ll)*Ju%[wZX,ַ!1sS oIL,ikJƖPR\0 EEm;e4grkbkm %{0#-{陯2~#g&l8 &p}qESW8"-=eໄwZ쬰_x&QlkO,9+Pj:~&QϳgexWtVUCc@'45%Eʦa}UuːVW3]M3 kKO<)*JߒU\vZՎovw$㲽|Mya(2nJ}H)u65$VvFgwb]ʼnv{@FZ[ګ+dՕ Y5W'YsiQ #5EI rn.(<9fCuMӞ %azV7ڲ<{2Vږ%3g׵u&ζ3I&uoCծۈk'lkKrOԍ0cIM!}Φ۷$3@F,o{gCYE˷ vԫWgu^}Iޥw+n+{IWKU?ӮIcuAfE/}dGؗxii*眶ܙO9K6o/cb0I4nrYܻ}RK\VYC{y3&9|y=ⶎ%.eƇ9+gb?q[KOjIp 4% Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[DImҀ7gn @(-QR[DIm% Jj @(-QR[DIm% Jj @(}mY67? lkCȔ)S;3N.<㌋X,7FgW}/:{e) QGO p؋|+W wܹ5%IDATƌsͼ/~w::j Q[ޡضmy>zytї_{yN^α!z#ȪN0!Q[ ]mKJ/]ؘzWWPL ͝7\vC[s['?ޟOmmLH+?`oj)WlC>e_,MU_in˟>9WU|<1cҬ폷~S.iKi{#dn hT+V7Iqݶ**_{k:2Dƍ`I`R3ydž{^ tY܌O{隋{<`L>𓅩q_Uҩu/{'dwLuiiY.:)+Zc0dBz26-['~>.NbJv^Suɳ-skK;pmssԉeJnNߍO[]@Rsnջ%gMi\c}S<2DXSaw/]Z<iS!lSE#EZ[?}Œ9&w=dün[[cKݧ,-WiI(4mw=m^d}7~\FCG:cy8wu /,js<[ r6h *STw2>bfS:Vla9 &glynL\3kHcN?X;i׿M|NqB'3 /Z:DŽd:'Ĝ!w݅4rSɓ'=6Ein1R좋s6-.y'9%eJS7,S}'Ы5_\{Jb-)05%u%S}i0#a]waʚ'I4sf?B\ie폆9s2'^,XP/_<'Kce/̘_v-yK?6g=8,eN~Fꔩ 6,;q.xS;nJ-rY{kvYi{>Юۚz)}2bX;|ck!ޫ2;V76O2_5)f^|闼F|V|ca:p:qG=1a/$:Xy D~꒪Tj9s>T[8%=wɢyښK3220g~?/.E/¡o?z9 0*Ӻ-fsz_gΛqƌfCH[swʵHYI5~x~^>oOas~xu0ܖw̝߹_opIr՟ -ҺĽ!jvaaYJ?uɄ 覶@H¨@8(-QR[DIm% Jj @(-QR[DIm% Jj @2bX "DIm% Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[DIm1hƎVWU5⪆~5E-*m܁>Knu[-ƄرeO.okOg}If^y[vO.os Οߓvoں>wjZ@TwbKrrl'ߺw^KMumK '7mܢޢ,۟&uSלߴU4u^]R{C{U^-F4e|VQuuihVU<}b0cɋuyYSU4t$Qg>yeIuOo/;ybBMŹ3skZ~tbŦ+Lp$-{l謫}SbpރM{[yRaZ*$~O8s3뛮X^YjK$\XRXdo*̲%5sKK]]rnFʪ EaS]Up1ڲaއMxKNc >\W(5%cK().EECCGKKrݜ€*(Jޫm2#(uo{s>>3+u|GggHC-{=/>|EbYĺ卉rSM+]oYY MD%uK;C^Y] -Ԕ lhlhJgKSrye{[U^FFF^Eui?$ʫ)UXZZ:BVqYrQwT3N.rayI's˓7n[M3St65$?#4nKf+ٙ!dU\=1jͥE}痴bs[uj]ݢjfEe{ƲǕT1ڲ"P$HAm˒ӳ:Kll+Ϟ>?1dY6Ɠե>uEU'ůXU}^X[GF,wGKUo 4'jzHg}Iޥw+n+kۮo'mչ3 gppNqgwZ:Λ1y\q]:̂mW/⬜ݛ&u]OԛZǀs[-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @( X[|ck0v0|DIm% Jj @(-QR[DIm% Jj @(-QR[DImRז?xxmsϿͯZLrܱΘqrg\w[ӟVC/N9efŎ:zb/۪S\_5ܽCs߾v?3y_7] #u@j LL m۶O>sGg}{ٹah/;FGV|t„ aDZmI^120IG.-ç(4&x7+[vYz􋥩?\jC+t?Oկ~O?u}?o̘4E~O/Ӧe#8" -0 SXݸ&Zƍw7*_{k:2DƍNbWg9Ω>!O/H^0#^ri,L{ҩu,{'d^V\޺4Dg֭sP}@_d]Wؐ>lْ|:vJv^SA1w?yVٲ8$IDATһJ.,\ui'}.ZlݰxNq΂G/"\P6ufEQuɓ?7a"8(in1Rde ^PUdNʬ~R֤^|闼F|V|ca:p긣K;ǧ]w-,]8P'J ov%UԒs 78$Sm9#,^?swT֢yښRo߹4###4{/S%hEH+/}ל^PCE:kv={fg̘1kFښx}kW,?Fʺ-0 ELWxYK/({*yՅ~n;㷿]H79iRu_a3F&kKܛoYϏ~:مe*%&L#޵Gm~Ù% Jj @(-QR[DIm% Jj @(-QR[DImRF, D(-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[4fHGuԖeH-lho(i>&7cHGTe x⪆|O˪lIPA]{^7m*Ugſk][Gcy̢0}זxix[~ˎ-[7<͋Ϝ>gj;BvlYMUr˚򊆮!Y_W޾fWݱ%]9dc[ܾjKg]I4W+{MEqUc{n"%Ɖ?3JTVna_֦*O^nv?K$Kʖiohؔ}ZUe.)ejQ[ʫN4ϟ ɇU6u=S$-^$ڪu]*w7Tddⰿr+{TΖSgvfײ%,sha'.OxLbڐsM3r[ljՙNHCfqM{lۋO+;Al,ny W܊ȦUקpUT|thj2O֖g⿞b%]]d|VVYCKjYf6^=K*Ko:m" 0TCh7O ;.]Ob{~zA߬RPSEe|qm]rzs:ziW{Cy7Ɉbɝ60{[znPg}Iq>P喪o߲{ƞcG_|L'%Yi{Mܙ{ɥ՗įX}ɍcZQ{]qѕkz\7֖dG=8 :%dj3{mݽם7csκ'^ZY=$֕oOnyc+Mw}qgwݽ~kZ}tn 46 Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[DImҀ7gn @(-QR[DIm% Jj @(-QR[DIm% Jj @(}mY67? lkCȔ)S;3N.<㌋X,7FgW}/:{e) QGO p؋|+W wܹƌsͼ/~w::j Q[ޡضmy>zytї_{yN^α!z#ȪN0!Q[ ]mKJ/]ؘzWWPL ͝7\vC[s['?ޟOmmLH+?`oj)WlC>e_,MU_in˟>9WU|<1cҬ폷~S.iKi{#dn hT+V7Iqݶ**_{k:2Dƍ`I`R3ydž՚3.~#cMVԸ*T[ں=ye C8lGrsxu_~u= `Tǖ-[RO?ygL m'fhx5̚2çTh o>Y}˖_`9wa]X9 N 2%7Wk.3S˩K]Q9%tݳk$M\Ά?/O^'q'V'SK~ӛZRd}7~\Fthxom-sKSy))9)+x 6,;>w! +ggK!iņ;^?S*ty{MsH{]}7M;ÿoֿ⃗tŒp%\{c?ۍ<ɹ(;Sɓ'n_:It1Ǥ/CniIDATd]~Ы5w<Fhú’59O:I4sf?B\Fb=2~v[%wVh\~8nxurkvɍGۋr+Ο0\om9S0dbD[È ^I},>ȜYBI!]%]QzK_F#?X񱏝ut܏|znn|z҅u4БX47'wx߮*ZrN8s&O:Ֆ#8bEsO=wG!$HL[֡>ۢyښRo߹4###O:Ֆم_ϧK/K~&f'VM +B>R/W^szAAFtZ좳{n]3̼y3Θ1c֌pikn[]wc]я|$zj C0z-ĺ-3 Jj @(-QR[DIm% Jj @(-QR[DImX,-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[DIm% Jj @(-QR[DImҘ!VWY5>#%3+ ##q{␶܌Vw^1g,ږ'OF,+lձDmy~ȹm]{U^ڒ}#;?;sT{MτA?o^7=Z^q׶ם7y#c)KS[1#Uְ=uW}Ǧ~?MKEALnΒzfףZےxC=iDcu[̈޺4/^r8yF/nLwB^Ʌ҇_K}=Mqucv2Ϲ- @t(-QR[Y̎pcMmMTZ#uЮclnM׉혁>VHY;qu3" RjB5au>r=n $ r~u> &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1߷7@O9*0 &i @L-1I[b$mI &i @L-1I[b$mI &i @LY6nя^W_ݳgO6#Gݱc'LPrf(XXlH$zlؿooڞ?J8Ss9>|x9*souمUm__k,څ&|ᢢK@=aㆍS\=uJZB?my;r3}qk?^ؚ;濾 l}+/yU7f~*X<3g^} B<'MI Wusm[={=)millwNw~D'lIlYV]âd&\xy>Y' {BgFJN#פ uj~#dVe>6ZԲb;3MNPv(׼tu-z ??qn5r#*v\ʖ-.dGĝ7:Sjɱ.ޒX܇s{')Ĝpy?g xnj1I6$O,,LѾlQ"g7Ly dSr9,]Lys[ﯼ?q-Ivͬf dSڒ4uʔ?rݲ~lI8#,w?ϒn(IDATڱQeªڧsf.9Eo֣iaN')f_~_3Ȭf}{a;o"Ӗ?|oӦUvO/}aȓqdwi!mȾ]r2i @L-1I[b$mI &i @L-1I[b$mI D"-1I[b$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[b4DZJszSZך鳪<7Ws[^s{UސyY#z[8mG~Ǿ~Է;{X[90rkZ$ C)00ms+Vio|w&ÍAxu{kk-{祷~CҶ~?]w´%!siA`ΎLYu:p#o)iMw]Si)[H֔?UwG7ʫm\7*j[WK+|Ğ8zk#4Oum[49y_k3(s[B*o[p0 5#+Vs\lu]K89M5?HLꚦcVߞ*-}vnqވV74=|mA[jsrrSFT1lnI_n,.tkC~iEQOQEi~u҅k*+3ɮڣGmz6`c[^y˘2wZ8`-eKTޒg%sF%cfҡ$5Ȩ¼[l_+6'pbӅt>~m*Oh<"-Y_S [(1ku]55aUj Q<(mM$ZkKGI)p ܖʺҊ^Һdl0%BSyosew޺6u5fn~6<#+o>`{4f 4o >(ܛWvUDIs?]N.\擛Z[d0|nisqKxn۲85mߖªf9oɜs1Aqj3㎫BeZee+z4Q7N%7W[ʫoyt|`e[~+ObÈ_nbNe6r9ȟNx7AL[RyKmR ClGl\^ȟw7 ?k^ JfJ][vZNN^Op7NAM[IL2Ȏ<@w%הehﳷjֵ?n״n<9fU9>k+*zz\km&oxn}8~S4%r*>-J__ڎqo(=g4%򚆦5EۛF4urq;֕=]؞ ΍Յ.<1eO4J67Ϩߛ,[;2T\w}mG=Vwn?ۺpbKw6UӓtT]8<SZwWz鹝_`Y>/1'jg`-!5dym0ttʌ(hh=򚥷\S05l隗Lp¹-[H[b$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @LzM[9oY-1I[b$mI &i @L-1I[b$mI &i @L-1e}ڲOlظG?z^}uϞ=9wǎ0aB1tbaaGN"aah{?*~+8s3q?7|07rT,?mL GpXsBNڇ. ܆6nLNr)j i Y*~wf M{[~/5s92w}sAq./d_W^zeWoxjCWxYׅIg٢Ufgo i Y*mIfC֮xJqգ=:p\L*[%?u+\`ɡO{s a!|kck2ymxH_+f?#:]C}2dSoݓ)O|₥ rU{WW^ @$ٔiXk% G aòlbΐrՌ>f~$tp̫/pA5'^N+ 'M̮NLa۶={ lJ[3]vT3m 'exۗ[?++džA> )oݶ-1dS֖)\r%'_2.\Lʕ[+RSeP?(K7} 6誢LgaO~;r:uʔ 7É-,8nӢyҥk,.-4> ,i>)̘qRZVdW$8(XbҰhҌ&LY4gljmsUv:|ב=?8߽g/3' QY|ou3z٣gL^Zl&׭^L'W5X:4n˖ ƥ#$CK :+)X2~ҢG^:.4/7?,ؙ=jjQOdeeXgY]9M$;/Y޹(t=:uoK-{q{φqniL7Jӿ:^<.K-|u^2vҮkɜpGM`)ٽr]2隃3yИZt -M] zl=_:YŞ_~pM_X<ƂCtN`9v %}L gle_SϭDV}vaUopɦD{AǩϻwӢ|4n^גTsԜN(3aQf*ƅ~ʢO{C6$aw˧]kб '5C$7m7),Rw5cř@s~ʙvMW.޲; k w̜%Yv̞9?uU|䱕+m4/g]fYٺy&5\:̞9~Ғ·$훶' x;!'y[9ZYIҏ|ŕWޮ/_0IǿO' o>+zlF i%np7|30P>l&jI1_ Ǔe'@L?r`@~O)]rSYY"ɲ?2ǿ O$g\7?S;o֣'v%/lݺm[c坟x'S**\Imm{_K?mYt-Q hԣ~{IDAT[M7gL&O??G@M2%fV8??ʒSNFݲna pfI$=շ*/ʂ{5U\L[2ۍuoz\X߳5K6pJnKJaeݽ=7啯j(+ӱ1Ee|׭ݢ3Vos[⑶$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[b5mٿoo,vQ?s[b$mI &i @L-1I[b$mI &i @L-1I[bĔio?az={jرK\u?>gD"c}{OUWBp„.4 asouمUm__k,凾aÆ1>aO[L᷿iok_8pڏ|f.G掼o.(.`ajijyhkߗS=0 SK[``,mI e7ih\O)~zGj|qccHc 'm!hX*ZXWR> eWԒk^O?/8Sdܖ7x^Rk%/ eiQ7|nޱ}G<~|/s9m!(Ҋ5 k3Qﭿ7{%yKmsg˺)x;Og Wϼ fIϢMGlZQ?iv0 ')rW]6-;˾&`il--;eĖ-eI=lj@{Kmmm%W^rc E_~/1mڥ_SLٰqc88H~ɸuˊ ,-X2]`9cMf+ g.iN]-K,b3֓ASRo4{BJ_Yfzl-E@%37[v.\)4vNSN>bx,ٴ_V\Cՙ9+>-Xm3 -M]k^zl=u붮˫?vu⢫&qcmO ]ɜu aC[BlV >n3|7sܿ>ls~6SSn)x_/m~g;O!,N[_WxMB6:eJyٍe7p熡Mi G &i @L-1I[b$mI &i @L-1I[b$mISN"Dbn @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1 뽩]~vsmii8KٚDΥ낥;3kʺw+iIZ7+/W5ykK^yC yG抒t2ꚥ@ρ_-`C2d4<7g +HU-Uص`hȢ1S1Ȇ*oLan[N-%sF0YŽt(,)J;0/ %ӆ7knmc-#Jk[pz'm-kO$WW6&jKGR?o'פ wW\ZYS`iߖ7umگ̿yn^if?-%:p褍(hh=gۚ,`𮆶VNaD^qiEuփ#1e:K+{Җy99ysTFV7l;NI[6>B#5uqBшpzeJ ۛMoWp:$\w}mG׎%Wuiʞh˯-tas7p[kwnr=s[g]7**{bkrMcZ!/s[諷⑶$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[b5mٿoo,vIDATQ?s[b$mI &i @L-1I[b$mI &i @L-1I[bĔio?az={jرK\u?>gD"c}{OUWBp„.4 asouمUm__k,凾aÆ1>aO[L᷿iokM?-ܑ7L 0? U-M-;}2W|gօԟZ}iU5cҺt͸WVvF"M+fX+Y(XiNvwSu+;4,4c˲e[&=dA~kr8~Wrrݖ̢klI>-\ ,c ʕn3%4/ؙg?8KdJ~I%xvz+6$8^kIKW㖮R9d11moڏZcޟŽ;.*(N\v(9?scAӶLa̘1͡cZ^E6$:3;;|>]3;}9M[z^j7:18#dJK/-~?0s~ʙvɝiQNjs]3&5/LU &Df|zܰdfΒ}c掚-_vY9Ddž$Z'7' s^7:d_↉7kߗ,? 4x?uy#Gi%xbaaEezˉ›oYuCU&j)}pFȦsY˙_yZ_ƍ׾,'''glJ[Nrg"S[Vw-? Y/&_=_yǕ%%8SdӾ-]N֭ۺ.S**\ƍۿ=6tU&sg5o A$Zj}tǟy滙'dkO$s[N_~_l;GW7}* adqڒǓm)Sn,s=7 mN[<ͤ-1I[b$mI &i @L-1I[b$mI &i @LrD s[b$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[b$miXo Յ9}QXӒZWzDunΑZkєWjj([WsyC8si]{lOZ~iEjzUgR^ϼ`{iD^qiEuփ#}~U%Ep6_ұJfnuyj E3(LoұMozQ\]w[UB…}~Mѷan^NN#9J]ݰcMSkk>'oKtMkUfܼn' N(UL/MJu[eigGBh{/qBшb{xZKnV_3h\-ۛV͟0uѨcOONo6]k*pI$=64V^Og,I,/[嘲'f9\w}Bۚ:Wۜv7Kw6U]3oo^Wڇݶqy3ʏq}+tym>;#Y׍ ʞ򚥷\S0 EZD-pun @<-1I[b$mI &i @L-1I[b$mI &i @L-1I[b$mI ^Ӗ休mI &i @L-1I[b$mI &i @L-1I[b$mIS֧-+ĆW#Gݱc'LPrf(XX!#'Hذ0=~S?}p;s3q?7|07rTC{3.ok]_{`yo/p„o>\TtI6lܰqc0uʔNWk_H[8{O[L᷿iok_8pڏ|f.G掼o.(.`,}+/yU7~˭]QKǫG{t8$O~V._dC%IDAT/ 3,doxlMCC\> mQQfW~GuCdNlJ[x㍿{2剗O\tA /ڻ2埾7VNlJ[4}ג#[aY61g\5㪏~⣙_zNl ,ә3`![^Q8iRΤI+vhn3m$ҖL}W7'EIkY1;g9M[{âd4&\Jhni ł!=-iw(\j+`]{/Ϝ4Չ9cxʼnɡxn7Vv- Ox~da]njnZ\ڇts!RmT:MϠ\Ԝ̃V.عrN~W~Jf٭5ӹhª.8lZItg ;wʟ6 {B-$,&Ƨ~ޤ^28hdsO:EZRysˊ3 )h\mQ^ޘ&ٴK_C&m%SIOZJ^ڳ{E%b!]J.[+gv%75n]]%auӴo\TeqP8cSeaI9/-yqKx-W;lt8M)mnǾ跒}w~btO5;GJ0sura>Y'!476/,[ɞ>8Y MiK)Sn_dun~'lue>{*mɨw[%;_]]<誢E,_/n~qs۞A;i?mYj}tǟy滙dǾ|pZSdI t^ CW/~Kկmu3 07rTC-Iﯫ<ަM,oz% CGv-d i g%`($mI &i @L-1I[b$mI &i @L-1I[bI$HmI &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @LNԡ47u>׎(o8x0+Ft1+yckݬ <"pZ媖4VַW>u kZt;~{W5wM-59}-*v4+._iUynN܆"'L[PݵGV.zPCm~4SzQUAd}ՃjJWmQqm{x}H"'L[;k i(Uٚ#SÁE7敯:cMYlMˁ=~T⪦c7Ue#k9XW-'Jo[|u ge_ ~壟d~us 'n9#0anKHYcD޴'ʆ'{`8pTZ[dyay˕NJC̓)-chX_9-oDjDnǮ )68iK2\MUDrgJ֯o 14fNK͜U6jjwσl?+j qdÈYI0.@lӖ+HIZMԵhܸ1'g!ۓ/oh D{]i}"~s5Q*qƝIw.eT}ܣ_ZQS4kZ^ KRcvR2-7knmck@#Jk[$綔WVjUDo~6wpRg?=++KҫV]W]]rͪ+K-ZKRX٘Lk{ J{Ce~WU˯Iv=r>7''7n}S] JʪdMUe*+*`{SCeąwO Lnymi"j+2VYojHn4ɼen]6m۾+owWZp ƾ-yՙ_J&({n nLI9gsc{֟Q>=vwMf5#_y$TWM5xZ嵙kT-oQXz`϶5YvM] mk_9T g%wZjqwkc[W=j9XյQmO:C(?8ys;Ve\wwkÂέk ь+.[z0u;;l_UgI"t&Qaj^ETx;2D26UoNU]JP2 \M2uwZ9T+}w srr6-,n1馩5`W[X^qҋb~бݽ߹j ys2y\H[m,ㄢ(:}0X+jk+BV+- ,onҚXUH5PTI$ZWvc{Bcu ^Spﶦoz1>>cLuψ=*Xs}~Um},ێzQj_6MISUǾKoTS<#oI֩- i(ϙQz7o\>-ޱJq J"޾fԋY׍ ʞ򚥷\S0~k|-8N8~}[F-1I[b$mI &i @L-1I[b$mI &i @L-1I[b$mI ^Ӗz9*fn @L-1I[b$mI &i @L-1I[b$mI &i @L>my?\@?Mc„ nKprrD C[2g*~+H.0zhg.`souمUm__k,aÆ1>a.{IDATi C\m~ŁG_xakrdț &\_觖W}O?s 2 H[,mI e7ih\O)~zGNZ뫭ƍˏ~#}+'''ٰUⱮ|^CĒYv{Y;O?]ino?/)~ג剗O|G ˲h{7ow$o9fٔViXZ~oUy잷;w @dS`wy.f+ZIT>iRNSbw88~Gd]9Gٔ46vl+w4dѦ0X&mْز,./XײbvΤ5'N~m9Go ٣-SKN9d\h8+T3Dc0yl$-<L~Ĵk3~N2eƍ.p"c ۴(g޺ti-KӥEf;;>\Be+ߕ.XiΉO|顎RlK^nICdWM,w4%-$sӲXG=+EV̿ Nl3֓_ h8ddĖ-eӻו.޲fz:زztleYٮ%U-s W[uCKfRyKWgoٹyƤ5aNx%q;?}LϷsV^lגnZ d%2K殎%l*xYPk.. '4| H6$dRG-G4M_1%L^0n6YȻWLM9?sn[I︒ Lq 3O_|CSM|GӴ2iӖʮ%= ,ؾ㢢©Qm̾''p❌e :vXn^κki[S0f̘~-/̖M+?LaGp4/Mօ{x1vqaגҮFrR.jH9vT4oHX?i%ѥLrKd*1/fƤƳӗ һ+xYE*[YP?ov Qfo9)'}Wj>G۱UmzɜE9:7M?.c3.KV1),]ړen%%g+~%33{N[6]ӗ%2wٸWbK薶\~e菜D"c}{ÀqVih˓ѹu/֍Y*i9Dg_↉7kߗ,? 4x $7rT!,VM'iEED7|ꆪLRpE?)m9s.rWeGKf#y_nؘ)rrrٴ(jᢿ?d'߿?'/Ηwf.WwÀXI,Җ>u붮˫?vu⢫&qcmO ]Wj~=ݘ[^uTU'[n^9]*.YiKԁA7ڸ>Y% P2mZkc7,ɿ+i2EK. -!*#z1"73饭賉ϙt;%IC[d$:.)K醙 '2\3-7d}c]C7_Z|􌕮;HzӖ7x?]gyЃw׵t_{]RuQnI=]7*U'VoYiKo*jnK$koVs6M5nZ*[]>ڼ(SUdhiK%;R'ϭmlM$[kO:7z5Ʒ _Q޾pbIMS9DU׷vc{{춵nVMOtӸ[\;UyWvQW]_p;ZCCĹ-iyZ;-3򁖮Org-6dmG &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[bkڲ⼑pJ &i @L-1I[b$mI &i @L-1I[b$mI O[V~ 7G/׫ٳ'cǎ}]2媫fSN"aah{?*~+ᴺp„.4 aS"~rϽՙgV^ᮯ=?ņ vǼַMLm~ŁG_xakrdț &\_NW}O?s 2N,K[o{CMk2S4i}ss>׸1sя|oaX*ZXWR> ƨ%)=yw(,s_p˦-o^K'^>6lHEo͗ݼcdy[_8sB?gl۲am&j>b%wɽ{R[ٲ-glJ[ә3`a(?qNɔ8 eSر|߉^Q8iR!M&,tn]o=[Bhkk._7l d\h8D.Vmm? jӖ]:uʔ 7É"GWn*4>S`93JYf[,xr]c BL|bz20e 2$UjmѼ[$?k (}ʕ[˦.-K.+[w͑OJ5 rcy;:źyÐ_0}'CwK:oٴh?<0YhEEDޛoYuCU&j)}pʦsY˙_y<ˍ3}uYNNNVٔ$M2E\߿'[~N7|ǿxr~W,Mt:[n뺼cWO-.hrQ8%76nUYYʾ-pf&ѢUnO禛?3\>%?ᴺvGQN)S ܖS_Wѣ>0s[%iu'?۴)rSL)/={>< RҎ#XI5Q-&:VvîY#/HoHEKV"׮PL-PH:g(g9; CsYY}6覶k C&-3 & & & & & & & & & & & & & & & L&Ľ-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1po꒢j=VRv5ݡ>=C_\Y4C9ͱuHuk˽-1 |oK+K;~+hNvJfW}']_ݿg]pwPVבkC_Tݚ){ZMLNsėyYG^@3n̠GRbtw <#{lqI oRe&]_m %[!;YW%.Pl"JϺ8cBUME8$(]t0yC~מv: _Wk퍭]!-4WS[JJR{}͚}Օ ,uG[);k&qjKH=Jյa͞C򹥣=T*8^mIzm[1VV0/]ͽq|p5\kz x%[&54$̯i,Fu$Upz􅕩pk׮漢3 0ed kWP=ɴa/(oBח[S"[[BN[e\ªf ,ǯ-}\QSV*k喒އ+${/].^Ӈ~s'+:zJ^esw4EG/^S]r^ Dǯ-xltXҊѱF.(Qd.Ӡer {[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[b*ڲٸiO}vݡЌ??N4uԊ=gNt:( x`at{?g©3mرc(v DrK{t^|~8Mͦ{O 7mܴ);l/9Cqį-oxSq2z{t(^x+O~5_<ܩҩPh{gܵa͆o7yaDIkyj-[Zwl:ѡP[8 lݖl 7e՟gEEgGn\bɊ/>֋.0eL((?d\wtj9ʂ }޷?BSH套^dsqchc̘1g.sU_7PP )XWѩlbrE<9Pժ ׮U euhݲ%eʰI{&sgʊu~֕rsCԉ4vxok+JVc+hҲi®PC7t+0l)_ΎCef, 顤^|)$֖?؝ xL}o~`M?/ Ӥti\3L.eѢSEU|g~L2Xհsp>n{hҺO/(p2ғDsN2Ѿ#@o{c{5_ѝ:AIB-|gY2am KC(]0+5Uss,*ܷ,EEr$Kr{:W-*/K'sECصxn~_|%O.bW];o{mϳ/`*BZe~G{[?04>]44խNxoKIuk&sei~Oʝ{ZKM,[WuԤCz myezZ[{5UBPUSNQ'5 aoKS[v'i,$Q)Eƺ-1'zI5Di$ba\4s$/NmImt7W%,ɽ9Q}hb{}:oNQJji-1e2@$mImImImImImImImImImImImImImImImImImImImImImImImImiڲpo @Lj @Lj @Lj @Lj @Lj @Lj @Lj @Lj @Lj @Lj @Lj @Lj @Lj @Lj @Lj @Lj @Lj @L_[V;7mO޽;*&Msϝ>^|()d2ؿooݞ?zzԩ^05~B^kw'O/!z?۾~g`*3f-ny_Fxį-oxSq2z{t(^x+O~5_<ܩҩzWhqW׳/w둇מyaDNMmWMՖ^]uͺdlfYCg5lgLd-pj <؟ZU߽0d${ U7W%{䑖ONctoK//({iM{nj_vlߑOھ'gqF&mYhZƎ{G$*?x]nܝ;tUH= .{S #yYQyy=@gAa8L2G]'p*޻;.yljI'n^lْY];lYDg迪m} ^ Ǟ={\pRe&̖}mW(;v~Nbrh??N]op:aal̍6:ÉI{oX0wܨtڎkesG[±&KLhZ2~%Q=,+RoN]%eGϫ\ݿ*UcD[o1An{9qcp+'%VVH92 I-Sϱ;M;Λ~^e:u$'@('9d}G}:8]Rmy;˒kK s v[T^^T!dNjZBhYT_^}=\t8]e2߷7DZ[뇫ⳋn>0jwWOz_Ͼ^0L'u xUҽ-itveUD_~$w{W8]Rm93Vr2֯~%_^M_[UTTU!ՖfμSLͫ˫tkx%ko"BZe޳u?xyee/>}hԾ۳0RmSBl˖֍=#=dy"^SWΞ}7+*WA{[^5_;/pu›>F1kK[plW}3<3nj j 0Dj jp:S[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[b*d2HӘק"up<=me%zggծho(+*hO^S]R4խ5ZZs|6 c{[:2Εҕ;3G;ruUɞu;:Ij|w~B~ ʉGN+=Љx si~z\~߸YN hx'+rEdTd0nܑ~쯋{.Ee]ҳr'TTjK[S4qM{ka*~tae]kGρCGR ۲'o;ɻZgmol\Y^SC-3%TRSӄ`_3g+IϪklm>p]˔ŝ`yMm k-=/|b;̢t͚P`X[zItS\Бy?xp-WN8Ё{?-sDG `4޽-5UFem2.=' mܐ- ;;]r mx5^P4$/kP/]GLWRV{ͮAϗm?La/(x u[{Aшt6(Go8== gܐudxmƫ%%@w{SM5nZX ;^~w,8ϑsZ {œi_8j+ik/ӽC-{FpbWkxoKj!L_m{nrı}&^qÝ?ݽ& KQ& D@STQ&}{ԏ/3τBS/a;k _rK{t^|~8ŏ~cƌeͷ}3H?#Mѡx|U?ds|ҲsJh쯞Ѿ㾯ܷg_z#=3È?#S`%{WW]5,YVPqv(vϴojO6z[( ИPPRwVj*ykInJ6#-* ޖ^z?_Pse.vSS`/|݅ؾ#;2%}O80LmQjźG2v;Z(w%rwZSB!H2|ŻIDATN=7DyYQyygA2eڔWL4Rmio]YDs ]^~`hd̖-UC,CȶP^ Ǟ={\pRe&P={~SI-e3gnܴ)N$U19ssuU[g4?s򒝫M4,xW%k;to?ִ%W9x5B'4"uVEK]ҾllՖ#f|Uڲlܢe;nlN-$ѰL] sdȊ+;snQYv٫27l~8g 3R|;p89vg3/=)S6;ر}y 7yյX%MԆк|$^eyeؐD:m`ĉva:E('9d}GԬaݱ{3*o9E3>PBˢܡ-?un-,%%pJ('β!-7atmǖTu)^|QK.[8Zܸ~NyB[c7h޲b#%Km pJ(d2ؿoo!>2'ֵWgg7?|v١wWOz_Ͼ^0L'Ou Bzh7-z~׳j` uW%޿ )jgrŗ'~+`}yї7'mUQQQN T[.9O}27j/Ŗ_t~%ko"BZe޳u?xyee/>}0Zojn|xclgyl}k)(D˖֍=#=dy" ͕gͦ j`?/~C(4n7}3覶vmQ[`dp:S[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[bR[b*d2HӘՕ f\IYeݚfw|[{?Z=E醮cO^͕G+qAWU=Q 01a>4̊Phv>~'.ysIMk@w}Q1hmd2;WJW{n K7禯J>\.s#z7DrZ]c7.\s`ya;MsMT:Υޒ?Wv7 `$KW6nxp] +)[fís뛻Թ+Ĉ$*.5褎FYgwL":{fhz 0"#-;tjI]۳7v¶L&\Y{jB6̛_6ȧ&Tc?ؒV>Vzre{KMpvm9ӱ"uWw嶦|Z3eq)l5mq!=]oք1sJ74W{7V-nh:O)Z|[~6Fli9z+p>#W66UPloiZn분7aVgԹζ֚3QƦk{ Ozq~Ϯޓq8JU.-2}ae*{MySR [Q-5 ys@{oKqE}W6'nZK'O). 24['ibmJ4--1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1 Z[`8?!iϽ-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1|mYlܴ?}>{p 4i[=w f^zL&3c_g Mz?} Y'8ů-Q >nG_n])i̘1,~}Gmp2jT ^x_lM6+-+=w깩t*B:ճ;wKv]zgyfGmPp%{WW]5,YVPqv8u?k?Ӿ=ټoy0|j lcBASK7}ʧdU7W%{䑖OFB套^=s񴋦ԽcX-z%^~.n)[rgaro lT+ֵ>riZB~.DΝ]_0Rx{$^~sgʴ)3RHww\N\]^^lsxoXP~p=@|(_oFׅ±gϞdp%prbrh??bYWI5)Uor= skK:z̙7m u.=jE-ߓ[zΊ]a钵G M>hܞ]:Ա|Nns-+ =wEgnkUf.YpŹSN^v O^tO.vѴdJ)lh޲ea׊9+ʵ[2k_k uYl֕R,3[֮/)|\?Obҵɜ/HEÒo 9uufE}꣟s\ '2vb$dHGr7:L6=/M)_؜ΎC+yxkWgY?#??7|jW@;9vg,=)S6;ر}y #4yc3JP< fб#L80L{^BzsI;wxfazXPTaz?Q*uت0xWxtn-,%%0ғD|g~Ԗ0/yVL)_OnLYT7t_&%s[%7Yvu{>dxiWIDAT/Jgs~ܢvR \=k͂z+V4rх`)d2ؿoo!>2'ֵWgg7?|v4]=}=~{_{0;YgWHO~AzU-^~庫Rzy}_`)rg\d_J8|yї7'mUQQQFB-Y͜y>W5_Wb/©鶧҇PK**0*Һ-.[o^.+~3SH?ܞƇ7vַn lIli݈ѣ|>cO6'?4p})8ſU_pg]w/aso -Yony(͛)겙3>\<0- 0-Nƺ-3 & & & & & & & & & & & & & & & L&Ľ-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1@[]IѠƕU7v<ܠӳjz?{{}h( ]'cvܑD2&=[ϙi콝K\2| ֖L&sei~t!/ӳ{;&I%kdJ>\7!=;PV139悲vyw ^LG]Y8PJϚ|ػ 2dV}ӭspe lurnx}sWx:\|-IvQ}C>y"+d2h+ { M퍳4O]݃Gx˓ }tԧ- U KzLN{d{/~s[GmueQOs囯ytȟ$;qz՝OqꜮkNn*yW%D7--1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1 Z[` gA & & & & & & & & & & & & & & & & & -6Ogw ISNsTNKPȊ2̀F~}|ᯞy&*8Oό;6bgAį-Q >nG_n]|A{ԩlg H=qMfμ::j G7'?gG^W'[JJϝzn* f_Ͼg~̮]l}͟F$ֲuV mɶpcj)YVPqv(XZWd}t+8~o PPƄrkmMՋxwA,Xާ}9oɎ<7c(4T[^znO.dpyodg}RmYs=7;ƌ)s9^uUo|#{$\>s;>@<$\[mw@(ޞ q;N47WUIvlYUN[֮|˲9fYk8O{du۶B-{I\rNJPF'5f̘NO{&$ o*fܸiS8/>?Hbrh;fo犹E+zǥKv\1],bWvPjUX%wp-+7/+Z};HkWv6WN-* C2iO=Tvp-ٟ0"Utj.4\`ʵ[2[d. +&]?gԒM-WeIhQg-[v.S!pR#3J=ᠮ^T8{[^[jW` eҵKVOYk{oW]Y>#r|Â+/>m]φ[W?ytXx^B<3# K/tk˟spLdkSGͧ4(c?g號? V58 ZK; $9眓 v#ӹk}l^>@s'_09ZQblU)/]L:D>kc}?vO8Uo|=H]6sfw{x[kvat?/~C8̟7}o{[?!(ڒ9DIDAT??ܼ9T}]p;¨qvm5q*SQ& D >]tT]{ߑʢcT6S]R4խS`r>cԵ0fHv}#p"ԖLֺK'5w$sei@ʝL_.sCgʞb~swe2,OT}']_ m\ZbI5f%` }l7IϺ8cBUM]*ܯ5Z-ܐݝN-@Rm)u rkPu6n}+e2ރ%IEȝ``S=t: m)\-X=2'wʔŝ9eI*`Otk;䖮EeP8$QqecSk{+{kÚ=sKG{RjRT(C_x~cӕѣT$${Rur֬i̧U7>xWcs-x\(Y%RS gM_Xpjbw[CCr|n -J zK=W[~ӵL6_L{AQzݵkWwUMeٙ@a^m 9-u \9VrKbb2ڒ-M+rE -V6#eҽhNK~s2j-o>['7犚ްRYs(-@a-9;J+VR<-;6QP-WےmCR60:dO?>:ouKV|`vG?ַ^tх8Ս \ښU߽ѓZ`{-%;>x4PH套^d1cLtz2޳787@M#8z̙7m uIULmmw=`ʊ]a򒕥+)]$<߰`]3{o^V(?o򒝫MZ+׮.* C2iO=Tvp-ٟ0"`t+7@ԡԵa׊llْY$[9{$Q..]ۙYUbnѲaK&0{T]yyѲмvI6TM-JS_qcpz8&ծ^=Kg$sw=ù;V/*Zشή0#5kA[?:M<3# K/I-Sϱ; M;Λ~^jՖcIZ{hrsb͉Vi3?&jXѿq8 =@liݧ v% Is9'hZZE U7ftnL%%pJ+'β!-7z`ܳB+,;WZ 특թ-[V,;Q+^ʏroZΚT֯KmymJ]SZ!Ֆys?o쒳Ե3ڬ]WM:rsOMZٲ֭۲㝿y]V6gL_w?'=/OdǻeҺG5}ǾlfF'Jo|zϬ0R͜Ѳ^}E50}?!Vm{FO@<\[P燛7Q߿-UGo\0-Wa^9*UrF3 & & & & & & & & & & & & & & & L&Ľ-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1xw{}0#͕EǨlh([X3t}m+k+Gn?h0Y5m=M9J*t8~-L-mΦYE ՘!0:46K\R3l rfEÐCq8 R[:2Yvt.ܑΕ+wf2 ol>l~պQ){Ʉ#?QLw}E@}w^|ĵ~%k r1/v ٝ{3cɉO庛hq;N} 敟_X5\ 'ߺ-;"nht.n ItlxBWGr7#t4(?[x3l N΍o:te pcBCؙ֤y%þ{ˆCCp ڽ-%3ZnS8,Iɞ}͚}Օ,u؇47ܕ8q!ilCw5x=]oքwH]|RGl-Z5'+1k:I=Jյa͞C򹥣=)5TБckjf%fU*|y %I?Ygy{>ђ?+i;t:O>C_QJo#oѵ-yZ nKƦdiG>AoI^R䶭Y<38jl]%zardMɵbVmm~^4+lkSD7aQefג-I coZg8W7?[j}>ٞR0 +SNMnkhHc_P}PPiE}!Y)ysCy~7pN<b$mI &i @L-1I[bex|Ο_<kٳ~/vY===V0=}c?`1ww0agi-֤ Y[=Qz?zgP7Oڔ)Sn\u͟_0^J[8O[tkh9r\?ޜ=ڿ6(ܹ׶~ܾ}~ /w=yӧO2_3O-m͢E5לz+?ۺ5y>t7I[`LMG-~nQˠrޞx9e77MLL+Dyޅy)S2,-:?^kݗ(ϙuYam1ɤb[#e괩6*jQr-)r IC~8]le=70 sYxt'Җ9_uFl8kݮ6uZ,.t ف鳍 tlZUn=}/8:t(]8GlWm.hܽ67Qؾ$,TrsƶØͮڼgFU~~ȷu/0&0my㛳O _~CU7I;#^}vA5W:q_H_w:i^w\gm̥sC>4]fvIf]s_ޮ76Sũ=y+Mx..tuugZ 팞h(癩7n[V'JI(s6o۽'ٖaNrтT H$aavUo_ً*sCC}q˂=N4Vk޽MX}Ǯ0';׬^1qeoO1W]:hT1 5[6n}\gaDSM r-wr*lJ_Iհ=$C#Km$vlJ7h>:鮇BnӋC:7(w+B[gqZzݛRIUM.Y۾T0taG&u `2y]0};Ǟ Z;9s_*Qطwyqy9ɾ'!YL$ݴ ?ors;VJ. GkZ@Հ^'+ ~_',پxɭ]ūV~lêMj˻cugnWhӖ.̚50Fe 2o9眓.kNEʯfM[P\S+?[XHT @:ՁD% ,ZuRǖ1hӛ ˤ ҅-떮 }C~fW}eMɸiUp9 YmfMvTYf~^ޮuYK7$D􄵩i_:ScV||u %#ڦM&dž,玙]ycU Lޒ[ul Җ LA+^|pQ<HmCBٍO5svx 8PbA:Ư~}_~!Q~[,} o13%,~$uuCDgM7$glgǖ?WW?LLJ[: _J|۫ng]}ÚAI8glҪ/lMzƬL [҅ o_ˍgLqw,䩖/ޟ\]u%%x4oKK'o^]ZTxIaֺu&CL,>RcۺG5~;nzy, ŋzC8 3I-poOg]}V~caӷ3O- /bcw t}ӧM'23Oy[^ˤ-1I[b$mI &i @L-1I[b$mI &i @Lzzz &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @LSj\>-kr Um8:Y*[D鐇6vl)9~ZrN:,%tdJysiJ?L/kGoɩhm߹'?y=wif̘gϞ;wnE]t^AA2YVOOϠ/p8LnOGXϟ}6):O}ogN&7̘!O[n&]֎/;뇺sx=wL.]Kv4-0iߜ.c#G\+'ӛ3g\7;ܼi^~٧lܱe=޿ޯsea\Tnmɩ!madؼ-l]-,췝2V"-Jtߜ=K.||0#+ -ö(Diӊ9:?6n V5%+o۽4[tu&ѴnvZ=ѦvMԁaƞ8̉frK=Pwt7{R^QK"Iu{JB]yw`5]WRd6m_4^yyaDSM @-DPyЊ!z S~w[.~4MOw$.:A jP+/ 4i~}DowWJw^ya|tqv OM6_^?C-}֭jI#9ta_뾐![hX{ӅY\pAQ0%trHc[QjZջ8t>ұiEVqrޣWHΒ wZR3M‚ƍ''is;o] 92iޖeK~3Qxއ?rG9{,G'W^9hECfٽ=octyϬY@&ɤ-yBו g'7n@Fɤ嬳ΪtǞpiom_[6$o˗- @Fɤ%҅ o_ˍgpэ#9ÉOLIܺ?OI?#eqYѥE.( ]O<=cr.3@&[[=Qzo_s퇿79EozӛEa.]0(kf_|p;ſo ˗-͟;&7̘!dpڒ/66ݟ|׮[Z}q i i #f̤-1I[b$mI &i @L-1I[b$mI &i @Lzzz &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @LShʴ-GR>tʛӸ|`M :N֚!NST^5t&;א!Ӗ=<ɽ?\]R"1|[Ym=' |t>>u`Eg]ݎZU>rpϝf%v}N JN|]u%=.O-9ͩǽ򜾆ē0Ǔi[tmL%̺mH~Ƌf|c{cNqOߖi;"Y<|W]s8EGz)YzݍץbkՐi9E[ڶ%<g\זG:Tޛ9l[[sMiAVԵ4 ;װq$J.Z!1ddEd~PQrb[LVTUUJl2DKS1A8Kn\]r J\XY;XsWjв쓏-1qҒ>>Q}ƙmoO j\좱#Ut7t5ԥÖܪPTQz+VvyUǃ;)ɿP+䘛roP(,)ChihJ*Z´֪҆[Rcǫʧ zpj|THbT)01-G۶T]VaJiԴ$͜#懩Eթk2]kAIWF˩Y^ט|5 $TwRU97) #(R8ѿ;FgiKoJ0-%wUT쨫K.\)"t66*d7y8+Z4?'^;oKZ 1@%8ΠgG}IDATcCj~ܰeIK.RG)mBfkʰ)0:L[W nzrշ 7+m'1fzפ'rD!twCAvy}yKEecG"9ZikOtloQ1ӎ;F2־-%5-[𣟘WPcG X)'~ܡ=0ZvL Qd7|dᥦ_<(# %-*M-2c>݌;F0D9[Zj λ޷f4!??n)4#Y{KUUTWXr*yD@QRQeu#'ݭ-a NzCw bT5G{+󄶭 q/$"DG;v-ʻ)9 "8>9 }W՘ʚ7-)(nnNG=D8H:6g۽^qnV]4̅zS3/aD-U9Р̺]uYS]tB;j+zoo;nQy`gu֧>7SN f jrkMc_~swuLw̝w>sgp…]pL!m`2~=8r?~29#{Ƶsm~Qs+ DB >lg{-;~/ ֧ukOۆ i AےȆ>|QK¢k~ف1V&>jlxKя L 四ܜ.*E-jƞ_sUVZko^+/^wǂolQrn՝G/Q00yO|D0.oI|ftC"}(TyE֪ڭ>/n)KWԥٻŦQK=d뚑S]ׇζlޡC Z?JG-6j]3NFɓ$M5!7ɖQK"Iu]*ʛF6u m) Cx/)cdKWhґ(R {{gU3֪t:1{e '4⺕c#wN_cp;6'aiֆ{t4lk>fjscW{{;\4+/M`wѠÛ3կ}{Wx^hpU*G3@*j k"d*I3erkn:15C-$2C{Ϧ j/ˡᖾDVfmP2i$9眓.kN͂ȠW KZ׻P!rQ*8,- *DXӷQKw}E+Cz. X6(y w^}.>!ꓓ3+'ɤD\POiuallص4=f֥oݺ'o]֪poL Y͊9Fk]!dAIk6mؾvW Kt.5nbOH֥t*-qfvW/0Knrʶyūmym+_1ć=!CGۡzW*$gЊ_8eB2h[sPy}vvSg ) \`hli׿DyaF9hxÌ^m4h? QuuCD5 >F|0LJ[: _J|۫nYUSm+Gxhom_[6po˗- `2)mIt>rƫYx [ggGnۍ)$eg !fMu'ܓ(fGⲢK /),\P]O<=crYFCv~u_??]aғ0dvI[ 2o\L &i @L-1I[b$mI &i @L-1I[b$m)'-1I[b$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[b$miP-9YCSTZ][ʇn>PycOIA] ZS0sdԴ]CU5s6v@NU05SiJ}䶫L/k ՏmZdUHEWd5dRRӳ6?_ߑg}0K*[R9ͷ.srʷMW~SVt8eQu۱[x#ܹlVbg߷h@:V]Sn.} SSyoRRuJҷ2{;[ӛW~M}3+++dJ(t_R *9SvCYz?t ˤ-=O]8'2%Ңv}9y{YgHLJ+5?ZNzkӭ%^-"w`X<Ӆ˖^vs䰫8+Ykԭ(Z#6sYxt'Җ9_uFl A$ RȀO!o5ձiEV񊺑u{ɤСC?b㼒ܐ??tkmw$>[ׄ KGelfW}eM~eחZywy!u fС_`.LST{…5a$ _TaC,~"s6tV4+^DRӟ[tu]Vm?<ʋW5%ҙ5kZ7lh6lN7??<F6yBWWשP 팞h(oȎnHd%eLHeΆ>/wo0oPޝ5Kz\IE-aa4Og6nMiW_*6j]3N몓F?/SM 2}[^ed<ۗvV*aqS٩ciIJ:Wuڭ_V~lñ(S޳ ۟nKvlN^wҬ =B_4{eL2'2h}/Da}%=N'5Bgպ1;7_pbTlY 8'LI3Tڒ;$2U#2=m¬Ymc4Wfx Fs9¾},hܽ,,XU3[[(vT?˂&_(%DhE~\}Cr'4j{zY`4 OC:m.M| ֗&;$'Li]aNڭ_1gUq5[=Jf߿fŜūCrmkrlHz&vMmWeٿyі#-NrlQK5|ioqwcXsɊ7l۝8dNqPG?mqq$?T(dT9gF__=_H?? c4q_hf pfɤDy5xݽlP9?V_]Z;O02)m9묳j7|)]~'o=0/Rtwl ˤ%҅ o_ˍgߵ+҅ >TO&7i gN[tS[5U5%LߒSlH[ʶOmOV&|{I:rpϝf&vgT}Qu+?WI]jeucg?N^U߷eZNQ7&ˏ4v3IPTbi+*K`E3*Jjlf"Xh%,) #noJK B${?7wʖfơC^UkOUO4'fUSִ$)LJ am߹'?y=w0Y͞=[XxK.Y߮ *gЊ_8&'~~>2;?w_&7̘rkMc_~swuߔ)Sn\u͟_0^-0>Ӗ79;]Z;GWO7gdϸo/?wyyahxkwBz{:}0.-0>$k577_s빮Ϯl@} c'mIhJ(t_Rά%!9.,nLI}[^yz~?(ϻp=O3eJE?^kݗ(ϙuYamI(Ҋm͏ӦtkF-!5K-"w8#dR`зN.[zٹs nμ9 \.?2)mimY]k6l:pM+VllA=^2ǡC҅/>̛=HUm0q_ 2g L[giS >sg懑䆖*/^Ք,t.)ޞړ[usu+Ll.޶1,YZSK7fk늗l?$Q?*)fثjޅ҅Sy!ÿjtfG[7psA&Sݻ{tn2jC؞Z6&o,~{]Xٖ(\>&-,]<6,Zkثj괩8dH1Id(%!,ݮ}d>`g{GGXw W'2h}/Da}b[\` SѶ-]5ka"Fs9¾}ԍb}+}וeBhZjE:jӛ !F]pA?iH-ׅ[K̒2l }o۽4Y]5KfmH5^8lؾz麂wo-YSO[.|pFqq$?T(dT9gL__=_H?? c4q: 3f`2i$^AAueʉ2ꫫQKyٟiuY.?ؓW2֗V}ugk;6feeIiK¥ ɿN76^'WlBFymӛn$gLߥ{7/ˊ.-*pAaZw?;ۛx&k[[=Qzo_s퇿7iXޯ7Sp^50V6wÝ_淿 ?}vM[IL N[^|Ʀ2 }CWO>=LnN[8I[b$mI &i @L-1I[b$mI &i @L-1e"ѷ &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @L ]յ<'kT :T޾yL')5][d6ST^Ҷ<;+{l7>؍)a57 qՕLs՗m?ܻC{>q񼫚C4W0iKƮͲm='URӕ΋;Ӄu ]|Ikwt5.Z*KV0s;x$yϽ, q}5MDߖ xc:vaM][8euw%̺yGբi]Ӳ 7wEƜeeeғďҼ-;S+kAHgc)-m´iWL[^uݬD s]EIՍ,J@3ˆm0cM[:&~oH(ji*bG]]:lYVY3myŲFg]ݎpjJMM;u0a !~r˭5gVv^~}Y?gw̝w>sgp…]pL!maO[tkh9r\?ޜ=ڿ6(ܹLB >lg{-;~/ 㒈֧RukON i #mIdChaQ5g쐱iQ)els k6t~@F277ݷ9]._U~wgtr+y➷D^dLJ[^yw.vM8c;nn9]~o dRڲ>Q:mMNasF%\+Q2)x -ܹqڵ.ﳮyV\+>~taϞփ sdRښ.IDATwMNUj{=ӟÝevD!u#F< sϝ:}j=:t(]8Gj;;('?rK«`~nȝ_0B)S^R.:d \oG >sg懑䆖[tugziԮ:,.ֶG@%ۏm*M+lݛfyo+/?ʼ ='nJ|¸& itfN4vB԰kCnޑD|$^ٶlƢ KG%,i_?}H̜ ζ-Ü M65hѷ>H]T:IʆV2JՐ<%2 ,˯ M`wѠÛ3կ}{Wx^%,;cU#MvԹziq}rQjƞ TOM6_^?C-}֭jI#9ta_ρDDDV5␺z /ZbqWDش"xE݁0v{z'ə̑I#.4ӖX%;Yrskn=jƖUY?e7m_մupñn; ҇$woX܋7&-]{sVG6kV< zw / @ȤeҿƽLs wnMձ枕ON;2Ay+:j.=5K$4h? Quu===Lw#]q (uY.?ؓW8k֦-|($\p tqcrv,9o7~#s8=i2iޖ[?x=g=/.+!t멖<y,Q?eDӖuk];J_??]aғ02;mU!mad, &i @L-1I[b$mI &i @L-1I[b$mISVOOO }[b$mI &i @L-1I[b$mI &i @L-1I[b$mI &i @L-1I[b4e ; R :t5f PN9YY9ݣ=bOP !,*@Fuڒv4s(C4\7/?~K?tU ]x%'a[Yx hcŒdRxI>=pj/ kLV"Asy֒ϲm=4 7Wd-'yzTd` Gv4וLmST^kf=S.)-nbQ޴*N4 $4-99J;NIӷsqֆ^ds]uO;G| 9ZF=k p"$jkX3gꦽ^sަW]p}`ͻ[K'sl֓?/xCDM_{|\?/t 5so99[ J[.GNxKM)mh؎i =~5lv5,w$IObrpϝf Ѿ~,ͼ{{^3ڿEu}BIMs\tS|mY%}T48aLٶTInm]z99m٣=S2ٽ4{6 B**u`SA!c& _Ϝys^0]OIiKkkL]CO ?5G=T=}pAznEq_FᱰS~zQ|Uض{wWl\|dVY ̰IDAT1=7un3rಫ|醰fkk;Հooc{bW[lłwW_=})2)m9tPpjkYm=jcC{޶6ٺ&?ѾyGG5oMkFuHl*ݼb:Vb<ϞHlO7c[W!`+zG|CM!rQKςOnJ?ȂG{ z#>}Z4[RWO1y,IGݽ:0M`7g6)o~>vEp^^:H1IUh{3/ok0xW] CEyvuܞkCth^tugnWF01|U s;W5un(Mg}=2RMЂƍaIjDR3 ۳Zd{n0ԝl۸} = O}/ɚ̥RIol)};nqJ?iUٴ*u\J{R4j6a=q;F1yBWW8kN9lv 'qH-={5ЙS#74=4r;_I2zeG5Iݽkڗ8t?%R}Rֶ2;c}/drr7T縙V]0yd2zƹtlauaYno VNs7!mj(Xcm# Q&?,,KC'}S 5.߫1N2H$2y*A=%%U^zuZ Pl*Xuu/~uK0dbߠlƉ4g/@݊$exC]\ز3,tN0ZHdR_Vr ѮUM6r뒉ʾL'P*Ld /1&0mOc͙_W¾+g؞JΙ9D{*3v: X ZAJ)@ J;;r岷ϳf]{'}|oZ'>?_C]wŃ;KG~"ȈJ]{޵vCCŽ63]NmU@-5vMn;ب?hmf^[>4椪Ͼ{k?OzյeJ5k:!,͜/^d< [LOjv?ƨ_{H@ZT$6TPCk`[Vw0V]]荏vnrv$ZpgZ=QS@-9tR{ſk%huD+;ˎ>`V{UvV팵x|޷F?M1_=KL-Æ߈ݪTNudX*_k+_%ޙ{ ZQMrŴyW̎-n)٭%%5MhDwqb&ٗS/8ƦFdC/-tY>vI'>gMzemI~Ag%]e0Y .iw4Q.zt8@+ӖeRmC u{vɽ_oUZ0?('9:>&KG՝kc\^xj΄UPkkmKf~q;]%y7r3qUkIq&J7+Ωx蒜!3IbYI5v~}#^2xmNkW?rZoLJMTKGҟ Ԅ?g|*\C,qQm{%m.*Y1sfbAcsGeDϾ"g%EV]]¬woٷwc,϶jجAC)|aNY_E']T{#}&v+{-=쳛/|جppL2GN9<& g.>8m DG%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-Qj2mh1]-QDI?1MIDAT%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QJH )E!9U 6yfj͚T0%)߿D ) T\zS٪dN/]+TX7ၗ-,L2&{FfuOO WO,Ө&Z4FfB^wW[~naD_lڛBS9MHviՍh,]]H{~ӲBZ4~`Yқ@L%MHb[/;oPtEfF?8/k# nϬܢ_6=76WJ[=sF>;{ſKW{GyI[I護^smzvFޯޚL`˺\3- @rJִ_X|yH9{Y‹ vKʕD ^:qi'խI'$#fβu׼':{zpX|iK/zV]22uE׮]CJ' >n}va@@3(jb˓O|KiiivZ\8(o Em 4#ږ;'wL.lmٺuϞ=f\v-_xR|XO3&]ڵ{׮]YYBмk[:ed&jޒD?,m[>ڂk=z8ҏ석ݻvox}[Z9S4aO)nd_BPR_7g 8+~acq[`ڴN;uRݛon(|{~W>@Q>b9~ۤMHu;L4:et*SܹKpdt͈ѝN\]SRꛯWuR|%QFFqw\sGջm,|~hw+߽}s1$^H)ɱ]QwUa^{ [mVxUa"9;R?m9c=h?=}2xOLWxiEr%.vmÆ}o/L3h3Oml`W^OÚ[ nxE>m}ra6/##cǎΝ;۴JLb98q^KKKI;O-{۶%{lhWV]]荏vnfۛ7׎KM'kAqYgMo}v6u#{Y8|KIɴo)hl,2leK̝3kԕWFҗGBw\G2rYKkر3|{rpں/e'ڹz y$Srl׮;/T/ذqcq駟x HIv&х8?| BTimOj;'eeÏ]rIV۲',ܲe)'{f,W{onp;w\xF-@8mytI,j5޼9q2tC䌾rd再:L ̒};/7---+W}ɧHfI\rl׮/?8l¤BC;SNs8J]@r!a\hJ (I[$m J(I[$m J(I[$m J(I[$m J(UWW" J(I[$m J(I[$m J(I[$m J(I[$m J(I[$m J(I[$m J(I[$mWZ5t~Yi yC ]Q/--dm̀cZcy J{i Fd&K |pȵT-u+|\۳֕!,<|AeŋZ\T$$Җʙ#/ydK}ݯUòFΪZ0&q9fA>WaY%}\8?/gw,\ iK?X1sd^zM_z֐ 'u yhmE̒'@rj!mY[ZhF Eb?M]ve̸+P*JJ6"Y iK|jˆ…kəPZ]]]Z X%1jֈ} aWկ"I%k\]/}IGg [8m<6WIDAT1AZZSPpyMf5Q*ˋ$$ʟVˏ0?贼q+9ƎFEIqAabQ f !sD]o<} ?[n=rE؅U<8)h}5$V=r#5r dԊFzސ% WTVŏ^>D}M=3b94n\ָD MhUiڒiM7ncj.*˛|<`EuuN (OzjXESiKimTwv Q+5bHIM_4$$#[3hNYR8$/3\1pⷺ8aDBֈpUWW7y$S\4t:c]1{KhY}^nc~bȬX0kM--|W*K jͮ$22;s[ӭnk%|D@fk[hV@+I[$m J(I[$m J(I[$m J(I[$m J(I[$m J(I[$m JM-1_=K J(I[$m J(I[$m J(I[$m J(I[$m J(I[$m J(I[$m J_ a22;e\($'JyU>4$w{3R$mX *jEj^㟉Կ`S8=- ׎uGje2;`EbW<0vdlΊOP3>34ޙni"iK,\PiKQazD3t+og=o^Q__8ʹ2o*>rǪ5ۏ;zN̰#)L|l}|~鿩:#N0^;,6CY4~Չι(vj$1Oj- *z^vꑉ:쉏3 -$XUkuUY6116X².=7w^fKo&E3+箯:>$jȌo; 3I.5ҖFdߴU,`uOPd>YƱuKOnлswn;̦s [CbNN,V t}HzKnC&,CgTU[ҁfL,l0sGe4i:&gG&LYs*B5ŽBwֳRÑ!ăK\o*[~RI5B+z¾ F=rXKFUڵkH {>d§֭S1={hhEMlyɞa)--NСÑGZ:wRG{޽{7os2c3{:a樎hBJr={pnpXR͐fhƗԛg{_\lYyEEyyEԩd9`!]t%L-MOسG>_; my7g ŷYYY!mfD_rDɅmۼ-[ٳg읗׎O*u?5cƄ}]vڵ++[hW}mKDUmۼ[h~Ppg_^[p_?G}Zё{ oxk[+_^9g&L=m }Wj[Y_}[~꣖n=)'g^ï>l̰;c[[bLviNpcRWB{ oO]o(jG[98'qoTQ).Ӗu睉FNs;ww<щkJR]-m6wmSo;uB~'ڳپ; V- ,Ll.~p(|ww;et5ݻ`SHi),_"wAsZ1c`maO>myЈ0;f5߽`޼вO|ڥ)2$|j-ލߎ?_l4tP8D|DѣfN8x-/'w=u+օ{ƶ崢+[^hduL+fͩ_vգ[ȹҖ}: ?U{HiɔۡsGq޽{׭\%ݞD/|:hw곯Z|%Q.1<)-Weddw]Q]]}5wTێb\b؏ zTQw+߽}s1$^H)ɱ]QCtv]+lٶu[UN;@KcP8'p=1z_Kffdڷ݆x 3uΠ_ؿ>3:|_{>]ko-!K Ʌۼ;v;wl(1S=~믾{/--'ڹ=fook\;ꓻgڧ^4-+ g5;͋Cۭ['~Xepc,&%Ӿ-rr"˰aC-]2wάQW^{WK_n_S wqHɴog.]jc\2bD˙3jֿ[hLi˱]zScƍ~' y$ٙD~% ׿o @RI]r޶m{?ݛTV?vf$Ym>\p˖|r^`"+[HB_{ケaܹs}K%%x{ 3ʑ6n'0>o. @2K{fܴ*V\' %qm˱]~\r^_u_ޯO  eN:es)'w?ӏ:*vɽK.]r*)$m J(I[$m J(I[$m J(I[$mRJIDAT J(I[V]](I[$m J(I[$m J(I[$m J(I[$m J(I[$m J(I[$m J(I[$m J_iFiaVZSҳ(_ѕF79<-3oHUힽG. ]dlk>KqF(KkЂvxʧԣKֶj߿k+qfnV₼O+l泜z#[BXR2<Dɴ%z}5Wm7]rkҚYcY0& ƌ˻ Q=7x$}>Q2/PplZ].w%>3~k,5B{j[FL[xsC% [7nִז/i D첤*±-],(_\<"/3=Yr[]+b2 IT|X[ފkWnQ˳9qфₚP&T̚g=Z:5sD~ŃA#sBLK*ddzs&hj0@v-KM+iiah!CHG*hf%% cG梢d-TGq#{ եrBJg+cϞYǦaZQZew9 =ιhD#f_Q>Gt/lR;eaq}>7:X06-cJ[^gN^Vh[OKfvheRAÓɖxg-/nKGW}+g 6yfj͚T0%)߿D ) T\zS٪dN/]+TX7ၗ-,L2&{FfuOO WO,Ө&Z4FfB^wW[~naD_lڛBS9MHviՍh,]]H{~ӲBZ4~`Yқ@L%MHb[/;oPtEfF?8/k# nϬܢ_6=76WJ[=sF>;{ſKW{GyI[I護^smzvFޯޚL`˺\3- @rJִ_X|yH9{Y‹ vKʕD ^:qi'խI'$#fβu׼':{zpX|iK/zV]22uE׮]CJ' >n}va@@3(jb˓O|KiiivZ\8(o Em 4#ږ;'wL.lmٺuϞ=f\v-_xR|XO3&]ڵ{׮]YYBмk[:ed&jޒD?,m[>ڂk=z8ҏ석ݻvox}[Z9S4aO)nd_BPR_7g 8+~acq[`ڴN;uRݛon(|{~W>@Q>b9~ۤMHu;L4:et*SܹKpdt͈ѝN\]SRɞOB8$Uw/linvy:ذfàB??86 IDATڜ>ofqQ3?ϖsӖ'h[.:enҒ)m5vٱWn#[{a{Hiɴo[ox\zGk[n3K¡곯Z|%Q.1<)-w?XkzŔ?:{+}[coO?ci?$ @H3?خ]cXrۨmz<\;UԒm[^UxN<O[;%|{~_ ӟU+^Zdfv @K3x 3uΠ_ؿ>3:|_{>]ko-!K Ʌۼ;v;wl(1S=~믾{/--'ڹ=fook\;ꓻwmӋ&ee8u緾yqhuo~k:߽,Nz%QФdڷSNN46Wv6l貥KΙ5+tUcjZb#;.#m9ޥK^5vKF~9sF8\mu^<)m9kA_{|{lظ18O<$$;ob_߿RH*ɴK۶m{Sʓ.Ќ$mǓ nٲO=3Ldeu I}77l;w?<yIR$ooޜ8SsrF_9rƍ~DSS&ӇͅHft>rs읗RŊ>$$m9kKknKUUUUwIaBs̡ܩSc9gqQG%. w吰K.4C%@-QDI%i @-QDI%i @-QDI%i @-QDI%i @ҪQ%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QDI%i @-QD3.IDATmK2}IENDB`././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/delta_time.py0000644000000000000000000005310615134002420014754 0ustar00# delta_time.py # # Parser to convert a conversational time reference such as "in a minute" or # "noon tomorrow" and convert it to a Python datetime. The returned # ParseResults object contains # - original - the original time expression string # - computed_dt - the Python datetime representing the computed time # - relative_to - the reference "now" time # - time_offset - the difference between the reference time and the computed time # # BNF: # time_and_day ::= time_reference [day_reference] | day_reference 'at' absolute_time_of_day # day_reference ::= absolute_day_reference | relative_day_reference # absolute_day_reference ::= 'today' | 'tomorrow' | 'yesterday' | ['next' | 'last'] weekday_name # (if weekday_name is given and is the same as the reference weekday: # if 'next' is given, use 7 days after the reference time # else if 'last' is given, use 7 days before the reference time # else, use the reference time) # # relative_day_reference ::= 'in' qty day_units # | qty day_units 'ago' # | 'qty day_units ('from' | 'before' | 'after') absolute_day_reference # day_units ::= 'days' | 'weeks' # # time_reference ::= absolute_time_of_day | relative_time_reference # relative_time_reference ::= qty time_units ('from' | 'before' | 'after') absolute_time_of_day # | qty time_units 'ago' # | 'in' qty time_units # time_units ::= 'hours' | 'minutes' | 'seconds' # absolute_time_of_day ::= 'noon' | 'midnight' | 'now' | absolute_time # absolute_time ::= 24hour_time | hour ("o'clock" | ':' minute) ('AM'|'PM') # # qty ::= integer | integer_words | 'a couple of' | 'a' | 'the' # weekday_name ::= 'Monday' | ... | 'Sunday' # # Copyright 2010, 2019 by Paul McGuire # import calendar from datetime import datetime, time as datetime_time, timedelta import pyparsing as pp __all__ = ["time_expression"] _WEEKDAY_NAMES = list(calendar.day_name) _DAY_NUM_BY_NAME = {d: i for i, d in enumerate(_WEEKDAY_NAMES)} # basic grammar definitions def _make_integer_word_expr(int_name: str, int_value: int) -> pp.CaselessKeyword: return pp.CaselessKeyword( int_name, ident_chars=pp.srange("[A-Za-z-]") ).add_parse_action(pp.replace_with(int_value)) integer_word = pp.MatchFirst( _make_integer_word_expr(int_str, int_value) for int_value, int_str in enumerate( "one two three four five six seven eight nine ten" " eleven twelve thirteen fourteen fifteen sixteen" " seventeen eighteen nineteen twenty twenty-one" " twenty-two twenty-three twenty-four".split(), start=1, ) ).set_name("integer_word") integer = pp.pyparsing_common.integer | integer_word integer.set_name("numeric") CK = pp.CaselessKeyword CL = pp.CaselessLiteral today, tomorrow, yesterday, noon, midnight, now = CK.using_each( "today tomorrow yesterday noon midnight now".split() ) def _now(): return datetime.now().replace(microsecond=0) def _singular_or_plural(s: str) -> pp.ParserElement: return CK(s) | CK(s + "s").add_parse_action(pp.replace_with(s)) week, day, hour, minute, second = map( _singular_or_plural, "week day hour minute second".split() ) time_units = hour | minute | second any_time_units = (week | day | time_units).set_name("any_time_units") am = CL("am") pm = CL("pm") COLON = pp.Suppress(":") in_ = CK("in").set_parse_action(pp.replace_with(1)) from_ = CK("from").set_parse_action(pp.replace_with(1)) before = CK("before").set_parse_action(pp.replace_with(-1)) after = CK("after").set_parse_action(pp.replace_with(1)) ago = CK("ago").set_parse_action(pp.replace_with(-1)) next_ = CK("next").set_parse_action( pp.replace_with(1), lambda t: t.__setitem__("next_present", True) ) last_ = CK("last").set_parse_action(pp.replace_with(-1)) at_ = CK("at") on_ = CK("on") a_ = CK("a") an_ = CK("an") of_ = CK("of") the_ = CK("the") adverb_ = pp.MatchFirst(CK.using_each("just only exactly".split())).suppress() couple = ( (pp.Opt(CK("a")) + CK("couple") + pp.Opt(CK("of"))) .set_parse_action(pp.replace_with(2)) .set_name("couple") ) a_qty = (a_ | an_).set_parse_action(pp.replace_with(1)) the_qty = the_.set_parse_action(pp.replace_with(1)) qty = pp.ungroup( (pp.Opt(adverb_) + (integer | couple | a_qty | the_qty)).set_name("qty_expression") ).set_name("qty") time_ref_present = pp.Tag("time_ref_present") # get weekday names from the calendar module weekday_names = list(calendar.day_name) weekday_name = pp.MatchFirst(CK.using_each(weekday_names)).set_name("weekday_name") # expressions for military 2400 time _24hour_time = ~(pp.Word(pp.nums) + any_time_units).set_name( "numbered_time_units" ) + pp.Regex( r"\b([01]\d|2[0-3])([0-5]\d)\b", as_group_list=True ).set_name("HHMM").add_parse_action( lambda t: [int(t[0][0]), int(t[0][1])] ) _24hour_time.set_name("0000 time") @_24hour_time.add_parse_action def _fill_24hr_time_fields(t: pp.ParseResults) -> None: t["HH"] = t[0] t["MM"] = t[1] t["SS"] = 0 t["ampm"] = "am" if t.HH < 12 else "pm" ampm = am | pm o_clock = CK("o'clock", ident_chars=pp.srange("[A-Za-z']")) timespec = ( integer("HH") + pp.Opt(o_clock | COLON + integer("MM") + pp.Opt(COLON + integer("SS"))) + (am | pm)("ampm") ) @timespec.add_parse_action def _fill_default_time_fields(t: pp.ParseResults) -> None: for fld in "HH MM SS".split(): if fld not in t: t[fld] = 0 absolute_time = _24hour_time | timespec absolute_time.set_name("absolute time") absolute_time_of_day = noon | midnight | now | absolute_time absolute_time_of_day.set_name("time of day") @absolute_time_of_day.add_parse_action def _add_computed_time(t: pp.ParseResults) -> None: initial_word = t[0] if initial_word in "now noon midnight".split(): t["computed_time"] = { "now": _now().time(), "noon": datetime_time(hour=12), "midnight": datetime_time(hour=0), }[initial_word] else: t["HH"] = {"am": int(t["HH"]) % 12, "pm": int(t["HH"]) % 12 + 12}[t.ampm] t["computed_time"] = datetime_time(hour=t.HH, minute=t.MM, second=t.SS) # relative_time_reference ::= qty time_units ('ago' | ('from' | 'before' | 'after') absolute_time_of_day) # | 'in' qty time_units time_units = (hour | minute | second).set_name("time unit") relative_time_reference = ( ( qty("qty") + time_units("units") + ( ago("dir") | (from_ | before | after)("dir") + pp.Group(absolute_time_of_day)("ref_time") ) ) | in_("dir") + qty("qty") + time_units("units") ).set_name("relative time") @relative_time_reference.add_parse_action def _compute_relative_time(t: pp.ParseResults) -> None: if "ref_time" not in t: t["ref_time"] = _now().time().replace(microsecond=0) else: t["ref_time"] = t.ref_time.computed_time delta_seconds = {"hour": 3600, "minute": 60, "second": 1}[t.units] * t.qty t["time_delta"] = timedelta(seconds=t.dir * delta_seconds) time_reference = absolute_time_of_day | relative_time_reference time_reference.set_name("time reference") @time_reference.add_parse_action def _add_default_time_ref_fields(t: pp.ParseResults) -> None: if "time_delta" not in t: t["time_delta"] = timedelta() # absolute_day_reference ::= 'today' | 'tomorrow' | 'yesterday' | ('next' | 'last') weekday_name # day_units ::= 'days' | 'weeks' day_units = day | week weekday_reference = pp.Opt(next_ | last_, 1)("dir") + weekday_name("day_name") absolute_day_reference = ( today | tomorrow | yesterday | (now + time_ref_present) | weekday_reference ) absolute_day_reference.set_name("absolute day") @absolute_day_reference.add_parse_action def _convert_abs_day_reference_to_date(t: pp.ParseResults) -> None: now_ref = _now().replace(microsecond=0) # handle day reference by weekday name if "day_name" in t: today_num = now_ref.weekday() day_names = [n.lower() for n in weekday_names] named_day_num = day_names.index(t.day_name.lower()) # compute difference in days - if current weekday name is referenced, then # computed 0 offset is changed to 7 if t.dir > 0: if today_num != named_day_num or t.next_present: day_diff = (named_day_num + 7 - today_num) % 7 or 7 else: day_diff = 0 else: day_diff = -((today_num + 7 - named_day_num) % 7 or 7) t["abs_date"] = datetime(now_ref.year, now_ref.month, now_ref.day) + timedelta( days=day_diff ) else: name = t[0] t["abs_date"] = { "now": now_ref, "today": datetime(now_ref.year, now_ref.month, now_ref.day), "yesterday": datetime(now_ref.year, now_ref.month, now_ref.day) + timedelta(days=-1), "tomorrow": datetime(now_ref.year, now_ref.month, now_ref.day) + timedelta(days=+1), }[name] # relative_day_reference ::= 'in' qty day_units # | qty day_units # ('ago' # | ('from' | 'before' | 'after') absolute_day_reference) relative_day_reference = in_("dir") + qty("qty") + day_units("units") | qty( "qty" ) + day_units("units") + ( ago("dir") | ((from_ | before | after)("dir") + absolute_day_reference("ref_day")) ) relative_day_reference.set_name("relative day") @relative_day_reference.add_parse_action def _compute_relative_date(t: pp.ParseResults) -> None: now = _now().replace(microsecond=0) if "ref_day" in t: t["computed_date"] = t.ref_day else: t["computed_date"] = now.date() day_diff = t.dir * t.qty * {"week": 7, "day": 1}[t.units] t["date_delta"] = timedelta(days=day_diff) # combine expressions for absolute and relative day references day_reference = relative_day_reference | absolute_day_reference day_reference.set_name("day reference") @day_reference.add_parse_action def _add_default_date_fields(t: pp.ParseResults) -> None: if "date_delta" not in t: t["date_delta"] = timedelta() # combine date and time expressions into single overall parser time_and_day = time_reference + time_ref_present + pp.Opt( pp.Opt(on_) + day_reference ) | day_reference + pp.Opt(pp.Opt(at_) + absolute_time_of_day + time_ref_present) time_and_day.set_name("time and day") # parse actions for total time_and_day expression @time_and_day.add_parse_action def _save_original_string(s: str, _: int, t: pp.ParseResults) -> None: # save original input string and reference time t["original"] = " ".join(s.strip().split()) t["relative_to"] = _now().replace(microsecond=0) @time_and_day.add_parse_action def _compute_timestamp(t: pp.ParseResults) -> None: # accumulate values from parsed time and day subexpressions - fill in defaults for omitted parts now = _now().replace(microsecond=0) if "computed_time" not in t: t["computed_time"] = t.ref_time or now.time() if "abs_date" not in t: t["abs_date"] = now # roll up all fields and apply any time or day deltas t["computed_dt"] = ( t.abs_date.replace( hour=t.computed_time.hour, minute=t.computed_time.minute, second=t.computed_time.second, ) + (t.time_delta or timedelta(0)) + (t.date_delta or timedelta(0)) ) # if time just given in terms of day expressions, zero out time fields if not t.time_ref_present: t["computed_dt"] = t.computed_dt.replace(hour=0, minute=0, second=0) # add results name compatible with previous version t["calculatedTime"] = t.computed_dt # add time_offset fields t["time_offset"] = t.computed_dt - t.relative_to @time_and_day.add_parse_action def _remove_temp_keys(t: pp.ParseResults) -> None: # strip out keys that are just used internally all_keys = list(t.keys()) for k in all_keys: if k not in ( "computed_dt", "original", "relative_to", "time_offset", "calculatedTime", ): del t[k] # delete list elements - just return keys del t[:] time_expression = time_and_day pp.autoname_elements() def demo(): """ Demonstrate using the time_expression parser, and accessing the parsed results. - parse a complex time expression - show all fields that are accessible in the results - show an example of using one of the results fields in Python """ # - parse a complex time expression example_expr = "10 seconds before noon tomorrow" result = time_expression.parse_string(example_expr) # - show all fields that are accessible in the results print(f"\nDemo: Results of parsing {example_expr!r}", end="") print(result.dump(include_list=False)) # - show an example of using one of the results fields in Python print("Computed time:", result.computed_dt) def run_all_tests() -> bool: import itertools from typing import Dict def make_weekday_time_references() -> Dict[str, timedelta]: def offset_weekday( day_name: str, offset_dir: int, next_present: bool = False ) -> timedelta: """ Compute a timedelta for a reference to a weekday by name, relative to the current weekday. If the current day is Monday: "next Monday" will be one week in the future "last Monday" will be one week in the past "Monday" will be the current day "next Tuesday" and "Tuesday" will be one day in the future "last Tuesday" will be 6 days in the past ... and similar for all other weekdays """ to_day_num = _DAY_NUM_BY_NAME[day_name] from_day_num = current_time.weekday() if to_day_num != from_day_num: if offset_dir == 1: return timedelta(days=(to_day_num + 7 - from_day_num) % 7) else: return timedelta(days=-((from_day_num + 7 - to_day_num) % 7)) else: if offset_dir == 1: if next_present: return timedelta(days=7) else: return timedelta() else: return timedelta(days=-7) def next_weekday_by_name( day_name: str, *, next_present: bool = False ) -> timedelta: return offset_weekday(day_name, 1, next_present) def prev_weekday_by_name(day_name: str, **_) -> timedelta: return offset_weekday(day_name, -1) # add test_time_exprs for various times, forward and backward to a weekday by name # define lists of expression terms to generate permutations of times, weekdays, # and next/last times = [("noon", 12), ("2am", 2), ("2pm", 14), ("1500", 15)] rels = ["", "next", "last"] weekday_rel_func = { "": next_weekday_by_name, "next": next_weekday_by_name, "last": prev_weekday_by_name, } weekday_test_cases = {} for (timestr, timehours), rel, dayname in itertools.product( times, rels, _WEEKDAY_NAMES ): next_or_prev_weekday_func = weekday_rel_func[rel] expected_offset = ( timedelta(hours=timehours) - time_of_day ) + next_or_prev_weekday_func(dayname, next_present=rel == "next") # times such as "noon last Friday" or just "noon Friday" weekday_test_cases[f"{timestr} {rel} {dayname}"] = expected_offset # times such as "next Tuesday at 4pm" or just "Tuesday at 4pm" weekday_test_cases[f"{rel} {dayname} at {timestr}"] = expected_offset # times such as "next Tuesday 4pm" or just "Tuesday 4pm" weekday_test_cases[f"{rel} {dayname} {timestr}"] = expected_offset return weekday_test_cases # get the current time as a timedelta, to compare with parsed times current_time = _now() time_of_day = timedelta( hours=current_time.hour, minutes=current_time.minute, seconds=current_time.second, ) # generate a dict of time expressions and correspdoning offset from # the current time # fmt: off test_time_exprs = { "now": timedelta(0), "midnight": -time_of_day, "noon": timedelta(hours=12) - time_of_day, "today": -time_of_day, "tomorrow": timedelta(days=1) - time_of_day, "yesterday": timedelta(days=-1) - time_of_day, "10 seconds ago": timedelta(seconds=-10), "100 seconds ago": timedelta(seconds=-100), "1000 seconds ago": timedelta(seconds=-1000), "10000 seconds ago": timedelta(seconds=-10000), "10 minutes ago": timedelta(minutes=-10), "10 minutes from now": timedelta(minutes=10), "in 10 minutes": timedelta(minutes=10), "in a minute": timedelta(minutes=1), "in a couple of minutes": timedelta(minutes=2), "20 seconds ago": timedelta(seconds=-20), "in 30 seconds": timedelta(seconds=30), "in an hour": timedelta(hours=1), "in a couple hours": timedelta(hours=2), "a week from now": timedelta(days=7), "3 days from now": timedelta(days=3), "a couple of days from now": timedelta(days=2), "an hour ago": timedelta(hours=-1), "in a couple days": timedelta(days=2) - time_of_day, "a week from today": timedelta(days=7) - time_of_day, "three weeks ago": timedelta(days=-21) - time_of_day, "a day ago": timedelta(days=-1) - time_of_day, "in a couple of days": timedelta(days=2) - time_of_day, "a couple of days from today": timedelta(days=2) - time_of_day, "2 weeks after today": timedelta(days=14) - time_of_day, "in 2 weeks": timedelta(days=14) - time_of_day, "the day after tomorrow": timedelta(days=2) - time_of_day, "the day before yesterday": timedelta(days=-2) - time_of_day, "8am the day after tomorrow": timedelta(days=+2) - time_of_day + timedelta(hours=8), "in a day": timedelta(days=1) - time_of_day, "3 days ago": timedelta(days=-3) - time_of_day, "noon tomorrow": timedelta(days=1) - time_of_day + timedelta(hours=12), "6am tomorrow": timedelta(days=1) - time_of_day + timedelta(hours=6), "0800 yesterday": timedelta(days=-1) - time_of_day + timedelta(hours=8), "1700 tomorrow": timedelta(days=1) - time_of_day + timedelta(hours=17), "12:15 AM today": -time_of_day + timedelta(minutes=15), "3pm 2 days from today": timedelta(days=2) - time_of_day + timedelta(hours=15), "ten seconds before noon tomorrow": ( timedelta(days=1) - time_of_day + timedelta(hours=12) + timedelta(seconds=-10) ), "20 seconds before noon": -time_of_day + timedelta(hours=12) + timedelta(seconds=-20), "in 3 days at 5pm": timedelta(days=3) - time_of_day + timedelta(hours=17), "20 hours from now": timedelta(hours=20), "twenty hours from now": timedelta(hours=20), "twenty-four hours from now": timedelta(days=1), "Twenty-four hours from now": timedelta(days=1), "just twenty-four hours from now": timedelta(days=1), "in just 10 seconds": timedelta(seconds=10), "in just a couple of hours": timedelta(hours=2), "in exactly 1 hour": timedelta(hours=1), "only one hour from now": timedelta(hours=1), "only a couple of days ago": timedelta(days=-2) - time_of_day, } # fmt: on # add expressions using weekday names test_time_exprs.update(make_weekday_time_references()) def verify_offset(test_time_str: str, parsed: pp.ParseResults) -> None: """ Function to compare computed offset time with expected offset as defined in times dict. """ # allow up to a 1-second time discrepancy due to test processing time time_epsilon = timedelta(seconds=1) expected_offset = test_time_exprs[test_time_str] offset_error = parsed.time_offset - expected_offset # add helpful test results in case of a test failure parsed["_testing_expected_offset"] = expected_offset parsed["_testing_observed_offset"] = parsed.time_offset parsed["_testing_offset_error"] = offset_error parsed["_testing_abs_offset_error"] = abs(offset_error) if abs(offset_error) <= time_epsilon: parsed["_testing_verify_offset"] = "PASS" else: parsed["_testing_verify_offset"] = "FAIL" # run all test cases print(f"(relative to {_now()})") success, report = time_expression.run_tests( list(test_time_exprs), post_parse=verify_offset ) assert success # collect all tests that failed to compute the expected time (relative to # the current time) fails = [] for test, rpt in report: if rpt._testing_verify_offset != "PASS": fails.append((test, rpt)) if fails: print(f"\nFAILED ({len(fails)}/{len(test_time_exprs)} tests)") print("\n".join(f"- {test}" for test, _ in fails)) else: print(f"\nPASSED ({len(test_time_exprs)} tests)") return not fails def main() -> int: tests_pass = run_all_tests() demo() return 0 if tests_pass else 1 if __name__ == "__main__": import contextlib with contextlib.suppress(Exception): time_expression.create_diagram("delta_time_diagram.html", vertical=3, show_results_names=True, show_groups=True) exit(main()) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/delta_time_diagram.html0000644000000000000000000032446515134002420016765 0ustar00

time reference

time of daytime of day relative timerelative time

time of day

noonnoon midnightmidnight nownow 0000 time0000 time timespectimespec

noon

'noon'

midnight

'midnight'

0000 time

numbered_time_unitsnumbered_time_units [NOT] HHMMHHMM

numbered_time_units

W:(0-9) any_time_unitsany_time_units

any_time_units

'week' 'weeks' 'day' 'days' 'hour' 'hours' 'minute' 'minutes' 'second' 'seconds'

HHMM

\b([01]\d|2[0-3])([0-5]\d)\b

timespec

numericnumeric 'HH' o_clocko_clock COLONCOLON numericnumeric 'MM' COLONCOLON numericnumeric 'SS' 'AM' 'PM' 'ampm'

numeric

integerinteger 'one' 'two' 'three' 'four' 'five' 'six' 'seven' 'eight' 'nine' 'ten' 'eleven' 'twelve' 'thirteen' 'fourteen' 'fifteen' 'sixteen' 'seventeen' 'eighteen' 'nineteen' 'twenty' 'twenty-one' 'twenty-two' 'twenty-three' 'twenty-four'

integer

W:(0-9)

o_clock

"o'clock"

COLON

':' [suppress]

relative time

qtyqty 'qty' time unittime unit 'units' 'ago' 'dir' 'from' 'before' 'after' 'dir' time of daytime of day 'ref_time' 'in' 'dir' qtyqty 'qty' time unittime unit 'units'

qty

qty_expressionqty_expression

qty_expression

adverb_adverb_ integerinteger 'one' 'two' 'three' 'four' 'five' 'six' 'seven' 'eight' 'nine' 'ten' 'eleven' 'twelve' 'thirteen' 'fourteen' 'fifteen' 'sixteen' 'seventeen' 'eighteen' 'nineteen' 'twenty' 'twenty-one' 'twenty-two' 'twenty-three' 'twenty-four' couplecouple a_qtya_qty the_the_

adverb_

'just' 'only' 'exactly' [suppress]

couple

'a' 'couple' 'of'

a_qty

a_a_ an_an_

a_

'a'

an_

'an'

the_

'the'

time unit

'hour' 'hours' 'minute' 'minutes' 'second' 'seconds'

on_

'on'

day reference

relative dayrelative day absolute dayabsolute day

relative day

'in' 'dir' qtyqty 'qty' 'day' 'days' 'week' 'weeks' 'units' qtyqty 'qty' 'day' 'days' 'week' 'weeks' 'units' 'ago' 'dir' 'from' 'before' 'after' 'dir' absolute dayabsolute day 'ref_day'

absolute day

'today' 'tomorrow' 'yesterday' 'now' next_next_ last_last_ 'dir' weekday_nameweekday_name 'day_name'

weekday_name

'Monday' 'Tuesday' 'Wednesday' 'Thursday' 'Friday' 'Saturday' 'Sunday'

today

'today'

tomorrow

'tomorrow'

yesterday

'yesterday'

now

'now'

weekday_reference

next_next_ last_last_ 'dir' weekday_nameweekday_name 'day_name'

next_

'next'

last_

'last'

at_

'at'
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/delta_time_diagram.png0000644000000000000000000133702015134002420016575 0ustar00PNG  IHDR{)MIDATx |T7.y[D[Vbw Q{`؂v_֮V%tj[KlQb/k,å-mMVPWfN2$!~^W^V4-)<5x鲍;ee%ۂ^-Ԅ󮹷a֟ yO-[~3㳛|cG+l1a\:Cn}(f0슫'}!<1Dw|3sEcԲENѶĄҘ:/ٹe5吞i U37-n[ڣfV 33Gwx8ˊĦꪇQW,wWx9ct9fEã[-*IqrEevAΜj^jz4{.g-0hTpF'pߙ uA=(?{T'MpV[6S.uͻNAhxퟍg{LS/{mEyJտ@Hu$ҍv}Fӣ.HEC%zǮ Mv-]vSpFuҫgjki 5UsZ(6zGg]T%go-l Xme&/ܜGiyKn4y'ogc7<doܧm5'k}ѕQɕ7iG8;??~6UU5#s[c]՜쌌9|KZ{L^79vFSc]u圢đfݱQOTuumM<3;!]R-Lp59\{Hdg:qliM4U\sCxvБ1WTJFKKKY[:v )꧚*c/>P}yP̭QD>=xtђ-]=m|jd1Yͼzᲆw$@SVcw]:m|޺QYYYλVPxz+Μ]>nƴKj^nveLք Wl|`f9gVn H7=%ӓUhD=xCYtKTJ@RLO.>x9 M/Otݪ5OF h @,h @, `bA `bA `bA `bA `bA `bA `bA `bA `bA `baW@yԘd 0  0  0  0  0  0  0  0  0,[jۺb}S8]0ᴂȌ92`---]x_reǾ ƦOpXyԘdihה_+t1N{W_vүxǎ5kff _8SǍ7ٳg_7mk}>3Y#8"pP Ph?6óLܛ}gg?Sp0 BiHϕ/@ʻG_yÇydo@R:{ZǰѣGǽJ] h0͛'? Hq?HToخ]!5{\ 6_t޹? 9( ƍ+V??ӟ7tQGN:gN^tJNN0)]6*y1>?%=_ܳh;3Iرㆯ~78L^yMŸy?ο~ԨQ@IVQagĒ!2`ɓ[+lnx[3|[wI owg[>( [*3*m'ߌNwΝ8&OKqpgg?Ƈ{}J)i(|wSzQ߹/*0rtLz04CɀmgiyEv GyTrY }9v;,5'+&M:=Z`tLz4+~I_Fe`(s1O|\e<ώ}[~flM ^Qy[+n6nr-zjoJ}jwc-QyQ]'= &}׷IC@3$voGO~ >O\|qT{Ѣ74зC@k?~o޼b a#Ɛz?MMMկW}!8ds ap>߆?4ЇC@>˯x #Ɠz'aR kW-!c}{8∨7g>,ISR@ k׮4>ZFGORC^caÆMiJM 0iŗZ0kk׮SJf~<'g|߉'0HwtsDRW /@&vZ[ }GvaOO#lR{Lh0<IDATc,]8q a#lp@0C\1oMA0:"pF{0C\Z!ltDpI1 @7`Cx]Ght,a;*`(uֿ He@G!~ v\wm-o?GG-7R0h (*9o,eۮ33@'jd 1##lХz۷]~\ݻÃ!1I&E#I!*#_[2_sy6Il{~t ox[ \rժ0}S j.>mĽxݺQ!++%W|2^ٸ1*}Ajnc枯s o;;.*n˿z7\ptw /T}OM0͡{_&*mѣGGo wD Po][o~.Ҧ 8;;+ N1o0K3o4LmEK?4.>ܫ0L>>[f۾}GIfCZwPq&=psssҥQ|$ 62Mvvvc7n=`ȹzR -3ȥ+<:ԇ*4_:`A~7/tmOfUWEݾ's?Srr‹/ϴ}`XwvCYwt nFy_ɧ;322~pQ~^FUsӌ_K(Nѿ/8K/~EbqS0X  o_Ï}_ھӖ<+A?j7* mɿhWZ~åE_vS8 fAMPѻ!t@ _rgQpnռrkM7^, qKVA^CYw0uQa`9_kv W,{/Ԃ/|sQ[UU53}3U|ǝ˞}_L\kupѕuA+gucǎ;i/1^e^Y_֓߷Y{n\39*t-a=蕷UfpN8oDUn4"y7o yU[;LQ(hmtUSrJX״dyƈ• 9wv͞# Z4m{Qxcu{ڭM55nwU-_VTEO6J|fxvq5vlX:~qoȁFzlB300.yR'`P=t:SWNxt|AK:\['(,>.Jit7Cq7B w/+LJ}u񡢋'zbVU~8ɦگ}uboܽ-;10Ȥ0H}es杩mԳ'e_oNzQRˎSM?k.kk\TU7@w'}OxEAT%Rr1DsSպ^`A}Kcbçt㼆]=UͩP f-OGMT֚+av^'gϚ5{,}v]VYdXlB~8ϻ/OAAtAI~XO^k]zJ\m/t'E$?QM\vWbZw'>M;:ƣFm#*| ~=i~-rcOzgO^v)6<#.[ Ou8K7{MmOѭ;mL/m}yt/k;Zֿթ(Qb륞^zoA_Q%~OݚֽuOH^>^l\އɶe%E.ֹJ@CAEЮ>T}.0L&o'_qopEޫ?daȶ|SG[3)ִN\\*#jɏ8b+ߕ-KL|~Ro}V[[u4iDPj7H3ʼn1!鹧7'Y"썚궆 yFU L>u{b\&.SEV[6lVvFUmVMv(a;^ľk?8~VœA] ]6x?pU_򖷴ueW\>?Z~՛7o~{NXx캶*>SϺxpy76˺V%.yk'du͍5T01w}hԈc}vXGL}HO/Uy1lK//'mBȝ[o>?dé5z/j CqM{F>T_^э5$m9_C&y=׍T|KEmX"&?*R~I-sc}t\m~;m۶ +x'YðÆ +79r ~.d}uG/k]볽D vwÁ_}p(zƒLNRWfh|89}{ɯ`z6r~;)Zw1\z>|3>|{SrN)rbP }Į tg:JK5y=z_#=5W ;2U %\{HnkyP˳ۿ T׸'ڶw%>$*Bg I=NNUv.#Ɵ|k=gMM/ye߱giOR)yo^]|B$oOF +BjT{/~p/k9hwɾNB83dv{ Wٚ?ڟwzG^G]_xNU[6:w4y1I{wN!giʨ|G~;W}?uɔ_ U|ZQpݧ]]GZ:8wgSJtnرàS_+U>e#Ovث;R]_ ;j-#Z\zjZOBCihݹ}WĒAo\S~]w={Jf~<8x=hw ^$5{[ʂr=*z>sĒmю:~oo,OQ[b]w3yȝ`(^6~Ň.ںk{$[sr=C&n޼%,s1x'kX'X043<A{'5錕|ͳN۰aCX7ng ><8HבU op8;?~˨{IDAT^5gnT~~0P@xhF'Æ [*' 3$o%<,vT.yiDp:D0iR3~|yG^T & _**_}n Ч:+!B߽/,箼`hپ}qǟ6ee l` Y^P{~bov{T83['`:C:%'',K.Ψl``!k o_W=ė%֯piezN+`ljAU|ǝ˞} mر#:`ZKs03s̷)` qwyEk<=9r>{g)99#Fxx}n֭'|a95߫^T J:AH ξ~xU@z}}9`% 4wG\/ _y`N F|hTo޼^9%gJ5@x>%X^4w]{eh xysýWO ~_UTt7gNFg-+ ONܣ:nMset]Z۾r(}nn);;$763rNaNf릋+)v%E{oתm<Gi-ٲutMţzN`gcی:;Vu9K6欔,*-;m%ۺ9ܥ>\|p ;??ȺtŖ%E0c/~"3WT܋vՔ 73vŹ?Y[W[Vnc77s8ű)|o z؋{G񨬬bKuQfhʭO]ՏWf>|V~=9\T{5ʦ}O>psKGMo(65kl41޻yGSWg=+RMK mMJ'^lc ]zbbRGݖ~]ḽc9ȭgl*jMc-|-oIL޾99u֟l1i8pogɳ|MpLbK;Tn-ɉ>뼶ͷ~li38=WU]:vt=6F̺8,>UW%9}gue'K'^ӰeIqN 9K֮Vۗm7'^hWŕUWVثc2w_%g:f]frʗ$LVV$:*i?-gΩ_8!9cܲ%M]m4h[#<\iƽx Y5X۶hۢ(Ʊ}LzwfNJF]S_əEUU%KQ'/Xqovi]X][ϺtٖyMו&Nl}eӻkII9s\y ޲fgV6[.\[uwª%F;(-8œ>zzck뢪`dr[yÜчX}3^iK}}O_ylƕlo AҸ6{Ba~W'/-Biр@̥I& 2 tN '^Nc׭.|`Gw[owΌկ=ƒ5G->EQZz֒c߭痖F1?TV+gLNnrfdWm k Apv~~wMUuMXW50;###{Nwԛ]Z9vFSc]u圢đ ]Kn=9Uk[VіP{seUɎv-(i[QKmyQ9w?O53$-;;]̺DME^6t/='5sYM~_T}v4$ XUۻ{;>8k+r&^#\[]nu,M5%qgϰ[?m'-˝~ݬ2꧶%z/Ϟrkwv.|`mMIsSrrA)=~_ξC0|:QFpyԘxjaN%NpZ _ޱcG3VY=spi7n' m۶fo~h+jkaUp/ '?%u֔){~C8∟Q <SwW1볟y ( 4 ߺ**L{ndQ׿MOC:V◿ G{6,{L{>qQ7 !QO0X]Gzn׮] 0"H™gܷUf@/_[=#ް6nl͝Rq-ƫ@K5O>AlذaS'GߵjW:vo-QጼmҤIX]X~@G.|s^oGuG\ݲ:/{ហWyqQa Ao]/$/iw ^n}k 9昨p(=<}>ܫn.~#^vvĉQni|K>]m< IDAT?9W]v'4t͓O=wfddyäaި֟nQz}gK/Aq3}zj^~_m*fP_Θ|=s\=%??8d;Ȳb+E-W'MzZ]v|0{:ꨰT0휯]vӬs[}P+%rZ tX[_OկMM Mn\}&O\VPZfOԛw.O^Vٳ~}YS'{AXL.XPûw"2d^[*38'ps=S V:@]X/Qaʈ• :ʾqxv͞}6]ֲ|V򪶶M>lsiJjApӌkd] &tSWi7jvN;=G/_UsO+xyq'tR3O/:%'ge~ӟ]|ɧ^{ `jtj]9,NEkNms_Ļe_XCQAn/,l ׍j ;OgK=umݦFf%$8h=Ra(ꥩGN׿͌\?/}I k~9lAɒnOZZHۧT8iN]ѫ*44}?>|q z 4ɬ-߾GqĎ;3 >؀!gڵQ3  6lJ?CQss4V03H}_|]%]㾔z-sѤI뱺Chk J/RT8#m<¯~!gݺQ!+++8x%8,L8c u[pvvo0C'}>ܫַ~`HI@ ";;{ܨnB.~# 2窫‚n_C›oyɧKmǟ|>҄L}gK/7 t͓O=wfdd&`ѿ/稣 MMM _۵kW@z/9w߳(z8wSHa\3^{e{G.O[oTmnޱ1޻yGSWg=+VkZRx5''^lc.=11K%5VN5טi׬Hm}Փ35{,|\x"ʎO=0k?ˏ/Lʚvl1v s[^~+v GnX %ұYWVǻ$.dk,)Iљ9K֮z%A4]$߲-uEUo\8!`vщ,!\雁:mե3pccf4>}DS4-S}!1:rZ&eTEfZZvCF΍7G3(aV.scSuUF]SdfQUUT [_YlNrޕTQ56T==99ge-[ΎN妵YrE2G?{kyu|[[`ʲspϬ]wsm5n ޖ䭶KمJں-A[[=}g.,Z;J s~}xW~ahY[ڊ4 HxGCnmogcUa\7]T%go-ʮPپm-+ʊ~[Z*x[MEesI[TD _bK±mwT vv)vЗ]twxeu?= Ptƺ9ى1o.zc=%Nm㶝XW]9(7qkvim)V${X޾tzNQIl-/;}i"Y] <{ı5TWYs]km]}t;mY[SYsĸOwT;VӪTCZFKKKY[:vwuSMASuѱި_2zNEKo+k沚)s7=qoiH K(?j?}՘MŹ w6E{^[3Ml+|Fk{=Rި R[JQw%,sJT;抧U H8Lzx%[6/z@cOye H߁0:tQ&w5w7]RӴc㊅3'>fKؼ}Cyޫ=1Yf.\񁙝͙S-p5w=ŲZLA3m̉jUq #.~(Q:kK0K7'op5/i20xtF)>M~։9kM 0`bA 0  0  0  0  0  0  0  0  0  0+`ߪ 7wqoT8)|85uk'̷zݵF MXXX~ o^>|oԂV5{Yuu[SF/_6uM37EӃyfe-gW˟Z'QX|t]Mrv-؃Øt-qa=6qY}Aի[V^Y̞qSbVX29y',NxF캬Ջ_ȟ7f5Y ٭7듅5 aʝ_gD] %f-֚ʼn`)}nV4cⲻ GYu[C۶F͚͍ @mNL|rnhϞ=.XxƗuXfgo&E8GO~UȜIgY&LAoxx# UᰌqM<}fu֔.Wz[- px #F|ǵ+-gM8)`4i~msg`m.nwwUsڧ߱cO|e>/@M/KGOOEU[5!ѵUUSX xsuS2Ÿ=,o)Z7貖DKU=f{|n~7}ɒ_C`i;Ɏnll߷m0qYwfn;So݁wrSs9/CHt5zacF-Z - /_7lX◇tLs!'mAz^v7*_7CNiMsssT}FnWھn+}5*#4 zY0---]x ֿʌ e[׊Οrժ xxq<oOcƌgȣl}BnUK `bA `bah4h`IE 00,HCz@jii nll|x0g^/۷QyQPz7n=UV Ui_|O~FM}ⱺ+3ҵǣUOv֭Čw^x!2?_gGVԂVlgdT53uDe;q[1qW˟Z'QX|t]MrEDu yUQH#s&9Gu/i`7*\=&SݩQpo|`dtckνT_  J5ϟW$nߝ?/и*)׺@^r`;z ԯ, jfGC^$n fC֍JDWnN훘Z]U7;9ev͞O+7vGewLt\+(قu 7ZҮC;ϞY]ד :twଽ{IdU]ؾ#1%sAmd}b@Cw10}I>f5}M x+P @L ,5Ă @,Ă @,]-7R &e[!7ߌ xÆ zj.pype^ oy[hXoЧ^}ը0r`(J^K۷oߵkWT>mGCQZknn#߸TY 00Te~>]CXw uiCxK\ph֯pieJ ]p[UUΘ3 oǎ_i/#CZZt۸isΟ>쳦OΟ<9[[n/W?䓏 ˩O&2?_gGVԂVcռu{G4%,\ks/[ܬ X<#*܈• 'U%E&vUf?=pw !--@y[+ny. o=ukW^ݲ0}ĬfM;խӛFkf-_Y~ߐ}c}'2fϦQIDAT-*L VC]7;*>QxdabNV476 nl c&.Yݫ k >Y02xqͼDoSMkwٗ \ʞZ@ e蔰*3?A-7R&u. \WS1rOD~. zտl 8i\=zT0e>QqӦ|lՈw֟OYɂd!=*ٗϊ .zJwv7j,|Vп6nyļ3Ó|$rGyK>ӟ,zȊOȨjJ2~AAuX~Jxv͞}6]WmrXG\󲚇?|}}>Ҳ#|Zq; Zlw Ɇ-Y7(XPneˎk ,*ٴd[ֶܫUhY]|~^s .-k#+?Szi?Oyi8HV',2Q~YOo][kI^{m#EMn[ajZW=;/)*=}n25&^һM\lFFUp_센y3)5kUy^uRU=ewݮ:܆yf%#t]_:տ$:}pJb0̞qV/nsWp쉪8]HP* CM >nWf1 @ Ă @, yytX_˶C 0  0  C3?cUmV<}S S @,$޽;*><)?/6lpꩧd{R 85ukzƍQ裏aA8c ԺBvvV0S817*_/۷wTΛ s`hK| KGqQ3R MЇN /ҧK?p{;W}!)>| '5yCz87\ZzYU9ӊ/ )|ߪtgiŪyC=viǎ_i/1^tO0t8SOEqӦ?}gMϟ?yr{날ԉWC֭[O<#+jrj{v/0eN^ Vŗ|?YaU*sx yU[;LQ~pΌW/>YiF}1pe}v|fZɲGͮ# _UU'1yd] &&h(v4}퀻֓q=pwNa0XyԘYȑGw!+ G$SO[<,/_}cv2^T<"cW:oT^Usᢖh; FK6gUX(~ru`w]՚YѬUˆ;M%gX\-~f%oϚ5!(U?_ܕ)zŸ'|2 G9ark\uߪ:7j^%ù9YA]켌䴰:eA첶Y.Z7A*#jb/6&*-fm5˳Zܫa{/f~㟺䓧vjidUg.+ :M/:F`zYVͻÐj5V9Gu-۬z=ZXZ6/#=5W]|B^^nm.ZZ[\ﵻʋVj u`kՌZ;Sr/M7Ku{:w p(XpWqyyZ=Z.1JvU5j^:{Լ¬DXͿhQՉU@k Ru# :Փ.{Hj]捚ݮ•{X sųoW*aﺛV|nGYk0`b=Erؤvyy'ߩ>,dh00\`bB 2ZZW0yԘ `bA `bA `bA `bA `bA `bA `bA `bA 2ZZZ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  ;xtFښև9uM[s%٭k-*iܹR[YZwۅUuM/NKFɒ±{_q[hiizN^Юn֝p99{C],ukkJ;NV_^4֧X<|Sу0O3sŖ쒚-OMȺލ/fB8aܢl-ɉ|bpᆻ. '5?tqNIm(v͊/o\q̧oRXٶ3:Z K_ @ ra kcMiN<:d}foY]:}0[f' -i\13 aJ-.Mߣf.RWQ-STYqa"` rKV=Wn?< k= oؾxtk-mSJuEUyvAfQu®5 ɕŝ.̩+Y jm̊ G-[ROklmŅ].,*N~.{K}]%E],]XmaZiިV^BGe5v5{m]}؜Mu]em cK$o}֒}"pce;~)M**KN̯|ýWO?uҨ ]soMo(i gN:ii.\yGceQf}c50 0Hp Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,~kl# !jXXXXXXXXXH\j mqw5aigѿ(``et9W/~ٗͻO:o/> vQc!o _`ݻvW~6lW}[Vjb>2«vs{bǎ5ky%.;]'kl`Ҹevo{w_J43xd8∠WT f8<ڏͼxEmm0 {G{t>6]׮Z=/}ྌ =7,H+@*\UxJÞÇydo@?K_oOOtw~a,曗~o6,7v3k$5=NrEQ5z-KoI$;_DX7oO~П)C. q+pATN=5I:k[;:uʩZOSOOF飹9*6-{c ZHs~ NjԂVvq?ŅoĔ_a'07i杫JdIUK_'&]qUs~qhslnL:%*455 T0H{ă+ goe~1'jw[r%UkÖow]b nU&g9WcQb<} Ŋ6Jy?)wΏZߛZDO`ݖ0M'~;g?^dj[VJnՖæ@NzBXߞ;d g 6^wҽ}bSCk O ĉ(_-tz}4`aG][~Aι.ozޏ%vu-? .ȸ=/n^ VǬg+V\wģrnoZ= N?=?et9Wvh>^2άP}tA:{ŏW:tQc!$@/7|cQS:Ç/}AT~6 m-jUk}Όf M-(?{?տ ʆ a߾=;),NZx34#˝; Κ Va}'օ_|ejb}ڠ s} uזzn=_gßOn;ǒ 2x|[w˿|?9H7}|˃AL 00ĤqkK3:On[%QgϏ^<)6hƚҜSZꙉ}ҚL[ Nv~~sMU'xuUs 322}&6Ք^ݔj˧m YH5J̾%XFӃ=%Cwm抖ꢠӺ)]c);kKNNs{ȺpX;̯߱y™ƴN5~6i a9z*753a]O\?''  XXXXXXXXXXXo~# 5Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,}~VZ~n}x;׻&L8?hiirkl_//Еwtҽ^|Aȣo _`ݻvWȰaî _[򖠷^˶;v8YḶ.w:]csqo J1IDAT~ᄇhgqA *&pxyanAn*>耎6]׮Z=/}ྌ 0,H+@*\UxbKg'gfF~䑥@S 믿 ˧L:;ΰai؛oyvoqc=fAR  W>QGݲS6o$tʐ~$*w}kh3Oeo%K zdOq+pATN@JvmkNN9 ?Y.Vw Y7???z&:] m' F飹9*6.<6`ߍ zl'lD7X栯<[vt5zӯt'/ S?oSj}0?w-ՏM|q'^x!,voOpr0W767ҰƆƨ~`W8\:s1Qk lArT![g͘<;R~ΡݭM ; *z81WuKjնN^p]ΝO ~1}uc[n>Q?SW%S+V\s8ȹ3ۗ~AF3& ł뒽^={U%z c긨gۣΪ^^Ȟ,Iئ;[2^~_>xANz9'~zW---]xAl/@̣37T}t}bw{r{ŏW/hȣ"@%wۋۮy{:H#Wy7?V'?t Ç_xϟmmAZSG2?Wm0oYpՂZoޙU:5_{ݿ۷S}?޼t~?7o=;kAh CS y晆}}Ss'=aYx {=.+SǵAo @_wmyУ<|%O=~ts, k7u׿7^G]~͗ʮ<&p^^' h3dg~cGqD0 IL $ 0  0  0  0  0  0  0  0PXXXXXXXXXXٻϨd*Z1v]PD[ʋt ZDo mM$-+[d)x#LꊊDFK vMЫBV6s 㰯*3~Kss;<P0@U T P0@:4[iVbF[@¥FYgL/>y,^Q GfC2ҘL&zVs]ڽ3Ct5ֺN(\".ћ8s|1 { #uME r#8Ô'Sa^|s]R\ܵdrOi(Z݋J>6}!{ӇIe_䣷DIcD"$:wWa"[>DKei>zJ8,M Ȗ]qR}dw^P+H09H9qvȞ1RmVLO16]Bbq~Vy,Z>^sE T ˴-ijupizf}`smΉFgm`b]7=,:W,B -p.-zy9W۠5z?2smYAF1fe\;ER2*FE-PdlUcbm_­byo+;eYUQ&?oigTi8,/g%(/?U_wGYqE;zx%${[mtmJ׆dZ7esPm`J枓4}krc&򶘸ܪJgUt|kخS^!ms3H֛sZ2~L̖SY'S§n0ܧ/ ԛs>piAF}<!z#y?m: 㾑 ٬v4?l^L4)qo8;=w/_K$#h3 O|Dyd^`xf\=Y48O~oGkEds|<,0ܻ4+ƨܸ:>yEĬRKYdyaVrQh~emXr0sk[ (-JIt$,4d25֧0sPԶk%*]OgpFqE?z WVFק.M)~WYg凖:Gzޑj{,^1c `]_)} 膊?~ɡ0y&k,ȂCOiY9,ͯՙO]K sLY>{Kͧ췴xʧ[GtTCrYֿ9e\]]M2 RHhm7oQ;;^ێiM)4iqqۥ?];!o]R.Ǻ_w+uY.Q-nx·_LO(}e跻Ͻ:rе,gu`%ʩRw?5s%/?Q!:IDATsI׍%pVw]읣m}ErI5}B^W;$[xqw`p*#oGAc]U/f3vw+VMUp.~V_+b3*1kXVbr\~wNu< z%^ڐC:w*{u4tzڌ&b ,pTOToѶ/~1mx[ KX: {v?ivon}xe]un th̏ŵv4sLKֹs/~^P{ Nnkm=}Γgxow~W{p('O8xPzMÆ 9bvO8|ſ+*ۮ|nW :yԑG=租~eegg ۷E=gk㨑#4N& ;f}FT9pҾߏybÆq̿ߣGYFi$\\z{Ovv3gعs!w佀}`\L7 V}`"_4.vFs3bDyynܜq{o=0.&{}0І~.ٿ#Æ]u>\U V[ UZW7egKq>>7iVi<;SyUN_\o.sa$˷'ֆ _+cq򝋡7_bDv\ ky3k|^5^׶Y¾IEmu^35FkہU8)\:G_ ,:+ż53\f.-:gSvٳggI BR-TJ rl5VG޾CFby}uRtFY,zRu:r:837ϨR/y/Myr|Uվꪮ͟O e6S ia|6]=|ST?uC}¶Gk؜qևQہɓ^zpgnΪK:u3FZsꢶ VVi3+M ?*X5RK]NZ/ܤܥrcދڳlƦJK>^i0TyHjaie&Y1|R)Ja|MRV<./gjOѤh3:_7)`%]4pO>o7{Ix%ɇ׈U _>Ng%~Qz .`WZG>׹a/;F~W7p䋬*PViV\yAUOr*xCAm9{5[ΈynFh;/_б>=ϐj[\f\,}/Pқvw뻫sߗ bO`)*/qAJX)eHp3J[)hVL3Y s6RfBj-|KkNM\-S/.m:#tU<jүYʯI%/w[~o-?dl`k-HuJ#=^ܫ^u樓aK N-fϬ~8[cUU I7\=lQciw]g-TʞpʊFw Þr&K\ƷOv!gmgb=j]q ?P4A}mAxk.]~w/ӧns/MrįJ{ce߬hVi\V.U0\ǏW=zq8ղ@{AW׾J@9yCFNUcd̞~$}ҹsuUV\ogϞڀI \D]bO? +~!sߦyРAz)k4o%h ]v =`I~W9BjF Rʄjlc.]nUYG˯pq@N:o=z,ﻭ;pMٓiIs ߨo cuqWәΒ~W_r`b!u^4S׮];tHߞ`Ckԩ5;&u+ ;H!# ` *4 P0@U T P0@U T P0@U T P0@U TAc2 0@U T P0@U T P0@U T P0@U T P0@U T P0@U T P0@U ڽ漐Lr#mߖ>X0ڰQo;̐&'{I v0&+2![+p'#&9Xh kSJM&Pm{=*,4E b2 piJ;T2c<],.Ruߧ[UV Tx$&Fhs뼛031S[u-ZOzpKV]V:Ifaι1o~'K Z/39zϿ=VK?UYN\lCb)ӟ߬5}uDw~,/dqfbXo9`64k=I_-
"bQԀ{j2O]Ywhbh6EMX R/ZhUjAFEP*jQ-U!A˧ʶ}>FO:3fpiAF9U4<_#ǔ}]nl bBުsw)N_*]T⎑?e}aL勃ˋoUkI"`P\u^^zsd2/BFzQ.&`q~FZgXKwicbb_QȔ7qciJ*Gy8_rRȬx+NUhsmXTKjsgt\bYo=;\R. q)⢺p55"Y_\U ϭ]psu>O,J NJ5,mޚPkZ#|n٫ώSksN?=B_#(=yڟy[r/b𚝢0(+{c +:;{Ff `NWj^Y]ZzضJuѹH2ޣg--1g4e8+h<@iuԀšSL7E3՚º" t^^j }2)~Bu~K `:k)IM%h9myaAۍ,KKug#9=&+_RK$xf90l[SEqqԃ” 3b5K7Nfɏ 6Z'!Ks -skS. zO/)͟,-X饽2fNޡK*UHAQۄw =^:BҘLYufkʂ@mA~xfYon'{ xѐM˪ +fLTA] `]MU4%Ya+N&y=}/9&]xT[le1~6Hzq^-ץaY5?S-N_e]3=*i=[vJX.]Jӯ`췴xj{])ZޫVUm@%^`H' @ m= 4Z<3L~rls8{% w =!K+k.I,vG=@{Bn7¦6s~:awN'< LP0@U T P0@U T P0@U T P0@U T Pz'*ҽ`*@ `*@ `*@ `*@ `*`8퓕o߱oC {ӽ{ss8p^7gn@;#1Eax˷>pĉEE복kg'Y3M}~XgiMtYϿ7M&p Ν[g}aÆ 7egKq>>7iV@>i0iux}UYgz:N؛'SRTi&iTwwGd:óhgcѢًDHV(vFLV@lTTk[nI^zk&%Gǟ<%Co:ѲJ;$"dv~k zo{ڧNCF)9s/-5ya J{|G)gd~~47unvVncovo @[ 泵Jƀx .V-j WlfdElܐOiÍ!/|Ѿ,$/=1d̐:;X[sM2)[Xڔg[ο 836 JDwIɩ=)XD-8xSgˣ混p|rz&[?9OzIGʔ1u?#-2-)X#,\Ӑ"׉CuW=ܛpGQ'S/+lźM:t6v.+Y8Yuy-הrh_\#}:T>kl)ZуۤrrX*&(=uT_瞰:v$.J+ޢ-,.K8cG||rF|EjykfV?E_ASk|6ܰ9sOn #E;QVuk2w w/]v.Y"EkxHK(*|݌58NN)y wz|8Uy&&$;wͱp7C`W> S9+oϦ5y/j2r.٬P¤Pzp Lj>]Gm͹|W棽-e-eR^hp9[>e[V?#V/51ERu(Ytzߜ<Ӝ:w;XX$\F#zu+?C f`_unbk gNAm"*|Ey+jߑb_uqكK5G et\\1$yPJM֭߃:QIdɃ[t#;dF.)^@+]+#ڰ_mv]ݝźuB'5? jD}EcѴ \z01( i=t:Ѩ=QI 6U4MkN֡yZ,^,|T*2G#rqXXM#zzէڰ1͈aֹˌgOC4v쮷Na]5mU%ΐIDATQyZ[vm$g)]foTo[f%&^oZ0;,>Pi/M܎,gZXmJI24z({ԋ:#tUc(p@==FCX w2hbռR냊B |R2ټ9~#'($S;J7׊_[6). rRExipzf^r>3NQgͷIE`snkov'N4.KiQ*j̓QI5_Ƥ[N# #?ɷZ1<~P Zd3r1P]o{^c\< >_k*iRp=I}`%ּ:U?YwՓH!V4wJ^^JݛrbKoRw F^ 0OCeS}ھۦSy5>H?ܬep Rɴ`ӂSۼYk&Q:h{뭃h&I9'=JToI O4-_mSOvg$H/;v޺qE&iO.&7z䢂3l?8>prh7ܚ  4{_oH픤ozv ע,4E b2O >YZbkΖ@5.zc҂h5V!KsÌ:Zϰ jSJM)~7iqJO,8+Q&j׭5]uOG^Z%,L 3]޳9VZb{U斦:>meyX1Yu]vH7[>QEŢ5Ԇe냑>_Z#hF*WWseEцS/HNؕsԩcR/*A)~.amXUNlXԶЋ 9[וʔqSs)bEѪyVe&*z&z l|ܓ:gH8^iK4I*>LMTCR)#?kRJK&Sah>(ꒂ3L5lwJ,ڲ7mu-Xy]R8s|Brh}-.Y+M?vu۵2Z~ۢb kij˧Xu5>j_ H7Ϝ~{N~3_\LveL*m5aYR$9Ys1'g1.'!äpQ1U6#g]Bt*5|vΎYenxq^.EkN\w.p cB(ˋ">12+7];mLHzgͿV:ۜnK/ⳋK?u^^zs.z̬R{t_meAu柅un>ْb m">b.̋I"\9hkgJnbF4F}ֆbqQy̎>"K**( Yqj=bӳ ṵ TI6s`I9+F㨵ϺKVcyNoA\rg.6]qn)ͣW՚MJ3\IR̽vkvJpOREYٶߛ]32\@[i8g:cN_]a*qoSXʿ$G_Jތ)=zrj]sF@4 b<2Q)+s:6:(*|izLR8(IiM^^ij@P'g_Ҭr׮V%@LT. TJEZm948wU!7 ׊$.-0*<Œ>R !Hdf`u0i?42vi9%`m*3fe*!dyaVr D۱܆_ORXMO\jy(.HO t.8}RL 1+J.-2L_b>҂mkj(91ەzrF*w|Wa1liAq4ry,@ON@[ИLg雒\]'bcU170Ƴ4=ԲZk#7eR^'{ xz6_r(+L+r#c4N]:S6|FJ$ O,:M^^~u5xeAJ|7uxz|ĖߣJ urqoKSsѰe(J]]qv[_.v;y}s|z5񞉾υ>WLZFr4G~L[ROiʳ mOۖ;LY|w\$S+zĭܵҜP?~?:O{ǭ_N]Futr嗉KxY`b3EkL ڣ8w\FPu#G*!c4ۜQ AfJmpvOOQPP PW.++SNN:z7qI4C*z\ Yۂ-3gSvvSzz С!v_̉D{Bu"'j^NXf]'x[R-w@|eo5U|3wz 9HiK\:s $iݿֶrLM X:CκibQڔ'VGD˙ 5͉#>{j4V۳g6[haZ:cG|Z2!Wz׭ɜ$oTM+hmz,K:: Eel:)&x7zz9}Fsok|sٳnu׮>7QEE#GŅŢ%t$J*غ{{tUV]c:u!n=QwwD[خСÕWxꩧsF>ΈynFL}[jwC;u)kCRB`w];7K>}FъC%DyG뉖QT`bKytos,j웑7=jt) h<6j4ph֗~^{?ǎخquZB^WWڻ vvF7IrԙknyI%GJT)ٚ~s,ּ0 #uP,'˸h] (>@l #Fpܹ #8&Q{;v츿~?)RH;p XBQG2 sAW'?7rcʛc;%//]])Z`W[씇@_~~E+ڵk@`^z 6̺8lA£89&oݸu? {vplHҞ65{L&}<)gkOG+EX,Sا?+}f=hG{ڶg:tҞyIveջtWAv;]\zVHYڶ<O޿61SN)}4˧ٟe郌ac 3!׈v׊_m&ru}TSE9Ä8 X;&6SV_-CϤ+fNV 5GJnFS_DhgpQ/m⥗[y&`lE}mKVaJ#w)D!px`L@k@ * ?ڕ͖={8x_ͭW6gؠ! R,Е7?f%,1bh)f:;t"}uטoHW={t_h'.+7 2D4iL:ͺxc'wp] {S\Xwp'O(+o5j՝;wDó({CCغ5~N]N|3Cgd(v[4MsAr;D3=0u~tí:LhioZdڵ+ݜve9 )+ʚw[g7[Gi_7:Ҝ9ΝkΏ2>r䁰i ޮmwF1GԡC|Im)&>kC$.${ghʤǥ;wT?st&4&6G\ GilmSvپ}ǔM*엽`^>[7--JkRDlȌ2jl"2|EK\76o |n>G1b{ '?{Ç_~5:[6vXvEqyJ7{(+؜6#sJFCó/JY\!8M1C4J֩xYЀd-WbysDN!"spR^<URuՅ5kU尵v=auZt^"W4jAJF ֭>@.@we7^2ATxtUM]h-yެfM9bب7uZߎ7g?3ޘ/?wZ^~L8åt׉R{'irs2֥{OC%Jc%[7n?+FI]w7 U;3vԐݱ!fv &i4,ywݻKÇoጅOaGkſV(QOTq5k]tӹLqacq#Tݶy5+L| (K{h/ҥh>0!Њ[ny vp,}z+|e@]`m9zTسq>>!w}W~-*J0j px*@ `*kJdwۿСC޽ 8k ~zhf>o˷>pRǎxftrrmY8B>}zžnmWrܹImvh&$ڎ[S]}WZ׉KD=;dgmZɺ~Geh;VZqL'T /];D2ui(mOϸq-ڟSv.]7fy\wh#`.@E˯{oZ>ӯ$(<-q#R/etgyy߉0w+JcG׼6IDATM٢-̈}NI'$V:7WRez)a<ϓX}- >[>K5N!Z%))ӧ\E\74~Aq=S]w_}R ;{B?_o9rh)Zܯooc}|Z,Z+3VJѱ Rd2m,ZYϏ7СCTC EEEn=k:NyyշWc}tҿ:7q!;^Ri=zT4|9'gmFԶh]kVs_~e1#CzIq>>-J6G.rk 1D,{-^4 j{H)8j"֙f;XA:C4Э[7mX)hrt.]V}6/nܶ%w/9&W j]hR~%yDG5{1%?󢼋{kF h+__=J#)1oӦ @cz}U vI7^D;89 {cV_P*HksNh7X|wСCąA#CF: T P0@U ^ӯssUx#Gj{8~xh23ݽF|M|CՊ,^Veee&?T=_W_g婩v9zǎC P{~ 掇0h@kkMM͝KJ)w?~w˝. )2GD+X?:(o_wA3@!۷0}F5ʳ +\mÔgn}G-`; 0Ge8%uEYYh?<%Ei}MIاW[׹kge9sEK:?^|ȑ¦7xao!5tzs[wbEfZ!qAGg@go>IOW!!]~heAAcJ<(.]{tΝ\4;MmW `_1Ho$'5zrR=dLcH#nVfJLg4 DUVV>7yFT1H#F WroaQ8z5zt;Zvrvv赍FջKg=tR-mY);t蠌 Ges_~6#CzIq>>rRknYseN&bͲ#3~oF?sw@|W޴Pa]t8UrP "<{4Vc%[n?0A]ҥ˪OͽW/"M}vќ~Ly+)fe]xkv9J*O&ؿh(>b2uֶ6"%߀x*GXys/ }М)WF+:zA-4;~ҸΠ#u p WiT8TrH4[`{QU33 ŠE=hTEU`[o#9T7GQ~к @={ݽ][4^ u~R Q"-9?)EICleҾOGV952jZc(^ #FzhL&S~?Q!ڙ=\oEK>7s ƈG$On\mB\Tm綱-Ըӽ{w"=ܹsRcǎǏI=*GqrM޺q.ENHĺV;\z86$ViO jܯ_?cQLq/ R7V=-h]1bx>}f=OuC%gϞg}evo}Uoa?V*IG-5WM0hOXRRo7;V^u@㰱Æz͐v\_+~ݶy]CQO!px* {(+F;#f0@aã<"ӟ~O$lu?0%u^~~P8N T P0@WviWWnayj4]ޱcǐ!CD+}u5C; mSSms'+OOܿ-gۊ+5ǏG~+qu4GdC%qohhcxcI>ey~d<\2eW=hg{eE' &r;D+LkMg+J<}l0eg[Q  QeNI]QVV&Zd?.OIQF{_o=VuYY|i\RΏ ]G<6 {w래g}++Z6 8:{:{gIz˚ezAc0EԀ=Jsed~.iS¦/v7Guk~w9rhii2yi AִZ,.g(((MVYYܬ}Sac 1\ɽEEn=k hsڡ6rCW&.&}k7Kn|9'gmFԶΜ9#qe|gw_~,Ȑ^RcϦcGVu=κ6dSoFuJ=auZ]sb5़AQ%ֽrB Aܣ3 ѫ C;{ FR+ԭ[}x ]ҥ˪OEb7IDATͽW/"M}ֺayy u9uR5E57%yDB-sL=,Ev:wJy$?^$Γz-Z*pr@Ƭ&8:;-a z{f:{lzj~ZEҿ9 J^='WMRU.1>_O최9޿k]JӦI&/,*9JOX5[~Ax{]w-}W[oJhšCxO +9D|m(Hih]]]n^pw_ROj.}U`byڪX37s ƈG$On\ږ{Nꧺ,3O:DiϼwfÇ Uw @Y|..`EIɾ7xXyՑ:f5Csqum+w]y?XGE>?!Z{8<`޽ vǨ3Yj`OC7lxG}ׯZI_PV8=}םO*20I`*@Jvedd~eϞ=_qsswÆ ;6w@T7 tee(8p;G.ZY8BMn(1 xӑү{Ͽp]Vs7o2dh>2uuƀO>tx.OPV0j5;w,ggϞ;;.+ `m.7 mήb[&)|8?9}Kg,.Poi4CtyХK_J Mwfz`T%^z[?t+.޴8`ekSW9A:v(eNI]QV֌yw޽J{{u:puîS/͙sܹxkCu@=2>r䁰i ޮmwF1G$ח|Im)&>kC$^}ٛ7?;}FSzܹSiyrb5 ހA|nQk>[۔]o1%ljӿJe]HN9j֭ wfڽ,2ci]cZ!.~YS c;ផzgѣb3Iء#+hqmcxy=vgkh^3n:O_[czUee?a[ۜ6#Sj[w2{/RfdH/1gSvv}{y oB%WS2}D|pޛZ-U)Min5ysmy/$oy@u#:)<-"^R71(Ѭ.rE4JKKOjXnݖ}Lrt.]V}6/nz5}/e&jKMyy "2YX[e箝MͳXEDjyJ"4B*%oWPC{<˴UphTŕ۾ EN`1+>@c#zuaaH:_aG!64& uZߎ7g?3ޘ/?wZ^~L8åt׉R{'irsu^Q!{yp%닩KZ@K"#"ƒKn*sW~=owgX!cCbwokۛۅ"^+.PZh*ŋw.5:|3>uZ8;Z,FE>5KS=O|zuM3gč#ǭ7Rwmҿl2Eq0,˯]8K.Z@+n͛6~m±{|񊖥_Pp ]{튔eÏ?N;rg||BΝ|cPu F} ᩮ P'0@U TAE߰qw}W\RR\ܾyjW^n}@u>W_GW}ﻷY{1 4A8?pĨ*Ic{<0Ο{=8 cǎ!C4gDd;..F?ߟ'Q+-]gUW~/uח_|~54gΜQ;:w".@/J~F7bf*m~q+x5)6ۯS'OGŧ%):{ W\=ܹsRO{+@hvY۾}G}ɚ~=}|{UTT(WrN]eee y嗕F]o݄j|͡ ~woq_omwQ#|ȑ¦50oӑG?NDi?W*ǯxԐJo/^@Y$ pt:QNQ֌L%.XN`혓SHD^u۾}ǔL @ x7Guk~MJdze4Lq / -+͒b0hbCXy...9~xzgQK:h84| ҈Õ[XT486cF{t!dY_vк\ȕV-K}51pIDAT3W72#`!R#RnLђ?e,Uw>#FXBgexnODB|XiS(!6>@/7 f#iTsTNID57!=5~i: pgPʔ^A֕7SQۯ_?e hP3ds'*D;ӵxy=?~si4GA1u|/?h}Iڹ]']j9Z*xN "5x=ϕ.*<+YINNN?"@3K5WH )>_ ޝҞ1YV+@6_٫R[7nsНR,e"_x20rQ[̈}_oX|ßG:zC ֣p?nq{mmX)+r7^}M9px9 U9=zxyn;c?UML;*vFʏ6ww/UUzedf.OIMdpP zOwUW @u~0{8}zžnUy;wnA7xyoH5h8$cǎ!CԹrmVeKW:'Oٹ$+=kӚMq7~{wNo~]i\ve]`t"UH_zk&%Gǟ<%Couo)/\#!۷sG˖gdf*퐈ś-ޖz%O:5VQQ!mUݻu2(++̙3|e=hh!| K_Pݳ?6`.#GVc8 5jcovoغ>kC$^SbNafgkƍ7^=jѶi A}F~~o1%lj}Gbe7GukXPP49!&6G\ em3c Clf#('VYYܬ}=*-vQCYG¢q ?g1C=] ։&ӅBE[)Y,h h^:t6vؖ/X~mF<8.[nٺ6#C*fVTT(GnnzXTx6ͯyPA,1ֲUfZUكʾJY>Q@T",g ZV,jƉj^^µN!dAJcZ5vUz2we'i^ٚ橫z1% ឰ:ooyy%Q 青gK Tΐv*ϝ$m3Rp-0ouBՒ|"e7IEzꄒ# W[V.&-m(.̼Pv<=w~PfX'$; H$xSU. uˌ530?|3WʝӃ"M!9yuQUR}=:9 B=z20Ob`͘S5Yyۆ׊_)mȑGc2 t4~;^^{kFfwH .);Rzk{ TI+KFZ;6iSv㓹vhOt)gﭷ-?\[_W-_mSO P% ;vLMioݸu~|! fP`89@*9NO>NIJ~AʓI&=`x<ť;o/V3 "n_uk޻k/7z6v0aBJݑ1uEo23r,|gw_~,J9Pz ֭>iQ9hE.]V}6/nz 1 OpO{3#Vi{xHukiƛ3{X\\2ݫJ8" )+JkR[O6oP[pW[]pPv9@4T_#G~~v᳽-T_=jaŋ>kC$^g޼3ۚWۅ 14+6G4SHD^u۾}ǔ |ÎFrQnͯ)@ixx6~X)dfv;%ou{Tx$2rsqq_f=3(U˥Egg'.ÕFaQ8ㄻI\7;݅`:/w1XX7OΖX[Jci~ 7HfA|gw_~,Ȑ^RcϦl۞=?NWG',bpR^nțW.ѫ Ce"I9򁊗 / QJl_ezovJmumG~+eK.>I7^y嗉<_7/$VG{جD%6]oJ<(o2_)+(Y,os@g~uBQ&hA+DI|$YD|@<ٜ~{^OhSc'do̺iQ 6%%uڜS-gϜm‘瘼k% Ӂܥ)̓irY6*e9XgY:Jl{y뤪z,"_NHK?X8eSb)L/*S$7'O4řg\/}q|wСldPqRaҫ¦}RjOo-Mys.H7Yl7͒N;XRF-P~937TП**Z2:oZ*fdz@7oJcwn| e[h2n2 -0] -ʻ9Af b|ylB,-,-Rdl>E֪o'uIsVNURZWWfayQLJ$yz*]hIi*IDAT<-2m 5-#-R==fM0pܹIm{JԱGdO}/RcǎC Oeenbw=suBNسsOIQIVz֦55n\^v*޽{ pDvUzdTk[*u%:)Ko\zMS{9νmZWȞ@4oQg-T!!7-V[!(<-Kj:ujڃ٭6)S3g󥗕f5/,}AiwϞ>vW+Fru 1SV>y ldݚԹ:8^-3ܮz[gmH\xRرcDŽהvNaugkƍ7^=ja. Ah3=}/};MUJ`89@28'LiI7^Dyl3c//#~@Րci:ߪM墝5wY]c4saM{ETr()FZΞksY#V+X^;Dj 1 F@[=أ¦^sy?ߜ%Oy,q|f$4suu6}  ?,rNSu0_׻fF H* ՙWxD?l2oCJgm'=YL$t$*ew)ZnsLޢ Μ>cmK_};thKcgIiSexy>}- MJ:tYUa+-ҭ#HВNݽtշ, rWV)6ߢcl{FRb¾^}% @Ua}U Z[p+T3u].7u3ySljlU*L;Xۜ7#29~l6)@}4& v%#3λCKo)$MOz F aWt)gﭷі. /ثЖ|J';&Ŀn:?rEE3g(_L0 @'KiK&jwɼX"hX$11l`ժĪa 4%GT vwwNϪaz51E >jCSUT_W]dds< :yr\W]C"#X]5}z\^~KH#nIb\d2ȐzWdd,V%DZ?4Xچ$u0mvڌa-xh=bֆ) <;i k`i,àgn VGs4}\5 Z(ß agO?R*UCf O~371Wȷ3и/n_ӻ{/].h"d{Knv̂j<xޑZm"{>5xeAn~@}-W~YJ@3L4LOQgթzٻf*JBUL: "*e!"XKl[j7t͌R0 m(7+LD05ge03~Ks朙3g3=sPbj0k!T P0@U T P0@U T P0@U T P0@U T P0@U T P0@U6_<VqZm/F 0@U T P0@U T *cIDATP0@U T P0@U T P0@U~Τ̬ǎ8qB6ťk.:4+)) ˶g'iwtч+ /,X`?`Rxaܺk˗/?}/lLf͞?^zoeҿM0,_6…sEu.]u}+mN|~{]4؄c?;~ӷ?=_t^9xРm[6ۋz1&+ .tQ6X/'+c?fgvvvPfª|z!Ys͹<΃ V&nsʕ+w<~,=7kfe&8(nnn&QG@)@oWoV-,>F a:Wb4!8H,FyMK)oٺM) ޥ{txf"N4F%WXJa*~}:H7?bAtJ=/rn+moi!lUіgV_kIW+4ƞ=_iWB7 gD.-\BS/q rKJRSCK*g,ω ,MPWv͗ ZyKb*2RyX,v2HYUK< [U6;6TSF%*yne`G'^5`y /Q y3֔kQ6?tKxU߰UB7,]U>rGUq$p䧕-05BwHZՄ-O+ 5[t鮌.iWWeFtῸ4+WUjK O)"j+U}!MD'8ק/,<)Qsa2>ut0_ߝIIFzhB+*YahYZvPM͑GTș[}*>wr݌rӵj]*F#L)yKp]}A_{ddTb~x荕f ʞt]96ܥ;*r3 %qA3#c7Vz|]pBmQk`/PPPА6[e(W_*Yֳkoa~.\AO':ѵEʔWHpyR "@nw~ϗGfF]y[!Ob֑*[B~jZx[ 5oXV-akwҴ_:d*go't]8ya.-KFUuV۰_[znz9ͭaװKwҶy1|!tfwJUNWuCKnQLu䯿=}] ^ .W [c(k4u+,2o/cH7l1W(Ck_Lh]*d7ƞ7r뢪C^xTu;*P_~GU~;NV NNN?2r`VYS pΝƭosBe_* ׻S*d"aKC鮃m :@9ϖ+kWk_6\'FUկWӒ m5(!00“B+{pz}K]]^WۖVz:ܿR0:owk+pcg/)P\iT؀eh:زJIJQDZ^+ _l"_<9YC{@W VrQO\g+f^-[^k)nKJJ8.5žO)rvRe%onKo]_rtyʑXge,Fo!0@#*x#Y֣ t\|CBd!:+јW5dtNXA H-טH%KupQTU5CSռύކNˢ_TƟ/:/˛{HQG۔Zm/fM5CMpѩ{%;^؍7vEhHE2 iz+*O>,m]Cμ%*%% |t͹3jlGm!%AZXcLWd?WI={yPGT,LJ R 1U;x{*ge }rw!خ,y~XY b&e0~C'+CsNL}e/jr?pļH۷m}x#;v|L~ŷ&6OV0&`l.{7<}lZ'GǹsfO}Ia,]x1:fJ6bX ,@ `*@ `*@ `*@ `*ؕl5U T P0@U T P0@U T P0@U T P0@U T P0@U T P0@U T PfF-mgg8[+>N/hrF܍QX##@!f8 $Z`!jnmf~2g]Ea+ *"!J_r Y8á-N)qW tnU\+>?rx:>]+gπ6-Уz,LL_%{J/-?5 Oӱ+))^ӤU&e +(?C`bjzT~k=MU403{ƨ5CZ^S_G9Smie9i =4j^\ rɑEIEGJ**(~%x]q큻{j3<ꎭB8yBJzv=%7;]?*뜝olLhdV! HܢI#WόTZ\e2!"{h4D${)UuΏ%5.gN+M@"}'U'NENBIDAT~0n x5ؖV91%]Q,50%u8ۘ5Ӎ6췪,*%#2݂*szSkxG8c[B.^ʆES5&aTv֏844Q )Ԝâӗ2f. d'F/tmf)Q*=Ȱչ__OW{CY<{c2NpEœ-Sv1x̍Ͼ : ^~L 0;b7:F}V:m֤o a$$0#n*Ȇu'}Ds6Kcjbߛ4ݩanK''~&y/NnTc=iQܑK)u Nr}sVP!u[tr/ 8I H`RFۼ`EG* *@l: =rf)<2h/j@'XU `*@ `*@ `*@ `*@ `*Pmx`Zm/ՠ `*@ `*@ `*@ `*@ `*Q~1..>=> ar} ;@JJJwҥWeQ 0_ߝIIɡ>>￷M#n^Lطo !KG،]Z/#]vMT`Tm]I&1qG/^&X'N|sMtaojoo/uBFOwT)˭[~caVÇ Lӻ1k>*4FlOwҥ_C=h:7El6: @T`Tжm[@@5ۯG&/_w{8q^X;0(qۏ?. G?fACxA s1s5 ([nS c}nh xJpY9r}9M;m<9c,_;*ܣ_^7o Vu5=z`QJ\6z*(lt<v}꾕nYSA9}Y zƹ3]Xt!V|e2_ eX1nקn :$˼g·~8ޭy5<z`Q { $c(waR_TY)ڃ{ƮԵ[_CB_{p7[YڞW^dXi]}h4WZsjBJaV+cWWǫݸp_azէY~W_͛Cݽ˔R&)x:^/k~=:P9ҾvLW-Zݕ܃POLнm+\PFtCC½=2eλsr {.\Fd׳Nw1Cث[f~X( Eg0)zZYq O+iwW4] +M++qtWdq~#JO\6fk> Pl根}"h݅V.љ#ogTe PqY6Ajlɽ_^2WTo"Yp3MSKhӦ4=ksߟ3g~;}L K :0kwʶEǟa]ZPtrЇ{干nJ%zp" Qa|/';CKDO* =(Gco`X?#pYg%~C?r Ute~ÇmV 6 VMW]b>$=$ҫ`{\prK~"<6E貮 -W!?<nDfW.\з(#yD:]EU:ٔvkZ:}(=<=+Ҳec~@E97u`l(uJLteNǎ`3Xwּy=H[KO/JrQ7<`{[y\э#{Xw++󶮖Q7o$XЕN=7Cu}zo'ڴӕ_{ j!Qg9]zi\]۴n-ny=wwq`lvұJM˵>5)9(kPyLPu!|8_Us¹ Y tAW7ܺg9_w׷`1l5˷~VI߾.oZTgĐu~~w_@#;t/ WtK>hi^/'?$BidMb֭ŖsM\:+c =&29}=^֏9(҅XlZi~|#3r7ߊ_s2n4e$(Ɠuo_a;WYwE#8Ե+ QPPxvرg&#r}\ 4*x` e!b Ï?ŧ|wÆtp.];t_ƎiѢ,XvJ¹"4:A7M}i*7LJ̒ĉš-VW?9W_;wkC%iݶTjeZ~ŋ/\Xb7 }V;svڵ0.]zZ~qq 乧|`;whTOp+WjXOpSN}{Mc揽_ztօēSebovJkܼ}qsssi}-VWF)phZVy <3sN9gꚔoN<|'ݻo<Xأ͛7Fï޿?Qς֭[pI5_&?Dʤ^2,lbFi*\ U gOL|8Đx}Gcǎvg/ /6<6G'OVoΝm٣@mtm˜ܺm[C'M_lmڴ102hrmCx*83lC}z7X(lb]Ï%4/^ʴiݺdSpGG*Q~wM7>}(Ο5؞C&Yʺ|ލ ncJ7{f@~הr//lb5`INܩS'r\uO>XRx7& 5kj <F23z?qTܹsز&sƓi8ƌث<6oVE^\ǏBV># /lb5}t .BK!-=#n{QYY¼ 8@y*pmF۟{{w5دNh$SW)cv77c/!y[HUy3|o]-b,5]|#JPZ4Aw{B۶mW`{ kM];Vٯ*e c\p%lR  ǞKcר{AZm ]|{Q KiN2ggs3K/|͢^[L668/]R RKR|۾}`nEEuаJ{:g8ߩc ='|IavZQ/HΝvn֕!|TRهǞPB ?͍g[ki̱w#ZvO@Z?p!}zkae32־Vσ/ZowbF=@ H uW>AJD5d]߽J!.~ g: ^ciϽרQrte}xjZ^n` pyбCېuQ))F}ʇ,ƮJ}Ԁc4^C/(2krȌ;W8VS;Ss,!`erm1 p]i,|M-!A?~~Z)7F!Oo}.V){{u{>L\r_{ 5k,adEk~=_{S2Ѱj{Mh:4B}J9ېuq+;wI =MB<3dH~}ؚsџȿǏZ.Y`9M喼浛[y:r$7/E5d` f4a2]t-o`*>lؔ;[!؊vZqZ>o·;;3g޿ϙ+ψ HB oƯ2gdd }6D'`S>'̢џȿ-[)ûtmn|*evICl{`ԭkC͘.]zᥗtY2 4d]x|KIjjԆ:hvrx;o쀶 9Wj8qPv6't7t|}hRʇP:p*e77h0=uؓ{JY~c?Lu{IO/ϐ>=Z$G|mD|A-:2"9DNF$JKORo홲[&_eMΚp -Z߷RJRS64t,:vX DuYrUewr-[ƛtC)99)}we FS HM}rcԱ;d2yT( o<﫷PQ~K1qv3ujWyđr 8ʇ,k&Ol1>ݻ#-~hB#Ǟ2gȐgyZ4Ǟcofs} Sj=z/JZ)px )7Ҵ|y+ DʛF :?tU}}mIQ_kОфƖvO% 3<,lhZ&jΡݙT]Jc;Z~lu+LL:;uˋ^Ol3-_YU t?fߟƫ7<_ eK%䜩%eUJ7@:5ү1YRIsϷjM,4(տ톬[A]|rN}]/JwctE Q>|ذڥK~}}1-Z(M7ݴeƇ'>cWʜmqq&j31ƊnO$^._߿=\6^Grx|laQc_}|ˋU?T/ûlWe>'^-K\N@Zӓd=ī`瘸Qe٪+0%=oIQJW)QԑIr? 65Ǭԭ[72n *pWݑi#vW~^Z*77ƻc^ooޢ6lvCoɫ͋~{BPូȀ~١.3b*.k`/PPPTb3rF?e=Sspp(**CØ=b@$Rc\𒮙\ )6յW R _o,KD>BN[bLw6{G7-QݺUJO>x%X([r>FU{ʊ#juJ5())nϞx4l !76kݺupADj?sufW_|=8vk]-<nl[i?[)~" ݱ'?z~r\FeՍ/П%ybԒ)ҫ+u/OˉQJ-N?_EiR(;\ XJ8LluT]v_0_n޸u,ȥtBerZjY"M-V ux^l{S5]/=\\Nmyo,'CI{;I/*r}cWY5TIDAT̽5B=O:Wa+^x߅6֘^}IW#t >XQC~8^lp<>➑/J=4klӲ8fǝ/PkjiF'! k8P9ʇu .Bӷ5( f'Rt٣vW[Ξ;'TccfƆWfcX]]\f.-w`0zF[cO6WI|ݸgy3KReo3, @_8WtLC*ٛf^#э*p~S%Ո6fRļ/̫e)ɻuM| ^3m ?|{Pss1S}CիZtiQEkW-/,OO&o6!\N,I*tu O*ꪆ_b}*^yc(Yl!QQ]3W<_k+reU]Vy)O>U~6Ǟ=ťKF?f߾ʤC}o>nnn={ 8zkr=N,8h]hKgɔ7.lNޖ>e,Ӳχr\Db 3\m2gψƯ(㯠дG/et?$=X-osC'+:~Jh\[qF8YRYrTpƾju{/s5$e_++I_= |ԮW7n͛dwɻ GٻwJJLdO-|8Wo7y?,j*_ ; ݕuL_#WfEhZX wz]϶õB5cs8cX3I yC~?0jү^&sJ`AQW[# ]=r!JmH}fNZisvvn}5h,{QI k-ݏm7zTշ[z*%>zT,cMʊ~~cyN[Su'uVC!;XE!eeϮ|rc:=MXnWևMu{\7WBR2PMe/zjlԍvQ7`jեKm[̍xmb~ߧtuuģ\w0ļ|#~{ru,fjg ]'arsF5P'v՝x#[hԯ R <*lW><+O [-;3b^\\3lDVV,i2馛DYBGuj>9ʫ!88ػr]}=?.ۯ׬7p !lA N5|yY޴>{Gb|Y1hR4,\r2đ# _~)߮VZ}G~%! E"#LzK;w\%9r=Ư(b־ghԆ?Kx*amPçG~0딛;Y5(-o-,[3JOJW.]bggW-f{FƳk>.Qc kQsʴtή]tдoNfıg >-,/3O2Y^ݗީS4Mב(3ß]-f{FƳ\U^nm-Wް^^_'Ӿ};yqYB5x* ߵ{eztУ2sgf!k53vewni)ޫF=Sh+pD=DԱz^YЪU+aytjT B7nıw%`oq;uRcoO|dǎoVD'D}of͚o+W|͢^tϘhl؀h\s/izsw:u1vUk{&O:w 7N>srZni}eƛϜM9>ՠ巘cǎ'U~eggGԋ5L``Uvuy99u;7䲞@:zƵ|hT{j۶FʱWOO;Y;}S&~{00TjoɳSRvL ȅ p__BtZCP6O`, RrΝ;tMW]?(')y-[\"{1b9*S!!=B=6ƆxaEE={y`,;;; ){-n{·INUt?[s䯟Ǯߗ&u6mO51k q?d؝]CSŋp>}cπcOnEo)]fϙg֞='yn%vv2%``ŶRnmo߽]}J;zlOjjnn2y-pVCy.YNZ$䯿^kխkY;ο.edd۟vlhA.`{kkE)ȷ[sE2 giOOQ&g?W@\ X BߤJT6Lmv&>r$væuhzpM.|s۵k'`ܺ88ez Z:ŖmO ]k&>rm62 ^{2i Ek''X˗/Vi=g׀[h!whwɻS 3kۑ_ZoѽȻGpj8c%#m[Ȏ_)sɛЏ-3)IؖQ~e }XhjǦ;*k|ͷiӾ}>{{{{Yk@=sڼǎ9:q@6:]nM;`: Ǟ=C8u},7x|#Ou͝3QP`aqMǎ$;9QU(,,0h;R4ϫD.^Vv%' /$$xBšB,εk׼ 1;[}߶$Q(]owLޝcv.>m,,vnА ڵS|.V7Tu۶mnj-'V@VO&o`\nǧ;ZiX`;QSՕfa_Nfm;ﺓe`@B 0@U T P0@U T P0@U T P0@U T P0@JJJ`*@ `*@ `*@ `*@ `*@ `*@ `*@B3Jr{y,A 0@U+))غ.ʮs<J'K%%%N|=13`nv =qU:rdsNe~+)Θ0lU~_I~mHɥ~0U7pdB%J~\}6zZźWPrV-{_iu[- , ᠫl}~۸1[4̨0M+Qa'&=u7뜴U~&[[oU 'E0l@͔я STlMRSK:W+넧vrbԝ~2*mue"%oJ}uvXSKg1qLZ~rt'/t}|E72) +ʶJĨo/:46~V}=EbmW|-xI}L*I%]JծϏ;EүQW\e*Fj5LJ)B& 8H{W:tTRREJ {w.$S4Ԓ-WYMkOW_}Em2|XigX'7η+:kU5T&2~7d޾]2U#O:sSNzN@(ii(*ı(CoV:|s+_HDudѡTk׮aNU7ݴQnDie]-3h?YK}Tˀڗu%yaQZ-뻭zTvJOTDOk5|r]Wj_RbrbZDz8-?yLf\XzM7ݴġ s)&F $%JrϢP[LU>E`yNи cxzz " '@@xߞ7tS7:pZWpؖFBV8bz[M]^h:٧e4gN:2!ؕTg1\lΑݙ4zX>q[ +̥I\cn^ 4$@ `*@nd_ov߾}yyyi\uj~#F7BZ1p9~~9[,,0f ]rEXOA^~%y se&fM#,ƌ0z໺z]o%:vZ9ܹs?}ioPX`bV3,'2Cup>ޖm2~ߩSF=)x{ 01iO|dǎmqq& |}w&% s^2.U-#l"rh+#'gJ'Dk[q2
]ɛ0*ߠQ~s*k[na/\бCannqQyj*[{\jjm>C:_ͳdXFΕ+H*u;DV-o~#P&f5Rfͦ?=mJؤ蘵+ٴWꕫ/0?5tY[V?+-6174T҂GoWp [cu‘v@\Y=Hv0•MyС!'`p0yMѰɱ7?u;WoMyqEcZVP Xq/MsJ`AQg.~S]fF+"gM~ _ț9N{I+}I:Xw p0t0z`MPw*gV9"BKVGbCS5!nZCh> x;.?+,LvJ¹"aΝ;ڵkvvvKz[V=O,hm۶\m 6&׮]adADxNYVrҩS!Jy0 I`y;z,;;ho&,ؙg掟Ν: T ;tX}zh iƧ'++?\@^*5`w]fk]^yֿϐ>E4+CRR~H0fs’p 0S#7 `xvvv/F̛;g0`F!Cu{ vםwnڰ/5,.>~MtL ’L`FE 0 T P0@}ͷ۷/7//77O4577knZoĈFP+zn4Ǐ6ٯT#G{˜hL1|O +&&FXe謬>}1#|+?2L5=~[ǥ?~ce$g]V9wO<_ڛo,###SYeδλ שµ x[ʶ}Ny(`B_(?{N^Qa*ptBakJM6 vr#+_ ,|+,Ye>uaSlN9.vRtmurwc֮={...hXQu9Xk/Iv͞3O4x%~#c(eڵkqEz~ݻ,*j DIKOW .E$0;N/G ;mZ4lpzK0={ʷ 0 W 99,I;a^[oW[S]9ٵGVh4B{Ժ`_ .乄Ǧ,ԒT-GhBctfz$e.#ӯ9.Y.sHVծ=jѲUKa:9:׭ok?=-gPѤ^ZBucEށ7'61>7G9yE4+CRR~H0fs’p 0S#7 `xvvv/F̛;g0`F!Cu{ vםwnڰ/5,.>~MtL ’L`FE 0 T P0@Qx_NIO9#cǎ.N^CxsNl@ʏV?ΞSoWt50Zaa{p[JoM}qAW6*@geeGWZ;|[ݜ9 kSp `7trΗ_4{Ǘ{q0L&f5YY¼dAg&|G++4= byeduLs9"*7bߘtv-Mh٪dnnދ/,̋ 2GǬ-,,rС5Jzσ3򡑲6X)ώ"&fӏMF|ŲL_0]بg<ӥ{Yv+Y;Ѱ"T e^v=g07*!7Y4V"ⅅh٪|Jy_x~ݻ,*j ӄ)>s@)R[ӹA+_X]an#\$Ȱ\bw9aJ{o,`V9 Ҁܛ3G3K46ƲG,Ѹ=\+@.ih]EzoMm{o?evډ&{SRKޝ[yrS}և'>cW䶸8ya;iwo֬ sMowqœ B ;u֑PM٫FG`P]Bn9K3Cǥ?\vǨ%>JQV2+ֲ*.2N <hEc ':97jaM[ni} tAW(?3$u"Wanү QͳDJiMhlI`!bdկ:_Hq6J8p{. Ƙ)+trt|7֯[+P&f5OO6):fJֆzKfNJ_|6/%b+i~jxfjcs 9+j9GS6%!@+dUpH ` 29Lބɜ>svYf{(Y0|@QFm'eygMQSjݖpFvS5o*Z!lTKQJmѢ?.kysW__~ow`[hmGg(#"os֯S$mMR&W_ 4S#+/lc7_!}s62e&gff7_Pfv!9.]#05p9qu/6mtu&q pifSO 3c3;/5qOitڟCyV5L @`j*@ `*A ;23;v a\\\vү__ߡC|@ tٻ'Z`Hwtч+ /,@0fr9ss,7{=#_|W\V:++O>\ticۯLuh;]wxh=ӱ?}E狋-Ϯ]۶lM'##SYe pfVh:%%%LlHc/<;גӯ$7oaؚ5r{4Z›GF&Ygl5qJ9dFȊ+osVŹgɭ۶Ŭ\403N;vܓ$ʕ+w<~,=7kfQO0`AYvsdwM7 +,,0hpQQF'XL*۩ӧ $v+e bXoƿ浛[,G&|0;]4̐~t5%5{/0=Yߛ]CGb|\dxO|dǎmqq& |}w&% ջe4ޮb_83OW%}tAnyLY#١. NEc] DC/)SW^J͘TUk Vu֛ǾpAes֔t M-<]bK@+W[H8QY3]BS0?dM&.mP$85<{Zj)H'GǷ|c `bVY)acۮdaydF5j ַb`Yn#.CNϳ7Yhؔ&i]I-[\zӯ$75fY>r$7/Ba c-i׮s ۲uR8K.#ڲ[Di{j8Hk:W[/71Jsw`zV\,*j ӄ+>Cj:V:;Cf$/I-IUn T^HZK3={ʷ 0 iJwG%LP)ҷe]45. ש*VM gO ),<)LO|;Б$<9W)Ye޾mٱ+er[\0_ߝII,z{uӕfjggɪh} q:3͋.r]96) dU5R(((0t3f"UA?dU'Z:4U6nݺ/\бCa\5'uu%glih]|&WX[7sIpY y|YGReMt_R֎zgd]Dr^Z&7Xn|CU+?=mJؤ蘵+9YXwcEC,4>t~@~bT1[b 3-+|4&"C'Oooo/,8 }Ua&ŭ{* 3S&o3WO_| 2uVJO7HvZRprrPeŽ@7Ν;+*s"uM_76X B)'4:;; ]S)/'hv9"of2prw麼J\^_]z}OtEe kg.z,ׁ!0@+)) c¹"D" YюΎš*85Eey{)%Ujݶ`! E"#;}`玟_=GG"M7ݴ(-o-[3JOJW.]bgg'vlCC;o k]Ezo0&4$TԉF.pu>}wm% 'O ))%N7̔o+2o߶቏2-.NdaΤ$avk]ţe#O/I1 ^<]I-v3k:QvDz ~NބTUkVu֛ǾpAF-穩d3HjjmU. Df. NXY,'7W?}CUj٪~7TYe bӦMY+oM{umͮ^ZBS*ѵX΋tF\mN %4{tK١.FrhR*8$xBŠWO&o)<69vY>KR2戼ڨ3rωM XkV  ZC*`Ž@7Ν:+E/zU=)]\ PnsE2]ϫ}-~]򖒐C3ß{_kq_ ų{1b9!05@7*7]Xsӆ~ ndqkcbodmt@T050,5 `*@“'7obwJ?f?~am;vt.wz2;0/;u`V~ŗqzVĿC/L ߳υR~hό z䯿 QV:++O>¼r?>w<nܺYXy8iŦsrǠ;;yedd 01%HzȐ~'<3ᓽOCDc3\l,+H{QEXHﭩm1wO-,<ٮ];d}oJwɻS 3' 0% ۷m}x#;v|Ln7Y3)I{fj0v*_ctu$6TcqP̼'9;E!E ^mqtu3 =F/I2nF\`ѬʺKJwa77!wW9@+[o(O?Y1Vu֛ǾpA}ko !KRKRu8r3ݗ(KRxFE$kBcK6r/ .K>+vFͥl>C:_?2U(P 3t+1eE0Nouk*ĬX1iS&EǬ]ɵ^PW\5b)Jt͏gЖV(Mޢ0.ܲ9G?r۫jt.[%71VW,srdUgUzqc  qaz*8$xBŠWO&odsr]Z+E⦆ $^1NiL97ï'YEcMZ8'vھ={v3X+<:wΞ9{";mDV>yIYhB̈( *q.hu2+4~A"oe۷~,I `3VWnyyGe`\ou0Zkh謫WDn x9NX v%4;U5#3߬Z!E߬uj:I+ڵ)&dWRRRϟM;p\0^;KeaQ_GU*..%k׵k׿mRį6gR)ϛ3Ym Q^:,ew_tQX_ L]5IW_7MXyyGoEeo_{G;9y(393cW7p2cIvEȑܿ'ik7LkM7ӞfLf7_7U3>??Yšѽ{!>23q#aL@U T Pp}uaS뿺-_aqq,h<4L6tE]| arN|4Ȧ:`]fϙ'bƍJ!dF-n*q.huKj\Zj)_R,='yng -8k4aJϜ)((P}t ;m|a.ᱩqߟa#E- /077ܹs”+߾?X.,r+7;'g߇'IDAT=ghlei=jYZqzbmh,9"gxޚVwtoiKrɓڵM|;%.zXo+2o߶቏2-.NdaΤ$aݛ5\]u3Tn֬O2^IIlF;/2el]136Ϻjd'*~Kyj[K'GǷ|c `bVY)acۮZomWKhvlYCŬ"%W.YC$JVL_P~]YzseS1\"LOVO0^YXq)MLvNAKssE=[/kUIQ iQ5`=hܩR8{쉼\ȀeCjֆT_/r"vTnj$Xw tpk|0miu -D,忤}i6AdO#ܴ;]+-H7}Z3pq:2sy9iտ]v5EЄJJJ´i.+f‹yg, > (#nT>. *..%k׵k׿mRįŵu,ݻ>#o76j Ԛ T P0@U 7v&%eff=vĉRtҥ_C=5ٳwONW _Xz`jsλ^+ Xn{F?\"@ tVVV>}DӹtҨ۷_lv=ݻtK{c~/Z]mloo/NFF̬,tJJJ4ِ~=}=?^xw%_Inް{5kf+3;icյ7L0ٔkrȌ;W8(sWg+[mYh:`f``9v'%Iݕ+WyqY5{>nZ...8`ؿ鍊nfWXX8`ࢢNUSO?6IZoWoV-,+ɍmk7YMKavh!Xk~KڵkylݦҽhTvAsٸr㫔 /͜='yngˢڿ?MQzzR3nW{hE0 /$쥙Ǟ{U4`@%f ѣ &VXX[۲.]Ga,pH}>/0=Yߛ]CGb|\dxO|dǎmqq& |}w&% ջe4ޮ|]'\g-r>ksv>&GqJ_83O.6322F7up *?T5^^{)C7c&R4OVur6DԇU6nݺ/\бCa\5'4qBEM-IM-~Ϛ k42g狀- v >"Ȫ  0 +B_m_}?aF9;; C/L@c俟eW_;xML&YYY}cFW~d k]]{t[ٷMKHXtsܹǟxj7X(,FFFiIwүSWkmN6Q/PxP_unӦ>%,CF&Ye,ayc9yk2O|~2U蘵הBvmd-oݭFڷW&_@XVFsY2ӳ|GæTٜ>sf]z<{l])Ǭ]{l]\\<Ѱ"r^v=ghRqqJo߱G+89PWµkⷋ&9ɻw 0=+iYTA^&<}=k]89DHav6"^4Avڠ.h`~{o,`V ?{wUVe^amPE[RSk`oCu Ĕ5!V)r!V1'Zʄ{ #*Mvucc&̖+ 3-!,Q*_m!n`~jm`NYV,_vEr(/Ot~1^Xos56̠1H6`gϜ̵P~]+z… nnns7ݾn_&\sͧ@wqm/ 믿~q"ِDxxõWrkҩS J{n~ ;叏>2g? ~W+jJP:dȣ?,e;e/.|wۢ[ʮ9#,VV_y ^lz;Ə4f䄑]|sC%rC?g8>׮{b:=f!p4@ۇ omSшn얛o֎n~ P윜;9w%4$DtWT8]%p`K \mGegoFoÇ544dV+a֝;w?DO׻w_أ.,@-0ass+]pᙔ KJ Artiiȑ#mܱhSfMQiToo@?S=S~X-'M޲fG2\XXtv}V$޻DO$ü_\f3+35or=n;_8X10s!ǎ [xߛs A[ {~mЁ-?W8@pF8˯ZQaRڏZ.F-oG?ezFs|/F/injxᥗFؒ '31t⌅3/(nn78Yg>xUkcTWW?~\i/xh#SZNgYrDw6|QTT|I\{ω_\jq Xi\Z>d*x$%~a}paGȟX^Ɯ2QeF㤠s"%?Nl8jF[8 J|ի|!D{ Iwύ:)'p0| ;{ޞ7޽=rIiC/Fl, *+(u+gJk8BU-brm[ZTIYM""u1BD ]~mT҈#5x0V.Ӛoټisr p߾}w|rA G҂jNǠ.(,O+Cej Ӥ[I3% }lG4ېĬ$%N!B/nFQfZʽp!۷T9eX|Kglˡ<? 2m2isCu6˪DHsEμƸ]r$j_1l̉J ڟZ)"R,1Xa9</_[7 p^8,GF̍;C@p,,%"ŗ^_!|6LPG0Ħ-O>n0sb'+{,̜xh:t8Q|B>:\l(J>M~f1aU:E`!va,NR)ɹ7ӢJۯk#UWWPox\aLe*Mf0^ڳaKfjaM9ɴ<: Pâa6M7 ?ӱ~ۯ#8%X6$,Y2zRVl~jl:n?C81i11Jյ[(\}_u`iw&pDِȄ%yIk"(CM=+L#7땗^ׯl:yjn5ѣ}w) u Oi?`@_|A@3-#~k[V{ ?z!CDOQiui~iѻE]ٶm߾-=4$Dt hVݻogϞƖۦBh nO;t_3Sٳ+/t*mU\\y˖3+ 80b;jHp400GJ@0%Ï>pyyUU|)?ÇkhhV@,Э;wsՉwGqww]Y8Z/=Z8.` Wp3)n ЗЃ8ӧOuͯomwwׯFƑ7<@j?.U-'M~!FE 8S~"# +,,}z/}Y{=]fj!9vwwGNرҶnw+m@p^~p+w-[\!JK_;e[~%{pCy p0 ‘^~Պ ~p7ئǔoyC8TL믿^hCgzᥗFؒ '31t⌅3/(FQ |Yg>|VQ]]}q'UsY#|ZmJ wӅ'W]9/RCb,/JR {Iq:!^}{X_\Xd/Y C|/6Tќ2VQf4N :'b^3)/줦Fi8jFֻ]Ŧ*h}UBmW^l a'ygHJ{niwȟO٨rt=|/ػw';[.1)0~4c4mՈ7Ț2,SE.&üJʌ6WbCs-*aq 6onU:ggƆY|!0_-"3J~mT҈#5x0V.ӚoټiGr p߾}w|rA G҂:* %’c K^9ӳeHn4B)eQH]X&ڹ O&疞57]U,g6_Hj&zlZʽp!۷T9eX|Kglˡ<K6;hʐjJd.nʛ)*E K0Wscru6LBndشV;WVzɔ-򔓇.9WYXz8/C##F̝!K8qRrvK/ƯO>DؕV#Q4ʌph&>YMoS.ѯW6s UAHINgb̉gvC*'=\:dyP笰6f¬~f1ʖWZ;,a+飃dLR"^^sWdFܷ<0]}zJ[LIj1+Wj]3 [V%e+LgUΡ\E Y]qXPhآϊmSߜ3lغc89&w=sZt3^?@i|up)AEEŲ$aɲ' ד*eSeqm =Ck~>յ[(\}_u`iw&pDِȄ%y)k"(CM=+L#7땗^ׯl:yjn5ѣ}w IDAT) u Oi?`@_|A@3-#~k[V{ ?z!CDOQiui~iѻE]ٶm߾-=4$Dt hVݻogϞƖۦBh nO;t_3Sٳ+/t*mU\\y˖3+ 80b;jHp400GJ@0%/;Vg'rL]]]R3ٝ!줤s Ra' -_@7?| H0i{g뱭Q6>rd{<%917Ҷf(Șȗ4ur"PV޳'cۛNSN5xРysΟ?(?\GzlK [tNMM[kk1 qʼw/F/w}mZoW'jٮ0s̉za-8k;xUkD~{Ҙ6ya>t:D5#RvHNgO@m;졕{O9qԱ*..V#'>t3wro'gkU%iULin֯c8|E])_?FɽeF㤠wNO0~|SSS4FMjguJe,!ޢ}MBVc[/D;zo~y' p$ y{{SVdgE6&8xPxVxk/lX\lH)H77ic FPWdF} cmltkR7W7˿x&>,[\vFUIC\凘}5h݈#Fuumfhe!^MCkG8Pt%?uYP,#fRVA}y~9YI0Y)Uī.=T2]_<Yh>ʒ-߼H]XacA!L1h 5 mylyJCLˮxaAeVʽ!۷T9eX|KglˡJ^$:D m4 Vȋ 3}eщy*c܄*[3e& EĆޱSMe; + Bi~r=MY}pB@L ZXXd[~FO=Z?Z6Y-9T"{`F}ykh`gΛ`}e} "p4Wqn׎'׭4p@3 vlf ] %d)8=c\ 417bT8]%p`K \ց+N<)\ Æ=*p%i1 E 4_}%1~Xzm~[ )M{䏏?^q!Х#Gvrܹw8zPY7k4ÆSkµL}ى[o9S{.)CvRRrL9eXiү_ߛy$JK4s=ܳV(9h= c`i[srvdLK^WK~9D(oٓMa'`])'t^̷ yWlJ~ ,Kfp6ڔ޶o8|E])_?FɽeF㤠wNO0~|SSS4FMjguJnʯ~jpUj[/D;zo~y' p$?U/ػwe&8xPܶ)'AUxKh%}4 Ҵa58>Qo)U ȌR%6"Dpvl"p5ҖZ֍$!.CxrAbh}?ch&[6oe& N9o߾vd>nEW(sJ)k5gݘdq O3 ̂ʱ])r_LD7F6wJRY2ښ~"uaq)~0e>Mu{AKVuTꕆ]Yy٘nVʽ!۷T9he/^M.ɸZiTQ>Wt!>5,sgUT[r>@R1nFIM-KvUuʉ~Bᶼ2EȈsxxxNdq\D l(9q蛄i.Z2ԖgxrcX];HYQF|;tPq*i uWϔ>CWÌBd$4nh6mnmg,^//ON¹+4f>J^$ګT1:%*%YuTf:acz:jCRf sPGCd1arpɨA U'  uV%eV'Tخn*ۜ-Sv|EEfsyueXN)gD99wύ,КSէ挘slڑyӄ=ǵfz |#YkO&D$4խZIn66N¥p޽ Uڅ]/Т`~vc'XX)97C+/g۳۔ո'p. ͤEɿ7oѣkޒC%vmwon+h`gΛ`}e} "p4Wqn׎'׭4p@3 vlf ] %d)8=c\ 417bT8]%IDATp`K \-w=zdG/t:]Д)Siط 6mm/9///` z \a[Ǎ'JKukF'CKKKG)#&6W^FFr-7_>}DOݹ>YI^ɶ䖯]ѢZ's|axóү 붭ਤ=ɐfL7=8"ᨇk>۟KM/}_;%)@;V*k__Fi/akG+\UYp0.8=c[MM'Ƶ_+kNv* 47u|W3w(W`!CJ;c۶ӧ9=x]]ѵnq=}СQuAg,!:*MӹY䪆y rKd^{Fɪl\p!;a?\{ω_\jq =+ @{$Ȱs ">dzzɋl.0ە)-m7|Qt=‹S`1Jh4uNļgR_tQF[*_MOT'|rGȬirx9XѶG_K_N^CRs#NC| ̭'iϞve^{yݻ<(:g;[cy n}+2 dM84.(os7<,VUYC%;S,+1"RlU&>`Jʺ.] ;\"Z9y11soټiVt'}zw׎'׭4pm5juĂK(U37d]LTklCk~Z8ض1+8FM8MJ8?C[B ǣ-*E\#(e_ɽ!۷T]%e/^M.lC/}b^t1Lan 7nn[zdz_x-eU"V*mp~d)82bn9`a)/Y-i gxK6>wcЎPAҘswW^lxh:d8Q|Bt3AQ@vPg!2blcunnva,NX) 9w؎Xn4UNV8uRm!)n1 S,# ԑm tp􂬀Pm D|W aZU_cm}֫'䔳@;b௿z… nnns7z^v2ٸk>(ׯ7,@h믿~q"ِxxõW >,vD.@菏>2g? ~W+\W_|zjC y8'E|vễw.l+挘S|XY} `<0g3[&aóVow3i #:}sC%rC? `FnBuO]'`HšիV G"p4@7Aƽh˻wdlMp=s-Аv/p400GJ@0%[_{QSeT)\Z_t)SM#0 t>?omڴ^s^^^׷O0Fw֌ N)@9R8FLl˯j[[n }ozpDQ|V#?_ܿwJ8S>vT8@y'$(m@ WK_֒'VVZS`])pzƶaoO(kV~pyzUx\롬%q7S1s|/F/in򫯶gP+7CavƶmOsz𺺺 kkݔzgC+W$X0CY^N'S0Y .d#硕{O9kKM;n|aabz.!G8N^dfSZ.<ՎGȟ^%2QeF㤠s"%?l0Z_PjE ]MNR5Bhޭv~-5_|!:A{ Iwύ:)'p0| ;{ޞ7޽=rIi%7^NCs/F(*9<,rc魊 B 0]M 1X0,S,+1_⒫4u&>`Jʌmwվq\nJcۛ":hzp͛x3ܷo];2\vޮuԨՍLiYϊoc3Ƭ$եk)QyL"SnAb̤Q.c**M)m̊/iӪ,8,Nb^'sB ǣ-*E\#Tv.m~jm`NYV,_vEr(nx6pGTle > EbBrxeڟiŠ&\͍qkTFIՖ&~y&J;,S ȈsxxxNdq\D-^-O1^h.Қ3WƅRxnN:TD}H뗹b [\2?(Wsm_C U'OJFՂ<7}%-+sCV:#:(\VH35n꬟!DFp͸ۺم:a'`;cxprpJ}CtV* +U KXf܆B>=%-$X2]#u1 ;-  %$l1YeAi'V__䎳gNn(o_S\pmcw`tuxe/kӊ~ {s}z@[]Ɇ=սbOTdq#/tE|?l2|_sV+:dȣ?,9/4pK/> -{opa^5gĜ։_y Y VIs[neL3r뮿NtߜP\s?,ж=.Oaxvk X=f‘!Mqoj5n]opt.@%99[32w%\9w%4 (*n Ѯ0%. p `QYY/?Ïʪ>˯hAf ~=tg~Mӧ݇~kxb ;ahKax0oe~gCKKKG):x!7_^MDe]/*\n?5`?Ս7N()9&|Tt^~-G6G,uڭ/gb6l_l<嗳.R %9NUk*+?UOe>r߬;IDATkܯh3>k7TVMGG `])pzƶ!'J7 tȴj~}&!L`NO}%_ݲ_|N6Z:k?l0ٸp‹/$OF2sY:r~;vT1W_s@'q_{h媼xNRSǎ_XXCj=rBHWiu:mZNLini&`m춯dE>rD|Ͽ.ᔯA2qR;CC''?mOFxޢ<^&K8R[?Oe/zo~yg6OnHN ݧΖlL nE_U8MJ}AyI n,i)~0=+^#DFȱ y֧Tī,9V9JI͝2^:ƘlCuUL䦊 !1W x7CE YyR_^Nih9lϔyuj6nkuFfO=;\%* !2+o7)3`I^+&w=sZt3^?@i|u訛GT6\?eNiM7X4m{i1C.^R[nⱍjzK~$X ]]hK$ٹ.=Me[u*ٸ>(e/.~ e?S24SWWx +cKn—@'>_.[;ݘn+ z!'-GC~W_QkVЍh413y?,65WvڃoTVucs?:9!TYɓچ3_4;hѣ&qM;Vr_o;aD8`ٳ:j/];U_N#p4םG}_wLA1_K.`?|[3}\^.Кp~p400GJ@0%/;Vg՗_#Y8Z/!~Uv{0˙r۴G8]ZZ:rHa'Ν~猣G ~hO3l0V-\ǟ(>e3g꒒9t(o,a'%%8SV ;_h-<|O@ү$I3'=[m_#(9Fp-5;'GiGDt?,p@=vBrs[F}=b֫En%'dG]RxwޢsjjjZ[kI8SS_~0zIf缣_>k3֒~[%'>q5WvE)cN mY#CVZ#:g{ÆeJ wӅ'W3'A禓KB|FTڶ/Z*8,J\aiE 3/=(K 5T^r\s2PWdF[chߺQ1^~W#֍;BiTWWf&k&[6otN9o߾vd>nEWS7Ni2iR ,K!a>ݲ%-WgYg%G=l 97Ul0ʊC֞ f1h 5Ų",!fAU"/ӭՊVq0dO?c6 p0+/Imr9琇s/Xx=oƛPUM&W7sLζ]cW4.'_VZ&P%;ʪDr6U:%o{(6U }e2EȈsxxxNdq\D l(9qD\>¹k5uu_d8qUVT4<==?Q3p7:Ti(>!M?3Bۻs5?Bvk٫룃͕a涿͌E)I8wƌ;B D{  6V%e) U6,ag$xG#uanKϔ`2T'|c-dctZh,Hi殮N, ^LmN–[2̠i amx'V__䎳gNn6_ {ɹ{nl < 4}`ѥsbe.ʌu OU3bΙ3kGO`^/.=:;FhͳמMHhobKu[WWzj%jniڴ8 {N2Ui[>vpHͲX^V"_cZ|Xi?1Mp!Њk6<YwJKU(qhF64ȶ:ד&8z~pm[rD"p4ٳg_w>L޲yS߾}]8K?l#ܮO[;h@f 'rL]]]R3ٝ!줤s Ra' -_@7?| H0i{g뱭Q6>rd{<%917Ҷf(Șȗ4ur"PV޳'cۛNSN5xРysΟ?(?\GzlK [tNMM[kk1 qʼw/F/w}mZoW'W IDATjٮ0s̉za-8k;xUkD~{Ҙ6ya¾Lin*ѳ m_`=rU{ p<'y>:v"QJc΋O*9\Msxnsb}]E _`>rD|Ͽ.ᔯA2qR;CC''?]穩Q&j:@%}բQQ^MBx GR5/2Jojj$罗o{L?*2yݻOYݓ-٘xA~}[\!/-&WxcҼ%8>QdXZ)z#{4\M|VY8e7,vUq+ȌRpB-^BEF4m3E?-7 rlݷo];2\v+4}bEJT %"7a>]r&,!fxa49,Nb9@?Cu> +IeI^kmAm^1rZz#*_h{waC^S;o?s bD/J&Cy87$ "ytF[*)5ao&wŹ 5^dzus'kɼ%7TwɎ* 7U),GF̍;C@p,,%":gdDɉF$~ZKw_.v2ɿKvСJD Sό"#&aZ(ni&6!`se6oc2YC'N3%/픗`h2T' Ee>yf]29Fg +XѦ[6|EEfpDYHuAzAV@xXq˪,Y_;vC|jXĨ;DXPc&>+ۜzŶ<_por3E7cpۯk=d=7R6 ^>k@kNU3bΙ3kGO`^/.=:;FhͳמMHho[=g~574mmK޽{' -\^Ekb777N¥/S)snaW(/_ζg)qN<\`IAS l=o艣GG &%J>`(aW< fgϞ7޽Z3=8xM}vEh>Z!ܮO[;h@f pyyUU|)?ÇkhhV@,Э;wsՉwGqww]Y8Z/=Z8.` Wp3)n ЗЃ8ґ#G ۞c%a̚Ҩ2߀~8S{xyrv[>./Oekw͞% 8e>%辥+>}H^q׽wHy@?̺gVfj!{70vpc`C+p7An2K_;e[~%{p<0.8=c[MMp_y¤qF-\ƍ7>1qy[$ ԗ_.^vK/+%aO.fb g(_|Q8L]]ѵnq=}СǨ>~^毘4O<)㡕{O9kKM;n|aa+k]3§ަp7]xre"u9 65wUE9"_p`ys?FiΉLJ ;=`n#]}mxiAUY_aɱ%Q/>=+^cڍA"1+IeeQH]X&ڹ O&~GRR>t%r.Y-aW_rFJaWZ,BQUfĘj!L})=ū| sϕ.6MJ#gg`{8#t`?lN3#Ȉ\s O3h4#RՅ5Qmr1l0Nι+r8W_}*NiM)n1&RryƬ\֫eFͰ>O/  6JʊRe8!L+ʂkc3`]hI53 "xEG˿~3N7Vsor3E7sƷ_ `WeCOٓ",ew,S]7*+vۯ#0i4>:p6yV*W)6;oWZq)mHk|բ#䇕Yiq!ӧ p~ nVuun|kVz/xh}w5w/<Io\\ |\^4y=K@p|辥+>}H^q׽w t_\f3+35or=n;ֿ]g+9FpN9رRN /{sB9hKү/ km%/{E;t jjjW^0)_{\Q Ս7>1qy[hL`NO}%_}^zYi- 0}L 8c /񨺺 kkݔzgC+WiKǏ+-p++'O吇V{=įAz.5uE-wҸߵ>#|Z,Lin6W%iU¡t 9ʋZ6wUE.?/V (3'M1/oiGV!4Z&v;D_ukzekjh9uS6N`NO~ -kIDAT?Nczȝ3~eKCPihpnٰ̅J!rcd!T.i&KMXYTF-cK⪵>i ] Uebr ktZUKe5KUimWo6]]mWg6bWcz裏=s==88ko߾vd>n~\ݶ*_mU}b}AVJޱ)2Ug3GM W$st>Mҹ [c$XuO!eWV0Y<[A},Qz˥C,wbDAfw/sr/E9OV1FI_=/R&|Mç+H3]9O%m62xڱ}A8Ui-_vEr(Tŏ*m4Hݟ(4AjZrEn.Qg%Bk(6U }R;ſZt[b㚈5hASf ͸h?{k3gdU<w/<7.\ W _xpU0JȨVށ3'8z4ݢwl۶oߖҶW_ \(K{7ٳgƖۦ!p4xۧ:w)`Wg|w/tתl޲e/J 1w5j*E00GJ@0%h𣏲s?\^^yU7|#oÇ544dV+{sYϝ;\uuuлw_أbhKG LHvt…gR6/)9&r!Х#G=sǢKl&O5EQ exL;}@n\?iͯ5{h'3.Xpaa}KW}Y{('@?̺gVfj!{70vVr rc.^6sЖ-_; _(K^v"N3Դ˯ZQaRڏZ}o|lcJ׷cO!2˅KJ/[6a:qJ_lQuuuFv)<: CVZӖǏW Z 0WWEE'Ol!\{ω_\jq Zaqmk}FYtUmJiӪC%r]EtyNgsKht}{X_\Xr=B[kIN(2qR9I&;۞=qhZBnbI8~)dsTBn[^l_rMM^CRs#NC| );{޾i=?iwLslJ7Mέ0W)Dn,%t%LV,K }^|ɇ'k*#2ɼO["8.f}rvi8 9e$`0 FUc-]}+bhʕFJr=K 6FCU'O{8#:(llpk#ڜN͕ac{[xFhf$ʿ:mF萙T9+JeXrUi!JM"V^^[)*Sչoy\!;vC|jX[eM_ey 2<3[T%Kևem7'Fp&>+ۜ-á >"3hgy*cj0]合E܋c[OO v s3Xd9Z9Ё͸N=+;~ Vئd-۷g~W5hsQ#EPh.8U@0%.o8xرO?ɓ}ðaG 817w z,Ї tn>՗_jOfhD?ZۃI?9Lm#|~RN9tȑM:w;g=ZoC5~aÇj3>'rL]]]R3ٝ!%%8SV6~Ŷo=3I]F~ՓfN{*e#G-%9i[srvdLK^?O@=l'@pIt8?ӳ2?cGv^zNn%'dG]Rxwލ;`praˢ{v;Ju6c-鷛?[e”4k QLIDATmYSCVZx(a &\T^N'rD|Ͽ.(3'M1/FM)*6Xze^䆛Vˬzq|9uS6N`NO~?>m}wo맰$ƪun12ƅ."nQP͋TVeOQ-:mD}"Ҵ]"yRЋx3qܰ 7c6&?rPm{qo۪#ƎP_}գ=n[ssܷo];2\v4ĵ`!TIY%]oQ\"8;SڜHEeqDJf̓aqs}A!YJLcٕjM GKg%EydrD}w 7hzV0Xm+ a>*+^6>esvxc._ƽ vl&PvpZ˗ݿ$zQz6kOz}:5̲4!WrwF,mۨdz"Ji[wTYhIs#%8 K)xhȶ_}Ɖ7I؍OT*J 1VuV'6.76W0 }g_nSRUWd^UVd}tܡC*'\`YlG!R7ό"#X1vNhFhs\ 3u Twx f?px#;%c5zyy )8w1cP"!`]hÈ_YUF[0A!jQsJT^ V%ebi^eв1F'dYU$Xf UJ IC"pn\%Í>,|7R?se,3X.Tw BDe֫b {S:T~ nM8{f~+f=7R6 ^>kp:9 P]w+O1L޵# 6-? =B|#gskO&D$4컱C]]9inS9wI*w ǮNɪYJٍ)nnn~ =gb >}Fin,S(/?W|T>? h=-KV'z$G֏p{ '=L޲yS߾}[Ch=`v|rA vlr.+6M.֤Ȉsxxx?`֓0]%p`K \\(׻=zTYi2U ؏Z_t)SM,Пط 8޴i缼u@p^qI]F~ctnН8C|Fiiȑ#rHLl˯j[[n }<wO>g%y%6n[wG~j][PRrLixzz p C*Xg_۟KM/}_VPrř@4+msy'$(m@ o_֒'VVZVÙ_+m555-wxBi\{{]?^~z(I\rS7<0<׿cV+ra毖;ʍ+|@=3m;}/5wtӴi p g {N2UieJԱ]٭Xi~RSZxSq1/RKvQAgXXo9 ݳ/n9;|Ee5. nm]f4N :'b^3)oc{BxԄQQ6M]PE5"JvLmD*_mG_~_6z!)S!>e8`=o~4;9孝]16O{Y/KM8&CfSCuDqBRn98=88ko߾vd>n[y5W6ʬ/H68Q/>=+^LFs,YI*!SʢL8MJ?y;6|xeWE SUP,U7_"|(N6(/H iC H,R 6ۘO1XҬowTY\3bb2-΍MHQEa~jm`N˗_ $OEd6 ZŦMp+r7GGԋ4TkXa4/W⫥|ʘguԊѐ96U+"h܂*>':.:$Q&[yۢMd5~sZ.j4Zlo7kR`R>t%LV,eF/l|'/[\Q4JY#5oBd5-uu*Ɯesem\4tE`GS?(Ws~RN\n!CƉ.23*qF˪1+yE\Q-޴:zj^~9eՐe 7ۍ9봍:bL9эkb7W_q}.J+Il1}׷_ \ITQj Oִp٦-RMBe#zuV!NgFĹ+u/I~nMEo}HeTȜFEײ %ȹLbzJa\kM0>35$^;k|[ӯ؏֚7xVծS18b]%X &]6t߀T%՞~>YI9NFĀUϞMYnu& Eo/Ֆh/t=mQ_)v{_q!AWJpS~g9bc~hfyn`I*~ASjG-NO}g+NU?-w5k빖Ξ"N>ZT+$ZOF&^ֻ6=+ތkit`,S$}W[?56+\NM<" 6;kɱ!~}sͶ%qA~W?9Dk{\u 3Ijg_ SqN uyT8)fwzMYW %}5kVU+{~} ne!hޔWO^ݿOyp4IJ~-t՚ʏtũXxO&S[NoS3%N_s7'ES4===GO_oٲs7 J5FuWArKob@HGo>ڳŭ=;Ϗ&j3>qF!" \_Z-.wũ!K-`MyRyv7:z(Q8(1)0pvm 0gd|Ʒ_׶wo[;wn3-TV 7?ͰZp6gjϔ/4V߹[6vYC_-hHX?4-=,Em/oݶu>X8-姐ˬ{fef ߟ^n~q c =N却99J;2&/9uL6p@`'ϟ?êʌ,eKh,u]yl ݪ`1[ndzu+W8yorms{[3W_?qMojW%rs3H>,.W`&h[n>E7["ZrtϒŢ=hfkV7\3 :t8Q|NjopaڪKG5[nzRhsx#yw3,oqglo ȐJ^A-њ&2%8 o #:8_gjjwPl˿׽0/tcxpklZZt${ٽw^N?3ou~tO-`Vظ?[c4j}(Bmn&'*ޯht`?WY%ON[ RKGeŮ9Ǻڜʼ4DtWH!u; RMԑW>yOy?4f'tjcYYdfxZ-Uyr[O\6u+;ow.ȽӎYclتI(U[KLP&n>k[hu,ȝ>Nn_3eQRvŹN_i@P|ES4ӛi[EL|.ɢWo9zWys.Kў=Z'J@0%: tjsڧO@2/t%;MմO1 p@}`K`,K \@0%. p `K \@0%. p `Kh6=sZvҷ_?)*@0%. p `K \@0%. p `K \@;:pc~ɓ' ׯx{><`!#Zh[}}};Ξ9-G{ҏ˅ ݻ/{GE7ַ_?)'֮SY޽m?<Ǟ[js7jn>|WG%:e!]6&NخmAJۯkۻ-Ν;7G*|fajZ3gʏW+`-_k,!M$Y}&Z`?9'{Xү_ߺm|p%2.YL4?~ϽƎ+N却99J;2&/ZޝEU.|0 \\MsE4Ŵ$[Dv˰Mqot+%oobaW Mn* P)>3gff`f|r3?sglإvYrgSvڿ~G)w/ ѩ{7cT??/ { ~WYpvqbvzvV}m=xjRdB(Þ2u=i۱Kg:ncOێmE'RHMMSx`{ iiiJG&ԦSm.\>֌zzwՃY))󆉚fGEsX*nwtn xojdO8''G)_o==nSEO!|<|?oVaÄWwOќ  6p cW9SOoMJYS͸nE]&bKrN4|.wi:ve辣]zu+S)x ^BEuzigU65ŚLJa^ܧ'O2gU͈h./{nժR8vTmHY4vyrw Y%7iM@Xat+o\ƩgN]!EJ6m5=o|VQief(]Jb _,_Oдf)4ޑ]Ef锸 ט2/}ݩ Czk;w=;sB]ϕKS_2)r-s缯H˘1~sCG2lrܼG=r8Py{塚sy򮛛 @y`EYvػ7UO9Ty>5P?ʲqp/TxfQd>6_O~]MXƍb}Uʮs]p+m{C[QosN†5l*Nq._+y۶}P>G|={GP;^9 j T P0@U T P0@U T P0@U T P0@Up*,,8:j@ `*@ `*@ `*@ `*@ `*@ `*@ TnZlxI NLwr҄&]:"ǰ'0">B!iBM?[/\ì𲏩 OIDATWyN 4挜+Iy9VL uN!r&[:;.Xoûc6 5k:[+*WIN:iC,yL\z&P+]cK.&uhYKxĦe6VxbnmʭTe-6+3}V3a2g||hp|&pvlش}BG2cC}4..nށQK\:-"]4>aG͓EdWVi PS8-:b_e溅OuCwcTvi/uy9cFD\5hM4$ jf"'k!!w .,̎ f'²s!n-񜳶:6$ZF`332tj4Q$]B^R,fv+l;|{vv5|7G3oY`n1@e* `*@ `*@ `*@ `*@ `*@ `*Pa|1OiU `*@ `*@ `*@ `*@ `*@ `*@ c4QSFM'o)k]?y*҅C}zactpuLΎ:Umw)ZbߏO qrzNIl_R7*ZeFg)4nAٸaz}Kmfn;PDݢX`JdǓ=dp)xQ?=_#['?K^9>K^c?z`酕Vkn ^ -ȭC&ݳ/)uavӤ}(WON+',1ɌٱCOVjk=,}2XNWf;%j~/D}T;uهLQx^ޣ°UߺC~ClqTe}czKO4ӹXcr{<[V{wb͒dCu=|Qܴv=xz(~Ɍ>+ տ0WV>3VDË-8`i>]?05k>#M -;{@[{tn+irϋ&i`%Nθ|1O؋M'K3w{מ)O /j'?%SM\Y'Omſ^OGigb7ݶ㣗~P[l~O+#K.}Grlr?z2EpW.z<=&Ч~ew;|~"#ǕI7USkOfKF֖'nI[,^~ؼ'5U8W&m1;;;h0ۯ ;bM7n:pR:ygƽM].^8z#W=:nI4`/'@]6}df͚ pڵ Ga-\>{a:y_L7[nrƍ_=-8;{u,' s{ 9״on_a`0=Rc??gϞ̬,aQ:xzo0dȽC6S pW+]\۷kף]z0߯:V} hc=| ;k3"̝kZo]zOǻz{W#O?EmIׯ{lxa>b 5wa&SnM)\k\ޛr0i.^b;!|]}j׹ݝwb}|SN۾𢡊2N>,G^A 0kӯ{;zV t7n6{mk9rcbÔ#fT>|VXa[|/}k`/+N:)u[C5m$~6i4j}{l#U_+W?zEvlR^Wyy upBB˗ksOuaԤQYnܸAꂃԴ43ȧ҅9.ro??+[iesrrB=+]CxuUS[6-ss~MA26kmٺY۵q˖Ha&/_Ji]236z]*tfdQ*RDɗY5^ T,rAo5zۭUZ չx{V)+۔׮WPଔ *w6V]zMTKmebt!DcrZSV},|~C:rqȸ?g}]4rNZlՖ8olt=W(#5C)h.S踯G<:}~3[=S"4rĈ[nƍG~TtWŮw?m}mM6m:)t,kgkf2S)OڤIޜh&5Xެ,W~^Ԗ?~#%uj^:/ZRq]ǭ|ՋW?iş.rss:q_},y|ͯ>~}{Ѹica!o>yKޘ|8q "ux挈j5iӦ.\/u15{\QCɛ>''k0ӹ?P [z{Saaa3._6_eaBȣwi#̷q!j]ݺ͞+wO]+ ;u % Жk۶C)2l=w*nc5=8(KؐIDATW/JƔ޼ys1{n]w . b[og=:w|{fvj蕢?8:uتUK1;zBdοy %S'Xeo8j=t8sr~k{^]dVh܅:>syЀ Jl;e_~U6ĉU߬hS6K= iRtrrr"mk׮ q ͚|0h@ﹹsssKc'a*'5jڤI;t[Q:, uN#@ `*@ `*@ `*@ `*TXX(ptT P0@U T P0@U T P0@U T P0@U T P0@U T P0@U T P0@ꉺq*;:SXRAb| MhbnUȌS2R )ni9KcS+]wbyP \\gxzaPR895! ;-6tcnZlDE'$:1ՓIqr73rm=ֳcu hrEP髍c2K֪\TwT]D5H.L5uڧ]w^& 8@Y3 <::İ{e^)ԄyMC5 ZNpsF}KtN7. Cw7˹oŴ 4&2شs ӌDnrAӖ:S$ Ólɋͫ7JW68m x&OJ80?JF7ar?/GA9_xξiQIٱ[S7=r6LILp87y ,ҐȒ}?id,+'YVzdtG{((,L=bH|A9ӏh̎:WNv23;s懹C]d|xo@t+-k 75[4*X lW 5a~'X%ό vn1Cd"}),@N/ YYbz0^VDԠb%e'ņz.\Cc趝)jwdh]!#B##tO 6LLP`I'%oZXlYc݄M?|IR@sb2_)ff7HzL&4I&hm%gv\j4b|J}(,KHŪEH'1<ٯs!7)9::KW7?h;2\-+-I޲D5{laLQmI1E}`i;X wT],GjCU7.zew(2mz^)T =&@)K7g`)O MhsKevd\ xGjX,(ޟ*)!7.ڬ>|'}`?sbpQ7"6DDgF+M=#ג{;+_zg}S+`,5Jz7fFZ;OLL %\DɞܜhBÕÕޯFGEz\?4TXfJ^)T@kBcvOLU.-NO^)9hl7{%-)9@lfZ|twvZ'@nM?~U|j%KH/,#C\$g;;8&-H >LQ#V}USKéyiQ޾32L>b׻+-+2də$pM9?K;NEzWQWy!%.͌0ecs).7.Wf0OD\_ڑ[vf+ M*fFӽa  J|;,)'r/jkR'U(K^j*7:}GozMϰ;e|FѤW)9?WqWn1G>kTWww!_|*Ȅ}UT+gQ_`*@ `*@ `*@ `*@ `*@ `*@B<M\l5U T P0@U T P0@U T P0@U T P0@U T𪯿ٲuN:u:~]۶z4p؇q*,,,wy¶ڽٿ9 Aƻ:v\颻P+6qmz=0 *"wxڵk{={*w\_zŞ={tKT,џy>(7W2׻w 4`M>; >2D?_Db~IO?}\NNNl ˿46mH ڶm+,ճk@yC8 :xۻ[n`>{ ْ%_`<[]n'27n$*fO]^)x0;;n1~u4irG6;v7((j >lͷk\"(0PʞpZZR۷WWŋ32mz녿>;;; 0_}j8="Q ajqƇ}_?O99 S'X)Kr`W\y>vo׮3~-,]xLh(((hJ?lgNl:ƯE.A7%&}spm)V5ӓ7}-eʕ+y͛0k׮wϻQwWnX)tMA#koY:0`]_m)Æ cJ `i[?MtIUɏ&Ur=!G>bj _Bjj'9Ë>{䁊<ۚݐwyzD "40`]_mAwu֠A75UZ'3.}zS˝(k7M.VeUyuzN?vlz7*nbq+V>+u}|u|4̬R}L^+#T^2yO(Jᄡa|r>/wMT/YuIDAT8R4.1v\QYT!nyJy3Nf>{lI<ۋMZ' &^!'...J=JuϪ *x+UxX'jMF>yb;oo.WPVydEmP=kU@m"J>[5ؔ&dOs*}oU~WcEQV~jܺE|U@~>uE+m5j:nqd6;czɛ_5Nͯ]^BakkPK(&O4{~FnS:_N}xY.0U߭ĽdK/,ZJF@ӧx]ODjY=`]5ތKL׷%+ݡE[04.X>.ǔT6./_X]ξ8l(Y,3reՎyUU߭XqlX}5/vn 5?nE?ȍW^dj&*ÄLjX[7fݞ-qeJCjɣwyϔ2(e޳wђ 6M1tEzgϦg.=tpL+g_-R5%~4a<ٻ#{@LNVď}8Dùyܪ/`vSSR0/C_Z W1cG7 h]X9gb 4>F4o(}^1C(_.q!=wGo;z.D)*$+PThGվ3x .!?So^,(o3g~E]&,駕zEn 3?k,___su8VW/ξ&%G̚~Åa<1v,J#B 6M'hv3rQx2J&=E܁CN9g5x%g-lzLm]ikݽrW.6[ψ(W)r,V C7ISx8O}.)QӇ;+rvmnY6hPjkQ)w\ݽ'?}Դs!dffq;;;Rsh싳/hX˙>ƃ~ԊxBж'Ǩ) !_*.P (#J>~-3n{`1_|U-ӧ9lwGw\YnP3ݺz<[o}{?2Wڶ5+ִjҧWɡOɝL9}wKcuE8 ]c6M0rEQ {}vrah;2ah#_8[匇5W)xLI=0+aeԦIn>b_ 6}Y%ӓ|}z Fe>r$'78V/ξ۠^<<ۭQS]s.='z<:"qrGf4Z,p)5tqrm׭8viM_5C/IٛBZk0GmpǺUDD+#~X] Wν}}jۄ~lpH+g_mp*,,,wy425.]5KM~d}w/b[{gvԬQ0sFk3"QPpe/;nZj)jGcW&k33:t.]_jO+#H?9IH޾#1D}O+\"u2п= NӰaƍwٳ1KNKw?3 3Դifnm︣]dY4eS 7pq-[hɿƍ 5_aÆ=/wg[oUիW?}v;uҹSUVCٳ:vs&fV{Ro1g& RɓNkسOű_{ 싳//`yyyL,i\d8_wڵ=i͚ XJsg+8y~GD lߑMֱTR!x}}5kYAdƩ52we!?}}w_\s._^T'խۃDq%8.k}!}V,t_.\v[K_^G3˲bU''X ˍ%w@jٲUoɯ4~}|$c٣Uoض>ճcw$Z|W'Z>>i92f(Q3UX|nwA)8 ֩cG"qOVNo׬56u&~˰M߮K0߀![RM=tp{KWTp߾}~S{fծ˖bt`1ZuZ;v$[ֵI& d޴48l\8";uX?u Jյ!m,a899ɳZ;ܸ;峬?n,=2×/tA\\^x13p =ȽC~{~Q|0P oyy=5Tg_b/ldFԤrSh֬]” \5Jb!Ym(ˇ[iWWol*W7=#Hz㏍]v~W} kdB6mi9hu5:ЪJ3eM`7eh/ŭwUq:9D/.w܁[z0ξ8TQ-}A3 7_/j[Wo|WW>ZIDATm6ɪ4۵{ +f<2ۺ# }7^4ӮKHT=}6NV 2 div-X_oEwW\/_V |w 8.]:) cUux'sNwlzz|~[W[k5l0a2N'yեCNp腋8wQL/v7͏V7np֭[Y^&zvwo`UwK=z75rY]&iW kڲe efݺ)crqssr26u'a+_})ξ,Ϊg_uV`#,gU?}]OZMS SDY "T4Wֆ)#ȷlBX9y/@~N65siҿ۪={*w5y'|vl)܋JOڲvНr |ϲϖ ]Z 357\.Ըqc.un2!3=O]27o޼97m۶_u1V:~W7/q Lc[lڋ 8УGaip'oYpWXRVJ+vz~}h$E5~7iIfVV#<9qgOWQ-Z%m% O>%yU1MY/X5Bg:}нr'?K]*j@VѦMǎ T+'0V*@G:SeXHV 0N0OMa g)kMZiԜ2۔G/ו+ ➭hh;Y(Jёx<,Rt ʦb8XULTizs=򗲊}&GYos׮ =:Oe97lp׫ލE]( fGɥ̒ay2yZOm:82z `e {t\4!moO,YU|yF#)=F[}-z+\{M\@b.[t/TWg?1xӓJPK.6SvA9JkWt!mjR$~4'DCeByח U׮^sƍ}JWw~_sY*c]n2X{ỵۃ4y.ꂅ- _VQ w|.Hn Mr68*G51c8,Za6x8Y|3V|Y}ξj/fkTPmUm]tł] ϼYnoN_*o3sFk3" [jf_s6jC b><~qpQIDAT/ l7r"w_W<>2矎nj;.Om}gK|ՉEe5}qOUQ}QwB(>9q.{v|n:JחN;o*S8jUܫʝ[3mm}WUX5#⬾HNGtCv" Vʟ!uV"MHބlc<`NFwà&$I.q=i+{+J k53Іv;wUܔhٞB]s> 0դguO &- T,uR~LL{?_/{,q)kfLUvM^t-׼,xDu3ϜS>QJWjis =YUӓ7}-eʕ+yVXȒŋs(/L}IV 3l7)h, }t]l *58pI ܈\kfWGI)xnܸ1/(z}jQPwpHeڋ&U(d "ы6[{?-Bꦈ7Ů/iNM4ʛŖնm[Y;画֯_ m+C],'juUe'6pWuXXbZJ8QmW)ܕ|{gk S@\*N,έF>o+SÖT=zC/B/[ZhZxNXU8xoBCK7mXE봙2AYB>}-SpWnx̸G-|[|qaݺ)/6-bC>c[\v/N sp7#RʙnrGM%S 7{g>,A)~!ag ~]_k rU{*hVd`cK1ij*jH~ ;JYw޺}ݷgzdX9QXemJ4+:oE ?ѕb82ePǩVTBɢ|#"?@[-7lPeܳ3ϬaG#Uh>s 6tc)O.sum4b,5lcDī:tP]Y+K>MDVG<q1,{ur 3^RԱ,\ޔP-. ,|dIz5=Q[]H ĉ̍6 Kك@?ѕ u +269SZJ9 )y_)q 9=V>ij58#-c߽CG5ſ*Դ3gyo*}jTޟ~436(be+7a+yga ^^ÇھY_XA迿D fƱ*8M-J7l _},qvnͯM- ` ݀nn.\ ,n4h 3,MMѺF4WYKJ6H>:qrwZKN/q. 4qk| VU[߾}wͷke!հ}TZ7hk|kg_0P 1s8YQ oVyS[_jꩨٳرwpy6Ty>5fq'iVꏩ?~,/ZW^~!Isr~S~f͚?^h;%g˻Y;o>-k'OaSy 5'G߅^}װ}K:e?*ٗͪcxfZt⚹Վu|nf'lU^^RpuufrvvV W\1؂.73 Z>?S7n\b֯{'{L&l|_~{L,seаaCa&%·Lةc)zQ-vL>lزbE={N)7SX}'P Oh#LQϞj:F ^-u=җ5DWg_J/kޱ l_ڟ[3!87!ؖa8up2Wunn. ؏&+,W}s!lUQosNzƍ\\\u][k(WB4n[VnH-"_Du,kvp574L`:T-S̮۵5f9p8/uV`#f'wvY iղݾOLyhă6X>Y/ҷ_.{9Ç(wTg8ξ8k}A}% Z]v]؛ (~lƺe/^(ukM&Md!% upqqA(Cg5^m2B֭[*M؏o׶5kp%mrɵi6W/XϾr5 }bBkSao踱;ul_npg INj{=|$z~<>tv:#lOBV&Bc{SSb@܄WSʿkVIad^@2Cٗg_Q;g_P36mM-3j ]Ϗʋ}o3ۯ٣{:tnJ:Y%"w+2~w :wuunXx]ci׶ڽgI8uWfnndAafV<nOlW+.®)G;uS~3Nt/zԩC(Bi5 &t]8W^={SeՐҸQ#y%3Ue͆ JyϟSj\+e_QOU_ڤAÅ ܲeKy*Y9YeٲVau9s=}Z14iDuѿ_ߠޢƌ5 m"}{RS+" Tsn5a&⥱-ZբytCTK+ڟ.YZ%yq1ctZ/ٗϾjq8 XC]\ʖr9O?U7+UǓ?VQs&yᶹqH Æx0Щ UOwoT O_|u&>)B~~G?'$d=HW"֯H2gŏTf`2u'w9fC{w-Z4U+PFLb7]e [rU\ξL,\}X!l\,]:w>x|2- 5lڤ|z^zCϛv{foi->[:&|z9vL{wP_(5&M~!t٧'STi->lBbGC.{JNINݧon6z/lI&͑@@5jH)V2{%lRviڂ欞3zh>~%r|~zoΘ?ùgslYD) ʵev۫kiСgϝ{*tÌ ͛7x*TI^]}0w M4Il{e{yvPacZz{+mW'?l… JMšlNu}뭷vm[n;}u۶W0^;v(h^uGB╖}0.^b7riPN;Rϗ}QvoZ#k_|yU-ۼe]=p_@ D]>YP;-\Mpq`&o&|9ߠO\S0j 4pS#}N?Y'/>⿫Qۼ;`M%C^_ܶc{32`PDݾvZ%79y Ɖ)j!P N,ӍbBaaIOǯq*'_1s0ę~A% f:{Ԝ kVu䉿=Դ3gδ6s޿IvEWNil3-+ ik ZS⑁k֯{'{ey-[iVغÆ-,VEh(AwА{O䝻4еC%\>oliY)'^q:95))үN~3+Ycްj+_{JX_Oϧ`32 [ҰaoVݨu[ \-[+)@uQ %zh䪯ׯ_`ܕV^5W@XL>V!2{WTz NRD4ꡇʊVhяm;p@+:MM4qsuhkJ?29tb܊m MU<^>jt:ziYASu+W8K9Y)aN(zVUI]{wUإŧ7n/HNUCo10"kga!+&O 7P @@i={ %osoO_Euy*C.6o2i&M5sq0/zӓ' Bh\VѴg1|c/N h0KdM{qy~!~~N3Mu8r8۰ęSWaLfSC [-I92R#2i4Lv$7'ZdAjrQ 3O_oȜ^(L3NHO zXأUQ'Xf=j)lhjK;S Qϼ?sNz[0ޭ[meiSa&F듚md֒yތYRf? .%%DmVmdlPVV8Znv 0@ 4pumھ][yaS’KW̮w}J/ ;D*7ABaa̐GUb`1c eހ!G ;DZhA&Md왳O=ь^*ZA~W=T޹C?0TO/y{U0 C `*@ 5kݑ|H_~[4o6ݼ?jCZmGɲ0ް@!@M-^?s׿fΓO<.Zt֭]۶ڴiٹԫnܸ!,''gCfXΟ {fAW: `SյU_ƍLlj_ , ޞ/~A8kێږgϝ&~%׮[J9((P$0Ȼp/ț,#v.:TѦv(!v˽ѧEqvq/P)_rYzŗr^=?^$0蹸,_y&MCぃ#W\)dJУJ6|!tsk SRtUmCB nif3݆\\~~koCQ=+6n8eV 4O<'e̙rժ׺uk9… GӅsΕlK߻,Y i3ey{-JCɸ۠A9ԩSvl۾}}B,^hA+&J=_z'/_,fed]׫^JxvKNSW W8kRLQW, md5r9YsF9)V|:zi5%AS7z !x{*k}hz*_ݻqfnTҁyu9VY@_9s*eieW OM3N\rT?ڄJ)7L26oJĮ$YmzѣD`(GΝ[eV\u?.s*l̈́UTpIDAT.Yم %os}Bfz]sפzҶU51w5R얿 Eh0OBygscu5sӲ=B{Y^\Ylzv_~Jlm;ߛ-o 5`oo>+,M;ڣyZ3w~V^/ϛ1uڜQN4\U жa7ijN'xMUH5@{m9JmFYUk\\F]vM6 @-w֮m[Ypq 5|$ _bCt &KL/k”Yeƥĕ~'ygL)?8`h @-\]oVdA̔眝}#q-*捘Cɂ|χ='֮]e ' ug-V3h#@uyG=sV8_ry7~{iq 0TGb=?+n]u؀^{߳SNlۼz󥋗oϗ{s B=''P̙CG\|M6~wh%)'2K.l G;]VsX(Ph @-\/c~ҡ͛<DM}[6 C~])4mD00vt̙K/ qss}w9:vvNOGfzUXNWo6c&P2h @-\\hӧo޼75mrM>ҥKv Pw+Դ}.\u5u @E:wؤ+WƍVv9?_0qrr4\''ϖ-qwwd'N@`On1 H{5Q-ڶϞ;mw6}hqn޼ugd F'XI͕Bzz.o.... 6矃 ,>_fgTnaasѸ1rW + 'ZR 5~'wܩEN9999t{zz ` 0{үouҥK5RٹHH:ѤIwiӺu;hٲE` [`N΍._`{ HMM!8՞~z/4l*` :U) p7o|P%zur Όڞ 'Nz@.` ^yu;}4+!?-hҤ,dggr?"yڽw~,XܝRup 0u!7h8pZn-6YߛsDD}ۘ(nq #W}cO(س-Z|޿^`m{ii>[lUC GiРG #m_} @ `*@ `*@ `*@ `*8 5U T P0@U T P0@U T P0@U T P0@U T P0@U T P0@U T Pz C5NN\mFN[#DdmJm`*T tAfbtIETD,Dvlnz+JI+vqJqVJL56MI hJR‘B)[k 95;_Mhbvʬ $yDrrOXY>1cCfIvі]4QG53K[",D#ȈպWTTL̸.9;<9gQSϹj YF ΍ 7KԔ7$8̀QsQ1J; aAӢ"6 T,^5&{z{3$4:S[}.&S`!&]ONRrvٙI3G)տ#c"zh9%46fE'D7ޒsQaj3QW9ag@tRv\9fŕ ^L*Lqqrr -Ull7$_9&Z;{=^jS*"LRh 0Js;rcTY'Xn'>]אs3,qvw5|?/,~5Ĺ!ё_UV\h2*ƨXI}Q §)D~`8=2b1=*M`]\JZ6cZyOlV]Lz;*M`iv'Xj@ `*@ `*@ `*@ `*@ 6qT`*@ `*@ `*@ `*@ `*`OQS7{pBC 0@,ߙ^a\6ͩ/j16T.UrJasS 5ٹ6qT&U T P0@ F?'W P!E#F-j&g +dƏZVzek%t+xQ{SR0+kF]rRNN1ٺ{R־x~o*[_d\-*>QVT}V3M|Kļµ螬o {pk:u|[+P,mjQɗ)/İ&8l"q+Rk6ls9 SdN^{6X YYeܔ2=0Q YFSL߷G NjV~;oHkY=…%Φ+AO+sR옷O,lEBWb|ܔ-"El|B'=_%瘳Wr+uhTUB[xTZˁ6&]mQiGv qr)mv/80HFfu~*K{%/emK2AYn@.L72%- t ՞[EƚF8Zrom=vqkl=4 h P { V#T P0@U T P0@U T P0@U T P0@U TP `*@ `*@ `*@ `*@ `*@ `*@ $j4$1I(X#'-"gil6X tp 0,00N}Jr; <6-)۩&"Y@2A+V9VbeF㲕K&-7-6"ܝ4>!щ饪5%< "C3C/{k +6Y<9dņx+kƗYJO~/{*>Ezˇ/ںw@ht|LUzwJ/>PëS]Pi MrUi pzlyEdlp\rb%I.nn%VRjWMuvq)+뺢Ċ#,IN2n9Şؕ}KtH{$-̧uROeû6aŞ|\?hiɭgl^:mRݓKJ>r#֧ܻtJ;YiŤ+J<'&d 5>]籠#R+rjvںC" Y KIH/љEGegWyf,dSIԥ_Sg]>apwQP%z.ygRL Xzt~]LO0>w};^M)~Ӎ[,TΎ O[}$9:[W J.ʊ++"K4rNX+xEE( YW򘞚ni u6oEHDnÓ"Vj{M"rIeށцfߴlPxyWI&~cCJEc{9XYvGcB&4I֢GWi}3|h/F'k’ջ빸)y+ƴnxG%h+µW>jJ~1O{o3b^=>lhn)"L ݿ!eg a*ʹWʍ$)u'ɩc ˥gZ;<좶LUjː@M٩VA.{q]rrmX1vm' ,ݯwx%Ӈr/]zJWr([ZzXC)')kY3%AgL Sj8EG <)4!tM W{ހ[2o/'goot̙#?|9wb?QqwOhTbZvԄӇ,[i\^MNTf=6'4T)j2swVY4]SE*12ݐki2z:dPxߴҽ.YX{/fS/H `sM769}fŖ JL.1_ɭnu`rs9o|wÔ_7\ PL503 :)[7;):s̊+Xi!>.%ސUj]oZWt},NOqӦmӣW;xQ_+gyǤ}o\'EW#Vg'k<) 46-3;DϢי9F]<=1""Vא{˴oKOFm[pUjȩܤp{?4k2 TTEhi;%zK2ejWkvrvThL)/`<+-wI TkK=~s$s+1)hEKO&= Ǝ*23!U}RBrSMwK,5;5=';>g̊2He`DxI^C&MHn,ϰ;/Zݽp$lV@"DGZ;,)'*ٓ|&SIH=<ܒnޚDɶWKVH\2]5~n‰kݧw/gt"?d{HWKRg/%dK` 7VY p Wwc.P`ꋺWo;!aWӓ7}-o<{Mj85׮]ϯ*˾>?z ظqӘq(嘏'U81!q~]\\>[[ְaC'n4h75uD>8Rc84(qZB8''G)GO)&@5,_(P*sիgϝqn}}|*ֻw$ iZ㖭JӾg dThnn,{ur T&|Tsn&@;_vWo߱Csrr֕+rݦȷE-7ABaaIOpdEJkn>YP;-|߿NXkSfd-hҤ,dggr?"yJc-sdg@ːgw$'$&7;XIc?!+_+W 8`@~[ꙵs]M#?θ|1OTKne֊oɓLIW n Xx}c(Z/TeŔIו^l歔/mX\7Ec4o74akqk%W1qqm};{Ë*~uіRNr#(~-3(\E3gDToxM\P2 h7˄ܓ5\JB2f/>…ӑ7ɺs6x~k[ξ?FV.R&7-\Q>PEc-p%Z$a۔5lcO.m'~ӵ?˨# ^^JWD MF_/{j8`~{f67c-M}Կci)f7Ֆo~/=](rt5iGh'.s-5DvJ皖ozo?qG/ 8n ]/╺n>:b/^}q[7qލ#Ğ{~vwVFÆ77?`HM }Ը>[ϩՍW{΢i_CJM\Ptʕ=O'W7#n4^S--Oh(5M8xQg\KO^C],MU~Vmofo/_H4;!?t-VOڸ?Ow޹`[!O)ǣw ~Cb\6 K>qG-Ip2,YBԸ'|TpM-Ewk*OM_S'_J鳂. ZSMNؖ;еwun8'x6!Mz<2Ra >?ٮ:_H7l%p|j>IN~7Yf p `K \p6էNed|ߥ'N|sR PL ѓ'O gA@W`hX7 ~wxArK/`p< CNйO<Wg]XX}_sI?rWA#ǎwzuԭCo*Tձ*CYIM;>/'5rptcf$:eT|8ykbotQ8]iJɹ~1X +]pA8%WZ_{Oe]Y>0,_B8G^7 VZF#/ܚ& f73*6JKR^^!|]ak4yym֕+WBz|;xlcýK˗7n$=9I% a...]jEdL 7 ҫ| -nk/aiWŋEWi5cۙ]OV%7j+* gϞ]VL 4 8`77k4kӵڐ)'M6l,r!TGjgJ-Q{RMR1yyrXgAS}ĉu /?̬Ǐ˃)Fצ? V c DûGv3xJ=ۘmr/F{Şt[QMѹ֧4Sx 3\Rb/W.uK=sX +͚53o_Μٳ0_>Nezk< YRRfI^nxCFЄF6kJP{j3<%?9]fk-@ܽ{fL 6j¢)).RQVY4z NLȎy7?1ؿX\(T~BVT w uvїV %u1o^]; 8 0:otӬ^%:]^?ΉRQQZ!Rh ? JnH/EϤ?%vhtc 5' '1>MCg%lAIQ?~I mY?G#%:d`tэRypLtjĆ1>nCe|igg(޸K&4RKKԕ Qok~ Xw4Gљ[@>=W#zg/=#@³_{}T:~f\x|.K^zy5M}nX>nNC^$ϭӯʗ<)Fǥr YY±}Go'-˞~jС@` 4,d8b0`N(LW>2\P=a]8Κm@iIDATaHñ)S~mKݷw`X)|';Rt/y8pQ^QΜ .ȃ;|p0pz`X3Ryy=aaO~vT* Nk$<=U99y}9-0,-'N^Jڶ_ 1+ fw:pz`Xf$ w. p `K T:ۿV8ӢK 0@3/|FO<)4 ]]a(w]{-Vr 4^8C>dæ_ɷߞytcaEp&ȑ_V;;9QuRUǪ G e%e;7,L8`sȑa#ꔩS cŮF`.~wQѮʇ*27'[ @c 4t^`Jj_}jS~%=ݗuٟg°| y8`+`XipGrkZ\Ϗ?73cy̨(~/eKyypivEV剮q[W\ 񕏋ౕ ./_޸ij$,gG.~Xt/17x{KVw~R/\gBM_‹/^]ӧ c'mgvEj:<ÕIjJaj[B~{LpY}nE@s^P__F6] ?yaÆR]]-ROuvfTO5җT6cTMv~S+:|83K2DJpl"wxroQj$?-&Xb+Z3mk3 i;>4J!*S}B5z[<[{ɿ/oZt)[R&hXi֬yr̞-W*n4ǘ~Kn,q Oh$~*sRZ8{̘(gGn5j{ZjޜG~SތYRc5gfJQXn~~xl) 55}{ﷸ88Qos\:G_-m5r\KQ~~㤛f*J wN aSƕzF/JörhU}?װŠ+M ~&)A3:,5kNN#tAexҦ"qaJ&42y2Z-$C 0oQ*o5I#Ôl@m\Ƽ>&XQ\Y"|p`8=0,➰0px^?;W*o 5pܜ?{J<ؾݎ~W@M'Nl~/%mʄ@ ˊ;`8=0,}3Eӻ^@0%]9{\p. ֫ 6} /^xQSAa\;9?R ?NpS'dQD#D'H wS'Mﱰ]I]]ݳϭ(5$tH}}t6$8xI &li{dɾNVMR1kݥ/ %T*oOqmyS?~3]^~ǙYR-Av> V c ݄yT&U\:q("Yo'Rf,2uBj#Gd(c~z#qB6J%R9&1ML5[0Z.=] غ%垹apj,f͚/g٢p fS*b )5茷W5%3CNtJaЄhxY%DVS㝩kzLogj !?^#]t{̘(gGֻmԨiESRӵp)i''ꂅ:__Q!UW26֘Ju6xC-@_ZYY5Mf )}7(J $o@E/;V'4W ypbH/NDya?j7(!ѿPehze[AHa?\pLd&{;+륃Mߨd| ud@/C l0㛾?13Hb`X;]iB}DFRIhq]3\/-lJ Nԕ Qok~` (m*-&M|GPr)?^kQ{FT_8{FtgWz^|m]:st:YKoIDAT5J!NkaUk4;ri3wK"H~@!JhrDWذ-}(t'lJȔ9Α77n]aגRCCUUUURR"֪L Wn>,X@. O<): -nRa=)Lͨ:}z{lgvVo~4^D/oQ am={k^c{5}Y}nEoN ^P__F6] ?yaÆ {qSƵ?gRh U*a_m={k=zˁOǏLqfT ea;,j77H7щnJI n1ٍU_e|6Jx_:fh5(uqCӂ2u>(!Pɏjc fhcm?0ZO<+Dغ%垹apj,f͚/g٢p MA?A j h9JVS!fzk<W/'㛿 HUXlPC&F^P]/Գ_{OwE3cz`XQmNIIOv͘%eTaum8819";`sN7 }L4񮐐>>@gahX7 {ŗX+WDru=ؒ[.@@u;'M^_]\|_TtX?:C5 ӵ;.~t85t괹ӔJ۽#ҹ3J zÞpiuZGzy]F1Bi:$)q 0jFt~GNB7McF>rUY{)[DO4`XiMn^ 6%NdѝM 29rƍ+ޓZVjhhXbѹJJJ:ZIj7u'i8?A:hrQPPxIѹ.^hq[B΄ IY4`/(oF9\sg;|'D|Nx+R;h[ޫ髀RWWs+~s\5ZmHpɓ&6LSuu\2>cB?G%R]=zH`_]}J|83K2DJplDwx?IѤ*M2\2.34>t|FsOAcbC5D8A~m'OJ7ѹ<<.>̖:Ư}5k1y-}K_k@E/;V'4WNq[KGEg%^Y8&6[jFM˧;2HNZC;` 4ő#";$TojJaJa+M:D\Zݷp UUU^5m^{ T{j qrm6y=sV:ե\je5/CtMv:7Yf JC -yy撟Nf;wDt0K;+9:ުɘ'!/7SHECCCBd‘NئeU nM#_:Znٺ/~/K~*A556nkaL?o:Tw:~ܔqC:VU`oJi<}{ZHpR\ G-#}D֊nc떔EW#جY3̙=[tOasCsq :6 6k9}Z8G̛`X0a.0@0%. gS}TFo/]ZyD =p=y{$tvywkj_-[ .pz=ē~%~{%w:`Xa#G~lZW>.V>6kT\|yMޓZVjhhXbѥv\DDp ¦#j|ac=ݥW+;?@tÇ.Z^3!zUUUӦxŋ/k뱓Ƕ3"5MT)lzgϊPWWs+v5ZmHpɓ&6Ltjz|G3[~(t4a$(jo{/u?T:շo_Y?~3]^~ǙYR-Av> V c DûGv3xVjCe|6J.Z41Gf.kK'(|z)rƫEغ%垹apj,f͚/g}rOP_Age]CF㕭7W#A:Sm2,uwόpvtaFڞZXX9%%=]ۅ_7c"T!6((A'2:$&t1&`aK_]g@E/޵pkks5hw~3(7y7եLxIDAT!r*Bk[,U&x񳥦4EgҟDWs|7Yf` 4E隓b nꄬƶqtrW6øz[:ҚIW2tEUVQ[~mFs2G6ex6Z8(~ +*KΒ2/hwkĈ4X 8*لg:?u ]reş\ǽN0?q;C{mzi?^N+_#@ {1b7df {\/{C %аceÇÀ97.8lp0^܏rC w}8kY G6# ǦLM/wށa㦌;rHѥX$&61FF~#F?٫VGy(hٳg総:XW[c 4,еd_,K!# P[lԳǫկ>":K@ˌt޽{RVvra‰l=qEyEŇ[EgQP pJ\ +Z_~Y.z-~,JWz_zRtN4.AVNrԺ( Š?G޶}ԕbגRCC ̒<9s ]*˙YwpEۺp&`X*`/xEaOrH-!_8p7uxReMﱰ]I]]ݳϭ(5$tH}}t6$8xI &li{dɾNVMR1*`T*o駏݉yזW:%>%p`Xi kkk`8 MؙQ\kNV:$aD.ͿOp1K 6c%3JR/Sc (L 3H4sk3-j(=a\l{tuK=sX +͚53o_ΜٳE'̚ji"k>\kn-bk3ux}qNn㕍V'_)H{j3uMdzk< YBMB)YP".ToM9G˽DasCs1=PΎ0wۨQR 6k;R˗/?)8Qzĸ %U~Q7[ȍ UǵB"C5G7N Jn<%]c38;Dݢ,"1q{?lzFR{G̛`X0:otӬ^%&jAΌS k'6EeOF/ R]o\xWQD%iB֤"J ʵ_+(!_7UŽasS6M@ra*>q}rZ< WJ歙 M`o-6_(Hjǘ昽ʿ([Glǭ=W#zg/=#:ˁ>>WR1֡>jڡꪖ-V`+Zmմ30=0pOcY4e9Ω>nz0a,]vM}n@We$_ר~T<8G8o_xXnW\īpFUǪV?ZiC>U^z csBBd™S;zg.Iu޽t`S`tF|oupH8o //}{J)2ѧ^tx]O;~yc=zn|"?{/LO<k#dĕܖ',{DW ݌woo\n/vcGW_I5mv?D77[Hlkt@HhNz \@Fwv{ !OO[jui .аl|ĉ?Į]'̙36C..pz=Эl~/e,Jwt۶ ht'1qo0*6n1joy^=E]wG??zEEmFΞ=?}U"Ka]%_xfY\14V8g>^-~ϿѹX GZfS'O[twkT*:KMMbtHS`XiDrѻoodWջ|ĕu t 0z&7/OtoNN=5p@)?ۥ$,gG.~X_ffV7ω#l,?M7w8TjqK˗3)⅋u)L^UUU+^xŋž /RFMOBOlȈnʤpOj5H wS'Uca󻶓g[0-Pj 5H5ZmHpɓ&6LZuuȾ}۝cT|R% їTJe >v7cS?~g3Z. +ܡ}`AtmmT ֿA ;û9 k̑zqG(R`Š|OOFQ"uiƪ"'^e|68m߫wTcEh bӥ?[R&hXi֬yr̞-: 7`&XQf,!S?~`;n ׼\Zݷp,gϞ|ۺugY z=,D*nce}>܎0K wR!=uƳ=}~:!2AZ3/ ]$i;&[?u|ˠ[=Gc5A`aWO~*BayPA]~ؤ G6#3;7͓6~Nv350cis@gg%7Lu_Mw<֣Vל/+n4^zQt:0pgKIDATW"e< `8=6B7#%[8UptajffemMۦͻ>l]CN tߌv0%. p `8/̬:PVVv!g פw: @Qp]] /7\"뮻ǖl Da#={=rSc>%>%p`Xi kkk`8 Mt";۟R`R~:f8K 6IqƇ(R4-M[4ܐ^z0ZO<+Dغ%垹apj,f͚/g٢p MVeKtVdt :]fPvHxj.EVXl}by4^`<%9";'R"5-F6C8+ׇÓ*]t{̘(gGֻmԨiESRӵ|)iz3f'6_c8bi0R.)%5Ub[IT56Bq-Q?rKs ?b޼}} 5Q~~㤛f*)6nz+6~TzrmS"9i-%f,G . W &8yѳ_/СCpk?k} gψPUUu[ջ%g7o%H֥-"5S檉rm6´͕q+i}H'VG[ߋ㻺J~P`7k {`X.Ï"*E㧎7e ᐪU/.[RmOߞ,aGH~ѵغ%e@pz,F76k̼}9sfSܽ{!0,M¢))oNo@E/;V8 :pz`Xf$ w. p `K T:ۿV8B0@3/|FO<)4 ]]a(w]{-Vr 4^8C>dæ_ɷߞytcaEp&ȑ_V;;9QuRUǪ G e%e;7,L8`sȑa#ꔩS cŮF`.~wQѮʇ*27'[ @c 4t^`Jj_}jS~%=ݗuٟg°| y8`+`XipGrkZ\Ϗ?73cy̨(~/eKyypivEV剮q[W\ 񕏋ౕ ./_޸ij$,gG.~Xt/17x{KVw~R/\gBM_‹/^]ӧ c'mgvEj:<ÕIjJaj[B~{LpY}nE@s^P__F6] ?yaÆR]]-ROuvfTO5җT6cTMv~S+:|83K2DJpl"wxroQj$?-&Xb+(U}m#uiW# 5L]bGTx 3\Rb/W.uK=sX +͚53o_Μٳ0_ J)&7tƛ~+S}1M12ix)nӊƻ2CS+Z?ʜfԵ lnh=3 n5j{Zjaa攔tm^JZތYR0G uk@-IG,gRdJY`aK_]g@E/޵ I7Uӕ(֔k36.z(8XnlrQs谦Uim{;?G#%:d`tэRypLfjEC[l%}JuHuڴ:(3ߘC{_c"Y&<5! !c2;bĈpen ׼\Zݷpp .uR1~כt׻rɋ??T/{pL7Yf` 4?q;C{mzi?^N+_#@ {1b7df {\/{C %аceÇÀ97.8lp0^܏rC w}8kY G6# ǦLM/wށa㦌;rHѥvɓ'Q(#77`ʔ+@]Q>uo6^^Ui;D'bh8pl,1+EүDzf\K. 6B&a]]ݯg9x|ا_X=kG%HEi)<&ܙs]wzGN trFq@fV|W(ZQ s 9goۺMN%а҅ mIjJ1mr+:bN#?m.쬦?xaUk4ž.]ҟ^Fǯdi&JL|'{# JhrdfĉR}嶕=zֿUnA+?D=9I% a...GЩý ɏTo>qy  צ߆>\p ֫ 6} /^xQZaa.Pc'mwrcMfOtTM⦆aCuuu>"`Z7O \/_Y e6IDATՆOo\:3TQK#41K]ܬ+b4isaE7=+ ?b޼}}ۿp`t8YJؔרST):bF\(fhc۽̶(5%^Y8&6[j)6QZP*C 9^@A 3\ko܋K2c#VLx@Ǹ544\s5hFΞu߼H7_ZqG9ѸY3=uk[7Yf` 4TЯ~5G*|}&!"8+W|8߀)Ss`k tF>췿{2Fzy֦]z}O?lƬ IN1s/]$`Xuuu=Ca~}ap*p"ǿ:~HʚsgɃwyfK`8=0,IyYY_+_8lpjUǫG-/-̞m777ag`8=@J.\v%u)FDnڷӯd舡;x"B>㏷mGV{tKzYGO6^IKow\)1ži +^v'NH{OVZV֗o./a7$,gG.~XLJ},SC.R~Zx Osg66l⅋L^UUU+^xŋ v;yl#tъp a :]CrT'0mzͿ {9}Z.zt@}}t6$8xI &lZ.|';Y5I) ǨqT[8OR7׿WW6r?̒j 0sѵRm0[&`1Qx`D l3uvrm6lO`< JnH7vbC5L]bp~[Lv#4sTtd|XE$[lLEFO-Rٖ-) Sc 44k̼}9sf¯UC?M+W6XqN B "j|E{K Ț_!OՇu4JVTuLa|P 1?^𬜤q.,lnh=3 n5j{Zjaa攔tmW^J 6sA"=zcW'+\/ap\:Rw'xf]VTbpbP-TZJ7/z|_/7NiV65+GTc&NJA"A*|ԿF,zǓJ4ze|uBh1r1dȐ_` 4HqWwV>4D,}[p0hM (266K³*0[0m@}M͠/h C:0w|Ba Uk-6jYE UEiT n1--%7\j;5ZHqWclbj*Ju*,OL3 p;j_8{FSfV}"~ii.몯}3D۳fԙmf%pPAh8R㬮\fΜ!t [Y-ׇZF1 s /!q2 ǖuZr /lb%eȋ2⥄M+ хnIDAT~*s=݅- ݻg@8;:mFmOK-,,ڜȥ͘* (_15x_l!Girgƾ-,_!**&ԭw X)QR<+8Q,qK1o^c(?qMzMo/_;UM]٬uHv;Q Ҩ=ܖg VȉMwyosFIk _ Ains@쑑JC -yyNf;wDN%b11rw=$О=~2 <`t0eT444$D&)J__L^1=pZP<`t7mӧT|}hue뾿@k}Tk1^Яom ka]&EF7*TO?nʸAA…U*_\`{4=-$ؼ 6afO?ZuKʌ¦pz,5kf޾9g -lnh=6O+ tNhsJJzӧ ?b޼}}  GoFBpz \@0wff(++;QYyy3kĻBBGVahXսKoʕ+?ru=ؒ[.l]z1:ד3%dʜ7۽''d8;0аpŢJJJ:jY j7u-!_8KEAAɓ'E>\p. ֓k+^xQ޿ u@.z9ڳnݑ5ȷDas n,aofx1^ PAJ]]ݳϭp h֦k!S'O8l0OqSƵ?[~(~8^QpaoJcTMѣ;է%?~3]^~ǙYR-.а@]w> VeK|Y>%IV#}IR+iBV:$[T*1ơd]eRxh滼4g]xzc|# 5nyJkQn~ [غ%垹avSb 44k̼}9sfpÍ77Q9UWUӕ+2i 'Ԫ7&{Dž#OlȈn>9VxLKV)8a<<^ĭ˗5$5Ur5.Ɏћ! m)c 3dgƨ}R;}Vd5ޕZ-2t674wX 6j¢))ڎ\JZތYR 䯋3Hy5J%'if\,eimQڟ}/,E+DEՄn eҦ3F)KJP5 N s\G̛`X0:otӬ^%,q[KGyja}EW{Zx`s2^>/䤵?XhKѕ,G [;BX]l&P] ,մ#",\) ƅ֪poa{´̽-/hy! h MI}KXTd[n^պ{8)+,jH6jV[`I%L6jDj#5/C 4l3a{diRPCK^^"`䧓7Y*ݻ>@c 4XlL\C{ zOyB0]L" Gl{1E,nL67T0]M#_:Znٺ/~/wu%?o'w[7f`X~~GQM "SǏ2nbpaUǪ-^6oO 6+5pz`XOw= V'yxxlݒ2cz)0K(f͚/gm w/ $,,,ڜiF7/z|_߱>a.0@0%. V}TFo/]Zyℋ =p=y{$t@Q[|55.O[|󅝱 4^8C>d_ɷߞytca tNPȯMGyy[:TcU#v}^&0O9jHat@'d$9eT|8ykbotQ]iJɹ~pz,.\ e է=W}_+* WvRs0jFڑ/ܚ& !f73*6JKR^^!l&h5ܼ6kT\|yM¦vIz-YΎ +544,\pqq/17xNVM|KoL WVXpp.Nz9|xm80WUU0m^xoNPNT' !A:]|Kj㔊MGM ٳgE=܊i v:~fmV<Æ V 9wT{*?J P\X.Z)BJJ'vcTMv~S+r?̒j  hM9;whX][[+lwo;2)ud7ޕ~vӯh [ wόpv,n5j{Zjaa攔t.%To4EV+:[ov:ŠTkƅZܱBzr5.xVrIp.X ?b޼}}۽p`t8YJtL^?ΉRQQZ!ڏ0cˡB_ش\g_KbrQsp(;B/ 1-ƍKaJa6'ՑBd! h =IX_TyʹӄeZAjKGZ]ܟ:El5mw&XBx7_GSSBIDAT gkv=-#F(ܖ_,k?l3a{gg:?u{`B+W,K^x^NGqw7nt|hM/mhr~?K}DdĈ\/^ܐ% G}vb#/{C c 4, d8k\,߸|ఁ%Uz+s?ʕ&VN tNF2M:o4?iqSN9vp_pᢼ9]w>pz`X2Ryy=aaOF^?;W*ovC`8"OOUnNa'ۗۮptao8qb{)i۶UV&\H/"^0l0at@HhNz \@C>u*#./'5r:pz`X22upL>ؼ57(\.j4ZPRrK?a`8=@J.\vS}USr+q?ˇ+V;`9\VZF#lȗ_nMKgf3%l)/fOp4`XiMn^ߺrT|T|\c+5\*._q&aS$,gG.~XΎߗȘnATeR-Q6Cΰçh,-i0hm>N>+(!ѿŋVx 3\JU"~v<<ZvE-RG74Em[maTkƅZܱBzM&)JazJ! N s\G̛`o[N'4W)'9Q**J+U򕚴1n-<%zf=QftbYWSˡB_شg_KbrQsᤰX~[jdz&dg&mw_d֑-ƍKaJaN7ud[;[?G#%:d`!:pߢTj0#G)Mdo~Vi+LrXnڦF*`5&DŽ{Z7ne\8mP%ńiJN7& !j!EB[1t4Ga+skhhjZLg%f~ns@7:>Ц6 4[z9J%>"X 2bĈ?. /nJ>z;m^SC,hXV2pa6PT|teGz„ݻ>p@aHñ)S~'8n8ɾ#ǎ._?\W3¹ s>\N tZF*/',L)?`Jnpz\ G#dcrv50,M'Nl~/%mʄ@ +-EN tߌv0%. p `8];gރV 6xzުVM8M0@(ĉ]OB3g7*l]zl~/eI֑~owںm`@ƽ;èب}Ĩ?={;_//ھn4r#z'*3zȈ!le줱f+-|6WGh8=0,2#:yw*eeG}/~~I&y!`ߞ'(H>RyJMMbtHS`Xi\[~oW^W ku 0z&7/OXӧӵ;uO 6PZzR#WXnגRCC eff op98TjK˗3),tpEۺp&`X*`/xE*(, gg% Y¡GՑ~dauuu>"`Zԓ k!k4kӵڐ)'M6lOR]ݴqd_.1J#NaEW{2}l\^}T?~3]^~ǙYR-Av> V c ,z;۟R]kR~[LàDeEeRxhy$cLlFk"*R=5_뭉k;>4whB4>k0=TӠw|Fxrm6V{FK7a![R&hXi֬yr̞-uÍ77[jyX_kI_#ESx}:}7Yf` 4:[߾}/Z(_}3_wh:!2AZ 0SO}o,wgF ;IDATA{Ym`to\{}GG_[(֦~X l{3^}&;NCGל/+n4^zQt agĕk-OXO#]InHn/vcM/ kffemMۦ3̻>l$:pz`Xf$ w. p `K |gffׁϟ.O>?S(&M+$$x`vQp]] /7\"#]w-yN4y%˯%~$kkw,\pjis)^{GsgΕ=>x6W`8=0,`tP__xQ{si{{hk5u_'Y&6B#-3ҩ'z-la8 0d9oUm%3>uZGzyPSS4VZF#l᭷ߑӯ䅿@i#nj|R[է 820z&7/Ot؆MoEC=Y=SByp\q{r^K#J ?\\\,:D-l-?RvKobe4SI 䢠ɓ.^hq[B΄ I5`/(_e: p7ux=""T YL^c{5}ag[0-ӧ@ׯѬMjCO4qذa^]]-㦌kJ-QtiV"؂gjRQ7Go?TW8~tygfI\VڹCZ6stیY1ޢ䇃Ro6& (SXIbOX)˵Qgd%C[?qR\:qRD.MH>FO-'n<<-ck3t :<^ҼFZmQӯ;OI2%74'ddQ]A!MKZyDrmٍWg 1iRݦYg Oh Tt{ [wόpvtaFڞZXX9%%=]ۑKI/՛1KUmy\ؙ55fe+m=D;񦦫k-ϽzD_Q!Um=R^Q5vw5n-["6m1J]R*Y`aK_0y+@FGnի6nz+6~T⨰ҏV8wk=X;^0\y\$'}@{X4x`8RxDXNM黋{5#jeEABY״s:^4泫ý! f\ :D0[[Y{FT_8{FtXUUmM;W^bj7 TPD(cOXWOQv%6բr66j7jD7ל(Gb lf ##L ,((ZɌVRkwtW7K]w޹{'pz,FwVsh!ѹj{wʁ][\?`0} 2E*"Ys1e__V7ތ_V$&e hXNdO81IΝ뮿.ѿ{w7(wumx~͖˗/K|6Wh8=0,`EF7*TO?nʸAA…U*_\`{4=-$ؼ 6N 5#}D $[RfL6E`8Yf˙3{@c :@4 6k9}Zр#͋^0w:pz`Xf$ w. p `K |gffׁϟ.O>?S(&M+$$x`vQp]] /7\"#]w-yN4y%˯%~$kkw,\pjis)^{GsgΕ=>x6W`8=0,`tP__xQ{si{{hk5u_'Y&6B#-3ҩ'z-la8 0d9oUm%3>uZGzyPSS4VZF#l᭷ߑӯ䅿@i#nj|R[է 820z&7/Ot؆MoEC=Y=SByp\q{r^K#J ?\\\,:D-l-?RvKfrQPPxI/\K!gB0m^}z{lgvEj: V c ݄6cj(iq\g~6rm61JbOq,\j:EjH3# 5q$(Stg[LvƛEk/"Y\}"jO>ǜ߃ ēMt-) Sc 44k̼}9sfpÍ77Q9"V!uf5%t<^ʨM UQe2⥌M+O  OWfOԇ4-EאԘoTc 3OjO<{K~*s=݅- ݻg@8;:mFmOK-,,ڜȥ͘*^c;qڸFڬKz>c"TTjM^SWBzҶ6NP-Tr~B<+8Q,qK1o^c(?qMzMo/_]biO-cGer a 4HѥaJa61mYyvnU`0=aZlocb!s5hw~3ênkw}zSyg mTeja㜨 TƍDVr#ՎV$7$!w VSZmռUO=0!Clmv,3a{diRPCK^^"`䧓7Y*ݻ>@c 4XlL\C{ zOyB0]L" Gb`//X&/ܘ8-ln`0ۛ6G*>u:zݲu_^K~*A5/O6n5.Ï"*E㧎7e ªU/.[RmOߞlWk]3ҧz`AtmmOغ%e@aS`8=@Q̚53o_Μٳ674w_:IXXX9%%=]1o^c}#7#]`8. p `K \݉v?>\|'O 'P(F >…6IDATno)ΌW5vp}=UYp#ykwN.pz=ؾY6cV_N͘|.]l0,q-0$9 { W(8#GR֤;sN;?0W^L`775ߊ0D:9KuYY_+_8lpjUǫG-/-̞m) ;#VpႰ-[M72&rӾMN~%CG iGm߅/8?0jFӥK^r=z•,MZz۸O/_dOp`XiMn^̬8qB*{ܶG*ߗ|Í7HuyyE'ٽ''d8;0аp>>c:upzSY5Hk6ѵt 'e%cdF"jrm6lO`< JnH7vbC5L]bp~[Lv#ɃAkq-ϽzW'/תi~d]WozR8tR^.~wqJ)<<^a\'491'fȓs!J'{x옦 H,?6Je|ƸۘoӚB"KT'3czKaFڞZXX9%%=]ە'͜yw.y ex}k1yiisPRS|5.ΚgW╞uYQR2iMc[MWj+ ?b޼}}ۿp`t8YJؔרST):bF\[P8ԂUz4!RRw0G FhbbS/U3(׾oÔŐ!C~:%pP#GD]Z8n)*•  6̜VG[$-w66PEAKc-!}AS:t1`8; *Zu~-o ⪢ A81&/Oh7Kz,n[qƣˀ"xƳBD|V&ʵ[-ahX.(83+yRo`ⴁCƸswG9޹C;kLaO@Lt᠂~>>Rq3  +j+R0^keʕ+~om@ᠮr}h5kD7ٴ eW+]0P.Y hXW>,!מ=_/ԿNxKTr0.??@a.H ~Pp=S~7nʸqEyE}3 N4,)pz`XK2Rmm ?tp1 JM7$:Nksϯпp \;-0,еMBmtN"߫W/ѹa.0@0%..};~ɓR(#77`ʔ+$vlQ>LFFzy֦bh8D,1+k[sڌW<%Z}r劰IXWWsS{ ўs;i/\gB?{wU;&H*Uc@-f 2K,!-"m-R WV.\2!+*") ) b e23sهMfG~:g}=o\p=3 >@$-HUEUXF&Fu"6@YyB4?y+Tڀؚ/ g~U9w˯9Ӗ4Pg-`>y:˗/ϏY3cݻWܿH.XN"M9'hTh0Z"WSu 0~EETCAA=;6'%Kig X+: Jvɋ.zdJp~o:orkYUfiUZ+(M Vw3/SjZ,ݿ>A+WjJbKhڰh _[G}Hӻ:U(qʭ7\HJx4xEMC_nXz`wߵsǶ{ǍU])fc.CJcp'!D*6K)10.1LH 34+|ncxV`=}V'dæ$-r~?_Ij[WLr_[dxT}~T>O w׏p5}Ṿ<;׈ٶ=1^v FַYY>[|gNOT{D'-Nj\!\iM}ʌm|^ zNbˁTUc3BNs s“{b/:2-/eu[HZt7%xxT'rֳr2J+3qRNh8]:w|G&?νRqxaӳjUψNN.[|C6ixiTa r3' ¦mڿV 8ƥyyC]HW~4qRu;JNf\\Cu&pmFh`o?. /ʙSvFh}XoQӡEjnȏ1M@m8Ȭ54^{ :h nn~Qx@bo 80i(b裖2ެ:H5Nߵdq "Y|߀G;~? Um1!d'qM-3ϱ׮5!c{_o]6yD:RZf̶w\BI<;2T: g,n˕+WE[LJN jա8ɑy`r9Ux~YTo"up:v@-0M{i* .XØoWF<!_n;2h RS1&z\ݾw~|a!J Z4cBef-㹾@9 9J6bV\;s~7n.Poo>CGaϽL # H#ݛiZu(בF 1HLRw}wlaZ9-|`X=0Ptه&? 4?[֮];a>0IIlDҹ@ùk5uKI(01$IDATV^;agP>жm[Qt`0f$Ԉ R`"@(7Lvߟ}ɓfrtt٣ǠA=GDZ 34Ddh }z^;pu,z6hB/^1λI K>Gy+~%2taN^|Y*lll,>-tܹᇽbG_ңwF-`:|?W2dm۶fhիRѲe˒ӧ Z" v]n15QlΡBM{ dy5jMT]ꭰIdfɋz Je9DUVſ*,hl:s0NJL7(4hɎ%߆A> ڼysQRr^&gRaѵ>NH}7z[ .О}A[s3ZRٟ&֊:7?:uZ?,ml箞kc/^ÓշWݪu+>z4o7)bߏ#t:ݔgggfM_mQ~z!89{)צzgO Z\5! =Gym.\~Ϭ,L5I jUiVGɢQ jV !oe*`ehibk47YWܹs/hN=7`Z |Z|蘵>>#<<޽{b5\$+۔sB8F{ Oz9 @vzᢢ_*ݡ`iiڴ3A:b/7{mmm׬ZGΞ=k2t5 1g)IY "U[ NG'Ն嘍a=('0<<+::W;)c0t峙O뵾]¥K׮;N7ǣOp[KO pοv쉕P('*CXRsmGstaՊ?hHXZb4ڹc۽Ɖ.t Kyb/}s4IQ"ac>&mhVFygPylDlؔW1G1ɐNTzkJC w @~ӯ\ kO!rm4Z&+\+v5mc+?/u{ʝc`]rmO=9K΢̑5S{ܜ- `(uVsTR0^FalQo>PF}^ޫf}W8Y Q*gD ''-jiT-' ¦mڿAT Y]Dhah_V'p}QVV a4y{{+Э[78uX4k3B{{q XxϚ&abfꔝZn;ɦ9_btPɑw:Lcupʠz:0,eA0o!^>j)Cn1<ͪ㽓wáC0aV|߀G;~? Uɓa95EP}xˌkckALx =5yNR+]mt5~~ҷΨۀgS|@ 3ڬ0H*%d'tu*,Nr7˩S{?zw}W폭chC﹧FonȪҌEn1{#\z59v]w)AFShѢEL<޻}BODqr35/t^Vj\߂8J%hd#fE~ʵs?7>{vco=tT^[o!hX=0P4k޽Qr:hĠA${'wǦݿݒ\`0C3ٳgȷ~'z{/lYvz&%e _$5K 疮]k-J@fh& NXFzLKA>@۶mE=# P#0^K@(`4%%%ȑ#?8_ 4;ػwoaC}}}i4@,fM|ܹoa«W -Zg^GV g#F{_Gʕ+}0c߾P6@ 6*\H&~1ecQ~FO;uhdy);6D Ueب` 3xYPT^>{f=GLۦ]c8m }ql7IQ:,_vZxBX@ 3hB.t̙JytT9v|rO;w,'U[IIoa2`e0͵_GWO='׳?vQ h}y}r#G>_>ee5颎͏NݹEK> .<qŋmݚ-8X;0HMxvviMaaJu"6@jU+D1ruIOj.QwR=o7[^߾c{~5}bFլ,7ے>=VX҂ڠ4*^cXbFh*Ϣ۶Q{33A/hN`x ]vtЗ/_61sA#jWjNJ[rIE#;!<]悫vwY5fcc#\v#ERg䂂mhժՆ/,/_?]\js}rNZJ7#_-!Qĥ#K{y+[嶧(m+2Y'`elqIkZJ~s$3\[ ]_>+/{Aimk\T5%>]h)v 륟utwܱq*njպQ]]fc.cctW$~Dq\7FI1`W~S9<1Chx!'ɏNoش1\D)Tڤ0.s+1EFbX5/WW6%l剪>a gĹJ€gWum϶ml+=1^v FַYY>[|DVRKkslEx{ )sfOI .^j5_3O;y㑝£<a̳' ¤<|begLɑZ-+I5eNӻ>ef99o$oԬw^@n^P.Igq%Sݥs|d2Q_W/8,yiO4,M'-C'P< >mپk9==#t~t͂\*%LѰ{_U1z2:8hmh͜޹̌&pԆ!Ty ?xxi-\ppz?Kp=ǞN%%_N:(/m׎ۊ8RmLjךRL54;G7CiJY1`⼕gZ`l+Q7\Ewb6~ 5^ItU ({tjL_%yy~ʵ/6g:v@-a3h\gIDAT,x,g~FXCum!J̸L*o*@c4RXh\,tҜ}Vo=C }VDFC?#FHN Jh4]2+kg˗]MK΁> 0fQC` P0@E ƍ_JO?x(?3/tڥ㭎k w_[n,0C}& dW^{]>#6(fճIMx0ogp/Z!0C _L.]TCr4ڹπ>ϹW^HGٰdÑHk!Cݿ} i] ։!0:uJ3R?~VQɋam[ 4 /DψNOjmnٮo˕+W[ @-lmmBJJgΜq"Mw_Z鷱ٶѬwkxTII~%[ akߛ]·iUB\?Su]&W=Wee5!͏Nݹ/իR֨ϝ.д9=zv%Kskʶ`#N7eUrԪu+ɑZ&n67/Ϟ<)`ԅJ[XX9zk߸pB~;}Z*iAżyQ jV "-wwRFN~J6lr[ϝ;y趱Q $E.]~5L}1k}}|Fxx wֽ{waxԇ;o'T;Jȑ6ƕ{ OGQoyy)@#U vqumk{ErM7IEAA=;6'%Ki.]jsCuѶ] _$kN^?p#Sk2lƦ_3GK5st[|#bOzeGz5" ?\[[X&7 5n7 h+(x%buMWÕ/8?ڹ2m<+Y:pZck je>ޡ4x4xEMC_nX߶m[X50ڹc۽Uw^H8.<ӈ0G-Sya)^9q嘍s4RV ͍h~|40l j̓stcog8I@)oL0\-2r&Utu#_tm c"[hjH"󙓡ӿ=?7Z?p srWZ:?/u{ʝc`o5 +}|ڵu$%@Z9[l9>%7WZHLIЏ:w<>Q~evN3 m5W}tu c=9I 'bor4rݾR*XEð{S&U}HSlL4ˮw KLRV]:w|G&?(J4#S[[^Ϗ{~H1-tb6x): 5dsoFχ96_'VD组O74k37;.π%qFf'^ǤpNE'}竕SFk1+;Q$zRN SE7-0VV$IHìW :}2I}&j}iF׆FG;kҷ34O!2Z`poEʚ8[̕+={LU-g,x>Ё+@*uGH a.q8uթç[?o~6+:v@-0鐧lmSݾwɛK[閘~%W)<ҳgEo,J^,,1.NCuC|WDg|AhQ/_5fly^Wҵ{WFSthnԯRE[6 $XhD-[LXbĨQ^,-J,@5hĠGiܷmö3WvyZ@c q99ڑrѣy?|WK߾ܰG!4:ggumO?_ K&R%t3$XG͙%DСê}oCQGw}7N4O S9?7,b"_*^Bۼ }dlЅ8'# Y|6K?Cث(^kBh'nOsuw[߾kVܾ'uY4#/PnzŸēf~ڪ%R #֗SN[z}'wCpK&V}HT|1eq~,Co LHȮ+>o>P@\]Iy&v KM]CVC.R8uOS=XZ_M)rV˳"F@Vq-EL95wv[yϖRoqsħS.Zo|AFqY|aMᄂ?' ta֥/>mV[FjFDK-ת hm;mJkA6v!Rrxx6;B~2M @!j['6*MZqmD5ϒ)eiQ'exf Pvf(#A#A(j! P0,˳"3@(`"aHwpI_m5Shd`"aJ%W^.W66*X#0Ю][8JIDATuhN0e(OyꇔDkϴ]vF`}rQTu)**:nV())9s挀~\;v.kDߛ-`-4"͏NݹSmM~uL}<;;[ߟ=%x#.Zn-sfq$Kzi wܹ_}soOKm Q~˗/ϏqyŗXɓB!r2E*((Hb] /iƾgz} $mݶć&?rYi1?XEK4O/L\q:ڼgH7!;4KJ6;׫ elzeڼ աCU+JOU:vvq󜗮0B6Ч"ņC^OMONS^O &]!nzE:M/yȨMҾ'nOsuw[߾kVܾ'uY4cvU؛N K ë#5Ŀ[^^U(z>1S4[뙐];V|Y>} F}^Mnڌ6 fvѷjKUf-5^Mc/Rj8m%3jŖ^+զQ#qV`X)^{>r]/zkfʔZnOӾۿ2a]q(@RnZbJԫ#B.{nj^}X_M!P'6$WjN8a0'V'f( 4G`dN|ڬ4%0P̉ˏN_:V9+/,Ph2ZK5jD4f *{/% J+j`"@5j P0@E  &;a! hz`"a66rq%rEh٢fҥ\f,C!%J+C?Ӯ] anݺlo~pp5@ :D.9sFZ?~\ a77W~o~04boO։ 󄅆żѩ;w X)bߏB"<stS>m%7g`ժZ2ߟ=%xӔ1^' JaO,رTz7.\ ,ʒ^Zm%eVͻS(ʹs^~5^>--ux"X/fn &=,՗/_61gpaݻw(Gj )((ؽ'cgZd6_h!w䡏DUٳgESsS_prU!MOE^^))TMȜ>m}A_W<ܡCU+9KXv; :vvq²xKF;K9VӯŔ' +Pxyb9#>eja%'nO CQw&aeV־ϖ/_6QԲ+S9R`^^.WiEMru9 `ԗ ==qN4!Ǟ @b4ŒIe,$Xt`%(`.TQSqC !xX,`X!\S`B(`X `"@(`"@(`"@(`"@(`"t:(`"@(`"@(`"@(`"@(`"@(`"@(6&JKVib(Bwu@"KЦFY;Wز⪎K r5m>T97Qq[Y"|ʝ>9|(Lo*ww2^\g- >mk58>X,JU99XiۆJ\.gm%JIAW]>p]V>6 Ьm(c$i_C.\;(*pQ|4HZT~ª,,U `Wm4w˞;u g,+˼eʺCƝ3?`_RCWmy60霮P~%QҶOʛ&ҟ!.nLN~h'%J]Ƹ/o1[O_]zvBaO]_!uX:UHi3|c\WsC_KŠCYuԾp#DN;R1죓!>N&N33\ '}h~ewzjWqq+םFi#0kL ֿp՗o^`6 Fm7''tUx}Rblqv>'TvMDXC}ڬ aA0!ސ~/.N/dalՏ./4JcV~\|aalyH59N9R=BYrjx6^+;]: gSOmh KQwt"]qL9TrٰߵD^Kl;Q#wQgE>'?dR5rpb)Q ŶٱY?9#VKThr.v9_TX(Ѝ %OxɭϕJ8UfĬ*!$J* )7f%O%wU#'L-#7%A9YYj"Ucb,mc|] 1;)^[Tx"\zN3ڔ'XN60gW<}q(Ða!AjH`KsRRr✔0w}?g5yqS)6R룙1ӚQYrwlTDNCp|Kbߌ~aɦ$ĆکT*R;gk9, I`{ Rqr[]Q ]ꭎUyG^v͕?|NJ9hc N\]݅̉p9J6+W驭Y^E =?[+Nj>Z?#D*pa)ylӺ<)z ȹLo-}Kfծc'?r{Of7#wZ>Otw;ܰXik}fv396T_37Β/nZ4{`&0Z?3"~9i= k"_l>} o 0D;]۶,ENuʛ5?p=?^, >B'N9}P&UErݲeˉN `by _~)_ر3ӧ#_ǎnƒ?4oph|^<1~S}kmۼFVԦm۵K~yEE7Cl4 t=hL3gEw}iK?jߪA#ɋ/4@,9O?JHw t7Ej۾֜+8sW :|UPkN[^E^fMe]pxڮt%+uX^.BZn%&oeJ{Bh~Sߤ`+W`֬_qvtaa\> "`eϻzEVVY{mQQ\ض;o {.5m$FŒw@;7_~`M5kHOn={vlllqqTUsr\\llj썫׭9R{m)fcbRIHU{o̙dȯktsWzEdž9rg[ӿ߶}Ngԡ}C?fwYCNn!ä"/'O4}7AIF #EC9xe|,ŗ">7-w}=7w٦EK;;;# s]:9rV˳" gaCmllˑ_}atQ^י3ڡ#|-ti_ܜrk<ϳ~8r]LM~VJ(~ Ǐү͂2d//K/zf'^r}8h@IĈhgV@oK/h2_QN[|Du w!ʕ+Os\KXvɢb=ޯ ͕eܢE)=Ο?/-.wߙۺukQW~~@*VDyZ][oiiҤIe>r@?ZN|}ƊzT[_}e{6mճмY,-[\2;tSin߻%ƫvZ5S""uarѧw^|^z_Nb={|\/zcQds>RSv0sqtŧ3ug+ar]5mȒ<ԶѶ~^|+6>S;sodɆ=%/~;NTKn`9>>c".\Ӳe˄+bW/A# >π>Y};I-3և5ZOA ]tXDža6,nl5|4ofoL瓐dNNvCggg #|WKXVZ֛|iQoN&}zUJiҥcx+!nt:]Y",J=Gh ۶=',SӦ1ۋ3nTaɛ7ۺsW).v55! kEЃ&1z{-+ggS^Zk1^ pu>Y^/)G"='Rm7?\ч_\YatRVD=>ɭ)ۄeiF@QoW\ Uŭz^7+ 999 {=>}D~νr=:8~_OYFZ<1?dn_Ov L6ήO|0l~Xk֢ykӶۥ؇zz<墂"i!OzrѡCFXymm0sVd~1~7ݗo94PIDATbK3MJJJf\;v.2YRkLKsU rpwNan5Qm۷ߚ3W{Mu: ܕ.B@seo=N[WJZ>wd8/5k6֔mUOiҥTh0KRw|iK. 3}~\j]ߩk#-HU^'D0sRLgO Z?%@scI8aZU?wܻ7SoO5M2@ ohHeęZ\deeZ;w˯9K M[Βf;psoNnH1|}Gx wwv[Mgesضm߁}kxEQ~wn)ER?swmNJ.((WT*[Z-+|כzh#~9)IzIHO9Mquqڴ mjt ?8Im:GK1.3 |cΤj뵓e$x\[v`^QBJu:tXbt n׮ݺ~'jnΝE_'VjYuQI.d)NJL"?:}~nc J ARM0,I;l̸.6{c)w`s,;sf-._\'& s“K3)nYf NQ8]ʫ]pD-0޽ .=gBBvXg}`p ~lj9 ŖPӌ#CW Iu&KnB+͐+̚;f'^ǤpN݅y<6 NG3`羊vGf Rgo6Dz'e1SE|wѳGr!"_HŊ#Yq1:D]uaa ݜjNvw]#C[n3V4^={H/CtSin߻%[:O ǦwQYR8E#ٳχ5gT/zcQzLMÄ.ӿx T|˫/,@,)78_x~MgK+2ůtU4!Qg>b\y񓏗ul\^˖-V1jۧ_h4p>sq*k}+}K3ž5Z4c I@ES))='-W}%EQTDΊhdRMە. -&:u۶zJX~u_4AKaI5k"F Kbgi{ a |~s̒|i[gE̔^`ɸ`"@(pvߟ}ɓB:vxc޽݇ P{L{2RlԀϜ\ͳ>ڊz٣pw\ẍYw[Ε+Wޏ`Ǿ}Secpw%+w_~U* P>Ν;~+/v8..=zPkB,ȁ#)Svl!1r>?ʑ] Lݺu*N{dTSutZյ.&<>!1>1:<¹ ǧ=٫g}-b{ɒ@C~UU.Ϯt+W%%'uPhВK~  tu .<ĴJw+))9~\k` ~E5EEE^tͷޖ~DŽ ѧח.=r+*h:d}%cwJ^R!}=C}Nۣt[知¶sml7WUF{znM~\?lg(8~gCݛ)/feeŀDM҂&nZ֪'%22; 3%G&3۶Q{3عs^~5^>--ux"̒fۨsv%ޜܑ^c~0Y2pOvwY='hN"lll0Vlݜ\PP`aɢ  ozWw}iqsR,))_5.W¥r+bO蛷eJ.lxHoF[BVU}Nbحaj~e.\ؔ~;t>>,vm"񝨹]:wu.Ӄ=R ߨп6g=22=]22<Ϝ ˹iVJ"ficoc\38I]'%E{'vSO9Uu5')eƶJ ~S%YhLǂ$^#vy?]fȼ\h?Ut7o> Rl5-oMw f׎N3&VB=аs&93b>n)T{L.^2|X`)6 C+K{_÷ M)fcbXw1-ȁӐ~4?FM DyD;9G/H4=gV{xD.bclvM.gR{Ϛ-;M?}u~,ۃ /C=':d"Wo =Qm+IM`WkV&7Ә upYnn~Qx0㤜 u6Yk4ǣ PIxwnΜ~*p'hgiyȴvqaNGuC]7L7WK*H 3c\hT:]pY"c0a v ] !Cs]qT 2dw+Үc'J}=4* *[-hn}.υ>+JYRXqճ.Cmw/AA/h)o-.3",YLoћ6nօ0K 1+P9kotE/Zʕ+Ң]{v[ X`& ^c4-oHA# $Xavzv_njk|}|DK '5뭢9!0Q\>{C :tj;xJM > wќX$Xgϝuծ] _$5KB'nOO_rqM7 h,)zT[m;DL霃>x?vP)?+uNJ?ۧ/ `m&-8Jŏ=m6VcS@=y%nZ@seI=ztb֭7گڕ\ЌY=ns5Mە.p$O֭-O@3fiu띻~ٳM~/.VZwfpN 0~7G MCZ [[&~mIDAT"lYsϜ9WIǏˋ[~cѣ6TuZ}?M\=E~ AEssXs۷o/宻xlg'-7SW5꺭\/\Pvg?ڜ/eIA*7WUTK:rovϟ/V!@-1w=0@E  P0@E  P0@E  P0@E  PNX;:E  P0@E  P0@E  P0@E  P0@E  P0@E  P0@E FXUyAHt``d]@P4:E]8kYơN6>˲rU*Jq-۰)sg&6O^PAe%$:]K \;+lYVapC nvܢ U}T~m(a}VŽz_ކ'kP(XŬ,GGqz{[gn˽vmOuVR,\yhCTُzs'ƌTKQ^aŽ,͔>w2 6< J6H׈i=-\~NKܡIkJMZI6_zf;ߗ;s?+~pcUS"Wۡrüֶq:ʁ^ |>!װCy˂]8I ɒ! 0x쪼ҫiM?3H_N]月*Z9SKY l QmN_h^raBOGhk瓰)[:v}}𰏖MXb4jcc>Nj[TBXp^|w /6lvNt|Y {Uv2/ÿ_'zP郃 8?+쀝n_*p{GN"7Q`j3 FWvppl"ϟg*@E6vrLI5ӸT'J4]#Qk83mj*y*$.;WEQ+mU*<:(̰w;A͉  R_{ue='!$8 pvfsTթ֡!! .H),./IьY(-_e1ϑw>_,Xo> 2 6r wi<.d?>xX/x;MIC?~)0M_P^Vr|DʔHArn'ZTj#|ӭ؏RևhN|r"Q uY "/V<#\ۚU:saOdKOqJ]u IJ2N.ĬZ~dFt24vRiWgYޡ:?kҡUU_P*jٗ9`Ls9o?躙c9K |.fCH`j7$&@EOJ*kJPP+t`9`Pt@(`"@(`"@(`"@(`"@(Uu$@`"@(`"@(`"@(`"@(`"Xsp¦6HMݿ?XAA>}!;ػwoaC}}}i4Cӿ}ȑO믿DoPNt?K%۽gϴ'C{iHOO) fE믾bkk+М;wno~ի2YoWlչẍYw]66[W\y?h6~a >rӯ uqJE^ܳ8ٹֲe]\\r~JJNWJͺO~26񋩏?a7q}'F~XU>GA4cK>$"e)K7I!pݛyX .Huvލ;5xLE@C|ʧ~F y'jM_Oޙ?챈˶JW\tG[n_'}u[߾’Yo z֥K|mvss+/C#+VA}~%?+ʰ?,mڴlRjsy{3顇z7Ȣ%ţLU YOfw,,M̬'O 4s +o i"7,:th-Ibݎ4l*ر㭎{v6קFS!m̼{wQoJJJN~#G~>q⯿֢p/trKm!p3,LoIEV={=4 nѢ>V}5E*>x?37?_hя[hq /J=ܽ>qm;7ov51&@CisYn/WnkGU%wʕ>͟-[:hjfZ7jN.N[Zޏ? jGovUJʷQ1VhJVr}#SүkԚݻF !kã/ |ړz<cnbv{3 yZ۴k|M֨npj[X:+]b媤d ZcI#rB>in… =1= "Μ9#ԩ[HE..[Nj?~\W[s tV W>.]z~1 e|Jwsppps3ha?Yj+u.ja‡bo_yy~MXW^hpq~jn;+-)Y*l]=Ʀ?>z\/\BCbԝ;9-X.>vPZ~Õښ-8 n. Xv/43m.yĩTJf7GFd̪sacydzk}faairG^xD4Si* =!Zm኎ߔcFOtF#_V&Ө]u{wυa wwN,IDATj第,0|VҌ|2w޶mkݛYn,YԱ~2a)qy7Nnh߱s?g<22tqLp\^JJNRmgŋӼov\FZ$ˑ_sP3:o=_g?d|5#[j{=&n߰WS q'VD组O >;`2? 9L1&O%<.)tFꀹ˿J**0$r#knRKϞ5IOsJUQ?;`2{i* tin}.υ>+AXh\,tBa 7gRp-bɵ]M(7+wV,9u?O49bTHoyx_n'32j, +hX=x4[MKxfq/=}iήNjFɒE;vS'O=}d/\MI?34$OR7\Fv)9QsܵkL>zCu(בF 1H4cٙ3]M,Zبgz뭋MzX\,jٖ-=uoqEX %7NUݰg,uv3?+>ƭMٳM~oMCV,sh|ҧ>I(n^;RSaŨfmv; !4| >wi$'~}r^y6oʠo?{#(4 C+8a3-M4.;>#8p}|ڵMٛ  EE (k,b@(`"@(`"@(`"@(`"t:(`"@(`"@(`"@(`"@(`"@(`"@(`"Ks>9ArN.ԖO(tY,py5 >_qph2x-j[p%)Q5B.1Z>neR#rmrS{U$!8VNqv1_Ppqrm|µ%eޡ[pQqB’aðXڿ,W߅˔u)ts<9{QOj)R+H0e}hqV^fl>W0X9/9_cglshsv 6OeV>,*32'>mXj&夤7/Isw"Q_S:鋯bS oq0%K=qu5C]| ]f,oS*h&8hYbit:]Uۊ53w]{ҮYSǼ_hg.2/ZģL .p yu`;eyGbٗvPm]FOYunCQ%Wlιf47P.~)3?z蜮x{T q[EL瓃| ir.gv|KX/( \blT(hF4*a$wnY#T&m`\C7 YhDLUۧ%a;,&+=L#h" 0:}yWr<@i<^vXZdshXLP0@E  P0@E  P0@E  P0@E |Xv; D`"@(`"@(`"@(`"@(`"X|NbݎgxwϽ{34cO+=)9ٴRo"o1{]r5fͭupTU݀zQ'oЫWcǎUUjHMժ/L\q:7Q'5>xȑ=rg 1V̴gϞ}h#~]"i)KZ{-0Oݧ,-z٧hRs%-kױH9/]a|t]?m[HY8qw/ZC 8ȹ]v]:w mOk~B\LyҰiho`!J[+P4<λ^yr]L霃>x?vh(o/7+SUS?p1Eh{Q\qit[6C_ai*^[UGv܂%W^}δ͛6m۶R+KԤV#̥jÿ26SRP䵉_Liq;o>4*ܨ9s:i+KQ̜"!zү ܲeKnҋߧ>\^{Ϟ)SogfpJলwo!O˵Ľ&a壏L^Uƣ6BCA<0x!Buc{葼yO=%/~y5poa<z_S۾f> _LfB~,.7mNz֭ۦOp4 5'6鞸hw榦eggKo͙J88Q=a,ۅ h>dѣyr8pC)nf'K!Ip7hr#.7Ii\\|z6 +UXXx~.Ỳ҆@W05tUMSF7aCnrTdfe )q:7awEǎ/ ] 6T.~́􆞑H.݇ h>GVT6J+17WWW믗.]jժ1 K;f)H[ _6kӦM.]~+W 0@X<(ݻ 3)$X7@nbHgr`/y{Q,,d֡1KJJ?.4to ~E5{b!t4{i4Rq ~LkYo)bߏk Y!-Z'ש;w4s֥Kۿ?{JT9Ϗ?O@A1Fzz>gxwϽ{3:w˯9ӧE;N/^$9QU5%ŋwy-{>7֭[f`iiڴ~_,IP$tه&?ߕ[/w ԡCU+9K4W`@}#kn5KOKݞҜ/%#`666ӟy:ޏ!,ޟ ٕcG@h( Cj)P0@E  P0@E  P0@E  P0@E  PNX;:E  P0@E  P0@E  P0@E  P0@E  P0@E  P0@E  P0@E  P/J88Qi–e ,JU99XiۆJ |Wu? IdS7B(Sb&,)Hޠ]Y~ d.+a%%T&% 473 <|z}?9@ hf8giѿumW!J5^y8a(y͛B(?@=ۗY2@ h>o,oR~N5ҺMH M?x\ΰlݼ~ݦIo/USW^yRH#Ņץ3Vd64wyZLϨYhQy|E ?6uRHSA.ݒ㪧h{ fߣS}KY]<] 45 G$ @"$ @"txlzZt+,\2 Ҧ?* 7u: ``"X$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"0@ҵ[`{0 0 0 0 0 0 0 0 0x=.^dŊ{W^y%>]v?={;oIÆxm{Oeժu[߼߻SN ҵ[`{viqɓZ}}?i֎.~9w_Ͼ~ag=xI4^ |)[%`u߬nޖذaY;gś]w;dd̰U֪VXEX~ǯosNԺLWMm `GR(_x% 7gpδzautuWΙ7k7m_;#O8@RʝsZP\ףǏu{(ne丑?}՛6m?H){k }&Θ?뿬Z; T ~嗣SNͽC}'; IDATΎo%:R)?CqqS}D.q|y}0{T*ಲ8v];';77{bsF,l}{w:Q˖/T ֭~}o̜r2{ !+#:tV=eK&74'3/#lѲtt [CgL}sy}N#OGWDSn~/{G=U22o**--=g~-|3ffu)jmY0oVMsFa3k#Ɣ -޻R oYmcmZ}?٪cf/-vΪW_aMY+"=G ER>ؙ?u0WnnZnn~P1}xڔu_^_:)"9ÿЫUVY0U>fP}B_I'أ`Jxgɮ])ԄG͏~W<:R)wq'PpC؋**&Ӈ6ԑJ8r.YtsqƙWμ(6w[~H)iM}򩧖-[ի_X}щSsNrݧoU+KV.b"oH9?O-B?\#ƛQ@^a;Ϝ>$h; DEk+v;omۍ??k ?C֥kp;Es^O.m}[ꐃuy^~ m #ي #DHDHDHDHDHDHDHDH`A `A `A `A `A `A `A `A `A `A `A `A `A `A `A :4cUYIdwN={H-;LJOk0zvɬC2蜞3vvyu}&cӆݾ}fPRy+ _3nTw433NϺ m /43%:yS7j/6lnm ei}&WD)`kKάY^^5JΝe{Xxc}s=oRE/@Jh1Hrݼf6H%MMڜ~.x ocWB... s=pfzFE}7V/Ua Bz RuDW=U5-LJx}[^>)9_n{QSwϟ]zQ{to#봋gܻFHHDHa+/:c켽+gqShu. ~7S+qؼ;sH`0 0 0 0 0 0 0 0 ; U>^t-$`A `A `A `A `A `A `A `A `A R>ϻKXo/+gϞGqD|@VSSU>mOO_ڸZ{헷q ҵ[HnZ\|wmw}{n:tpoMu߬nޖذaY;gś]w;dd̰WTW^,{xO|p@){&XQ/(.7sL{ڡsuْx}n]w!9箆;z[ߺo$F]>*|@ۓJ#ާQ>?}{m"Ͼսze>왎;V2 G۩s^Fo[ڻoV\?ژT {p\7\'mG*ಲxls}͞6KGMY\Z:h;>RǺu~홙3yofs uhc`nXU{OŲCk?&dQ7[9 kV>1;.'.v&O?#L=##TL^pSE/;8)knnNC>mLZMMvwSZ8w'@/(.y݋V~hh3^z>UVTϼ~J{ҵ[HTz})(}|s'7듟<ژT ;v1qe7چqٍْ3mL=/eq]4O?}ge愂+ڞT)CN_ly_85甜'?+g|6wⰳ GOȣ"z}ꬡC v^so믇}:+}k 3 8;ͽ;z=tiN48@[Ң\y߬?F?82@*jpmY0*@[`[z{M۬+mKc;8\U6`Hfm3.{l,.;${;gG˪shV{q5Mk%}2GoK&k؄X_ߴi]E.XT`h:VDVȪ̚fKU;W=ʆ>8S[ŸnIAkW N+8[m[ONeUpn{dڐp9Gmu}T>iOUgU`s!JfwlIDATq='n={ϲM%k7}ó f_QW=>2.W@W!o()!3$aLn^f^^: 5M(Z;wO[رu=Ǎ-#5*f.E ˛V4.;,{ĬO\YVR1@bR.++c\ߵsssݪrȴs*O-]=1#씺lrݷwlJxݺuqo`홙BNfZ\y=fСCu {1H mS^dIhR}Cs22B-KG玟[[%cy3ræln]:%mgtj~ ->O?tT\~EA ;eGR1HxsPQi<9ʱ5o g6Ο_^X7uvѱrGn5:+334SN}j[= kM aMIetͫ0owoz>gT싟ɰ7dL\=oLfE_3 g|KZshv)'}wi4^ nsȌfz~RK^ZbyE\ 4r{7ZkLfkk׾Z3,7,߷`(V 3K̫ɜ6~xYԢ9ύkֽT~u 'T o3*㡋CC,W2=֔Nm*/EA[)8{0 og'կVO5&yO?o~b}$pǎgLq\/{b 7bqP?}i#GR9 |7/뢙E~?9=7ly̋r/Zh{n}'Բeˣz /:Spj)9OPOUjeO,ODuCݿSyVm=x>ȣf6Wh<3 ;+iQڽ4HRRU>m7GzhF3|mX@p;Es^O.]ڌC>xy]x;6y0u0DHDHDHDHDHDHDHDH`A `A `A `A `A `A `A `A `A `A `A `A `A :W嬼RţbTfǿfn,>:Z+gWEE aKS7>ugO_TSSFfAyMA`okz tIAz&TmVL蕶ō)ӶMUNpw99 dw?’Z]6{R~NzûGGXiٴFpknɤ-v]2k霞3vvyi{Uί;߰a[72*|c^X >ܱ e MUE#rο]ׯ6wBn[T<6;ms/8íM랽>/,hC+U5cu͖j+O]ܰk4}DQUιmy{Խoo?;iZPU^~3. 8i×޹s&7~iUu;WysE|E[I&kN[VoΣl[)h=i:kV!=31qEqш޴}cѸK2Z^9{Dv]={n;z_/J I/'{Iu< m{[lfoWUѬN_=-g3ϚuV]½;GM+buOSVYhCynEotioW^`[|,Rd8giqq 5M(of4|Eso珍G= ==s{+ݤ;vg U*\TU|f IOKKK//5]>y/|QQaA~N+[199lc݉ˋ Ggk>3$}~e}!-VSSӂnf}w⩪¼PUxjT;r]\ŹcԽM8bUOհuI9aco<ӟv+puBˊ ^E窿PR>'MᗸYy+ yZxpٕ⴬n[:m3]ʆm۞9{ܢWӲz|89S=uU7-.eWag|Qm>oiX]>9䍧nտvFh@j$A `A `A `A `A `A `A `A `A `A `A `A `ahtv`A `A `A `A `A `A `A `A `A ?O/믇W̌rGIDATi9-bi555[CWקއ=⦟Kn`|u⻓'v޴nݺ|k-z<:h ?:ԨO=x%KO=ep ?qխݻTCf;}_{u1GFT7ngƍ}'RcjS&O{ I78K oWpCm[:*S:jw|wKϚOƸvCH&OYoqy?+~J\yU'`_(<˟ 頏4i|x^ر[n|ٙߺ[!}O_\ϽT\`I\b_k];';77-77{V dGhT @k^UU<ޕsF,lH=ǔkw(gpN\v YxݺuqѩscL̬{}oPXv`>ᑿڛG7/YҒYeulގEsϭ-.(xJq1c(.6iҢAk Gᨥsמ$cₑMݑ5q~ͽV'.Wwn~/@ EZ|oFm*?7tЅæ,kmkffM;:3hjY,Wzb **\3}0c~i3LwF4hn޿[ЫyiΚQPQYe.qšhwLf8hjm6~`iѠAyØ}^9{0f 37Mū++7nxןJ~S DEeyeݶ_71r.fUqqF/î/R㖏z~o}k3{ȵg>O<黓'h/F?'?~аļAկsZ-b_YcGF]=nxa èuu̜-T{oV؝*WEzaל?CvM\poZǎZ>շ_ŲC+-YlUs/yfzs*ko?#LU3OT4supXt)QK(|TyvBC>.x?@7}]ړ~p~^~׾uvֈwSZjW*pfj{4îcƍ;G^\XYad|膺_~?IUt_JgR̋6;u]6yn[C*{)ڵkoF\=оc~2ㆆ"#<}{b\E␚^ΝTjZb}w.Wʥv'e.]⢦&owl\_ >_+r?ϹeK_w~ZxnZx F<ēN\;|#)ΓO=7jO&k}UϥnhPpCN _Syl6aƏ|\a78jE_1bPP+_UW]x)֨h^&mG3yk}hc>zPx;TWkt!}Sng|;6mN:u-ufwc/sGܻjUH5,??>0 v/e]!0  ~ KU^^_WH5={<#7G/U7lp?u|ڋ{헷qagYh:{3NxojO7UNW;hRr{lhͻK.mŸ ]-y+ܒE{;Y:%-77z^ڼ^}z >{p\?C-9dŊ_%Y ^lyJt\|GtP<%SM?1+kkdfivqc/6l?!z5RGB :[^Qqʐ?7lɃ 8:7-͟:oFژ9ѿ=oPX/G'􉋪F5;.Ю.]^?C>G D@Vf6msҚ3QdV1qum{i̬ koΟZzbFa=ǔGlުP]Y1}P{aO>!kfMn22Cs:uZc9×<3 ]JEu7.{qܻדK_;4/ʨ<V-.jUT:?o^zf̘_ZlUth:qF g_O;(k1s  h$f;yk}hc5~6d^:ˮ,SVznsߪ~+gg?{Fˏydnݺ}!뽩Kn`)Бn[IJ}Ν߬O~3>h$K#Oh{)/>{on~8{v/A8#Nh:_ҥKh=h2:ϞBCG?ww\H|c.SVw믇TvG7s8u7HdMfGLڽčL0 0<O<3kTVuvѡTvax`KX_Ʒ. uk/˭:*@!wǟ8 !7.我_?v=@SW\yǶ m c |Oy̑;H!IDAT':9UZUϭW=*j9G1Gݒ3{qѱcNHY?1~>iqdiwO;6E9umڸif͋7333<>ֽ!~T|VKhKLv[be}VkC3wv~#:w|{}YY٣֯_w QJࢹw[>uqу>g|1#俹ի+7;v QJW_{6nky7^yᇆu<Q rM|l?ڻT]hɓO^y]8vgl锴KC֩sGXⱗXH^fpe˖okyYY\ iDSrr}rȴs*C,6}{++׼[ݰaw Fˣ@A:[^Qqʐ?7lɃ 0 pp?]vߌP7;ؠ5S2[q@f^F(Y9Yiæ^tAQK/='.}hAqT7t>Cٚ~?36Z <̳?=z{㲚?]ffNkdGۼ6Ox^[8%{چjrƑs lnGkr{M_a2p݂}GwL\f?}Ec/407w+*+à[SK[t}o; ܯ_62@,p k^2{3? ".?OsLH^ }xŰՍotRMW"Ϗ aUnJё X=@|}l}^;'{ht)3C Ua{{Mɬ:(;}xPwF<ȰzސF[atf4;hд-a茉s/6yc2koyÇӝS6a{+U,=#%,f;yk}hc>zPx{Gdzn\xϦ,]\2~>=q^o[TuQ/<"%]v }Nc(^97FH௦*'_uezzzHv9[o9=K}ޭ Ϲ'&O~ް>=ǝrܱ=C{+w>?[oǍWKv W6/Vر㷾ywuNihڝw}I?١ O'3zRޠgm&|A\v)%@\c 6yfYٵ{ sAVN V[[b͢-~`q}0S_qΎzwb QJ;555^|IC3i~hH(Gmkm~#@@qq-8e6A^79o`fϐf3fL]* gfСC?ӡnC _z饆YzWJ?Ѓ -X f_>;og虝hk锴h@xWÄFcusF)R7-߬];';>6m}քp|S~hr:33+Hmo4IcKؼUFЙDyc2CǗM_8bӤ]+ Teeffui _ĢϜ>$w)9:˾q؋\yu[Vv3jgɘ8mP]33'ʵaP6W.W>VtJa#.Y{[oaFVRU}痏Y<%wºstjuWr񵻦YZ4hꂡr:qF O(ӉOO1qumѹ{6́`4n/mu_^Z׹''f;yk}hc>zPxm.(.y݋V~h`W'xca%Kz %]v Lz}k[jQSvG͏~W<$R ;v1qe7b9m9@"^hfѹ:ϥIqƙWμ(f޽/oEHVluS|e˖GV_tE~ԜSrܿ!Vd'?'_ܣjo8Cs`j tK.3ir!F3|_vcߺ~?)@) K/מ04HDHGǟxg\rMhG=䐞秲 7|[JD~嗿}B;kE+V}5]{|9H}p_OЎVxze1K?[~:(%GW\yǶ m c |Oy̑':9UZUϭW=*j9G1Gݒ3WK.=Je?yCqdiwO;6E9/\IDAT|vq#O>oּP7/z?͞aݺuqq(%@X>Vu)q38gʹ56֩s7MǛk=jof\<d.{wÈ׵Gh4{` l3qՕM ک Ec/Q^w+o yD#BVzk=[xOf.UW^W^5yG{,(qC}!e-, өsGXⱗ4U@AY'8`ٲZ^V9s?Q(dN)mР32jKGc\Y6l?!hyٹsЮd>⢼!;Ÿ,:4!o`O7#d"3/#dl[VNVc#.^zy;;ܓ_Z ]K =Ѓ_p#<o>`AS^dIYe5t-psҢAu)iv ]P:5dM_>gmvNG̬Z{9#{M_2&Ț>a‘'it5[\`|OGws|.sQ<;x$k)9ܥKw9{~E23mEtXե5kĬFi+f̯k/-]=bXµo]3GP\e(033n?b|9ю1 a׿K>|t}Č^oNfмNMlq%O,C@{#o]K^\4݂3 Z3h15{OʈoAm\{߼a s'4\R3`a4J0~ov}ponС~*9G]7nyO?'~}GqDN2yҽmvVVH8*Y; zfZP\|Wyک{s.l)86,??zzmIP `A `yܻxɒ+V^y啐]v?={;oIÆկ˪U!azC]o^]ݩSlB^5ig>;4w+OfA>/-.o /Dʕ+=u;ko\w\uD#23CU֪VXEXD_ :]4,?GGBy\s1=JO}O\XrG}\38WgNH u?|1ɝկ[nݎzvE?RnXiŊylOf4u~hHF퇤oQ}KmߣbO(F'޽_sM\0 'B8jK|xd>?az\DÿqO'Ι=㨣W_{-̬i7˗E!=wק G\oEdf\@;J-7u49W7yŨ=sssrs W]#b7/V]<峟= ک:hƍ74,y;~5{9eihz)/9݋DiyJq3:uQ?pTlذa QK٭[RگTz RG?V-[q ;yʸCffO6߯*f71#;٥F?G}hAK/԰7Z?#@z8CS7z3kj'ٞ;xwygNڵ\K.3iradlYIVffhG>/;F3|_ Rr8˾q؋\yoR;x(Ϋtvma`CEڐ,Fwn>ϠCUݲz[T9~8k]u^t7kb9ä́ꏝ_3fMZwk/Fwޅ|_c@2C_K/߬>_|Ű2k4% zWü-D>fenosI 5>+͞0k"Xu\MY]UKÇM?qT>7}nFo1tAKpؿkK:@lw;o)eAq^%kA'̫fNm /4'Ox6iԽgwm=;k70r;GBɴ!cMʪ8T.),\Ss@aር.gT7 \1mV6GVxsgYee}\YhSϬٝ>dDݰEڶ]x a]51SbQ2nuIqE]mkq_Tqc~ouqݾ>.?@*C7[{Qv~ᢪx xcy!-KiCUш_]YW,()̯_dRuI9Uu۴؋:4!}}U^X0cT꛺ev77_h`C `A ]z+/:c켽+gqShu. ~7S+qؼ;sH`0 0 0 0 0 0 0 0[E@ `A `A `A `A `A `A `A `A `!{]dɊ+KJ+zyGo'_ yi555[Cկ˪Ua:w~yڰ.]dw'OjzwY;CW߻z ;k`?zPxm 6yfYٵ{ sAVN {EeyKyŲᎷߊO:ćGo0@jux3gpδzaz1W-)7ugZZZh=`RʝsjHǏu0FҏLazhݿ =4{}_/}Nsӷw&|pQݫW˞رch%#{T*/(~8N:wnum$E]kʅCIũO=-էuuvR.+_k؁6w9knttnnڔuk囯#!u[.. \ߞ9ѿ=nf6׭ߠZ6fuZ/Yw@МZuc4;~n\fL\=oLfm۔ C:cbńkjw Y3uPzfgsBڕO bAjF[ǗM_SZdM;JYufZ8~۹9&w)Vܳ`޼F7O9*,፽C wWŲCk~hh4xCozz@J@w\s?|qhASk>3LIܱc˞XvC m-)83---ƤcNnrEιѵ|o-/Z)z߿w#[iNF-,IvOuc%CذZQptkK="m=κmQy[gPVUcS_笻6|m~{O#%2‚+{fސOxƂ;b-j\wkJ6w̙T^]gF-ذ1N5:]5;~sƚF*oN$/\Wۼ~5#%C،j=T!a쭼CO8i×.ntwo8]Ug'Oꃖolu:UU;Ip٤7׮ 6 Ioq/,yaFUhvA~v|Glj%v=+Nb掻fILo͚6-S[i7PdO}EOW7J[>iOӳ\QӇ,*Nhom`T0jA 쭹E.yKU+g|#e FsGO*9}c?Tt5Ӯ,kqD56ԏƆˣw!MYuSL+jjvAUQEٖ^\?ꢂ޷ӨݹT\4.!Pׅ)E%' n=z:>>2]?{^U4+gOj{Y( 9k5Ӷ֟öʢº܌:(aλ9;%&f|GwQ;$Œj@=~ֽ'm,6)x7fMfn>,)-8<wE%q׍Օe>ׄ&!̓wڬ8['oZeUVY>BIdvNKK˛Uv={Y ++(.w*_TTXS{;v}B Cͮzbr챳*7gG%\+ #.Iibwuɤ6UOU-3ι᩿ JuvSճ®otkGu˷|pua7inW@4ʛwIpSj`/jfyJ6^0cT::ۖ?v]V} JX~emU7=]B36VoY<}Ϫ½WG !qc/lؕԶG9{ܢWӲz|6w=Wݴ`+&߶wyWo(iHaOvZ3#{Ieav eƢmu]o`wHʯT~CUӤ_a*Qp>ׯҲ0ymc,Ì0 0 0 0 0 0 0 0 0 ; U>.]#$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"|~ti+W֮ݫW˞رc0;JrAqܹoMM-knC R| 'zRMvVVYC ws⤓NvG~Ut?75[_yh_ڦT ֭'HMyn?^MNڽM{@j:.'C|?{o $Ϟ_ h_avM6 >b)FE=M4c{>gTVWޓOqglgu]4݅{@ΕW-}꩸ٍ3޵yiuvݭNu8SCѱcK|ʫ&{aϻGl|NY6W6MNp/n7'\10//u[RZSzˈ=26흔ۄ(]< >/eqY ^lG[͞0cܑ:ݜT_ښ6G%%\Tɂ(!+Rq[5?k|8WT2 v<C3`nxguQ߶m2qtH4rxɒYUܒY;*?2▒{k/}%ueӏ(U5lWWUKwʢ-jT<ߢoݒ__]nhtk]lʝ҇׻K ^L}x)eժ#8~O> ?{Lm>Ѓ_p#<<`A uûW'ݬjVZZN G,.າῖ|}57ҿRGf{ܒ32AM׺y.u_tpn _q5Zkks7^@y^^w,0%(lw۝M]X7.MC]4BNڬWG]rl\eHOٍ_xuVݝѻ]O@~ܽ7{y555k׮O[/{ɉ5 'r@EE$-YhYZO-4D2$52ESK!T$%A\r."w|ޝWY{ӧ`%ڵkBf7jPU42ŭ_i;ݼJ w)YE4] lORC&֥jFf s3k ur`U)e])ejB2sC⾜n ++Ϗo%.]~J`0g\m0wkZ<:vuRni--V¡Db5;17݈dip~|]URe˓Xu?Gjdv;#&fſYwڢ`E'meU`+2 x,tjy.euϧ= ̭ZʮBjj2+%r媵 bo78-f.t\ MZ]?_PJxc*ϛ??33ݻs>ٹ3vjժ?, 0~DqJ RKR]M)ʣu9WYdT{xfk׮ 2mm]tvrrrn߾  b%ʩ\ߓojC! o 4T\Bw^/g5q;foPzE;ۢIyEpU0XZ5 ~ѧ:~=c?W5KT˓̙9Z޲1ul23v.{ݿ7| 2ŦP,Q&%,۩`9SnEtF%tPIռ%}~F9] X[Nԯ :OH%Hg :N-t=!6/Y1s;wL Տ_,Z(}>~iV{vvӵD]m}Zusu/UF 0*U*QѲ%՗!?y{͘{9*G5YWK<* NMSZ"8; V?l$pT^C?L^ ^ݫa@KIDAT׆D{"rbի0޽RF_,##CMSej{`VRݻ[>Q&Jwy5ӭNzŽT~zڴe"nΝ;jYr(KL4kϣ)” 4B'Xך6m&4D9ڗ& LXN`X[7DRGjQ=w㾏Uu)Ƚj~`&qy?hEqjt1ώTpn~0תV:7c5c7Mu떀xiv͟gcc#3AJW^Vӟ{xݛ `vӣg.R?N ż ͛ǽC!Cݻu^iqq֍$$ի4ÌFZ;;1%셨V3`Zyp]1sM=/ m0M(z/XK2m9궐TQzTRX˶>/񊄝T5}4O9Crcęv ).RDʐD?ǜWs==&|KnXJWRږ}GA3ո!2]7cj\ 5ۤL7Uqe >|W5/t~:uNQn\}-Τp/Or[J^wO7?Kvf>T֫q_FƍYՃ61(vNF/saXZIz*Jr(̈&izzj6hVmMJ[g/$*0ǫCӗuf kW^3e"|D9}]ք81&&`kt,xvk͊+z7VM.8타0M]6uIcV\7سm QQl|܃ޯ-qjgT'+O/؅r7NS=y̰2ׅeƮWz݌v5 oFzOLRk]%l ݸp]܃3֤3ӓc"‚|\ۉD9j~]]mj⺰ZNS~3Z.lY/kuUZzeÙm_Xiif `z#:<8Q&ᩢ \5+OuĪ՚.cbsvOrLx0tU ^ Y.jZbK)n]b^OqWk*ҳ1jٸ >DvL0C]L]'2K wwS/3'W`9u]W_"]/`6D6l] uͦ},j}UѿLq;21&c;7--ѬYN[pZY& K_{mi ^oxIljqw-F5_gklfJ5^*+[k6k36h̹ksWʯRW XnonTmc,x<[ùع%l\ߑڵB *\TM/sTM%W|ڵAC^m^}KNNN *ȑ?3)i33g^={naCZ`rPg=}vBm>rS`%2޶N7<%81m ҄+zoR[ϖ2N}۱mtxyO˭F?4?[1%m,#{cZB{nhnPdoYuO]e{H,8RMf)(i}\ҕK|ztɕȞ~qJJO$=U}ݣ|tfhrkG͖D>߯v_~"eO;^+cd YF9:c=]S 7ٙ+a {W{`vU͖EV>9b9LomR$MB{{tkFtiwȗgIR7ԕ'i'mfOu~rrʹ9X$g;sz`sS֠Yms:b *'Sڂ=T>օ^rޥY)֩ͫ;kɳsY(zˈG3_GyN2~zϙz1-vTZ y"]s.z3i nR"ůK'\tIIKp!(doYuoͮ[f%IѥkFAlCC)\\P4wBƗHѐk&<%| >Fخ7Z.Ir ((=k;:Do_Ȟ.kJވȞtTr<)_[% E-=Ewl #gB[ V59Փ08'Yς)te/r#ߣ3'ٸ`lpur߲BTLiȩ '~νN@ܲeBnK50)alZU7q座r+-?G1h؃TGBK߲ ˵M[KhG?, XkZ%V֩$ۇ iDPȞ~k" 'oԑk53'Y]Ichh׮}ړC;ܥN0~bjsGg~){tv^]Cه~\99N:W*ٛmָrS'Э4%'يȤ 1_{L_,@$kY]١g:GhgR`ʿYpwIE]fy}:?ץ{HŚ=s`qWdgg:,abܺ])P8KM2n=_rGT¡Mƽ•˸ޟ2kvL̘`$ VvfŒK_q?N8y/sfGNvտFxM?8)nݻWMPj3*'7ٻd-3s/O|QkׯܨfHyۭG*UL>mkN>$`xQ {~!m۾#>7M>"M&]N\qH5GY&;tqVع.SWg̙zZ I>+˒ӱ0sW]; SRN<|t׮]DY |R&>Nl D>wΟk(8יy}3g;f/L / m͎1Jwzgl8pPF2qСZ5k<_|ԭ ۷uiU^F7׮S~vUYnn332tZͥ#]3׍&Nyk̠GM6:]>}LEgE]:wQqM%kl٪eKҡ~DFqQ]/D%CVr*"<|}1p3sqC{vn{ _# SQWO7YLt!(ʪW}ɓ}{1)\[l|E, wi߮+l2ak`S&C|ZnYy7YT2Fwϲ,ݛ}Ym6ν*͛7uTG׭RQdDԽp3AUTqƍ͚598675!϶PyL^9v?ˋMe%Ggm۴fnݺ#Gܹ{qFRSZX5j\2Hެgd-oefedoA&{}*=dwF<~:Sfa*1ŨF>տQÆ}{ K1lzӐuI׆(tysg_ |䈚ӻWA~~[R\X,s^#~}ǎ'N<{'Q]x/R;;Wbٿ@V-Q:h1פ(M;qB޼vVҼQ6R^mڴqk`.U'Zjv{BP=Z YmAf-3IDAT%gvŋ))S/ߛr֭[M&*I&J{ORkmPk6eyo#JN5hW]KK;*}k=/8Q{ow/\/w/.bo׶I7݋)[;ATJQE|ŔMf?_ywޮ{6mP . [dm۶Q` c޲eKy[_f;#6FEާϜ :s6]MȠ]TMឤ̮^&N:D)݃s-?%? ~O< `B7o| ?K_w z?eWRY^v- $ytn^\dR9(wdާ7njҮmmx^d Ek֬Ѯm9vDfM8+(UMdq(F 6TkT,v%')ML3k68n߱}B?Oχyj*,YCYe i!ʅ(k׮ 2ߵHgWmZ:8{"59'$Y>gwޝΝ~P"^^*G>6!gNjʳ.@퇦I”B*]KKIYBss_}DžQɻIeݽi4m䯿zܹts${W}Z&jԬ1{*ULo﫮px-[́(;١jE~Q)Οv3?ƒ˯W.u T ݱsgRDsME50oNݵKMoHa&5C-۔U3lb9upms0qQ3+\drYqFT1Q }5]q JjժsC?Vvi*;2dorU~Oz+4-oǎnWP)v#g-*ݓx]ݟHFB9 < o|oä{GS^^ƞH5oq:)nbgFA[%||> Sazpӫryg䞩M65ji_ѹ7;-vW:2+/偿wI)wq+W*{G,Y^z2wgߍeyMQe7n|D(i&)Ģx~=N^f5>?P)-&o5t]JH?QV]H{Gy}5IHXl]<*#/an&.ϵŠ#GK'ɥTҵo?Bfڹk&zx}=۽woQކLeTFZT,%LZhQOoߞ:wMd`rŽ7o.!c3aX%$tOҷ{y`ZT Է-֭[8qxyg!D껪 9sfLuIGZ>?;%MI9Oݐ<:;&psL L=CoA{gQztPavQ[155_W-Soys;JqOqaf^n|,(&f3kveFQnPr\Y)+Լp!2^$(Y21g%(i2zckAr7@F*V͚5DZc~k.}=Dy~ܴqԘg~g㦨(9wT\V ԦyR lo}l^m:W7ISGv%! x[۷iƽw}n=6l5qU:r0N<^ro0MьEQ`Ƚ(dohJY^ܓcwzEˍ7o{ͦINzJZM?ިBŝsVb-.xMxkǚz Eyqkz?~܏6N~E;"qW Q}Pd|vyu|9\|4s`E?mQ0˖-[Ύ5Qf= 2w~Ȏ_4$NUNݾӎԜ}Q\x`(ͽl( #sgs⫩m1+{&ܿzR7=@ѱ/RYPs̙v^hw֣`%ڵk_AF pdoS@6v𙥫R|j`Bv W"8uvsS hG\|99%eM7w3~`%GsCR Ɔ!YU3^946֎sΈwde%ʮ9NwX5GEBYqVN{!o]vj&m^6 wig/򪮛YƊ/4ms6oxzɚB5Bʾqb^X~s~Jo棲~F\y{U 0ml5@4y!*,7.gGܮOݾ{N/V}'f5VQ+欒s* LWi7e7c\)5Ϭ,_S2DJnݼ%L, ?`wV3Iɇ|IX_ٻґMDaWN[*M.dEMqSg<y~/#ܹɼO{{ۗoRvVG붗^|*Qio09Bw.uv7_,2>9y5씱n{G 5=]1E^1dZtj'w1n딂\XXΚrso,>)<}?z{Q~,Ozv,WVr)H]]BljG֭ iSԦ_-Gѽt$'$f͚y`&_SR̀nj0˥H/nyJ]rJOr>XoMƳSuͤI2O9pM>>kVG+wrkGij$dFT9a=\Ի2>X9v𘚘6 E)R\玝޽ԳGׯw]tQmV-y{hW_>1|3vC^zݾuŋl[yU'ϞUN{+{\á({bu5m=ܺ{?CkQz꾛9sGa /Y֜Q5>TO֣.ݭGcNM2uj54_.=І7u Usҥ41&~H&\>}G状&rtHc'IDAT2lvvp`krH}E[)q::iӦjHazR;f<8SS(ፁHP-% yr:u(N~eO~s{}U}])ʕB}rjkJ4~P&^Ed"Wiԗ|ʓd9̃]\uAժU_݁} K,vss+ːlڛ-vG>{\%][>{W]R^ ] 0Sޮ,3[5䉞*SZ)(j FV%>|P3^xr}lagǎ>5bn|0 vSQyObe~;*?/_ǎ\+yN2!(!Yŭ甂*ΙsW*-g[g1/.ĤJaw.j[ ˓f֞O{V307iMp ~ZJݛIjZ>ׯ+}fLwb, XKn\DOٹEJ'vRVR34U 8MMѴ]9 P<55Ut^X'~РR+:M'#2uCr|_SBQZB|dW~R3f1YJ05cdqRa[\Z QF0aQz-[cԤ^R?nܴioEe!{@.O.^TPvKү_aSDڦ#"~ܔ@u ޜgl}78e񲼏q)R2!J&ls&MdƍA|uoi=?^vJUiڝju96.r⅟r+x+=N;nu/*m_qsywMjb] arWTBVZP/OYp7F;frI}ZȵJȝ87.9_xl~w\ 9><Jr?ϕO7vxj~hmǍ%Ve mR}Ħ回lcƥ[^ety_4+>,-E-~zxj(3\t7My2ZBJD>}RE+/:Ceas˙{kuZ֭wŕ:V3a*#Z>_~-UQJ/MzE^yxzqWQb2XdyIۼe(=w/]*FFqOvO \Bx{?:z(5E*E ~IM$-~1S(ߓhۦ͛z] ,\x1<24kY@ H *K~wNa>8qGyXkj:Jx^]|4T V+}E{fF45!W{mc_w2zgWR&jժoj_M$}K!8; Ҿ&燍D%#{kM-[.gtq޷\n}NxYa<ĵkfQӽ(ޓ%))j:dNsTK8p@MYy؂~򲚎1CD_~[~Z{}wUzt/,5qJg<>|&M|IꫯD)1+w*mk9Ygg M2_,Z(Jʕ+j⁜ݫHHL읋m"*hG/WD=ر7 |cÆ7ldj7e`{x PW{*vz'Y\XK`UY;wڻWj?|ٞ>C\գ'};oan'P~YK*/%mmW^Z5҉2>5U&ׄ_Uu/lt ,womJd20]k"UF얷#t[J) Tǽ/[c`/^(f'En2$'s6]FQ]|Y=׵lB>32㹻Te|0NF}:k_zU&&" 㦍a/Q>oϘ.UuGw7{Lmda;b-4o1-!YxvzMmۦ͞x Q&f (=ɹSܘ¨ԩ&tP o*zBSA.\P]tTeyzLv*,`/~9_`9?[9*Kƍ9 vyysߺU5jҳ_!dfLSy uusPT2`3{]۶dQId͚5E9 {qwխ/^6[؎pA֭#JIwƸ}(%5&|kVn*J I ЕFtY&L^z-G)ϲC٦"YNfʹo O~yR~ף=|O>$W 6|? v.Jڨ []U7p*=GQÆ/Oko(AQ~cwr"{d-웫?sae۷oTe3KL&JuOR)7)'NԽg5Վlll TYNڪU:ܫLQ A6(СjetUҮ]۽%޻N*gW.e =j¡u+?T6"sQ}o+shBB[nV!'ބ^Kӕz5[hqiySo=O}kzpU0Dݽ{s8`W4rJChyMf">}1۶tcӠ~}'ҺUKyo-͚6}07>?{#{ì5onVW֡f}x\%֫s;vƪ-_`j3hG'|_3x UTy3´ҡ9(})i sӯS#ڵmӺV[fmW5q{߈0mxUKwN$խ[9a,'Qֽ0g_wT?vpqn߮-Zw0[oc( fMu=/[%J;qR #Ѽ\ի׮]0 vsbiŤk3+O.ffokN=nR?:8#¨~e#l|2SnvK.8xhē7=7AB.: KqM\z )G1uԑsP&56d7yqׯ5sjU\@ȣ[>ʺ;>>-턼S}I K J$O{ƍ/~YT`'GGy'߭Eg3߹{Wk污CV* SdPr(T6n:vT+M5x#㯿6l~W\ܡgN6^899:nտ9U.-ً5xIDATX4i"/XMs}ELex;c-)>tpTTto;vP-@zZ۷iƽw}:rۙӕG9zÒ~zD-i3*@F+VxճQvv/_\Ιe 7!{7W xԺ4(=]6X\rssZ}K׮$_Irf2%K{YYY?*m~<'t |fggMtFAܺw7F KQZ=z),µkf߿? nY_mdjrJ6n4vOYFQCп=pI%Yz Em6h֬ +O_8}v׌W^zUNՓ_O>oZ]]^xqk6a~nnB|4߿{:d.b7YFm4uw] ט=úsޱ&/-Ý;w>ƍZrN5Q ¦Ya3+=]5kngתU˲D6E^lڭǎDF O$9򨷏:hmx N۵kmNׯ]'oպ/Oч!%Yþ}Irݝ9זb[֌2#{Bq?;dle0_F>fh߾]Bf[v >mlS϶#|#y؁ci)i1b]7~W_>1Wy{Ϡ5Wj*0k9~+// }jd3 z婠9Akk֪ѭ2N* > I_*v ݌ "{QruQ5޽ /Nk֮zOD2wt=:5Ƶrs/غU7nmz**z PЁ"Vj>i+ݸqʕ⃄ig^1aoÃ| }+~|i%yiv*;7ʬEj"++$5ZwFMr 6Ʉ_(t6.]  S䐕saWzGsB ѣ+#"Sa_?duH:ԏ5~ĪU]e_hYŒv3(FNm[رSpV`&xN莝; ̰hj.gO欉}}/5jjʟ"QIybzMׄFSmY9OM"USTSe;Js8ӹ[=S )KZԡgBSgx&oWծ][ xט_:=ހ0x9(1f(o k+M|u7LM tsYT;єsdk߼D9:ik/Eq9agX)9*H[D(V}w#O2%@ڭX׬T5s~tr3as6[!SV!f|CStsh`ЊMO)is?.TW і%ȒHC(n*tg߾O?5VZ}vܻ7_~eSOgd}do@UlLjadm&%CS%GHҁT=?4EjZ;#wbdxX9˟3GG oP(kРD5lxC봴BsܡyW= ?'_)'SE)nqO05jP'9IӄVt"ԞQd_w+ӽ{w3D6 #ݫ8zڕkꔦ|NwVޮ|mqRnNn:QJQ^Wp9*|6oNi5=Z57ȩjKyS'?UߨO?'=ƻ!<%5O7{_ :K[3GYڔ9DŽYW|(?>v@Vz>SǎZKή[7ׄYK_~R,tg= fE*8a9썁NJbt^?+l8x(b9Ȅ(}o?vаsgωTWGXd#wh]b[jjyhŋJҎ;\{u۵K.m;&韬'qs#)Agf-޸ZhOw,sgä}a)O۟k¯*Ӻ~N_(cb>Tʥ+(aVlllޞ1=xڛC;pZWӃ aCׯ5晫W MЫ篖tu]{ 0sTJqǶm^zI;v\IDATZ;wũs"{@ j 9Ȅ(GsC1q @Y6>( ڶi#S#GY;.vQSG·|ڷk:b_ 6J'Nܵc7_ծ6Ң 4Pv-Zt7`aԩ&22*~#t;OTМ5 VV͎n0h oFq2C,<&M|5K*&BA "{QrM6UId~3=^ Az?o_H=I۶mkJvv*@8x(b9D-ZPYYYW\)vmӦHK;?o펫}+~|i_d@*;7ʬwjB+9^Rf Դ}إyԩSjڭG.ҥNA& N[.ќPë:rʈ5ԧ<9@YR~g6<FFF-*Mٻ 7ή[7W5m=NjG 4ZMS ϯhzl֌`xN莝; ̰hwޕ Gɳ' sľɿ>^z[OL E*kLHAjª^J6ʋܹhbsn<5ZL0=vsnv:5p_DeI]gf6#Zx:6&*Ǣf{iv2 `읚V doޖp iߓ}ʿYvFT5k}Q%%;nh2W 0azuVzzgߝ7n7 T5ݹObVё_bbbѳ fB adodzJ {5TLݐ"nnH(vu(]*ڵkog/30[_,Z( 4}lؚȵ2q9sDFǽwͅ:|"ޮKbV,b/*Ez.;7)2%X&s˱iСj9o!C-[hu7-Z,<<`Ӣ.qiձS{"cq9:רU5)*`QA{$kBNICXO;pLh{QhxE נA֭ZA&DxxQ;Etr'z SBm+B| \%o5b>6H4穟J88ӹ"%WP8!a{ݻ"{@F)3k\=(|LD4X=L{G `-kLXbgo}nxO%"%լiӏ?@M/4(a2eNv},{kz(}A< {#9^ Ư?ZMaX`XE^#6: `;c t9aV/Y/vLWZE ;7 8^q*Cƾ~4h?6pY.9m;)M[Qyx1hѤ$y(m[MC!4??OUllT`tZh=&ÏO@njYy{io @_zޭ{7Qnq_Yf_&jժ%P(5''۶Mz%aqwkfΉ]2ܸq#!q_ʑG!̏'}VHo5Q^]( [eAS6mxj5#vif,A!{[;;;5q+W#1('[=}kcl߼L/BhZh1=x`qް05kh٢~e:a_Ga</UCTJUwoBK:uT*o׶n]7֮^]vM)!b*U{_q@Ő~^?`2yZE{r-Q&Z3HM;~G,}YV֥KKo<{6]ݼySMTZUN`:uv8٠~}a mcN9?scoo/I׮]<{ E.m5j&EYupqU֦\ҷWLO(j17cP.M!7@!kР1\vmlah{E.bqa`^-[ӦMGdIDATDZ?7kE60sf'G prrԄ]3T`Xצc'L8~m֬yޖή[7ׄDhNwFQ|fճgQ'[ U+Im{^8IM׬]ןx:8ʡ߰~C}{ۉ;[{ܪjK}LٛmG6 }dϾ}Ӷ5f['k R 4,܁"VL6]kxv7nDf]n>Vv/_qӦU-tN]У{wA6mF=5Pђ7^3W Re]t)9Djm:5%Ku #g~9QXY׾k{5YܹoU=&`2"{[%֫OOO3O}\vwuֶ ع3ԅP| #,Q*U_}Օ.d8yw,vn~MH-ZXy}йz7~ٳ@:yd料nn>{x) 0'-BjmuvY$8yQy΄NI{^,a|NwgȐ'doվ]+}|5j;CQÆO=̘t,SB ( M͹U8:)uShR+vʢ*Y>"6-pU#u?sxn ͳs7D. JPpաG5q…wޛ?i aC~~ݨ?㦨(9覒յB?HP@Zjө=蔀cNqtRaɩJ-yޚY>Jĩa@ |8ӎk3#V/DZR[d^IEqjԬQpdƍ|5k׮-`.&E)K~eY2F뿙@A)4hYo|JjpTӛ)OS(uSCuH<>(2RZ?OYV-ܾovݛ/u.^do`Mt-"hr̟eYNasZ`VRijrj  1NeGFGfΰ Qn]CaDf<"`w&:X!@u9Ȅ(M#GDY{MԼrOaʝHT|nnJ]Pa w3a~n6~4UC7ua_ؙeb5tjlRQ3d"{%p ԗ(޽z3g]VNkKڻ8 =%Ai+ڏNw p trU4z+r˒ю=) }:57teR*MұPYޥzt.`&%D*B'\%+!Ayq^~eaΥa2~m# Qh QJu۪+2!w '{!fČoMvf*Ѐ!Ajb{+,ݻwGs]ٻX `~Oz+3fW֒&w$͟gcc#Jowu0d"{`1a<zdBɒ ի'Ξ{߼qSXqGvՏS^-9!{@ ,˗O:%-[eҢEE~Zܾ,d͞5o\M8q͛իWeվ]+}|5/\欟gSOU/hio/pB"Uf-N>}Ν}]kW9~kגSi=Dhdo, Uaz&v쌽)`T~~-hղe&g#{W(7țW}ʈ;'`$w^9w!{`yaͫL\zڵvo~nk.5 do#{`acCTRţ{V-um.CddŲRSԏ89=!J"!emdo057oTժV@ svuiظߒ(jgFk|Etf6_7kޏ дI[&߹sgsqn_~=NUdoS;|8YM4nXC +Ң[LP<E63.26hng'ʧiӦjD\_A6 (}I7?ʆVMWPj܏†uU0n\<(II-`,d2l (SNi=P>6\%EEGx*@hڲm֌@wߛPs[]Y,G;Ĺ7rl<5Z(7`jժsC?V;v|st^RƫO?q_0W^Vӟ{ҵkz]^/\mm|h6LE?!۽wo,ɓ'w)*Zu׬#Lm0SqQc駟wԭ[w7<%L١ 4SQvk#?ݨaC}wc/02Iɇ|IX_|ĉvlڵm+ 4UN5 X`U X`U X`U X`U X`U X`U X`U X`UX:JV`V`V`V`V`V`V`V`V`V`V`V`V`#H_`g+ ZծG?n\t01~DF VLėBd|,NLQ`: b#_TDi|En0?XJ'FxiPj,@W;[5\}ץUZ,HhxIDATfDž U^/t`לu'$61EKX::.خ|4*CSynvL7N)ܭh.1YKOsz.])+8zb_> {8.ȥVJ}?~q՟=eҎ6ڿMGc޴ᮣgXw=2QlTe7Q728qa^쒗yߖ7&+cߪ)O*l2S0{Ŕzuд /^S^;uZWeoS&.+ԯ٠[Ϫ ֿ}’1N~uX]\}ұ%ΌpQ_K>frTQ.e58!E6VʦGe7Qo~Tjuֹ"R>y8v)e^ywnBo ew4!iaهLnO@QLl7.FGCƹ:TFմ Xb \|Bbj}Sƅj'grE[3H%X^fN]6Un;׉뒣@2kѦ+Urp'j1bYv10̈q)s'/R`P}:3_3>e #?HS5` & W%(B-0-$ZjljٹxED'^Z&_9GWRxp*>4ۍUaL/ De62m9궐TQzTRX˶>%V>_18$76N9$$w/ +>Nt*$[uZKt)ApMQbZbbbvµ%)V}2en2ߵUbS U؟abRn&5)Z*XR v5Kjڍ Sԙ0?艎:<22nPcass+%^LX:mPf5͝~RSi/vvaAoT2O ;aa0`k ޕTe_xךX.&Цqj6ֲu~]]iwu\\L変1]M cGwwmpkDҳsTS\11ǔiAX5q mK! 0GqNǕޕT) wk^7rFXȺ3$ԼKrpw A9A\Đ]j4v#3g=A>(arr8 pe#taYek[C}83Ǖj\ǍTO63Su!ayGyՃ~bZwL/f@hvϔm{=39&<|ƪ'\|buKEwO(C ʙ-9Fy3P'}3s*/+/o,#.i翞lnun2HtuܔMekr[ ze9 g& pUzMfC"V v7ktxp2{x(p>,rĄ<*zЪ/Q dgg5-3zKqa+!^kW;cKbQj~'K)ʌ ѾÕĬkOQ? <Gs,6.1 oe)ӤBKhC9u]a,#oH6+SlNە_Y\}O` ϲQss{̹ع%ll`9&,}- GWoЬiK.~/w-kMMs/ g͚o}x']ܵ &h[_ m}SNO+e~%u5E5F/˗uj\64nR/scs=:vR5ſQ5D̉jbiaD%(kZ(*(T\6~uXy 4*P`(X`U X`U X`U X`U X`U X`U X`U X`U X`U X`U(2z9K`Pz `V`V`V`V`V`V`V`V`V 㯿6l~W\ܡgN>075oaѥC>5mD0*B'\%sd鲷}/+rr~g<-W^`&?;DM5=SRxlGY`_ 1~\r)SK9rQo]m綝>NZkmNiGҎ8~c#7jӖ۵m+r200#0K/f}衴ǧ^y*hNPՅqFHÎmVeE "34m ]ao2_FLԏioPn0?G]'3pA˿9~AWlg7]tI(` 5! HuiW܎B82)@4¹cq9:רUCMgPDѽZTSVzQ&<=!`9WRN@13l7+@Ϳaю,1v MSg]Hg ެ?G)^yBQx˞Y@ o/p&`s+iQ sUֿ\?zʎ0A+CN+YP(u䆩jҚWݠ̊׮$>Ԕ~+R}Pvɣeѳ}Ч"2Ή~\EdA` 0Wo.\sbYYW`TȘT< {05QjgUUܹ- s~^'%W?z|{ۍ7/T쉳wlܡ~tc[L7ӮYcGSʶ,U3^C{_&RժU曾=tr.E??^]vҧKm9t4)6i}or:QÆ|%/ |d@?1=S {CC11 ~xP ljh߯_ײeKy]NfU+N9"effY >\XɯO{A*BdOTf_}g޽;#ȴ㾽WZUdddt+3S{N,23ώ@O֨YcDŒW>>~(2>{&ώWܨ7u:rܔ@t3QiS+ժe8YIn.+4uRr "%4pz<^.+4f+k9JB0Y #]ٸX:jԬ!`4n<#]%OzfmT2Iɇ|IX_+3+'-ƙ9e`3}ЧS"i:k뇚gVm,:DƤaюvt7GNqGDdn5A$Xn^&~tOȢ}:_zQ~0#KE&'Ԧ_-Giߵ0"R /2խ˱y+SBCSCڪ@8&5k0g&iӦjHa9h{>jhJlߜޤϬ Ms:G3[/umbxYy$h^;f@̻[7 5+cV`Nutd @UpD@IP &#VX<=jdZ%G f 0*0*d׆ ;t8/\(LF[wtЧcM4F/0-K.{L.﷝όyZB 4@Uiŋ_~e߈[(YV޿Ν,Hʑ#zj;pԺ]kvI?v$؁c?veO={vm X},K WjW{ Ek8=:hW_MSG;~~r X}IF`pE6}FZ 5aoz%Vf Դ}WYVgddX#GPOO}zd4XMS,}fˊ3ΰq-#"~\Q^%͘v%{y|"#1 uM{SRy=(2>;g T5sǧ:BYjT:?Z hwVjj5?&=O<}:Y~D8]"4ixG]Z,KU_4a؈U3t0 t&ȼc4yb㼕89 bm Ǭ̓u=k | M-x5O#aM!*ſ!tSjX]f@B'\%sIDATLLjʥLKѱs21gݜe, UTWfηTNɰF`zʿǒM U2k]nW&F*ew.$~yڈi2ѪU,ɞkk 0*ٌ2[KtA`-e3)(޽;S{{J6iK5j(u/eK0wGJYenNMė=dZS["ٸi*'w:ev4MoQ*T]GmzYKio zw~^'%iz|{ۍ7(S'ޱqѭG?o)[er,@0LBZډ=tv֩_kW׾]Ҷs[M:om]|E٨alR0L㩏 ./PVmxZ X`$Lm&DMe8۶E&_}P..B/аX/_~w-bݻwR_;u@q͛N -6W_.T<Ν; d2A`vxjs?y}V_-ܺu7;} "ۗ$Pnf'h3]۬U!M%[G9 5oe̐|y6L /̲ tR~FO]=]W_e:o>ܷk߮GYvB!0 #V@y}5Q~Y[A]a__~Zuj;k U,s?;nBQWjpaMZ577o,L^&_jzYY&:*ݻw<;.3` ;ߜ6]z" 5Pa&|jsNTƛbw03~ g=z޻7A jӵؙclfĊ/L3pbOv#Oq/\$`$fwMM$zxOuӵ ҧK3;;N"9:: b_]<_8㯿, 6⩀>*Oq>fAqQc駟Տ <=!`9;Kybgn{Ԕ)iyٳAy]Vh/7u^f)6~+RGĆ22mak_C'H5P@ƍ|5IO̸ '%:'a}=<3+> _:)Reo؜2͙>өidhl5A$Xn^&~trhGQ[7o @, ߧ?,@R AB<;n|dC~0Re|ԣN MiЎ<&F[ q 0O&Mđ#x9h{>jhMA0o׵eim^l׬P1̻׽eBe cg8)}_ vQ )ʧ@NGGf;ΰ t[Ω9f/6rvte w.T B'\%LLjʥLpҥNwܱy~GZ yˏ,իW?qXzPɞkk Ua9ׯ?~XuV93xPr.܌jzqD@!EyLM7/}Q ]M4y筷 C Ҩaŋ>W{;È_o&i#;Lܑ~\b[[6@g|t`G{w׭su矬'qO z?6G 4kvCɳy{io ` 4, *[󭋳0avDA 0,\TtʈUk䩑#0G%C 0@ (j+@ @ @ @ @ Uil [XKemZޘGQQ'cA:k7Vkz~^U:)I}O(WSx[_S,vt:.mA7eX-nNS{dQѥ]k0ysCs#- ɼr)ov. aR¥C!O扔]re.{fvK,>O'ǔ4rYI֓ߓ)mI_äu!{׋x/]Ȟ5b0x//="*{1nz=s[H=5N;*>ؿ^0kV5+>oo a ,L~Yeub,7{@LcA:Lޱ~;4#GY `l pr012UW.e &&{]0VOv͢zq]q箸]qrf9gBZj5hŹsժYӛ f7nܨQU3.[׮ ?/12B٣` 8;;{WoXzuU)LYkbᇍov͉dx |\._c~:u#GX7V5nݢ3L[h/<ܾ:Rf$EGOM?2&t}ڻWOcff[rfWMtҹkW<;wuVnݻ c9pjډ+WD5xExr` ..%y{7~ظiIIO<ٮm_o@Ez_?kղe׮]<}lիJ["$)|ֳc`¤mPo/apAMk׶ؙw‹e(ӶMT3޽pb~{%Won:Xpģ_',sΫF 70͛7O~ T ̷YY3qsDtv֏rej}[9tđ={S4e,V>WiޤO]Ä-GjJȱ-薻~/`;vKޕ/l/YN AjN:EsڵAC^m^}KNNNm;8PL2uAEEK"vJey+̛T)x#LF"% .%5!S\@o.93ð_s/99gysM8 Gَ;-^\QQyW7o]vMn;ů+'cE .7H.;ߎtXGKw n2酄K˝{]w9>fe6lov^uo0|֗WR0f)`[J߱^[P ?TJyh4;}57_?'{^{-k&~ɯs7Kon>oүdkn}ۇ0yz%syG7𷭟(%%[*\è \!r疚![*C2M34ab!-}}G?̹&IDATyv۔]{3P'zp>\"`PGFT OrUW֭}hLeuW[́j%ߡ[*~;.2toMT4\wVaʺRk¦XT-7 u]>orRK>{ |Qi a^N* :w҂C Q69o޹sğh;֢^wlTY:ego*{?X 4U2&cWrl!o[(RSW"MWXh2?ppvv~o2/:W1cM+?q-Qn֋{ͱxg&.7㭇<8Cȡo^5^wXz ~͎QqbK[?'tpP={m>cF YZ1vF/rO 9ho OԽgo`'8ZXX4F-Z3؉'ק}f=>$Цƌ/j{~>p R{-y3nuSs?إlU>ǥͺ::ѣWϞ_.petycF-?Z';wE}:>lP3f2忈vmAN>#}Fvvn31w-?}UW^9wl %>rDi -3=V8wdRpߤw35x@Z믢HZZ8x`WV[l8\k5J 4I5@{r9 Ol9S3t)JcǾ2=Ei?-!@j;99}f9r@iͯwSi+?:TVlJ_7G^"pa8(9$I1nxژ zjRgRPvر>>_=s4 PYAӏ颋.8aԊAwk֕iW5_[njX n /O7'QwpVv?{##:v88z0i$7ܹh>3GyLȑ#A@g /VMu@ p/_Ν; w.R}ʹ}p|c+o7)ZJ77k.RwaW5G>]z5׻/=jIi4M."@ܷo_c'0Vvl͹? ԇ _Dmž^Jcǎ#Ffj͹:~MZݨ)/ſڄ=)A+օ|gZz .5:6Vk l//Lh[c?+/Ŀڊ=`o ӪTEo4m_ϟ羈Jy7xh֜QQJ㕅6ohZ SܹsR+J[J\O͞pg>-[-^hD\5#ǍRT>o;|'|4ަmc.m63m7!;{ ҄}azJQcm+7[ͷ͘Εܲs/>NO?;Kٳ(++?qssqVƿgF+/ç/p}vLFjڶ۫/"c0-[`PT\9eo߫lYTW^Lݻ{Nh?X0K/*M|)fY'ʕ;-i-#I(Q!7CowQjIm'NHuO׭{cƎڃo7z-_9_XHf;|U^iحG[~[>z`i4ޚۄ/RJR4}0OCs~?3vDJ|-wSO)ҏ)v_Dү0 16.S3kMHR.9)~m>}$Y?tksn=`N~."ǔl?$Wn 6K/׳5PѺΝ;>t{ˆ j{kYp{|GGF]ȑ]DfT]IZޟ9w'22lY? ʞwJUEDMra4Ao5_lJR?"*WVkT-xS 9w[ޔp)/2J>z܅GJ߄~E[AJ*zםݺuh#ʌTF/'&GDȍ'ctq/:8Һ+E3ω{zN\***?*3wI.{gjIW^ zq~¼ L)Z6Zȕ^a1r2ɬ6v-vCN|˭~Mtqأ:k'gR?M6̜2ѥK?Lٵ`] K=U_Ow"SVMȣY;=K|v+!jHK7cC\Xd>eҟQʌDyed?\V "|ǎ~߽L{5)Q)FI=wk =,UXlZy~fiHjK F3}O=DJyMgK57RtÔ5Ꮟ"ȹ)KQS^yW~ KaS2qS4CէsE`6[S.OV]%. kER/-),d|KyM v*5|>_ (vkN"X52,2dyF-?[}yu^ .QFGFR+j6*hMYʰym>k|5l3 xTm Y.: ;).DurWuy59rb ?#Jcweѣ?o]|uS/pt ѳgO`ĕnnJc׮]&۷P#z?!Q>lI/0@!%4v)`}9k+_*ۧ4ܮ j:s\KKjx`mmO7vG!:k,(.5v}Q]v=_+q߾㞞 0ZBUP /zĹ=+ԭ<-=]iOv֞-޿k_?U'gCZZ+hs F EGE)W&nڼY/Rj{^{7 :n4vn}FQC#ǍR>o;U<fn٢xFW\7HUTt;T3gW"pr,}SydKYY?腚|uQcx-e3&>>CWun˯ \X[y/ z{G2f?'OT rbhlI4'k?v="w|}+yy_n2;yACʺw޻w/ Glͥ#dTۼ] {vqxխtmff|4{O<)LB*3RE<4qqG]j<_7п_njH|E 2x(oMqkH?M7ݸyg}u\ާO"g<6ѣJK.m 1UX#4tnWhWHӺ^ov Ɵp{|GG,ͱM?>,л֭hO}C<Б00Сv)!S>pt$``GpCeey_#S={jmCg;w}'5z1/ }g1h!%_~u]v9}Lƪ̃)j@+8Z3zԑ#G۽h4~[P{%przڲDs.kp:fknRvNw_?ۗju}3/|k8۬ݻwOru7@tX,숣U%:u3f7n޲`'ΟרyG~W m/kpo'O~ÇtYX1 /Іx0 VE `*@ `*@ `*@ `*1GG `*@ `*@ `*@ `*@ `*@ `*@ `*tv0AO.-R`sMAT 0@Wd4%yVцB@eT p^vFg{4Ѱ2Ը/+,Pt7K ~zswg/:6҂G1_<ƽdye0?]b ۷ OgVnGs|4^Eu{QNZrk-YKN}0/.Rh NΫC+R$vWer j+.vי  ǾKsiNVR|fly/Sl"ݚ;+{IIڝ^67{|3eJl?dA1kzFgW[[)u:P:fW*tLU}ˌYMM[Ʋۣ eFclWRR0%v۞:{twyW>a*Ĥ/)}4I~E^eiam)+g1N_O*X2ŵyMag/+wr/ǾL5riewly&dlwCֻi:Gk;IylG{铩LHVzߕIY[tͳxՅ{OYqcwcFrsQ5 ř:LYz:-r%z^g}pjaV)VU. {U*N^QUksLSl 5;KeJqw-EaՓfEZr3ÒvYEYd9R;]hHҹX%!e`(`榄vD٦iq JShrNty FgZluf7[ 9z)ɦ_䔴ڰc`i>c9?T Z/Sp{)D*3@uqla24,-eiifjW L6*H6gdSTcN5R7$ԾWg,P޼T-L9ķ,3er/5.LML_Jl:$ҥXP )gBBhЄlhaII'k k]\ݞJusЁ5$/?LCT L~i499Gο9~J0*Q*4\22ZPI%yy]Qp*FA~Pk~r3~:Or2兞h\|⊕c5j#^ \ho3.IW%f򥪚C{"KM^m{䴒Эٌ1sTvUbUݻ8ՙC0jkL\t@DR)śD*+ʊrҒ yJOBe@}pJay銒BCJ\NRR߽#rMvR.1Ujq).ȴJYNr~jza:VQNN妋rR}ГA+zL#µZœ<?0}7Ek5 h46!/yy)+Ne9˫AO2 ]eL |(%G[ޓIDATDXBb!2R# [vzJZ[3sĴ4VYZ &T Pk~TP﭅cTEq^ea^SkE>u-q ]76J\6úm~1ujepf_L0qGr􉞮UQ'WWa^UpTRrjٓ<ǒV|~&j2ˎ,{^z Mڽ"FWԒ}YIì=[aR1| FG)ߥɳ|YlPcj6TS@+͍TfN&@GFNwfz<ǤRtXF5yqZ9JOD#9!U`t;*JLsNqU`jhs n?%_IyG9ƩNh*@U T P0@U T P0@U T P0@U T P0@ 'OT >u[@uT@ `*@ `*@ `*@ `*@X˚5l~w=*νooo'MVX灓'* ,瞯T7{7uV+]T J9q=z!AI^<-4TڸiMRcO߬MAP[{(ߎW4Sg <__q O{WZ?K #dO!sj)MAP;V15k둻Fwu*s7뼯^M:SRșTPsKKR/e25k S6xjC5P]+ҔݱwjWʄnwS69oP]~뭷ϟ?/5tzݬ\v=WT T?TaQauHt뽽5E tqƹs GʔCnʥPj3&>צGnXWE2QwHr5Ki PurtkrM &]0K.Y0]5En<7~/C}*_~$#[pe&qӦ٩S_.jMȟppy@b~a(?WJQRH-LL,gI0-TyR:v*;7^-WtOZ^`OK4nAJc?^3_hoj| }tw&gG/M~4Xnw==kMla2.7mMk3t(?;0dy|)/2ۼ<":h~-J kξMqה}ɧ˷_֋FIp*?-:zC܋bJݓf\-U}-]pC{qFNu~(Ud>5W0+=MwV{iܪw\rEgL;xE֑uF>LjژE+5FjӅ?&2vת VkMm)-Z(TU],)N /ʸDEsLYGyxsMdAP*KiK3fG)Soe}Ғ\&+l#D+;w+UǦr<Z@Ν;vYQQqK/TTpPЫ-&~8 MY ,`^q^]`UmVoZ*j3<ڳYծ,7_|w<k׮E+hgm{xx,} ,գG׋Vx(r򶯶-}a7է[^=\v8>,^i?#gϞNnZ?4,7omӉ8Ѹ;*ˏg~Z$k/1c.OmԓO<>tD}aí-ׂwV9MJ❷%ֶ_(csKAAh ]tIq_\ }_߰qÆ:p@(W훷K~lD:Ǐ`?>zkӏ6`>Ƌ6cNĿ}ާK8:F3hg*f,$f1ax7Aj4(h4yJ\EivB8ojY/]7ދ70I^\v9aZ##޳U8$U`Ł{ݻW8CzC`_h!0b7``*@Jwgef޽'TͭUW 6tq!*@MT SS8P,{{EK 4Iءgϊm|.~}ӯ{Ng{&ozuf\{n^t)=e@OBJJw=,D eQ3|=].UХKʣEGB@mvK])}I7:uJj;ww~<wlgŸ)Tlu;Kԣ%/E]TqWёfCG"~DI}Ԝ~%~ڥDŽ++eΆ\@;N:u"jc哵R۶@i/\P"61/Oiˢ9?-knaRR;'Z:4hd';^~E򣰾ڸ雭[xׄMs{ k>Y9MYxޞ.=D/7[#/@7ݱw+wk)ibdz7dxlܼY:.}\,JhCZwL1꯰v ikEk\/?X?0eK^=O:ύ0СCMaFy{oϗE&8wϘÇwڵF犊 qiKN)ޭN5E%aQt^w2q:;8p o62HteFҥ `G2[f=~ͬ,%5&qӦ}YS)v5T)=v_F.7^-QYΜR%#Wc>o>(zC Zyr\).Oڴހƿ>>J#M5G+>Bݽ{U{A.mBQעOqpȷDJoZ9Y}y處o4<= ܰDEӕ+b^IDATd^A=o'4_"ZIkjܪN)Aʹab`aJ~i+'q8)pfMف6;7*Tk"c1R|5WuᏇ&+mdپ  0[ZtRDowbC[C]w{C`5+R3"W}ZvtRn+׍6;Jퟕ/%Xc9'+'v*ҙk% ? pPv tWi)#ږ~pX -5[9ZWZY:7^c 04ye mR# I6SpUYX9M*'ӏntCV*q9~3z8XroDLgy .$az0R tX(3<K=c_@㔢(]Ӝ^ _;X~ Q?6yޯtYÍ"=iVʿ&1B(ȭJX(xEN?ѯPj/>,i,:[7wD ㌛n^z3g_EGҽgSV._DGg.lWۄ(Y<_k8.U;B:~8!lo\nepuճ啨W 7*-^h8.U 8p`h'jg.}޿{WBv|ާlD?!!Z䓵mtӹmG 7r˅ H훷KqFα>>gD`1{O<)`2Rw. bM7ݸy[oE},|?Zٲ vG]`}Ge9zT̄B nݺV 4K @ 3>^qӦ;vCҳg+ 3ft`` ^qUٺGw^ܹG~g*K'p~qsnɟΝ{uk}|o!;w2CN|˭~M'jU:N.'*Nݵ4'3gڍowO,)*+N4:<fw }/wN2M^ +\G2R2cϜ2m̐5r:{}ӽ{_!j!;vsWXoXTҍKI7^R}̙xn?tY@g8-}eyyUΞ=?_TڃFMh>޽a>//L;ur]FGqYNNZc\[Ui[5~!E슽M7?5{ힵS]Հup[_ގsa [h {FAA#w9=bF}Sò2))#Gٶ@,,,TCi0)I皷,UĶC= r /_*W}0xS7󣀷S~=*mjX]XoʙYF+3&ȼz-ߴ5RL@k*NZcԾ@dӬaP`q>]L+|~am̷-taYrZZ%伀z99;<%hW97L`W5RzmmtNkuRz pR^6U :ȍ˖dzgt,.:(9 ӥ9|YىW }<|Z?]d*L:&;Ʀ[^N)Jh\]JrD͍K,]Ud@\J,^2;XxhbTYEn"wqL{k~u9Yk[[C]w{C6>: ;T F_ƞ{vh&yflzv\;}mptPbܴ*|kP"T"6kȢqݗQ׼byR֒iK(\>b[5eiSSĮ1GBqFյb=g-̖n>):nXggܾ}*={DYfiVbpvTe_gibG%7!e>CLPW7I2swONߕ –U,#LB)U ;WPqպ s]5|׮J.T\- MRRI,UJÇxDy[eLrx $*;cCEbzbfWdhvŢ4oZ40d .^e>E(͒OWJһg olXD)'⡌v͊uLLޕe+ӥU|9R:e0qWp㒶3P5,/h^zOj5/>v޽/IT8Coy^[q">4`aQ٭(~7~,QqpΝ_Q۾ڶ0zP!˃0@qa9_&M $9hEܜquMs7ϝ;'m޶W׺Wb4hX2oҶmokװqÆKOe;v|U'_ImV`0ɓϿh=z&5Ї 8`ݻ8cA.Tm* v+VR)8-}ڜ+wu=w:)/ѮK @ * _ _}ߖtE.>]vuAc84U}f=%{ﹻYg 4I8`Ĩ1;V#!wM??@dCw9dȐ􌊎yeKk]9 +tO]{W/]Ҟ>|h?[MٳgFΎg.@_͉Wڮ\V& iRlV3$$fd(: .ĥ{]rٹs)_ё0@mvY۱cg}њ~{L'iΒ9 @,))}=RI]txvW7^|Qi\bۣwxǍ|o_I_^hmwY@g#E"LG(c\G1WI ҥ 2gC{]hO͞SѬ,{_{omr[P ;j 99;E)՟|R_;vNzJQcm+}PixjBi0&(+$(QudMCƚI?~SN=s'IviS'axĈJxߤ;C%(믭3݅`}kkm17w/[c<pl]Xe^ӛnѺX:XIDAT.+KLx[nZZ99ܳtMTMNw*[FJks!rnnjC-5ZY#+T]"5oѧIU.uf5Jka2侈oC=zdufn ݻw_qƂ]zi=/zhOj-:#(ܶ^ꛖk(No4j‹$YtJ9=**rVi4!>(S#[LJ"iiXa/Eq)Jwkz;E{v~M>%tQqͷM3m*I~Jaf=WJ͹uMdza;rwl߼} My٥nꪫjKի׋N\}'3~8`9q>S~QٸKwW7K,aEZzǫ,>-{+84`E`U T P(5k>ْ9zT8{~'N(@Ծ ;RyͶo%kZX}$Ԫ)>+ "=]JC;w2DB=7XG;2pߧz Mm)vO{WJ{?3}[K u~;yRi\tE:< ;Zr5] :uǹuI&?tri))W_PL ?:.@رS9?)2^zjS~kba)O<5!@ee3gv=txvW+ҔݱwjWʄnwS69oh&ZT /֯n[o}޴zN5P.'vʕ-[˜ ɯ.`WuM7?5{h33FXTE]/M%C4!9|p[_~PAXj;w.˰^4ӎ;Gh_OdǏAz=%e1۶4#G)!c]F˔KmC!^5_񹢕‹j$fW4 E:ug?OY?K]=bp%OtK`8߱>>c|ƌiDa'gk^䜨sopGgVy䐠8]x1\7S[ݼn(F;߿sseu絞};axOslʒ^Rc7mj<{vx[.<"lITjg-Q>EyByG:.OJ!m\غ3vMQȍ(BUIk2Ы)v 9HiGK4S=V|K/"~ݻ8cA.THgj4T|S55ˇk_47-ߴY"+dh~yDtZ+]fR5}ɧ˷_֋FIpRS6}s$?vŎzwj8_?M㥙֚Xzαy[f%KיgY.h3ئD;+ɽ4fi"p] /ʨng?+I[Ñ[6m8P!VR)ҫG VuNhz֚++RI702X.[;E?0y~qb{_J;BRy[ q^WiT7؜dN9$ՐĊ es _(4;JٟzСC3w?}[CEG;h}8WAwnRV]ŅqTľ2]tIq_\ }_߰qÆ:p<۾y>{&M&j wsrn޷Dȫj{J/43sf?%@e8Z۴aC3g u׭^1:7K\\z= ;he7y70I*t+rNl% P0@U TAE|᫯ےҒRn}.JƎ phxh֣_|GH;v\9-q9s{Ɛ~pXEÏ˯6s)N4:<ܹsȐ!M;ˬ~/W;ws*VSYҽ^zw{=}>r_VݻweѴڿ^_~ +4)6VziLHdHbLbFJ0kȦ .ĥ++=zr;wqs╶x:99;Y2g(%%<\gUVV?~\i]q.pZJk>J^KR6;n W}% ya}1`.#Gh4ѣe|ZT+4\5*aZꭥKeΆW + ͛=YY%*![- 99;E)՟|R_;vN_c 2rԘm j*(,T^)dJM3day&> ƷyR /]{/?X!cӤKJJS|N:ύ'إMgg'.ÕFQqIwNK~uQ_[;Xg; jrÂEc~5X*IDATјy餿xkEi߿?UO<9{9[t]>iOslʒ^Rc7m9ܳt:,)&Fpˁ0tk7Ey !A1c(?Mkm_kyKfd2g욢pMKxTKݞ{[NM<Ѩ.uf5%Fx׭G+>`K^]Vw /҆{^"$:_H=7M _k,ݢ38!Mʞkb-Zc3YY(ĊsT^߻K].]Sxv~M>Eܖpщ&pjl`sM_0O]9~]<׷>C4Nj\h3;P9R:(s-֒2sFRj+qE+“nяɦ0nXX[Ɉntg/-6~{ (qR3" ~;^! *NU:D*[:mښ|SݵCkESewV{i\qpyt}<\'ZXi|U0O%?RСC'{y_phSjsѮRe,SÜWK?Pغ"i*޸Qw:wWQߦǟϜ:c#̡X/R̓2j5I"ô3@<.`;/˿4&tVTvyi-ӉsC [^|AtyYq׶xjg)5֔ ~K:USMQүÑ38 }K.R}*c`ryuuTۧμwOiZae^71) GdzbM|֑ˣo~>g#p5G~_K#R[x嘛 0|!=z*Îvؾy~;S۩Y9r$̟׫WMk5I;e+jp՟μꪫ8"ǯω[ѿ _Yze +3>^%`1pia{W\!"+{@}TjF `*E/YɖwTaQauHt뽽5E tqƹs E3رsz &O `1HƏ))#Gٶ9zLi2Z\Z+憙ª;ސ Y^"Z-(Qh!CxlBdNzOSsq[o  "a[(xߤ[3fLZg;9;]3M'Dͮ!Q|MI8JN)ޭюC}n^YjK͹ Rۺo0,Yi_(벲0Շ7nԔ+xԩ]USW*Wm;=ǺvI~b4%?c*͋{]7lܰc8_o.޺?&jSiWr{pBM43sf?%@ml۴aC3g u׭^ç_z+VxWw^ ԁ 0p@`u `*@ `*@ `*@ `*@h4 `*@ `*@ `*@ `*@ `*@ `*@ `*ЩIJR|4OrhwyZM}rK2S|b(أUiq$}I`*4\6O)6mxhFj+ SJgW@\fQ5dwEcNɩ颜hZKwaɆeawW9Y&+ei^V9S}NYQ(Ej+r"&QZwWj.IN1 ӳRx IDAT\ukLȵLg,5{!L_ {:Td|4}y:%NN{wcc|׉ӓv3u/[as-U^mpZ`sY7ڡ`8&."+%^ZS4vzEfe12=8:d0. wЬ"C> 9owҰ:@e9z%w;#R'ʭJC^M_)Nr8&2]-0B#umRV_fks H˜)3əJKI61 5.,E&jnqa;$XPh]87t3!x ppm L_:lސ#)9# c>8.IW%n>X6"Yѥ S*(ZFXʭMzVtQIjۍ7DFC ֛IN vXSTea>ZδYRTSNH 9+f3eMZoc={[vXҪC,WⓐwP2N&^VpP=ZzJ Zsc YyǪ]WKܽ"T4tyq _P&ViCK`%ʿ^]+iJ}v2T+ӂM[-&8&@9F^49 yK4ڰ2P# P"XP `*@ `*@ `*@ `*@ `*O@]-P `*@ `*@ `*@ `*@ v3>^qӦ;vCٳnn 3:00`^/@c4y߽{Ch  8 5M4.pܭݪx-h !~Ni\tUR;$h<~(((LJ@dOPi ;뽽kU9dž,/ͦ 0.fRt^pf~h5{ JcFKVǡ]EO.թSa)_1HG67n$4x`ȫ'7;*]nzg'ɈV2T1J,V:/2ʶE${$Zw*ש/#\TʟܖS4ɠcK<#Gg雖/G˒~Hٹ&8>ܢ3XSw1^r6ڌֿƹRϭ(31z(WW*̓#t+WćF!E߼JG-SܹsR+J{WF/eN&9^)5<.IҚ+2(+fpd!ӓS"tBS~IDAT갮҂yLN^Ik^]KvDIR=1>3XIjY'Lo.ү7YjJr ,pYZj̔8}c.i3ťZsi6\*ɉ[TΉ/I]R5:Z#o}Zr/Z/Sw{^%'R33=V0or?^zh7m L_:lސ#{ vM:7ZVt4I7ȥ9rUzMӆCaHzԾ/a3yyyɫ-{ϼVRg_hOm>jSy9Eu.QӢ{<,ZlOKڦJ590&`g&T'uac䯥 ’kârcbtN@^t}v%+ IX.-NI)3=]Qh4hSSd=f>"tYajnP) KJhHz{ߋO1qSv0ڝh46iC.>ż>ȋ :{M^)\55Z2}[goFxX=y5Q& s-aag6^ycͫ_MYq*3Y^ zyO*cZ&vH-ٷ걉-{zzN },iUS+qI;u`MO'ag/+8VfԷA{ h43:t/:]5̇ޚXu `*@ `*@ `*@ `*@ `*@ `*Po>yR{.*U T P0@U T P0@U T P0@U T P0@U Tpǫ6nڴcΟ?tP777~W]5lƅuXhFcN7[>+P,{{EֽgoD'(5h>wPt鱨G.HT@ .rQhѦ8u[nmfOhGU`@)+c6Y.<:T\xh:zF;5\P.XGj oܴI4h1nz{&Ŕʭ ӮEib"<_V]Ik2MS*z$ױ(2#v)wZ$++oTtw4{N]Sn`OK4nAJ5{?Pz)/my-:#߸)*%z-RvI*҄,/g/]Y1aRH2]ĸ&0[TVΒ.bD|\a:R kQhBys.|z:C[/ɗ9*y|ۈ `iZgiFyem<<:[gb݋3rJl/#\'i3e^ K7-T"EaT𛝚[W*Bo[x-MЎC_ƞ{vhCf 4|O3vIqz?]'G6Qʼnӽ4=*J.Gs) WW(nM}0tpT۷SGn!ʼnAa&?X@X͖YV>< 3vVh=6{qs#%j+.0^UZc hZ3xMwҧ"X!BlGH";J?xMQF>;ۼJu,RU"1H(5Ye̕,|ywW\e :hk9b:8%z^{7 @)w9)m  4蕨W 7*-^h=i>N[vuw~@-;vJT6c#@iI۶X7z ^ ;LTݾynR~9q->D}:{? eO^u{.._0__K/9zT.7ș``ɓ'WJ͹Ə +;u&:60 ƾ0sU T P0@U T P0@U T P0@U T P0@4FQT P0@U T P0@U T P0@U T P0@U T P0@U T P0@U T P0@: {sh ѱhl㰿n 8-:&m( 9U\TV1UO(905.Kl> K6_G"3S\y6g+5BRRśt3yqZML7|^%5N;]bHq²:Ib0B۩eaoC΋y(,L+ei^V,ߞ:yY!B_'7]i)^{3 n6T¤݅擊R|flyu_.wkWg 5%iw^th U⊌VLV6BNʖ<Ԋ)UEqZw9pO_<#Աݫ˻ t%ԡe=#l;64XC^{3o'h{JsU=*Ic %zZ}`WQ7QM`1 _&:&2\Jevclwe3i,rekZ%,%EϤGε,ƭ65<}"gl0gM]Y8۵ʊL_{t.u^yYӥ,h n6Yǔs]SX"-BEkk"3׮E#eӅwKH)j`zM1mQVQ훊[P*7Bm> ^Z:ӔJUeA,-EN3Sj [v [IDATHIQɕo$<E)aVOYE' OJYy֯hL cpb4%زd[^vr͑.)SDi:ע-Yg3: $HK0!*μ1IS%[d=mDJ0֙ L .ampJQxԒ.tnYhP.W_ĺO;])/UFWW v.]m]AZ[AW\bfDD+ ,=yS##j똘[au4ugvWnTg!2Z^ W1ɔ 6㠋c"S3"-Alm/e'!Oml@Q`(,;-Quо%''Z7ZUYY]O!*ɩ++  %̋}/w,8hyvfēHVhB=c'bڀ%t.K.jUEI8hKuvju^ -J2{IVS6N7:^Vp+E۲$j,'}XuL3i2ˎ,{}&e^ZK@jɾj79qzҪ/{6>R| _hVK1r/iCKiP5_h.Mu:-:F!<9%{͍TN&@4)͍[mjNs N[,&'y @3,-X^Rl9k4BvԻM[m޽~%yұXӆ@`$`*@ `*@ `*@ `*@ `*@BJy-Pg^(A-E]DJpDmPԂ-؛h+inVH]+XbWRѪˮQFA j5xYT[TsN%!r2;mޙygΜ/^XXXXXXXXX wK<ƚ5kҫWӿc3p`nnmn`й=t鷿3^ {^pe?޽{;?jFKۺ>~t/giٮC[vc/ޣqFܨ6mm h_73UxڶnmןSyb^|y`NnN`[ծ{V\]{o\on=caDe\:c[fcI6߼Qy3Z}M]u7O_8g̋gn\1Zo:u iyw,.-M'Nx7Im5~[qo| )G㟤xŁr\>T^n]]:ťQ{W-[4kTs)_?%U@WNO{ ]OaâҰ ˗Wx2SHqv+?11Jӟ( \ag?~vХSIksGVQVtZٻu6rM͟@ցAj|o7jKqa{hVV'J.иF_[wȪy\]_ūՎmYX'l?slMI1/p^|mаf<ԏ4P*'3lڷ-8t?.(zre#:.=T^NbȜgI,QHp(F9-Kٯan\Z_w#眽nٵq~kC͘r=Zu1Ɨ:o}&ڔ ~{.n] ?NϫJuɔs>W]}{ :x7cf+iS)Ȩ +^\OM>8f؃M*|+ G 3foXo-Zh6vش&k˫7ߴ9xݙ]375/w̕{69'̜Z4{0uV#CK9}Q Wƞڲ~oGW|Bެc]Dhc?&7h=Ws"$7mփzk'o{DNd Q s:Pp'qq~3+={<|Qk{?*\[28-4|~i.-nn+@'N]T劗I4fM4Ψ#'':&Om9эr<#LCNynFfq3 5̌%xS{Dq`VS y N6'DZN-X}9;;+tizȐǐ I4?8muϛi:b|4'9Dt׎Θdhȅu97LO7׺~Ϊa+g]w(ٮuUM3sfa/4th^Ϳ]ך7'6th)>pm_h ɍͿ:oie%Zl>gW.;$&jGQc-0''Iv+oN><+K 0ťS'4077*ԾS;}fOLfͿi뉉S܉ߧM0tucY3*?س]}*?,cذ\V}sBJQ>! 8"'숕+/pi Nwեc5^>*ϿvS=Ç- ]A3[i Wϼo[7*@=xUW'}vyT^Ҫw\c98-կW?_ǖ?Ǣr~uѿ@L#a[wj1 u+ϟXvTmFn2JukCvӟ/ Ѹ^q=Љݫwh?i#|wF?PZV&/?UqQiyz\rCj꒒DM: /k= =7MI]>o(_UQg/pn~jmm(K=hp~cD谢d⌧Tq%B 9I\}ĭTY2Չ Es$^ųX"5XhK;vΞ2wVOis'/MvvP]1wriH;x֜M4/iEoZ4\=\~V&VN뗑=qQuT1fAւ1C-*{Tg LĬ=rެgT^ N/qE5) @;iI2g_Nл~U'_rwKnH߆NСyE[ V h7uuu=Ā @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Buk1w  0  0  0  0  0  0  0  0  0xz|ɒ{7XfMحz>}c tuuus{zogʫ:={߽~ؽ{Љݫw?jFKۺ>~t/gi;C[vc/qFܨ6mm 웙*^m[O)9y! )۩խ[Nkj:1HmFz|ɒТ#9"lON~Pdj~3W0sڃ5.>mMp#CxbzdZxvNxbⰩ ˳YX/'g@hC>Q‹W!W6<fAj9r^xtgnٲ{.3N|"t~3,^Vbj+W]7ы1=̿x\~ t=[uܧhI53F'HWTޚW`k,ҋ\XVey&~ꅕaM6ʺ+GÏUv~ڭW6|֖~;*fm _p"$8wLMݦZpmɬo~ܶ~y?,ZT劗CS0ic&s~k^.^AxщGI} '쀕W Y!!yŽy<oVČV+À-\xc ˈ^cg]qr<ϡ>&M+׵y~aCvN{v{T~ޯ ;眽MQm:slq>W-2숛9U8z,-G:>餁1N0.tzOL/za`7I{̚TǞйXyKSAĂƝ>6c5^*ϿvCakگ?33{_vt2+><*ziׇӎ;.ov׫/~ccQqM_ݫUu~SQڌ^S?}}ĂFE m @榒`й]wg_Bg5W\C9$tb{b p>'MWv? td` &;` &o,0  0  0  0  0  0  0  0  uuu:-Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,t ibFn&%UaT/lr!J&eh&yEsk@ע8*KN[٪55+e6]GWխ5 쉥aOD0~{OkuY\tBVY.E plUNP|ŸR̜%eK@\ pyQvѲMouƍs 7 +ΛXRZ7 JK&fW[P4MTyl~"Ź,yTW)XiDlf\^4q˷l2[^Φ#c!*|q%[meO~ԏ=v[KvnQ/GEUvy9 rz43yVֶp7>]X>tKJ_kRĪ͟Xڴ. Y'N[ J*COҐ~NcMbƼTx.k>=Om8K'=5mqO7%&W&q^l{L\ɐ*tUbW̯nmmƣ'&ìojw=ZX1mFY|@iiT& ˫4%n?G[^jaOIDATV,LkLԓxb}swTC.(*+̝QPj [wq^VR/yr͓fɩ+%;oʢsR(l(19/'\f9/£M/sA.6e~La~q'L _N]E1)t˞Mu"oIo-}[njq%s{*);yZ>ɝ<8Y^Ve$niKaoSnO tj-d{d+Sl(O=?'?//zϛ;c3 99YZ{CI}D)/)IFp跚[4!>8ԛ~+fo^4Թny.sZ-;7' yxƦh\qEq 1k[+k]UeSrhj+nmmG?&bΦKwfl{m\QUոt ɆݲcttM.N r]A/H\TZDX]RRȿeɥ Rq,~6pbV>8V"$>u[jHny {_TeoNfܸ7(w6rQb&3PeLmۢnTF_}uQ}+umG5&ilf[/{'\Qۣޢ7 u_TtAOEX^^>o(_UQ쿜#\_+.oOtJNρg\ͦZS4~tJQi+fR1%% a{8'??VLt滯Wj1+on0BR] 779r߱47uŠGM)2g溪⊲-獹!PIwn w͚G.jn֬M7.rŢ9EͿ͘ heLGS=2SV:p ?WN,}LrEj nC(sNNEWOli'&{N[0[RĜ6;Dɏ^QU]4dݔ1V%fʬo"T -Z~gB+ .މޱ~bV)hڲ)9svvp).*\d 'iy`~Qiemjʲ%EyٓKϘ0qs*o(S< '1>lK[N:9s9ɃzHER]VR{Ƃ-5dܪ,+l8ʲ9EٟskK:y%7cO=dOzb3r K+kvK sOL4?UV+N2ZP>LjٯNc=AXf]u5rNamx'ܲ&5qBm锆}ѓ%bFKW6wEmrz~GUrjڒDŹۉIY<CEXҹ jy'] G״ Yȭ?xyqk>ѭ?P uQk n۫ :t?hbopAQQ4 1=rUyddmj힕5I^|Cfᜪ/uɃ) gֵ@?{[6~aaGS[i~}sMSnvdW֭=$&sRӖ⇾r[7k}y+aС\W|7OٔT:wWKC*={/fIAKrҟWhͿ߬i]oi:mn`ڐVϞt)^PW_ߟr1?t7-LJE Хݫw.: Kf4aW~^ʺc~;~<ס)<Hg̾{g?[pSZhQCБ)W~ߏ ={| /V*Uۚnܸ|ɒ{78C{{::N=ST؍Vras/8x-?8\ Cgᄇ֓t /¡O/]LHCJzuM]w˯o:j7wo>ھ,}1~z_>G`$XT3-T/)_4n݄'| ?۝*o׮}&4F fF!׿ҥ[g׭Nڇ~xRM[KT>o2.C&VN~Moz<~XNn|\ןSybff.pР#skMiks_{u>{ٳgs;lfI.. ( ~//=a3Gs3=wՋ&g_K4>ťS<ɁXzw^j_pݩ>p6X3j/Z45ݾ '*|yOmx94(dM 3> D=8obo^ $_~^.S }ѿ'!yWϸ[.IG{O#L-+蹛u&[V]o}cC7eϾ4̻KgT_ ÌdWr1O?? wIDATlM545'p]W|ͨУGrK'݊soiı}ᇫVU=Cc q~!Gf^(y/z} ̤]-41xa/>s,6|>~֠I>785<ӥ8 x~s[/8{龙4T &oS_[3͋ |ov 5kք.W^ӧ=fL@8ιFɓv 5 Nl,0`1N-o"U8]غu*W^_ݻ1G nԎ[dO7WscG7.&*bWkR69?O۫4Ct] tMMT9zxQ~e?z;o? }As1)tg/b؆ rG3W|%֚5O=}g?{-L_.u;s0$//!ح~>XSwig't#1!$l Wx7̾>U~nwG Dѷ1?ر"v}7gi/@| !'}Y 7HK=* 3=T/؛zwS+35o%M{ Ǎ 蒗3nٳgj6g/?B[W^;bn9 ;{W7{{>w85wDVlX_.Nx™`vypWҭ[#ea<ӳ@t+Љ/m?0;;_.' Mlrlyk>ٿ)S=#]3H:th* t;VOBrҵ+3OT}/] >?_aWv_i/T*~Vx.Uj沺e!_+~vgI^xᅰswswBZQ_zTeeGvQ OS j"`x>fggqםڷ S>\RؽZzQvf.q8կ6dH^s+K_555,HO?;oז~vN;}l 6󮵋7R4/6OڵQya} owf8(:5U533k_B>\ēOyݵ}gc QTt7oK1lXuC{̚T9B_.4CkǧW@'KGW7]4"?~̎k,?#X/7W^Qz 'ݸqch/~^^l4Mv4uܨQ~T9sgw/%~S[߯Z%z뭙Jx|qii(^˶{[^5tBV>;}9g9Q#pt9 ),*Uk5~Os1A[x>뜯}Z%?l&+j~ 7|675\ۋ>׹Ͷo۬e;|F4ʒBލx9lvy7ulv6CX~tӒ5a67ך|Ӱ4+lC,_٢Ox[ՏOvYVG/Ͼm;y?D-{v{b<i7|*7^Ōe]}YFsSSpc]r}ݍ5s}uoݲ)E>,K#>ngjMrInݺ+q^u'/~ xS Od}Rn:eYS7nC*_v;~w^zNl{QJU˲7hnCVvƜXh_VZ;o6$7+To a_5>D6C}!@͞xwfL<9*.CC?mmY^Y8(ro0tmn]K/ʫW_{o3ƝE弼kZf\yՌÒ)09aK74ƘD2YY-~t3^tEvE{9堨;tF(1b׿;b̞={dS7ƀ-杨p\*&CCy.-L5܁3B}mҹ'z<Կ|nI g~% ;[I^O}Y}Q[f74^ݘ?G>.B㝙A8yߘx&ޢɡ ©RYaQKù/;mkjN4Ձ`{ o_pA]? VHJn29ProgSsS {vvZ_]N7uNk=6n'7{Od ZQgg~`, 6).ȃ>tWL\˯OZ;G}|ͨTo 4Tѣon/-ԨѸq9Q|g^Ta5k{_L|i>/Бcn Ks;co\v{τ޳gGg/?BF ۪"U8C1ߦ S`u6~oeA Q"IDATOsJUo޻nݺ?)55 ii7ךVsi[/q8VOŴW~6q0tT~k'@'f_.?9U> ׿F}iZnNhݺuB^BuZp˳ _ii} /B iŊRЙ|{k!{N'PVg,mO{@Ҋpvv dg ZzmժT$XۗF,nGc\W~厵[A[;FУ ɡbETx/=STӭ;?]j 8,;l[vv!y˗'&=53e!jjj/X*~iŽ{AYY)-}RpXzW[tYES ?f?!'|r'֮; _|dS_>\WW;n"Ӭc Qt7`%O{yک_jOoص?-{vw-ۃ:J~nmd~6$Uؙђ:>1ǎ9"8 tQQ{oySO  G}g =j@IT!JۣO}*@ٰa»fMj>t =_z_x {߄i{Omhy/`}'O=Brrqj»n *+v!vj⫯vݿ td`72 ֭ۈck'l}!O8+t`:^Z_|w{Ķ~``4nXXXXXXXXȨ i `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `b[H7J'ggddO. ZZBͭsVv ]=\3Je/f+.nfڊQ솝3&VnMȟSX=GٓKl2fAjy-1+/sX[vWx@^I3C΍ll[b1{fmZGff{nܐ j76Y۽G;=qцU4:]_WW~# VVX4V-8଻kžz)Qn/5obUO4usf꺺f _HęWLXn݆988 P>%'6v(V.H= f\-jLO9d%˫MV,LkL,|ܢmc  ֚6SZںZΟ<)+Mc6 L@,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Buk1w  @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,B%K{xc͚5ӧA8xQ;gvmn`й=t鷿3^ oMG5$tb{?jFKۺ>~t/gi;nݺ]4/^{vT^jb?of{mׯ?K<̳^9ܜYUUV/W|5]Zy{OϞ=K-]LlϜpbިwB~gbIEj/}igddZ[H+ϻ1N:oJ>(;: NH-w @K>QyЁ>}kni}'u+^x=#`KTޣU J`䎟 XVU=CNO{ i~N*7~4:H:q5/wذyoaKμ{Y kjjRA#mnryA#?HM͟ia'ajFz|ɒТ#9"lON~Pdj~3W0sڃ5.TF}dik6ߴrµ&;l̦BicM ulݛ1pTzg.H˗vAj9r^xtgnٲ{.3N|"ac 626o،ц>E oT*w=˒8ѩ5m{3%:x2m{TRMRN&{DNxIUUadN26 Q1]ywv p~oGW|B;ڼf*_H^=쭢wPqT!++_Yڨ W?UxnF:!Ss~d Cx+gmvbfn7;;+Бҩ !y/!'7>9)IDAT~êOM|9vbβ?v̰>}gsvNblpNt8 /^0%+6$XУ tmn`ڰCZ/w@/.-W'F2??B:{3v]Tw /6KٻWЅS'4077*ԾS;}{ZO,N/|>Б)f:;ygjqZE#,7:g]޸xi7GU޻+WF>ytcZg~iomsZ|EnN= ;a\j.[w뮟ӟKH7~ŗ˔:1-@8_pgOtpܨQ'|uWٳg`IL.@'$ 0  0  0  0  0  0  0  0QWW @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,t-ThC蔲'hΧl5!:<@km/T[5k@ 6h+cvl~IQa^vvfÐyKJo[Tݣ~fnEs&f&6٫znaʘc?*6k pUIi+Xfłic̘rnakK'IdGo證biYe( ڵ8' +u¤Y_zw}rn9wHZ5-0r*>oS5oƉDRm|JNmj.Щ)fH;yN ͫWWW&-i7ynIQ*, v$Xɟ++dCh(/8{VVNnAqsh/ es&n+1 y+{Y6Ԭ|t/5f=3ͩ#K{ s 8[]YvM[T[.9ypV-}pq4uNȪ9ֿf[/3oҊ ɪkV-_<'ZQ<<@;h\5w'-*-*h* j˜좆#3;;'pʌ'/JL'6ngffmn8ʮɟ+ʫw7VU,*۳ߴKeYb}/V6 P[YZ\<7l༂E%s ׿S^(O̭f7eEMhQEOV'J%Mu?EBN#Or̭7D-oNeMiIr]~E' ݰw/KwLlkur[[əR'l8{Vˤ;~ؖ[3@ Ă @,B;)ԖNh%.ִqO) tm]-Oڦ1S s] & `bA `bA `bA `bA `bA `bA `bA `bۻWЅh `bA `bA `bA `bA `bA `bA `bA `bA `b!%=of͚Ys:/G~rV<{H 0@S\\@*vWo I~rOTbU|@GJ y} Ǐ=7>cذkzi 7QrGS8Gn[r ˝Vu9g/[l}CxbzAz[-dyGSI}rB:ʷv 55 t=CiM[5%KB8戰=9}Cyhy\ݰw= kԖ;vƪ}/^VӒ{L;lZr˄kw8t`P]]3K @H IVKu];`ƎOL;3MG7ѧhaTst2-om~[{t{Eua+?1qn!waF_[pdh6;@v8m+^>la$onL'gLmܔh- t1ԌG/^veah/+S}eehV>^]T劗Cy" v8My.2;ztiaF薬\^z)@RxRhͦZ=fX"ʳϮ~Σ_;z [ +TͤXG^x1M&j{pczQQWW [vH+@ť_Ĩ__HgTs3ծwnFw#{t=FwjO\tO |Iũ;þ:R:=c̟>5Eׄ?XR*k322)͞|ܨQ~Ty<G}/L-N+hD~~F?;x{WaEx(>`'n` 0@,/-᭭u~SɣGa'K e .sӟ/ ۯrwB'b8G> ^x≐5jℯN={ t180Ŵ``bA `bA `bA `bA `bA `bA `bA `bA 2tuZXXXXXXXXXXXXXnm(=6@l5!:<@!]7\ zCuE=2eͭzod1 R dl!NU`;-Ss+׮|ŜY/Hi+8!O]_YK'=5mꦕ'nHXQyЁ>}kn"'u+^x=#`N-KH=_N~Cr>kժz(ɤSS`Cgo`QJ#pEE\SG8r{uߚ;lXB+=1=cfM6,ca;jyyySI}rB`erN~0F֟UM̞͟4ԦǍ%EGsD؞Dj-lMԐ;uAk,U2~ՉҴæ%WMvU0pTzg>] fAj9MG_uϬS:H)ZQYWh~뵢1{Ϊ[w(.bUռfn\lUnR ip?϶_CQ/66J!j-J4&= rye mcҩ *\rhV%;2Wͻp櫶4#t V.YN&!yŽ+f6,cذϳ3nz+^=mlbk'\{e<7Gd2궹ukieW+_2˜ ;9uݿ[/~!Q]޽zxK'4077*ԾS;}'YJ; _|I{̚TǞ9|+Tʿڌ@'f>nԨ {A 127.""" return 0 < x < 128 and chr(x) or eval("u'\\u%d'" % x) ################# # BEGIN GRAMMAR ################# COLON = Literal(":").suppress() CONCAT = Literal("+").suppress() EQUALS = Literal("=").suppress() LANGLE = Literal("<").suppress() LBRACE = Literal("[").suppress() LPAREN = Literal("(").suppress() PERIOD = Literal(".").suppress() RANGLE = Literal(">").suppress() RBRACE = Literal("]").suppress() RPAREN = Literal(")").suppress() CATEGORIES = CaselessLiteral("categories").suppress() END = CaselessLiteral("end").suppress() FONT = CaselessLiteral("font").suppress() HINT = CaselessLiteral("hint").suppress() ITEM = CaselessLiteral("item").suppress() OBJECT = CaselessLiteral("object").suppress() attribute_value_pair = Forward() # this is recursed in item_list_entry simple_identifier = Word(alphas, alphanums + "_") identifier = Combine(simple_identifier + ZeroOrMore(Literal(".") + simple_identifier)) object_name = identifier object_type = identifier # Integer and floating point values are converted to Python longs and floats, respectively. int_value = Combine(Optional("-") + Word(nums)).set_parse_action( lambda s, l, t: [int(t[0])] ) float_value = Combine( Optional("-") + Optional(Word(nums)) + "." + Word(nums) ).set_parse_action(lambda s, l, t: [float(t[0])]) number_value = float_value | int_value # Base16 constants are left in string form, including the surrounding braces. base16_value = Combine( Literal("{") + OneOrMore(Word("0123456789ABCDEFabcdef")) + Literal("}"), adjacent=False, ) # This is the first part of a hack to convert the various delphi partial sglQuotedStrings # into a single sgl_quoted_string equivalent. The gist of it is to combine # all sglQuotedStrings (with their surrounding quotes removed (suppressed)) # with sequences of #xyz character constants, with "strings" concatenated # with a '+' sign. unquoted_sglQuotedString = Combine( Literal("'").suppress() + ZeroOrMore(CharsNotIn("'\n\r")) + Literal("'").suppress() ) # The parse action on this production converts repetitions of constants into a single string. pound_char = Combine( OneOrMore( (Literal("#").suppress() + Word(nums)).set_parse_action( lambda s, l, t: to_chr(int(t[0])) ) ) ) # This is the second part of the hack. It combines the various "unquoted" # partial strings into a single one. Then, the parse action puts # a single matched pair of quotes around it. delphi_string = Combine( OneOrMore(CONCAT | pound_char | unquoted_sglQuotedString), adjacent=False ).set_parse_action(lambda s, l, t: f"'{t[0]}'") string_value = delphi_string | base16_value list_value = ( LBRACE + Optional(Group(DelimitedList(identifier | number_value | string_value))) + RBRACE ) paren_list_value = ( LPAREN + ZeroOrMore(identifier | number_value | string_value) + RPAREN ) item_list_entry = ITEM + ZeroOrMore(attribute_value_pair) + END item_list = LANGLE + ZeroOrMore(item_list_entry) + RANGLE generic_value = identifier value = ( item_list | number_value | string_value | list_value | paren_list_value | generic_value ) category_attribute = CATEGORIES + PERIOD + one_of("strings itemsvisibles visibles", True) event_attribute = one_of( "onactivate onclosequery onclose oncreate ondeactivate onhide onshow", True ) font_attribute = FONT + PERIOD + one_of("charset color height name style", True) hint_attribute = HINT layout_attribute = one_of("left top width height", True) generic_attribute = identifier attribute = ( category_attribute | event_attribute | font_attribute | hint_attribute | layout_attribute | generic_attribute ) category_attribute_value_pair = category_attribute + EQUALS + paren_list_value event_attribute_value_pair = event_attribute + EQUALS + value font_attribute_value_pair = font_attribute + EQUALS + value hint_attribute_value_pair = hint_attribute + EQUALS + value layout_attribute_value_pair = layout_attribute + EQUALS + value generic_attribute_value_pair = attribute + EQUALS + value attribute_value_pair << Group( category_attribute_value_pair | event_attribute_value_pair | font_attribute_value_pair | hint_attribute_value_pair | layout_attribute_value_pair | generic_attribute_value_pair ) object_declaration = Group(OBJECT + object_name + COLON + object_type) object_attributes = Group(ZeroOrMore(attribute_value_pair)) nested_object = Forward() object_definition = ( object_declaration + object_attributes + ZeroOrMore(nested_object) + END ) nested_object << Group(object_definition) ################# # END GRAMMAR ################# def printer(s, loc, tok): print(tok, end=" ") return tok def get_filename_list(tf): import sys, glob if tf == None: if len(sys.argv) > 1: tf = sys.argv[1:] else: tf = glob.glob("*.dfm") elif type(tf) == str: tf = [tf] testfiles = [] for arg in tf: testfiles.extend(glob.glob(arg)) return testfiles def main(testfiles=None, action=printer): """testfiles can be None, in which case the command line arguments are used as filenames. testfiles can be a string, in which case that file is parsed. testfiles can be a list. In all cases, the filenames will be globbed. If more than one file is parsed successfully, a dictionary of ParseResults is returned. Otherwise, a simple ParseResults is returned. """ testfiles = get_filename_list(testfiles) print(testfiles) if action: for i in (simple_identifier, value, item_list): i.set_parse_action(action) success = 0 failures = [] retval = {} for f in testfiles: try: retval[f] = object_definition.parse_file(f) success += 1 except Exception: failures.append(f) nl = "\n" if failures: print(f"{nl}failed while processing {', '.join(failures)}") print(f"{nl}succeeded on {success} of {len(testfiles)} files") if len(retval) == 1 and len(testfiles) == 1: # if only one file is parsed, return the parseResults directly return retval[list(retval.keys())[0]] # else, return a dictionary of parseResults return retval if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/dhcpd_leases_parser.py0000644000000000000000000000575415134002420016645 0ustar00# # dhcpd_leases_parser.py # # Copyright 2008, Paul McGuire # # Sample parser to parse a dhcpd.leases file to extract leases # and lease attributes # # format ref: http://www.linuxmanpages.com/man5/dhcpd.leases.5.php # sample = r"""\ # All times in this file are in UTC (GMT), not your local timezone. This is # not a bug, so please don't ask about it. There is no portable way to # store leases in the local timezone, so please don't request this as a # feature. If this is inconvenient or confusing to you, we sincerely # apologize. Seriously, though - don't ask. # The format of this file is documented in the dhcpd.leases(5) manual page. # This lease file was written by isc-dhcp-V3.0.4 lease 192.168.0.250 { starts 3 2008/01/23 17:16:41; ends 6 2008/02/02 17:16:41; tstp 6 2008/02/02 17:16:41; binding state free; hardware ethernet 00:17:f2:9b:d8:19; uid "\001\000\027\362\233\330\031"; } lease 192.168.0.198 { starts 1 2008/02/04 13:46:55; ends never; tstp 1 2008/02/04 17:04:14; binding state free; hardware ethernet 00:13:72:d3:3b:98; uid "\001\000\023r\323;\230"; } lease 192.168.0.239 { starts 3 2008/02/06 12:12:03; ends 4 2008/02/07 12:12:03; tstp 4 2008/02/07 12:12:03; binding state free; hardware ethernet 00:1d:09:65:93:26; } """ from pyparsing import * import datetime, time LBRACE, RBRACE, SEMI, QUOTE = map(Suppress, '{};"') ipAddress = Combine(Word(nums) + ("." + Word(nums)) * 3) hexint = Word(hexnums, exact=2) macAddress = Combine(hexint + (":" + hexint) * 5) hdwType = Word(alphanums) yyyymmdd = Combine( (Word(nums, exact=4) | Word(nums, exact=2)) + ("/" + Word(nums, exact=2)) * 2 ) hhmmss = Combine(Word(nums, exact=2) + (":" + Word(nums, exact=2)) * 2) dateRef = one_of(list("0123456"))("weekday") + yyyymmdd("date") + hhmmss("time") def utcToLocalTime(tokens): utctime = datetime.datetime.strptime( "%(date)s %(time)s" % tokens, "%Y/%m/%d %H:%M:%S" ) localtime = utctime - datetime.timedelta(0, time.timezone, 0) tokens["utcdate"], tokens["utctime"] = tokens["date"], tokens["time"] tokens["localdate"], tokens["localtime"] = str(localtime).split() del tokens["date"] del tokens["time"] dateRef.set_parse_action(utcToLocalTime) startsStmt = "starts" + dateRef + SEMI endsStmt = "ends" + (dateRef | "never") + SEMI tstpStmt = "tstp" + dateRef + SEMI tsfpStmt = "tsfp" + dateRef + SEMI hdwStmt = "hardware" + hdwType("type") + macAddress("mac") + SEMI uidStmt = "uid" + QuotedString('"')("uid") + SEMI bindingStmt = "binding" + Word(alphanums) + Word(alphanums) + SEMI leaseStatement = ( startsStmt | endsStmt | tstpStmt | tsfpStmt | hdwStmt | uidStmt | bindingStmt ) leaseDef = ( "lease" + ipAddress("ipaddress") + LBRACE + Dict(ZeroOrMore(Group(leaseStatement))) + RBRACE ) for lease in leaseDef.search_string(sample): print(lease.dump()) print(lease.ipaddress, "->", lease.hardware.mac) print() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/dictExample.py0000644000000000000000000000336215134002420015103 0ustar00# # dictExample.py # # Illustration of using pyparsing's Dict class to process tabular data # # Copyright (c) 2003, Paul McGuire # import pyparsing as pp testData = """ +-------+------+------+------+------+------+------+------+------+ | | A1 | B1 | C1 | D1 | A2 | B2 | C2 | D2 | +=======+======+======+======+======+======+======+======+======+ | min | 7 | 43 | 7 | 15 | 82 | 98 | 1 | 37 | | max | 11 | 52 | 10 | 17 | 85 | 112 | 4 | 39 | | ave | 9 | 47 | 8 | 16 | 84 | 106 | 3 | 38 | | sdev | 1 | 3 | 1 | 1 | 1 | 3 | 1 | 1 | +-------+------+------+------+------+------+------+------+------+ """ # define grammar for datatable heading = ( pp.Literal("+-------+------+------+------+------+------+------+------+------+") + "| | A1 | B1 | C1 | D1 | A2 | B2 | C2 | D2 |" + "+=======+======+======+======+======+======+======+======+======+" ).suppress() vert = pp.Literal("|").suppress() number = pp.Word(pp.nums) rowData = pp.Group( vert + pp.Word(pp.alphas) + vert + pp.DelimitedList(number, "|") + vert ) trailing = pp.Literal( "+-------+------+------+------+------+------+------+------+------+" ).suppress() datatable = heading + pp.Dict(pp.ZeroOrMore(rowData)) + trailing # now parse data and print results data = datatable.parse_string(testData) print(data) # shortcut for import pprint; pprint.pprint(data.as_list()) data.pprint() # access all data keys print("data keys=", list(data.keys())) # use dict-style access to values print("data['min']=", data["min"]) # use attribute-style access to values (if key is a valid Python identifier) print("data.max", data.max) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/dictExample2.py0000644000000000000000000000415115134002420015162 0ustar00# # dictExample2.py # # Illustration of using pyparsing's Dict class to process tabular data # Enhanced Dict example, courtesy of Mike Kelly # # Copyright (c) 2004, Paul McGuire # from pyparsing import ( Literal, Word, Group, Dict, ZeroOrMore, alphas, nums, DelimitedList, pyparsing_common as ppc, ) testData = """ +-------+------+------+------+------+------+------+------+------+ | | A1 | B1 | C1 | D1 | A2 | B2 | C2 | D2 | +=======+======+======+======+======+======+======+======+======+ | min | 7 | 43 | 7 | 15 | 82 | 98 | 1 | 37 | | max | 11 | 52 | 10 | 17 | 85 | 112 | 4 | 39 | | ave | 9 | 47 | 8 | 16 | 84 | 106 | 3 | 38 | | sdev | 1 | 3 | 1 | 1 | 1 | 3 | 1 | 1 | +-------+------+------+------+------+------+------+------+------+ """ # define grammar for datatable underline = Word("-=") number = ppc.integer vert = Literal("|").suppress() rowDelim = ("+" + ZeroOrMore(underline + "+")).suppress() columnHeader = Group(vert + vert + DelimitedList(Word(alphas + nums), "|") + vert) heading = rowDelim + columnHeader("columns") + rowDelim rowData = Group(vert + Word(alphas) + vert + DelimitedList(number, "|") + vert) trailing = rowDelim datatable = heading + Dict(ZeroOrMore(rowData)) + trailing # now parse data and print results data = datatable.parse_string(testData) print(data.dump()) print("data keys=", list(data.keys())) print("data['min']=", data["min"]) print("sum(data['min']) =", sum(data["min"])) print("data.max =", data.max) print("sum(data.max) =", sum(data.max)) # now print transpose of data table, using column labels read from table header and # values from data lists print() print(" " * 5, end=" ") for i in range(1, len(data)): print("|%5s" % data[i][0], end=" ") print() print(("-" * 6) + ("+------" * (len(data) - 1))) for i in range(len(data.columns)): print("%5s" % data.columns[i], end=" ") for j in range(len(data) - 1): print("|%5s" % data[j + 1][i + 1], end=" ") print() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/directx_x_file_parser.html0000644000000000000000000010743415134002420017531 0ustar00

template_defn

'template' identifieridentifier 'name' '{' [suppress] <[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}> 'uuid' 'array' 'WORD' 'DWORD' 'FLOAT' 'DOUBLE' 'CHAR' 'UCHAR' 'BYTE' 'STRING' 'CSTRING' 'UNICODE' identifieridentifier 'element_type' type 'type' identifieridentifier 'name' '[' [suppress] W:(1-9, 0-9) identifieridentifier ']' [suppress] 'dims' 'WORD' 'DWORD' 'FLOAT' 'DOUBLE' 'CHAR' 'UCHAR' 'BYTE' 'STRING' 'CSTRING' 'UNICODE' identifieridentifier 'type' identifieridentifier 'name' ';' [suppress] 'members' '[' [suppress] '...' ']' [suppress] [combine] 'open_template' '[' [suppress] 'WORD' 'DWORD' 'FLOAT' 'DOUBLE' 'CHAR' 'UCHAR' 'BYTE' 'STRING' 'CSTRING' 'UNICODE' identifieridentifier 'type' <[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}> 'uuid' ',' [suppress] 'WORD' 'DWORD' 'FLOAT' 'DOUBLE' 'CHAR' 'UCHAR' 'BYTE' 'STRING' 'CSTRING' 'UNICODE' identifieridentifier 'type' <[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}> 'uuid' ']' [suppress] 'restrictions' '}' [suppress]

identifier

W:(A-Za-z, 0-9A-Z_a-z)
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/directx_x_file_parser.png0000644000000000000000000033305615134002420017352 0ustar00PNG  IHDRjIDATx \Tu%ES.b%Biඛ }o%hۚ`nEfCIPASE̙F.3Ùq39g8g3s>}>P(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(ـ(]6:*-j!@*OqknvK9||T i[>fo}|B&NT)ӦlcV}#ͪc&v_[%D5yT:2_1κ\UuΘ|@ (. 3;`,a.?ޚ~^s9kt/!Ϟ#l@`gGg&vזܽC,^RCCCf,g-q aÿ֔ϼU_jn(}*J=)ݼC&-^E5Stu~ ?`jX5Y6Io\J/]f[}JK^ O|5=g16n;+CZ6oO_Z^ Jvl͔ܿ~n}#K[e/v<6`Բ7u>i=v|/[..UKuD{U<=f[k. ʶ8 8f~%,8x7r& ~BB:?ِ s[?w 34*\zzK[f~>CWYYi;wlMـ7ΰ2ON,쐰StVŋ͋햳l.pG.ϖlKՖ^KPԼy^7ic E͟ޔJlMـ>QQëwU',VѺȨ9/+Vڹ~)cu\TԐReTJXɀbvwn&/7RukXuKh|BTٛ*g>gսt[ֆ`mPa. uWi۰=`gJcl@έA@ sL][՞!ܺ (DޚJ.*8;#j^ >?=e8;ru@@@@@@@@@@@@@@@@@ZxF`l@l@l@l@l@l@l@l@l@l@-IDATl@l@l@l@l@l@l@l@l@l@l@l@l@l@l@+ʄUXwi-&yxz' ΁l@ X_.lj9 MXh*OUDQG 'Ov$HHUoڗ$(nLQf#jF?S^P~V\c2ye;,) I YyMq%b~A]vؒժڂ-d :TJNV[ E^]-eiJ µsʅwhgϑtt}[E;?71EU(WΊ hfN1u1eEڦ"Wħ/;"p6/%$3P-pFó3b#XsBO,e\O!\={׽*fN0%qYuf6y `l@B;DbdPԋ_"OO1PE ДM_^]9PDi.b2:EO\ tʐ,gjG c+vu˹ڱ;s@]ܸ4*4+Tr`BuQzԺ #3>Ku``HUQȊS ՋQ{z{gWkVBKjQJNڗ>v8(g.!0piZ7U*xӊ6NY t%YYr͸skhh05(c7pOryמ{Z9!:jbt!Le*ST2Le*ST2r=n}А 88V;Q{ zji|;njkbtϞ=hhhض="wM @ʅ-go𫯿^XV^8bė_}%`{}mȐÇG7uꔑ!!pjn fxF.ҥБ!C\[_=}8릛nZ{efU)My?3:E& 1|?|)ؕ+W$;~T@tk׮o7.jwXy/Sp(ؽ{{aÆ EuuM#?ٲ-'Gst?{ݵ3?ګzt[CC'.Gg=._^&>>>]/T__/{ꕛ-2N5w۽'OhODM&?׽oL\ӹ۷ ~9?=p|_>%C6 h,y2իW_+r9"bWaTh[+W#xp.d+*r?~\*٭4̜oKwm>ٲU.>8ۇN;vLSgΜX_o訉QƇޓGe*ST2Le*ST2{qÆ{#:g~B~'O cȐ[<==;YYyIMY1yݽWßRxS{珿i klYyEyET.;0IUIFF .MRyמ{B7nnnnO׮|ߏ$@8*7Nu5e&DG H'Ln2˯>!OOO)# `jhЀ99dF* "h4x 7~_RZ*8:|Xlݚ.?zNi̘aCS^Q{OTE6 K76}y˶;Rt•+W$;~RsڵEM.E_|EEUU>o=?R__{z{{=3aÆ  PuuM#?ٲ-'Gst?{ݵ3?"rz%@l@444>>#{iJxwVg$R}}4S󋌼Srss n Y$ޗ ,|H/'} /_˧F+54+T+@WTȓPWWrDĘ hTh[+W#x 73)WXQd,߻ v$$0ʖGz{t.M`l@@l?~Tpww73[7xi̜o8 OVe71iKIҒ8t91Š4%XeAcېh.#-[BSo}Ԟ}7r!?ɓ'aΏZmcڬ6t mi\&N]pRkV)W}n<ytb|} Y%)M*/׎@('SjUx7Km\*Bו愥g7]Wk{п+cT3"1)ş *KDx`nraܸqڻwo/?_BX͎͝IDAThSt nLg)ƌV{/V0"RB޴5u>RXٺ4%$I4I2YiK.R E`I>pBu]L.#YUT[`]NMFlLk´x7cZ^wu_zSx/UT`!ע 3.6Iz{'gό6r]s:EU(,P%1i"[ȋY_tu̢-ۤ5 (]UU\?N%8nݺEGUU|}'DGIT7146M=s&&.{fV.G]3un  dܘe>bc2ӴDIfg{*ϘnLS,GtP/mla2d2 ۆ!GhzQϴ0@UFHfĈL.}lFmN3]hƵ.X*ȗI}C:v~TkoLjm|؆TƿHzB}/ 5@/3f4R#A2 Xـx\P+1cȅӧO pI%MRAXQLF]cZN<1yn6GSRѽEa\͊Q<×ZJiE-Vmҽc 0H'3.Y7>IZ-wע_2 p*oᛥ)Qv''پ%n6mXec] IoqjeժiweoPvLF6 `'7.~vMKUΞ4KS{$'w]TX$fj%Ƽ=kX>ǐ;TO7IX]W`Kޑ*41רeRk2Z|sv4>])'&3c275>MH4ա RHcaҬPEM WѷSo0P?>P7֨ـ=ʓ 7#ST`FҬPMiDPonHl }Ώ֘I1Xv9d"8CfeD0IYlOV\ZK4-w@&jO*8fЍWvdI~ lclpH;Ԙx{d%*'6Kz-i¸pu1Wj*TcPXh XJ6_m)q dMuL{CWϮ^+))ڹqYupPSK _R":.ShSn'Timmrzq[ /s(xMqI.T$'V\"- ^8sSmv=a)ź.N1̟JiKr] C=]X[V/jBlϺb2 o&sV.{qkhh05p1er ~%MBά77{z*.[e-^IK5-]*RJVT:S^=kH,yyFMTN54e%%'++/\X9!:jbt=yQT2Le*ST2Le*ST-*"tc{1I+Vif l'-V̭ .Ӕ>}3gN_d֑噱17YX_luww")Ey[ܮ%S]^y:Aj'Nl={f'E6 `7dɅُ );\ H^v}VwAfeDXJЏ'_6`8VQL>%iOB\+^b]g=[hhhϾ]\zFuGħƷH[r1u7HiT3偘 / P$>}L)-ՔIM25 OjE;%_Xo8$gO2aKڅrUS u%%$$us2'KFK %/]ںt+i鯦KS_JIzv3fNjk-YS[sxL^Ϥ3qcnj۵d*Se*wmlҷ{w+49={}|| &[MJkclL,[7#F;ູL\P9D㘁l@P~6`C[e?ߐ[o_~}zٳgΜ:uj|y~zNg+ ^^ͼ[R}˯wwF|= 7 YraciJ*܀X܅A+Er4?͖"p(۬ʪ BG\pa7s]cF [)(pĘ9Ϟ~,~UR%1U^^1-vjϞ=(qsՅٗ?4 `ذ`P^Q!OIEp䑸0Qxo4㰁 rqGBXR`ƅXLqLG* p}hs|zƍ”c~\3GF6 BT==)YUd:_~8XV院*T/Ƥ^_/b Gp|[ҧwoPSS[VfX[hf~n60.Д-^L9? GtHiwM7s _ҳgI~l@ )*++=… WdӧV}KsdOU(5JNWϞ\rg';Aw2D*v*pB/0>^^ׯ ֱ+]7}Y* WutHȐ ـR?Oo*M #{s>?[KـSӻυiv`#OZgr,&!55rZwトG v+](j _vr\۽:<+5Cooy&< =(R  :eʒ~]ߪ [-sTO?}lW:׿nٺ p^dҥ渻l4hTzǟltȡ }IDAT/k 8pW_$KlL!WH^+r9"bWkK_}ڵkNl@ѬGI8>ImmQ}<ۣG|hD\@+vɓ& muFѣ۫V Wl~qYݺq=IxgϞRY4VwW8ʪSNKSYy3 5!j_}-|_vӬK >Q<2|H+ڻ 0+&:FtB\TYyEy6[׺glޓ'&DGY\Y-|b v$_=+WWL2E'[ʅ~0eW_]PP(uW_ Hitz&N9C^BG ^t=ߐ%ON. sܤ'x(Rؖy, %I*++5ܳv'_"yv~0n8VķYͷߞtmt!___)$[_l C6 ޢ4+Tq֫Acfe 0-H^_c*-M ~k׮ @6 ,4?#;T)ntϤ\#AqI[<2|Ir|Ċb4S# rcg{{_˜,+hVcNg[Ǐ ݐffv% fk2ٳT>zا@'t\Q-2@,T-4>S[YEM.=̨فI*1*Tn,R" NM=sSmFg|q[kO\%i,0x#݆҄(ӝKe*ST2[oo[Uw +dVo&E PT2Oy7"ta)S"plu'1MhB* CϜ9{̙K,M2*ST Vٳ8"hĈ=zI{tW9HN5cF0mb27$a$%Rvw"Pn`g/.97˹jiֳ~0n8{!`YY=`?n ot àW Y%)R#Ӭ>LM>5tYSjPygk4+*vw][dl޲Š- rsJnݶ}ٵ'9rΞ4u g2,Dmt bl ?H!kq|\o, fv<#e򸬺U+rg((O[Nի\Б#';WFQG1*{E Q^7h8bn@jujꥧ6^ٲZê,(d"=yO5rd~HE߾}C=%=qB{ȴiN'j4[Ԫ˕r׉9uIj Osno`}ղ5%&'LRl*[{~vw37}|ڵ=zL@pAlr 4h< DZ~Ck36bwɓ r.H˷t`\֞xM^3E7sڌm`|U%tR33>.\Li. _R"/sB?SX)䥉9kc&Ryxn=}d# cͥKڛ7 Ǭ^իWO:-r-"`e A6 `Ʊf?_a))/03 .^4+cA9{6SvX5Y]٢bLF]mkk꟪^oA]4a:qi; y!6td\3"G}QtT>r E^c\ـ=tl?)9RzL9W]]SS#w$+_>([r~;K{ y"IDAT5!:jbt!{[o,Ο?ѣRͭm9y|[ZZzĉ . n2dQM:edHH_x^) ӻڢwf$;ci>{z卽v,A \ZؖZ2lDyxxL{A8~\p\`A'++ WF(ـ 9~;4w>">5٨Q>mT+_Tq4⫯3zjL˅{cr}}}b[ׯ_sCKӖ[S_EY?W^_=wH>l8;BC|:s…95eڣ|Q֤{BgV._[XτNh51>p1}|…:"`J@6 h,01'ٳoK: stY.p{%$%=zL\޵k۲ek2GPGrV4N.l˩tI~X~Њۆ ֭ߏEy9\kk9\l26@ >q|\o, 3wsO-jUlk_ڝͷRadH8pԕ+Wjϟ?uzK.ϟdMޓkOT?Z1q/C>C2K\@uuM#?ٲ-'GyM7̘1^={ wM/㕴Wҥ‹)/$ p=R[OjoV3KzK|>>aw&PSS`z}Ͽr,̉8*ؔϊBp!wOpհQٳg~)tdHŋ%, 2o_^ y b&DGKS“O:#ŗ]6_EFiUnnnrz+wS[;uС@+y Y/\-q3.ّnnmF@Y=p=}>zj=p#׮]{21Ry۷m IQM{oD/߫X9'K531\pA*pEEBCt}PO  r\&z{x&P jƊ9сXS\rD7fGoZI* @6*4+{_\tD~C4I~ǎi~} ڈ FZ77 X.+.+hg+>QTc۷\^v|T0(pD ҷB* Z.<ɓ̜_6~b/AH{hZ1cɅwFr~bf˗/^x&ppN yuMA-lvO@v ` UQnwĊ2iHoMev$xz{D4#W{z'4όn!rbuN~d⒒+WVW"(pThZVvɓ&:\&}FԳF.?yX'MٳL:21:J <8Б!wFDҷo_ >}#`Ώc2fE{ DiڛL^[&j;$DIM-dUQmFnHiE ,g;'++B11pS gΞ߯ ֞[зoߐ`@SBC{]__/,cGo~>F 4Riѧpl(_,5s(Vb&3+>Q.SΟ zs-TU gΐ KBTx@ ݺu;W] 8P.\xQp]zerkGN r (sE 7~(T I:!xyyɅjٳratx1cȅӧ͌K31:J& `%OO@l@h*6((_Yмy5r͕@h< DZ~C< mӭXkк rgϞsq8]{I*P86.7(= W] EJgan*V8#nxIM1Ƥ0%37eϜ- GS^kA/&pǨPiB>k36bwɓ y.&02fP86!b-dVe6QWaf kpjƱf?Hs_^s몜=dh>}#`@)^c\ـD]7j]N+WcnFʈb;._qʕ֞eѸkO|]Le*SnofϾ} .D oXXx{ܚlyi D&% %]ϭLpB- _R"v12N]LHLA -+cFttAiq]A{Nvv]ST2}vBf=lT2 p>vD6 :-n>\r쫱wvM\|W^sztn@.8y2o}o&H Ώѥl{iV$mQ(D@Lk[UMI63s"O?_ [RA[>-.SxZ^tjڇs0UшY4lt9BP'B wǒ^ž:nB'Y `vnr]A;Nvz]98S>)6 \I8glg&+;\ TƏOUB["V6Y<#R!͉\+ Js~Z71H2n?n`Gjg&r#꺠0fk\/k x$5+5qgu% 7i%|lL>x_g3O<*h_ELsv2b#u*)KJT .yݬAn̞S `3-ahqTm7`ʸA!'`>.A Z"`'esv'b,t~'NzDn,Q:ymmZmlbᢽYjUaup - [B8]r[JMrS^}tFjך rsLFQجԋ-~`@]^PkvǪf xڌ]9}Elc2 U BZHTm,X$D'amnfwٙzڟXam+;|peRҮ^C*STU*?q'N(9R*?o޽;sk \~a 0P$FS 국ʚq:y5Ir൸mLm,CLֆ߅ibKڅ7q.= IDAT7DRT(Ջ ij6sl=HIҫv$$hP%&Ƙ.J͏u+mqEW#Ovz?c=wtb"Fj6Du1Թ59Ghr[+qKjy\.kwk(_{(;Q: b΢̻DdxhMqtn+qG]HJKNLz/ѻ@מȭI8ٙ-0 1$&iԴ /ڰS ' DA-+cF\pnf;],ݸV3'KmT},*Xn5 A>Le*;he[w 6"`sNlT2정&`p>؀ SPX$eN?gĚ؆/ IֽpkҷQ=LM)Ύ7T*Q.NMg6kJ WH"=Lo4%iE瀅i=VʖVyLVvn̜%ar䵆ٙF@+s(Tr*C#mȐqc#?n;wɓ' Ƶ;Y"1 j7k>}p\ҧOfElΉ k\I8glg"V$}{ 7ChSlSv>+7PW{)~.VefR-k_S j 7fr%wBbux}trnik}dHT)LT\r$wry?dCĜ~(vo&t15yZb~i&5 JGf2"O+Ro95Qz?i/7%eWkȵwiҕNMw`|!P-Y4]YaN^+B &MN5iU~C jhc6M-\iH5;S=68hĜ٘P/H276u+' I !#ve}=hCOĪVjgSLaP9Ow/'l6D98xf}l@XkÖF4TpOṕzWieoRc27jUEy?nn*뼳 feDxLΕ%R+_( o9Ө=Ɏ> awD-,8(P]bL즆Ap;C-͊ ՆrWbXnRf5lyx[JeZ)WvH+ʖ.%)+ص'O'7&8Գx~*|) 0xēN՟񞐯ᆓP;2G澡%82ّ?⛼6+^ofF JA|).s' I !S"/Z!K*}vuh\A&aKA+nVN/JX9]f(l5 @>8'`#`)6p&.r&}mBv ^+<6Jf,0ʊTCϪ U)״_]U1OoK GUi[Xe Jy/=ЎB5P${$jVM{X- O LΉ˒ǢfT0s?"{~6-Vd%{O H](Zim k9) $chgg?flؓ==[1#,4R|PeӰӊ QE\ܴj C= 5'[z&_|vZVqb0X ^~/i/-A8ݺ&DG6{B |}[>k-OjQ7vsd_8ɾ dݳ5%B:#!X]o%cr,#n ѝ2 -[\ ,}l4%%#>bZi sBń*coL3s~"::Z`+A کVhƖ:i!p)h2` Vέ,#ֽfhBu7o` ar6}˭$7)Ad+w$DwA;&lyi Ν_|޻O*DFD{nX˟l_W_ ~ĉٳg_{RaÆvzer( j۝dyɖuz4+T T7ص'Ϙ /J/OO//fϾjZTx1%da?ioh0۪mr.\P}6dãƏ:uȐB#֜j{IB-pgbVrny@Z/n%;;s"3LmrnpZV2`B>}:ӷ*`D *e.i틱}pNGkuH,tw]޽BwWRe_o&+;k~j?)En){$+=injC:'7EE?Yi[x\ qߪOi)21|RCC oo#5߹˯:s{_rgаaCbXJV:USS+PapZa/Q.5kap;ƏmUG}栠awH]x^j|T[ާO=ύ~zg~ ZltlŠ3 ק+Vuu9ԦIӖ[S_EY?W^.F 1|5 TK6H>$Z-BpφwH-w6eqI.;}'^OTT_ַݸRWWWxsku׭8y{_ł.ؓ͹fL.xhW>{{xxowJ}4s>}جM BfYVD?q"g{s:A$^pvJm*NaU;>V!JM76>5e\]#/lOVIԖ|jmg-IrUkC:xϽ=3-\1CjBmMP'| J=yxG-J5 X_@Rr՚iUcLSEc۵{|+DtO?TsIiJ|_>55un^bۧNJ2Z/ݻ/!)cڵkmٲ5G 8/_41U3ufOF!(-+xo{h]nN֑;74t0u~CtutxxHpptZWvވl5Ч'_p:8kaܹ `;ih `rl' ,s3 : B6 Ͽ;a O/84'}:C0dmtytY%!+{cBbaJ70pȐұ2H!Y#?ٲ-'Gz 3?"?%P)?|u)ݻdՉnsCdee/]j_C`[vWHSOUqΣO?MY2Y9q>|lB.e/tpκ)'A܅Z50i={q 2x@Gio)|#ROw֣VѶ2y[..):xи ZGg=._(Fcm***?{a~?V̍g+١<NK }Uה9r9 OÊ} جҧOvCl \3l9e8ޔs{uIJgpCM7$<9˃z>q3:l[/ʃ]~ψ-^a,m9}|Ϙdi/HǛ^~;$32=&^T@2*4+RCW8/~Jx :'cՉb'MNs#6 _~N=rb_<詀{M}0bhٳg-tNԍ9sƵ]_|)xe3?E>(جͱT?N.9r+2yE0nl4 (u|3BX*Ni۪m9ۏ?.]ffr J k2މx+WN2E8Fst?Ϟ=˭de-[kjj}|IuD۷9lF3?bN &'<.Y-|b 8Osq_4)U߯R8yrmV_8P;LDΈo-N x'Igum tvҿ?)zLS&`?W_M0lPam9t)N"`sl&`̉3_εas"Pho+L3ӧɖr!e oDj<2miCCT:4` }0 ٻ~tw lsf?&Х:*++8 {3x󞼼N?~Ya=rېАQ?ΝـߪO#'tۿQ)orwvǨ=z(^w,zLѣǤi_y>>>BaqVE@3~e]OS:v]hϟ?t4mٺ5]{%:AhN۷o_a_Uo]~](-{y{{3g3glߵs-+9R;/788hCc6|22!}MIK[aC/s!x5IT,ݺu;m"43 __-SZzNؕ;L?=uN]ER=h-pwTHawumQ{~|qsֿQ2}`Jӷ6k!`k;6SlaYF8glg&해tymtʕ%)Nis}RիWE'T:%>?tM^tH\YY%گwjMfuE̶Xn)b5iZH-sn8fk$fvڵEM ϟ }oY޽TQWtļkmV`1nԩٗa;x?"r{&oc졇yŶ{酿i! ^;\ӡDŲV[)NpV@#v7uӟciX.c4|%*6 AiveDUC(:wɓ'8؃REᮣEV[^XOҧ]¹ جc*\"L9`;M?6૆RJr{mu}c} *\۱Cʏ/~/>/uz쯻vǽ{bB4G=ƺ_ m.3ſ]i|8gQF>v/5/%n Ҝ_>}{_mYg ޽զ :{~N>}ڵC 0^:h aGvXIÚv~WBwc?{ݵ3?":… rCQVƄ$FhIDATß={' 8`ndr\Em_*WmSڳ M`L D;? 8:\\sc23~5ca>ּOUeYX#}g?z]k;Tvn1]^"`yGlmmCȅyl/cg\%Wk'caUY2k9Aƨ6*۵ϖqvVJ~[\prjaarN ŘE|/.wгhګGsª~NY [ 6 ؄-Ιb;+!lizmቄDc71nww_icb?/tcg'$ uVA~/WXMƤ:tl4=Ϻ9/UkSWZu3/o~۲IT,[Rx&Lu1};d׶s2"ϮeO l-k|_t@w?;FJSg9?\?=uN@'wFL=e.-l.gѝnӿ!.GLl`7uz-ppt&?׽-'G.~v;_Cgqf=3K~e6K+-!9E,P}Pfu' K42;[ ]LDPP`%h<}V: /Oto:V|_>%Ǔ{ {o{_^Q[7LYyŮ=y$\XMMM262R˒Eelt^RV,Rc.ڸIT,kǩpUֈ [~kE t-l-܊NЍG'D;Jǒ$?A}9OOۺf'y݆v[lt5%,S^CB>}f)2)?`Y9q]LWRZ)P9R*Xy16uhPᘬr oyC.S dKJ_^._;^aG7g,}[Me;;MXVi}||1agLay[YnE(ɺ0E욿z5;2ݸ-YA9Ytg>}B7C[ 5(6`Y9bNrlm9ۏ?.t7L [7MC*Ka 3gfeo/,V0dwr jjjD׹~'UWkCpP}8EicsLȐ3OKjhh0}7ɓ6:XցVYe.6q'c[o-SN .jpD GNkw~=^-5RahEi&7õCK~acm$*U>+]1#};d |#r9{vNڢ}v_~[|lw"n\, ,\CB>t-'6:MA[kgNYο{~< lG>ٲU.ɽJ tbYXݢ 9ػqvw6!ZX{kkcfgQڶm9r+XQgk9N|Czcn]'Ji&$/,,6@dl:eFT>͖|F(k)$|u\V #;Z`8v%4{F} daK;knvh) 9Y.i{y}Fqӧoѧo }}fY뺻 `#`<6SllBFFv>wgAul͎ ~vʺ_f_nCg?ЮW+<}ryqs62?oO.:EП?cN1G7}!\117ʗKmyuJ'tJ4lo ww V/iWo~,} [o,joGu/Ý {ư4thΐ5 EC[yeTW'.mgL~>/~i{>anC%n~>M ]Oܳ7>x[@j o7?cݳZ}dLyOXqyg5' JtqzȤiOێ޺8ikc­\p^ =3fǎYT8|ъ l|lm2j`~...9ֳ Dƪ:WmLȝR>W;:G#76*E(2-ъ,9l#FSM._ڮ];iv_ŋ#yl̯ sV*KnαcsNŠkjΦ$U@J.kjmi4j[}nA!G^Svu m lf>^66:wW>αkrlPl\۾ ۺm0ﰾ<5:jz4=J5]3+&Meqzt@JvAģr'b|)ԑ}_zjy Sۗ7j<¤l{+sgz6IT uRv2-ϗ'kEGMNqhSR4ʊ:h$5^]]2=EZř&MVkFo=zuAu[U;v̚ULz_7KJ-y{ yl7њF!Ǝ'kxp?,j@|UY|mvLaXg-=dCBƢEk8>e{0..Z ZW߻wYk!Wj2ոur[c'OlM5Q^Em4罃ܤͪ!)Ϥ׭7!rǽ(N EzY|fN^נNN_F[휝F`3 lA`5M4 nC{7Sc/WQ4+ hwj1v^]r#[ % "UZs@ȳi5klku{\ݳHM&ucSXA~k-kXOe^}Noռǭw2V5bsUu5c_ь7/!.ofebݗWT/MQUW5b:9k5= k>Zr2|CY~r5^%g[G՚E&- ~'UI<>GOISI{Hq{g ] ccDuOEpyzB>(YArFksfSlR5'֌imb(/14,_^hh`mmb`]iq֙MQJmꚬ;I4=-5ئE_wӵ{m[i[v8 y/ب8㴇&|udʉWo Mmw ݧM,]Rnf||f1B3NE)Ӆkoqh` N㚝t/[]eJ75lxV{ h/֜C"gWWRǮ9rMt9&bۀhHy^!j'n-ck1jӴ`:~qcǖt\9x!mڗ%yM>JׄWE fdZtt%!p}UY2 ` u/_r뤹OӥMSOͣ4GelE $^3m3駟 oK/ 4/Y;Gmߺe=c8؈˔#ÿ߾bs_4Jvo|lc' kJ5b%`KFɺJ5;꺞Bu_}^񻦒/zVS9X77zykPO>u5P_uʕ+6 )l6F`#j F`ӯ P8f Ds"MQ)!^&35= UE-^%N7~xԅAMt*j+/[µ-ai^Wۑ.z+^Pj ~ewbtJAA擅;kۇ~l~ܣf|;-pRI{|%)_K_iue:# +UwOD~4J5+njw"tWIsWBRiHUzTNbDTk߈k&DS)̈MIkP:tIzBX~*{l]}t$!#xQUh`P=I] wiJO 7#&%>!}{*:i7FP"z,?yG]-yZcGlV>= j.6 0vd'j zи~p RnqAl݊:}zV4|4tWiVzAq5\Fڛox{yͽzeeyUO9#ͣa#f ?oj]v/ʎ?y_~E8ak=ڕ[`u8}wlk53.Y^ h+\&BᢟSWڇUZX=F_IQ<ӚڊQ"'EuSO>uV" K"il6ͮsaznD׳3uװY8nwb٬J;5xݫ7\lTnmnݺa2J!CR-물[qz=alo<%{Dzpaw ܣ}]XIDAT8U>pX)Lwedix8^-~BLmq!3#fDj3X6_1Q_Rwaө:D˧KV&GVKCx\a~0UhF(1Vya Ӕwu//޵eᗸixu TZv5CdORؔZp58Ƹ߶huLTgu9Y޶soN? fv /O?կ%E`Vl،#)SNwᄡŋer׭CnXu48FY 4Ll:+j&\_6 MP9ٚS[gR]E株%2TqVJ%?<:PLF7zGR0[n˫p./]*P{^BT,^u϶g=TfX>C5aKa<춪.?®j KUW9ZZVL|mEy8j9+xeS)iDl)TmӟnI7H2}BSދtE;Y$hݧk3\Ro픯OhHdA8A3šɪ##8-8T}Yő صkSTmڴYFVFM 6ܙs'JNFRv⅋JaGgIT/EUs^EjSQJXHSC& L:ݤeW7ɔmb˄xcQrʕ+| ]r06))lf07؈5[Jֿ. k^u?OG~FWgK8p-'0:}H+JҳMR)1ÂOv^ehɏI~X#NLSOjuV2PofMݖU;f>' l\s:{FZ[f:Yf"0. 笁K.##52V)3w~#Shݽp1X`DZmnР7au@W֌,4̪7ʥWի;H(::hΎbQ"˦;"} T.Pk\ڒx(оDƴѪB3"<:Ϧ~|XU LyŚ%[ʇ,QyT]2|ǃ󂺱n{paRsv_1YѿokT/<SS/sy'd&^jo.?OAwv&(L)|C./9b{?jw'^=(|niz7Ɇ 't~€[Cc!~q5FO~Fgh_\/p'ԴT`Cg\!Vi^2Xò:Sf `au[ÊH7&NQ u_ݙVw  2ߥ OTʪ!C9>~zvPP^\~ 5$9Ec՛" rQūC6 Ă(iwQT?g׿ʕ+Oy>DX͚],C &a<Dž{kWuPE>Pt?&j*^~6<01{>^uD<| ˕%af ɇG8&%.>hp}Gv\c4/S\n*+qn :]׽loA4^׷}ol&Qe3EMO)1[MɡڔULN5"wyuJ/oxЫk*Z}df?><~P}|m^l-f06bz7{v#lj׊'u7E֌ A6|yⳅN:zh_oƕ֌XUAuusƟ(lʖ*Jn'Gm[[UiJ[wSF4 ݸ_5Z(Pzk"4Յ0S\5ot N:}='u&ӷ:F lE,:y`>>gg>Ϸߖ7oؘؐ±8g'JWu+? +7<],\EAk9k\սq XVT=lݱe6!qƕ}+gexcGCV^:q ?CKunj]^ߥKʫJY|[nڌ]GZՍlbjpb&n:zv[SnJNumUc%[+IDATBw{=S<5zuz`z>2fʞ6JΟWu=7xdU*,XWÍ!}Cm#RM3;xŲv!&͔'˶շ?ߺYФݰy4;f06b_^Wu[.t6PAsz[`uWܖwidck:w=w >XwQmݸ0J咽cǎu]؂gk:QVVEߦɦ@o]PPq4zrA>u&N_/M|iݲN_?FSJ;l!YV͆lu5mݷo,BJ^.MIKиfƵCmn->iϽa0w7HʊM>~,js3FJ΍_`[%|3?Ta۵C.ޛޮ/w Wf_SMyAnXYCsړS) ˅ŊRd5{߾%v;SSd)8`*\,xsHfE63ȚmuD]q<^L|3e1y )Ԫz7b_MA|) HGMM v=uJ$ŨX TlS!xT,. v%00Pws`wjbmQwʷTN:}Q|wg231AټNM?MLC`sS6C`sgZ6Ve˖|hq#gPٺ[gWkYR:  y _/V8C x񅹝NhfEKWwPong?#Mk^nԝRWZ\ ]708ZLZ34޺SWo(Jڻu&ʇWa5Ɵ{//|[˥̺˜{FtSpN$dV(*(3G9k<2qE ӕ|a#6|C{ dȔ?5Lql<9ɂ,UQQ~lK|}}gHTKtS%'ΕؖoNyuC!ynp$cL5'Ӎ6wF`3IP``JYgPlO]׳+] ( {駔rFZƄ>;>̉ʾ}rd#K9=!hXN/{[)ê\aɄtwwAg";qSPݣzb&W&= {v*d.6+aN7exgRak_~񹮼~-Ի˗*М:q!C,jD'5LQZV#ONP^کO5vmg>;~Jys&ȍe' KMՐ!3 gDem-}nZ)ڽ[9i3emm%6ę+\[`r;,'Yf:w<,d"\e=O9/kՀ@9%;i׳anP/dېPE^6g@`s]6-gء Z cmp5%o߱c.uo>e%?Vh߾yM?ҿ^*>sF)Sa>?2a|+7< 'asYLV֭Z]7Yx񢧧[$9+̹sW~! ׶i':}Z) UFw;ޣmW12\XJp|]t1Ζͯ*o`9 bw!?Xl_IFΞ=:v(dͯLȀkA/?[7owܸG_r㦛>dX)=6Nm!C'NKyv-Cf_ FL8pYWk\|%6 A0bdMk5 o-Z*;|Ogѭv"aSsU~֭~O lf  -4b`4pRE3a)ֳzyk~le^iF}^mUX:T , l&F,;؏҂Q:7ͮ{)ڝwھu˘{`yBN5H8O@9Z5^G˖-k! ۖ-OɡUӞ޺ ?|\}l[)߿_98؈ԪU+p@V"ZƚJmalMI-'mRΉOK؍EնȰtJd]Qƶu2/HIU&X6 @`#M4z`ӝw6NhحCBIɱ_~k5lܹseeeJY5d0G+,:wf:؈9ձvém=5>0[`Îjv>>}}s JMat*0uNT ΢;u~jqp&6Nߑl~9Tw-z>wJ}5 u uhP[oLqJ7tswP`붧#G*YUlٺu7(vɝ03]iU;o$ }o#'4~7`:4ҥKm`h0a>g@~­Y)=xyy 4pY^0_hTSP ڭcJh#65M$u8 l71)k~ɧݑ~`G 2} 5z[S*LC]peqmŶN~lB`9s`33ѱc{r+8rq pezya!R#7qujjKF8/6o9VmH4d L8Ν?m׋:nEx`wԹ[n"_SxMN,6,0Qw R84gEF̚]s"65DPGr@a Xُ30ۚRa:T5es:}A`[SF`W0ΠhAJR Glv\ >s+ f?V; ߆k؍?2] >bsN˒..f 妯!|7H \fя}-Zuu|Ew2OpO3>˖mGqMcFwG&O, }}QFx#B+W"]9>n8aT:>A4V6/ӡN\Z:}ot:lh"lᲁ0cWl?խ?x;|^{n ^^votr,?2.)#a!m۶ͷɺ(ThvE㦛|nA4p-7ܥs?YgnI΄jX˂wOyzzO2_ۦEi3?)+;1T5D7SC8=ݗnp/ w/rkO?TQQv??|7… ${s?\"oveK1M{' -ۧr,١}{ak5S W^5ey>}E%eBf1 lm3uGpP \6%'#: ͍ay_ nS|y?iX֭[6B؁Uʎt[jeu'>[) ,, ܫ}U'ҧϝwlRX*#kR&'9 >[o).))...(@&U*U ]8>rj^^+xo9L.^k,0n>_ +E**N6l,ӬY~}oQ^t>/ȩ.)\s5mՊƻo\TYYy)Veg*n;(--u 7ɲnowfG3kW+\#`_p+4-sСE:pY E=>}"lJ@YMsJ4VN~ڵ;maϜK7z u]]vYYw<6{ 0 0 vf]ҦMG '~uNj@'0fyTXtRvҼ;<$E [-Za\Ԯro uMa\qapQWCg1[ƹQs³0ǟWGy˗/L5ꎥ|Y;1|Y<=[㫝ϟW#,uY)]X~†ӗʕ+vnONޱcdz`CYRrlK$@m۶Õw 6~{4v%~wEW~I4Vi[`ӹs'p&Zyrܯ G|.]:c5QB}o_:wpeN޽2^_ChzVΑuGu.Bl΀f<\=q.4x g~yw'\q5 3ZV?p)= ݗ: ^{mvnWPȾg\@HYW>7zN$ؿ_߃.s:s nV|n?,w֔ MCfd”ӾJˎ4.o.^[:nٲekz Dc}.\ƅ~gO<&s督o2o pz{vmhJݫl3֢!:FL(ۍ ?M| ~:w$וᔬd;ݥ04Y[,qҥK79y[{dzSz:㏗.cTw\zjYN`76cz`3|%'NxfgPh_rN2 ,HIU 3mQ)rm0=3tݑ' ux>uh7K|w}Ow3.![o{-7jJ.vJZԩ ^/cxk*=nRߟ8.O yUiu;ܩSĉMz~s9o_?|仢n̻ Кͫ'SG93۬_-C|XEMNպ -,s`_/\XK.#=h}Xçu+o~:>*:t讈H!m~={ub#HK*J>pX٥so+;ٳgo۔G0:} 26 t9?nYtmv5_ 7oպUU91=֒%7?FrLLJaEa1//A]  @mS ^):t6WM$ }o#'aÇ ftx@mrr)%`xI1۫*k_;?k~(uj}mk+󄥬YFVn_^6|,TVV>2YUg p*{{d᷏/JMJ|ܘ5&Ϣ  S /Q߽~8﫝́3fe<̬'O 22;5~T\BR`G ȕ)j  p5 &sСrɥ,^N9*{RxVwջ7g*̬,H9J`% ywvBEEE#_|//^Wv…_x1p͎;lp)W[!qk5ʹW^iӺ!k?IDAT9wG<;+/..Qn0*:}ɏ*|kٲwyӄzz>=ԫʕ+˖/kiÓϞe(lP VlNf&&(j.؟S5\(ロW~zƍz;yhp_QS&,/bL45G1@i0*'ɯ˗,Z=:2rxhhHnA\ڹ=7wMLK֭Hv:w믿6Nj@]wR|k7w7tboKw**N0 7{K:uN7@~w)е{vgm>9ɯEf=p5J!6>EKB<[y7_O>4WzKc%iX0ׂTN # ht\ g3G.(P ]87VVޔSsEkǤgh-NH)ͩ@CDnG|~GӃRjί(4O.c|7)((09 ^I\rEޱcdz`CYRrlK$.m۶}R"'܈WfܹR8}PO[h;(Ɉ;G%piХKg&%K^2x rrcfM Q|%d/jkyjtZ/W/+ں!7X\\r퍌.믟|jZaQ 4LLuddR&'Elj茙VĉFx!.'nG&]䧩rϗD1=*:z~FU ܛUsd̈́jtQQC*GbsM\.0?TO~х?ggRݚFҖYGׁ矅s[sqEmr5+hmߑ''Yfܩ>uF84$^=tܲeKJmaaLzK¢CJAܚ5yaQшb,﫯~we]V2pTPSiY.f&yD eڢxbᝐ1B\#2k%:U'7 p`gkm FŋswHY:~bQwZ3516 Pp5ef7\8('Y{K9X];26Q&$V-YPg^/NfzI䣉EI#kָh)6%֞Ȍ_:- Cb0J!_$̤s}` _Љұca{H/(ʕVe>cqBֹS`ƺvbW+)'=|}|l{F>mK/)LVXRd~YoALVYCAq٦,wKLҳ}G`4lJ՛={o[֊ V\rlOo6h܈F_ѡC.ӳGvm -}yf͚  hg='HFfpɩR`WnEcJRT)ߢ br77zxx 31f֭[LA`@}\ g`OcY8rȰ +/Q !Sr2sD`⛩F9_=JB@CdUFPU71ibSjtN|Xu.Da+ Wp8_PMkYhou/.]1w!/tt_cBwoGi $fh)%5984rmߠ(GFk^SNqi=⫂Dm]m߾p63krʡ=aw3 e5F~Y Vv~B3TȻ ԪU>7ᇓ_j@Y0 0 3Sj.кU1#"@Mr{A)]t¢ d㢢xs,|{G4kz5t\verԗl`]zW'& O,TVV>gOTũ$ڵӸwG&=;(PٳM4֙[2ᾈP˗CCoճK-[GYh]X}}|tExr<==eaחupSK^Xr`Yo8 $h\616 8_zg~쩳g}߯zp#g?3{l]+-+-+_>ұcst[fMzfa,m۶mݺWoUPD@|OOOAr2qIqd=,46bZb'2.5z9#y/K=2.R7];cu{ݔi]npq&O7u޶۔!Cf$N  Fq5 _Dۧ@Cžt^zo=lզp)~};ru[7٬?=#oΏj5{X=p];ȳ͛g|nG`o{Ho7(\Ǐ+ػﭘKΝrڻw_FVW_}h҃-4g+mh֏23ɓc{ ޲<;E+#ibl@p" y=͸[nŷMԪu+R~ۑGJ+ݓ'kqsӮov/xm#9۷_~ Eyf~={uz#HW(9TrxOra9?l߽zVسgf&&4:lB`WxoRw6?k~`?W֭x>',馀'I4ceeeG"WddR  ؍M^ZO|zb„-%aw2=%{Iyq޶euuڳ496{ tW3a2WW&_>2{NR60s_KC|4`泳+)9&,u9aҲyrR Xiyrֈ q |}|BC$ !&)=d=ݻOX9IZkr5y9ߕ%s_|QX4A6"(\[w_e{/Slo>%`x SJϚ߶C[^_^׶Vna7):wᾢD]ZظL{{duBC QW׵mY[fRmѲpS<Tʟ|0߳ݱb4/kAJ2 ;a6"***nx]P 4pnJ呔[=<=HΩ;EKVn&mD,V]$zuϦy`4L ޵).\ /~! c%K kn" J_H?#KOz6&ϥZ5Cruxd)6WS]/{%ϟ&ržt0j@Z̄$\GF*ep/_^hj茙VĉFrI?хD`_qi1B&WOiL _ZOnf=(vQ 4KdYKWg վǓot'>;s7Ү\"`SWÈ9VZ}GdABaQшb,﫯>Pu=[ySedrDuݨdךA44yL~j$iUWsQ#-gXoZ.]U780гwswHY:~bQw fk`  k.T#\Mi nr%?Y~WY.)9rhtٔi$=CVYM>X49_|6xaŹ ɡ}~=R*9 3mW{8}W=+-SNz|yu;P~ް^f>\aF9ˆ۶ Ȭ۬. uƚ^&X 5ClZR8?{\YI@dr~evղ#N<w hU >=9&%;i?sN"fReX, ZiNJ₺Y=PLbͽ 9"fFQd&GۮՉCx=ݮ],\UYrU l6*j@L< 7ps^Yۿ'LWvcZ/+1fĈr'4Fk1|j۶~z4y QW5' ᡦ ]IYTqmIýT9HDLVRo2 z,#fڷM,O2`(k.6p9<%{Dzpaw SbpMI"h_?PEByvJGJ}ٛLi'm+ Wp8_А` @|5+p1 ؟ms6m2YN&._XT4d: 3@yzPTԵ3 QP\.Bu#畈h!rgQ2ZSuWɊHPTPvͽz lh\\ TZb'I^}* &ĤeGV\UAHa nDc#$IDATZAi2pN 6ԸYuϝ9w ~7; HW)OK<-rg Ek;X>?V_)xR&lh\\ T+-+)bJԚ&ʈ(![WPxUnwBv~P*@ "(scUJ=4OP> qma o KS`!{)\w{ۛW-l_;uk֌-,C`pǜt^N!Kn߾+7< '.<<<&͙,! h\\a{?[7owܸG_rM7}FF` .GL4gjȐ9-,*n>}%:ꎑ׌ {#Z mʫ|m^==Y:tG2*v"0*f "DD_ʈM0^yiK #]u?큹Isz!\| /}EK~1-&j1 WJ)Nt?+#pJJdǧoq$lhR-kIGNpbW~ɧݑ' !\ . 7.#p\Ћ -HIU 3\Wnӵ,'F|y#4->>6ֲ L/`g'G`W2V)؉nr.'{[mۻw߱'N73`@ãph<}}н\+`:+hR S 9z>7njÇ]kFo=zuAA6{#0 Bbn\㫝;.[׿;$k ]]p%o_zU~HN7lxS/0SfШ~fϹ7nK]|1j/]tI_ƾfo][qʕ7޼58tϞxxxTVV K]p{ f&=;)p`O F KWzʅ+:Y֭mݺ\&# ׯ_?aU٫mQ~~~=n!p2d[m/BGܶ}LJ&f l@j@h4=2Eזz`YE# 9;b#c-V gG1*XiYiY,t0 Q+pYBvcv~bJUV3RgNy9d$\pQOt2dY϶g/hrlF`aW3a2WW&_Z6nڤcco]mk4 2es +ȓrM`J˶ȓ,F|5EW6,'Y`y6I&y}LOr񢺍unWZ-눞;dYG{\4A6G">\[w_e{/Slo>%`x S.]W^UʽN\(3npR~%9ʕ+?֬l. 8?=8m|ܘٓgQˉ O'#3ɓdѣJ{?_4=|iKJC+WrFffs6Հ#xΩC%`xl۾]f?~\<[y˜׬Y:@Տ^mѲ,j~yKi p<e{@-6{ L.`4\k"d]#S&_3mQhߐac¾ Y##>d}LbNHi0*`,WײmYY|KVTT߿_)?CI4c'N>Yat1̵ %U)q{6΃4:[a|\xJ_׹*GRnh攴AG&J/ߔTW<_]= y[}whȅ ŰO9#`#? vZdav6XW;µ `xaQNՅU`k._#*P6A\T7yZ_Stzq?vףG=Fί+J t\ T0^ZLC)\|yaʢA3fZ'N]ɓJHO'WNN"0qme~6FUꄨi.*W%&WEhm~awdr~Gؘ<$-&'~;@HK1|uщGuzb0hJKKWA[SHr2_`k Wi9VZ}GdABaQшb,﫯.˺F ɵDUPGUѴQ\P.R?"2?9;0_{ɩD1=*9&+vS\*Z%W=įO 25k{ ;R;r]r*3CXV35tkvA9B[~`C,[R9 ckt@CwG&@'O++ϑu&d# Iʋ rcU"-|u<=R}Gam~ʨq C|5 ceI_۞OC vsA IDATƋh_oX/g}ܰqdaDXmzT 9V˿oqRoKJfzI8.u3ӄi ȿąӣ7Fםi o ww~u?'ȩνzW+_h !5j@L< tymDcms[ $trXi ]{IuLy0(g*1΄ڀ_n`OSc}Q/b=@|mp1\ڴio>sFE-hpr!Kjy ÊR:E4V P%#k2 w!+¡CJL/[4-Tݾ9-(%*Vobyjt|_8o:m_Ź sDXçTU~_n+yyugfYrV&h 0292YBzuS8qF|߽ 81+]yyy 4pY~/^}ʜG&W'[ HЫw­CvP3 54q]d쩳I1I)z :,|Qw81+%+潷]|QLLP&@`# ht\ kYR  (,Nrl<9ɂi_ZL(y|†ʤؤC{&hN᷏/JD`s0j@LLzyO)匴 }&?(ݾ}f#K9=!JrwI˵ !ƈl'4$XN l2 Scw/m׮,:q!C,­vᷴYi>wٱcw- k4L}( ;o/lm;vڵ[~{vmG 0|l+س}u[u3C__3QА`ÿ/D| WSS ¦{z7x㲷=(W._Y1ENFNذ qwW.*U۷_~,/_vnul#0~:oX>s_n++#}[;unJNݱmo@`@؀@ ㅫZb':ڴir#pQJJdǧ@)N&jLiࠜd-}$'F|w͞|yՀr {j@8Ν?mHA8=+5{ ܂T031A5q5 i<]!pbW189j@@ic- 0M̄zpr6qq5 P-#kR&'9 6~ƍy?pJڵۻGn=:wPp>}}н\+`=+pK)=gxm{;VZz ᬼI lp5 PL .W O?i /oӞ~zzz aZAF|׏?1 WPΝK-^yn8o548d[tu\r却7o ݳg@@|ߟ=;#\eyϾQs_|ҥKt06 XãRՏLyTwnv@hױpJ?%E%l޺nTZmw/`2kMWwo߾~ p]Mo'=;)p`O ᬊ KWzʅ+ez7oݰnm֭Лf&&46A`,löw'r6fθӓ*?ޗ$;%1⅋r!XɂOw_$_W<2V)؉&y,#St-ez5 ]ӈ#<2fn܂mrί~d3?VUKr`f+0^++</yxʔ ;wrJhK]G$%`x S-{G+e@zҊ`l2| #Z+w͞<2<$XN py:Y'OVt__yU);qQpY3Rg1Je˄վؼ%4_A|2AΩӧheeM>~,x9Y3nf#W?zE|hq#sIO>{f1p $ಚ Gõ&BU<2XSIDATkկ_?a+凞}HI3&,]pĉnAXj}LbNHi0*`U/+{ض},xmºmQpƄ}BFGF +<;;.F2*v"nV l@cl@G_.^(,Npmk~#KoJRy6՝]-竧XUtjvNPzyY~WyؒIX*pP,Rx4;_s;rZb`N)ޜ]$k&MJgȱ"'{My\wCސCzL=h3NB۶m?p?D C|".XirǶglȓА`W<Mk؉2~ 7IFmݶMﰾFy5nG1iڼ2ӈ9N.RG^>?Tk2}]nFhhCuBEEŵ; ]uwGD|EW/m@B`S3Zϥ;LQ /y督o2{-h´̈#%[(%Cը!wvJI`Hu\ercs_8o#g+Oa ;F 4] 8=9&%;i?sN̉\dњRT 3EDj{5z^8%"flWVYk. zU\ 8)$p57ꕕ^P+W>}挰KMX*42T.0qmaA$h]EL(\=?aFBkNєjb_8Iϔk 8C@|Ջ =䣓̒\ag Ƈ!bc~r<=(*jf1C=?t"sjGQ=naa1c&Nhݺ)Ljml@`p{\ 7p9@owg‘Ge7nlHyBu(YK6'iS+-ӣRR" 㼅8R)QjX˂yL/`]mڴytd9 ?¡=np0_ΊH{] P%#k2 w!+¡C|kKRӋA*Un7/)QwLX&,T{)lXKzd,ڭ&[w_AWdʵrZAS_@!&)=9z*P1BdWMI*]gӺ#rk/?S5 G`#q16 PLaU ~ғJY5dpn0 nlРJG"+&yP1??7#N͌Ŕ~2AQ))QBTRI5n5 ًf'1q# j@p.^^^bY~/^}J;!;?:sԵz|Sm*[֍  n쾨{?X,lXE-42?uqz|STũ+7*W>fd{.v~(??#vpWw;(HΞ:TYY)\իWgOٟd9GCf&&(L@`l@j@p:6|,ȺؤC{ TTP4'fR22qE 'pl<9ɂՈZLTkYR宅 z=mJ<<<ElvB`pm1+{i]]vpĩT- ۅf=zsfǎYT8Ҳyrr \OhHdA9$e'g[#žy)1τKٗOYRnNOsHpl0Ksu5p)6ѷO`텣x^,_|e99ac6x] TqBVTr~)˺˗ݭ[7 ke!4$ 9_Mpc5{JAؔsi)$lp{\ Ts`J5$ }o#'81+`kȓА`CyNWnvymD_EyN* G|7Hwڌ #Ѽ \W_PMkYib&?3#jYBD79yYx|MqIIqqpA~ݻTo~p}}н\+`+p{)p=k?ݑwO9#\MΝo;$$8*v" j@ZiYp/4OqQǏr3_--_0eԨ;-/// _+pcᄋb/;wNSOi}YY/^}I @`@SLa;ᄃw˭閛Zn%\o~;rHw{rd-ΒsΟ?ѭm) !}OXС"=i7/IDAT"O9ٯO;{^]oc%J?O8,? 5WϞ {&V Bl@j@9իWu[|Ϛ/تժu>>r#b"{dI9%Kn)ɩVЭm S+-+-+_>)!6i+pYBvc׺?x0gK᲼{i؝âFLO^-g:}zmruq9Ml0]3LLzgInj6_>2{NR60s_KC|4`泳+)9&,u9]قԥee;\XDZҲ;$ _MTICMR&{z޻wsst f--kl9s+7KhlvE`Q\ >ʤ^D>}K.e5.X",W_U ׶v~ }ryR5׳͛SV_mU+w͞<2<$XN py:Y'O9wed(w3j8-+9#3S@`  j@L< ԡC{KY0 Sm.w̙U٫ųE]g9S)gfe#t_lޒF@B|2AΩӧhee0߲e\zU͛&^W\Y|0\K|%91LLP&Հ#xNU<2fڸqRѡs1+jJԵ-̴wG&O1Z'4<$X9a!  E|p]۶oak(-[7SAɧ =;;.F2*#F`8-l"//Ja`@ ƪTIU7SU*eJT-˕%6%ʅcsEqzzNtz)Uw)nO[Z,SˍXPMq…_x1g؟O|pao-Y2d]vdHVBYn&Um%8ZT6Ʌ VUܫ,fMCQR:q&(ĥ/ 3`LY~Ќ0<$XWkSO>:,9m5&e]Sq1iJGQӫfo.iRoKJ9U9[nA31f֭[aP(j@)&.)٫?# k^`_m)gݦPӛ_/̔MKٛ-yGDYJa#'TZ5z|#fxznӦͣS& UGba#A2˂z3Bi(]#rY^mG1?9Rƪ3&'[GQgN*>?h^,2@!2Ӧ6qIIi T$rS[RBF,\bjҔ%Cq,䆒+> ^s/<99;~gO` P.9e҄W&`:wws,&i2O)Yy`즲N'C}Z Kں?+2pg^|HqOgTݮpE4wKWdqVel 'y5IiԸYuKN-8*"ς)Y0M SB.':TDd|Jx.ZŪI^r6EVYo/K/)5qV j- L P ܙ(MuQM, e+'ƪ*FX};(³! 5Fm馤Mtq*g z0ncÔVVX/_RngX0y}_؊km?Xޮ][H ,dqV  z& ƐW&`NpOگ__'6X],&,3EfV6Ԫ`< \c`I[ Y}/|O%'K)C:p~}[;Vw-+-@)tT\AY`ucaʜ=&%=^5=ϴ5krew>yYB}Bϯ_=iO{2ȸe++;o[ӈIDATk҄'S" c6 z7̤m[gD77&lY3_!`6WS!9{j5[7o~p̘Ç^6a+z~ƛrLdzLc6 Κ~Ɔɟe{VFÌ@#VkvqY=wVN~ƽ0#̍;Ļ cÄINYCQ#G _X#BZnnntu̗eH6fq2| fod޲ _ٓ̒/< G`̍ـ@CzU+9{l"c`lsy`'(hl@!phHY1~`W0X8a6 kXB &`~g G` )"b\*87n~C~-*߅EjӦMWWݻcԨ||pw?+Iz),<|m{=RXxQa\]]E>0P7*¶0<\xޒ]&,޹srd[aomlGGGa=~Wذ?3>tHX"o_l4P4AT;vYX*^Nw޽G_`._Ywl-#˫_G~?S"ziW^&:u-r]mڵܙs*+_nڛ\=v(AQ/Y]2E !KB'edUcǎrn' V/8x'wr1{@`#ܘ 4w2=[613"}s^[a757 VEVቑe\#7ŤvYVEyJ/?4Py!WYoQ˜B^՞=zԀJ|ls2yNNNkפ.~_o=Sxzݰ *|Z#ӢFiEZ2T5﫩xQ4/ou?*SeN;|yg#c\T4"f 7ُzLINڵk'+V^ZWb@/^]-J%"G NL6*1r;D7:o>nׯ!3tcF|j@|6sON|"yUl\SSYs8UyEF*[(_*^,zq ޘbnh?F 7e˖gxЃf6l@0`0޲DL/~Ԑ%E_yZXeQת%(mC)Eb¢<9I4*w77kY_o`QXag䤉:ֽoǏMԏrb}2j){̦Xը<ݰu*E.]~ G`1Z)"ȨXΝ;+])gƖSvťhlnմF!LȢγew`pϗA[4&.?YP+f ja[b1D).زUKcΈuJ΋RUA%84RfӴk ҄w̺Hײ>EI>dǍeRhqX^\XԪe?WU_`o~< vE !S4%TE뮏L"7*VkSvǂ(>e<RU|0npA#1,cK}[\iv\MGeִ527;5ua܇Jqǐ!]BdIDATB| {(OWņ&( vX(hG;)o:SkK6 [|ス||dqęRa]6ssgF[`D+M l@c6 XGd!UF}PX]yg)w\5a3d@_HNY4sܴiE zw;F/VkAԂ]v)?':88:! b6 `dž)ڭ O^._ڦMY8zqg-|鲰\#qFՄ%r],[*,CZ%,n\A: "nn~B1$ a/R''&=@aUf_;) " Fi&X3w}b}zVuv k׮_^ӒGsP\; t1y"络u/}K.(see"+`Ô9{J!LJǯ{`jz4Y͛sgxx w>xad_X]vN-˭~o7`66P7B\m,hp~`G?~X_8E6aUZnwh 9{j5_mX/_,~d|,̉V6D X9f k{u9߰AX1ګ={ +7@ 4$k_,5o?yꔰ6:v>#ƚ%?kc؀FD,m={$'gо{>?yr涭+?R_`^|}'!_Xa|7{ed9@#n@B0amSV+E80܀e_0_ )TղpwspwIeH6^†\xp W;sNޛYNzzƆ/׵lRIw617F  `۷o_aթknΐ;z.OowW o;TW[*ϿvO1 #1*`rcM؀Fl@&M*˗JKKbn,RuE^>^ ='9{׶]r~xb_V}vo#BZnnn_ d9XJ1.LlLr?|Μg&?-ZLM [Ԧ]e{/.It\pw~M>t+ WU@%6# f ݰLm:+S.e炅Ӆa6n_c ǹ6ib_ɟj~SsY6i;~yK;5 hxTKtN<9aⓥ0K!O'L&~|.:~'eѣrKLrFffX0/G`3 `9l@݀`B{"᯾K.k.W!6M*Ed Er]QBh-?I>UWn8TtG.۱bФMsW9g&/^|eΫw[:*ΜZ~'&6 l@B0 둜ZicJqʕL>c_=zJϯ_}*0Fo.ΞeԪJc֕f'W*D܊5]6 MYS,u:7+2UFſ=U7R{CB^Zˏ%+?Uۡ0u1ӦTݑNիW:t+[G YBlԠA"7/oXxveEeP.YXK);ʹ0@֭?[⅗C|%HZf+6?~x-x= eo 7&a[mi/ޢv^}ž=]B3:IE]S5F?9EFDT SEE1#+>BUyM,qU>ó 8pPȶ6=z#__PUuc 943|7{'?!^ i`f`j-~|=}u8mou32.4Nh4G-\YfuCIA y5*J]"1R-cUb6E;:7'W)tOyA*`_&`~=NNNON(>˖3UEԝkdnvЎ8Q"M6^;M1⣦Z3Sڗ/7U6AI>! ;u? $P[-B`n@Brj [!+MtY):(yILw 1ϼCxៜ\iES\&$/lKP<|eō[1W2h ,4sj\Ϭ. gCON iBkx} "][r,޼iq|][A"Ղ3c6 PPV OdP:ޱsT*M 1uBVɻEI>*^Ū(ClƦXA҄(5.eشƊծѩE>=3pj0vAe?Wn_EW;(EQ~E]RJ X9mfv/@b ⻩Brd ٮ$XͰMek1޺Ǖ&z+X"<1R6%+j``IlJ @cx(OWņ&xa_ؐ]vN-˭~o7aI 2_MZ+`Ô9{J!LJǯ{`jz4^uuK""+W?qZrZAwqk'a+97kow9;Y/_~.]@ 4]FhY6a6_mXǿeQ^ЗM؁W|I_̈́ 40eֿ52^pA.,NMغ֭[rÃ@́LhzLc6 =GW!O@Z%, M7o.\0p y)eG?p^Hyt[[l!le/?؝8E9{SO?sGrݻLjzL @61Mey!O>phn,E/&aO\<\dzɡSSʕ'NH-[n]G8ltѧHP':h ,Grj&`6&9{ \?Ӎ,e^ʼ I-Z-}J+Ņr{Kzk&?[vap9v֐lQ SZ[Ux sgtn/ϊ-(8o=c {K]c YCY/ꫵURR"϶RiFP̒MXőBuzfl6Z_l` y5IidgZ:YJ= pmdy$|i3^.CB`ـupwSZ[b}zV\ƭ_1aCϒ~n!FTOW<|8_/W?W_͢+`7gO^E 5AiVg6@"ـ`M6:T , &NˮU~'@lfdž)MXJhl޷ݦW\Yhj3|ѣGJ±gK^Zi٥ٛ)-Ţu7K-T.ѩ9=Tib; q5ىGYS##Se1/%m7詚!G}Sxގ-o)EaaacM#īWu[Wn)Tgf& Q TܼaAdž?*Y:n?~ΧSifvHP"*%FҤ*6fku12-'*u"߭2 ˕c4Xe99mE%?FjC^^}\k]֕223%>^yb~:k&pw֦P5۷ls{oj֡CkR bA%/ƞ4,QY{[͑̚S㣔my[^8EڒEёU(RҘH42@.?91x7Z\} ܬyz~ Rԭu֟\!VF|בBrʹWla325kׂ1Nsڰ^fݯFYܰqlu۶=eҎɮDxue^Te[~VR'gg' 8M_bSl*Ϙqe"]U^}>Q^{)EʿW&;u}+>K UB`Yn@!?VrlZ3Q{sψ[~ݚ\+Qޙ& iT*C12.4ҽ so3 <'zsQbwAȤg}yU\iZ׿%&-wPȶ6=DuUo\#sS+Lk㪎 > ]čbUTJ;UD]y_ΜԚu;upkVS-*!# 5?>AiVـ@C0z7lm={$'gŕ?r(y ;هc<5uZoa^ݴ#Gy.ZggyE&hn,T梄PFuWQ?/Yzy&<9s֕~ҳGQ,Ezf@͈W; 5<ϭGpMY0%Do^4$>/8bHeYQоs&g`xЃF`@0Lo 3ҾTF }u<Ū/ OsX_'@Lyɠ;BskDIV}Ye;k\{-S?T>uL{^~})& eW`9dž)ML{41m%mR>:)X歚7cknb(HÅ'jo ^82w]wA|XoY';"vOFcǧ/uE}%vE[lq+sW,!&)M<]kFuhF~R}5/xxK~~>_*a|wg_DI9?i*Q7y9eO lh\rj- L(QPpDhXy0cUT/6 N,%4ŗחy`AOu 5"HS]#s9DE9oL/Nq׾]1Rr8ydcpڨ^n ޘ7RKwY4Ft(YH|@ 4@)4\yuPO6jx.ZW*=^R9ܰ^*JQjHB3bkH׼zdܺEy!SBTKbMN}52JO̞&n̒pyv Q9w  1Θw],+=8I_>2.4:l8v?4,7;R1VFv'ox%e ք `F?@ӦM^zp~=C\#N T5C ܥRu7$a.ק*Ǭ[g7;$ni@c A`s߹suttv.c@%s߾_{+:;zk֬Yʕwyq}o ??~=v=?س;}[Ο;rV~M4ck 2_MΒ+`Ô9{J!LJǯ{`jz4^ Ͽd]r ,NzЁڹu.lYiYOlE` 4^FkY6a:[7o~p̘Ç^6aǺz~k@`Z&a8ggSo/ccg|y@=MrPEn^۶ly{Q/ UmVHo 0nJ6&vL^'{ύ{kÅ0 ` J_"!4&ڵk`?vݻ #Wgsޏv RW|_.&YY`*6tx7 P!|l6)"b}yH]v5e`lBuZ- w77w7@Q#G X$ Tf#k0}&>M 6oΞA)D X'f @CJҍ #1 _;Z0L0<X8и THNYl5W-_o[̬?SءkW>|CBܩh@nմz_>ˡL7vwر# ?@؇nݼ<=ٯVRR"̉'e۳gorJo1 HfIDAT 3Wį܋/}9|8_[[0~Ĉ=`al64zpppP׮Wqq萇^k3aLhoǏիegI_ `{>tŠ!Csdy$ T٪UtlɩR8q]7xS}{fh Zq̈ HC*Vp 2HW:xteWl?e~l6 cÔ&Grj 4G+ŕ+W/2u5qQe}qqR8pٯgmsWx-Ǖ& h]vnȸť[-=F)C_,'n527;TXFjY/(Xzc^ChRvhnAƘhWm4cruL y!Qi?NJc֠֬۩cDž^:E, Xf1p~ֳgJrҮ]?YbԓNʟW 9ktj0iI'1А%m=Ҡyj;@=>~ k7Wj_lŋ?'WȖQ q^ oJ ;f]b궹FkʺҰqƶlR@7lzL6Ԏـ`z-~+s*|a">Y)&[|͖ZM8#nd;"^ؕ_$u*ޡ^UV^rѩXըé^Xy"g)_;ZWˎr 0?Ӟg''''M '\eCEy82.1<-jfgnΏH}x}B):TyɌI>!qh!Jlelh$Mr)&l 4 йSg(9Ur0< ,VX0Mw~BvK,VE")V/C%Fz^g= =Կ/].]pw оtE7nU \A`爯5X|C^MR95y݃ FO i KxNB5aՀC'.ɷZEI>*MզQ 㪾:#vTZ[著S .Ż j- L(QPpDhXy0kt:.'i3o R D„]]ߍY_v_( !Ml퇑q٥cT.ko?Ǖr>E'JQU4[ F*Co], #W,$n *{stkhbCY\.5UT2m NU<˳TcF 전Аnxe\}9u>S委'j%0W!t]4hh 6lـpƄbY_9aMvWiFU"oEDVSHȎCnثT:v'ox%e ք `F?@ӦM^zp~=Cn 7So&9״WM74j}1 9:::bw;\ܒ9Ko/ y~ ք `휝'M|B<ʙgN;ONئM@Ú4F` l@c6 4wwSczߖnJ$ ORzy0#,d!P3jIDATk8ˑZi`9|,Μ83#t㧅;۩cg*C;w4W ll@څ SZ[bOگ__'X],k^SUO"̬P̒M7ne @e%09w77?_d!j̩s/{_w~3WO ;õc{ݵm۵k+n@`k,6( ]5D޽mE5k,yʀ;<}Zm뷅 п_}{;Ӟdٝ{-ϝWV{9+?&M5\AY`&gaʜ=&%=^5=n ~{.9YڄR wamZغK~AWtDux]x6"Fiwm,0OO7?8fr?Y/co?kp F|mW0gP-0on[s)M1ٱf6LXJ1<]ΚlxW6HPܨ#e, *`5վdE{& F|`7gO6#3K~, 07f Vٲ# TX8cn!gfƌ _`^`lVـc- &|lq, h\*$Vq6rY3_5Sl5me g3y|C5%s+vs͒ j- O @ca6 K&Mի Ewu 6 +$ Ҷm[8~nϼ3?#`[5m-..VoY`W3!X7|iY;vťn٥P9jTTT;thE`3!؀Fl@777駟JnnRxx #)Tղpwspw(_HNY̦>繫2O?\<뺓u6B`=[X}5UVϟߺm[qqq.]LVg},WP̒+l309}P)Cjsy޽{eYroUʿ"G6B`=J O1>{+:;߸iӦ{ R{yI+`Ƭa曳'=^w}7Y{So9@`06l@! ׶lz:9RN銕>?[JG)p=E!uƜ=@ۻv믿|ݤIrʄO^|Y֞>fIlZch6٪aRO~}:yW;m[ MuPT3oVi?ZF//_ /Uhxx|5 @eC|hxo رcg:Z>ZIã6[/^i[)lk㷙wMxy߾}J=jd] 7?>Ai6`l3!ـP_-ZHZi6md]\\0W_ۥKi.*"E3fqws٥J).^ʜW=~\lݺu#6+@c_T%/P4? O(OPȃ0@`mLM &Mrjg}_ޖt~z/r㲾rESSGY\yV0˹;g ?}[ ,0-J cM߰qSaan˗zxx |;R.Te&6E;v%ܼaA5*Ϙca1m/gWIEnjn#OUt *޼rsljHA[iO+YQdު=+/Ⓩ@%6̭`~zPٳjDYy=#ҷnyў4;tKQfkdwi%A˴K/Q9NѼdYMBnh7i>b٘f^a5}5Qv)lyrzǰ^97S~ҧ_޼ 9 Ŝ8c fRA|%A'BTdZvprrZ&vh^I,zlQ5+g˚RLcbfcU>(O,y;|SG[S}9e}ctq׬NZTB`# 7?>AiVw k㶞=SvɊWlڶr'vPUꞻCPJʆJ4sN,_y.9*՜'vW׭,*5B 7אB?__vsON|"yUl^J1ʂkR[l$>]qӌj 3O6=3aǍmٲ!u˦D lf _ߚ;/nKNF qH.KVM9;vWfc- eW`9dž iϳӓ&&VDt\hn& uKzSe]1+?{FG`3!ꠉP.9e҄W&`N lvys(wh>xsӶ\R9^.qZ0q/ma~H}yh_"*sec ɫIJ0'K=OqB3eL*vP~S)B8@lA`@]n@BZ-l SDy0j({6a|=rli6&El>*ٗ5 Sʏwͳ {"F,oq;-(kA^Z=^|eh#D4G6҂_xaIג?(SvTB_XFt MFڑeiPyaSG e%hLc_[5+{kuRG*75뱅vIDATiGd~˿S>=aߧˆ]1l߳=pA!"i67fEw&vCR#v*]4w }Y5$Z}/\s667fM`61`_ jYy )"b\p, h\[X}׹ ܨP̒+M'T P84.fMl%›D޽mAiiR8+`V>a曳'=^FG`̍ـ@CzUkY6Q?KT6Բeoxc G`gV T9{joJA]tpիW6B`Mr׀4h` U͛7X1@ 4:f` T&Mrjg}_\cGue.̚)uP]VMӡ_~ڵE Gw9@CͭkWGG`b*X0e7nޙKҥE*.m۶FIW@|0ߜ=y،,Y2;?~gcBTG<=?v{ TS\FMKNY4u9XgϞzXMy}ZT=8=t>Mر2ш[nq:ԭݺ ؐ,c۱cG-z) <=yŀ.]ڑ#['NéݼCgu<2&Y3&pE,+W|l6L` 8BZ-l&զM #wݻE }Jj&ou6m:_>ܹsFe۳w_'>XB,Dz-e=JQi&n^YYYCֵj`;4o\`~;mX&MnY(+ l3` i֬e;XV9R9Φضsmo}Z؄w Q#ϟoժH _ԼyVZjֵǭV~s lFIIIC<ԱC>yԡC>9Hs+'onw[Ϟvosvnӿ_߼==<lBWWױ<|C.VNFL`.y ġʫt.+cZ9SgϘȀM/ՕxWPN.YL6W`-JxGw 7̬,YVyqs"vWfd8/]]heхU鿧: `j l.ǠSpر#C;zϿhݺ@{,:*IOb{F Xo7oIx'Q؜J1.Ly{>&Aɧ´l4"f-|lN6whݺu{ .>su)--=w\NfWj,<@# }dĤ|`I5K%׾P\5BhCY;p%GG^1g5l!`9MizܮRlJreؙG>[uyY7kljYVU1 4߮][Y;v,x+s^ +SrQ`RzSf9{*Jl<,VNgfmn맟-kz `Wl݀@C0 ~3!'O㏥;rr8}[/]GSZcnnqoʚf͚>h+A`lh+l@!4{2vڥKv+\+1n>ښBg:[WoJoӸΝ;.X1ln3S0;T'N[5-[lC~}2ib>ֹsgسw{f00# T&'wC=wdΝ:uzdL ĉM6rtttvvо}Ν۶s\tܹsJ} ޷}fΝ9[vy8Ǎ{|cJqP]VM,[zpSuV::`'}j.]vuzG8peg"L> X6l fPZZZ JrnϞ PNNY-~?-[=ݼ%{gN!D΋;Of2k0FzfVFf,||l~|RL67m رCY]S*..43g4s֮Iy4/9e҄{z7VÇ󕩀Ҡi{ʜ@){{ɓ&>Yӻ4P׮]?a2F[R͏OPb6  j 3пRlNvRtرw/V4mtQޖ>Y&2mJʼn0zwwsS-[mؔv<`͛7p^0 Xa/Rd!Cw? cK)S+S3\rjge9Ƅ<ڷFu5hڄǛnVnܸLe`n^ް%:T0YYgdfmܴIR7`f*<:vpIY}ɓ?:tg`@VtoqqrLsN?.{א].Ǻ/_vڭݼ[t(:әt3Lg:әt3LgkGscǎܨm۵ŋ{/8Ry6 Og:әt3Lg:әt3Lg:B:l2a6ـ@a:wclݻ4AGV:[uܼn={ť0ґBuZ- w77w7Ɠ۽[_?{\ӱCg~͚1vKB}F 8`سgcU5hJΞ=w\Z`!7oުs6ǐ%%%jt>I5x0RZ% ?_f.>EEGڴiSyS\%{ѩUVKW[zT@PZZZ Jmܴ)l\>z{VF.F?kޑC|3t|`=|ス||dq o7oIx'Q hڴJ-=}˳LgϞOL\}モ/PWڷ~m[W~I=D=\rXqRt"PZZZ J`g NEVM7$`CΜߎ?Ѓ*ʤdѷ#`;nػoWZ`6 p[\\zx+ɓjz6E9r;gϝ>}?޹S'ٻ8;?%Pˡ`1C㍇C2QY!AiL1#Z<35gu!IDAT8S/]2ew4}kcYOW5*ӷQ{nm-8{OkX7/^<[T1r-ų}ҙ9~2͢|e^\1)O?;qwr)C=xdWO<n|(XtuCiA]/۲vمOeogS]UU]=MGmiX- =c J1'RЗM6 rmKCcGRYXw O'zd{ !ܱe7nҀ[^ʼ/|s}š֖{Οյ`:[N`4`o2WnÆ  61'N/|4v5O䢂/,*]s |u46/5% _P5re,q`6`xy}pp"]];+*Z<{fdm5aQ)XرΥ8HY(~+ͽ ol:nY–p7KBH44`(mhXS\ol`WsM\0-;?l_Ww0 N&[UX%ޗ\qͭ}>as,U`x]KlUjk)+Lw.y6HFFF쩏}jh ?ы ep!,D<䖲ufG?޾!I<~lp 'LToU6Rtskm9k¡p `ڀ|;J/Z|umSDZgk/6%uݹzs˖//gwxBn֊=oi|=G)(5<8 #o0/ D6i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@:i@)ӀO @|eX|[i}˯WoFXbopշOl{@$FFF.:pm~ ?ykB}eX|> s򥆙weٹ+0[' ܧ0x3Ǚ3g?᫹k yp ťf"՗zo_?{O~\o}/;LlM|o2'Oj]~۟ Rm_ꖲ'z/f${n}ʕG_>0Cjsn!:/墀K <( s._\nZO4DB ΋Ƨo$wclTӽ#V^>ڑk͉捣KJ VrGyU+oOҀo)[K~u'^wîUًL2p%>ѝ;ksz$87j0vd'ZHi\㖵L1eŦ!5}}ShWe=I}=T7oZ,޴/^ ۟o#;QiA+R613#+?CV.s؍fl/ɴ QC/q/?4^~4rko?{F_;R!Ke]߉Bݓj'ZBME۞7u;k&~kG[:Ѫ3㾱f`g(d jv'/ڞdBrS_ªf9W}lU1888>ӏo!ϊ0Г~<n.kqg \<+t&XuL^jl95'(~r|$[Rouk> ݇5=T.ʺп#g'-[jT\ywmhdoӊ䎭c_uWl;w\vOVe̖ o@qƒ#M, Qre{ށPRTy:sdZEHJWeozveڝh޸~eF+6^jƕέ)k$w뜴UO$6}VQӁ}7 S~z5;wuaXLu͙l^rMl.R,qf7V;>grEsaoDC_|v^}m4[y48~MojZqEQh̔wg!/ab 0ۮ]c]R6OM^Q3iL-YLel~#;kmW? u7d2ٔ`@kΚiUޝ Lf{LD(`u\t;Quld> VV!5/_fh(@ G>\xi(ݫfEՖL 屍{SYIx|}ãKv5ttV;?PqCއϫn7^;gvKරwKyh:qf Hؙ-}}0uW& 'LaQEq>M@,45eiPzs&X{we+6l̴FwLfڹ$^[G3xY[ h~2S1/='VyW@Sص2Ym* vL,:Mj\*'7t+6|bf\0WvoO/=ڻ15}֗'ϻ1{cGۑr3'90cvM|v~IDATݻk/qɃ]u^0Kc^xc" 622rсӧNY\ttz}.n^_ׇyН(ڻ@ߦ<LɾGYoo1Y;zsVwjTŸLH5,ڀտ;JKӍ7w*>U6n/ו w%loCl`Q>g{5אtg>@,ڀi/J]wډ/>sk}?z.ngrmEE99j}O1nv߿u`!J+/⵱D~i< E ɪOOO}l'V\`&z_=G|εLRsWK K/~ws, 0j e x<|kg?~0`qZiӧO?~yww'j?W.]MF+mҀuҀuҀuҀuҀuҀuҀuҀuҀuҀuҀuҀuҀuҀuҀuҀuDڀuҀuҀuҀuҀuҀuҀuҀuҀuҀuҀuҀuҀu IDATLjIENDB`././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/directx_x_file_parser.py0000644000000000000000000001326115134002420017207 0ustar00# # directx_x_file_parser.py # # Parses .x files used for DirectX. # Based on format documentation at http://paulbourke.net/dataformats/directx/ # # Copyright 2024, Paul McGuire # import pyparsing as pp LBRACE, RBRACE, LBRACK, RBRACK, SEMI = pp.Suppress.using_each("{}[];") ident = pp.Word(pp.alphas, pp.alphanums + "_").set_name("identifier") integer = pp.Word("123456789", pp.nums).add_parse_action(lambda t: int(t[0])) # scalar_type = pp.one_of( # "WORD DWORD FLOAT DOUBLE CHAR UCHAR BYTE STRING CSTRING UNICODE", as_keyword=True # ).set_name("base_type") scalar_type = pp.MatchFirst( pp.Keyword.using_each( "WORD DWORD FLOAT DOUBLE CHAR UCHAR BYTE STRING CSTRING UNICODE".split() ) ).set_name("scalar_type") type_ref = scalar_type | ident ARRAY = pp.Keyword("array") array_type_ref = pp.Group(ARRAY + type_ref("element_type")) array_dim = LBRACK + (integer | ident) + RBRACK member_defn = pp.Group( ( array_type_ref("type") + ident("name") + array_dim[...]("dims") | type_ref("type") + ident("name") ) + SEMI ) TEMPLATE = pp.Keyword("template") uuid = pp.Regex( r"<[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}>" ).set_parse_action(lambda t: t[0][1:-1]) open_template_indicator = pp.Combine(LBRACK + "..." + RBRACK, adjacent=False) restriction = pp.Group(type_ref("type") + pp.Optional(uuid)("uuid")) template_restrictions = LBRACK + pp.DelimitedList(restriction) + RBRACK directx_template_defn = ( TEMPLATE + ident("name") + LBRACE + pp.Optional(uuid)("uuid") + member_defn[...]("members") + pp.Optional( open_template_indicator.set_parse_action(lambda: True), default=False )("open_template") + pp.Optional(template_restrictions)("restrictions") + RBRACE ).set_name("template_defn") directx_template_defn.add_parse_action( lambda t: t.__setitem__("closed", not (t.open_template or t.restrictions)) ) directx_template_defn.ignore(pp.cpp_style_comment) def make_template_parser(template_defn: pp.ParseResults) -> pp.ParserElement: """ Create a pyparsing parser from a DirectX template definition. (Limited to templates containing scalar types, or arrays of scalars.) """ float_ = pp.common.real type_map = { "WORD": integer, "DWORD": integer, "FLOAT": float_, "DOUBLE": float_, "CHAR": integer, "UCHAR": integer, "BYTE": integer, "STRING": pp.QuotedString('"'), "CSTRING": pp.QuotedString('"'), "UNICODE": pp.QuotedString('"'), } member_parsers = [] for member in template_defn.members: if member.type in type_map: expr = pp.ungroup(type_map[member.type] + SEMI) elif member.dims: expr = type_map[member.type.element_type] for dim in member.dims: expr = pp.Group(pp.DelimitedList(expr, max=dim) + SEMI) member_parsers.append(expr(member.name)) pp.autoname_elements() return ( pp.Keyword(template_defn.name)("type") + ident("name") + LBRACE + pp.Group(pp.And(member_parsers))("fields") + RBRACE ) if __name__ == "__main__": import contextlib with contextlib.suppress(Exception): # create railroad diagram directx_template_defn.create_diagram( "directx_x_file_parser.html", show_results_names=True, show_groups=False ) sample = """ some stuff... template Mesh { <3D82AB44-62DA-11cf-AB39-0020AF71E433> DWORD nVertices; array Vector vertices[nVertices]; DWORD nFaces; array MeshFace faces[nFaces]; [ ... ] // An open template } template PolyArray { <3D82AB44-62DA-11cf-AB39-0020AF71E433> DWORD nPolys; array FLOAT polys[nPolys][3]; } template Vector { <3D82AB5E-62DA-11cf-AB39-0020AF71E434> FLOAT x; FLOAT y; FLOAT z; } // A closed template template FileSystem { <3D82AB5E-62DA-11cf-AB39-0020AF71E435> STRING name; [ Directory <3D82AB5E-62DA-11cf-AB39-0020AF71E436>, File <3D82AB5E-62DA-11cf-AB39-0020AF71E437> ] // A restricted template } more stuff... template mytemp { DWORD myvar; DWORD myvar2; } template container { DWORD count; array mytemp tempArray[count]; } """ for template in directx_template_defn.search_string(sample): # print(template.dump()) print( f"Name: {template.name!r}" f" UUID: {template.uuid}" f" Open: {template.open_template!r}" f" Closed: {template.closed!r}" f" Restricted: {bool(template.restrictions)}" ) # print() vector_template = directx_template_defn.parse_string( """\ template Vector { <3D82AB5E-62DA-11cf-AB39-0020AF71E434> STRING label; FLOAT x; FLOAT y; FLOAT z; } """ ) vector_parser = make_template_parser(vector_template) with contextlib.suppress(Exception): vector_parser.create_diagram( "directx_x_vector_parser.html", show_results_names=True, show_groups=False ) v = vector_parser.parse_string('Vector p1 {"datum_A"; 1.0; 3.0; 5.0;}') print(v.dump()) vector_template = directx_template_defn.parse_string( """\ template Vector { <3D82AB5E-62DA-11cf-AB39-0020AF71E434> STRING label; array FLOAT coords[3]; } """ ) vector_parser = make_template_parser(vector_template) vector_parser.create_diagram( "directx_x_vector_parser.html", show_results_names=True, show_groups=False ) v = vector_parser.parse_string('Vector p1 {"datum_A"; 1.0, 3.0, 5.0;}') print(v.dump()) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/ebnf.py0000644000000000000000000001077515134002420013564 0ustar00# This module tries to implement ISO 14977 standard with pyparsing. # pyparsing version 1.1 or greater is required. from typing import Any # ISO 14977 standardize The Extended Backus-Naur Form(EBNF) syntax. # You can read a final draft version here: # https://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html # # Submitted 2004 by Seo Sanghyeon # Updated to current pyparsing styles 2025 by Paul McGuire # import pyparsing as pp all_names = """ integer meta_identifier terminal_string optional_sequence repeated_sequence grouped_sequence syntactic_primary syntactic_factor syntactic_term single_definition definitions_list syntax_rule syntax """.split() LBRACK, RBRACK, LBRACE, RBRACE, LPAR, RPAR, DASH, STAR, EQ, SEMI = pp.Suppress.using_each( "[]{}()-*=;" ) integer = pp.common.integer() meta_identifier = pp.common.identifier() terminal_string = pp.Regex( r'"[^"]*"' r"|" r"'[^']*'" ).add_parse_action(pp.remove_quotes) definitions_list = pp.Forward() optional_sequence = LBRACK + definitions_list + RBRACK repeated_sequence = LBRACE + definitions_list + RBRACE grouped_sequence = LPAR + definitions_list + RPAR syntactic_primary = ( optional_sequence | repeated_sequence | grouped_sequence | meta_identifier | terminal_string ) syntactic_factor = pp.Optional(integer + STAR) + syntactic_primary syntactic_term = syntactic_factor + pp.Optional(DASH + syntactic_factor) single_definition = pp.DelimitedList(syntactic_term, ",") definitions_list <<= pp.DelimitedList(single_definition, "|") syntax_rule = meta_identifier + EQ + definitions_list + SEMI ebnfComment = ( ("(*" + (pp.CharsNotIn("*") | ("*" + ~pp.Literal(")")))[...] + "*)") .streamline() .set_name("ebnfComment") ) syntax = syntax_rule[1, ...] syntax.ignore(ebnfComment) def do_integer(toks): return int(toks[0]) def do_meta_identifier(toks): if toks[0] in symbol_table: return symbol_table[toks[0]] else: symbol_table[toks[0]] = pp.Forward() return symbol_table[toks[0]] def do_terminal_string(toks): return pp.Literal(toks[0]) def do_optional_sequence(toks): return pp.Optional(toks[0]) def do_repeated_sequence(toks): return pp.ZeroOrMore(toks[0]) def do_grouped_sequence(toks): return pp.Group(toks[0]) def do_syntactic_primary(toks): return toks[0] def do_syntactic_factor(toks): if len(toks) == 2 and toks[0] > 1: # integer * syntactic_primary return pp.And([toks[1]] * toks[0]) else: # syntactic_primary return [toks[0]] def do_syntactic_term(toks): if len(toks) == 2: # syntactic_factor - syntactic_factor return pp.NotAny(toks[1]) + toks[0] else: # syntactic_factor return [toks[0]] def do_single_definition(toks): toks = toks.as_list() if len(toks) > 1: # syntactic_term , syntactic_term , ... return pp.And(toks) else: # syntactic_term return [toks[0]] def do_definitions_list(toks): toks = toks.as_list() if len(toks) > 1: # single_definition | single_definition | ... return pp.Or(toks) else: # single_definition return [toks[0]] def do_syntax_rule(toks): # meta_identifier = definitions_list ; assert toks[0].expr is None, "Duplicate definition" toks[0] <<= toks[1] return [toks[0]] def do_syntax(): # syntax_rule syntax_rule ... return symbol_table for name in all_names: expr = vars()[name] action = vars()["do_" + name] expr.set_name(name) expr.add_parse_action(action) # expr.set_debug() symbol_table: dict[str, pp.Forward] = {} def parse(ebnf, given_table=None, *, enable_debug=False): given_table = given_table or {} symbol_table.clear() symbol_table.update(given_table) table = syntax.parse_string(ebnf, parse_all=True)[0] missing_definitions = [ k for k, v in table.items() if k not in given_table and v.expr is None ] assert not missing_definitions, f"Missing definitions for {missing_definitions}" for name, expr in table.items(): expr.set_name(name) expr.set_debug(enable_debug) return table if __name__ == '__main__': try: syntax.create_diagram("ebnf_diagram.html") except Exception as e: print("Failed to create diagram for EBNF syntax parser" f" - {type(e).__name__}: {e}") ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/ebnf_diagram.html0000644000000000000000000007476215134002420015572 0ustar00

syntax

syntax_rulesyntax_rule

syntax_rule

meta_identifiermeta_identifier '=' [suppress] definitions_listdefinitions_list ';' [suppress]

definitions_list

single_definitionsingle_definition '|' [suppress] single_definitionsingle_definition

single_definition

syntactic_termsyntactic_term ',' [suppress] syntactic_termsyntactic_term

syntactic_term

syntactic_factorsyntactic_factor '-' [suppress] syntactic_factorsyntactic_factor

syntactic_factor

integerinteger '*' [suppress] syntactic_primarysyntactic_primary

integer

W:(0-9)

syntactic_primary

optional_sequenceoptional_sequence repeated_sequencerepeated_sequence grouped_sequencegrouped_sequence meta_identifiermeta_identifier terminal_stringterminal_string

optional_sequence

'[' [suppress] definitions_listdefinitions_list ']' [suppress]

repeated_sequence

'{' [suppress] definitions_listdefinitions_list '}' [suppress]

grouped_sequence

'(' [suppress] definitions_listdefinitions_list ')' [suppress]

meta_identifier

W:(A-Z_a-zªµºÀ-Ö..., 0-9A-Z_a-zªµ·...)

terminal_string

"[^"]*"|'[^']*'
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/ebnf_diagram.png0000644000000000000000000027724115134002420015407 0ustar00PNG  IHDRkbIDATx |S_iA2b Rh@qE(87ʆ(l}慲9}$JqS)m1L PRiQ$sr4mK[y_99r9@&P0@U T P0@U T P0@U T P0@U T P0@U T P0@PSmNFDh͕ l_]!D<B t_B@WetڨFgH74rO\g} MQ6BٚYVZ]Sh.W,L}Rޢg]G AWu)rZU[V۲Z.-6/ZtAʔ:߰ 3u"`eFy{Mػf^ʚd{jFSwjgЭxMPL pu~~GJJӝ3j-V{"^JʸWQlQsm"Gsi)k3c-/QlϦr5T)"x+g,Z)=n'\ys-6uw^- -MRgSL {om|lVtu! [\hC!pbLO;fw.Uئ*OLV:({@evkS$EnzfOn&Slݬ/־gz!M}/𫯽|0#cSZߕcV)uJvJOgY 3+ X{zYj7 [D2R%snYEh^Z5(+DVy29&1nsm\)c;?%_.˙_NuOIGf/ϺW[e?Tլ.\ BsēJ9!!~IS]gmt4Fǽgw:)/Z%]y}_s3^s͋^rϤ}&I# R py.^Y۬ɳ2ӕ+V7R֔+,ڎ*Xt9R9ͯBQQcPj]\\F-T-VH磒:ε\ӣG3gH=EE' RP IG!M%BN.]=._ zmmXזmZթSJkmbĈD'U+ɓOǍS R߹5qkEX򫯤§~:l0NCeJA?x8\L( ue)}:ޒz8!!? %%ӧ*:JUUѣGr"fT|OoW k N>FC 0JtRL',[>7BA(].}iZp9URoFL7&S p>7~P)`2ǎ۳HC9sE7p믅hD;d8ӯe$A;WA.MzT,t-ypWl~q6.d`>`JsGF&--fMh~%5;L2t`?gD&e$ @ 4@ `*@ `*@ `*@ `*@ ᄅuz 8P P0@U T P0@U T P0@U T P0@U T P0@U T P0@U T P.UGa6 G*EF(SEi>$T!kN1dPIJ5rfyޯ3_\V^,U) o>{]S(',Uu.Y"\3l矝K^'Rg;䊬aw:'Z+:o5HkWoqk- FSd׭yԝ]stωnR$ŵԊ%Wbm9Õ^Lw\Zfɨ9EnYw0kb%}v_]Jڠ_~H;9cXp\;@U@޼Z,7秊^*#铹9kWKrsåbj~%Oҁ-y@R^rSwsu-sk+;vj.ʗ%(7REӾŞͯ{]]ܭKvG}97;.}yiXrv/,۬u.ew }Lh\;@5x0B\%`-Nysg9JQ飩]b%S5ClZ)UU-^"t~*hSgxAi‚j?͹wFYR6ui!\pM½AMmX\;@"}S%uo߾jNU@/Ð'֛,!gG#m r=NG;Z@F9wҿ=5y5~v+"f o綾 C|̡l1=9gMKb› k @ 4Bɹs>ض}wQ RrrRZFPѩnWJ{V3ɷ&?@`uG7"OAw|^ju `!d?q⥼Wv#_^=ߥ TW俱vv~Ex~ 4B×_~ug11 8G IDATKgV:_{M3v@/Gol:ӧ~(DGw]Pvh @ #4H7o}iyX}7᢬ƷQ}ddw]rh#_?.];}TNtu^#E\;`Gל3Ν{Юz쩋_$O8b0F4衺OΝ?G?KFz94Ͽ8vm)W]y#r\%@p _;fm)} k`vD xczGd? [t/?n~矟kv^z?1c?3<8ŹkM`~jؿ\՗'򪼅cUU{5j8~*)ٗ9'ŽSq4IwTVU}WG7;=QNx֯_nZXudQ{@vZ?o}V0~ܸ\Z>?d}-..б/Y.rYaT?7tUîrC2P;P+ڎ@g}a>LyFW\1دU}ݺmU*0F?v^?kZsHVӣ FܦBh5з~{ϧyg5{dwH nN1yϬ3ζlgϞ8hџ끃_#?Nw"",[dmO?T!k10PeeՋW(凟{)7tԛ~oR~ao@0|ŊoV*M͘*:ـH~\; ʁw{brb@'Doh^ٴ_d0t8/VʋV.vQ'tt6k/A˿bDG? uZmUt8?svN\; 4]@nr{9]>#GHM_M⍉,]Ԉĩ/D˙УfJHÇWTTWh0p?q&(oF[}ȕQv@ch/gmhYwVkݺv^xt1NVV*K.cc.-n(Nj/JnMzcbbD۽@{XmiS[g];\kv h;~ܸ\rr`j*~i{}?e7E$gYk=Mg g5wm\X;Qj8^|J8z,#ZmvQ]DwÊuµz61 #CLGO-<4NeeeїF`G} \ËK˥¨1"4U'l@ƮtEOb>4i N/JL\$W\7k_>හ,4qx1#mmN];Rgʧ=+lOy%̚@K1rKEYi).z\{`P%o}-㕮rݜ7\wt;2nJB1yU+ ݽGR{5kG>Ëx&vN B_x6;Ro~U::AkqM\\T.)n)b 1\hݖ]>EZ[ى^Km]J#GvmH-S%8n6]y%Tvη`ﶭv|dSΝ='Oc_EխgW夢U_>rVuW.ܘ<Ѵ|X8'bsAz)+Q{jN@׎ػ9|^F}0Ўʆ=-}mZm[ƿrRwIlX:Hm`nW.~lAhgґBLM3 ݹ{)-vhΫ ɖlزvAA*=]Ji_W1Xmm9+Ky;Ai?µӖ:y]4aDE@Ϻ_+Wiz_mA,l1o@\ ,$~\7qrSHJu6rp=o2Puձc?r .G×֜Q`ŧwϸRZ)74 SexbHmoTZ/~0vܿ@iuݺkƩS_+ k0kf~RyxԾy]ٕ~!rQmtBMBeyE&D\>WHewɉTC#ymRC'mūݩ6Cw]99^dknG9yf(TM={ z>FRR-WqizA]MWj;̵#O8ksE{5nm{w|a1ZϻcE`/pG4WVؒ[UQ>X__ORxFā7>g:i4UN9zTȷ[ԟTxW># .Wv6w ~辿? M}{4s[?Wmݭ7iȵ5AOk̲gx$/~&P9DFFJ=ٳOԴKi7x`/T@kkX]~ኅ}h[v ܔ8r7O Ijp0FW]|Dpw[nzÏ|-zn!0 jU,9Xd{lrK/տ B.( VhM>Ѷxebs{V ~ӠA߷XnOM=tLȏ>+oK/⊷6CJ5zK/ui)o cMF"C=<7|[lyɧ(}YDGG 8R䒋 \;-W`s@hZ?mLni>ٳgXF_G\u啢H+>-ݿ'ɯWʗ^rZkƺ}Mw J{DE9o3S]õ$z$ XvÇ пDX;wܑGX}Zkj`qd\rɝ?Z,ȯj`?;袋.aӧĈvC>rNgE@"""pЫ_j@ `*@ `*@ `*@ `*p8`*@ `*@ `*@ `*@ `*@ `*@ `*E͚3aQ5kL42ifʌZ9]:tsh)?~=Z~3-36@fw5{+j<**nzv!*%uwQV`!d.,7ǡqزi3';!FxQNmi~JdAl.IFɥ(Ml|ђn|#_L#S]{kן)8/ӠӸhFiuLVɵy54t-knTTS .mè5۫jZՔnr~|zG]󒝫KY_RzSYkw{"O.9RʥjOIgH74r1mϴVuY-^NL^Av|::ߖ\oC{:[s5_,RSQ97>sq{~j ޓ*f^̤Us{Ⴔ)k#<-.ecx3 5"h5<ҎoZ2e蒘;^/.HPKR9S*ݲzޖrlmvn3=ybfnr Q|hؚߘIKs_87qǻv\Q`SNd՚ w[tvY*k҈zs*6ont$Ձ.1!.ޜϦ235Xe6Vsi JaP~GlMVbҋzU=u5b{<Աc eMr 7;*XTlrfVP}{/ U:7.pTj5/7hZj3l;E$%iFP&RشL(>ϣ͘1{BfZHI/?7r4ҟ:3rͶs92HW'!WwsնJdnlP @h4=`ؕdQ]i+H ]PZڮ{ gmm|cfrF^aH5ސ:[]YV\`LSNtuXm/K:ofRSzf#TljrgϰO۬niH+.:yd JM/|SA[O\hbv5;y̒91YzQm3%ljb Yf/HeydO7}hڤ׏Ӥ[cT4\UM6aԎyn7MSi7qc&-d\]>RaNHY#ߏmyԯ̨nrwfsg.6"=PdL܄[p(]~e3&y3bҌeEX J֓ۗMN*u?XXѪ=EJZUtnе9E:C~۝V1YFXZx5J+;\JG7aܥ/$Pfj*@ `*t@Ct!mXVW&s`E/1~~$2)#9V@9U`,*@ `*@ `*@ `*@ ᄅRj@ `*@ `*@ `*@ `*@f?ϿoΏǏ?bq70) D83J̙39L/^pAhǍ{V۫rK+>A;]v3J?~$OM s A 0uoμo'v뭓ouȐj4m%%{JAFCjK`={n\SS#{3gѣ3mv5!B Dh3g*.-_9<}wּCy_9tL)0-zcyaÆ)'zJl`+_R Ž7|tݻKeRڼYt60n裏F$I(o#:ƺCлwo[ITII\Ql`Z)>\T Jn FF~2N% `*0 4BGa6 Z ş,zpMWU^w!@+:S TwR|z\kY+y)#/Kp-)-a#Ze5c5(+wOwFfzD׬bP'02 _=2JU0uX>{]S(',Uu.Y"\3l矝K^'Rg;䊬aw:'Z+:cim35-.yMg.OYQ \|YŮwD7) :+6xJmU/OT&zdw΃wr/01g8Xz׺ծ7)W+å%o*ZSf)>`0W5K:Al}NE0ԋ 7*ZzĻYWNvUJ͙X_R.T;[/yfNO>wrϕOZski][))")_^vbO4k[)dbIDAT;rnvN]p;6o9r!\-v];ts 6+r[)Kcnz`E?nAuʛ; NQJWwMMbwW;..%dNgdwSXóJVVl8=hν;5ʒkO 9'\pM½AMmP+0KŨ۽'L|.73}bEzD Y:S '9D@#8w7-ZsG\ ?L﷏*ݛsUS{K:͟M3v@K.]\#I0Vݻo_uСR[o]]]#M_3/ oKytw;B=#Uޞ=zH .?~B@ 0[޽;M#ЦԲR@]ޯi?RG#2.~lA5_~jd??עt5c/EgxrqSsTJjmV⮖HE@^^ҫd_oO|#4J!wMZٳJ[׮OUU_~p@oYrdeƃ^~rӲO'ݻB jTO../Y.M)W;<%Tz[=vՔ :xځZv? +7|gҔ͛5ZMCʯU}ݺmU*0F?v^?a-1"QJ̗_}%7l0v:7 $%%JA~r4(T;e]_L{hFmH+L9̻_Ԍ'N9U h.L)':aѣJ9qHQ޳l1>R߈bK.\ ؇?$:ܯbJ[&N gC_=4 [#SDM'F$:_.p͏t3r~}+Wddi(k웑>S0!fARHmE/ٖM$2*RڴR["ukWw-%6,~Fs7~Vv>x$k$(auc׊ԶF;]ZɋwI|m%ڜ*ZvߙΜ9آ?`PƠh_Z6jە1͍p[Ԉĩ/D˙ԣflԩSBufm6pl]ZxMcqu}hkrm_ǂq~ &QI{qA v㞶G897 7㻥ԆRh?ܺm{|ebDD/vX_|Ra ұqu]7H^kf5gj]>}58}^|~4񑳶ݾ.HOr".~ەk+-o֔ƎIICcG\m'Փ.8y-uRr`I J2vvuoo9/RZ Uy +jVn1k?5ק:P ?"oׁnh~l󁵖9 ="}PaQ>Z^4MNs,'&'.rU?>ޜz㮟@u$'}b (9.&v뎿>G#Lڷ B^kT#u6Բ4z ۭڛ#LKUslnH49ڽjp*jW48ެ6Na <|pcdM#@?1yvA WC:M"&ib6ReR-SYaޭ;QkU;$ݒ6u(w4UxA0Tmc+^+#2URn)l)z劣] m: #[ſ][/rwl#6ٓr^rEݻWJփ̅ Ž5[@\ll IU"I[Tkՙ܄kUe@SW-}==+ͨV>Q{ n_pA-F?l<{Oog[b2gI$[8`9Ixjl ;wFu^nG g3nE 7uy府^|ߕN"TzZg?r|wò[qn@Uwk;-MYir߭ע:@pj&ЧOU6isnZ},P]ޢvmrCRH>\uO,rwkܸ{u>2ӾG9oLY!ٺ8b4ǜ4;"^mAk+̞=EgQodd=FkŽczү^:V~Lt=%v`͓[ |Un(,pۛȬr3 O<^Hu'WnR'5;"gk6˃T.%99둇wl`1ʔw1> BBDcw-}S%?ɷXnbJy5DB3Pg${YZo<-W1r| D3>y T`XV#}UoH!U1=M3p\8c9vc.|Z?˗ȏ2j~#*ʗ]v٦·=} ]{j 6\pmioIcgYweI>'ڟ?.uEuw}| VcM4Sצw~wͫo u;G|+{*Oo<(+e/}ii?w#ۿw"$v /Lu7|gۭ۶[1[{^*\MZ0 RU13?cSEkin?r:.$X8xcOطO{ڵ@`p89R Ľ(;lN{g:MiIIn<@?(T ÇE'IDATyxqcIt= p¾TqbqoK9'ܬVgl>H=om E ;@5i UT1w vP iۭ[W_?>yRm(ҩTÈF 3aWs`ɶݲaoN+/WǞ@u 7"⶝JK>?EŀFX}J!66޽{+oViР[,*K>uWޖ^]yom(߿Sekp &'#rJW _}Xf>7=fcܑS]pWcnēOy ~Яd'\䒋(ߋn O㣟q֠D?%W]yh7OK/~үTJK.@ >=hݻ_=ҋu;~G?Z%Dx|cf]1Paä{}BkΝ;rRO ca~%]tѽӧk4W^qELePjf8ARb5oO:.ޞ?% omv5jz_=yDDĨđNhpq$``˥^˛]̙m~W*S$-p~{u]tvݵM)W7C].>kvЧO..\XmgoIRjc@p4zRػӽzjbat׾>>r'NH"""M޽z⋯b!W x-p7UG&} ~J\w7pѳwa&PV)@"C^^wRnarǻg/}s~P˜;FA>P6={=A$'0v}R~?޳jݱmlLݺې ,^3~ܸn7q-={C ,u7}nU_k2psjWFk{_׮]wEDDᆴi?C@PMKT P0@U T P0@U T P0@U T P0@U T!p5U T P0@U T P0@U T P0@U T P0@U T P0@U T P0@U EsZ",:=?9ۛZ=DetϊZ!-p27ګҹЦ+EK @iNQiN:-UI5[,gʒByV%6p+&h8VSw⢓g>sri#"HJ3hEЪګprÑ/С, dk(.93_z\>6} ZT\Y,w+Fz]jttc)M#ڬSwnԨxg{SoO3͹:ioG[]f6{^g+Qd}VnتX\:)gy&=3u>n5kɴ<)9y֬]%;WFy&G: _w5YL9R!\iN^ w+qM*ݲzޔ9kDbW eʒM{<߰~d*^by)) JEUZ=[-LCiie{祿g]:)gyC{hꝘbˑڴ6f9׸wCcA }Pog[PbЌݝy$O4Sߺ0t>vj>^UwHjMJz~ukjʴBG=ҙuK_=!s]}ǒ1^?@@i&JD%j&1RK6DVh+H9758HyA'2 #Z-kLKDٲӞuN12[p;/#a^4{VK6ZV:?cgiPVQY^NY\K+.UkҼygF9RO7b~kgsvCA>ȖDN[_fMw^!vZQS՚)z)i7W*3hdM*&yP1nֱ֤BҲ4My<旉XMړr V_&e$r$LJܯzalZnS) &Nt˜ #B`mɫRy$HqXjuTbR)lh0Ogͳ2sǜ~ XHXcQj t\{\ZjX]jrd #5/p_.ɽLqMv5:ku+̖2@KY|hU֤1Tl3Th!.Vku GKO5۫!;TT,kktٹ?t  ̖lVB^ w~фd?6oWj(#7/X[>zF̤NQ)'gmSj*;0tg.y1h̕&ӧ+IoHoD![bN~uی9Nq(_֚CF)ZrΕV32=@ $5m!2Ϧ&gmJ9;;9lx</v1Y7}h5}n{|]:ʲb);%!@o*JUv}X;ObAnhçv;o>sޫ+6K139^#Q"Fw J -0ټN}1-^>684K]CleX 4E8"R4>;fz[g]{~rf׏Ӵ©7xlTmq.N*tMJxq-=i8I)/6U=w{1TiNv=gI1YWL9[Xrªct78c V9B~vO`v@1K,Ȗo/Ht̤<:V,HZkHku$_cFLZUtҞ3Ic0,Z5wB\kJsG^Hn4ɦ3}EN0m&+\k=spڕGJ+q eX[6cBc11ZVXt+ ˦:V;?VmZ~yw8:nŒ< @k84uIU  Ds<(6V[bS2L j3 :V"MPY#`uJs.eu?LZZl=xIDATm6tH<үf\&}ȤXt4B<@ `*@ `*@ `*@ ᄅ@G `*@ `*@ `*@ `*@ `*ֽ[KJ>rdUWn??>пp;X9oI>ܹsҍgq0,uw!\u啫^Zy "d-:Jgfe/ͷx_>IɄܴlqW_-Qzߒ}=|eQ=zPC 0H` i f1czV|9zfo۾]y{ۭyՈR#^326o*$M߿tyS4`s];t_7 4wm\q`tqqɓnQʞK ѣ?%/" TTT(ѣ?%%pEŗ`,^}4JJO՗^5=."`yQQQ!T PFFX^}4*TZ,!&`U>D):Udꨫ"#NW)363]K:;CVYkre5(+wO/akIi=p|OT) Zp&eǸ:w)Nw)x˟ymnWuwydT䩒^|ͫOk]G}\'*cy چI&`oI;uʶN-y+n`>eڻω.>B<@ώoo_R[;h*SrྫsK\ |(wԒ!?=GYvЃR= ܟ[Nz⪝ sҲ^]N{X0իnO5dj`1=Sh^͒ra~6vn~mvd}XZZoI^É Fm^r[82{ezio+ _pMkO;%ռk@^Sߔ'{ӵZg*3*BzȒ}r=fk*Ӥ>(!G֋p8>g|M:J>pTh+5C:' ;c?ST\3߾}FF"j={G B 0S#[ޱeLĒco`󿛴#!krCzW4u۶[[f?}+?Ww 7yOg%ޕsWW9:cjG"jsFwz,ҦG^a۲HgZرc&O* }ڤ_}R޽UW\ѯV_?NIO?5āO]h>͢* k׮J!:ϦyF#BY? cnW遃Gn7 ~"#|L'GX.觓ov|(?KܹsD4FP֛͂8 4@hfQ ;S**~A.Dkqmv]V^^VV.LLL4Lpa$\D!@s*woM7FEE0`u3?o⦛~| ZVt8.PQ' 4Hm_\؂l˳g:]oVt)i'$~>mtgT9sF@:m_t-Dk(<%|#?ܽ{KƎTR᧿d@%$+}***׬Qw~(O?r^RooMoQ\Gb^=O\DDGBT4{oۥgl޴ITzytu3O+|H͒'?!Bq[# Ν#G%讆9w^/:ʮ{Bfޖ6r_KLԽEsy^\\,Q?no~R~d.={En"D[hdU6:f6sfbBR}պcvk(E'?ڽ[) 3مcDu.m-7|@8e,Q]۷+VZ:p))7.$}RPv|p`6S#Lg햺bݰiQrw!b9Z޺>zd2vnGζuOt~ɉzJgMxǴMh:RgcݐTf;dܺ\[#s5xaژ>M|1vڿr7=g󣉙vw ԟZ+lӋm3omobccEQK~il͚<pl}3vɯ sZzn5a2Cwͨc֌Bw~}(>Aޥut.ǮlOC獻q,yͶMJ˹{u9o܅{ymMޠ:,|Pnܥ{zs=*͜k>k1ῢY>?}V{dep6 hؖ_ }lDFEE@%1t݄(LqkYZa_9#E yUt7-|VwX;mZ7PSsyuGsgω _+.k"gs8O˵q|)<+g=rvq;k{tdcK.ܸkh Tm/;YgΜtmWi4sÇ <+͏/?O4:F~gJgwM{%B"ZF~IɾѣF=zۭБ°Xv> Enj?_"fׯjhvBܔ?1٫*ܿIDAT[ Vp>m~0[eu>ϘlgJ'ɳ)PpbLO;fwե7oU i?k۶}I)R!.>բWE`^:xC6lgɕ^Zt[(.>+e/}ii?~ + p3㮮zhSϝ;w?\*'$__1*~1M9V-1~0ֹJ⋣?D" r>/ .?a߾}Ryؽ{vwUt 08VSVNj=7)7**Uo`q}lcqb 0/3߯+~%:QGy/޽T>t_7 D-aO5.+BƷQ ݚrE[x/V R}d#':)sݶ??VRe?'ݢ=Վ@1" ww,nGpR\\F-ȥ\׿?"g]CD;~kW_ZфFP.Ε4z?(ܗ. ⧊ 4zh;o+-]R~PՉ?o? ;-'*IWss)7[_/\Ïh !??'N|RjE+pϗ~txEkQf58"˅ [(q5,~ɛ~r߁nprՕ?](TxQ@GR(CH)*+喉wXF;%mCүē/R8*=ІfuLJRUR+yDrܐ!\DP3BȻGJwe?a⊰?X&'T@4… l;Fa_#;F?xp,տ@]tj>¹s.f¯j@11ZmA'OV?q>zOPg*] Kt>f 6酷[w(J=r7wpl]wzСu74 YGPmJo߾1H]vR(ٷمboɾ ޒ-5 }T()w,|O5eGrdeMz)իW޽ty!C֍KU<x $p7z*І ~&m?n RQQqѕ']oxs7$E!tRLUc҅ e~㮾~"0B@׮]>Rd-8wT@$k}p ǍͯT/L)@XpNys0Bٳgoew5%冱R"H>!{}555Zwln-4=ӥ/7}@G"#|wŻt~[|~'r_ٳ;`БhP"k$w\"a߾˟cMX_FFҥCα}{xرGRU/ Mih :RO`*@ `*@ `*@ `*@ C `*@ `*@ `*@ `*@ `*@ `*@ `*tڜЦ+E `_ʌ'Lt2^ &@B/[WWQ:*:]0틟 L;ve @WLPw};Xl͑)EM+2 :my5B3 Li^Cnlͬ?+.Q)\sAvrƳlN󒝟HY_QTV6K139^u9"Jf4UP哳m~gZߗgƴڝww͚0E`\{2x^mC^PWym f=4;ϩrQeŹ:R ʇb F<z@5t]ӵVU󶬖fM$NjV*]27,qyLXQ?tzk*&wF-/YSoo%37-q/(6[}-SiNdGi^][ӢDGq^8/f*itm ]=epy-RŽ-RgY( ՚OW <㐝9VjF\ŴvGQ ]C{5Oo;יR5pܱJce&읗=B\1)op~ZkFzC 3UwD yتzVUtJʋcC}oh"eE9 .GJq3ֻvg ,RfrԵ'"u W9Nr_'O}<~qr$JF,uZO-06Lە K((Jg-!˘dCm_|oD鼌|Ug/) ӌrKB[Aι(!7 Z%-y:M rl-^ؒʵ'L}LKJRՊ`7+U#奺v>JK+;ޕ,c33*AYEeҾJq4֤e7= O*դM鏙aU#/U*g˺o1 h(L#"J2jC~eaT3H6e֦ B\nƬq9u#*-.mM lzFSÖB-VߎAY GfΕ+R.؞oR~tkI6:۪FW$xS9զ[Q"m3^=f6ݴt]MEE5Λ am(Htع|IkfObJ7jGJs \e6%0訾62Y*k҈zs*6?Ly0l%%%:Qdq-Uk4"N+m%Aħ皋Gǎ**\55~z?=kd2]տftLZEe~9[+iu5MjM5'ZtxҤ] h-3V@k:66>9#l*j*+ȫ9J$cAW>lRY^9rFa9Kl69-I˜[Pk؆mѾM\1lyMNWp4ck$:D6IDATtY*MM6*݁fs>f{A+0ao!o1%uX5k]vX6 5kc=dݍ/J5;,6%,xuk8t\sZDʚgXoK9fXt&:fI7xlTmq.aAi^Szs|Xٌ[V)+jy91w^^֯}Lg+DbnYx夬fAPmNUTL9[;>?m,<_6Qt ΐkrẗIYNIYEZ6.֓ۗM+2FڡYںLɢUs'Eiiק5ZTvf0czhK t1eکΕK>t+ye=Eq͕0ːeuϋ+ʁJK[ɦ^56iR>hD;d8ӯe$A;WA.MzT,t-yp.+4mZAF+-KhM WiN5#"[3uԨm@YK&su"*}ȤXDh*0@U T P0@U T P0@U T P0@U T PFwT Cu `*@ `*@ `*@ `*@ `uo֒}rUy}ҏǏ?bq70)@"}S%Νϐ=SƏ'a7*B22/ N"۔(AܨYtcCl(՟I٦0ʆ6 R5J6IuTREiqHhk6=#999'y=ߣI>\|?^yeZgGQԩSrG_opo~W_ v]g;ӄ{#G 6,aUg߾Ow}7է_w t:U(sneR/E]$};u_ hW_}odG}$Mt&߿_6,y;{+`qDRv5y:/)z_~/!4̀hՉ믛ZcHIɜ|:hѪRꪫȌ|_*< @tU'^5Fر\[B?0A8qNLCCK` ' 0@ڳ#ZZ:-&`h͛NW߷bƘ6 Csjͳ/^y`z8fbAt.mR~ɩS v?寿^W)RNKGx̙=yɓz} =\W:Ryn[T.+Չ~7~_r?>VNFYgyޚsސK|{ߍ;+Nt x{y-?!u|f>Y.O?&1b<]AtBTڻo:OyoG;3!xIY˥[&_;o}p4)6r\}wn y+u:5#u]~aQWR.QM!tTub߾@K>7nAte?N_8S;PYR>rti75M@32|?ˮQO|6M $άo__ϯ?__FbGp5 7};B{©s(yS{ N':IiMM_EwqRYKm:oV}]Ju_XhUO[8ً5RT>-ՙqo=zا׬U.ȹw(:OEe:odI7D>~ΐnxs<,э&ddwOY7w*@oG=Ӱ9ۤԇNP1GNҙ.RU7$kqVx$E߇~;ѩC7ՕI"d `|ak{'ގoV7_ȕW7kiҏgRT}ĮzҊƹ%OckC=/IDATz8̊1r =OŹc8-Lva[Z#?ʏid=읫4m~hjz˷I?ƕie=6ʷuMUoN+ε <$ϳsq~sDy=3gƘe)yVСCjxC ym.vOnxmke9Wyk7:~U^<>jo_N:RY|"{g)< Ko?4un EXe~.S~Sf\mQ~xa")s.(NLP[~=z~9T |³w7~{ҲszS闫{Cne/R#-ɬF]++u٩4ԯl%>_TmNܥ_ZY,d)&|ڞZuS?O) {hoVDEPm&ɘ:qg7 l2=PU,+WN9Ck{0tyϴL/0(މohX8~\R={qyzоNO3.*#F 2dv}U}1iCyS1W<է%ۤZp'g\'mNu2iV˕ ~#$ɏk/ټ9թD "ѥf7 zĈ.t;EڹZ eKW^zw9ϙ 'ȕe{ ]RjKho۟k.VYS.YMXQ5Epd\~y5c2~}]";ϲgoi?g5cEI:}6_)MfL -tPl~sϕ&{}zL)ys}"*@Q{ ړяKWn4k&nw.PK/XgU8#wy?$ۤK/| fbgx.(47 44⢋Nr֦g4]tfi/o;h_xS/MR.xm! S23ǟ։ӣG{_NRv| s{Ce|ۢW\O0zg\-48o7 E X@G|_H\z^ : 0/~C.Ȑr>1QOQر}>'"Ct%_iJfK%'|?n޲5TS=d: @ĸ 4!%N'z>}Z`hy;)w??VO`rrܿ|^zIL _   t$&@h `&@h `&@h `&@h `&蚚`&@h `&@h `&@h `&@h `&@h `&@h `&GD[^gDkDZTt CA\T}#AO̱:ۓSV`{Z!j9DI΂l[U_[wMgu/sci3gn悽ҿ39$9y`ź{'& eNgPTa9ΦTl5)K8y*.!95] \WYc2x/M0 JY UJU{:r/*q Wwݩ!Vmߜkw5?WQŔSt[489ze]>5VJgU:q8,-^.nz^ymNGA3D_VVAqi\iXyM4R#.53Vlن)>U;/ع^ٝ"ÝeOV1v.0WzkݻqJE J<߾bʓ\⭀y~*7dgʼnX:}YV-[F g<{زqW$NP)!&lY~[6]?}Xe?fG+l51BѦG*J XMo.v5U,JR:7 \MB*74\k&q:u'h4c\>jҙM8,~'Mrgul] %HxҬu T&a[ YHz;&Iɦc[f co4r4ސEYXI&_,uURIR?զ3 BΒl8)YjJJdwKַ`?Vqʿ:QOY~(;}>R,)f-l椻JUKiH0XSHb4f b[eHE5~+g*B=7;riVe"%??3hݔhkUUVΦwǪJpm> he^aΕO+ we8sνrs؞ϝ̿b9˚ۼⒻ俾4n,( JPKm>F@Z lQgU;7>)iR֛GgkVGiku\vkI1)=W;ռ>4V*IY:NG)xNT 3ZױҶSl6[l4+nC40si{j[: !XźEG%6[Rupc󑌽wZrΨەc 2dhpZMYU[Cr)R ɢb\gEr|[AȑMv77 H~Ѝ-KK9]3s<|N9C1t$Փ[mwTn IDAT^Im(ד^GQ9A QFtT\m5o*}rj%|SU45ȯjձKMaXEJ9vVi-K:Pr}}fXڂ` -AnJɱ1+[iu҂c9L[0w:&g(׬j8 ?LJD1>n̵9= D]SSS襶,ݔ',2'[*2 ';boJ\[676sKeY_oH[\r.=l~7gqPNP]6.U'S|B ut,‘x+7$;C_g;vћ|ch3WIV&eyFH=uwfoܢɫ%0W->H-oлLc͎O5yѺcWsu^+~˹:}VI׏V @+ 4=M Wg6LY_ۖMbǮthQtƙ(j[4eU &p2fJm;֒,@ h `&@h `&@h `&@h `&@hB/A `&@h `&@h `&@h `&@h `&o[v۷×^rkv | /bثLn0)/ݻγs&ddHaXaۼ%rg#zSN-]]~}׏??WݻOEz[ɓ~Ϟwԧ #G6lXe wǶJm6uT ^iZT,ˏg 0Ǎuz^+3<(%Ea+=JD'0^6xˎ_՜;+|tccs~7@=௾{#S?#i:--WO^x3Ό^1֧OoMQ 0KmuHk[nQ^V~'%n{Eu|1Չ#GQJu⪫@}:,u  \[[Nj:O>cO({>S'Ƥ 3~bԉ_-D90@Mfܡ'G'!v̎`{N׬;F0"nqiR,<ToZ'ͯX#)޿E#EsrowY->'=j :k `@T?Z/Z߿[_Nv[-^k?]U=?yk)Jĝ,'/=Be^;L^v DF{լNSCTݿw<'nwڗ*nU'];;HrOl1{\ڲvo暧VPr[)oYx2+e4#Rr9m^䦒թ|`o[֋#_~~nRw UYk7*߾;A]S6c !}/|bi6)L/9Z_/h:T%?gNzIw>qwK$dK嗢'`{|u4yfzKj`ĉUyͫ[xU|f_ߗ\R`;*D¦+n_z%u'7 %+69(zG ?4o[0ꫯ^ӱ|4=e)ʼ4 ,5,vSo\Fi߯^rOH4~nW:?4W|r@O>}~ ΅6xn{ﹻO>t߾~GJ7ߌq`קo>}ƱWMzfA{ÇW‹jUt@o} zkT1}ZfmguϏ @! 0[Do$y z}k 04;^x `О>8WtO>}矋3/΅gzM}^|9qN7]rمvyf]ђ^t}&=_K?oV=UK?S7MwΝ}8S[n_)ė4[Է{J]g1 s푮1w>u"111M墷[5kթSDYq{k3/qyӇ 6ҡzy\\5|n_HsvxyUƗwlKo:x!M\=8~=Gr:v޼zt]hn&6.{^(MJ7{O~Gs]@cΰxlc/|ӌ;=={= .@طz}xW tE9Na.Jbb^WOk7j:!ډ'hpmmmƍn8{ m~ Π[snUgDק|1 E}onYv]VN?v1!}+D IDATVNIM=+Mk?d|;YnO~U6oycn]sO}O;җ}M:KQ p X:!#cWYȒСC:r.BR-zXb)?4=WM1& {RgZ۸2ͷHbҴMٲp_VmIx ZĘv9VfcZQ=YihբRRiOA)s.wWx2skb#%zeoC֧H9>*GH~}~inWntyqYuVy) hZǧba\)+yKO *D=v=45=ϥ"ܧٻ@wEX60 Gko KnY*/o* +R}YZZ޴$]ϳ\R֗~ˋ~徣֣]yKRQ*ҏ Aݛ,d>!Q2Hgr=$B]]]ү$Zs/4Yܓ)W$$%9f>R}T֚tJxsYJx>*y֚ qLԎs[|CQ?VePܩy>.<^c&O Q6פgI>{<%]y]I {JRei=luJ.[8:+. 8r1bW!9Gˤ钹t0PXrX1]5[Wn%WME|G.^lՓ{_`-޻f3xrA͵Klnt#j!|u+}䏓2ŌbsSW1%sCívTKR]hWʳ1veF+-,<,m3ztŘW{S!BK#234ksڐr[y u-gz]uoceyOo0Wm.欪=f4Q$EreMtسK[=qs9Gjniq>Wgtr@nC^iMSu3E'QϫUy{6[j܇g^v- Љw2uD_eȽ7eI?Ցk~fRy|vTw4q.nu55d<:qD^ʢIC qyK\ٛ8^?T(P~*}Ny AU1,-j僪 hh1WZz+,וYg2%mOs_-| E1Za pyx RZ=7Ᏽ+hG@A=|]N[y/iB:-wEo:X&D տh'^yވ k#ce7dȐ_>uz؞3腿#ϨӋݯEs\n=r߯^]|fW@ w+r^o۶o|ۖHx%]e/Sѿo"Bkqן^ 0ԉPSWǎCHtaluF^2y7}}έ;O|qByy=moQ'7Dh gL@a҆A 0@+()i.j!Z{? =D׻֒.j]:Ⱥ ]uUyP߭@=Iys=7 K.۹YL=?]t||{ngw8c ԉ?Q]BB?x}Ʊ@oGuX-%wMQGF{Òo^'Np0z+0?@;{:D?lm??~ƤΏU@F8'O6xTJߩVާynUr߾}G\qE\npbce\=~ߩ 0ӧWH?;gt.Lkݸr~sϽ.@{ z-G `&@h `&@h `&@h `&@h &@oG `&@h `&@h `&@h `&@h `&@h `&@h `&tNa(j58]$uKoIeU F ZgS :ڑ5"`GߊYEk)9N}O.rօj{؂*iՂa϶(UfMY6gvɐ-࿏\oj[ASNQEbs\i+\CnR=^0+eAgNrsVԆi)~fiuqfB%*.ʌ>rg-[n8yݖmUgNzFMWQ^ݑ9n[AWJUG)@o}(jk7jyZXjr;*%܊Ҋ3}3.zIyM~ m{ڕuS W@-2 vߤY[M;eVˆ";ET-oZ)n۳ɿcGҮEӓt-{vzj͙MLfsoܲ눫N\JR3@# @W pi:@S=-r$Դ 'õ^)Qค/gffEV3iv]qΊwF2fgCod۸}/J= Fe*kORCn1u:>G곭ᘇslκ/މ)9)g޻jKő+f]G^]=kbJbwQg-Z]*X:fcpo\A$dZOزhxDH6zd]QT pT]`Jjڡ 58lUI L2 ĥ9Ќ][*qViIv7_=b3(6i[Ve&hp,io,&@h `&@h `&@h `&@h `&@h !_  6T@h `&@h `&@h `&@h `&@hB۲l߾>r䈈6 ΅^|ƱWM9`.kjj /EsY۷=?yKbccEvxѦՉuiN:P.?5jhvIUqibBF'dii$Qԉں4'O|{>0\tEɆdm~PSUc/ڶ;^?fS~U0o33,3ֿ Γ3W:I4௾=N=U^+.mo_th }4|>}|\}ϮW^V:C4em/N|_tEK|!}FǞo͖k9u:QQQ77(pee:1b܈+x/gh>'<ۓU%0_/JziJ }MH}Ƭ7< O)jch==XPK@S \NW^ȕS*W2.tA\jWWdsh9.K?[kDl^Uz}tX4ഴTu"\W کS"ŠKE]xkQfl77 qAM+W&{=:}hhxڍ7J/ş- `kI z/_xkMy;!D _Fc5'"!3h9"mV[Z9眳ٿ`IT'W_giK҅J/ES?~1Oqos%M`ɗ_~YyohvyO~zm#G=@4nAo,ځ 0@M 4 0@M 4 0@M 4 0@M 4A$4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 Є>"4ز:>V'];S E3/ۋ Q!]O:@XQA=Xp lZ3"]WYc2K:u SvA5+AUJ\O`GNEY%.*6ym% ͹vWpe*[L٨>8E׌ZE^\{ZS l ~fnQ,wU؆j[AVtt:SKQejNQe(Q78S6iMfI\)r\jvIl{ <,hp)'m_٬_Ѩ p-0Eէj;˓6SdZ;wZi5%ܮ:7vqɎU7||NƽDeϪ{{UJ,@ Z7gw]l.`.>ŝ>ERjTKt%g:~.*r>-O "AN^gϕ|ҷn`*=t*mxŤ,KIDAT@th%%~gz)+V`*_TyL%RHRKܭDJ~~fN)KתMUf}ZkNEkΕO+ we8s8Xew7ϝY?V:8u҉T-ޕLjn&[=migۥp/(Jg[W>kڹLIlu64_@-Z"=JS]7\vk/I1)=pW;34V*IY:NG)xVYfS˙zÈPY2%wvӖf.1}{@'kuhCN届u&Jmvz;WVnW-(8դ95Ӓos\*Z9֯#Mm,5N·aU+Yնg.DC]Yʵ%u[[7ci3cV!;L[0[͊;-3{Zk{^]}`]qsfP).ގ :~jT-)(\PW]YR'u|ӕvoYQŪƍ O60ici;S~RѬZ<ܐ]TYw,ՕEن᳥:hٮ]0ܘcs_gIvǣVeݺ 蚚B/el 8qgQ!\EuGZ*6'߲ѿ[*|C͑懊<9 #E6Td/{[RB ut,‘x+7}+U^읡mM|k=n *J1ܡ,pzفoLAeR2\ 8,>Q 46Q8* 9 pC>W~gLJd؛gMh֢կ8!!qbݽSZZe&'51ĔVmζEXÐmwQU>xѾ듲Ux|{ԗ~{vՕ_%|lY S6]g=3'Y >@#sE"iQQ/KuAn(Uo#& zH:G^u-[ݳrNUъ)* Xj0e7?V||m.4]3^-0e}m[6ґSy9]q9ږ~%oYmٳEĎd& &@4A@h `&@h `&@h `&@h `&2EЩ/t*M 4 0@M 4 0@M 4 0@M 4 0@M 44Ź.*M|u"hi.R{lWY41!#2ڴ@Mښ߭YtRU?,mq/ `&@hBnLRШKOWS!GFN]rXh*/eXAi]mqp%0Ў}EzhjzK1ulI/87RinذaiW5gnsЖ_4z\8&&ܗl~'J-c!sR16;sT)"ԕ7]-[8__w[Kz)v.v>/5{J!мķ~NUo$%LeK{\Je{u\v߫,a_FM"TmIuB:흤K/˷28_2?&''}Ql_;S w555]]x[7__Q}:`(~R ߦMztkt1" }WI@ QYv:#F\W[5k };HT&} SN}xt~<2o|V-ǼT|~}cW; B@0:JP߿hƆXKO]X!ܾ}ge"BarZ3y'`BθL]rfN<`o2&>si>:-Dm2MͽΪ IMrq"vڅܷ/>t?O?(*_+KKGMY)ƴ,,~ZgZ۸2M( arIDAT˱2ba\)yueew}!*xًJoi6'p+/==OٍycQ7;f~5nZ@SC,渧}{2}מ . zLDp J;0ĖO9  ge_~y6s|)FمymyZ=d A˛DzA S:>e.$*WJarn KSonjw/kGv={zώ0%JdջL9kO7DZkZ>Zrb%z>ǩ_-lkuui[圧,e%sQӯĕ՜{ž{XL sȞUyo6V&+D'W&Y=Re.ju y![ulw첅KNܫgD{ϸ-i==*[XxXpNB,%LS݉YnJ.phzoY޻D*Яv-azCJqзrR ItxO TJ}7R~!pk}:˯=W* X{7Tis6OK/U;wE޻R z+mYϑzB{pk~f5"Dx#:$M :?@7Zn5dgL,= @;D5DkSntXx.={j%_?Fvq!.^ pxiMz :slkЃPJGI/ t@ *M 47@E `&@hB MUV&2`&4}: #FDӯ>=4Z 5==y/Չo}[<(o~p u_~<3##Fuz9xDe.|mmZ㣏yg,&yվ'XR/Z,zF]z.8B }ʞ͟EX:zw0cɢɓ&c?BT+묪`tݔ)Wg45+~{wobMO,_+ PT/p?}Wԧ/JibBFƮ$ [gZhY]ʴ2kii2Ƽֱ%M^ᡩy.u]©C,TL7U6/[kX6~*JC»f="xm4m#;b>zs03{Ц3Lvd/߶ijϽSj9眳ٿ+]>ۼ"':@InRP,/˔R؜mMk1Z"LwDI^s,JfK5yNW"kr!gI%>7va%{W*%GYHC"9֣&[kMk{Yk+{WgyN%J/[d[vȦRpxJ ?D(Wþs9<Ʋ?dL_|/zx%2w=t2SĘv9VfJ¼1ٜmRl>\Ar[of}u!¶#> awOuHx4GE+*W,TݕE>%'2zt8,ZJrVb#Q¶OFQ\9!R4]}(O~M|{E<)` o}>FCR׼DnJN}ȽܹZ'pk%)nqȝwyR~'|}xz-_;^9 |! #\]DԇB;t]~EaLP'N O6fPLSl6n9rU`E7 l:Z"e`VYS~8\SIAq;BǘMJ*a ]}fU,9wuMfG(}t<2߿Ĉv޼G.]ݧGg}>" ۿ_!֪s  \yoGN OTࣟ};U΂ǟLT`I߿heu!W,MOץ.] ]+yh1]g\X&z}ʞ͟EX:zw019zaK[Xn":DNmC!rmQN<`o2&>si\\6HW^^gUӤLz8qqX&Mt\JǙ_vڥ}^1׍n m\tÇ7x&M{x &2o[n/>}TzH22v?ntܒ-f-M(SCӭބ%B تdn.`Q~HE~im4~&Sݮlc^ؒߎ+/==/f{}RROoYoR.bL2U&D|ߣ MC@ Q+y3H̵%*}`ִU(_+_ykךjUrɢWb{':9T0|U&-{8+Q>0ezsKY<{$*G%7r,eI[.SJխf9J/EsM~j7@bm=]yhbOB^aI:yڍe0$ {ٳ7>/=^ q #M$\:ٲS?RL[չ'|g)NjD;-,<,UOy2ӲvyDto2O~ejU60H;vk*-[.V xe畍ЁZ#̟䧷6rEqJ)#:/dyof~"܋E1w:͐([ ,3Ęv9Vf\6GtL}dܖO.9phzٸψvio+[8?mi==by#QF/Wr'gOZ(B7/E M@oxo IDAT[:/:X,*4dOpj6 UOMM r|~&ueVy KعSBm326g[1l{񷂎s`y7)Z+=?8Ź'9{@M:Qt_ @M )-.pQ1 ϔ%ʉ}4nM 0@z~ pQh `&Y/N1T@Fos)u"o_/?Sib#Fm4-'=up GD .@طBػo:' NGFp~:>zh nA(|mmZ㣏WHO4kf M쳟e$?w<:}/!O4}zl:]/Z,StBASuR;8Bttqa ?+{gIi7 MX2!#?[~j=f;tf'3dζ&^t:'O|07M}4!!Ok}_o^gUӤLz8qqXqN4х*#z6{G6~{wobM/\4Wh)d/rO_~鋥C(]e[8~Zu~Voiڦ&U:j&!Cƹ%egu,4un 5!].V+G{ڞg {C"Tl59ews(;!Nݾ8!^~`=wϿ#{Vo!Hٳer[U9w1}7 Uw"a{"ە2]6bihQ8[4kե[gRq1[]A~ejA~tO2ꗭT_-s:Q ?O~zm#GZ`-=¬G狎~^]-*Q܁1Jˮ5j1ˢ[qx.g{T2%;&F<%bMI h?-3γ{YʚGy]cvWL/t 8t}S[z+x+~;oy) Xa $1,וYFRȢVʘR{˽߸YR~ng*̹Qjޚh [r=9YufK={M@7![>( ̉k1h gڊܫ._+WD@w *$LECxH$*M 490Ѝ4 0@M 4 0@M 4 0@M 4 0@M 4A$4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 Є>U[:Xx [Ne5c(3[?oYm*AzWU)pE5MMETnd W lۺJp*v RYu^uT)O kv>濑8u_\WYJfn3P\8ߕi߹s`^\#=͐yfoR[TA{KSNQ+K/c'@9Sgq;7K]շG֛K@;YEk)f9ytOX] 隚®P`.zӖoLPp"lo=nYEqR|Uf6g^Jl i*]-"QT.H`u΢̄PmI̟3'Yt gqB--2{KEʽ: L_gNzFkb/!Iu ;=mLvZYZ]uӼE6 hJY`RRENʗ7TsLzu\ h(Ξ^HY~(;}(TKt7- =[B$ېo_dw('S]U>lkDygPuZM6 zHR;JXwgnM9vI9r/pXԗQj;*vDCeNe*iQEu2U[ߘ RMޑe*{kj{YsXd}@tJ[P`nޣאc[7(+w;~*n˚ۼjBfqr, JZ$hٱZJ׻W>蓠WigWS3s%vbÒY)N3Zg+x^YG ! {$IE^Ȟ֭TA.#]Ĺߥj3[ Aߤgf)ڂgZg${o'ڔ_0y!R#PӖkJ`8rCyRݠe/0%O(YKUV. [sLrg]3py:Te'W;j5=: +K g }/ޮr:qw6eUVy_ʢ)Ldbϐ~o͚eJyS ԗqޗQzsJWqqUKMuŕm!^};pc&IₜTj}{;p-VePƍ 61f;#555]UlNu{K~V- Tʽ: L -6VB8sw(P&o8b:Gn-^bQou#b-[3T,0 NP]"#G?+OZ{Ǯ:`1 %US<]{߬(4{{Y3- nܯP4C]K#W?nE@)+k[W&*o08mCeF*qeUO: 2m2sg@Q3MAqE7S|bęRqd;c$8yb_ҡL^f1ĉ284+Wl)8dvlmr4;ՄLk[MEB>5ꁓu!:Y-^ӂnX7sT|qxi ȫrϗMYVJ|`~+Yҧ˗~`tV+m)EkٲtS>1 4k#!_IVZP՘M,J^Rlb3spA~ͺ5/s}oR7feM3Z_^'U{hk@蚚B~+^mxfug9-J`Յ;QeWa$[*Νu$vm˳~̧b m丱ǚo_cI/OeӔS #vnvJE1o=6-KfyD=ΝG[1/Cİم"r {2Wqe??$Uhy/V}+c8wM_ٲJwN8ڷku+ߑ"K?;v ąL]:ӡn9w_0A 0@_=+)EFF K3/^n41g3W'fso@L@<9EĻ?`bu:}|z{e=t߂֎zv= kk vp ~ࡇԉHWg&)zˠ5>tK vp y>x Ϫ!Q֭khʈ ;?q+*(_IJ7q̔_ָEnuԀ&Mw/BEȹJHam|:bΦ 3 1ffʷ=';Y){HD}= `)>MCm[`sgQ3?5t f(uuuc谰*.7 1!bu" 'Yk2JM'6OYToD9PV/)ƌUojloJ;6y;O$(n{k-?P}WW?b"`Osfs'|/bQ,u.g՛;U.&RM$$&0)[*=7kg;9?pw<(Ԟ;_3S_ޓfUHr/El*gZ[0er{Y 9h2ԛ[SfV.#<ۑ IvIDATڽ$l  7_q%;DDX6l'2"zȶO0?0ۡL>'98P.UBdcDՉ[O+yϢ{0Gq7ztnۙ8ݍ7K +vy>QEh@{ιĞ=TWV=x|o{4~K0gш?Ao}[};S$o}u:F@.ХChz\y*QrW($4l*uSߝk}wqTG{ <~UxZ޾r&ecv‚ rXB[ 0/l`)mRǎZVV_AZ{4/x4*G;*侫$cGVff H ͹Htm )av D7/o s#G:ɓ:ncߩ5ӆ/Oع$»Uo߿C߿ޚ(z8K q!ΝsI$w Af͔&'7OM[m"B@}.3sZI;vq%s}g ,MHWLHfl>,g CP-jr8s^Ď;xϚ4r'Yg=ԓ;3}ytˈ[Uo~r v6^ l>¹8O8_?>!M7l~nź1׏ɸ&cؑg:St/.p,s5Ov ;'/*4hБ#GGF:N%--R~Kv/J8P?EP\3G^t}j+.ҥK{׊<轈?Νܿ`st[qwrdى{ǛוNyI?e;w/'o}[@=]:[B~BQ_JVhg:v"r{H) b+5xiwFΎOjjԉ.s@p"FqB7W5 ;p|uADdx8wy1@_?_aoۘvtקtp~'Ǎ=~s8wA1p)]KSo?ٰqS[UEIDw@6cZHKd1MӉxQݯF=s-g <Ǎ5}iqq]m 8o O;-;#&p@b{,! зh3h `&@h `&@h `&@h `&@hIhh `&@h `&@h `&@h `&@h `&@h `&@h `&"m3t:%zӢ53ZsA7i [hd455 @`&,MU˵FOUlLV'畻[Wd$svW`"cݯE%fKIU}MvFj }JT[ސ;|^zp]0} -?rHisɹm뛫O*()/HL6wy-6{47%^{ši Qy1-lHk^mW*WiZHR}RJJC]]BwWY괧4;MuJaSI8cQ@[l9嶦+d"ef$+j)}NMZ]عmb#?'kEҊk\$4bޛm}:i1{n; . ]:m5蠇sPGo(4mDZe=$TK7u,G1bQ-"6զ/ܸX9 қ]\OEz{awI1Q$g[mp17,o,͟U-R- IL6fTU(,%.uչ>]ʹG%˘Dc:A)lwE'E-UO6ejqcչxn=1otWޜs^mXѷکuR?*Զr~݅_L8n6*i DsSPNEFͬ?9V54>&eYZvK>ɆXGF+2baL( @tcN7 "uv긮4Tod\dsYW;VӱjVNz?EFÒhȲ8\^ؽem1HU JuL&o{Mkq}p uR1aI to hmXFen (_sB6%EJՄnl%dHԞ%1;&ǟ,,mjE< fUN\KӵJM_+)/Om#ޔƐ۞gqhEC|F[/&\:kQy=wI >FxbwyCWc(Z[q!zhT˻ #*.G^/r8=ZU\~\ɤUm:< 6a吩WƤpOs/j0Uv8bQ=.IDAT>*2fRr6Vf6lY&q[&:P3&SU{sF]UMk幁so'kc澡yដzgAJY$"kkS4vY=?}T4z3\%YY/Ե]WJ ڎ6{~1K6˻ PΔÞ~c4o pZq C $_~p 0D~ 4{SUQ'U=oNe, 瑭Sm7YdMbvG@ }9<>1UNQ:']$+90)ofJ$2@ h `&@h `&@h `&@h `&fht3& Z@h `&@h `&@h `&@h `&@h `&@h `&p/6`PA(bSʌ~.hF`!o3׋ؔ:Ȼ˦]uz4"NpG]HyzIte~ Pß?-_5H]0c\y_w,R]ב;n^8kU3O{urW 8hG|-e-NsV1Lpm2Kޭvg{^÷eS.r7ׯqgxp65}Gޢpڀի/ڞwЫ8w!CtLcX+V\͗/yOgEsRܲ[}z_}*5yI-`W-R{vfvbz4$~ ,˧>R'kgnGKTJ]1M<L5,mǚV(>kt)K|Xtz8 8w9 V‘ 7r/Mow̋E ||߾Z,]vŢK-L[ҵRn*raL{VYoʕWe Jx{r[Ԟ/H^ΓC5OwWq@KtMMM!?h/6S<3Oqyi~]@Fwꨲ{Wz0-zN:c`@߉\w߶Y|S1SSrXcMbޗ'βiJ¿)s ;  K%_^Ӣv%E<N#Z_zCbB酅[ͽH\jƸҟGpsq,ZK׭OLL6t/;D>9w˯^qu'zu8։̹%h["uE~ھ>;qGx؉oYX_",I;{XctNz_0o=lj~U|ݖy~f ˌ˾sЋ^pw۸?}۵}׺EV֥M;B.SP;/i? |ДuE#M#EJIN3?a]p9 p "Rh:>>콲oAZ]kG]=J}{;8wg??CĀA3eAOp%K;8wg<" 'Yk2JM'6OYToD9PV/)ƌUojloJ;6y;O$(n{k-?P}WW?b"`Osfs'|/bQ,u.g՛;U.&ˍm|`2$$&0)[*=7kg;9?pw<(Ԟ;_3S_ޓfUHr/El*gZ[0er{Y 9h2ԛ[SfV.#<ۑڽ$lK;ms(o:.dg鸖33/ C%X6lt|E =|s-xz|wLqR~o5wz G[* iYެ n&>1׏ ]\>mkƅՉ[O+yϢ{0Gq7ztnۙ8ݍ7K ]޲tbrk6`Eq|9{.}%:ZЧ1#AX_Y84{m#ш?Ao}[};S$o}u:FsK@lQKy0J3T"+Q$O-Hh_XmV^DWRhQ_up(9jkq(s}g ,MHWLȍ+og n)Pùs vt1д3@Oz'w^}gy6=TmR>秓*$#;34VM8_?>!M7l~nź1׏ɸ&cؑg:St/.p,s5Ov ;'/*4hБ#GGF:N%--R~Kv/J8P?EP\3G^t}j+.ҥK{׊<轈?Νܿ`st[q׊N8w~]鴛[Kky˹sWַ%Dl|٥#o%']09+KzdV}=i_,"׹"^q"Y|g1xoF =t  bnk3EcU&t@򃯎6wСߜvyzzN8c 4K+uuo.w?dg`U/z4(7+xiߟ~*Z|:`~s'556nj()h5a;ЦXz R ii0t:/vq@b`򸱦?S__?-.uk-<`A!]tivthSl1Am&M 4 0@M 4 0@M 4 0@M 4 0@M555 -M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 ЄS4K .у`&m&IEDZF pnM'zmM6-%U%&fz|lvb]F[4g[!3ϳ9<%<w׆Z_¥OԧZ6w5`Sʾz;0rUMlxVAIyANg[*)j5vWg۽;(29"8j8: j-q畸<2OFWgO'蚚Ub6 ڕpZ;ddu))xp٤ wiV] k7CU:f"RPʴS|T4f %/e1(܆ `[J,&>xboN(ZғM:M m3=}a;{d1b%W/a <43*ws<-bϥF5C˩u"O-k/-tT)N>öUΖOmsB6SZj>is8VOQMmxֺՇ$GMSai[[-4oI ;65. GpZW9f"{;:˘Gc{DNRڄާ$.{Q1W+1;W,-2jU[3vSZz`R )r'gvo\8 9sn},0)~r iԼ{m"qB8үزrfS3sʊWSuF^0Gv#& TjQ} Wn?-Ş\ֺ0zQ1o:XnyIDAT=n󳕛7n/bhzEȨ tyBc(S+?D7Tdfw Y+p hZ~G|bĆ0yoF`_S-n,JVz$DL<L =.Ms-`&@h `&@- 4 0@M 4 0@Mh3uA-M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M8Ećo0(y^veFLo?b4#^7yElJSyeӮDs'#.f$QZ2+W׿~9 6~%EVz h=w/^sԲwH{oJW3UXhtm#og\8Rm@UmaU;А!:@ޱCj,zx]+}MF{v|K׼'޳㊢9s Xn{wKj K}>=EE;3};Cs?`zqU|skq ͓#fw*%O]׮̘&cMK+RU5%>,Xo=ӏ^;cq`{h;ŢRoP-.bѥsRZ)7Ups0m=+Z«2%zy^=-jώ$WI!ښ'ǃ;Ы8w%|uAĊo)Yݙ4sG{{N.R#Xu;{uTٽ+f=Ussw10I|ݻo_>©C)9n&X1}˓ggY4%{k}ߔHp]s/iG[MK~YQsV g}/r!1lva\^U.{c\YU8Z}K8U_5JhSWl}Rĝ'N8x&OHS0z4+&@7 ;Oק 9<Hчw76WgЭ8w]V`i_|]'M' t˴q_W_ѿԷ#/,kbg'Bs`uja~}⸈J: .']y"^zƴKN< i\,@ws%$ x RyÆ ͼ2CD;-00@X/e뫯ZVt Æeff'LehJѺHyKפ['M̙x{I.`S8wON?)XXN^^Y] k]pڽ;3x!ubRՙIg2h i8]};3q:~ó=+9E:g9oux2bO :Wҷn +3u8FM8yd*$df23TS)rakZ2uDTC8KLV:,%w-w9=uپX9ͺ_tA;q+ԉޞvݿƲYLb13Ӹk|ګ|}293hrGΝM_'Hn:nS.;y+<@̈\WWN\1 L"rC+W/ οbA8O7 bwu}&6碟%":/mG:W_<'=.7.N]?wO s}`fD^3~kB7 aCk"Biibl"mr|1z:K/6inw[α joBjM?kj\0qB&S}.}Bl͑UN5.F7SeErn^v>Vdomv:HFn|5!Dˏ"zՕSaܟydks`|ͱ2uЍsbXUoJVMRUmV # "*)1LʖJO<8%N-) ԗ٦|}*vQg J̢|Rq6SKI)7u6)sM?8ev}o B>³);[a[qOfѹ3Ĝ*wDL;E$7_q%;KDž~u%X6lt؋S|}k)C?_m '0_0ܜ)7Nc>/ 5'7ŪB\GjEG^6;]OxlAlGl(##vHsc@l._o=߫0gy6g|!ğ8=hРYy3 ){w!3EsEd>|8w:}۬Т|lL˹n@5x4!]39,:'k۲}v59HIDAT{9{bGΝqKvv3zBouO=N;GLϋMj[??L(W ֯}6X@ EI';'醃 o׭X71d;AgnE^%?e .2sE} :r4qH)ZDZE@zy="BR'V8e;?] G"ʕkыU]-ze^tC}Zg5X]ù }.>o5Z)'^7ׯ+vTѓ~tti-o9w ^Oַ5;{/tͷң &geIS#u:E:R+@V>k`Ә0 ;Ԩ]x#D̍}=7VIYo8k@wtMMM!?hz:xm9 p3@c~^W1zWO1OƏ{V%p@b8|S&ҫŧ 7g~RSa㦶‰^#ƹm vcNj׻_z)[^zWlLe^o4{vAQ7i:QN%NCZuzkٲ%Q-ZE\{"G>y;jic;8gTcrzQ{[1X\MþINaAz2l̲JnzZ`OyfVcvnz2k6϶:CoZ_URO.B4O:-ZϫVV ϳ-rZ-R{Pݚ@ܼ[s[hyy7&fKI'x۝[ }+q:➒,2}a?R=_4;e/_$]lqeaWټyͷm7m1k {g5IKMq>k\:1:MǕڇ"{J畵ѩBwNʯnx]fewhcfzkqVa]*eVw߮bEG| /2K=7&ݴXsS|s6nUPsSb>Mud̍}n*Ϫ{a)8HMq6)ܶ\`2kL0bzjӱݫnJ+_[ű[EmtĬrMʕ7Qi1]&%&o9]`KyEcךC`<Y[@׆yr;y9-c3=\1_=^_AݽTPVXʀ\Bx4ϐ(ϔliV7ڪL.td욘l.Q^CYnAb<K1YMƉ^ A]8mL].AtB}i5L*R5+'^7c]y<ڭr8gLuꦵ;2YBSz-t[gyvY5μKngVw[rbrhޤ)n-VZb)/OkS~>)99AĒb3- }?WomVKV|̞ LJY.bKXrb2xéiwW[s]2Fq C^?=kqjVME1'mU;鮲 r͆Di?M6tڄ\n-qA:Hrh{8P1V3=S[2Sr6 Ϋ_S7>mi tMXu0ܣnG)hcslc7.4*%II)~ݲX?v!y9=RQtNb r![7$ 0@MQ^=O~xp$MVĹx Β>onoMy3SDdg `&0@M 4 0@M 4 0@M 4 0@M 4 0@ _m010I  0@M 4 0@M 4 0@M 4 0@M 4 0@b>oxvk۶{{;p 2GbWOy)_m;f2_,į.p՟ $??HwQAĉo'rܻviz&0@L<`P:H? DZc&~G};0yO$-= 7 @soO՞=Gՙ߹>O?]tJD 1% ]}>>h]-#>}3V?([wN'"G)"}Zͽ;מ&qL?T/9wo?:%_RG1x@Os->k/u:%'O@b)W_OĄeKO9%ƚcaƆ?i."gR;}q&A:Zijjܛ_|Q T'{wϿ|sxYg*bb"7khIDAT#,C­I;d dgӆX>ѻH?E?goN)"K;ȱ#.r3 _c,rSXeqMXW4m<;UvܻEΝM;wL0{:"8jFɟ/6qyv>S|xx{ȋ<6v_U߬ofg 1{jn-MV RS'{Eۥ-/ſKy ao1]˫Syliʛ O9k8U. kd jԤ'3.,--[uwɹM~ &Q|se"5߬4|8uEݑqK]ְ$ߏKWڕS#z+ga7_1{}&`0(OW^>Vl0MmXޯ% K6ifC,cC(X &MզhN̻ܶjgn4h\b2sRپo_z]ا}oR-WݽYL|?up"AYS&ݭ|kVt_/Jk6Z#Lj# Ӊ@)X\#eV*#H~qȕe!de;Nm ?ry^m~Ym}o,wF{+WO@b)gdx&w Hj2#BjL e q,͓]jr:QֹfKX秊JrexXYvƝwTY 7ElZv(c7{8m){mW:99Gz/ӻ{>e-GJӛ_'"s4I$bx׏0,^8gq[ѽˆ̰N kg!P̿! '-@Mi\ru@b)zQyG-fgۛaƆ\SEC„xGU\N@b `? uz/KE fˁF~fRtzn]<D%ט}JפzԨq'z}מ{?sH:F@?xN?K/}^^@4qR"i@^≕? 뜳.XxOQ`XW_^ogf \3~|nΏr~t駟. &vh@ 0Q 0@M 4 0@M 4 0@M 4 0@M 4A$w4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 ЄS*嶙t:1ɞSEqZVC=ƨQP7i) X4 ti)NрhҦRe,E-;WϫVV>V}UCb}UIAV>[$YkB7: ͵FOUlLV'畻3gՅ f՚[\\4mof'6ߙ[d/6?ٷ'B.G"WT쩻ZVvp$7oLVAIyANgE .{g[oLkA_nӖg6$7>UzG~"nN-us oT8nWټeR&r,lӟ^]Z0?HV_k>6okPYd%.^4yjۆMˮd/]e t4bޮWhf$+Y&=oya٬rgc]dJWwyFݦyc wivlزwƯ5ުzG~O֊AБ[wZM+i 8=%7u83UU,S=UT[o_us79h ov77^5WɨrY}ҀZ}ݿU-o 37U˛䍘U4ZdN NY\ ^uSs {UߤVVn '(w4xK e#ŌYEzl(W؞]OHj.$0 Cci,E6ua$ۨdcvIUERr;ꜚz{aulm1曛?NYXRdJzoԪ\ j]S*3&˛7*<(1(dEة\,I:mSjۤL$^RYrͦf'!eLk`k? {zcuzp>19Y6Zq|ӵ>=+VpRLwDI7#G^oNQPs譿K$n .*s Stp{C'յ2|\)'5z7%gzj*gz BIDATNHKj]M64py:pwS;\q#lnʤ-51>PFM4dYJzuC޲xu(hst(<5.˵]RNY[XQJ8<<_ȕ.ќk)qe{[5FR˲Z+M&ejFzf1KoyQG0Y.ojVKV|>ǫNh4ֻʭӇ?wx\NQ[gJ]Ub)TzdhTXiTv3qX0IɫB2 X͍.[Iܖ CW3US2%gcUiu֪DMk+˙Yu&=` OiMXwjFԕ7\_8-յ_ Fm5΁SjtpSOynԲ6]2\Q#Sg~첺u^g:ꣀؚ8cgypbVf܀AR&-XyXspK4;<9!-%pBJJʨI3 w9Qhq\|4FMZr9鍦/hfqE1gckFd|#j\"vl<4K@(vx `ĸ*[VrBQ@-[7h+efEy_9R'X.J6 Ў%_p;vlnxwԷdOο| wkkמ{?oY=5&)_L(4YM4`@;b`)t,M^#oDz66,尡CGR@9EĔY[aӹw>Ӥ4-VuYol}*_RG1x@~[[u_׿]@߉\aO?&-=k֠'_}nP|)}'2sS=Egm)AӶiJkZb]b\ak_H{VzkӬmW'DeejЇb)WUU#ǎl 0)Щ2m?v,^3?z-jDxwtLZ3[)2Qt]gH>߈>f׶m|ê[TAt`RSj!b?Ĵݵ&{ e!ƴNtT+ܘH-o!9so c޴`vͱ2cHZ/Է ibϮ=DD+3ҝ;E,R&ZG>V'Y,*|^Em} A=\ubOQ]HZOGb)gdEuwg-R??|. Y:񝫮JI@622uw>Q\|ZzܻwbiSO=x#Y?"M;Z]q;w.ҵqneRuUE)5OȾF}'Z%׌ׯPK/[>@i<=,g I~OT=hxw*5?gwӯIuQF ^{*_|^ӓ u^a?K/>gyڿ{ךEgImoFSkk(6≕? Dn,\|E"10IІlz}{AFYgG?ɏbz`@;b;]D#M 4 0@M 4 0@M 4 0@M 4 0@tMMMxG 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 Єl"IDATIX@FIENDB`././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/ebnf_number_parser_diagram.html0000644000000000000000000007357615134002420020520 0ustar00

number

thousandsthousands andand hundredshundreds andand one_to_99one_to_99

thousands

one_to_99one_to_99 'thousand'

one_to_99

unitsunits teensteens tenten multiples_of_tenmultiples_of_ten '-' unitsunits

units

'one' 'two' 'three' 'four' 'five' 'six' 'seven' 'eight' 'nine'

teens

'eleven' 'twelve' 'thirteen' 'fourteen' 'fifteen' 'sixteen' 'seventeen' 'eighteen' 'nineteen'

ten

'ten'

multiples_of_ten

'twenty' 'thirty' 'forty' 'fifty' 'sixty' 'seventy' 'eighty' 'ninety'

and

'and' '-'

hundreds

hundreds_multhundreds_mult 'hundred'

hundreds_mult

unitsunits teensteens multiples_of_tenmultiples_of_ten '-' unitsunits
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/ebnf_number_parser_diagram.png0000644000000000000000000030353215134002420020324 0ustar00PNG  IHDR/IDATx \g-dXV*(ʊt9 j 2/hjt#4e7Q )zTꈊF<'] gwv;rݝKyfvv]3ϴ3 WN`"@(`"@(`"@(`"@(`"@(`"O.R)-Ep`ux`0N4-EXnV..< W\uUaLrqH_odrrl v039WmwoHܺӵ?҂~-{ᡖ$f圸oz+Uc`0ԾD >9SϺ}j"}Ǭ),0Բ ÅUzpAF.'k{(n2t3}Zs(m )zRΞe%%5vN`uU.R`.?ev_iƞ!qulr]kΣ.7|e: =q 9-Ǎb(?1{hgiׯ N.Я֜~'}|@'yg|6YYY`ݲ_y?p3=,pJ9"p]]*曂u E OIҸ Fn|23-\*d׺/jwmHBVN1K5*E}:-zVS{v~p\C #˜Eٚȸzwu=“Sw.:Xg~BH]X4{I5'T!iM-_'i)=" 7JI +=:*`'99mQs6A3jdE E#t:/={jjP Z:Y&ٮo6=ZJ,9CP!FvسS͊M׶m{ysЬ:v,pfm9{9w=rtv >w98o\.\+P1rsӆG~XܸiӚy5)[|kiL)S]xQZϝ;wkߟ~I*n6m\ g8)To>ܣfOm ;qޢl{)okd|LN._N@Kα7C:|x qޢ q< ZLa&0rDCU}w@FFf׻:ӱcpC(kzq}cG71pj}|B[a:CCB8o/=r7VT/8~^+1_?upAA\8p@)// o列/'NH?҇6u}fӧMM0p-g]8o/wZgON9bĨ#n^^1nSj^+*:k7o-[vyaC?yfFk=~a?K)\^R^|GS-Y_åØ;~p3 Wzȅ("7vN$sʽ%yww/ߦ{3i„ Bg 9Ka5[ @C΢\paGnݺؾ?"UO'?YiS GwZv{:Ka5@ V|WjPR޼+ {/-X }p-Ν{ᥗ岟+ ^Sr[o!?tHsޗcj۶Z`iraw}pr/_82ry_ZM/yB8^rzW^ gr^r=V:@:׈rr%:u$}:9Tr8oiPaiюp`.NvXNˣMerQ{‘9^r=-/[jmHi={V.mV[>%ט۴8?__)f\x_~9we]f4ޒ]r޶4wZi|gvrj{NZ0΢z.h?ʅ]_3א+P.T4ʷ~'9O__"ww]/.\(,,j#y]`ﺜ6wWG]ZK.Xȵ].]tr ;9Ka{NZ0E@ٻW.՞knݺɅ ;5z]ۖٔu9?[TS~5\-U+++'N?v^?6z]ۖGz#?_u]pIIIښ5ry=\B\(DgNښֱZt]ۖ2GXV[ÒKa5=4/UZZ&}nTdmM~u\vۄ{iRįNb0Zt]ۖbG86&F.,Zc=6f]Wzi;Fs|ܹYOW^_RDsWtzii'G$.{M,h#xh0ZgL]7&_4V۶mcӳ>j6y:WIDAT?f5ת9Ed.;Ro0=wըTxGRAzM>{_߁^ڭ&uʿwT˟f8͉ot<9#A:h2盪l>}Q- ۃPڔ?3٠4eAy-1D774$(oHgW^qm_[EgrLGդv6-hS] /wRvI*w<;3gظnҔ+¼s}umoݍ,}\Czb^>_5mޞ+-̚vCS0j{hKmw^^N;̴Η>vh.g wK駟r޵cMGgJ kKrK_x~? cDh@ ׾}ƭ{-ۿ[D [Vfϟ?81АIpmw*޽:7~ŋOnႅ ֻDB,~ oD|b4-EJ/3j6edH?sϖu;w\VVVB3f?tGp|u.ɒO]uU~1Z̓+XUVjRGkO]~gxI`Ϭ,Ӭ*]/#G~Lyk#'m6USVu))̯=W/̒BhPK Bm q-P)YM3GS,Iey:=bTjif+J材;W~L˦|Ar>`azg`'—ܔ^W˳vܦ.ܖ^ ~MMӢza?v7Kֽq*n:z/󌗛sNt_ZWxGո5Ӊg .R.N9a> ߝaS\D`bj]Y0cni*!b4~}e/ٵ JnkHV-x%)rGOB)% W[ou4osC^;eۑiB_5YNHg<ѮQ}\+i5gZ{dպ`OFwQMjj{fQim5Zc &0Om#?AZ>G0֞zRω{fNh>/ԥt4% #nW>r6^SBƆ*^) ˞%[/nl$|V:ZPftMAز:r42~qc[n`yWl簍lУm-]"e`i`<{mbWe t}V褐vg+ZòZjq"{Vj4wUx^ zO WUt*Zw^1g3]xV!4-|ܡ8 ҈j\EϺ21?F:H+ͯ^Ӗ+p#mppGU=8yKpJoL=ϯ{:>RD6kWa}5MEg=g|dSi'upj~˽[/mQy1jAՇOk 1TקKʿS[mk+ܱSg3#èps[`" `"mҪjhp>`ޗȡ6OzGpo]3RFmiFh0pC:8# P@ \8;Z@(`"@(`"@(`"@(`"2 WG 0@E  P0@E  P0@E  P0@E  P0@E  P0@E  P0@EhcSJ%UA)АXuCM.cS.^)gd[ 8ru!#BVdt'@`"lLnj"dьQ6 Vk̗kcW 3MzhR7_ jzq㑾jվ!q+TO 2S"juҾĮ(9qv&rENJT3UFLKE[+S Ow\lu@TRjI˅礌!HU:v(N :4'.d+_V?`W :S})Ycݏ CZ0`t0VSiɺ^3jݸ3#+v=JIrb))zR3-͊#uTmu o/S^*4CUJ鷚[' ulMhTZ`9v:;\O~ʠ`4}-W/<2¸S<|yOL[=ܳھC<2iWfDW}}x\3͉sxy6}6q,;u@NB}ccMuodLy{">.Jʕ=!9Lsό&XnptZyOL[OJ2&πp]쮎ʒb̄(_/݌ŭu>> %ɦ;VkLkYz<=ԢمDK}UO\0ZZXPKәQ[oZ"pp}9zg&"_tpEݺ&w7vm[jl0yg)MXәj*JIқ¬`cRSFNXgеlM6ĺӅq5i ĺiʧ+buBWrW^}aqQ+ K{],#:r0>*{!mCS.?BJd;o׮lcc 0έ@E  P0@E  P0@E  P0@E  P0@E  P0@E  P0@ N άc-E  P0@E  P0@E  P0@E  P0@E Wz ~N3sD}w@FFf׻:ӱcPN:]ճgO]А^ZTTN CQpyy_x#孋/ жm{ys܄ة`-//L fޝ7iʔÇp…WqwW,۷hm۳ggK!AA k){5 ?J]js 5,}~KEZ?Lh)n:zw[{v$dC):.k]9&|hjտ1*O~D.wt*1H7WęgH6'868y3Pų˪Uߺrʫ]-#6e4a;˭_9_ۍ܊}a4m6%lA :xđreFvct*۬*KRGU^-G߿_.O5A4ccM;?vup\x_pqM'4j:=7א5T˂Yn)'fe.py{@cUcUmՕzŦf .dAU팔"qΆVy[O[ $'v7CI]4uvGSA7B=}hjYRE()) }mF#֫EE+輅mizJJ~X z^ ڞԆSvsI2{nHyi2k:qIegɵKR1iLMWfI?Ns0KJ-))_C/?||lG2gg*fp$Fe_x<>NcY.i~Ēܴ@caEryÂ@ yeNZkۖ9fI 1ksMZ{$$'Q~tyr-JϽRKkq0տ׮/O<+Fiʯ \8JI2Gq]:*-yQ-eˬeQCh_y}k6.|y-s5uZ͚i9ܰ, MW4-V6mIަ)JWIedؚ˥RfK]"IE1K.u3Rd -yX"j`'oJnm}3EbXNz$57UWS[wunn3pҼ킿4]Z{ ^-'U?AY3_[\Be){WTs3h5_*dnP"ZaSЭ:Pф(|`Gf|tS6=ORw)\FxYQsϫ4ܺ^͒+JCs/6n+ 8@.+>VWy;1Uk]dbS{ʚ6VOnīb̓WYFl'LhJa"qxmҴM-F Y>ilXKcfH/9|GO^74P5i r3ÒfzI_dm6Yr<ITNF\kڸeO/]:0}޳AC ”) ^+υ^ \믬ة`}a#/\-O!?ߓO:Lplw p3yi|?Z_0W¦Z;Kԝ&Sh\K֦15r'N߄iP赯~jk״$"KثGn9QQFl%K?CΝ;?ܳSRch2@R{xIw&o=vP뮻nHsss3 -@e P0@E  P0@E  P0@E  P0@E Ae0`"@(`"@(`"@(`"@(`"@(`"@(`"FәQjJY*@iNJ]e ]QP~.^k<|#3O @c peQЕѪ uf|]cv@ҁXm٥QЕ%g{N(\![ IDATq`(M9:9r\ޡ@}g2~E~=G/?`}<ѝ(Y\,vrN%Uf, +!X.ܵ!)YG Q2z~a.Jk^G*FOhMtqfrTQQ)Y,'N\\ZQXjZ㕱&<Çׄѥ73>^N#+-dŊՋ󌌬7Z;OV#} 9q=BgZTfUVu#w\ASG]3y#+9#O)ٳrr/MdqjN66Ҏ[ըgd [UlSmgY`parWWv:;t-O~ʠdK]]`ȈXrrūekB͉d||KyEQu2O7h٥ C59њF=Fh}Mb](]Wɩ}YUn.]\),; Bfw8+!t-pІ$H2$uDIr̗ wmTB)}.#_8AqV:86+G޸zq)4*$n8S8]9E]i5Q?JpB WkǬ17&qPpNru2 99}woGR jP>^ o\"ңWiQlMH+-v 9[ŞWJ;^|OzD}5ۘ>Kk'%uV4\ejo QײX.wӵ17f~ȵEQ%hlgZi;?~rOgyͳoDRIn)_Jm]B_S^.: }ryBS>C;hf]olg O O4'+]:ߚ=tiѕfStM__ء`˸MEY9%ҜLUV# ?(7#-D}*z˔Ej]*Po)>Pea+'3r-Y,'N=*|EYSRc(uG4i͝)|]¡ˏg_m}ۉd-U P0@E  P0@E  P0@E  P0@E |d@tY-E  P0@E  P0@E  P0@E  P0@E  D;p ##3]ر?Su:/={jAe0j]pd97R޺x񢀒m}n\777H;uAݻ&MrpRس+G( Ђ>LhCS #G5rM7KÃ`JK˾;6fdf3>Z(  RrܱcKX89jN\3Ř %!C!Zą /|֭go&F3_~iӦP 08\J+VkwYʛ_ź[z C@J4m0qK@ o-[&h%.:ggݻǣG?.pN4^fy>>i·"5iv} |Ϩ۷;uAr^{P@CqoM>.h >Ym CY7~j~}ݮN km#Fe Cq.gϞ7λ~[\p% ٳWͤD.t vo:`I3λ>ܹsjӦ PR5Ejy&yãO<ѧO=z|pQq^R矿?[m{H٦:t9#}p| o&#!|C?ݻoK,io_ݱc fb__lɒ Fs`0adk 4hBw+L9_z&NpmګIG.)=4mh2ہkvSٷt&M~\ ZEO~DN;v|}ɫkVO0~N WҮ];KhH;wH/+yoQț] ?>gjZ(ԇlekR攩Ӝ`+gm[3mCM֬P8 똉'˽3ucQc37mxI\';w^~~$,J%$.g޽ɗ, 8'p۶mJ~3N짟~V._ަoq%0+IjJ7P8罇0o&82I6n #Go=<\/ȶ &pA'cΆ7]PP XsWz'?'9q׿[:t q1/? {0aԮtTȷNvqӌssr%:u$I[VLiCt؟)W۷Oc1ƖU\ͤ.9\zɀb=Q㜁W6 7ed<ؼWrرwZ,ub~\Eo&8o~TW/m* _1W /^_Ν;we As9{\h׶WM˦Lu |;z2ͭ-7Z !0mޞ->$ȮxAwA={OOkrSYҥFK.XkM>p*F~ ޵K… ֡\պ KSΥ B׮];Uo??4yuۇ֞<:S\X| ZdI)&%cMЮ5LsK.rA:&aHVp?'fĭ)H={X֭\ػom~8g\l˺yyӣݟYL'ۼWj܇>oq =}o/-Xp…Z)ͤVZ/UZZ&}n$6&F.,Zc@CエZaVmbԔz7*4іɯ.u-¦ >H\Zmڴy/koJ?jԊw@r<;J.%*J\rct*ݬlkqUCڶmH.KΞ=ǡF+I74|+^ٳtGh%ϴUw7)j>:A&̚ ZC^=FCڰqSuͤufW к8ZL N8 Yv|Zo.8$1h^pcc7RRtA.7ߐ*U3vkV׶^hArG,}\5l@}y?3٠4e m׺9_ w\ l:3^*!>SngCΆd9:ͤ]a ҊIjzW9h ϋVqN8[[ Zu]쭔/}~ʼnI   ޻|ax;JZXT4$ ׾}{t%}n咜3ͪZ}MG_X"ڍoȨV駟DcMGgTԥo5xoֵ^Owp_ mޢ6F- n4TO`\OKfbV|0몤S'D\~hr~ƭ+T)zǩ֝/nu^ XE^vf_sklB9LѺqe9yÖpJ__ճgO]jO8uꔰStZ2SVStfm}帙gÃORG6LRuQ-CHK{~BFXGر]Z4#S?sde}]Xӧ7^ cB9w|jW/rclng4ըTiY/jbF*OX.0>}[P;9P_׵S4_wX?Ϲ/^F#jhMN7 VD]Q?jck }ybn=_7… ^]@]={-֦ޱmӧ5s!u-A?2R;uMmwﶮgn[߿O>Um ZVog#ع?@81Lڴi~WԨ#׬D)7GS,'64?&U/ K7EQ4.^pZϝVÂ*^UU~U 7e_skkLkZ&vnN@aofKj1UiiwtF| ]o_'q?E^^`ahZzuBjgjwVjٸN3)_|۶Rӧ'~٦:t\Yj 29J iif3H!vSC+|-g1$kSqE0}܉M*ktϖ,ؙOIA4o DOO[$kj?4yurF{i{yx4}vw6-h5E,[ld]2͖N 4iצ(7)=4myR=uژn0TutӗClGym۶^;aKSv%sdΙʌmMٳR {8~(;năuЩҋht[Gs7;[>k*mꑬf,A:gGb(%Z!8{KR۩\탃r͔֌E/4QyMu6\:P*kr I^e~NͿ4oإ5?u?w:vxY n~@rX;\Ak߯h%.7^'O,,c7$KWg4 $޹u[tor[o1_?:EKs5zܐ[)Hplv3]&_Z{JĢrjY4KvT=UNmB}5+T&_Mjh@k5ݮu=Dv!j??|w/XˏKDƪ <{DqY{ I4]]Ӱare"5xx'U'k ᜁ .v;_x1'7uםRS? ..+ sNrqh}|B668, rstw]Xw?k0#/YT] J%z1O..[nСCyyTy 8pB~AP?gH*g9-Ȧ\;KԝekBҪ]KV#U<]#2 Dk*PbJG/{ (}$Mڨ8Sd]ttZyO6$!3+)@*hhH U2!M/ @V5>]\X,Z-NgF1r=jmpd슜Ms4b4}}HmUo{)_`OKux9%['G((.TsE|Ӎ;4*Po%U*Ճ^Rga~a~]5%5 j6Wd]).?*%k{(u H:FH ^q<}NJ8Ah5߿z3/gf@~%jγu< ` 0@E  P0@E  P0@E  P0@E  P0@E  P0@E  P:ep$;uX P0(`"@(`"@(`"@(`"@wddd|СC?;V4x C N,S^^>Hyŋ!سSӱSg r9q.m]wM2bڴid͛{e Gm{l0$(!Av-@S4J.mE4ia=ǻ=;ytG\xғ́lڰCaHn,0}?'/@Sp Q^^G{G3́.h5ϐQCFN9w܂io45R!m8y3gB.V9TL]=5yrMk[l@oz5>ؤ,_Z… X\6h ڴi/_874DX߿_.O5A8z4a&hp׻.Re3U%[׮>Pރz˅hG.)) }m6oQtV$/ƫz}ȅ!-k鐠٢Կe? JRmXb\İ P<6l3sobTk^j~ U տ\Ko喿8LS>MɝD%\g}RQjb$BQgar靑a3|K?K|T;>N~ ͔6 \`<},yf7<+)a뎍{}f>bZ`j:.*<&B77Ǩ6WLQqF`Қ3uk]ڠϏ g?`0T^q'C;)w?MSuƑb)ַJĒܴ@4r ]}3g*i׮ZTӧ l?'9qu-Vd]٦YH ƧOv֭\8XpP+|wQbX 'g&nGE&:^*7^) ?rm۶Do'qw^zʫX\{ oH䀁±cwf\A_#OW c 13⵹ rƆ[@{' ;]pN}Ȧ pi} nӏݠ'Ϟ=j[*o|G_~T-p!wAY^鹱 sսNOdʐˣGɣ5e/%pQ6h oN11rayûxb}q'KOJeo;-X7ngɓ'`?1_JbdDRٳ+wEloԥ:u '?9=sV8}9徵Z+OΈ}rN'ks_wh뮻n[)_XbsQAnwpkJjݳc ۭ3 U(tN,^5F۱a!rqw|ŗp);vފY4XjRaHPCZj: hŚs=q&ᨮ5nOr4{]70Ȉ#C;oV\2 @\d,G(`"k݁9_:tOǎ矢Uyyyu} <c~]Eyy_x#孋/ tcϞNO4@P6;wN4yt^MMz]s}O[svlݻӇM<:y{CGykND*.,>уW-^ux_ʱl @\ ޽&N,.]Vr+QwWnOx"BܸiӚgɾ8mڒÇ5>ؤ,_Z… ʼn_55-M}[.M 4|pxmڴy/kT?q-Y[_]"@\0Kwxz[IfMNGA#򆍛lYe}& 7RRtAyyWz\RȌWgV3?rhVk5T H,//f޳AC7JN~[XT4$tڷo_jᾃ6imޢ6mm @/t^__MG.\k~I;vܔyQy0~_|)OnȐ~u#TTzl#RbJ_jè Ʋ4&5^"bInZ`yѠ^{^oQ_c\@r.;vW۾< |4JSq% Ɵ"pRHE>ƬkL=}2g4nnòeyGErk۴i~Wڲsmom # Wo06nސYH 4^YJ Bz^2gzgWnD诲޻7xr.VRSQҏ۲Էcg>%~ќxDx{cmxFRfv)/ ?H岣@ۨ[nr`A#BF 3N}-\HyG{fJ#>3*7^S-8@.+>VWy;-4q":+D3Llk+6=WY^ X6 @CTu2T#!G=뉠[Nˏ gpB^,=)?(}+:_%U*՟e ѱSg.Вؘ|my]x189|]w) !{#h` G<E1 ^_"5 @CF.ԩT8q y왳w-ZyrF쓃t:}ac^QAnwpkJjݳc ۭ3La?L _|':uJ8ÆzwEǎ.۷1B8kv]õKXע`ϻV}a&ƐȈ#Cܬ؊`DV0ej'P0@E A8ggݻǣG?.MNٳ.``hhH/VQw}ʹ:$\E۶mussbhF(ٳgg͹a~%.\xuku{\8g޽{Z|wɓ<:5klN<Б#Y벶onݕcG׵M6'K΃`MxiWLx #3S MXڮ%'L:,{[֝w P$-{GDMJ[VٱӾAbZ!qKhe3K7?3~JK0ΑZ,(<&BBue[0>}\`aj 29J=z/H{fq Ԙ$7z5eaK lʸ:!$9)G[nr`AtmQBm6]lT`0c˰J끫^il"V{ +Wo'Ќ{-)=E;i8(͢dnq،#BQ%"&TJ43s}8/uc*uu7%4 r6GiX/a?,9Z"`ue©\~\ҚK323?R*xtHۗUU%Jl˅ B۶mW<:v,zKknb\~2 PJZ;myc STP4'b>:L,%CxQ$[.;N^~5v\PR|G^^u{nwp߾}ߗ/[OIeצԵP&SN=0~_|)\W\#:`ʤ.в;~Q+ \}p-òe՟~@l%5Y+عS83)GۖP&`"Pv  P0@f_gmv]|Hqᨺvu-^v5`F?#?檫<ڵ@P6B}oUΘ~%^cc_^.c{޽mY%&v,Nw[oͽpHG9'8#1=%]hn*W.Wgj:&h w:5ٷƹүmΛs^+dq>ZeekT*8mڒr+/~|pNw{׸Xss{?|\h-( :1jJ]]%ۇ_]3{lc^*\paYjj=5dmM~uErQwxzfdds#'tl_e|L7wȘHɧUm}&6 ))\_P ||H)1XbzCn'=Kރ0?--//f޳ACoJN~[XT4$t >45[ܦ18մHѫqvT.+R*=zt7;vܔ)/s P mIDAT _|<)#C CggWּ5dn6bp) [ K, [bXhl+63WlRzlDiXDĘ6,#wAHݏ^vM/}U+U!@y\ tǎ?(]LآZKoȂ\Ccj?ӯn}3'ŨƮ.^,+.וiƥ˓k+\y:_!|tX;H.{ >R^MXW΋Iq7-PXRWk3}qp,ssqھG?w^ҷFG޽( vL~͟59ь|_{$X 1ʦ[s|MP˶ף5x.J 4l&{f)jo+^xh^X-u|`ˠVb%Ǝ z5*Lkfa8FʚŵoNEݻC@Q Z:Y&Wzȅ(qw .T7pw.^8yow}+9_k<Ϝ16Kp;uXJ-N$ϔ(,e^~@hP%`ɳ^}URAJO}_~i{Y\3iZ-Qhrթޒyu$S)_I&;<P%^l7'au{P+B8ޝ{سK)ۮz[5I@[%,\pW0Av׷ŴΥ'lLX m?')Ƕo}K]+ mMG gpcϞ8a^+DhDV0eR5  P0@f_gmv]|Hqᨺvu-^v5`F?#?檫<ڵ@P6B}oUΘ~%^cc_^.c{޽mY%&v,Nw[oͽpHG9'v}… SsKWP$lޱsZ)]:0R4ұZglbc+O<7wȘHɧUm}&6FJJyy5 3Rʷ;k?DސkI-G GjK˟l`[T(P;rsoaQѐ;F + 4:oQp#WSKՌK74<zj||}:)?#K~+ GM;7edJek::uJ¸`lO/MҏT=;rM?業Q'3?tFL 1%ir{,*Uzl#Z!}GM_ʾvW|' PݱcO>J%aae/ א$”r.Ц+ L5/83c%.8<[HZo\K=}2s3|{gupswBmYw,@\}<80:ϝ nZhgI3^{l]1)5;W7Z25,kģ;{ҷFG޽( vL~͟59q)xKxu?wkB%MNآH.n\ݮ&l+ &5DZyn-$jOO[үG ǒdž͐G eX2ryG{'h Y{=,쿣RQ{jTN rr?J\… *ͯ}izA/N4]Jfxas]Vfv#ytY@c) F:9x+ )?3'J3K"_77G(1K7ꫮ R}zӿpN΂wOjBpN]\ۖwo{$)JJbG>7ٿf:(`9 o {ރz_q!wܻgǞl_L)v۲LJ*a+ ䷻/u.=O?YgcRhh9qopN1?}o^n w'#35},={{ r^{@+P&Z@(`"k݁9_:tOǎ矢Uyyyu} <c~]Eyy_x#孋/ tcϞNO4@P6w z76J?thw}sΉF+pm.z߾}{v0IX'o}>=oɣhUŅG?zūNyR;vܴa}ɹm[ .zigϪ"//!gΜݟJ~j4GVT?w܂yrk>x_Rٳ qU].\ k 4p6{ ;M\,篜&5Pf҂@k.N۶m+@1\0׉QSliir!lJؠჄkӦ|Yˤ7+nښ e9fMlg?rhn=z$7ld*{5!(ˎFJJyyWz\RȌWgtl_XCz2t_PPg=44~dAOνEEC:8pN Yzp}޴6oQtV,p!wWWP>}BIϵV8zorwܹ)#S*[w_~0.?۴KyrSF#mήk-? J;U1+&-1,Zrdž8b㼪Wy5XdZ'#wAAt"G4W^rA[oU+W=Dq.;vWvjגǔFSyjmLQ\C>ۺ+6cm/H"ʼu7wnb>:,{[֝w P$l=#S&Y+0Tϝ k`9Gf0MIq ^L]"cB6[l16=]4[0>}z P0 ݰ1r܃I/WШ~;5^׈V%ٱGw֙RbscƏ`D_>0~©S>lتwWtQ؏ @]ڱ}#k>\۸ WsM7M[]PU>0~cHPPdסC#nV JGhš 4e`"@(pGo޻wߏG?~\8N:]ճgO]А^ZA@iӣ?tHm>أ͛VMFLmœ={vvܜ;JWr…W6PgOp\P( v޷o_޽k]T^^>|ݻNs}5Zp6'KOHёuY7lH>p]9&|t]ku\( u`0adk MXڮiI^zF'LT:#~I*-\MkpG巖-tKWP$́;v<={N96n ~}x_P{5^s @@^^ Rp \`]!5\_8+d$)Q{<%J])D`R].2M *|4 7w3Geo˺`]e?ȔIikJ?;vk]jݏcTa!9C7W[TxLx&z!DzR%4561aݔFqԘOXqBZMՁΞo"igpe.)x(G*yϿ"9xsߛ4 L}c6ˉ7bInG-1,m"cbW??{ff*불C K2Y\xju&3^ka5؜iia6]l<\]W]ct=pͮMR_$jO0q|$kbXƋ{MM! r6GE5c}Ϳ iuc*NZ/㝑aRn-RxD#co;n 6ϒ%rٿ0Q Z:Y&Wzȅ(4#3#GW}i]]Z2{ɻT8`/?Y!dĨRaHPP ytY@c) x u~g]=d`ܶmۤEr9o[͉#g; `ac%irw pLX㺇G緗-J2,a_}/8&SPM?wqQǯ GS桟A=u_n(֭+(ShY.]6^WϞ±LZ= R\͝Xɗ6_9)ϙ=+o-g͌^ E! P0@׮QPo޽<< s{HHP//hB/faΜ9SKM7?}|s<$WPs wd鷁 .v_}S.:tP P >p=USSs}޽G>}ߧj5W{9Su#e;>!H+{ϓ'55K.&pmm3-;;yMr~ݒSHI5);#;%.\9 3ft*++[n@VuDtIJ:66;]Sϝ;7nէOk~(̬5INϿ z蘡qq 6y+R 0%q|ĉQjkk7~r1p(kQ׸qO__goK{9]"9f,عs-o,wPѾ Tڰ{&jUZ镘+OM{?x3f6^ajFƘ>{b𖆖jVYg[/8IW6sbr4lSg5555 y6`B'NxP0%r]G%~|BB}gZ,7 x?jH^ ¿w)üZݡCFt0-ﭛsr=j?C 3ltwY7H0a-^AqnVU7I{̭i]ץےfS,!)]Q 3T.YoiIݺuh P ]tٰ6{q^={U;2..X_㊣-?ؘ~x)L3Tl>!ȧDidu47Jo4jhSc'O -؞@Kes<6+jFf鵳Uc=b_lJփgW(_]&ciA)!"-cˊR}IVt=oo~xGFhgpdi*x(% ÷UgV|9tD.RkLp]۷\.>,ZKeO2L&6319Sd~0Rv3`%A3ݪUትwd˪ Ү-}~2 ܱcԔ= IoFL_OO ' @`'#יIDAT/u_kȸY}ٚҧkW]]]z G)˒%={JuWNOwx9nHT|[q{]-xe`'7M:OȇRt^QtmwN )h K.f/N^ԫgOX&O -؞OF).y˃K^N$?g v|! @cB 53Jz (7 P0@E mm۷޽PVf0 [ջW/?xkoh#V cǎ=6-[-'2׬y-\8m#>Wc/鷁Sfy|r؃?.^(T*83ΧOjkH+-w=x 6s&+=VeW|9d}:vߏ61b5W W1jkk=˙jaWf̜aZx7"nW^OHknkZ mĹRbS3Cڳ`۶=\[xۈM+*j#Xүwwց,JNN %,`|(eڧ}Qrճ}_Jǚ>? EWo7n>]1r'E$G5VӧOO1ӲӕN<)/[:wž=KŅ \ޚƛ1O>!@I'T|Cw}?73''W٥˰*L K+NNrᣏvСf$An[3^cX={^moq\xxtIQժ a3l0[aWSSgǍ M}KI?q$y7}kT'2GSYY)#FxA(VSGfFvbk5N՜~pvvGBpsNT[:$[7{L[99K*((S3J<)LTE M1,ks,S70 (Kդ8ncIegeqّf޽q7xÐC~~PGk&+W91P8hY.]6^WϞ5J<KjuZ]zx^*_LҜpNe)EC6ƉӺDMԮhRjsy&9urjIIges<6+jFf鵳h;[ N7f5R:hfk4, {(6 rp^6^?}IhݯtK?𴩏ag:Xg͌^ ڧG^N*{|uvib/n2D.K[ԷO_8\|X\WQAptDu[7;`I <ܔѣO?jS.L4YU9$k<f*7Q"/g֚v x 35 فLeFuIaa͝4qc2[@P6z3A>} .TyK}ŋg,.\RvU.`S|3fuhPn'$.yUmsϨ Mؤpm^={l߿ph`WCX(ydarG{z,P= >K)z;mUB`ՙYk {0xР)ӧMׯP f\ 0ոA`"@(`"@(`"@(`"@(Zc`"@(`"@(`"@(`"@(`"@(`"@(`"^ _JV"KV`ϥ>5쑕K %E1*XP;Pu9+&{w2wquH-ir!7-*ܽW`Ż_zӈEQNuT5soKW_>[0bjkk>+`+>/fwWdNnuY[UQ|ɭEic v$whM wuMnD'Pg}*\[1jRKk/WqY]Ϝ~=gءWfx*?[(˜~]&n^ .6-N&K$'XuzgԿ:+$*Y`Su^̿MǺ YlL哽Lɸ9L[_T׿$><|jC~L=0&(uľ+y_% J7 s/e0Vz}&897?G}&2 n"3cpzty\325UկSjQZO}^[`WYc-9p['\9.nJb_¨[ݽ3痸.ff@1-ӿUW1哺~%_srr:Fg&Օ>ywc8GN1U gVΘqipܾCԍl` pX'ȅjQ6R:'if 1KL`}W[W7~79Bªս>Qr.[fŲeߨ(y^vkln]+0"fyQ; ULbX}}M{R3+̡lUI~FL1dvvʰl<7&/VUg{Z&g 59҅ ŹNR h"fF-/6TջM7$@!TVtS!V6~*|MJ2}V̕&}~T݄rUl˚gUҵ_E{K+Gx9v! i^cM_'/Ja=J=Yo;)7̈́'SƜ~ݼfW|4nNNnnn#1+LG2|n#S&_{֯j,n%w/_FKH))"X9 }A`"@(`"@(`"@(`"@(`"@(`"@(B3P.]G 0@E  P0@E  P0@E  P0@E  P0@E z IDAT6n賢/*)?vɓ fV8a ;˟~jESuםoP.]GxdXڳۄ8;;paö(QP Ъ pWgWtUk[V;>or͎3Az79},]ci3{LJ%5JbB_4`QqpCNU9AK}c^&p:uG׽S ZhjF- |lHOH,+VyK9dm;{#Ǎ>o2zuf\?ȝS(s5ɝv7iB̛ouEP{.+G,\gY(2kׯoQDVkz :3sWpBN''OVTTp-u/_z.'tA1 .~{xEqqGAR.:9 1j)'z=P5BhZ#GE?p1HGʚQZj@)&rtI-]ERf>+͎Tmt婃뮩Xؐ2CwJigqW=L# 3T.|*` faݿK5ԍ:jg4NҒDM<$G2P+3:.'yNJM NBr0"6TjoyyI5_͚nR̮wX>8+Zd:6uƙݼm^F}Is4)񅑙+s"Ss9gӂKY-p5 ?Ѳѳ-o~M7NWD3G* %Fɭ^HGdZPJK2%-iG [[vܹ-7pS1nsbB@vZNlTqOէRϞ=+B>}deߋV)R-B}Q i67ҧFI AO߫ w77quF[?vQqږ~72^;}D~oWg+.>,ZK]O 5?\33Qj68IW-?"X;0LU=߹{Rf7Kzw㓙Wyۀ[f GW… Nc|`iFط?ܬ׊ wwwVCC_^T*V}9~l2a͑M3fn=#KtM^Y:rиn W\^}.ծ?Hc@Kr=f ~ɸ{L(r=kfTUx񢥖p]9c>$R9sF\8~]v':nܜo>,X 1RyJjĈr#O<smx{CC*.(~k {RywD{2WwNB 6yN9n'}iiyr=PJGpݵNѬ֟m- < ,y{ptDohtlǎ{YkspP?  qM @(Tƍ}VTW%ǎ8yR8՞7߬j'L8Ab})殻|WE{`hp8ϟWIO<+ٲߣp tIIU>|OPe?:!7>lo}s YFj9}{v}ɢT*6@#Nweeʇ?pK179$ZqAG+f?*!O hQ90?!ђ~yK9|xx޷z丑ͷ#r֍#3TVV69׫33G˝B1{8'Iܵ|ID[Rӣf5yoŋBhP>}rfM&roK{9]q,)عs6lvzudXjM\ չT\p!'J5m>5XjF={rɊ >嫼ZU Z®ll udvNW)ډ)QѼ墸XXf3L 64z(9'2gQ7vV;:9 1Ps3鴰1jFӫ5;Z|رw,,ܜ{QQ~lO6o2uڧn7H/+hFi:thyn\)7&EY+\[f< Oegbk/G~7dt]RXZ.4h1CbJ/Jݺu[rE? %K.>`q^={6_O_u#ZTOS/cNRudq SMMLȝuMf51giMo*LOhTi>ϞüD pV'lϿsb3ivfEZ#vjo?UDztmF~lЄEaq6/DW\7P#2-(%Ug\!g/׷Po-GdU`lOi*|/nptXhmVxMFn*seiTIy7 'M>e5NTERٺe%=ZP5_T U.~>]%*q//Y*5Ú̮-=G*noKt]I7-JS)a?twK/G{ پg ˄8(׳fF9 "_fx*N7rW 8⫎̂)˳|~b\8 ooxhCo-sue%0=(+vw:UUw宁G9oჅ};I/u_Zcc[\`k+-5idO$RX}:1!~|5CcbzadLm6`Ȁ[nSNB*(;\v 69tDnݫקd\2ܡC3U'`pTx/yDv&yUYQΝ=-՞۶@˯ F8ȑo,;;@QN^KXb`({g[U]}J%8`ZSYY|YP.:w~th]cTRC_|)Eq|ĉQZ-9qkzyh?T\pe˚5[lc]s MɕK//G*/Vz*oGZV S'GMuۿ|׋>Ռ1c}{婽rrX۰0B(YKɰ*̦tngM`(;}t555 y6`B4. ѣ[׏x_H8?___~#Z0OةbCňV*;X"Z\KjƩӹsR]Rq]_vnɕjK:\xQpO6o,srɻ7:Ju7ȧ44-_Nn81B2-{V%֟ Ώ&l4_QXx(2!Bai G_/K727&YF]i? 70d1n>=joiIݺuhz6`k0weɋz|oQXEV;RGfךV;k6tW>`1'(/5҃\r謠tyTq5NW'Ӡ-t19D)ku9kLԍ8}LKLXVp|ɓB 91Pq%вs5#3kYXhfŕ/l9 _m0)Rtp~iZ8^$[.z' B6Eʕq7*=h]COȈ?К])O+͎TkG_uawnF>}pa?*H~ఴra,%زto~NK&zd/g]*?jիc´ʽ+EI 3nqJVk\l78`h|<++dY\>"<]yir^ԍۀkLzyys$&/5DV`FYkKΗ:|g.\ ;v<}ꄰ]H=JLR-[smm/^7ЮCRT\ ?|0[%3fHLYPuJ%diG%`ɳ<ݳGPy~<%дMoz;mN?]Qhճ7_=<8A) \ʘbn^3橸XvH['$.yUmsϨ M(_}6lrAa[s`k%I.Jhɠ[nhzOϛO`k"1!~݇xi4Mm[O`>l:3+{:: 1}~Vb! 57 P0@E mm۷޽PVf0 eݫ<574O}`Z;v챹OlohiSi(v`k:e{~qT9O{`phÇ[3$:&߱FDvm [:u$ۊeGٰlÑCG޽z}O lxTp ' 00#-_ʫ r6-yMp_b;{.%6%;#[>T= mõŁ_Ǎ7Xuž r%hϑ#Xүwwց,o:9%P϶8ҷ'*J p>p\tu*vs&д+22bS`6 TQҫAkI7_~shOW\l(-u![V)O<}rw"~(F;}â?$.MΪwF¥ev 2{QXݸcr(K m6Q(w|'%qws`WTM=3®tuvOW5s}1axޕiڞ˔l*,󱹉}R)RĽ9; px.nyZXh]ԍۀ|MFCS]j %qido|0`@ɡw9cZvrr:c]H=^pAR-[swvL/^7ЮCRT\ ?|0[%3fHLYPuJ%dW sf?*(a>t=BJ@6:aƏ7s7`_z};m۰3?ˍҷoq(yQE]\qAцV_A ]m4E}|Ƕ7 [^]_Nn̬ 4(rJiS'Z%l Q=  P0@rrr>uȑc?P9"`ܸYcaCVZa#Ӧ[c¤ A ](p?G^Ҋ3Ugǎݺ_\{>oRѹs 00z/'[IDATLF;uTSro8ZtaMJ]{]vc~GK?CJ<.߾b %_e;EFʇYk>ؚ5,#ر7t/={K^RkBĥNhZR  KwN:+tV<|n4>(k]_|a(ۄo`c3oyyQy}owыE[iUZkUy]{aԒXؚ!c="}Ϛ!zxJ㰏Azƌmnʎ;mnvޮwUa*mXZOĊR*-ib1a|U;("H.>555 yv ol j餢D8񾐐q~>>>Wv}{|iZ#uE-9X&4ju##3u.?h}U<ҟߥ{/8yd)]_vnɕjK{Ν67N:OsrTQP(^B};IxQ`|ɧn2u/"`roPЊwEa %w}>x}z~pM/ ?[ Yx{+V|a'Œ8:wn#Kf@(`"W_}ȑ#'9rDqa.Зy_x5/ ^;c,wL4S9A] 0+^Zq-@j;wnxcΝE+Ysǎ|&872^}$25CŞ={7ܹsRݩKҞ_{lъ#..(ᆲ+U*Uk!{pTp?~pT8;JgΔo/^+Prp_cY͛|К j9JnI poNiAyF- 4 ~[,/b;v(8`>~YoƲ"tV߽~&:tXz7(yoK{9]q v7?i&[aVJ,viЁǛ6[3d3f4;1fϞ={V.ڽ, Tڰrq͔iV]7{U^Zkhy?Y̳O<)ȭ4 5| ѣ[׏x_H8?___+;[9nd˗V5ҟ^j:]hAxP{K[|#䢲F;=ztsrޫWQpMSN-%v45J3J#Z6&.& t2cg\ivw6:Ԛqx"4%<]u)V׻4P64~ָ%z]77zƥjRb_OQ$Z4tP2bp6a0MϚ%沷b➒oF|y^ͮ)%z[^⻘H7fu+%rzvawR߾}pa}V<7JN˞kMu3m@6[Mod TC{3}\k~ܵhڔ]o*S~4w0D_XVd(JY\%q62.m Y wQ'J ם"ØCL&JׇJ P_9vV9 9^q:#f}]֏:lķ~+7|W ѥZm~`;ٳ}ŋӯ[N, KqR!M'F$צE_qA\4]R g`ѽ{w8iiKzWT<LJּF>yW`>C@;F7G|ン?w|(EOrEq0[COL:_~07(h{˻t"Z ְkmwP>{?~mlҟC\U\+>0ɓBaD?C;`Xk%l 3E  P0@׮QPoӽ{?xx 4^^Bw9";vyɩ t 믿ΏO o\p%BxQ.T*@8p`፞w#vw>S5ޚ9Su#e;>!Hc{yF/rq7 7kkk͘iIk{-,kJzMI)q)jI׿<`1?M7$84ھr\Xc鷵fݞ}{Jsf6ڭZ:+ݻu`0gflxw\34.5NM?Gb}^|)R3 F8`>~Y vK/IDATرcRiQ֢W;2omi/ 1 v7?~Ǜ6w_L}j\[\5gkufdg^X. oqlaVJ,60QMך?a:gf3L3+xx5r*WD,aUإUcib5z*obHyZaUذ4s5,6Ԛw #V2j0ޘc;}7=*v {)8`ҥˆً (}\NW+6YBhrv.G2)3:HϸHRitQWpi7`4NĆT:M oݥ,⸍u8Z-r!Ay!F~&8urqЂwN `cnjfEZ#v~$]-jFIR~1Cbri^Vh5.Ts4)񅑙DPzC$wޘ&/啟ʔPUJ3 R"զk;X"]?{zRK5?𴩏-p]8lY3T4:VjI$jh޴9#ncITPzm#C<"ӂRB^Z,Ɩy.ק!mإ ?cTn9tD.RkLM)۷\.>,Zxq GdqTO?*H\˽I`i8:O=UE[bM^J&MX>aY|-˅3}!!-WKD+60ZUwFҼGlKM 2v%%Kl, 2ze Kd\쟔 ƚ*7RPWGhl?qq08-ZSʄ( fWYX*Vʵv6OU[[_T U.~>]uٜ ޮ2{ {Rqر[=@*nX؏.]G%A3K*W%'6a][vrdRpǎSSOlRKm/'' L 0yR{,Lkqx|\gg>LJ})`5gON>a\֛oJK(igٳWK*>v{q#GhLŷݾwGۥҾPV|yӔ>t|(:%ݺu[rŝ-ueɋz)z'l'; s+ XA`ٟX{C`oB 53Jz (7 P0@E mm۷޽PVf0 eݫ<574O}`رc}b˖ 9~ڿ@5Ͽ¢ M}D=Ss-{>f:U5{uA%8 nMط~ry 2nԹPo+9xdò GZO>2x5Wqҥxux+Zү5}J~'lvXJlJvF0mzpm rѭ[76@>G|(YHrZˇC>ӧO˵G~l̬5Ǧ…rչ4ͅY]1rR 0ӣf6ɓfyK[%/z´՛˖5sk`y:+c^.O_DVQhmOk;_gN"#zG5m3f6\/W32ƌٳg˅wwM2jbj7i>oX [eX*/kUyKo6,Z,xـ tة[※@=Jν%z;X7y a^jR%RvD<-xk:;9'Օ?,Gnga\tӟ|͛L[99K*((S3JF:IsSqّjcUkjm,) #Y_'|9e/ o1;ƣw7Ϋ|P.)RcPj>V^_GEE7xÐC~~PGk֭[+W|VdwKtamEzl7(Q&jhrtZ+G2мF#&[j٘`)JSdl OYrVՙ`RdL4Ӕc72ߦݸ^:Z^цgMKLXVpjiaI(8 lfEZ#v6oJIKEr$k^ĬL_R.ZD\q4;|qߕ.t iѤ޽$8w`XP9o{.{)g |w ?hȻ˗C_b\ŭC t3+ `-.2=79pQ< wi^ZݎM0OQfYAݚ1Yow +<ܔѣO?j[IaaM4qnO2.swm U580"Z%Ze*aUG.I qvWԻGfתUg#hE.I$kXmZk ;m/g]*?jӧ{pJZn;X"]yPŋgL#;Mo'- 繻 7 z\rg>(e?jn݄}ܷmö,7J| {,I^дWЮCmҠ[nh OJKL_^@Ӣ>cVOϛ-E˂^93׮3xР)ӧMׯ;G6 ^-G`"@(l˿n۾}݆2L([^7 &7?qb_¤ ako~ Fy-#GOHkY}4VNN %,`|h0=-Z;f8xR"3kMeeegB5yMr7nM`~SKIDATRC_|)E.n;͍`6qp= ӣf6ɓfyKM-{| .lY3=oK{9]~BmpܱcԔ낝;OhgNN]z?~ UZmDp,N"#zG5m3f'L*68c<~5#cX={^moq\xx|DJ+ê0U*Wyi^[7|Pvgkjjso^?>p}!!|}}|}|>;Gh^<~R.I%Bŵ6~h[\9ggg8z/t; 7J7^_6͛L[99KwirjuN,!SRƖ]R(O -3]:ncId],LTEIR)AIIiw(+͎T{)hsc<by#YݧjSp CF 9Am[nV\q@ġ@˺tamEzl7(Q/gn2qVjuBelecJ㤦 8$=} .TyK}ŋgt=BJ@6:a!q+Zo6{|F5ox7nBv۶ag~{YX¡G,IZpQ@KrG{z,pT "1!~݇xi4Mm[~80[^NA"DL6_~B1 pT7 P0@E  P0@E  P0@E  P0@E AU[[+pt P0@E  P0@E  P0@E  P0@E  P0@E  P0@E  PV2dT*ߴ]*g|.yFA`\}V`ϸ/.qWIM؁˹G^19\U<>۽wDZnIn;Y╜^Z7kr|~X դ\cş˔;zM^^b<Ί/jlKxN(/WNχ[֯'Ǧ ޗs ȸTU{X̳b=[.ΗŹ'c'uJ A(B{N _6$F-Y;=8JNe#xX}}MO2gWVgT*Q#M-:kXQj{V{SZln:O=YE[IFc۪҄wϏrS6uř݋F%l\+P 7̈́'SƜ~ݼfW|4nNNnnn#11{rc@(`"@(`"@(`"@(`"@(`"@(`"dLt"@(`"@(`"@(`"@(`"@(v׮QPouս{?xx 4^^`TLm#GMرkM}x1xР3rVwHSR1> :k 0hU.~>]ڳV{>\voMA^jq]:s2}Yﰴ{DH_$5HL[Z @!`)Yүwwz q#II5);#;%.\9oۻ[ף\']ٽ{OR")ONYcf^ngy\{ gϞ1k\+layxӦ+W ubOxRTt9G"K^yU{ {>]؉(/ϟ?/׃] `GAhV7n%j_OQtYKa6:XhL-c<-,4O$ҨNIɺ{5*=b~|mT_@cZW]?S+"(G54+XMz1;%TX(M"d O9e:U'bCXQ[ cǎp]]KVu,8ʫר7Tj |\[&jx qWOW]hY 4:VюuVEٶ9r\׬*֭|NL_Y@i t߾}paq;B?.DVemsyZw6˅\z( 9m\ZoHaFKMfz%^^VO?Uk1p=SW+6O?{oz1ٺ4F"E[\>v3p}f)JWIDAT{e|nZavmOubOcǎ)'{y)%a9O 0yR\'vO<>G33C_lyӵӫOTK.o\?EI;?lϞR]UG9*8Pt`?.Ֆeoݿp}NY֟'7M:OȇRڔ^&umwN m%MzhRڳ US[IrZضxIa&O }g ,lX._~Z#v ѫg6# Gq6 E  P0@E  P0@E  P0@E  P0@TG 0@E  P0@E  P0@E  P0@E  P0@E  P0@E  P0@E wU^iǜ͍GV kF/+IEfpOގW]U%c\-?s'wwjw u}p[g[)Dˋ~_U3_ަ4oZW\VQkVrYa#r>ymNPQ!Y;rS5W9#tW&~"ά:L?j:zdJ/TzG]}rZQUc#,wVdNԪ|Qү]o[rGWrziĥur|ݴ YZ!k9SU/+6-b" }Qƛ\+ϙ^9zvՅઢxCb߽tJӵu%iY*/u^O]՚F>s~}|7MT_{Q3үRo2{B,nX\dqݰR6:ۺ|{9 V_ܦ_rE뾒or~k?f6*[r{󵷦Np1_xy+5vw^~W( sdi~S6TKS_ildoD>Ҧy۹Mz+ӝҿRþx"0(Vߛ$nOfNJ"p$O2={}IN1VӶMK#^66qjC~Lځ1E#M'ήPf[%6oj>}ۼ ٘Idΐl9}%}O뛿!h:'elLe"Wˋ_ΊowS>8BwO~_OĊzYrU.q:qztyMiɦד30 \&YזG^~+f|ؖi<'%l;8*>c}~+a|&7,҇}3̐7jWq~=ʧ1kO5尿_[lt<{(*n|S]ab9 }ѥk>)OiTWVŏy;yvdCQh"=pipenAؘ|yW{}=|Rׯ ˸7:*7WUNu ά(I1A̹}/\d幼27uIkj|ٸN%USgț`Uٶ^a}~HWMZ@y^xƒFovW7MqUI;=II\;e#$y릅poTKU٦.'k~QrnW-kk{ cB;[Q<׽GȻxl}s <[e(^Fbʗ>[U>J=44-:2uyTMάۤ8krFqE6~p EIkņzjŅiv;fۭVrȹ3r 0f|~c*]^$CWQ3Z9gvZ\>N6#WM@(`"@(`"@(`"@(`"dL\.L(`"@(`"@(`"@(`"@(`-޺mݻw 2@z?z S>}(pر>e˿hiSХ %ł֞̏駟sodf Sw((whYkX*?jYtL[oc9 pmtI8o+9xdò G{>2x/DL߉$&_HgA`{% pK^4ʞ~Yʠ? EWo7nB1zȘH~RPb>qkzy /.\xs2 +oi q!>H(1-. {&jU47ê0U*hVXR~{ ӧO ptJ r1oD˽y a^їk`I SMq$ו? ] Y۪vk5ѪIDAT+kFiZV7T[fbCt]HTE5ԋ(aϖfw)*)KPd20)iȸܺ51OLs=/tIrz^b\%?Ѳѳ-# ݩS.^XԧZsQ3׮on<ޢ,6LxzjBˡnBv?734via\CL4kϭ/_:d5Cu~Kρ =I9Ae%yU5svGl#D^2P^m*(Ǹ0´:+ZQh ca X#z慘F LK&{ƿ-k[O<;`gg_pa} 9uؓkwбc__~ӧO~i;ݦUIڤZy.#VWqS̆46" bĕ䭞<{\?Ѓ R\-&X=c9s{˷KCfF͐SToUabHLfԎT\5_subР[?roPYʫR]}ZkgQws&_}6lrߵ_~Ekx\?f^}wVJ^켰Ivuxn oe .kc|@_B*Z{ZEU[[_T U.~>ݺMR6vxy...CR~e]f93׮jAS"Oگ_?J`8 @(`-޺mݻw 2@z?z S>}(@cǎ=6-[-GE NHF 4A8[W룐+9uj'=Ï? P.ڹc }w,1~ۀ!nN; GQmE#lXȡ#rc^>'C ::)3,0#-_ʫ r6-yMp_b:w\JlJvF|V{l֣k-`@>G|cIY>J:9%P϶8W!*J}r>p\tu*vs&1ϐbei/"9`>~YM-햜8yr=oz y| .lY3=oK{9]s,)عsɕK//G*/Vz*oGa!P\N"#zG5m3f6U W32|{婽rrX۠0aGd.=\'ê0U*h+cp?=CӧY̳rpF%~|BB5ꦛn-w弆y 0FKEN)Z`V Pza-xk:;9'Օ?,ǎ+|9G{L.^(9`d)S}psN; ԌҴ|9A2c552-#)Y"(GljrxƕfGZEttQD|X3LݸD?`u0f!&Ozػ[ vfW.z;B˓ѪF7;`I8:Gn]EO ҆+ظ9i۪P/1`hq杖a¸U*/) S6E\U6R%١65NIßj^-jkk=˙jaW:ϧy/\R-6VAJn6Dنҭqř~3:$OžswK璊;>uB؏.](q 493jTHUǫ)Lb7 9:99͙Pb<={ ) wSiUZ*:OO_hMoz;mN?](q 쓼<\rK¡U~WhMv̘[աC_Pn'$.yUmsϨ M8pm^={l߿5W pE % t-mXy BHL_^P蹏ض A393׮jAS"Oگ_?Jp`  P0@E ٻ(_-S&+eQTPQ11 A Pr'RuJ@hEJi QHQr,'AiaxβrYn.ʛwSJKKvב#GNg~Cccj*** ^|YX{}8`@T gAC%_G `˯zJe=9;wW4k&Oj\c;898ٶ07EE~8v8ʅ+OW4h ;vV:t8 a>`dxIO7fWwoރ|Ν;'6lf\7[z1G|ʪ1Ǹp ' @@4Ҥ)S{m++QP%H (/nڼ9esqԕ_469@a89euYY?xѣEr=yj'8Rv/^rV&z{a&0_O<9)dj]C$#7daڵkgop R-2qǭލ`,s謝;_=ǔ/LMUjj$6gcjtCab%q 3P]EovtŽ#"Xh#+x髞6K? %?~hiNHx !Ei:xV`LXxj9Wg5yraggb{Mԭ[78X$Eo@R!gUvr'"ݿ+3^NXr)*:Q4JQR@Ϙb}Y9s`dxIO7fWwoރ|Q6lf\7[z1G|ʪ17w>ԩӯ%|YF4e~omޕ~%M7Oc N:e-I' )1QG/;zH}2OGKߘ?ҥKcݮ0WgN<9)dj]C$#7dagop R-2qǭލ`,C/kg1eiiz ESZ4Id5Qٵ푤q5s\oܴٔ]?09dJbG0p޽y7v\&)"XGIa5*EIgZWA}Ak%5ܾr}@l}6aC c߲⥹x:ob#8soAa0}}z qwwswsja ZA\`pRk#977E9E]{N.8}{8:{?tҥX0:w`IxX\,[lm*Jݿ/_|,RNNz!G9tTHQAQäv4wʗ[YY P@?~|`ӧu;g=s9׏:*/ 믉Fb4 @6b㦠'j{χ=?y s#۹OsƕCݷd#+lzgΜh;u$ p >8rmcF]5nZA^޻:9)?ߊ+?6ݝ;7oбcGHܾ=1`,pn̮b޼G;wNm:̊5i nX/gˋcFNlUc!nm.]oZta> ;? iҔ)r{WZLzw$N7mޜ?98uꔜ~%7h-^vh\dI-,ԧ˹\11К1ƺ}̓'ON jMK? ~CF ]vo~ 7 R+wܚ-x24ڹsLiYZZzADҲ\]׳wO1rqfSvٿ)L 2X줾'$ wo^r%7uI7QVQjJ(IҸW!ɱoYQQW<{7@nܤYYm /ނa^#FvucC>(HMSxHF`vT7K?~rQVK ;kwiRm\m]W70q˖iiҗT ܑU^NDeGYe\Y.J S[q45X]r);Ǹ8J>nIDATGukX~)0>7#;r)bCAz"G4rQZZjkTnV|nz3gC;u~M[ nV'2Z]u$IV!W+}muE*<Pmwx=k,_&tkfY^ɺX-%c+ӯ]-bmӸڞ/{eO{Vڵ{wj?rH^pфJգ~3KRL78Yik_=cK9$nnjb*Zfx=M ܹsgblAW= &~1K*~G$U%q~3EaUju))2B1}OC|zbE fZ:~PX,&֭\?,()* H[ˀZ$ib "6g9tut&u o YUBJe'@a,An %E%Uth☞1 iݿrUNtX JX n0*`U;SCMU(VuÙӧY1NkOx%ѩQS9MUQN\3\'R~M4}}ORq]w:_NShIx?,ۻ}hmb˗#ӯS^#G> @aрx*RgxTP}MdZN;ix;agzoq!|DωOLtx΋A7˴@΁Vˋ3g qw<\lMAO{PoFݷs玍;+%#]4+lzgΜh;u$ 0sǶ1G r{׮ W7-eP}kuォXSO0g<=|pc( F  P0@E A8uYYرY(@Νﰷwtttw[ zO?Ñ#Bڷos^u-h'#<ӯҥK/o_V{\XY 0S8}uSEEŨc+/v< N.Nw:ީ֨.?}u;6Hv[^9#7pdxXN<Ř~]<]WGwU('.}}rljBjLD̹s'~=P^\x̓޿@W%}.AaA;~k d'vUϝ;7kmv)i\wd89euYYY.\x7BW*?9UWy{a|I!SknǥzAʂv7W]3i\ti[3Ž/Yfڹsٸi\ww T1a˯z?LR׍XlG ݛ'/E!}7;**[%EIVIEqң\\hѺV{tXEEKs_uߤ 0s8 [PX8kh_ߡCO?YoHvw}Ԣ)>X \cq}4 j׮P][v XusZcnj z93 ri\ܜ&uf:uJ^֧#k^Y J t}NZ}qMv&ơk_T!tGS,DoMWWUNJZ$L{`oX,5ߛonVfpN֯I}+zm͉m.jQ~3⵹x*h&Ms˟R-r84AZݐ[\ZP.1~B o:!fQVw4+(5^S +nXݒt>UOI zX`,piN Zڙy}T_Kf!/IA4U {n1QmaA>G8Df'{K-ZEC{ tx^~h}PuQ Oz ^d/YȣZ Za /k?>q5|4 B6޻}UW7pکZ4Ea~9Fx 'B)% Mw 󥛘ú 5ي/Ortnm.`2 ,z|woT=ttҠI?r0BJ*=s o{/Kq}%SV|y lZ^r%olFx h -ԩ5oE/[ڞI =[E #idX{G(n^f\ o}=q}wtGYHkjˠ[{18!:u`,07-/z}ca:IRI_ňIMHqڶomeeerq7 0O8z 9r9Qrr RoU6s>ޒ_~:u!ݻ 0OSV{,7ߔnI:6G>:28?+,ԉ'$^= OPvBV|r 7 N5{y_Mrѡ}{rz~8зo_Sv Wn|zh#,EOŇ<>q|ՖAݷ|c*] 0Oܭ[7)1[Ͳ؈QG~%TnI~Ey剓' ur}`,'"71rN\xHnRYXTT+4שSO]`,'{D.SV_o)7rS蛻,c#`t媣Go77)aGrn+K;^EHi70>2Eìmo?/k{&e,{~ڳ\nP\pQ4c~xg 9.Ua:u"@OC)!B /D03QRr3&zZ?(䕹/I~_ x_$.@?_Fj$>zU*Phٗxqr[؈1Ve Bdmʒ]WY/A HX9'j{|Cn;ͷ,,ߟ}o_n5;kw),d7D q/֯spKX:0#^l5'r89 {۶*!@UJ6JKO,9%uZaqt 4iݻ Š @E  P0@E  P0@E  P0@E  P0@Z P0@E  P0@E  P0@E  P0@E  P0@E  P0@E  P0@ډ6&'\eu&H|ǕjڣNC0@>[Ql*/̵x//0'ʵAsBԆ=lT.! x^[ʶ2 ZVgsz'uls=\>Vc[m]yfˈ)hAZL x v5{Y+ylgݶog./5t.j6{"ĩߐj9j9ڍ5M&hi !'fȇL&TYd团+c_њs kuo3\{>}I0e4mhFUүF;>'!N?-:Ƹh O hA "}\́eeeY(oMUyNSk@˩6H.WORuh].B@ 8?2:M^{HK矷ΰͣRֲlN:В qoW-X5\kc9[.?dsK`qzZ%DUY _{ 3!]7OD3ExW\fօƴIDAT3FЂ RyzƔk7hVN "]JK)jr"}i.hY^t4-6ٮrJfk;cm]$Z{tN]<Œe- P0@E  P0@E  P0@E  P0@E  P0@E  P0@E  P:ӧѩsڢ`"@(`"@(`"@(`"@(`"XxN]vGV~:vsw;:: @uVZ gNlO?Ñ#Baڷos^@[թsڲ| u=5%qe$0pYZ5z̞={E[.3OׯoϞ=zwظ)-=]^)uqc0pYTc cȐO?YR$~qdK/1`k',ȪόwZhW_)-Jzr궭_wv>wԧ|ų .Rݿm΢}dd|5:&NxB-,'")_˖)9J ?^?\TYNJܸi\{=MN.-`RM%uYYر;w|`__h;ʳaӽhJKKvב#G矢Ng~Cce9;t6Sj 5=o.D6vksWR=W^}[pҥwmڴyeRhy{v} (ZNQAѱ?rJՐW4h ;v\= xrRF'O1_O]wm&S>965!5&"\9iO?sW׭[7h{ }Vm:̊5ֺ:W5ac&y9,Eݻv<ɔVYYY h 3(J,-=]‚w$[C@h'>ۭR}ܹO=-m (.鯿7i6V]z*U (/nڼ9e4%ಲ#po)׽m=}yurÑ#lfJտ\0F4G/3^;yj'^ν/]$>_|y¤rNz@ҿ<~TXX/HYЮn}DCt,*7ø䝖;G;;*LZQ83X%^;ʰȡcIzk3vp6Rn}}}zkj&G.&9sF'Np%L߄35kLCzr!u_7=p]ŵgLWV; 8wue\шB߀"iRH3 c70>װqREmlsi3|s_6dhs#w6fhH4T&0TcB7)O~Z:lSSk+IzANurHfHɆ`w!&phK.hӦ+/sv6޻׽NN߷b?O=o⅋&T3qP|%JSpʹbWGֺt_.k2}V3ᝪ^!\(E|\Sڦwظ)-]7G ɲYymQG̒Q4|h:_ŠQٳW^2c~өWcW  ֭\?,`p^$ȗ?0fz}JtMTgH}*]]m1dI?_nlLǎ+ɧ1fj+bLyZv)g*{v}{gԨ&_G)hR]+fn;]E8☞QQ=ua8W(%e+NBKA ?OYv0ԓSmKs>˗E $%E%UPWUIޒi_}RTg%պSIL8z@Kǃ¶m䮪ώ_R1xР_e_{1Nx9+/OwݩQS9M\s'JO<姥zyu .Bk[ۮ]ZUɝ:w-{?|sQQu6e׻>}S61 oǏ.M&,ۻCL긎|,RNNz@ҿӯ͊eZ*herHߝﭖg^W|CH9ҋvHvܱqq}d׳CO'OJE ru-k 70q˖E)mJ_M?[^(& =kR̙3B?)ū/Fy{\6rlm Z,,~퓿&*~^}{Ͱ4YBbVf8/}u⚸k/۷cRagg| \{ 2i|wpѻqC=y;wN]wᒥC4Iው?1vpgwݻ s |MNZzq}d 3$XGV-[?a3grN: 3D=@+Ńܹcۘѣkׅo{4.V}+Vԓ&0OϠcǎœ \{`: ^@(`"@(`"@(`"@(`"XiZ`"@(`"@(`"@(`"@(`"@(`"@(`"kCN M\hJ}UP~ҹjuGjڣN-SKgM _[:@Mou ,t]_KmjMtH+GGV;z(ҝr_[t&ki\CO°?.xi*OF __zR<yu AVКZm=4=gֱ9P~F_Je\JY4mЧP{8-WZ{J˽ܧl;U>[Xى%0(V_D yZ4ckNmSE'eu4W"`e~sitVY oS'r*hYmT]][g;W?^rrt4vm͇>gH]nB{hnyrmNƐ~ 3E^qM>89DNL~e%`AL Z.Dck#6*Q V9WG/OMWH5RSui]L}* RMR\ꯒ6D+wΎHn IxfN~þK|.3qQ럦~9iӰ@k21;GVlc+/sSm|t]—WcXY0V4nڢPM{g˿9qqun,&|l}-:bc}*e\V6*+(<.9=r4J@kj)?]*h?\4)rm훊rr lwKNǢ0 I0$+++ܖ8O(` ,hmfRD[Q׹h[6{u-en:$Re(?3S4J~&OUyV&KHtz~Y>QIEF@+j\ k(//wۼ.:L4{Hпdʛ ײX{RegK󗇻V pM>rd~C͞-͌ьK9'=:YT?!pM /`x.;,^^wfwVejkߒ?ߔƹ&ǯ'˗J}=ViA^A\W.= Fi뱟%؄K)k,P٥ˌoߘsYJM뚢 "Z`uhi;.b^fw'Nj!n^ν/]$40%ɅT!k޼F X/2JhiƹZZ%ZT ֮#['+.NLV򃺺k3h҃&ɎBPhYEI#ĕ*IORcs\oܴYhiJ !ZS?.ӏ=Q ֠%}r%7uI{ *cvChyTmh5VS r/4f=RL.:7Z֥]0{jOuϤG?(+Ehima;Zb‡]?=%xunQ܍/`tyRvqO(n<ۣҜ0xk±*Qg 2/*#_zyx>^;r UaćtOFީ;V6 V =zUDK_Iғ$ֲ(IS(GSբ$.ofqbvUX1"6ExSٲʣI-ㅯ;^;C=c+ˏn8@Wag rDz-R?=@,u{sA~C7A6,x&W/i.(+eK#=GDK04_//N(Z*]U .WUxәvW?Jm՟Au' [Qn,MW}n̳ cu͌ԟI鷙ٞLGsպT; "G7><578c dd]fIE~嗽e#3| 3ƕ(מ1NiTSLOרt.+dCLբ!6@!2.ؓ"SK֪cRFÁ^׿άU@ /zuf>mZMnEcِ-=yǕ^;u V yJ4F@!HFzbx RkY8 %2IDAT* IDCh8d _7Cs^ɹ ui\XP"4 Sc<QXRNV Q~JZz 25v"Wժ#+%++u2zn uCUnˢD4'Q,M(z] WZVuÙӧD ՜`)(8=n2 3}]'N|a3FHr>ʋ3g qwZM*l㎥&?!՗.^Z<#9ap|B};IظøRo:Z>G;1RTM9{1פ0̙3bIQū kE3\zYkY[q[MW7m,]#ggD, u{W''[r矧70<=|wKdM`N=z`(`"@(`"@(`"@(`"@(VX:z@(`"@(`"@(`"@(`"@(`"@(`"@(ڐBW$ڢd*gi.t.-2%K %|+mBz]j:L.6-P\m\Zyi h[>[bk%(.uAZ.-MRj[4"}]YUϣHw}mUҙ˯qm-? *Z⥩<+|y~fK^+;hB%ZBcT^^wFwl\Bֶ֕ǕoF˽wrNX=g gIOZ=s|},ڗ2sDC|U=zFO˽ܧl;Uit&RDÊmfl!Ꜵd[ryNϐϹmN[sls.!OD퓙>ѕE4]ٶc+m }2N#JPFLe7v١+ZmitViW\Z%ug^JRuuo\z˽zˉiCRӼ~5\~ sS)ќp!g;n]#Nhs:C4iX6XDT}ege*7;/NL^>Ii!_2W/ǕV}՝bj#^L Z.Dc /6*h}*^Es%0ѽ)7곟Ӄjt;ICs~O=pQm;Qm]$Oe3;'v@l> Eꦩr/.vvNg~PEyָsxWƧfY^thYyZKOqr Z1]Wrm_A=X  P0@Zzh4YyzaW 9?i56!HL@n3C&ۉƱv Q 0@ `"@(`"@(`"@(`"@(BSXN`"@(`"@(`"@(`"@(`"`8uYYرYzVx#Fx:{@;wMJo ܹn}}}zk4YiZ79}J]w?LG*<=b\@Ch߾M{uS.k',gGyAo/L3;}aLKCIWnz+**Fg^yֶˌ۳gO^*/?ݡ/6nJKOWJ8,xXH?/[;֬]{9yܼcǎh!|(9}wm:>C`zIDAT`<8ӛǐ!~LR %IȨ4) Mꔛ25fVYYY CKE@XUIМ՗iJKmn]gܙӗ/_=۷駞7mޜ?h 5>L? rz/\p_?ǏKu.Rip6QFW}Lo'%1lgO{ڷo/f0%>C,=KNKRAfŲeJNoǏ.hYq7(Ge|Ǭ? rRMbh߻)/lsr=Mqr-Ʒdgjf펬tXfΛnή[;|`Ĉ<пK"}mಲ2pHkJp#ZFxӌϐkz r|_[oM\ofekK["{{8xhg^}yj_t_~ҥKR/h{.M~/:T ]vСOڊQٳW^ly \tSQsÇrmx񣺩Gk/>C(b!C7`NRnb>0IX_&`I!Sw'ڽh]U]tx'v;?PÀk݋`a,dhϚ dKɁ'~4)J+W%mNK렰%ۖRnJٳgC1| BOIS^#G> PExX\0&kNx?PoFU2ZK`RZǏŵ^]ki|4V}mU]89}J4M؊f:vdٙx]wOMWV Z~R?=%u>WF܇e^f57z-5MU%|]kG;7l_ΟLfx==5uM7tum'M9o꿇g] ǪtͰk8a:y/UvcO5^Ϫj=<6{އ|pثTTTN{55ַ۬:w`Jk^$*w53քJiY~xunՏ^*TyOVqK ȥve:7{훜OV|:adoGhӱcO}|p_#1tt)]ynnb=FWP~I+gmsN?|fžvO?Po~#|=t\%뺧]SCLc{]'\?d3Gp#kkq辉2~ OG_˟!ҹK-"-R?2!W:x%?K؉̲&t V %),ZХKލ_i˗9;WZieeg_\箓 Ԯ2+]%j+t1VyU.H&pVO-OΦ^j!\buqtFp5Y3f$J9`KL5*DԜȗDֺwظI #Gy:0kmm1d% E20ohphդ~槌g>mnzI&_|mwYV0?{+^[_n$hpأ^mmV5>6C]2:LRnxP>Wu / o{A-_~U*;˹h)pG">.ɩSDiϐ!BĨc$]fLޯ_ߞ={:j7Ԡ"6!Uz 3/cZwݨKyt̸+%ɓ&~:9Iɧ1pvT3*)'Ǘ놡A\isk½L*){4e`pnݻOD⒄]9ƮrCO?`O=}3jT/Zq|3U&2kgru+=r*WU۳rΡ}koh$X{r=y{vkt{oKVu:&}0=>'IkjQ|c0N`cŋ/8{iGGK>.τivg*s2^߁WT;LTYjs\yefCtV9T̸Z~_5P Lz|ڟ{'|!j\^2]>]J*Ã#b#?l Z2RuR+;GhH0|TA?T6,\ϐfiBCwuL }M=\')QiBh|ǰ~Sb`S۬IQ i>$]m$wUu\^! WEYgȅ rqe6ᗌ"m ?^?\T!ϯ?No{hQ=֕mIDATW-zF7Msk?~׻>}S6]di_fŲe-~5+lsr? 4D3[7n,,P IeҾ}ؘwz ksȩ{p~&3~>{=0fv$cǎR7/oL q9'#eu+ZYގƽp:hχ `V]vC5S~0Y^&7f-fVv޽) r# sq,ZΙ?ϜDOIIY~pw4FYY\ $YiUDMQ&OJS(\Ҍ!кY^["˗/.\D(mfr&n򵼸җh}r˪OW<0K2 9q\ rmm?P,@g*~;&zmK m@N֯I]'M\dǽW/-{(ژ˒uM.Sx~ڳ|oQP n馻9aʎ̭d 6;R|ԱF@CB=UBHފ^ Yńu#N Yn0AeST cL0HNYm~#  wd)u8yrRԺHP˗/OR^ԫȑ`nрx*R<\ڐƼ#ү ^=… o[YY `n%;wK=xekΝ0OM=<۴P]wᒥC0CL_l4 ﵃]>>C=

syntax

syntax_rulesyntax_rule syntax_rulesyntax_rule

syntax_rule

meta_identifiermeta_identifier '=' definitions_listdefinitions_list ';'

definitions_list

single_definitionsingle_definition '|' single_definitionsingle_definition

single_definition

syntactic_termsyntactic_term ',' syntactic_termsyntactic_term

syntactic_term

syntactic_factorsyntactic_factor '-' syntactic_factorsyntactic_factor

syntactic_factor

integerinteger '*' syntactic_primarysyntactic_primary

integer

W:(0-9)

syntactic_primary

optional_sequenceoptional_sequence repeated_sequencerepeated_sequence grouped_sequencegrouped_sequence meta_identifiermeta_identifier terminal_stringterminal_string

optional_sequence

'[' definitions_listdefinitions_list ']'

repeated_sequence

'{' definitions_listdefinitions_list '}'

grouped_sequence

'(' definitions_listdefinitions_list ')'

meta_identifier

W:(A-Z_a-z, 0-9A-Z_a-z)

terminal_string

string enclosed in single quotesstring enclosed in single quotes string enclosed in double quotesstring enclosed in double quotes

string enclosed in single quotes

'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))* "'" [combine]

string enclosed in double quotes

"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))* '"' [combine]
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/ebnftest_diagram.png0000644000000000000000000033612515134002420016304 0ustar00PNG  IHDReWbIDATx XTeul *`%$ɨN[nv_7rJܵĶMTJ&k2vYDMrh3Q3.Μa3yxs?god@U T P0@U T P0@U T P0@U T P0@U T P0@U |M1QI4)kuū3&0@ 3Y(BĴP'>֚ BllN>+!*YA)TcN!2ԵAX3 5ⲕqҋQn1e%"54 iƢjT9 eK=q` p1Q'TZe-dHLsWE77.9X+J Ċ}3S'Z2 ΩAU*k U g%*w܃l&ETYLeXrfM9ҬUfIB.^Rq<{4aLC}R jInˇavGLZRyW Z 5dZmK:^hr"jC&䞲VACP%i"3͹xfWFO( g&e?<+e8!JFu%'QkAF:rXmYMеi#R\Tmym)w=fRq٥ˁKYPe P=4>!9-XP+M^n RlJI-pM.^HM 5b~jՀXH4Fvpj2/-_[ `Mba܃pKҙ㢤8OW_!aG^ZGrձd>cلaä4{e6G&O寚1""AKPXK*L rUuJ50k=UnL˖SeտN ,WF^.ϊ^.ZsJ <aM#J6M$@c14 X3T P0@U T P0@U T P0@U T P0@U T P0@U3Tj5DQ P0@U T P0@U T P0@U T P0@U T P0@h/>;x07h޹СCǿ~ >Cz9p ÆvΝ; lZgTlS})} حyyWo>KAmjϞ7醼2үJH#~s˓ٳgЊF[z{;⊾cF;f5\=@; 4J6?qܹC_?‹/826nwpp5(0޽2TTTH.]-uI~;v(/<׼ | GmLݻoۺ={4n0}47f/ 0FW.R+ӗuر-땗O?k"ez-jҡCW2!I>碣ߞ﮻v{ֵ!aCtv0pcxmF'(=*|#]s,KvX ?E]0lg0|8K!go~5 )K.-ʼsRڵD3H||u;kJ^=@m ٸHΝK/ ueeeJxX)t1>=NzɥVdyg_ V |1HRy5}R)}^58(HΜ9륥?EO?P*=? |gsݫh=ݼ{w], (߫i+ꑷLm=үT=jo|2 N|J900pa R)Jov7Lph /V c@u эXo+1*2((P)oj{{TߛxV&]k Pҧ' +{Gf h5/JYD[1꺎;V7&nTp!My066rE:E V%8XOz 8H9?Xt7_} R;]*s<1'}ʍwfАg,L}vawCˋtV;`!F|ixh|E]ԫJjտJ'о| 3ju "J*WT&:sRԱ/sUW46t… x3'\+GZ>?[7g3뭷Bwֳnn+毨kT TMtE)tM4'~뮕Z<ZBt@t]v= .o -{#>ǾJӻT}'ʦo~ф&*N#3{ݕ @M:\^={{AKKKr=h֌ɧ3?p=*Bks+7`qV)deU\\,o"Um6mI[Rأ6hRw=fPF_|ю`Rd%ܬ?vɛ p cSǎ|17W {>zh]5f&’vF»hQ+;ɹŞ-w ۆeGWcyC*y6rKc{R)o(_y{+SaƱ^QUwן=XǤ+*,%M9^: i,N?)Q9u}ӧ[ JWcIV=2J&i=@N _d)6aL{ZIIӯ ~;~wΙ晄&0iiSw%e9ݒπ6:33wvl4IHY*Qh3OBLg:ߜRZ)Fzm'ajsEgA K[ é\ōT2Um.O˙6uU6ڕm7a2 Vjl_"ŔSsejZ`~Y\^(m05zsWI Bԝ7zguH?Od5ʉ'-yjlb]kl(ג W@c@+,T=MdxsM鹍o䋨Ʀ^HuSL;'9)&navg^䇦\pAy9fcF_sBCCj]ƶ֖N9w@GKʟBiR{c|㩷֜Ŕ)-񃅽ɴhZ?>Mz{c?‹/*t .@:cHG$<9ȑx9"tRmi~m%xKcxx/ 5>I|TO[K990#MXpGn"vN 7eҊR%sR/nY"^+ŭR.RE[z`)כ=>e*Zȍx^Ism_R^K޾1rW$sJVpou|;romNٰUoos.M.{;UDi}br˷P}?Fsww=r}9=oeQ9>Ssu߷-gϞƍO|w%v ʙ? 4@Kzcr I OX1_~Zo7~U%TY{뭷4rEWІyND;F R%&JUC8pT7|=;vȫ#ҵm&|iV w)"cE YRxO>L ZOxA Qt+C ?sE~ 6KW_ p,jAWϞCRA('(=Zmn?(wB^-ߪIhqQ0lH@=ۄ<8p5QIw[>;w)]J!Jeh!^HfM{TR+|J/(@[#5yl*wŎt15vx$0nkr3X)#xnђ?~.wIR\G}Ja 7Ԝ{%(/Gzj@T ~h]|W'fD3w^v٥J u#wܹ\6P m о)ϋwR?slkoye޽u]v㻾=yh-D޽vy}< YKCbbu|Z¨GA~頥L+`)j#K;;;f'j{d1ٳ|r̙OߤuK/u=uΝm](AQ 6LS*m⣼mR Wѽh|)KbrkhڂTHʗ^rIxxBB.(uu~]KP;ntc[4=k׮Rhu}}|06Fх4FVgٶw0;Za[_=Xs/ur"Wٓ_î)cG]y \OUk%8Z--o_~Ar嗏JҒ; ^l6؜ΩF+wR~[n}]bz>W8&*oE˜;[,Ưgo71GkoZY waǻ]k7j/~=xvMmJhAW ߹c)Dױ."5ݻwW h*ϟLzy/12߯405={^yӠOXK6ZPϦX{^yqR_N^gbߤ9?7&l;wnǿtZ޺4QaCzo_Wt#>=cH}}??A74D?wz-_t"|1HPS {>o6_s…HToD50ڣ;]aĝI:hΞ=;wP^&hM`SdڵTZ#n***ڽ]|JCt:F N>-ڧO8aСCt1=zh7&k6ܾÜk4K׸qC+  h>ÉivlxlּjG]t~ hv[oٶu˘ѣ|ݺ=W__.kkz`߫k{v) vذ wO`34 4 `*@ `*@ `*@ `*@ 6M `*@ `*@ `*@ `*@ `*@ `*@ )7&j45P]Q^6e.xuYXE@U)wԂ>UhT pIAf^ rt/ rB垸XkNjTM9fhS9)PSLa4׈V^gUK/FŔlh[D&U"KS-9:p69ESn~Q# ḺTpIDAT [j,H4Oy1-ѹ{həVjkK8m-gnY-&0Df*7/yqdXQn}&V˞:)גiuN T=X+ܦbL]ӊ}-N8AsaȢ* ,trČ4}@ pyV~N=x˴DIUgYm("YSuy4`YR}mTn&l*ee'6(M7Ӑbq߇TuBsR:}TUB"4V% h J D&fs'I2̠nrpfR3ʳR ҪdT)`ZriHNNsm6)3٠u61=m\*5-M6N8}RJ6.T~9p9╢}*ʌtf$酷YR*{Ԛ"S^c05O6?웙ioA{i4Z}BrZ\/Wʽd6؃dSJjkrBDjjUSLREi4ǶkPCyIo(esSsZb.fAKz9kML o3Q`YfBLMtToI*gtW`hq3'EIqXn)x,Jv"4X=VSz^[9K>Fշ1AWe#iPp3Ƹ5ezdpQN~m3j4ᑆTe yeQQRԭ[bE lpT{s"c9|yGuJ75 B[ mrǡKLT^hj-&y9K )FKlyŘi#jDmOvVLKkHR;\^RT$uX&mmpߙ;k߮%MHʸWAQS-h#r2_n-Li.@fR\礍O/]BczJ>\"~&f=ט]I,eTXu”X=['p؄uYTmԜšݦH}c{u[SXG*2&jj'pBsAJhT]S -X =&n1cRd#,2cGI+I `>!aG^ZGrQ!R[oxԎe* heY[l>jƈ*--fBc-/2!49\WVkkU;{D8f=jH/*;N,rjHXXĈ 3"SƄиl9UZ @k$2?ɞ~Ei_@{Ҩ5`@ksfN8үdK4 9V@Jh J&>70fI9Y+me@9iWR3X$mIaic h P `*@ `*@ `*@ `*@B@5Dj@ `*@ `*@ `*@ `*@aحyy>kxlqMA 0@Z>?0U)<1'sV? \tqRm&7/$#l3M?Mu.]C 4@U T PXx]tnV]-Λ ֍Fwm᜜ѻKh?-MuG֖lK҈fSn&茱w۔ Sw4sNEE3wƲGڗh,'EX}-sM>y1ۤccܦȟ8t^I*.cl@9Y }jcr:/:z\Ҽ.;WV,j*w~Y ׻:uLcpnеkz@t}KűDLãUوSvY4:/=j.w)~=|sb w tWwgH{c)ުt,Cn,7rN?)MQo՟+ʋ32  N 3M`?)kpF.EbJ^VӕSX>k:Oi-be|I\OD>G):N؎ӯM\tا~Ɣ#mՋy-f};wZ2|Mi !Hn21<2gjtۢ{jmDFʁjm{ ϰJyQ-nKyonm5nNRB>kW|"6xonأ/~ @eDWZn)]oJKi \Xm7a::5!nuR seuQ|xlq,Y_~^xŒ .,I[m, M,ꏱ9-3DGڤ9"t)j╦OϘ;{dRdgq.gkjHш Fc>G7yM5Eg0~O;o:d2qOfO@]1#囗mʡ4 N5wna5]{F.u"x}gּ=vĉר#_[JPy۶}qnRf?4a@|5NKcc&=\VV6j={*/CCCf< 7\߷o߈l4ٕ~UFP§p$%) h _z ٳg!R9**hϞ=EG-o>{GGGGY?B>};wRnW[n͊e/1Xۢ0=ԍVI_]ww7ŴZH&;[?&/o _|_/c3_~e=\7^꺫D )/+/ؾz-i?0e괽{Tŗ@ ɧJ/{=O/̙zzi {(>V\Eӓ :@KM":tKW> Wך}k#G #[VqqG yF)\tER/C~)Zŗ\,1`.G|)Z@u5]}kQʏxD?)*-mwc;vJ9o۶g%7רB?F'.U>K7 %cc#JA7ݛ/E~ARlp sMmtͯZε,I]7F)eKapwMΝǹ:60 wEl#ïhh:^7/=ew'w|ܘ+ {ּ<""\ mT#gfsË 4@)?~=|sb w`I.]ֿvQ.T_tEs5΍wGZ&}t n50(P_ܵkʌ'O 4U@]c)F>}tV[߶rgX{-F{?}5:xѿ{hO K;|;r;8q&+ǽWsr%^`*Xƒ["W^Ͽ%%[zM7m`>ݕ2mݍ&4nG~ᇞ}?^|cnmn>ȭ;w|] ?r…G8p@*ɾvc@C p;rON$?1񉒓%u0W)?89үJE~hGn_m!4ݺ~=?jӥy T 6`5)O7sLj^,YSMglA 𤰷LNV"sNڬ>dSJ:{܅kBTߵc'Izf܏SԶVG4wa_[Rz]Ysiވ7_šCz8axu"x5Vte;k.KE0)[[2/TxzlpS7W#Lã>-һ;A1יYe.zQea["g}SRbMZUZRʭʺFUx8]\ޟkϱ*j?w!_ᩦ5Tﭜ%ycww띻vX@Q`#-}iÆ-"oV1)9k2\옓Bδss5O~yrO3Tg%'j5sSȟ*:x佑WNš*],hZӠAıteI6n/jG'g {}IUNN\CEt](m0U>oXѭӠAU'4ԽVgr_h8݂ jG9oTo#d?PR׬?/?‹/^paIm۶o`@M|sŠ)kY8Z764"tԽ;sm*o1s6MrGnMQ=-4"tDqsC(w}i@m|r,jmʑuFr :U9ړSU5v3ʰUܝ}CjU}_cUe6Vm{_Q_uehʽzSj\j#]Af֟f/[\)rE„E; X<.\:|ār߾+ @CE:tJFfwT uFDFTQe5$kp{3xA*CjQ~e:&fR/P]vպkWǏ A 0T"pEj:W TC-񏊅s P u)..Vw;@5P .@bIITM7 Az|;?_|AP0TaOBCt:@Ml6[3NX*';0R=ht k׾nk^;v kȑ^%m~Ǿ8tHpyn)OJgyehᱱ p]Z^.++5z̞={!3}۷oDXlOJC ym*F#WSxsk8GߔK4/=ٳyqvcAǗ@7)7((UHݍJa踫+h4_ Ja$RIDATB5>-}gϞ#Gշox޽#Fܬ!R>};`7EG wx+Z-fŲTm_ ]N~^씟~I/>q=0U)<1'sDǗp~|Rm_/c3_~e=\7^꺫D )/+/ؾz-GT:~m_ܽ{w%?p?+ K}+zWNVF_+8j䄑ODbiKW]wz4~ė$? ԡC_̙#c#d{)V#k;5 T^z|#G_ nR~X<."!K.|s.G|)ZT8w$>XWe߿wM˯OR~vj%]tYE /R~Zչх7L`PXG[>Kӆ *˹^O|hݶտ+׮Mn82=sV&.RU?HuRϾ-FCR wyG+/ Tj%p ~ywysDG'4e| &,L`?s㍎5+7'FypW jۑctQ*|xTYwDnݹs8(܎\|œ'I'JN4}_crSv8i=97aR~prb׮])k:ᅬSR_߸E\~hw<^W ȗ"PC#untB pr٥f\~wڻֿw)W_~(e%_s[L\ˋ)ZO?۶O3glg3g<ק@ 0=J]_T姻><9wN&]!hC_'Vqݵ.|[~s@ۡp{k4^:5wug050=`!C`*@ `*@ `*@ `*@ `*l6 `*@ `*@ `*@ `*@ `*@ `*@ `*tMfNTҦa5%Dj\[h" 撚$E+J6ʍҵ$KDc5a뾩S{Z6KA KZdgf+pM*-.޷it}YWBl?;ӍEyuiVvxIh1}ҿ!֝(6n+;u8ՌaB%Gv\k{xE"oDxM\ LL3%վ!f^l% o}WSh\ pIAf^MzO1Tv D&-9շ5PwiF)nP2 G&fZj۔L}sqҋ<޺S )!%uLwIOLIO{4biJEFx )]̜Wq,,ٷڎZTjKLI7/?6p7/uqkV|Jeό˞6jɘu_8'!r|rDn|KJs[@gO~VOc-2v慔|Ӣ[Smƞi>ĭ.nY=sjh4Y6;>~a&osIAjQ 9)\Ialv=;#gҺμM#O*4YЄk$Km[RjHl"ĬM*Wń\[5ҕxR@M*ϤU?l\4xDmuL˳;pZSe孯vɝ2nwXQa,p7IT\TCSZzG\!|pKg%Mb/_utgN_f'鬉ϲ(ͯ \rМ:xJ-AuXx(31qȤr!Kjmۨ3Zh J76NG3赢**R#tZCTiLLD .`sz=mĤUo,MΚݧ$kVz{!pZfjjHOe/.Ok9!5Jsv4.(*BNKODC Y9BEvZNܸ3 UOfh iYƂr}Wj쿤}sONLI1Y4IZMl?7"PKSm!ʄR+*\cXK&nr.g)GQf 7M3t -KgN&>ҞDžRٟz7$8(2Y =hڀz9U\p*Q)^?}ѩےTn=d҈js*- gXgu;k4,Z斛U&DG(>aIVt6,.0)S7421X`-:qp~٣`KI5v,(ܐiؔc?y͒I1 XSjUwO'[|~VN|dQBEChhhi QkE#…Gu#p!7(T#Ґjaϑ%)q1Q~>rc{0g-N֒U>Ԯ&A J_Mi&,K,9s /^ٵtdĹbJK6D˯F s2]gK r"$$e*Ru,d&O~1pIzb#T4ސzo1%% )VY>-E%nW<3YA&D FV5'5U~ l6[=K)!vaMՉrKA7}Ki=KXu¤7kNBzXz5c&QQkNS4CT]:vaN YZ\f찦MSN8ϵ[纇ZfI:7L1! .[}Y2CgvMzO%Eiھ3 ^4fASRqzk`P]p ÜE*ˆiLM6R`XXQf/?Qf] O2ڱlBpRs|گU3*{ ;{U)1Iۜi1Mqnu.9iI2srW&ȐYtx۵6bĄKI7$Pj*@ `*t@M%D!MKh9suqWؙn,^Q]⤰&d^`*0@bIDATU T P0@U T P0@U T P0@U T P:KL!#T P0@U T P0@U T P0@U T P0@U T P0T᳃ss杻:t'ChhHxxxkɉ={j`jqRO.\N:LܥklϞ|"/~Ws^&0~L~hwcnj暫hjQRR/\Q"ͿuB*wo ''NeJ'ʤrΝ?|oӍ7F _C#?~ݻwߔnkv7~+/:t> ښ5/O* &qm۶[xjŊ+G W =RxLoq#Dw]]E)?(U5/I[cyÿsEI{S)%[sԌ*@M޽'MWA]S[wnMpoc&y' (b޹s䇲׼ ޽RPRZZW_)AGo6fuEEDf?+оY::adnQ5}N{ܩ7&%NlRfqZ|RCD5 7vcd nmOJm;~;lT>8&?tQ졨uݶ+[vz5rጱðm"Z}Ӣ+++{bޟcG{ehh+=׼sRERm`i& R|ŮrRhy[v]KĎR:%l rRt2gM_*'HulQ5`BhǏKyusǎS&dXY_IqqR8l`KkGJ+/\G*nzxmOh*R+r'U;w痼vm0l!=z?|š5/O4OxԜsW_L3zG+AWoytMD'}|7SUYbMrNr%hLkÓsOZռ8{&eEU*w35:ʹTΪy)=Ϫ_Zސgҗ;NBX+ZcJAR*OJ~Rq+?l-xT-@?=vjN$Gs$FXTӵ@ZiO}zajg>qlj}KW]Ӌ+{_/Nob-{qNw;Ia·r[/⎹or2)GWꥨp,O|؋unV^}[WOvh;'u5j{{;)|RT^IXޤڕtҿ|m҆ Ql9Ǥ/ _f\6ȓmH߿kXԷʬcR=φ{.*OD:iiη^SV%:g11/\eΚ)r,'Ν=׈>k{vh óI ?&?PRs=gsWJcҭy+պ46~ UCWyuT9$Vxl'/x{;rѣǎ}by/J/Kv, EIiZr}\cX;^q=l\E5sJS6jkS{s953OSz'*]~h9-Ɵj.űtвɴa{ǹحŦСUld ǟ.]CG0{TXKKʪGg$+﬽[ƎO}p);R/ -[# $㖯t}jS Qk7pB])J[~#|7rmL\)`Gn?cܓMjOBfkwc ?_|! @>)c^)8qB@Ijttލg޹K)pڈZy%cŠ䉓Gp,_<)-CCt1lm7z5ED #zYb;f;k'wӧ_}֋o)#3{ۨ#_5S>)*'U+ԩS UW/:Z>?g 4%\[m伿qhw2i %|i֗$44T_< U4t])|qP 暷,(믿^xT0 wٓZۿ_)h4ax0ОY~RSN_;rE ^ѫRaay0Ah4Hpܹ?|M~ I~1mlڒ\ԉ չ&l6ۤ}#8Yr~DPW2VtUػ6󟪨+++{bޟcGBCC^^BAR{s}3 :DӣGǏwڶ}IDAT\cǔ^#0NӧO \뿹Y/x&P[oe-cFw{G&MA 0 oV9 .tw߽7pk SsL(DL^#ڭr>,-KUNj/j Y_ˇ'[l[un0Mը[&2TOLIO{mVk|[kV|PeTcN!2ԵC uoLH3SnӤxގȘy>9BՏ]xR^Es{,ΙA-Tq}t)nK&dAKi)i֥ `\\:;*zүڛ*߽'g 4KKnI[V?=TM|s/ڴԵnV}%pPKV˞7P4_9E7njnY:9G6T۱K~s/> _uT^u2]uHMBN ͞Mu cJcz RUȘٮ_5N4qYn] ʄ\[5ҕBuK򦆌뺎sԓ3cVBPeI9wR zh!r-9Z4$r$'PI3ɅK̦dƱdh(l)F)rn^پy@}3<F %a\(ѵq!|бqwYIK}fekCy4;wdj$#d|4?15oYR [&pº"Su+738 P%9fxlrZ\)U}8EEO5V٭OaAc՘iҒFЄ}DҎ 12B&g:%5Hxl=&5PcYޚd8-35PCzKzZ9ޥ"9Ԙj]ej􂚫ؙh&1ݭRyҙ㢤8OVR)oט{Mszc,D-Rұ(4{ lo="PK56XeLEk%79 ԭ.4x{nT$C`i N寚=j`X`95/I h}Z]ј F& B'N]6{ct})?t "#M5YLw,pk&smyuF(]'?E'ٙ0B8iHJ5ZvTa4D{.X\m4撬dge'%nV,UcۖNq8(9O@ I=-1&%ٯ{ȴ$O~YV^b1dڇMayL>djJ3h'nͦKrO/:N~Х %*ib1'Q;S+]9@%V)+-*(hƻz%eZ.}NZB|Oͱ{jҽVY|Sf{1! .aY2]CZ =L֜0&h'p؄uYTmTT.JLItk䰫apN[^_erȌ%isz!?ǸܒnMRZϒ#V0%ڏQ5C|{;5h,p|KJ5'!r|vqMۺt]u]ǹ6=oH#kg _69$l٫OY3k<`ƛBEWh?53{"S!:yʩ!aa#&Xf2Oӯq]p 6(lRnu1cLF4j5%Dm⦬Llh{>_ܚ̙MK"hs&%N Md6Gh*sh `*@ `*@ `*@ `*Pg>cU!P P0@U T P0@U T P0@U T P0@U T P0@h***6qk^;vWuګ]^y 3 jڙV? '}qkX) t/ >K_:=9s9u{|痾h7F;RVV6j={*/CCCf< 7\߷o~W]թ-~~vlx7hT&JUW2>~ACF{!݊wMJC ym*F#_+)s~Бʁs Q0?4F{ƛk\M~ᣦ<vra)S/\ ֨Fpn<~Th;t{w)y} B 0?d MJ zu*/ȑ3qR^r@[#f]F0ftUW_x+'N)_VC|?&*((P -a;c-xI{?h),ݸq_eޓCCt1lM@j"zBΜ9sQSv/\^n-K_ǻn|5s7A)nּyyRaxl쯇6i.:|~ވlKݶOt@Э[N<'Fg^eЮͺ/"2gpr~,'1嘶n*Mj믮?N4y z?IDAT3+Zb +B)|'EIV?9)5#nsԉ&h{W MT{ɮVj݄HZھ7qk>WUHp^ Qnw8 Цmaz|5FRNx,!cko5w$ݱzK_*+**2UU9rh;`l<Mwٿ>R0h-?ъRС^Cn4MTgߟ{^і.\p%%R9[nh\ǏK ;thzXܰ1QW@Uɏ=?|޶mmNd !D;v(/ 6Q)_SxR/8҃ݬX74v G}Ct:ᑂpZ77Vw5F_ v< xo~r4 "ۂGFo_蕌]v V5vTEE@bF9Gb%ZB6Es'7={;0ƬHw O+4$+ΘWF m`: 6p!g,{ZcSQ-bK}[ѕW^ry{*ϝ;K^6`6t]L=/@6V? \tqhᱱ[l9ReԜsW.S:WV, hş\/;a&1uQ5#땴TgN5qNocY+WjrK{upj$ۆzT?~ʔϥrGRt>%it^}Nn[84޽{=zTxEn iwnJ?IՋVisotK8hduY/59ʍ亅mG^\ռ8 lߦU;om/Uc?^]Bڑ,H4I DEׇ*_fO?cς:^L>:ck; kz@t.8B`Ժ)aͰ3O3ӭ>~R=Z_/):v^?kUʍ)kDg ቌ{L:9ĢItzҰ9#G>B5QZvր1Qi u"y&ָDz;{(m83Uyn]x,t.g=)7L6^/1|lFpyoqչ=(?DEE~B gGZGWcyQ.T]]wR l?dZ;(vocB݀:Nur=h{ZsaA s}~DEkz 7olpxG N8!ЎiApX}w/EJ!44T_< N<>{Ja .G[>Kӆ *K/}$)iG7^{rW  mڵ0k!vQBW꣔_?9P 0*\bߟ{^) &FAh#omV+N~lheM[Җg<@Fر+m=ٳhS8Y9fq o`ᱱRznh_=1ϱ#`㡡!/U>A3Μ9sQwt\ܰCt:w,o:~ym۷o5;vL5q; >6]ޚ'_rfG`h _ҥKuokQ.Tm*~y5%0|LtgciڰCк_IJڑ^|M 4?*@ `*@ `*@ `*@ `*``*@ `\kIDAT*@ `*@ `*@ `*@ `*@ `*@BkʍMD9(M`M+m(]'."@|/V Q:,\{:&*I)3X$@ | th?ӱ4/;4}[YxŖ,QMK 2ZMy5 TOLIO{9 *4)Vrš䚢M5"C]ۏO1Y5`_#.[yP.SVZ!Rqn9 Hf,*oJR2 ,Yq'=?Wˋi oF9Eϴ 8B™}M~]w_GK)U3(ʭkFPdbNQyAmxRP>9M> ײ%` p1Q'tTZe-dHLsWE77.9X+J Ċ}3S'Z2 fJ\;bҒC?j\J_mܪcVIyal>q$dydSJR ׈`MOT.9hɌw|P6>l#YkZ`ʳ&+U}fIRy(? f'?viuCҥ6#I_9;lvf.Tj5Rrc@ UbViAV |Oơgc62 稴6@0Ϥ(J9⍠M (L&* mtnFq*uC<A 4#Q҉7ksi&||o^>|?_j3z;W+F:Z\˪^R7f-ZV7W#M Mpmnnl-*y~yJEuM*, C S{wmu6Zg{bsR䐊"]ң3jF777YSK8uIg?feoy6QFJժqU{j^m+SעjTy[vȱt9|W䶯_gmXe=WZoqo\hNS_?й'@;fܙJMIVkeuMaGS􅅢( @$rbSm{?:zPcêES|tgt&zW{wg.UUCκrV|}`hՔ-^pi~z%&βbڤ] _t#P@/?{lJAQWX\nw+ 1_mB[j]fiˇqyjz K|9TZ]m-sa}ږ*MZ-F]k̏~$3\r?ViNdpnSUvw?pUUm&E pj4V˕뭵KZ/# $+~ XmSo<~REjSKy|nr h87_0hHFKlcF`CIE~ )(4f7mIU;\ZVg7ӯ֮~&\ ֐07K۲}Uq6Einl ׋_6{eMrn_zef%ዬ_@oයA^l<.U κD5gs/J]e}z+ 2&3`!Z&}̻E[ZrZ(=Mɥ_I#@`] [j./M4h`4 0@M 4 0@M 4 0@M 4 0@M?+ "5M 4 0@M 4 0@M 4 0@M 4 0@M 4}[w|p/; '/o}vї 1cƌQGn];w&]=,}Iq#{; csƊ?n-*.`B>|n:wܲS#6xlQ1]t]uײߚYlM"|.Y\qOKht u6o!ao^^v`>u`Ozu"{:}T{gO?u-/oU F^ Ά[UhltMwٮqal]"-|"[MY6aP`=w ]d2事Ҙr<{yo^o˃"U{ Vզ.,g0ĚrLtcH$M9covKG xcք29L+CzY N_۾D(_[3x`iMe?jooHpBKWfwu"}q`HFw0fHt{R}5vknjRKwYY|\wVX,Dq0"!],ѯ_Fo"tr2dsoseZpC}O:=6iӧdztSNGGG }zB/abY]]Tuy`g^k?gPF 0t5bXpϿ$r=2fUR]H`ܱ%^6v7@ZJjW;-|uY:/D]x7>;q2|ŷq=|x`\^kّ{_tE|D/%Uu]Ӫnxl,Bʜ\ND)'.x~Lcj N^ExV\nwЩ\,|uΰ=VE;/ð'N^¦nvn~! ͫj56ԑe+;䯧7ڲ*(_|ONR}NU*5H}+ p{mVM*_/$eJC)EYYDܓYz-OpeUk#7de{pyJЅw)팵5bPD_3ick±4K@n(~rrEIgv,Ȥ+oʉl*VJ_k/ e`2F|W˃fՀ<efX16eUuQ6-/mƱ1_V]zQOt ZcL:>bmrwy_ l^GX]rt*kS6e/nuRSrT{N ԧy͎_% N;OK5lXwD'Zv|᥎u" vr=g-확sÖͅ]S"Jt<_iZN~h+tsCjSuK}'q̘`5C-e1)]BiGƷ!ɿ:KV*]υBRw7@@ kh uj|6eDmwرk|Myy64m@'+s55N~|{ ; MMRvNv߆tO+=dUBDu;2z0 'ƾwz?nB1:J{ 礁-7{llj_TP\u VDzCaxT.ίnY,#;RvrR;/4&^V^|G&*w&}UQ:5t>"Y?Eײ! v}R_NPPZ34pՕWn"I(9mh3gL-(˵(Ms˱%3's|_WgD;W}ff>e-_Juxk<.zPijlT1F|6+̀S[2 tҝ.{ȫ|ChjbYٽ߹?4\Tݞ3?&2mCk{?\z?k׈](&Q  Hfp_GRMO^w/{ۯ.X!i=~qIBTV@VhqwXDoU-Cy&d$T⪵ EFV/_y+u9at&NKI^᭫^wW_QvomMMSs:1'X; yy]֋Rq\Yw;r[UǼ.ڼvWlP hG5-v~|fЉ nQƲM[KM~^seыyQJ P6-zvCf6Mz teJd9\_S3Qk)7]oY'C'NO̎M'|[bu]5Z-WP'zfR\GtV6>/__QiKs7F"4?J (hAOwᲮ\n)*p#<_aIPl4ff7('O+-:X+"ΐ˕H!VU v-zI(.hhYux;Z\M.H7/86BõݶZt[d^7Uɻ3SgU*/lWaY WwVRi>=u6m꼂__7Yc&R[pt&T@:ftQ{ssӎMO.5Dú [瞇t&c_/M-]VfNa3*}.nǭƨRIJ~渝M9Queߡ_Qa6X^,^.4 {2aȍQ]U۔ VkyO6ͨ;o ;OG>/,EPs~DmMvMC MtS'Hvm_枹VRW1j9]1$oUS"gv8]Wv~MQoP pC- c3޸U 8rsݽ[Ut^(jR2H_>S[;n-F]狶u啥h+lq ܔ6mIҤu2k>ܵ-3WJÏUFդ2RY( 퐻cj~nV̤hwV ۚbc r[Uo,ΓҺQXʄvZ2~Ј{Tg)} -O^-ū=ٖkզţZ'd[=!q!=`&@h `&@h `&@h `&@h `&Зp{{ܵȑ_|k;w d'N_xG_^6a Ӯ8p[oͻ,ŧG*)暵3뮸D@>ɓ? M:<ÇN:% I9R%[ }zBd)]o~a~{嗍1b׾6`?nܯ6t9ݻՇ_wݦ ;z^jy[ˤ> .o2Շ/oݺ' a}ԩS~y~( W8kܙ3gO;H#FؿB>I:\ !+MFQ)תÁ];"\.uફڳdqWn v7?HaÆ]xG_^6aM9#EJ귿" 4OzRY4.]dՁҫHe?mϜ9#2#Ş7\vݏ?뮸$"8& 1Vַğ'Oi%owqGo\{ZXI_~R&O:gN eܵs.i`bY˒ )ѸСC S{;n͏֬YFtϯ_9w^}ՓO^4|俏?X9#{g?mT5'_[~;hР WǟDJP4;)ߪWKWEFS;N:twy`xwL/P+)N62_o5{Ν%9sՁ["@Zsv9W ggKon][s{g_޺u /%%` n&ux 7t/~>p Ez%/Q~?9sM--'K.otϚuPnqSƉկ_G6>rVR:۵(^8'XTO:{gO?#iB^ᆱm"E={#F]Uh[ӿ'Vû^KA@u3m8;eq~ VY>\hY0`g>߹Mu(./3v=rݦKQ)%o.\6ױskee~u6T?[3v"-RzLoQw:`/).Re+)4mvK٫Dd'znEӥ1oauxc 1u Å®V|8G^߽[ͽM:aTJ()8peK_1Q~w8ke0_S*Uܵ+R]t|9~9CEIk#Ѕz0qZ 0V u{1kW'Ir*s[%?׿f[xuIw:W?lReUTRLg*C"ӯd> 1j(u/HlmhD좒yTu)'HOnغ$ycF^GK\H"\pR' r9NOgnM,lvg=zȔuC^\tНeЫ TcRr*{;6@/$Erl*UG4[껮Xr/}W˫U.31t^"ˇ:&Z[8@ڀ!SހijL U Go(K]gN)q\HKxe+WU P-kcNu EZԿl4]J:yغHIDATI>')E%M|W9l1OݰrwypRKZkK3Yx;b/"'ny5h | Pci||T7uZ+)UUIe]),%t׭KQ![ @n.Q#J>u:?NO?tS{[3ѹ#G; ^Fᵩ#&U^(|O[Z:xBeIzCjXrc,ϽK'LjTqzqf_.ә)y〓~sW>eoWm13F;.<Ѕ 6D 4g:5sjF&Pe;.0U^a]>dqW%u|~iHqՋ-/Ը@AA_$*ה]mbM}YۜeYe rK1rf~H*м]*aS/nzߣ| G-.5ivϫTv\oΪt;Bfx/?4p\'7=Kwc:sՁ\zuq{Z#aZTL#}:v=0?X Zru:.{VX]y]$HoWw<4-zθ`C6իڿ21N-z;}sl!=#r͡4(1ReWX['{^@Z+ؙcXeuQӣ+Ձ<u!\q8`R"O @%dct%-k橧u\1V3Mnٹvb@`hE.)rURR;6Q]֝4o|qxo^HHwq^\,\r_6 }ZQLzu>nrEohd̹ R%ad]Tԑ2K$'VpQۦ\O&tF]#w{ux 7;(VBuUN ?iI.Z>{J-o`NOob?o"68ƾύ_#<@]JXcR(S,ݧ_~kE:sLշ>mT.kVTB<<RF> g>licI+[RS999Ww\,7oN[ޭ\eNuqGG n;^֌駟;z춱mw-k`@I8?>tpe8A6 v)51~ogI_98_Vy-?}ieW\} :"}ݹeg`}2+(xIܛm.IVi76-3a/Yg S~A7k}VdqL,+S߯dwެOO>/Gޟ҇^޺UZ q-9,@#Kw<쳿"3jʙߞo tv< J 0*$mnҿa Ezxӥ:QE5ܖˆtk!3=Qg*Zi5nHᬗs Dss{B; 8{6X>jX-038trO"ĉMSMumQ_;yo<_>{Aun=\ռmR;dR!GLC}>5Ja\KChzr1j]e}[覷үoك+'6- @^GtVuJ|ӛR]-fSSV5a{;Թ"+w^jU[JfYo-#b(0JD^8.Z+WOΉ𯳶s{Bg(7FJo4tq:}^K]Gt芪Up/j>dZ'=z#bUnӘB!W5 Kri?Viu'<{jK[,E`2Cd6ٹ}/I &'YEՙlG,vwKoFQgնyr}rP:OS6Wp3<.X'`@9iэ(V4oncahtW{+glj:gT8uCs'fs wMZ4r\ 8Cvs8 1dyK"w)b8z5y嵞CL*3h5ү<ݾj¹^A9CFxJ3.ZqA/yZn^4et!l~j,oX#6 1^@;w6IxahpVnV̢[WQ< f7ԛ`l>--`'X-^'XM"4 0@M 4 0@M 4 0@M 4 0@M 4 0@b>=!h|yw߿wsCK96V~*٩ :y>UX.9G_.R]R40eIMM@6Jd&uu۷_}88ZT\t "|鰣ޱsg0bH+ã KWEj"Q],f 7Td-)K{!Ms;uхsC?U{~cݮWWn纬NdiÛ|;49sIDATɦ|ԩ?:O4 bRv۱5_@/q!y f ~Ctm#snQ-pss:pfyB}淪aQvG[^308j٨.9 WDMByx|ozyoPxQ_~'V&ݖ nԉee;wq]ZziIB'*oo|ڧ:T'<5}12{/6kE:~-mqƛxrsq|ԘQoMiOQ-}a"GByI 7&bzM׊'[J|hr|K`=y>>{T5IQvxWj\+D>µѽF]#wHR6{u+ةcg^;镰gW6 xS'O @d0Z"GZ>G߈_KxїDIp+O ߸)^+"2p:#M7nN ES֚;#U?X\k*hJ65>sՁ\ŜHZxU᭚~w -gmu֏_<, ߅mx4âojEq@-pII:/K|r)`<+ ԵMOܨHII{-boTn|¢:WLt+?Nc@e5oW>' l}vnm.)9ʰ_n^ǟG+0n޺ިzⰸnG\u@dS (ܚX˒K:::Dڕ{E_V{c&1]dWO~/^Hl yb:['W@%m.jZtW~ WO,=aE~}Nk5i80~ݚ\ i$ƳOMж/Ϻ?U?W|K_ܳߘl, $;X]I} ѻ=U?}H=ï_|٫gR늸9Dͭl:^Wau$a3VE kpyŦ{9uVoI]y_Y, uYb7Whڱa ŢOˢ)X 4S7Unpזw(eY/5wcs=Q![ެ!tp<Ħeu$Tٔыv8~FOl hrPnOү7r1v$_|d.׫f!|".OWlu6̖HA1XG[̦D Ѵ\(@Lk\3dfޤW Og^Dn:5yr&uzSǣkjM-&NS =^3uS7kw57G?hd'޺Y/lfW]U/QcX1R"VèbQJessc(7mNnܓ"+9;b_Zh]yP:S;&[mzъFwUGԮ3dy5VWI`b?/X)diDA؎U덥F)=eژ']Phv߽9X+IDATjf[if/Z`i8771c@;罱{۴񹜜$d/81`tG?ч<@l/4ڹc_4~ygΜ@\p[}[]<5;vl8;5Nˋ?Ciӯ_ȨW^:lnsI4P;MMyyyϬ_OER7Ϛ^V&)rC<H e 3NJVu~k#:}QQk[grW]uU/K,Y\Uo R{ xyd<kIjҫHVևQ>㐬dd777W])oTnn2 e DYBRUk@S'W+3;h().9s?>udtХGG3Sx[(((?ގ}ښYlHÆH]uײ9)Ж7+_n.)᭬Ϡ,!)|!Y)tYI@"HoNW T{EL!](KH D cB \@~?%%oBYBR7psssݦMn@t:] OB0FTݦ),!)|̙3nji9! ]r5|C`>u`Ozu۵(^(]nC),!Y|@ݻ=TNNMg%2eci te&HWs| B=<}yb:,}ŧNZCYJuIEeںX3\<@iË։^/}uQ0^4I4hgCƿ+ͷse5kՇ -  ⬐SYz*[ػw1yk/׭DҐڗPbbYٽ߹Gf_uPҤw% }0fX:R*_/;PWqʜsgЬUhT}{=ov6큑R}?giCǖlvrs]mu˭O~_ Ǐ3wyhvKMZ-{}n5&'_7uJ()8pKI4`\y1c>}Z ՗ENUOloz3.2=T0R]a9."%_| ҏ;wŬK袋>ԖUu}Ç]UTun. -76un-O}#a+-%7L${$vBY8 n -faZq.dآ @ll=xd%*GwH]XD(q|\]V^pїMpô#sT2&NVyOe~=NOMI֩3ԯS3\զ>Q˹'RCe`PY ;,1O/ȥ:}E'ONo1Rg3λbgϾO?J3N=ذ#GJ:\Pu)z |˅miQ}\h46; '89=HT@a~~_7o/p{k;g)]V[K[4ϓ۱Wyӫv-]n$N޹vPwXjwfZ򡎉ʪV:KvPֳ(|hJVYu5ƧbEfږo6_6Vu+ohOΚ/ fҗ'Q/pjoDڔonmb)K %.}\Y] OcntR(Y8PII8b],p6c+ƹH|?;\/P>c$O?u75u҇3rf۷\9R '7 |hzTᜬ1cH-fc{sNo|ϢDu7;N4.*.k c'M`me+~s]:1P?FZQR/#Ϸ"is̙&L@m܊ ŀ1c`YR/1827ޗ'FYJl>M {Iϟ|Wg9%IDAT\D^jL).̕pҨ^&xhHٴ{7\Į[E~_J@ڤ!@:)Ka> :I*RqPEf"uKM|mwziFyRiW}p$/GcX-Y\UQ'jsrFN3X#+]Q-waENiEoRJ$ }@LK2+R&E; n-]K<[uU<--'ԟZ^[~;hРЙ;昤?ѕn^c%S_ɘ?'R끳Q"%YSe)7ޗbY{63%bO|IO?w[^V;L~7ϸh:twe3PqhyލVrMZweg.:ۯ>{/#F]rHIi8G p(W`kM8orߏ\wK.{~B' j q1¥wݿech6t. W5>pMw?JD!ƐE߿zuy;Ik]:\&ߨ`WR6a~7\V)L~缻=-)PEo_&&שuūiWhP*^DZc1S)|OvKS&JNΑ]C'}!_~ X*"JwU ab{b|WRbM瞿{nj?V2 ANLr,iP@+_Rm?m"䗃dh1L6j';߿HRJoe]ץ.7:M=[(KtcgICz{&sԩ?KJ_?)>Mٵ~Yk ݤ\!+J) g\ߔ65=~}/ЛQᴯ ^)SE/m;@cѣXS.Sw&OVr%"n&(72꥟qH^zo _7k_!  %!ʵIA^Q펵AJ?<qR{Vz)J귿" 4\"|g4,R&E3h`nuzg\HۻrUW @}NjM~JgCnn@l W}ZieLEYJY(K!Kޗ}w+JhC]2,IÆ D3fn4{(DSR\,} =s|ԩ/| "%dH>Drl zy"?wbȀ_>?wݗ]vRBYBC't#ע, sUV/d BYBR(0۾ӥ?V#K.9|__ܒZVRR( ;ܜԢ! e I3+fP t: :ǟ@Lun GP>JzӨ۴I~  0r}ǟHkQzPtGG#E%$8Μ9sp%\s7` e&HWs| nyb:,}ŧN@(KHqP=Eoޭrrr`_[3x`iMe?joo@L,+;? o@(KHq[otÅ hINS}zBZ-/ϺcO?~@ͯ_ t5@\<'N*g~{淿5h ͨFwd 0c@M 4 0@M 4 0@M 4 0@M 4 0@r:::}5M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 48<6CNNNx {e.ӢDo@OSo#f276C5EӲ򺎎:@nح&>wjh9z[o}eunX?OW\i{"y}ŎXؤ̆XKɶxKў`Fz]6c-X뒖+R(m5Z')[핁۝VcƷ8œW+/t%"Iuc!}D{t^O!3Rpכ(?VgCS[(_.OlcT'0Su_m_P|F]U 5꺿1CZ`UjVtnѫW)M6WKWVwzw,z`q U]qVpN);ͅ94)]Tvuuݺ2{D/V#$[!nMQNF{fuXt;K.'0n[4kn ]o((7껽1Dq:QTY2YgP*њOQ0LJ>reG!]ͫ0Fl,PfwTy6QK^roIeu!ձ'lG렼bKH]yr"<зɩx[q#ՕWrH-hȋ2Ygr6 q`[D׃v_XvGjfԝ7yM'C$R{f͒<9df ~F O(м8P6mr8]}A_>e[]}ze\>j>N+APmH%µUCκrJ|}`u?zhq[juCܾfvSՉ uEC:qi h׾:ԁۖWJ` o ^ pYl%)٬4 r96DQhXԮM&C$RIJr*#/9v[Mj[IB4Om繳=$l;b<=]^y|H0{Ѫt'p]U YRfK7~31β.kொ De̙*  h ]^JʜWLɖ)ퟅUqf4!`[Z&},Kiitp&~%{lv$kL \$\^( 4@ `&@h `&@h `&@h `&@hB٧'U "4 `&@h `&@h `&@h `&@h `&d}~7w|pѣGE pkQq#/(}paGc疝>aFt@ ]uײߚYl^ _9w^}ՓO^4|俏JHs/GsJ%\yՕWnAd%O 0(ˮmoqYq C*2@ wN{]缻.1c@:xy:wNgչҏDi}7?ܹis999vuu;e(vr on_;Oir9RRg?JwNz̼w[7ЧeS>uԏ~D5fj'zŗ^PC_W>'n/]aYaQARm%/Q~?\}W6?P]iE~=Nk ֬:p72N,EG0PK軲)oyy:pW_07+H$oU]pLOS7xÉ@X5h_7Ms:]֐s01z^)gوQ#ʮ/S/1Oʦrԁ]ռJ0q}c^By)1ґ|ߘD8L݃[4&YYa\+ܜ[8n׬ =o_E)v1}tCG -SXJ)/yCt!j>)znnnV.xK +,,wD~FOToٷ(GKRD+R.˧icK6;^(}472AT[pt^$0\.-j_ߞ^W4`3vzKEWNKĻ 7j(5߻" *Z':NG"Oڎ\h6vWech\۾Dimw˷ ) V:}Ӕj[4eq9*B# vmUrUa^H'Xjl+$(uTo=sX4#lƯ vsU}WЖX>s}-L]\zՕGZ:苃cB}W67g>E =R+ 2Y]&eOQ[wDohT~s챞+VKyط_.SǼSWwlJIt:w?G=Xó n@ߕMM7Gn[,#ɜ}9cH$WO~/^tԁ+mHGǎ͹3gT}ӖOK.oʦܿ'VRTxH0ˋo0\Mg.VSd㤊7 ,0A֒%Hba7}zђTqYyJ.:@ߕeXVvw|D랪ֿ}O{$2?uO|rBz?k*cz R\fn{Ӌ>~Rd;w ?{A}в` >-\w޿_WC_y7\]`Qu@ M 4 0@M 4 0@M 4 0@M 4 0@r:::}5M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 Є~<6CNNrVd8޶GoI)PMd4!~ *2՜Jhj-F}8T\g⪭*/WZй\Ы_*K荖ZWKMzmnG"ͬ?W2'rv#6) 3ۺ-GNi7mwa멬uL¼j-=zȸuY8S(#T)t{9xHAN39ao]E񬗚`zݤ'M C$vxQ, f7kCW-qO6ؤE{֎gJ,v(c|AAzQ*J5]q;t"|Hc\R} Fy-f4!*Jbԩ˭΃5Ex-vn-.-_fKWMUz[gvJH9Vu[Dʈm̎::nU(Z+guάF%|gnn|ܥ5U?Y":Z=j=Io9]vrKݢу7.U{:N}BW<}ckmv#ڵ3KLB|?8 u&5B~ҚіpW+8'ַIS[Y͝[>P/OM$-yE<ۺl6IC1s:RtWӾ_n0:̦4nT8CFz"w$BW^\l-sa&A@L@7£ ZnGR^,_׷D:T8JOZ.SXq[+Fľ]d: 6a吩SNrO*ٷ*4V~zN_sZ%WECr-P]xnUU rPv퇟'w= uW\;u.ǽ;%&:Mԫ} }y@٦rrw=wOl ^ #4W$n@+g~h2pQv)$;Pv[Jou EtMnJ#s# )1i@% BTE:F*SF-'I4Iy=}s>8δe5զǑLZ}ȡfZa/͘ZeSV;eGDusoiPy>R4{U]*b6?a[wYpQV=oW_ l%%6Ӳ{Pyľq].ۋIDAT5iSWZx}mKʠT[xUM͝yPve(wxm[1{R~ngƙSf/XQpk|_a%'[p~\yXYWli+[W}6 O*WAZǟ c@}uIAn^e3yH8fڜ=w瘭}L,v۶- Av]+ʔ3•GރVd#~O茉]IT{+ttD{~8Ţ4o p~JK*` 4 Є*CVa*CU,l)%6=^.jJ/k<.jp*;BV{[0@NIhŗ~%G߰pa,"czM@'XM 4 0@M 4 0@M 4 0@M 4 0@"/>?":spR`&@h `&@h `&@h `&@h `&x6l߱w~tCD <C>8S# GV-YZ%-ZX"iW_ow?_"uzy\:+f~zhIFGGG _|~Dmowy~N;{~p=)@ǒmmm_[>yy7.l-I} 𣾀6 Dcǎ=)ܗ_~_gm3o3[p"x4[Wϛ{駟. <>9XHdSVJ 9o|󆟧7E|775;7m5 w,C =gYH0{-WNrҌIyyktq|{9 WG^>fM/4H$G/yjBivo=ǟ~ 'VP5!HCZ7ݷhQiq}Rw(K:3~SwJ?IMvzqGP&=ugdd kpUWP 1|7ל}ѣGovsH'4;\ ;_']>%/_ڼ@N?}QuxU'zх#/|:Ho~5zы .VY/@N޾?22.0 +Zu+gVF~qSƉ%]D{3SfuW7<22Ձ>v8G.H,s7C:eB79xj\[<{ァM"lXHа&\;A_b@NQd%ZCT剭b%C&(i&G 9rH3[Ao%N6M# "vzchnK_+O;g\S'N}G7Ջ#ǎݑ;E<#{17b5;B=Dh8nT?i={q~tȴ<(kQU ʣRZ&^w"piVi]:tn y {**zHXRgM^voz0R;ͻMNOm{,`K;w}! Lo4ji V<O2fK81Hq3OȏT'KZfViJ ++Mg'ȷZ[WZEM$)?_ rT_ޓ+f;v,MJjfB|U]4޵,#WRnp+H !Q]Zwۻ;>]}fھ;tʆ f︨P _)Do@NM2b.#wͭgCg֋?v\U'͖H筫c"rRz;ƺ9y聢.UCcRMYY%-2 GE9> CCJ~woќ8~"/v=yӧ5U"6/mT=֮#$Nn{>?4.kvh9b=Yql-շ2'Eţ d(:Z!Vgz),68&NHy;K8-ZXq-ro*_$u] .u 77/68Ei #@s9d4kj&.WЉVs auh'!0gL;eOGuexd`gouc;.Rzh7 {G蔝S ҩ QOBM )#j9hhCܴ[L+u4+6 <*˰tSw|: :k8xe JK7^!C*;DvlH螻r/\1>g}wy۟ݳI_ /腚w.xL0W\O{xR+k{ ү,@h `&@h `&@h `-]fIDAT&@h `&!h `&@h `&@h `&@h `&@h `&@h `&@h `& HO9#@]j@ pJ{hB 5nP彷5`5Jnw*&` hw,+8[îd\iSW swm:sZt=%Kl=##RĻ+muF쭍JsHivKٽ29=űۻ X{i-3),Zc3)#mR*I, #tdUun)vJHƣssEKyK5Vgyco[UFeF)^_RRQcJ z }dOZtD)ȟi1vJ8bNYf/|-6) T~_ny?JxcюS&c Zj/w0;/`)utKW7ֵWIu[*>RWG粘x=iAw+O|q&KO'06DA#%PʯȫsFT]:+ ޤ0mՓqMO^+c3PwLjX1#WҬ+Բ(;fpo \oUeVu<@ `geiF[AU2 D'qTtYPi'I:eHflp;Ş]o:Z/uU>u^Tf.5m)}Uע-\nIyYR8c|7 &+?~HC}9*d{k׫oo)c=)?I=ON՗ٓ- 7)o _7JҦ:G$۝&Amp sN$Ζ08g : 1cTj:FCD\asZnڷm];YSHp[/Zѽ4{pz"DŹ㖓O@Rl,+Sߨ jt+i\\Q$\rZ j//WfYP|3tfWcZ0oP{.+3- [. ʔH_]lrrk]'0u^&?!Y9:TZasV7zZPg.Spc1i+w"Pc܌j-#lfЩ=\i(Zhcz'کeu.%r ;(b`8$9}l>GEgV(GII UOF7M}DZqt]I)`=S\w`roL%GdO]]_}OHӶ/BӯD_<\`Rw܂) V7l[漣u}Ie7>lu۰`J[O*Wn۾$py; yߺ$qfw8ү[ڶbv@is3{Cm+oj;liN_~GƵۏqOC CV)oۤO=_饻HSkj*jtǷQ  ulHCi <c//Vn̾46pc!#Рs~V;}JO]!_7RSŖYat ?j~ JV:0C`!.pq=8wvֵk@FLvk|WҲFc 7͌se<zMsH/`&@h `&@h `&@h `&@hBGRg@P 0@M 4 0@M 4 0@M 4 0@M 4 0@>Æ;vޏuy Ҫ%KE +R$}7ܿǟ|KСC?"K'\q\/-;Ϗͷ޺?/ziv~333EXmO~k'O=Wfe}ؙ"~†Sctر~VX#/\˗^mT{&T{wfrˁn[&}ys~9EzR"5g}5G?[ l5JiA}98gܘ_H[?fGc="!;wg~3~fϹWN1)/?o p:n~sO<'njټA%O 0R(Moª;D)xHf:cum;*;.8ѣ/@*NwYgfo{\G"oⴉξY6hZ _DZy~z].[jJ!f\暳9[>z-.y餒#?{繞Kt˧K7׾)?~<=D/pV{^IoW]f>_/zT|q#K|)۷|@fVڥvᯘzŵ7_?r̪ߨo>n8ѻu~÷jIDATt ^ڬ\9'tߍߨ444=2(HH,s7C:eB79xj\[<{ァM"n5$x& 1lµa%KՁK]ݼJ00$D'j!#gfʹ|">rx i#&Mb쬬´cnϹ*Srm:.|MugIA틤8j~ Ec~)zniiQ.x ꇆrYs}4 PpEoy".J6 ;#>e!:vnſF~&SZ:02O44ZqsUU3zchݸtSH 5u wtS8rH3씝jE^KՏ=B ΫD*Z':N"OZ^_#%=2!2Za=ô㣔ɷםfZUZ@WlN}#]yǦB¿񞇊T꙽kݛT'tkaE =(w_{sGw?MJM;kwMC 1V9Ǔ̅N4{ R\0c&)o ^ +3+S4%JK敦3[|-F+M-֢nƔ9u/Wq&egX_~ǪJnB+KI)7uFDf(.-b̻]ۮ>3mzoew\nbׇ_6Y&;nZ5) :.C+֯;^#-1~Ǐ=l, )yy*w<TN!oN=zKjUa&}t 7Kͷ;RF:NVhae\\_DRbj&5wSs9G0F&'"QM ބ办q:q\!M3vfi ?`NtLNr=`E~b\QuSzmkئѱS ҩ QOBM ENO*fu{odW:򯖃ޞ{F=MŴ"_GSbCEƷW:ݕlm=;_եc'iHiMbVGK]j+tvt坤%UjY}mv(M=ѫz\~ە~,%4g, k@'X=uǨ?iw۠ɝiExe />?"c{@Ri gHNޚ!!"13-˯߽$#/Xϟ.3f_q7;X|@{'<PhɄI黷,Gq2s|q߁"1y>ވ}4qK^rlH:5o0w:~ֺdQ=J`N7~;ux{sՁKW;">8͢ɓ'+W/o J|iU/{\ODٽ&FMM K*Ӥ΄+SkQu3Y@}qG:gddJO0x,7Ekok_7|r߬|F7=2((ҟ4U /Т{ jnW^R ҟy_W=ܷ2='jdx]7ڍX/_|P:~?Lܳ6^H}/н_C?.P$ 4z>/m,zׇ \;to J{s]哖+' ng]^kl.zf믽zK'1'L/>~J`5H @h `&@h `&@h `&@h `&dttt;j@h `&@h `&@h `&@h `&@h `&@h `&@hq깭ƌ %Ő0X,1g(n/ed쭱.l&C+t:Γ@]g}C -8G͚!Z؜K#v}#O 5]R{D"=kʦѷ`i6yS﫯.)blI'O. mþQdqea2c0WH)X;5R]ͬ,e(bTWlqߴVi.eyIK]a'ʻ ߤl?,#XQc֭U^;vRuu@3*l;+QjsZL,\]fVfZF;-oVԹX{g8+tY M69 S;~--3g)6jc[:"-5u ٖ\/WnqU7RZw&ԣڇ)5\6n!z9fouVI鼁hKӫOu C#Bk猻kͫG} Y3gw7ۗU+Kdw1kЈ XW\ 5{m^l8}f:-` |n'j2M<ˁ|e~`rfzI~I7v[=#[^I-M`"tĜW$C +fFYaӗȞTwmՓ䲋'26Vy#Gj֎7ԇg>-_13F=ڢ_NݷT}vq r#)֚2}?skA[^S>Ue(oAVlPkVX_$#IT5Zy !GMY2en=L҂}. \ ,}R yb:¤.`p8 {旇FYzgoCYU6# +]j:\1ٓV;PiT^L\ˆ!/<5V;mU!k0[S#O[Rt:}UF_ao>[$㰖 }`=CzM)5--.6u*IDATe*t`ѫtz+']GјXmԘ!Ru254?Vj1oVNun[zz¤ݖ#{7eem.4Nk3=cm,ч5dtHY2K U)rX*̅3{B4@d8<މ.¤p :O{Rj4lw*J͏җ㰘 2קTCs#ݍvkeI%mI)4Uu+T(dkJDdtttt+-6&3dCr&aK\ 4i.S״_ w.(\nuҸouV=}oATBlc*NpQf͞UZR71nq]wǻUQ \ cgL=NeCV̞7377`+{HM>aޤ|Cts'̫ - K LYb۾u%JBqrVw۾ <)8;WuCaûVӁ-DF 0@M 4 0@M 4 0@M 4 0@M 4 0@MH{?:xСCHcÇ^>uy |(Iv=?}ؙR]ZhaeSctر~VX#H ֶR׶ؾc40q„+'Nkj,@tg}5G?[)\/  ~ޠ@*|775;7m5 ~YhaeO.Moª;D)%"]ߌ[g_v߲mG~?ze@ kpUW~f\暳9[>z-.t Ǐ##F> G^autN޾?22.0 ֮ͪzŵ7_?rn)Cnzi:p+~!33fu 2(gXIL \[d]OJw8ߨ444i SnllT.wIyYnŗBDrYsL^y!a_25+*#oi'!-ܴlzXƹ[Kˋio]AĕSb>rx ihJ:uq:b!eP(1Q>Q+&[fygZ߱%iJ/1w7gKE#8"˙k5c)#|MiyҟH#~؏PChzϭR u^3cYl#f?)ᆰCgkvCgv^y1$@toyU+W,Lz|Bil_$gKi]ʶ/1ּ9kb%+vt}!uˤMnEfVzjT,6I&ЙH5RCGmrKKͭX{KneA,oʍRlC('F/ʘT믺C;zE~w9( ӧg, ;YAmjawA Y:] !kԩ=E;. gkבaF7lESi=\\pq #ǭr"wHP}X%XeJSwgIjh\4uc9t^HݳؚWmk99r3EJRu,g[S_IH?W[oeǣϋVhaezH:5>sԁ?6^;Lm+B8#Q,?o%xygäJ.uZ)W;L߹l ΓnJY1̳|ްc~@M"Ju0R~,(Y Jrzp:e1UJ/Ww:pȵ"_hjV=t@ZI?"s2MO43$foɍ1>M O 5B(rbW,J/8:X98[,j'# rSZ,ݓ4꾼HcM[}Ц՛|w:^8K⋚w@gt/;#ѥ_'X$ 0@M 4 0@M 4 0@M 4 0@M 4!CQ 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@4j0Z\"-K3Tvq8+t! 8z->)MIIDAToHa)X $htx}h`sMGG@W:*kwߤl?,>V]KEbk\Β+,]aŖEVa2( U3ԅ >{j̡݆ SSygnN*~J'B.GBNo֌,eKݧfmwGNga̕Œ 0_4hxomw;le :6̤j oO ]S@Kq-쩝?v~{!2ݠeYs Uʏ6W5z͜%Ҵp/4m|쪍}Ew[# YU]6sM.e195*P1v9jlނؠCD )GjKkwgaubu1畛:'.UsD[/(*Wz_jo.wՕrgLU\W՘q*̆2ev["[09sQ=V[lLQW< ^J<)fO*/։TsVK{R:۬{lj{AS}sU8VƺQȼVU<-lӖ([el+sHXO^'/qUp[ovljtwNܫOLѩ{$t+4UZ.]SrH܎r?R+?8ʒ̿%UAMEwnwnS~_ɼ<),ЍFܣO_n厴VUvZf2t%wTw;2.)l|eϖ5uU#6(*R(rqq;ͦ. &<V@kIjҝ{]k^mj99hޔc=)?;d=ONՇ4'e4I[# W^֚w*g)xh;|Sv7j\asZՂڷm]j'X!) Vgwtr#݊)gt\J-zlos۪ܙ rD{JǦ^&?Pd\p -ڥ 8cڧNOW_55 FLXg4* 5Y-7J trZ]L3VQc0wҿ9NW=p{Xg)5 ,q9G:TfktVX&>ti?7n8,fs"#٤ZF5-'e5LZ}H20jaS9sK64Η8j)9c\ke9|nhʺCRox4wY#br gnܓ-g܉r[ Gّc9.1ԕ^_pU{gKqt]W|VGy(>1elRvnyu,Cshۊٓs3 gL`E4s  F+[W"z` 3:S:@9#1SrLVwϔuD@|%5f @kwڕ6yzHsVsr^<5Ņ7lV~p9c'X@7iކn9G@dtg K^F'~ N[|Wr -1 Ʋٹq.9ܬ  0@M 4 0@M 4 0@M 4 0@M 4 ЄϏtpl@wh `&@h `&@h `&@h `&@h ia;}wG:tH8ծ8yN]{gT;Ϗͷ޺r{ЗL0AYWfec-;r{2tҷ~?~\NMڷ~G}={/aÆ_|p8qb_dᄏwSOz?L.3f $ ը"TPo/Ǐ5u:'s;wR_^{5R`@,Ҭ k/o'}yg߼;T_ys +S!j?_~Qm=̀֜CUӤ\xݍ1mN;e;^ ?~\y\k{[:>*ohmɒvۦ W|gpOk{]MMMW]3u㥫|eFqqrkCz0 .࣏>:^"Rɷkx v1ˁ'n;!Hmg}~nSkvXytn%78 PHݛTu.ҩsjx]@SG2 ʣ ݾEpmwunfEmcTXN9du87צcm"(̺bgujGڐnd"AgE$` g'|E}dZC ֎۽oKSH*YСFʉWPp+nڵ!VzeK7x+Q^J08x7+m W׿ ɐȻk~]pAsDzfzZ<)V]p#|wng-r8ۆw[Tm4)< v]{hLV/w?zrExׯ#.PIDATeX?i鳇֤ vwmW"o8K0-2[ icv{Wb-|!ޢ{Elc=KsD鈔/û!RnT4B6)dzYP)?c!(!ݴU)Wȥ|3Ѿa?[vՃw|#C硲ӆH_㮜Rg8)N\U{|oU73v\FgycUKEqo\`LzG~ ^ʻ%؏k<tm˴G(Z<$;c-dS?w&@q O8!tykF=u(uJOvg֪e<86G_MфO8C ZၟyjwQ4؎.i1k~bJc.Xf9NaZ6v ԂM0 [Vr/ywʆ$pV=#Wx*.ezyK/,w޶IJ,w zw\2Iu?~8s]哖+Ə5M5Cr5yY%?_QR|)Q{w}yM~C8sp; }EjDŽ^mD_^o ֗_i޾EMYYYϮ^{/NAkz`u6X3~Wgh7Om7y,-q_qUf0@Z!>ON^Ձ1Eq_T w$SO/䒸zYk|ϞwORˇM/h@,@9sԁwG"H/{}Wri HQ ӟwYq-5z<i`gԁ]H 5[S[ϸ:@"=PѹH}kNV?>[۾>d~BMĈ`T\SΝ`.Ғ) 4HmbAi @@h `&@h `&@h `&@h `&dttt;j@h `&@h `&@h `&@h `&@h `&@h `&@hz2]F*z4CUjB`q41nIjΈ=é>!G 5X< 5-B9RO`.Ї-"Jԗ #a GS(=6tt puTTh0tYr 2K4G-:c3+LU_N huY OݣU:- Zsi-3齥\okw-Yak]VqG$J^}o(蝥^=LvҐa%^ltTF*eXΘJoAs5&}O0OMqCN*~[+(rHn, ⹯o^ &WpQ}3G4xT2lg FetttD^f*ߴVOU O?g(+″\{%}XssSA 7l \RQc}.k"]c 岙s^="ʜ]WqkuV=Fi9-&oa)z+kfuoP}U oP358ΘSV;u(?!b &Zhgzi(8b~Cr@<a/U_)VGyUO7w3W|G͟}/.tonGFfuhT755ej)~6嶾C guT O"*O}7{þJ2{W9|Bé]R}gdKoU;&^2yT=+lj_Im-kz*ŕhх]}Tz0*ۓh휴k W٫|eoX1#WղCiPwq1\o|lc Z4($b>tuAOXntT5WD\f%dX_0%~_w6<n/ӫ7׷:co[a}$K#Ώ8>3Tq1Mx/Ys>G>PJ:gK߫rͦjȻVl9$-敛Dr8gI>PVU|XٚYYZ+×*7W,䉤*KsSֹLgu2a򰍔/texgvIWSV\ oz]"]ͳʮ_m++U_"?R[\Ь93|ΫPނoT-YnkM:w;TW]ߥZXuu$`[w7UvGXixl1%yڈt\̒ rV^M%IDAT3&K# |f Y9jn:R{2t:Rcol7٤6:cdcl|+sHoa1TEqlJαUŅf$9-ҐF 7FZU][cQtmsU\1OJۯƺQ7Nkes5uwʕGk-u1uK+6VmNQE c:unKvm֤SW5 ljtԄgAmBsYҕ;C+ w8Ox-OeXsBVn+D>3zHw`][ ;jo:J 7bkzQ,0J өܙ_lRMe4% څxs3&gb.g)|e66ov~n\it髺omt-JxWk*)ٲ汻jeV$*8>={my jT-(5wm3di.ό>rqmh<ܰz̐)-a ,z]A/zBNKw%"zWϞX')? n){#DKgq U=r*h_`gOeUzQjMu]_t4.ČumQ$yqNZxGc|5tntG&b:c MJۼoW:ڙ'lw^w ڡ}U#kxPzڈNWu8}F9u" ^1I31}\322t/Y9җBsyݵKTmڴ҇L3y2`ʍ"Ie=XZ--PlힾBUҮkwYԶ*Jqq1:s®²2W[CUYZD?n/?fy?wSۜꝱ^k#S NYeMG.p,WUaH!]`}igF9cWjy\iw>압6%qL2vYФKYl[>[ݍu¬h}m²:rϾRvybT3wZYj˻hulܦ# eFwqr7 ʓZܦһg\uiΧe61 K+7Voo5 sa}PiUvccHEqX̆kr;9#Њʝ&^6<UjQ8+uҹ0luVa+K;Rj4,u4|bx31}ZFGGGҌ'ಅF&>䐾6VF-ք2dCcM|SH;dFԍ{,J0iSWZx}mKTQ}ix%6R >-1dj1&T ?v.{Q>R ݸ'-͝+VgH.sNY+,3e5RrzMuxJ &C=Y'qðQ.=uL{ڈ:Uy e3lw/lꃬ# 8\bxq|f(Ю5SgdLY'l˝w()3WZdu$Ugr2Ο4;昭}䮡z͟T2z_Zyޓ\CjSW9`ٍU6i:{1YrV̞gTp|o8xJhV;Iܠ ~rmxJu-uV;UzUCr4UvAɊ] `4N@h `&@h `&@h `&@h `&@h o8spɡ `&@h `&@h `&@h `&@h `&@h `&@h2,餿o99g*6՜Q(^~[$лO w׷;\(ﮆK/=CZ?}l昋(?zjtR-3j-O5#_U/^#WY齃-q7[y.oi-V᭔2oy{Ie~PoUIu߻ uw9Rfҋ?R ׋田ayE+W޶_wg1*s.}w2^cg{=Bˋ{ޖF7z혽o\whj땆ӗ.;o}5]{ٷai@}q|Å_ýMA%sЋGmQZq\?\O5_zk̵Eme-_%>1cͿ|"<ҷfݥd1r`o}ٗuݑ+le}չ [YS~%d Z@@/(9P^8"ZQojnj9kzjK׭^;spI/>p+s~?[]Hsgb]ޟT)}O̱<(+s!a|+h@`+-_1޳u~з1@kkoo' ~cF_6`@e_})}ɻ|@?{5)瞫J{7ߦ>Sa拶aWSG*,TU @/9ilT/d+Ɵu=kۋ.5oߟB yiky/_Hg$60K{_۾C32/ %~)N!G83'\1^t ᄏWȿc*?lؾcG:tHb0t; W\1;׋s҃СÇ7|TCL}%>jjj %/tp{уkG}saFͷ޺?/IpտYueDJiv~ʹϭQͼ~& y.R~2ީ)qر~VX#m . 7^)@~"iSZJVD}{ޕ[W*,xm6[8a•'55`|Wsԁ5ީkkkr͵orp10 z>4~}:1c6ozqPrEڧTonjv9oܳk/i;wr! L?nq GE +}j,$/zN 7͞^U8ꅪ!xHYT8m⵳}pփ;䧯[rIDATZ ~oƭ3[/oѶ[o=K7$m~vutnH :鳴K7׾"QSzf5o9GrhR:~z>:aeXUMD]LKIؙ [ˆ1lµ޾qItnFuA'766$EhKe3M*ߋw׌#}U S!_IβLOē_D? m|}%v/OϽZ1,xdD epHI!) 4uqƸޘ'GNS;I|oLNJ%˥󧇦>_̆A#on$p=fk&5xƹ:T4t ׸B}~Ou^?%/{h<Y"?1#Y*߼HIls&.ܤ>%uomh%҄t'˩5& n~_tՋȡ猼]arv QBfQܭBZjzyOז)T.W0[qyg g}5_ҟi&IK9ŋyؑ1p!?ҤO7LZ_1swJMEl퓵f9̼X3~hz%5]?2LBp{\kYgE؆;}U֛f拭0߃ǗMTodRNX?K-]Tk^U %J57ˇX:vjV#Cں54LF܍| =dyPFx<>c/j&ܖGso^y] 9FNbHO}̯D2B1HUlPHײ)} P$~~a4V[ [/}m^8A>,$yi\DgQ TAG!׭uV)Id~ XLPÀ-JjPýWWwc&zEZXi۬!TR[=&A cUEV+?3I%Rm;E*9*!mvVQr{ܴ8\ kT0/5 wcZDT1?Y7H(~wpꊕRv[zk+@_,}_; n}B7+"Uɑ|wBmc}UjYFueʻH):p[Khrv8\ HF0w˒qBJH^A7S&ׇ}ήK'{J¦eӧnHRwVxs轸eX?yTixJznX;zP]E &׿x_kn`Mnw#eS˚v(1'^!;~IJ~nK':Ҽ۳h@c֮#N,&w_EשÆ_O?>yRdy/(Mѝ? =c.@E ZBJh˦>j|hڔt)ͪI6X)m 3^i8@ؠRqT/+"X/+jF܍| =^-lS*"d%BMvf%[&TK@o 9v&L-f%jyuɿJoN7V7_K\@nn_>,EJ?OՁ[o#RѥUj;E +2Tp s9G4p z7{_QJwl؛ܸ"§߈KpԟwrniϧU^|Zy] *A͓땝#9ު{ǵؾ5'k4䛓6HWKt¢oG.' S.wտSG*TRJ}Hhw2jC'VˆP/:E.7f3bp7'acGGP/!|ޕ9nS1W4G9o J/]>w*in7/w߼j,WnͯJ{Nf!]>y/GAav`uM/8 m u_G_v_j?#j9팺h3_wrJҀN6N ΏPӯsK|󂛇膈dY6b=wn0ߖ2 )OvVm6]Jh6c0) L5QZ׈|J %hbKkiϧcdNDWmn/Cso=+K$>®_i=yyv(ʓzaF\$Ny>^qu"~)NoV|̘D@Z?M'# rɭ.*Y!T?jEV?( l*Q"^{WO}(-EJH}MUB=ލ"TүRR 8O >Im>wkmä\mIɓ'+Wyp_}DR)7~;ux{ОH_AHHn[w0_3M.[@~~_ +[FS)t}ڮ2MưƏ3^1.͌Scqlӯ4q„{p:\{Du>Kw~żӯ8Em梛It _\_]?ߍ4O%; }ns]Y8{^#wR}?OiG)7& ǯz(w[E I}^eע}׿_W"ͶeK7x+Q})} S&O~YHS)-c}*Sy u3qIN#ȿ8\.OzRw!R?gL_/ռ{H)>?S% @o =Ww3s]哖+')hTW_.)O>./ߵc{{ O):@N5y['?sPVN{wZ3yqSQ"]8򿾩&HBGw+e^:=X5>]KGرc_|/; M|(Yg/_K|i]{Ywnn[[9|?o~wGZj^_6233333o3IDAT333v @~X5zԨ1Ric|]1W}mT@1HhA y(M 4 0@M 4 0@M 4 0@M 4 0@2:::5M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 Є"e ]U{i./g.#iScܒԜ}-ʐ9R>Ox@d=5kZhYcs @'>N]3Z<^Eӕ-/]oia+7C#%n|<ByF= bnmU ,|9SZ#P᱙Y֪k hVԅ'Q*GyUXV\洖g lߵ5J.#%̷qrI{SQV&Yi0/J:*}#\Yj2w,gLug KGΠ>Y'8?^'?ǿŕT&- 9nu_R] ڠU35ww $&¾ꆋmϨn҈QgFJaluaWEQgh7SU}!}r4Ʈ8,^I_.=#-TP | ['wԘCߦ˚.wטsGl&W2gsKBĭYia洘IW^eb6I*BW>R<*acBX?8c[NY4ۣM'Th m(gUFp-ݠ^m;|F;,qqju^ts7seJwҿcvqigb1?@L2w;ܦvapʵ{I_C~X OЗ~foqxCIb*o1[9p RJ߶oljTKiC}se ֩lM{BW8+ oٓ}%9zR<ɫLWE_wRv8nOҮ1_fnaŌ\iT Auxlss ޲e1h#ԣWTӕֵ?;cQ]P \ wKg@X?o2K6Uf~4[lT<*+w&is}V| zYj nk3O}k"ކIH5B1#cEW'mmoy^?i#)=RtS{yc2ѰQb}BY)1a6{LSwH/V0}l(߽Go8ds5s%7>9š[sW(AJH+,ijT:U9~Hc]բo{޹ÖF5t9EDKb掮 8!A[3p~u{Muگ&B*1iY̤mWwĉ63VݠTW'bojK;J@{}V3"DbPMz4d0)1Ѧ[Ww&"6{qEKy͜IZidCippsyF\\\b2>ATًJk{{KuHwdu&,o)شY!ųEg!bFA_XQQeݞ [%[(\Pk9g$ iꝏ/( }[iYfHT| +,3Ԏ T׬(U"O"`R|nbkҢGuH~:`5B9u;jJJ*iҲSme[>;ۛ32J+]ݶnVSs]4,>%\֌j㕍RS^ReS6KFyKViz\6&wjn(LQVk'U-U.6ty}\xFgVG]eY=-A RRnƖLa޳IUX o!6:iﭮ<.{/~I?|<+&S"`ž5 wV2ojfQ8f,K(o5i %x pJBKW՟ػ>,s`GWاgVJa҅JM6gMcg";wL7w|FʫÆ%O˿wf]#yޓǵnuяtk7u(KwPwoħ5ii^}fKuX&ݿҰ57玚IDATb*w)G:WhhiI=V~Vy./.]=7,&Y)5`4'}rVCӪѨx5xx4uHLkZy SHx]8+Dִ}A;Msv 6$l)UoÒZ@_FTmpIk#Au[Akvwֶ%GCr,{O@F'XK,%@X` `%@X` `%@X` `%@X` `%@Xa>'*@dX` `%@X` `%@X` `%@X` `%@X` `%@X` `%O k%w5hH hҖ$7l8""B@۫?$zKx`8qfȅ@^h=1[@yt݄Z8aֵh#_35rNҕ*ٹĕ½HW6Ȼ^U)0{I{b$@(eP*kB{We\#KdaÁU_ݿLJlTj[K8/*cwJo IꔫoRUIgTlN@s̮\/_4Mr--JtW67v'C or/!ip{فaۙq[Y\5>lY+/^ؿEMu& Gא~K'F&j%<א>=k@"rWj/OvM *64:=3H֟ w0{Iӕp{k\p| [9:S d&fb&fb&}\_iK >[^>?sE@爄|1\pAfƤ/6}2wuuUwg0I_&0/|yo}}Į>yq<ȱ_5&ES}p8G;NK'U @^hj҆]=vA ²[uxs0cX^[a{W 2BxF r}Wv'\CDŹ~@Tom:%S? $CZ>kn9cǎ?.!1be^:n)y*Θ3wk Aџ}W"pŨQOk/7wނLqS(Y9RKE?߿Te%fߍ/_/7jSw{d DQZ&T<AG;7ˁ}Ta+vl9pԩ];Ի ACO}7roohN|ǏHNKtԥ|O5O?F~+=D_Tjֻ-Ζmuv 2k{(fN1I!T/._Vx7 > tp2뜹󪴩iO^U{_gkc&YfDÒ%SGk?[0{}iz'7>%|5//ڲ_X޳<.oS9˜fĔMk"c sfϧ]-sX|Demꙑ^/س<6ZYZ}=+R #f;bfeޜ/Z yI!`8->ޚb(S+FQo46 `1ڴqǙfK4ex-oyB؞~Iva9×TjٞZhlҰ~nN£.+n󶲯ԮxEhk{]t]YԸ81nas 1Ϗt]*3s6ީq`_~SR-.%9g0 |o-9W]]݊+t𣏴%46M*Joj7{ZUU:,Uu^3fByZn|Y fgHGqQ&P ip!k`L.lf1jQ;4J;t.`b]]֧1haM;`\n(<{Wr7fO˗0"F/1.8b1HfȈ?s&ioHY+t vj?RMt2 $:e%'Z򶬮Uq*|}̢&yʹzXb]kdp:* 55 HfXų乲?L~ꛅ)+;Y*~/}1hh}*jxmVR2Ԭ OPEqQt2̏j}fo;IV ^mkEy@iZDu(?xb IDATV`0Z Wiu_ЄX~(`z8n^ S,9;n7% ^߹"̴Z=}eҔzMj6tgsQD^B3Vxq| u$CJY[ϚR7hlVXTy'n ,Za]bڧU:W̩HD;z^\Vgȑ3Ҳ.] [VT NTЍZ3zAR8d k+x3mh~zѕZRf¹֢d}lw)U>V^"5}5՗],Qo=O'Xyvg0h+=NYPf+0jWp;t\z,Otp5¼'suF=q„ ޞ%9g t]~YR̚y˓o|Υw^xL 7-Tp3hh-eVo}1zzVLЊ#mv2N5AZ*WY'0X뮰Zoj|T?=$~ xAjv}?z?"t^[䶤5 wLYL[nE(W> |+=}ذp@;MoqLhwuuȨQzVeǀbz}Fs*R7ӛ<QV:DlJ Q]a`G~"jnL{>'i-֚Ekr'-IW_|OpηyQ?J_{Oj.G3:9'",ڽ~p‚=#؃ |Ok/La9Gigs ?H_YvlVwWr srƔf` z ҵSʵ߽{Gu39 {M}}kSL  g(-DZ߾>+4N(Lw@=gM[w.|u_|q"z(;k+>Y[ ݖ;s7!% @=4b6#=N`<;o)~ %*>+z(_w=ozLZ\O N!IĢT|xS>DOg7yE 0KXzO<)9fM9@ r}1HONxAQW^1Wiï/ "r>L koW#..nرS:>?o4:c.4(%y1;oM:::/ O>e4Hr=ȑgeb&fb&fb&~uf~cdtOJ8[ĺuttBȐ! C^tES (?:(?:\"[\w\s()<>[\].,;:@"]+\")|[!#-'*+\-/-9=?A-Z\^-~.]+))""" "@" r"""(?P(?:(?:(?!-)[!#-'*+\-/-9=?A-Z\^-~]{1,63}(?": lambda a, b: a > b, ">=": lambda a, b: a >= b, "!=": lambda a, b: a != b, "=": lambda a, b: a == b, "LT": lambda a, b: a < b, "LE": lambda a, b: a <= b, "GT": lambda a, b: a > b, "GE": lambda a, b: a >= b, "NE": lambda a, b: a != b, "EQ": lambda a, b: a == b, "<>": lambda a, b: a != b, } def __init__(self, tokens): self.value = tokens[0] def eval(self): val1 = self.value[0].eval() for op, val in operatorOperands(self.value[1:]): fn = EvalComparisonOp.opMap[op] val2 = val.eval() if not fn(val1, val2): break val1 = val2 else: return True return False # define the parser integer = Word(nums) real = Combine(Word(nums) + "." + Word(nums)) variable = Word(alphas, exact=1) operand = real | integer | variable signop = one_of("+ -") multop = one_of("* /") plusop = one_of("+ -") expop = Literal("**") # use parse actions to attach EvalXXX constructors to sub-expressions operand.set_parse_action(EvalConstant) arith_expr = infix_notation( operand, [ (signop, 1, OpAssoc.RIGHT, EvalSignOp), (expop, 2, OpAssoc.LEFT, EvalPowerOp), (multop, 2, OpAssoc.LEFT, EvalMultOp), (plusop, 2, OpAssoc.LEFT, EvalAddOp), ], ) comparisonop = one_of("< <= > >= != = <> LT GT LE GE EQ NE") comp_expr = infix_notation( arith_expr, [ (comparisonop, 2, OpAssoc.LEFT, EvalComparisonOp), ], ) # sample expressions posted on comp.lang.python, asking for advice # in safely evaluating them rules = [ "( A - B ) = 0", "( B - C + B ) = 0", "(A + B + C + D + E + F + G + H + I) = J", "(A + B + C + D + E + F + G + H) = I", "(A + B + C + D + E + F) = G", "(A + B + C + D + E) = (F + G + H + I + J)", "(A + B + C + D + E) = (F + G + H + I)", "(A + B + C + D + E) = F", "(A + B + C + D) = (E + F + G + H)", "(A + B + C) = D", "(A + B + C) = (D + E + F)", "(A + B) = (C + D + E + F)", "(A + B) = (C + D)", "(A + B) = (C - D + E - F - G + H + I + J)", "(A + B) = C", "(A + B) = 0", "(A+B+C+D+E) = (F+G+H+I+J)", "(A+B+C+D) = (E+F+G+H)", "(A+B+C+D)=(E+F+G+H)", "(A+B+C)=(D+E+F)", "(A+B)=(C+D)", "(A+B)=C", "(A-B)=C", "(A/(B+C))", "(B/(C+D))", "(G + H) = I", "-0.99 LE ((A+B+C)-(D+E+F+G)) LE 0.99", "-0.99 LE (A-(B+C)) LE 0.99", "-1000.00 LE A LE 0.00", "-5000.00 LE A LE 0.00", "A < B", "A < 7000", "A = -(B)", "A = C", "A = 0", "A GT 0", "A GT 0.00", "A GT 7.00", "A LE B", "A LT -1000.00", "A LT -5000", "A LT 0", "G=(B+C+D)", "A=B", "I = (G + H)", "0.00 LE A LE 4.00", "4.00 LT A LE 7.00", "0.00 LE A LE 4.00 LE E > D", "2**2**(A+3)", ] vars_ = { "A": 0, "B": 1.1, "C": 2.2, "D": 3.3, "E": 4.4, "F": 5.5, "G": 6.6, "H": 7.7, "I": 8.8, "J": 9.9, } # define tests from given rules tests = [] for t in rules: t_orig = t t = t.replace("=", "==") t = t.replace("EQ", "==") t = t.replace("LE", "<=") t = t.replace("GT", ">") t = t.replace("LT", "<") t = t.replace("GE", ">=") t = t.replace("LE", "<=") t = t.replace("NE", "!=") t = t.replace("<>", "!=") tests.append((t_orig, eval(t, vars_))) # copy vars_ to EvalConstant lookup dict EvalConstant.vars_ = vars_ failed = 0 for test, expected in tests: ret = comp_expr.parse_string(test)[0] parsedvalue = ret.eval() print(test, expected, parsedvalue) if abs(parsedvalue - expected) > 1e-6: print("<<< FAIL") failed += 1 else: print("") print("") if failed: raise Exception("could not parse") ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/excel_expr.py0000644000000000000000000000432015134002420014775 0ustar00# excelExpr.py # # Copyright 2010, Paul McGuire # # A partial implementation of a parser of Excel formula expressions. # import pyparsing as pp ppc = pp.common pp.ParserElement.enable_packrat() EQ, LPAR, RPAR, COLON, COMMA = pp.Suppress.using_each("=():,") EXCL, DOLLAR = pp.Literal.using_each("!$") sheet_ref = pp.Word(pp.alphas, pp.alphanums) | pp.QuotedString("'", esc_quote="''") col_ref = pp.Opt(DOLLAR) + pp.Word(pp.alphas, max=2) row_ref = pp.Opt(DOLLAR) + pp.Word(pp.nums) cell_ref = pp.Combine( pp.Group(pp.Opt(sheet_ref + EXCL)("sheet") + col_ref("col") + row_ref("row")) ) cell_range = ( pp.Group(cell_ref("start") + COLON + cell_ref("end"))("range") | cell_ref | pp.Word(pp.alphas, pp.alphanums) ) expr = pp.Forward() COMPARISON_OP = pp.one_of("< = > >= <= != <>") cond_expr = expr + COMPARISON_OP + expr if_func = ( pp.CaselessKeyword("if") - LPAR + pp.Group(cond_expr)("condition") + COMMA + pp.Group(expr)("if_true") + COMMA + pp.Group(expr)("if_false") + RPAR ) def stat_function(name): return pp.Group(pp.CaselessKeyword(name) + pp.Group(LPAR + pp.DelimitedList(expr) + RPAR)) sum_func = stat_function("sum") min_func = stat_function("min") max_func = stat_function("max") ave_func = stat_function("ave") func_call = if_func | sum_func | min_func | max_func | ave_func mult_op = pp.one_of("* /") add_op = pp.one_of("+ -") numeric_literal = ppc.number operand = numeric_literal | func_call | cell_range | cell_ref arith_expr = pp.infix_notation( operand, [ (mult_op, 2, pp.OpAssoc.LEFT), (add_op, 2, pp.OpAssoc.LEFT), ], ) text_operand = pp.dbl_quoted_string | cell_ref text_expr = pp.infix_notation( text_operand, [ ("&", 2, pp.OpAssoc.LEFT), ], ) expr <<= arith_expr | text_expr def main(): success, report = (EQ + expr).run_tests( """\ =3*A7+5 =3*Sheet1!$A$7+5 =3*'Sheet 1'!$A$7+5 =3*'O''Reilly''s sheet'!$A$7+5 =if(Sum(A1:A25)>42,Min(B1:B25),if(Sum(C1:C25)>3.14, (Min(C1:C25)+3)*18,Max(B1:B25))) =sum(a1:a25,10,min(b1,c2,d3)) =if("T"&a2="TTime", "Ready", "Not ready") """ ) assert success if __name__ == '__main__': main() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/fourFn.py0000644000000000000000000002444415134002420014107 0ustar00# fourFn.py # # Demonstration of the pyparsing module, implementing a simple 4-function expression parser, # with support for scientific notation, and symbols for e and pi. # Extended to add exponentiation and simple built-in functions. # Extended test cases, simplified pushFirst method. # Removed unnecessary expr.suppress() call (thanks Nathaniel Peterson!), and added Group # Changed fnumber to use a Regex, which is now the preferred method # Reformatted to latest pyparsing features, support multiple and variable args to functions # # Copyright 2003-2019 by Paul McGuire # from pyparsing import ( Literal, Word, Group, Forward, alphas, alphanums, Regex, ParseException, CaselessKeyword, Suppress, DelimitedList, ) import math import operator exprStack = [] def push_first(toks): exprStack.append(toks[0]) def push_unary_minus(toks): for t in toks: if t == "-": exprStack.append("unary -") else: break bnf = None def BNF(): """ expop :: '^' multop :: '*' | '/' addop :: '+' | '-' integer :: ['+' | '-'] '0'..'9'+ atom :: PI | E | real | fn '(' expr ')' | '(' expr ')' factor :: atom [ expop factor ]* term :: factor [ multop factor ]* expr :: term [ addop term ]* """ global bnf if not bnf: # use CaselessKeyword for e and pi, to avoid accidentally matching # functions that start with 'e' or 'pi' (such as 'exp'); Keyword # and CaselessKeyword only match whole words e = CaselessKeyword("E") pi = CaselessKeyword("PI") # fnumber = Combine(Word("+-"+nums, nums) + # Optional("." + Optional(Word(nums))) + # Optional(e + Word("+-"+nums, nums))) # or use provided pyparsing_common.number, but convert back to str: # fnumber = ppc.number().add_parse_action(lambda t: str(t[0])) fnumber = Regex(r"[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?") ident = Word(alphas, alphanums + "_$") plus, minus, mult, div = map(Literal, "+-*/") lpar, rpar = map(Suppress, "()") addop = plus | minus multop = mult | div expop = Literal("^") expr = Forward() expr_list = DelimitedList(Group(expr)) # add parse action that replaces the function identifier with a (name, number of args) tuple def insert_fn_argcount_tuple(t): fn = t.pop(0) num_args = len(t[0]) t.insert(0, (fn, num_args)) fn_call = (ident + lpar - Group(expr_list) + rpar).set_parse_action( insert_fn_argcount_tuple ) atom = ( addop[...] + ( (fn_call | pi | e | fnumber | ident).set_parse_action(push_first) | Group(lpar + expr + rpar) ) ).set_parse_action(push_unary_minus) # by defining exponentiation as "atom [ ^ factor ]..." instead of "atom [ ^ atom ]...", we get right-to-left # exponents, instead of left-to-right that is, 2^3^2 = 2^(3^2), not (2^3)^2. factor = Forward() factor <<= atom + (expop + factor).set_parse_action(push_first)[...] term = factor + (multop + factor).set_parse_action(push_first)[...] expr <<= term + (addop + term).set_parse_action(push_first)[...] bnf = expr return bnf # map operator symbols to corresponding arithmetic operations epsilon = 1e-12 opn = { "+": operator.add, "-": operator.sub, "*": operator.mul, "/": operator.truediv, "^": operator.pow, } fn = { "sin": math.sin, "cos": math.cos, "tan": math.tan, "exp": math.exp, "abs": abs, "trunc": int, "round": round, "sgn": lambda a: -1 if a < -epsilon else 1 if a > epsilon else 0, # functionsl with multiple arguments "multiply": lambda a, b: a * b, "hypot": math.hypot, # functions with a variable number of arguments "all": lambda *a: all(a), } def evaluate_stack(s): op, num_args = s.pop(), 0 if isinstance(op, tuple): op, num_args = op if op == "unary -": return -evaluate_stack(s) if op in "+-*/^": # note: operands are pushed onto the stack in reverse order op2 = evaluate_stack(s) op1 = evaluate_stack(s) return opn[op](op1, op2) elif op == "PI": return math.pi # 3.1415926535 elif op == "E": return math.e # 2.718281828 elif op in fn: # note: args are pushed onto the stack in reverse order args = reversed([evaluate_stack(s) for _ in range(num_args)]) return fn[op](*args) elif op[0].isalpha(): raise Exception("invalid identifier '%s'" % op) else: # try to evaluate as int first, then as float if int fails try: return int(op) except ValueError: return float(op) if __name__ == "__main__": def test(s, expected): exprStack[:] = [] try: results = BNF().parse_string(s, parse_all=True) val = evaluate_stack(exprStack[:]) except ParseException as pe: print(s, "failed parse:", str(pe)) except Exception as e: print(s, "failed eval:", str(e), exprStack) else: if val == expected: print(s, "=", val, results, "=>", exprStack) else: print(s + "!!!", val, "!=", expected, results, "=>", exprStack) test("9", 9) test("-9", -9) test("--9", 9) test("-E", -math.e) test("9 + 3 + 6", 9 + 3 + 6) test("9 + 3 / 11", 9 + 3.0 / 11) test("(9 + 3)", (9 + 3)) test("(9+3) / 11", (9 + 3.0) / 11) test("9 - 12 - 6", 9 - 12 - 6) test("9 - (12 - 6)", 9 - (12 - 6)) test("2*3.14159", 2 * 3.14159) test("3.1415926535*3.1415926535 / 10", 3.1415926535 * 3.1415926535 / 10) test("PI * PI / 10", math.pi * math.pi / 10) test("PI*PI/10", math.pi * math.pi / 10) test("PI^2", math.pi ** 2) test("round(PI^2)", round(math.pi ** 2)) test("6.02E23 * 8.048", 6.02e23 * 8.048) test("e / 3", math.e / 3) test("sin(PI/2)", math.sin(math.pi / 2)) test("10+sin(PI/4)^2", 10 + math.sin(math.pi / 4) ** 2) test("trunc(E)", int(math.e)) test("trunc(-E)", int(-math.e)) test("round(E)", round(math.e)) test("round(-E)", round(-math.e)) test("E^PI", math.e ** math.pi) test("exp(0)", 1) test("exp(1)", math.e) test("2^3^2", 2 ** 3 ** 2) test("(2^3)^2", (2 ** 3) ** 2) test("2^3+2", 2 ** 3 + 2) test("2^3+5", 2 ** 3 + 5) test("2^9", 2 ** 9) test("sgn(-2)", -1) test("sgn(0)", 0) test("sgn(0.1)", 1) test("foo(0.1)", None) test("round(E, 3)", round(math.e, 3)) test("round(PI^2, 3)", round(math.pi ** 2, 3)) test("sgn(cos(PI/4))", 1) test("sgn(cos(PI/2))", 0) test("sgn(cos(PI*3/4))", -1) test("+(sgn(cos(PI/4)))", 1) test("-(sgn(cos(PI/4)))", -1) test("hypot(3, 4)", 5) test("multiply(3, 7)", 21) test("all(1,1,1)", True) test("all(1,1,1,1,1,0)", False) """ Test output: >python fourFn.py 9 = 9 ['9'] => ['9'] -9 = -9 ['-', '9'] => ['9', 'unary -'] --9 = 9 ['-', '-', '9'] => ['9', 'unary -', 'unary -'] -E = -2.718281828459045 ['-', 'E'] => ['E', 'unary -'] 9 + 3 + 6 = 18 ['9', '+', '3', '+', '6'] => ['9', '3', '+', '6', '+'] 9 + 3 / 11 = 9.272727272727273 ['9', '+', '3', '/', '11'] => ['9', '3', '11', '/', '+'] (9 + 3) = 12 [['9', '+', '3']] => ['9', '3', '+'] (9+3) / 11 = 1.0909090909090908 [['9', '+', '3'], '/', '11'] => ['9', '3', '+', '11', '/'] 9 - 12 - 6 = -9 ['9', '-', '12', '-', '6'] => ['9', '12', '-', '6', '-'] 9 - (12 - 6) = 3 ['9', '-', ['12', '-', '6']] => ['9', '12', '6', '-', '-'] 2*3.14159 = 6.28318 ['2', '*', '3.14159'] => ['2', '3.14159', '*'] 3.1415926535*3.1415926535 / 10 = 0.9869604400525172 ['3.1415926535', '*', '3.1415926535', '/', '10'] => ['3.1415926535', '3.1415926535', '*', '10', '/'] PI * PI / 10 = 0.9869604401089358 ['PI', '*', 'PI', '/', '10'] => ['PI', 'PI', '*', '10', '/'] PI*PI/10 = 0.9869604401089358 ['PI', '*', 'PI', '/', '10'] => ['PI', 'PI', '*', '10', '/'] PI^2 = 9.869604401089358 ['PI', '^', '2'] => ['PI', '2', '^'] round(PI^2) = 10 [('round', 1), [['PI', '^', '2']]] => ['PI', '2', '^', ('round', 1)] 6.02E23 * 8.048 = 4.844896e+24 ['6.02E23', '*', '8.048'] => ['6.02E23', '8.048', '*'] e / 3 = 0.9060939428196817 ['E', '/', '3'] => ['E', '3', '/'] sin(PI/2) = 1.0 [('sin', 1), [['PI', '/', '2']]] => ['PI', '2', '/', ('sin', 1)] 10+sin(PI/4)^2 = 10.5 ['10', '+', ('sin', 1), [['PI', '/', '4']], '^', '2'] => ['10', 'PI', '4', '/', ('sin', 1), '2', '^', '+'] trunc(E) = 2 [('trunc', 1), [['E']]] => ['E', ('trunc', 1)] trunc(-E) = -2 [('trunc', 1), [['-', 'E']]] => ['E', 'unary -', ('trunc', 1)] round(E) = 3 [('round', 1), [['E']]] => ['E', ('round', 1)] round(-E) = -3 [('round', 1), [['-', 'E']]] => ['E', 'unary -', ('round', 1)] E^PI = 23.140692632779263 ['E', '^', 'PI'] => ['E', 'PI', '^'] exp(0) = 1.0 [('exp', 1), [['0']]] => ['0', ('exp', 1)] exp(1) = 2.718281828459045 [('exp', 1), [['1']]] => ['1', ('exp', 1)] 2^3^2 = 512 ['2', '^', '3', '^', '2'] => ['2', '3', '2', '^', '^'] (2^3)^2 = 64 [['2', '^', '3'], '^', '2'] => ['2', '3', '^', '2', '^'] 2^3+2 = 10 ['2', '^', '3', '+', '2'] => ['2', '3', '^', '2', '+'] 2^3+5 = 13 ['2', '^', '3', '+', '5'] => ['2', '3', '^', '5', '+'] 2^9 = 512 ['2', '^', '9'] => ['2', '9', '^'] sgn(-2) = -1 [('sgn', 1), [['-', '2']]] => ['2', 'unary -', ('sgn', 1)] sgn(0) = 0 [('sgn', 1), [['0']]] => ['0', ('sgn', 1)] sgn(0.1) = 1 [('sgn', 1), [['0.1']]] => ['0.1', ('sgn', 1)] foo(0.1) failed eval: invalid identifier 'foo' ['0.1', ('foo', 1)] round(E, 3) = 2.718 [('round', 2), [['E'], ['3']]] => ['E', '3', ('round', 2)] round(PI^2, 3) = 9.87 [('round', 2), [['PI', '^', '2'], ['3']]] => ['PI', '2', '^', '3', ('round', 2)] sgn(cos(PI/4)) = 1 [('sgn', 1), [[('cos', 1), [['PI', '/', '4']]]]] => ['PI', '4', '/', ('cos', 1), ('sgn', 1)] sgn(cos(PI/2)) = 0 [('sgn', 1), [[('cos', 1), [['PI', '/', '2']]]]] => ['PI', '2', '/', ('cos', 1), ('sgn', 1)] sgn(cos(PI*3/4)) = -1 [('sgn', 1), [[('cos', 1), [['PI', '*', '3', '/', '4']]]]] => ['PI', '3', '*', '4', '/', ('cos', 1), ('sgn', 1)] +(sgn(cos(PI/4))) = 1 ['+', [('sgn', 1), [[('cos', 1), [['PI', '/', '4']]]]]] => ['PI', '4', '/', ('cos', 1), ('sgn', 1)] -(sgn(cos(PI/4))) = -1 ['-', [('sgn', 1), [[('cos', 1), [['PI', '/', '4']]]]]] => ['PI', '4', '/', ('cos', 1), ('sgn', 1), 'unary -'] """ ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/gen_ctypes.py0000644000000000000000000001244115134002420015002 0ustar00# # gen_ctypes.py # # Parse a .h header file to generate ctypes argtype and return type definitions # # Copyright 2004-2016, by Paul McGuire # from pyparsing import * typemap = { "byte": "c_byte", "char": "c_char", "char *": "c_char_p", "double": "c_double", "float": "c_float", "int": "c_int", "int16": "c_int16", "int32": "c_int32", "int64": "c_int64", "int8": "c_int8", "long": "c_long", "longlong": "c_longlong", "short": "c_short", "size_t": "c_size_t", "ubyte": "c_ubyte", "uchar": "c_ubyte", "u_char": "c_ubyte", "uint": "c_uint", "u_int": "c_uint", "uint16": "c_uint16", "uint32": "c_uint32", "uint64": "c_uint64", "uint8": "c_uint8", "u_long": "c_ulong", "ulong": "c_ulong", "ulonglong": "c_ulonglong", "ushort": "c_ushort", "u_short": "c_ushort", "void *": "c_void_p", "voidp": "c_voidp", "wchar": "c_wchar", "wchar *": "c_wchar_p", "Bool": "c_bool", "void": "None", } LPAR, RPAR, LBRACE, RBRACE, COMMA, SEMI = Suppress.using_each("(){},;") ident = pyparsing_common.identifier integer = Regex(r"[+-]?\d+") hexinteger = Regex(r"0x[0-9a-fA-F]+") const = Suppress("const") primitiveType = one_of(t for t in typemap if not t.endswith("*")) structType = Suppress("struct") + ident vartype = ( Opt(const) + (primitiveType | structType | ident) + Opt(Word("*")("ptr")) ) def normalizetype(t): if isinstance(t, ParseResults): return " ".join(t) # ~ ret = ParseResults([' '.join(t)]) # ~ return ret vartype.set_parse_action(normalizetype) arg = Group(vartype("argtype") + Opt(ident("argname"))) func_def = ( vartype("fn_type") + ident("fn_name") + LPAR + Opt(DelimitedList(arg | "..."))("fn_args") + RPAR + SEMI ) def derivefields(t): if t.fn_args and t.fn_args[-1] == "...": t["varargs"] = True func_def.set_parse_action(derivefields) fn_typedef = "typedef" + func_def var_typedef = "typedef" + primitiveType("primType") + ident("name") + SEMI enum_def = ( Keyword("enum") + LBRACE + DelimitedList(Group(ident("name") + "=" + (hexinteger | integer)("value")))( "evalues" ) + Opt(COMMA) + RBRACE ) c_header = open("snmp_api.h").read() module = "pynetsnmp" user_defined_types = set() typedefs = [] fn_typedefs = [] functions = [] enum_constants = [] # add structures commonly included from std lib headers def addStdType(t, namespace=""): fullname = namespace + "_" + t if namespace else t typemap[t] = fullname user_defined_types.add(t) addStdType("fd_set", "sys_select") addStdType("timeval", "sys_time") def getUDType(typestr): key = typestr.rstrip(" *") if key not in typemap: user_defined_types.add(key) typemap[key] = "{}_{}".format(module, key) def typeAsCtypes(typestr): if typestr in typemap: return typemap[typestr] if typestr.endswith("*"): return f"POINTER({typeAsCtypes(typestr.rstrip(' *'))})" return typestr # scan input header text for primitive typedefs for td, _, _ in var_typedef.scan_string(c_header): typedefs.append((td.name, td.primType)) # add typedef type to typemap to map to itself typemap[td.name] = td.name # scan input header text for function typedefs fn_typedefs = fn_typedef.search_string(c_header) # add each function typedef to typemap to map to itself for fntd in fn_typedefs: typemap[fntd.fn_name] = fntd.fn_name # scan input header text, and keep running list of user-defined types for fn, _, _ in ( c_style_comment.suppress() | fn_typedef.suppress() | func_def ).scan_string(c_header): if not fn: continue getUDType(fn.fn_type) for arg in fn.fn_args: if arg != "...": if arg.argtype not in typemap: getUDType(arg.argtype) functions.append(fn) # scan input header text for enums enum_def.ignore(cpp_style_comment) for en_, _, _ in enum_def.scan_string(c_header): for ev in en_.evalues: enum_constants.append((ev.name, ev.value)) print("from ctypes import *") print("{} = CDLL('{}.dll')".format(module, module)) print() print("# user defined types") for tdname, tdtyp in typedefs: print("{} = {}".format(tdname, typemap[tdtyp])) for fntd in fn_typedefs: print( "{} = CFUNCTYPE({})".format( fntd.fn_name, ",\n ".join(typeAsCtypes(a.argtype) for a in fntd.fn_args) ) ) for udtype in user_defined_types: print(f"class {typemap[udtype]}(Structure): pass") print() print("# constant definitions") for en, ev in enum_constants: print("{} = {}".format(en, ev)) print() print("# functions") for fn in functions: prefix = "{}.{}".format(module, fn.fn_name) print("{}.restype = {}".format(prefix, typeAsCtypes(fn.fn_type))) if fn.varargs: print(f"# warning - {prefix} takes variable argument list") del fn.fn_args[-1] if fn.fn_args.as_list() != [["void"]]: print( "{}.argtypes = ({},)".format( prefix, ",".join(typeAsCtypes(a.argtype) for a in fn.fn_args) ) ) else: print(f"{prefix}.argtypes = ()") ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/getNTPserversNew.py0000644000000000000000000000303515134002420016066 0ustar00# getNTPserversNew.py # # Demonstration of the parsing module, implementing a HTML page scanner, # to extract a list of NTP time servers from the NIST web site. # # Copyright 2004-2010, by Paul McGuire # September, 2010 - updated to more current use of set_results_name, new NIST URL # import pyparsing as pp ppc = pp.pyparsing_common from urllib.request import Request, urlopen integer = pp.Word(pp.nums) ipAddress = ppc.ipv4_address() hostname = pp.DelimitedList(pp.Word(pp.alphas, pp.alphanums + "-_"), ".", combine=True) # expressions to extract HTML table from fetched page tdStart, tdEnd = pp.make_html_tags("td") timeServerPattern = ( tdStart + hostname("hostname") + tdEnd + tdStart + ipAddress("ipAddr") + tdEnd + tdStart + tdStart.tag_body("loc") + tdEnd ) # get list of time servers from NIST nistTimeServerURL = "https://tf.nist.gov/tf-cgi/servers.cgi#" req = Request( nistTimeServerURL, headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" " (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", }, ) with urlopen(req, timeout=15) as serverListPage: serverListHTML = serverListPage.read().decode("UTF-8") addrs = {} for srvr, startloc, endloc in timeServerPattern.scan_string(serverListHTML): print(f"{srvr.ipAddr} ({srvr.hostname.strip()}) - {srvr.loc.strip()}") addrs[srvr.ipAddr] = srvr.loc ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/greet.html0000644000000000000000000000737515134002420014276 0ustar00

greet

W:(A-Za-z) ',' W:(A-Za-z) '!' | '?' | '.''!' | '?' | '.'

'!' | '?' | '.'

[!?.]
././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/greet.png0000644000000000000000000002733715134002420014116 0ustar00PNG  IHDR@JIDATx |uk 8$=9&30'# pEjhiQ8AO,1O4).JJJiQ|{Oc6k޵]uoI  @0!`B A  @0!`B A  @0!`B _rU]U(xamœΚY$hB9jW iIa󙶕{o^Y>.?ܢke s_g@^ḲZ~ ..rŦ휜a)53F^Y7~ԶIvj*&O-xjgN-*߸N vѸa~ËVygy;_ȼiJbڄe :^Y__cWl|_.97~G;ۺ*wSQ]<Y<}^W/7m- %Vx׊%?j zɼqyRy+d.xEe'ɠnߜ 杏]9q*2y3QٗY]yx- +@Ȩ2æC T7ڼ 6R V637hod䂵+姂y@MEڸ%K4 zŊiNN[dJUU˥<5\Xɀq*6hMڃKWj`cumR߸qr^&^P0۸qE[ʹomYXUոK훟@Z+vfàf.磌*/!3{洒U0௹k{ oo[pGʛ6̩Op999s rOYxZ^gb}v-.o~]:&^;Uyy^Z[VtD~~/lc28TK&Yj` oi\sAuK־bWW-VtTɤG_\TRZUW-.7"Ѕ&5^Cz-N[Qtխ]k7XXZTvW/ly׭do j~ְcR<<рk'0n'3ÿ>nq7pN:沧ZxM/c4ZHZ >1vo{jgN=hau~E~Y[Zէ$PXxʠJS3+:8tEKn̂M'<?⒒w-vL9k.8s7?Ʋ^;?qf `=<[ ڊIͧ^24ܢ`*zVf+67)6i^ (,8.*Ok%s4-O\d 0WWMA.+Ikm vg^U9cw7Wk-|+S+P yշoxNg6 $  @0!`B A  @0!`B A  @ ^ޑ@qA @'  @0!`B A  @0!`B A  @}>^_>؆ rܱǎyN/'ݦ5dËOy %# ~| /lW_}5 ;s͙;//{CHN}}}w{'/lo6mJhÇ.f;_Bgv'_'>>b>oW_SGK~{dWJooNÞ*;ܞNƒU}+ ap#@ Z7Ν;9̷s^ ~l~a~[muy}/o9'|{?޴ÞzۛٴfKՊGW>ڼ;8yI?ŗ4aQ#rM]{e]wt>w)2mآyߟw1G%/L3ߞ-=999Ia_xYwܝxɳ>87财͌ :[H/. %}=Kלa3Jo{6ۢRgS2}$S}wui Ow޵.{0^tEڵO~*CB_ 7x_>31jĬZu«3=W__O8%fƿٴ鮻I:y͵uw\wc{/s9ߐ=oKxS'/Bj@mork^gzcCtʿU?i~;K'4fvj¥[[ s9-ޚtwnnf0񒉧}j].-=y֤Iv.9P?67_<:g_Im?ztNV'׹}/9V`/})Wg;6NG䥵{6d['NXL9w̞M Meoﯶ]]5>Y5=9lİ͌`7Zd(H[\p ;pẺgy&3s{:b]gY'N_3t=?P_[t߿ѳ+3C̜خa ?xlQ-nO{KḤU8vo?~ݺ[ǽnq Eڭ}/Q޸N=m]xd3n,8!E*ʕ Ml.OkqS/fݵǘ9g ?͇kCl${'d?7{ǟ 6mO}H~QǮݯw Mn]xE~gm^>5϶[)'[hT4;+uX f]^t!eMIVMh;śuwΨ·cFuIF tR}7睴3۶m NsS$n>cNxm}~vZ -H֮ݲ sڪI1e&ٳuԊNNme* ih^AK~VL24IkkS'6mNGeIA~>_&~IDATdUR0y\~20k*Z9_2amvRS[,-K/@>WhxK{yy3M @O;zMd6;g[W,?yfyUm摦+c0uԍC=z-{m{Y:`ٞ:{(y7Nvךgj+WL\PmSY_%OƵ{_:=i3y,u>puo.9쇤n=nҍK_76/k sO=|{ۃKWbڕ˓1%UEm>#=_gf4=N:Wiݧa*gOe{˞kNͫL^o*5S4x)IکekJ6us:zaMڔ,Z\ܞ&ݲYWfL%\`ڜs^en|lMk-_j>:I}D2cU2~QòalԼy.@Й~ysKX7u_Hz՟+>/ow|)v.Y}i裏 \OٲlU2}ܐqŋ`ȹaoʢ.32^S>KҖڥW0hP͆_6\IzUYo ՙC?ªUƟ[6~ԯl-]EΙ67^m=nqAKoZiM錃&Tz޶ 7ˆV6 K|I*̜<٦9g.b98aq+7Cʄk%5cԒg$&ThVP.-iaKWn(Պ%ױþ!S+g M:l{JΣ)?93Zu;}Z&;n۾ppFC!v3p޸$~ԅ㓚Ӌ矹Z0E/p߫F?XΛ㤫ƦWuǻxId+׏GV<]qT^wfvΌUvIf5uXǏ_NHکk{E;zՋꝩO>~3mؐd%I7غpę[:̻5n\MN%З]{e] kI7vn+i>: o t^9刁NK3?QmSf,;g̜&JWkatuoG3[|_{5&2|']3H:lƌd} }arh~34lK;*});ǒS sSMIw(.s9 '_3nܸzcfo.IگӇ=}85L&Sg;sy2RK.7dj Z[s']poAta^/-(f7x؈aqHk%_̷3ˮʗ#7ڹ;~M};hO K1w;ei۷#'+`{a_wtwA=vͻzhb 4p uys֯ߐ/:g^4#njLbK>RG7Z\M^ۺToxd#HjܼҙM9coS>?t~3>nqv[oX@/37ה,kŸ쁄=~w.9#N{OgKƒU}+ aW`p' s˾yqرS>:9Ón&wS> /'7ox|߽¶mW>9'.K>`ӷ80I}"X0!`B A  @0!`B A  @9   @0!`B A  @0!`B A  @0!`B/9UdV&!?2 @]]qUm^w[2qל…ڼT7bWһe^ҀqVVCe#m?87/jV3'8<|$ m^{~Y}}Q_X8),.W|pj~i{k_V_:@-r߂¤hUק|>{p&Mlkp{k_V:@uNگYh{[X2nC3^pEܱ#ՇзeMgh巹kn$;rOztM޴j]qX{Z7o^[ݮy鵬5YZRQ__ xumю՗Ч`ݍ9ge=}V]4g² tYI@O) ..NQݱz@n^BJg^y֖mc8//r7g[,\];VWkJpKᷯ-/7iIu;tKoVچT?m%!Wŝӧnڽ- @o\WQLb]2}O?* ('Ap^+G6n.:i㒀,cP9=ޡn;n] b*q`u0!`BS__ 0!`B A  @0!`B A  @0!`Bp~ 1pP`B A  @0!`B A  @0!`Bx~տӿ}_|1Q|א!Ç/>&(,Lr[|ൗw$O>yeiS+vagbG |y)oYz׿ku⃽\rȑ'&ȣSSܩcǞqv=   ^>;ws~os;GMlRjEգ+m~w?鼤CRi`5~j@}T_hlѼ;꘣!U㩷:-_|wNm䥗qǍ/SY++3=z[L>'xHw}ɧ.M9})x/xĨJzO8%fƿٴ鮻I!}) /.<:gt䥵<4}v>f7<{MҦK G7xҭzڄι[oM!})Wg;,1tuOgk~C's1sS{;`Ռ@CVgvNqUd6l;՗xƍ{O}o-LUK?V7lH })mۖxjoۆgfӯ_̌m}@OŢ|IDAT 5]>v죫W':u3GS-/tF<'R+,K}%2閿t@pR>y7?G/3&zOQE*&oF@~ؼG[7l?={F'鰒9pϤ˒Stئ_m -\K.nSV>ϾהQZח.uGgm|.鄆gssBl ''Tt2c̹S5~ZO ~e+۞o~QzB_ &~83XǤT[W|j|96 3RG}IO2+g\CRva ߘdMe7-pom]Zzىkدfc5SɄYΜtҗ8cf*>_琲5|ڹӆL^SǮF_v[s}͝[~Cj|>9fdң~[ڧ7", greet.parse_string(hello)) # parse a bunch of input strings greet.run_tests( """\ Hello, World! Ahoy, Matey! Howdy, Pardner! Morning, Neighbor! """ ) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/greetingInGreek.py0000644000000000000000000000065115134002420015713 0ustar00# # greetingInGreek.py # # Demonstration of the parsing module, on the prototypical "Hello, World!" example # # Copyright 2004-2016, by Paul McGuire # from pyparsing import Word, pyparsing_unicode as ppu # define grammar alphas = ppu.Greek.alphas greet = Word(alphas) + "," + Word(alphas) + "!" # input string hello = "Καλημέρα, κόσμε!" # parse input string print(greet.parse_string(hello)) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/greetingInKorean.py0000644000000000000000000000075715134002420016104 0ustar00# # greetingInKorean.py # # Demonstration of the parsing module, on the prototypical "Hello, World!" example # # Copyright 2004-2016, by Paul McGuire # from pyparsing import Word, pyparsing_unicode as ppu korean_chars = ppu.한국어.alphas korean_word = Word(korean_chars, min=2) # define grammar greet = korean_word + "," + korean_word + "!" # input string hello = "안녕, 여러분!" # "Hello, World!" in Korean # parse input string print(greet.parse_string(hello)) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/groupUsingListAllMatches.py0000644000000000000000000000100015134002420017563 0ustar00# # A simple example showing the use of the implied list_all_matches=True for # results names with a trailing '*' character. # # This example performs work similar to itertools.groupby, but without # having to sort the input first. # # Copyright 2004-2016, by Paul McGuire # from pyparsing import Word, ZeroOrMore, nums aExpr = Word("A", nums) bExpr = Word("B", nums) cExpr = Word("C", nums) grammar = ZeroOrMore(aExpr("A*") | bExpr("B*") | cExpr("C*")) grammar.run_tests("A1 B1 A2 C1 B2 A3") ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/hola_mundo.py0000644000000000000000000000402715134002420014770 0ustar00# escrito por Marco Alfonso, 2004 Noviembre # importamos los símbolos requeridos desde el módulo from pyparsing import ( Word, one_of, nums, Group, OneOrMore, Opt, pyparsing_unicode as ppu, ) # usamos las letras en latin1, que incluye las como 'ñ', 'á', 'é', etc. alphas = ppu.Latin1.alphas # Aqui decimos que la gramatica "saludo" DEBE contener # una palabra compuesta de caracteres alfanumericos # (Word(alphas)) mas una ',' mas otra palabra alfanumerica, # mas '!' y esos seian nuestros tokens saludo = Word(alphas) + "," + Word(alphas) + one_of("! . ?") tokens = saludo.parse_string("Hola, Mundo !") # Ahora parseamos una cadena, "Hola, Mundo!", # el metodo parse_string, nos devuelve una lista con los tokens # encontrados, en caso de no haber errores... for i, token in enumerate(tokens): print(f"Token {i} -> {token}") # imprimimos cada uno de los tokens Y listooo!!, he aquí a salida # Token 0 -> Hola # Token 1 -> , # Token 2-> Mundo # Token 3 -> ! # ahora cambia el parseador, aceptando saludos con mas que una sola palabra antes que ',' saludo = Group(OneOrMore(Word(alphas))) + "," + Word(alphas) + one_of("! . ?") tokens = saludo.parse_string("Hasta mañana, Mundo !") for i, token in enumerate(tokens): print(f"Token {i} -> {token}") # Ahora parseamos algunas cadenas, usando el metodo run_tests saludo.run_tests("""\ Hola, Mundo! Hasta mañana, Mundo ! """, full_dump=False, ) # Por supuesto, se pueden "reutilizar" gramáticas, por ejemplo: numimag = Word(nums) + "i" numreal = Word(nums) numcomplex = numimag | numreal + Opt("+" + numimag) # Funcion para cambiar a complejo numero durante parsear: def hace_python_complejo(t): valid_python = "".join(t).replace("i", "j") for tipo in (int, complex): try: return tipo(valid_python) except ValueError: pass numcomplex.set_parse_action(hace_python_complejo) numcomplex.run_tests("""\ 3 5i 3+5i """) # Excelente!!, bueno, los dejo, me voy a seguir tirando código... ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.691751 pyparsing-3.3.2/examples/html_stripper.py0000644000000000000000000000326715134002420015544 0ustar00# # html_stripper.py # # Sample code for stripping HTML markup tags and scripts from # HTML source files. # # Copyright (c) 2006, 2016, 2023, Paul McGuire # from urllib.request import urlopen from pyparsing import ( LineEnd, quoted_string, make_html_tags, common_html_entity, replace_html_entity, html_comment, any_open_tag, any_close_tag, replace_with, ) # if

Regex Inverter

by Paul McGuire, January 2026

Description

This page allows you to invert a regular expression, generating strings that match it.

Instructions: Enter a regular expression in the "Regex" field and specify the maximum number of results you want to see (up to 100,000,000). Click "Invert" or press Enter to generate the matching strings.

Constraints:

  • Unbounded repetition operators + and * are not supported.
  • Replace + or * with explicit {1,n} or {min,max} repetition operators (e.g., use an explicit repetition like [A-Z]{1,4} instead of [A-Z]+, or [A-Z]{,4} instead of [A-Z]*).
  • For brevity, all generated strings in this utility are limited to 7-bit ASCII characters. By default, Python's re methods will match the full Unicode set, so macros like \d could match numeric digits in other language character sets beyond just the ASCII digits '0' through '9'.

Note: Complex regular expressions or those with large repetition counts may take some time to process.

Regular Expressions Quick Reference
ConstructDescription
.Any character except newline
\dDigit [0-9]
\wWord (identifier) character [a-zA-Z0-9_]
\sWhitespace character
\DNon-digit
\WNon-word character
\SNon-whitespace character
?0 or 1 repetition
{n}Exactly n repetitions
{n,m}Between n and m repetitions
{,m}0 to m repetitions
[...]Character class (any of these characters)
[^...]Negated character class
|Alternation (OR)
(...)Grouping
(?:...)Grouping (non-capturing)
(?P<name>...)Grouping (named group)
Other common regex features not covered in this utility
^Start of a line
$End of a line
\AStart of string
\ZEnd of string
*0 or more repetitions (use {,m} to limit repetitions)
+1 or more repetitions (use {1,m} to limit repetitions)
\bWord boundary
(?=...)Positive lookahead
(?!...)Negative lookahead
(?<=...)Positive lookbehind
(?<!...)Negative lookbehind

Examples

Here are some example regular expressions to try:

DescriptionRegex
Match one uppercase letter followed by three digits [A-Z]-\d{3}
Time of day (HH:MM:SS) (2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])
8-bit binary numbers [01]{8}
Integer from 0 to 99 [1-9]?\d
Integer from 0 to 255 25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d
Roman Numerals to 50 (X{,3}|XL)(I{,3}|IV|VI{,3}|IX)|L
Chemical Symbol A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|S[bcegimnr]?|T[abcehilm]|U(u[bhopqst])?|V|W|Xe|Yb?|Z[nr]
IPv4 addresses in 192.168.0.0/16 192\.168(\.((25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d))){2}
MAC address [0-9A-Fa-f]{2}([:-][0-9A-Fa-f]{2}){5}
UUID [0-9A-F]{8}(-[0-9A-F]{4}){3}-[0-9A-F]{12}
Original US Area codes (leading and trailing digit 2-9, middle digit 1 or 0) [2-9][10][2-9]

Enter a regular expression to see its matching strings.

Powered by PyScript and pyparsing

packages = ["pyparsing"] [[fetch]] files = ["inv_regex.py"] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/regex_inverter/inv_regex.py0000644000000000000000000002147415134002420017666 0ustar00# # original file: https://raw.githubusercontent.com/pyparsing/pyparsing/pyparsing_3.0.9/examples/invRegex.py # # Copyright 2008, Paul McGuire # # pyparsing script to expand a regular expression into all possible matching strings # Supports: # - {n} and {m,n} repetition, but not unbounded + or * repetition # - ? optional elements # - [] character ranges # - () grouping # - | alternation # __all__ = ["count", "invert"] from pyparsing import ( Literal, one_of, Empty, printables, ParserElement, Combine, Optional, SkipTo, infix_notation, ParseFatalException, Word, nums, OpAssoc, Suppress, ParseResults, srange, autoname_elements, Regex, ) ParserElement.enable_packrat() class CharacterRangeEmitter: def __init__(self, chars): # remove duplicate chars in character range, but preserve original order seen = set() self.charset = "".join(seen.add(c) or c for c in chars if c not in seen) def __str__(self): return "[" + self.charset + "]" def __repr__(self): return "[" + self.charset + "]" def make_generator(self): def gen_chars(): yield from self.charset return gen_chars class OptionalEmitter: def __init__(self, expr): self.expr = expr def make_generator(self): def optional_gen(): yield "" yield from self.expr.make_generator()() return optional_gen class DotEmitter: def make_generator(self): def dot_gen(): yield from printables return dot_gen class GroupEmitter: def __init__(self, exprs): self.exprs = ParseResults(exprs) def make_generator(self): def group_gen(): def recurse_list(elist): if len(elist) == 1: yield from elist[0].make_generator()() else: for s in elist[0].make_generator()(): for s2 in recurse_list(elist[1:]): yield s + s2 if self.exprs: yield from recurse_list(self.exprs) return group_gen class AlternativeEmitter: def __init__(self, exprs): self.exprs = exprs def make_generator(self): def alt_gen(): for e in self.exprs: yield from e.make_generator()() return alt_gen class LiteralEmitter: def __init__(self, lit): self.lit = lit def __str__(self): return "Lit:" + self.lit def __repr__(self): return "Lit:" + self.lit def make_generator(self): def lit_gen(): yield self.lit return lit_gen def handle_range(toks): inner = toks[0][1:-1] if inner.startswith("^"): range_chars = set(printables) - set(srange(f"[{inner[1:]}]")) return CharacterRangeEmitter(sorted(range_chars)) return CharacterRangeEmitter(srange(toks[0])) def handle_repetition(toks): toks = toks[0] if toks[1] in "*+": raise ParseFatalException("", 0, "unbounded repetition operators not supported") if toks[1] == "?": return OptionalEmitter(toks[0]) if "count" in toks: return GroupEmitter([toks[0]] * int(toks.count)) if "minCount" in toks: mincount = int(toks.minCount) maxcount = int(toks.maxCount) optcount = maxcount - mincount if optcount: opt = OptionalEmitter(toks[0]) for i in range(1, optcount): opt = OptionalEmitter(GroupEmitter([toks[0], opt])) return GroupEmitter([toks[0]] * mincount + [opt]) else: return [toks[0]] * mincount def handle_literal(toks): lit = "" for t in toks: if t[0] == "\\": if t[1] == "t": lit += "\t" else: lit += t[1] else: lit += t return LiteralEmitter(lit) def handle_macro(toks): macro_char = toks[0][1] if macro_char == "d": return CharacterRangeEmitter("0123456789") elif macro_char == "w": return CharacterRangeEmitter(srange("[A-Za-z0-9_]")) elif macro_char == "s": return LiteralEmitter(" ") elif macro_char == "D": return CharacterRangeEmitter(sorted(set(printables + " ") - set("0123456789"))) elif macro_char == "W": return CharacterRangeEmitter( sorted(set(printables + " ") - set(srange("[A-Za-z0-9_]"))) ) elif macro_char == "S": return CharacterRangeEmitter(printables) else: raise ParseFatalException( "", 0, "unsupported macro character (" + macro_char + ")" ) def handle_sequence(toks): return GroupEmitter(toks[0]) def handle_dot(): return CharacterRangeEmitter(printables) def handle_alternative(toks): return AlternativeEmitter(toks[0]) _parser = None def parser(): global _parser if _parser is None: ParserElement.set_default_whitespace_chars("") lbrack, rbrack, lbrace, rbrace, lparen, rparen, colon, qmark = ( Literal.using_each("[]{}():?") ) re_macro = Combine("\\" + one_of("d w s D W S")) escaped_char = ~re_macro + Combine("\\" + one_of(list(printables))) re_literal_char = ( "".join(c for c in printables if c not in r"\[]{}().*?+|") + " \t" ) re_range = Combine(lbrack + SkipTo(rbrack, ignore=escaped_char) + rbrack) # type: ignore re_literal = escaped_char | one_of(list(re_literal_char)) re_non_capture_group = Suppress("?:") re_named_group = Suppress(Regex(r"\?P<\w+>")) re_dot = Literal(".") repetition = ( (lbrace + Word(nums)("count") + rbrace) | ( lbrace + Optional(Word(nums), default=0)("minCount") + "," + Word(nums)("maxCount") + rbrace ) | one_of(list("*+?")) ) re_range.add_parse_action(handle_range) re_literal.add_parse_action(handle_literal) re_macro.add_parse_action(handle_macro) re_dot.add_parse_action(handle_dot) re_term = ( re_literal | re_range | re_macro | re_dot | re_non_capture_group | re_named_group ) re_term.set_name("re_term") alt_op = Suppress("|") seq_op = Empty() autoname_elements() re_expr = infix_notation( re_term, [ (repetition, 1, OpAssoc.LEFT, handle_repetition), (seq_op, 2, OpAssoc.LEFT, handle_sequence), (alt_op.set_name("re"), 2, OpAssoc.LEFT, handle_alternative), ], ) _parser = re_expr return _parser def count(gen): """Simple function to count the number of elements returned by a generator.""" return sum(1 for _ in gen) def invert(regex): r""" Call this routine as a generator to return all the strings that match the input regular expression. for s in invert(r"[A-Z]{3}\d{3}"): print s """ invre = GroupEmitter(parser().parse_string(regex, parse_all=True)).make_generator() return invre() def main(): tests = r""" abc|def [A-EA] [A-D]* [A-D]{3} X[A-C]{3}Y X[A-C]{3}\( X\d foobar\d\d foobar{2} foobar{2,9} fooba[rz]{2} (foobar){2} ([01]\d)|(2[0-5]) (?:[01]\d)|(2[0-5]) ([01]\d\d)|(2[0-4]\d)|(25[0-5]) [A-C]{1,2} [A-C]{0,3} [A-C]\s[A-C]\s[A-C] [A-C]\s?[A-C][A-C] [A-C]\s([A-C][A-C]) [A-C]\s([A-C][A-C])? [A-C]{2}\d{2} @|TH[12] @(@|TH[12])? @(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9]))? @(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9])|OH(1[0-9]?|2[0-9]?|30?|[4-9]))? (([ECMP]|HA|AK)[SD]|HS)T [A-CV]{,2} A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|S[bcegimnr]?|T[abcehilm]|Uu[bhopqst]|U|V|W|Xe|Yb?|Z[nr] (a|b)|(x|y) (a|b) (x|y) [ABCDEFG](?:#|##|b|bb)?(?:maj|min|m|sus|aug|dim)?[0-9]?(?:/[ABCDEFG](?:#|##|b|bb)?)? (Fri|Mon|S(atur|un)|T(hur|ue)s|Wednes)day A(pril|ugust)|((Dec|Nov|Sept)em|Octo)ber|(Febr|Jan)uary|Ju(ly|ne)|Ma(rch|y) \S-\d{2} \D{2}-\W [^A-Z]-\d{3} """.splitlines() for t in tests: t = t.strip() if not t: continue print("-" * 50) print(t) try: num = count(invert(t)) print(num) maxprint = 30 for s in invert(t): print(s) maxprint -= 1 if not maxprint: break except ParseFatalException as pfe: print(pfe.msg) print("") continue print("") if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/removeLineBreaks.py0000644000000000000000000000350315134002420016076 0ustar00# removeLineBreaks.py # # Demonstration of the pyparsing module, converting text files # with hard line-breaks to text files with line breaks only # between paragraphs. (Helps when converting downloads from Project # Gutenberg - https://www.gutenberg.org/ - to import to word processing apps # that can reformat paragraphs once hard line-breaks are removed.) # # Uses parse actions and transform_string to remove unwanted line breaks, # and to double up line breaks between paragraphs. # # Copyright 2006, by Paul McGuire # import pyparsing as pp line_end = pp.LineEnd() # define an expression for the body of a line of text - use a predicate condition to # accept only lines with some content. def mustBeNonBlank(t): return t[0] != "" # could also be written as # return bool(t[0]) lineBody = pp.SkipTo(line_end).add_condition( mustBeNonBlank, message="line body can't be empty" ) # now define a line with a trailing line_end, to be replaced with a space character textLine = lineBody + line_end().set_parse_action(pp.replace_with(" ")) # define a paragraph, with a separating line_end, to be replaced with a double newline para = pp.OneOrMore(textLine) + line_end().set_parse_action(pp.replace_with("\n\n")) # run a test test = """ Now is the time for all good men to come to the aid of their country. """ print(para.transform_string(test)) # process an entire file # Project Gutenberg EBook of Successful Methods of Public Speaking, by Grenville Kleiser # Download from http://www.gutenberg.org/cache/epub/18095/pg18095.txt # with open("18095-8.txt") as source_file: original = source_file.read() # use transform_string to convert line breaks transformed = para.transform_string(original) with open("18095-8_reformatted.txt", "w") as transformed_file: transformed_file.write(transformed) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/roman_numerals.py0000644000000000000000000000722515134002420015670 0ustar00# romanNumerals.py # # Copyright (c) 2006, 2019, Paul McGuire # import pyparsing as pp def roman_numeral_literal(numeral_string, value): return ( pp.Literal(numeral_string) .set_parse_action(pp.replace_with(value)) .leave_whitespace() ) one = roman_numeral_literal("I", 1) four = roman_numeral_literal("IV", 4) five = roman_numeral_literal("V", 5) nine = roman_numeral_literal("IX", 9) ten = roman_numeral_literal("X", 10) forty = roman_numeral_literal("XL", 40) fifty = roman_numeral_literal("L", 50) ninety = roman_numeral_literal("XC", 90) onehundred = roman_numeral_literal("C", 100) fourhundred = roman_numeral_literal("CD", 400) fivehundred = roman_numeral_literal("D", 500) ninehundred = roman_numeral_literal("CM", 900) onethousand = roman_numeral_literal("M", 1000) # lenient parser - passes all legal Roman numerals but does not detect illegal # numeral = ( # onethousand # | ninehundred # | fivehundred # | fourhundred # | onehundred # | ninety # | fifty # | forty # | ten # | nine # | five # | four # | one # ) # # roman_numeral = numeral[1, ...].set_parse_action(sum) # strict parser - rejects illegal Roman numerals roman_numeral = ( onethousand[...] + (ninehundred | fourhundred | fivehundred[0, 1] + onehundred[0, 3])[0, 1] + (ninety | forty | fifty[0, 1] + ten[0, 3])[0, 1] + (nine | four | five[0, 1] + one[0, 3])[0, 1] ).set_parse_action(sum) pp.autoname_elements() # unit tests def make_roman_numeral(n): def add_digits(n, limit, c, s): while n >= limit: n -= limit s += c return n, s ret = "" n, ret = add_digits(n, 1000, "M", ret) n, ret = add_digits(n, 900, "CM", ret) n, ret = add_digits(n, 500, "D", ret) n, ret = add_digits(n, 400, "CD", ret) n, ret = add_digits(n, 100, "C", ret) n, ret = add_digits(n, 90, "XC", ret) n, ret = add_digits(n, 50, "L", ret) n, ret = add_digits(n, 40, "XL", ret) n, ret = add_digits(n, 10, "X", ret) n, ret = add_digits(n, 9, "IX", ret) n, ret = add_digits(n, 5, "V", ret) n, ret = add_digits(n, 4, "IV", ret) n, ret = add_digits(n, 1, "I", ret) return ret def main(): import contextlib with contextlib.suppress(Exception): # generate railroad diagram roman_numeral.create_diagram("roman_numerals_diagram.html") # make a string of all roman numerals from I to MMMMM tests = " ".join(make_roman_numeral(i) for i in range(1, 5000 + 1)) # parse each roman numeral, and populate map for validation below roman_int_map = {} for expected, (t, s, e) in enumerate(roman_numeral.scan_string(tests), start=1): orig = tests[s:e] assert t[0] == expected, f"==> Incorrect result for {orig}: {t}" roman_int_map[orig] = t[0] def verify_value(s, tokens): expected_value = roman_int_map[s] if tokens[0] != expected_value: raise Exception( f"incorrect value for {s} ({tokens[0]}), expected {expected_value}" ) success1, _ = roman_numeral.run_tests( """\ XVI XXXIX XIV XIX MCMLXXX MMVI MMMMM """, parse_all=True, post_parse=verify_value, ) assert success1, "failed to parse one or more legal Roman numerals" print("\nRun failure tests") success2, _ = roman_numeral.run_tests( """\ # too many X's XXXX # X after XL XLX """, parse_all=True, failure_tests=True, ) assert success2, "parsed one or more illegal Roman numerals" if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/roman_numerals_diagram.html0000644000000000000000000007332615134002420017675 0ustar00

roman_numeral

onethousandonethousand ninehundredninehundred fourhundredfourhundred fivehundredfivehundred onehundredonehundred onehundredonehundred onehundredonehundred ninetyninety fortyforty fiftyfifty tenten tenten tenten ninenine fourfour fivefive oneone oneone oneone

onethousand

'M'

ninehundred

'CM'

fourhundred

'CD'

fivehundred

'D'

onehundred

'C'

ninety

'XC'

forty

'XL'

fifty

'L'

ten

'X'

nine

'IX'

four

'IV'

five

'V'

one

'I'
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/roman_numerals_diagram.png0000644000000000000000000017353715134002420017522 0ustar00PNG  IHDRXtIDATxUe?g-LFP) 1f頖mAZw&e)*[9 Ю0ZcΈc+jLZA{03 {ϼ߯ysϿ{9>9{skP  'H8A0@ N p`$   'H8A0@ N p`$   'H8A0@ N pٹ9-䕬`sE0=G`sE0@µEpŜN- [j.~<$[Zεj!meam.NY~;s 1W>0j/B[l fqѐmo0Ee^Nl֗vٳM^5GEpוS ]N=xyeSoN:joYYW,W0, ˭EsRۼeU-Kfpt~IɰUV69ǵmӔnv St2?]uξrGaIA\/,baEK]tҒe͓aÆ4{8"7tNnn<dzUխO0ef3 ֯k oLx\aG}(*-'t[It;@\HZU^Q/we%S>ChgKTV겞YVOme=z%%S=N/JپUs<|ʽUK&+CSo-_6+oHY65͗`5<+ȝ~XWV@8̻/~N74}"]Z#&Qނ} .3yi7k65iцT}Z]҉͞*f~c5%3=xEpʰy7T.tȡ}*ZSJ,ov_-7 M-և=%d!Eׯ[4et>rҴ+{f*Э&>qã-4[WVn\޵+~+HAD$   7 k%Cr:'wz=wsjX\GG?8ti @ȩ $$   'H8A0@ N p`$   'H8A0@ N p`$\Ao d?W$   'H8A0@ N p`$   'H8A0@ N p`$  oݺu+V^v3/ґGUc}}߁~㏛;4HdM[?l+,w,Yg{~r3#O;O;#F半 ;vxR֮}|'jÏ;{n23,@7jrG$*^˧ݸcN8cQnnn -\1cꩧ*?vj֭[>yן7}Z2Οcq}gNNN-CF*XnjOITwuw f=~l1?/{CV19[;8YATbE^?Ŋ?UZTԃ+o_~vrGԤ>agy&*v؈zr vI+EC EES>~g,]rDž}\)0d kCiJ M=\Aɩ߿".~@v/ƅʪ 6No~/d#N=%.7:EU*Xnfrg%VUUUq W]9W{*+O??wߨPVϖGʆ6^teH5*XXigZ:d/ jJqaqր/kk:mPа _/t= ڦn&W{V_ŅV/}jlm۶?9* 8pL~~ ;* tkFc @֊ZtQ#~WowjC MIU+'N툞k7꽮wu~7hP_Ԛ5pnCBco..UWCQT 2dO[oUWWuQZI:]*Xmlؐy.<'˟ aIqvzՕsvz kBn@g &@TѝjJZChj^|7:>M?qc3kFƌڵ]) Z.'W{\%K3?@mlM7w|Ɖ;}A Oַ,q㽉vK`Tj >s7nG~'@}%ql$IDATƛn^#K}K\NGEM|]]ng2,@7u!o߾/]c[rrrB[xFθq! CZ}yAz% Ϊ >M8ĨHw3regM?/nT8O`<`\NC7Ze3ƥ|7BwIe|c\_ʨk;BKQْi:\e, Np ⇗;ER!Bd{6ƊY`oT0餯\[:͛<+&/6 n@vkV2~n  q{Q逸Z%[QtS3}&ڠO>TE>Vqxt+sCQ] ]}[p[ٟ97jeǎ7uTT}u_ZBnqkwFΪ[^_C`b<,M0xAŽQ3ˇ֖ok6K3ͭI=k_w[_ n|vYT ~5̅lNeXyVe;^5R`gEѤhni^{AmP(_ʐ>&xkImY+ne@?&o-67W/*wT;~ر¶軤쯙;.7Q|Z^sE[3&oxرlf3WLXJTXVͯkyҝWT&jq6|6a^{^Nۯ5[CV߹z[73rWƕ^YBmk*>|^6ƹpA*hN])F2v=ήʛVG ydǷ 7Έ¹v *֏꛳ zmu`cm7o>ӟ|aC/⣏>Sұע?u`gЩE,}9fH寅칟9goXjw,Yg=OuZo4/~ Џuoik133 ;]X-<$쐺AGTURiMSwdjTП;1w}]?]嫮,:=RD獞}g=w|7Ws: =tCq/57ѩ玛r`vVt,~뮻4MϞ:[;>xL"8. q f0X,nlaכŅcpC-PxxqMn [;g-al|aZϞoů{X_pQk7GJiz-ŷ|5/ [V^pHM~w'ӫF#?_7=S;񎿼Z k{DG*ÝWB̝ Rۯ5JU_ᐶ -giv+(YanUq;d6޺gP-yۤjm^!7_壎:Ug6ĉoQӿdMȁoa{G"on;gm9M.GְfqTd+wYFOv,-7sEpUP~;Rィ~|?^o߾CGQy̘_=?M騶Y\~τ 0o޷S}[ʰ 7}Q#;*5/Pۭ`mٲ%/g{敽+hsKǯug΂CKHg Ϙ:w߿=rʲxȐ!?\%{)|ώ˷-X2Ü9_:=!VRDҌ )B:(o RZrgvd,@7ӟŅ#?<R>_ 6?,\rBeeՆ Bfk_ 7oz:=a}ŅI>2䢢ܸ|O g;usӻB ;֮]R!2oUUUq QE gX? @OxW˜1!>:./س&XQfMFӂ ;4t _Vqaq_0>.)dA?c\~%۶eh^n2 ;^j~{ݾCŅCLxkzՇ>y<* }Bjjjo*C4ޗ3 7 pԧf_!|d#,Y“. 1^{q!BƘ8aBFΎ툞ۿiݞg?W_ :ϯ Æ cȐ!q @O5QPtAi{W8!؎/]Cqa3׮ ˲3&7mHϜr+6mǍuc *C>>Pby2C"O~".,YDZGM7Dž=vpW@/A)ڟo>P%߾%._z}%8po˫yKW\}@ZiϋS 'G&NpWZZp„ ͛7yW&L*_ROžky8~ى'6y'_P01ck@z+G]쥗^,6Cz? 􎫮+2UigZ:d&#]yL WEs?_2b/M z׻G=0}u g}ay}OUyƦ999q᭷ @m۶-d32 z>0 '؀ }~%K=裁eS?{g>gkԭ ۿvkݺͪ:*IDAT[/mlؐ=| / 3*XQVtOWŸ}'1EM  @=vmfkyFNd&,@7ƅw]w]C@[ŅM6螬)>2 ;o[\>B!zMn@7.Y4d%Kx@PtS睮~ƛn^#蒷~M߸qSfϟ1TP%߾%K`hE"vc7/z~x!s̘'}z%߾Ƿmz <@[T/2/=?_/cU5oV40}>Og$>>Ͼ^xۣT^>xfy^>qܸKWK//X#Yk^硴aY3he!J_ *v*\3P}qT OO3M-xP{%e jZ5޳7%~_NG~^ &NjukO=p{s YG_+WFKك`ϚJǝP3wܸBtD5\(CRh8n6;!z[EKn1;hz׻GUTЊ}GV=|i17n]`!G}6|_r-(-7!E ϻ +!(谒[smjTa(4:6԰Yb̽\CG%ڬ`woDqAV|'W'~I Gx] /uPy5љjpԒem% _ K{g4\¶';ܹ;(e9;*1k57wϾԵT>xʳDg/֟ϸə8awu}fօ,e.o%'pBu pIoEfWwFnYߌs˷ *Kߩ`]cP 3_^Zȵ~A;_5իyr |{Ac6poV7 ۹¼A&[nY!앷N/:+|9Nϛ3.p;3]N7He+**~c[4_^+g+_s!;"13 ڱl?ԥצx7|tKtCץ.mDw7f\^*mX={jPSzHu[+8r̿M*;;,u)<t90(>8̭S}ͭi`Oe@?`:enP/T\8f}rRtZS:.46TcpF"^*wHX0van{o-Ա{JI6, [o[㸂~zm\ Њ͛7zipذ^|Guafǎ_ڵlܸ) |G]{wg4FvvGd3,} :xʪ&9wWj O;O:L]R]]gטpyǢ\)| \Ts>>XHty/Μ㩧*/uQ>ߚwyӧH ,->iLn^\sE߅:Fʲ^~0dȐ.Z[Q ktz >s?*XzP::唏sq `f߿".~@FںukV^v3/ґGU{8=wA}O)CYt)?'Q555o\Gl%clq_nݺ+*{W2޾< 7yrѨ=\ŻN] \YYaÆ8 ;`fpq2 fE'cC8JO;4 Ž;k;ٸqSt4ۏhbNK?/}O;Fc|iqiGyĨQQxQuϖ߿,TXx~pVK"0 9%(uuuv^ w, @Q5&}朳;棏=?EvK3'''tҐ!Cₛޮ n59% ̗󗧞`Eq >|kM*Q^i`U_%*g^p{LƊtct @/#_5끕;tAe+_tWTIDATX (0*XcQVۺukTY88?ސgGoo|3.ü p8pn~\t}Q,TЗ_# d}瞋4 >M2ʲ^~-r }^`a <}Q,Tgn_ϞHSN9go[ w֭\YV=˯=У>2qb4zN<g 6?,nUW]̋/tGjժ@x7rdѩgC4(Їw}w~x&O.y̖ 6au5555o\}{xcxݩk++6lpz z͛׿Wz>nzU]]+i? qዾc*.wqį=YѹM#ިw\ST6| h>ݿb5__νzvX&UI󗮉R Q}L~{xcC{;S {%A{ɧ-8;߻U Ǣ䤏|W}@ƅ0۶mbΕ)MƏjkh[߾?+8կbVfT_:-(.=0` {VE\ =yhl~ig~ڑG1*o԰aC=jǎ_ڵlܸ)K#XK@R?Dž1L}uiGè⋏>; ͌ʭꫯz_R?ѻw~-eYYH Oc*>3Іs 6u5_裏oh CAE'Ay f]}goͻ&:EE9Οchwһ $`1}vyM??Xި܆ Ծ$F/'.\5zS?C>xcJQ,+Z*ly..$Kly{Fc"ݡ"}U|;M[FUKATbE^?Ŋ?;; YXyǩܲQ?h8?ސg)V-al6JRH F`ϯ JoGuGuT] =۷o7njɿauhT [vW}瞋`UU%yw 1uAϸ}>{>vr`O0Pt6ޱ쁗_~9EJEGS>~g,WVfDVށIJ1]Ao~/7rdѩ@h|~@/Se~Ѹ/ƅʪ 6lo `ER+X@B5@xFcy뮟omc!;?[*BO{? tϮNj|wqS+7zJ?W]9Wi:C{yTezN6uVֵUY*1l??B%Ӿd)Ǎz+ƅ=mcgm;*? 8?%% `@C l߾=tRMC=c{ژOW_}{s۶mqa`dh?N>q>ѝ-qWGcرqJ?VfdW_ x{w1Н4]хyj!{P]]:鷿]\8_@\ .@O3QC =ӫ[loG[Wo\S&)GvʠA%-҇>ƅÇ{gy}4n_s{[cwq؎`%Q?ۗ--al&l??N%ӯ@wҘ}]$qE0g vXnn6{Ӯ@vJSȼYVq,vwE2^ o`b˴Ñ"+ZC&z}‹oFgܴiǸ<Ycf.69 d)]ԼYVq,v$]*ض2mq]n tsC`Cƣtsglcͮ_f%ؙD\XǍV4咥KO2=k۞7{*"ՖHNT l[l8Rd.79!)`i%ąoy#td.-qK.dS>QyyQ?s?_WWY~s?7}MQy>p ivJS.Tn{jެ~8tFԮû"I;Q7TmeZH]999!"S߄O qwy?.f֮}fId7.ʆ ψ0tCY\:u|ye讅įԁοƸ tŕB4{x-$d^e={|QM)=Vn{p|tЮ{nyMZ}#Մ ш [aDl N,1/=ȑ"t1M[}`h ow}BMM̈́I'}嚯mݺu6o_0Kpذ_[PyEpAݚ5鿊{DŽ3ފ5憞7ƭkfzČ,(m  q{'LxOݾ ~xK/(vYm]T#;%sNɐEurSFoǎ̷Jǵx+/Z Wշlq 'ݭ=܈Z}yA/|5H}"U}#+ؾ{ۙ#;=5oxkV%B{޷ҩ|&*ر㦛=L.*:/oW<#>beK/}kzO'nF3ky챸T O:m=Y0C3ME>Vqh5_CO=ed;%3S3f^{G]䓭U4zc{Q^#71ї 6nB+лFٟ9n4[uyGfmueʶމAW2'\O*=?4o p{dh^I[Srz7~_}g|У.\sAqƸ5͆U uY3h:$ )Q=\//X#4NPqgyxeO{WW^>xfԣYuOWa *^xQuh5+,|RNCl\θ Cݴ[ܚ5O|9ݔ[\ڲx4y}ZΙ9_|1tbҾSN>!kE-= Z FG7h ix߫;߽M-ofO^2~#e'gE˪U{lV+f{Rj"mM߉SL`[=j˽vA޵qC"4|Z)_[Jƨx{#HlW2)M /ڲwq7~'w]wT]C@+>Y駝ˣj=BtVgJ_=׵Mפ ]f,_U8(]抎pNW>qhuGQr_*M :={l7n\SVi[yE* fƋJףKM~=ƊTZ?5^^W kK? ڹ&٫+ݹwS͊pkzԬkJ.ks;]fd ;%޻L>IDAT~7~?"}?y׿}gkA!M [y/لH-*o 8:Kc1YMRfɽYQ[e^YgWnP^UM:HPZ_ksۮH3UwbQvOl'\ oWG Tmi_RQ9|xAdAk~Z?lR%}KY-l2vqwbO)>U?S |#G~Ig\}m^;IՕ7rg-S_[mBkמlPv8[eQ}Ҳv箵e~+ v0kcW?<#BM|㿇n~^cn;n苾ԁ&{ k7<6p+گ. a;/zoCz? ؄;N`n;g.S씞ȝBw>?ozޗ6ƕFys[6!sՕs|Wzդ*̶4'z|Hwd~}spbYe޵5ѻǭ =+olгFY>{i*Km)8;`rEw^37{New?cI1 }ih߄L/,w5 :uoOfG_mJ=]]gD_6~ܪe]IevJSϥ~/ SˁSCSwz&@9d0(4i~}ֿ򬋚dg3n53FvBެ`'3,z]W^ |;Bv߽h-fiyfwgů{i w^ M=z! ,5<{_6ĿQL?-o6x+]vΟVe.S;lѡF{kIKB;Ms5{b+4?̞"xjޔj>c Ûe Ъ 0C~]aJEڢ{oH&n W}[嵓~ڔ/0ZlLdZaگ-3e'~'җ:2!EKq M3vJS$[}4ҧu{U+ { 62_T2ݑH_fuw` =MVM Ȍ׸ $ NoH[9 d@|4:?4o`ۢIooO p`˩kuěo d?W$   'H8A0@ N p`$   'H8A0@ N p`$\N]]] \ p`$   'H8A0@ N p`$   'H8A0@ N p`$   'H8A0@ N p`͖9965E͒!9;M- F&[,d}#%wԆP{e_nܩ˶խ蠂h=?dG ס+/+^7 ayKk_[1I/SWN/QS鋫7vlCr g/ߚEM^?^:9>CM;WfDL+fV: n/qnLH^&K/YV:uXwKuE ڊSKַ.]4ջF9uuuNbN7<ڨWx:i~?ihjس>i#ftE-4M[ع2' nme:JsԴq}mue8}uM/=z:'Msx+;^6yVS6n $RAp􅩃ܻ|^Qސ!J*zeŭF_W107!o9eeM>񥬧޽|vĹ+GK&tIL[YҎcyE#]7T¼n)_<(a%RMexo9So W5n&HtKJ7E+e)f7 6afZ[Orዯ84]zxޒLo2r24dXnMK:`!ySg,)R8|S~!Bn}o:h~ N<ȩE-,N_oZ[V>tu耜] g+CW/bzi n>o_v1Q,[\]ڶԔN/yݦwy{B y.k޴˱dW7ꯕ8uak}*hĖN莇ݴs֦zEnވ$O;AϖWn({6](J|8>=uXRz]ҝOWVU%u \y,9qINe=_,zjW $K{Wͺ07kz6͚@0Y]j OZz{ :JsG omAZ{-K rrrrg7CEl~ѬyeՏ]^֍_iWM_W>=7tM'_ij-V^1 +=+U>tVW8g5;Sij+ZI#6.zuwO =`Xϧ_g3 6m<v{E0mP  'H8A0@ N p`$  TTIDAT 'H8A0@ N p`$   'H8A0@ N p`$  |}S М+N p`$   'H8A0@ N p`$   'H8A0@ N pY{W^v3/҆ Bw}w~x&O.PN]]]#|}SlO3/ o/|uՃl}z>—ٱm۶_wo-mk{ŋF>:tկV^zuT8aG&N؎ 0,.񷍝7o>ӟ|=sG|ރS eS\[[>M{G?* K6Dii#O3bh@ށ/wOݰ> oP5a];q„UWv}x(84T2t%WM_s]+w.s|xdMؽQcG='ŗΎB\w/l"-|):gh7?*:LJn 28dξ-yQC^8t293"m@ m_يmӿ]3w觊 ]o okU9Q=(﫺p’5k:to[|6./1cBಫ>y !󓟈 +~ⵚ:1gukDMz >5t\pܱ` dS|?>*//*l|mUS }_>qK. οƸԯiM=[S ' )L0/~!./eɧ?߭]e[6oK|n6ySpذ_p{Bwuat95/Q|'W<∐whh.țod鏣G}4S?{g>;A0Y"H8A0@ N p`$   'H8A0@ N p`$   SWWH.W$   'H8A0@ N p`$   'H8A0@ N p`$   'H8A0@ N p`$  Q65'6,%Crvk!se^dҺ= [WISm[9%dh-?2y.@O+- qm_ܬݼye8,xNyMkz]YzƪѤ 3͟ZRV%js Q8{q&?nŜ_GSWN߹bg5!yK[Y}WiKuYԆ[\R{$@N]]]c8rmmgUk>Og?|)+S3}_mkS?uQyfM͙4n蔕 K x̕69#B:=V^G.Y'B35>fᡶvk;Oҹ әu+=65vusoO_V4o]^5gm_eiJ*:u5,4zfNoX t0yͼ} {j}/fI} o>SӥMi3°.!֯6e^+ԯzWa?E!o+ 5|ڽg ix\PRSWW>=wrt]+װv]?6K\U>dFN-ul^q-ak1sd, +7oD.@ɒ 8pR\8uu="dW״2vKEٳ:azw] %Apn8|ᆩ%=r]>#mav61xv͒-GV\@m] CeKKNlT[ҏl._R2(XNNN-kol钪-WL3dx8{DaIyMÊW/7^۹ ӻd,)q}[ >ު%ŹU4 ,):]SzʦvaQiKuiQEojgm([ljYKkw}ފ9l+䧋[ʦ|Gm;K%;bN7>R~cU%-W& \yzt!yk6t]0.@i`aP  'H8A0@ N p`$   'H8A0@ N p`$   'H8A0@ N p`$\Ao $> @`$   'H8A0@ N p`$   'H8A0@ N p`$\UW]̋/aÆ'<:h'x@˩kuěo _zsa:}1nj l} sl%IDAT _rNgvжm~߽c :wzu ? 0,.񷍝7o>ӟ|=sG!.7'@&Ȧ lG}宼qzಫKhɧMYjq*i2>ãSW=l\ʆƅ?zw8"?6s'?x5k֬) 7]B9SBx᲋Z0ٜdQph{ʣO8a=2Ơko֩'LXzuhׇ8N*O]I;r%;ǿps]XvU4Y  0j쨸PSSӝWvl"-|)g|p’5kP?=ٛSULw]V[5xy8{f6mTxƔK -G]d^⍿mu`cmaW_ i./ǝ0_]z SΈ++ _etE~_Iξ5*w\]4N1{tg+ cdS*//*l|mUSj+{oOωS'4dl 8Sz7p%7V-999 cdS8a_B\^r˒Oӿ[qF>QG]|U(Ń\zɠӮrNv+?gu)臋C7v"|{~[%Qo9W|iօ `ϲ8K8{GC8a)E^[=l}ze^6Eezj],+;bcԼ8fq)]W߃{Ty$@Apn8 m$G&oY2}M_~sg-^9% HxVYOv?0tҭjgFO7gQt]CflxiF8tѦvŭ++7l.y%v yڽ"7(h`$   'H8A0@ N p`$   'H8A0@ N p`$   'H8A0@  7b}rE0@ N p`$   'H8A0@ N p`$   'H8A0@ .{~rի׮}ŗ^ڰaCx4zNTpa{#GtA#F>zK~IDATxUM?z}=vޡKzu ?˲ 8ZOO9{eYY0BRR\]*~xi-Μy` YλnL^2u᪅{0Ô_b+dl"x::_ʣƎ; Ȉ >sax':@/ɦ+W= ~y7߱WNq?<dl ߿".|9B&9laN dS\UUO?jwӾrW޸qywbpUrƥzS>sHߧJZhU)תa=2A6qݴ!āMr͚5kMZtO)ԥ?OȂGF~xnX?1(uj V^Jo+v>|S, Q |]Q<r%v̿瓗}ם0FjjjnMWw֡#8匢NXf͒vO]j {ց',ՋA۸~Z۾?O~?0\^v tB0|gC'etY6u DžW>tҁeJxpꇤw+-'|)vΈYVև@Ȧ!ƌo xZTӯ7y܃Nˮw !pINCtv܊ x1SWW7_]tkeeS°-yf~Zk7=ɡzoEwhl┏|T^^Tƫ\V~9#?Oh8p7~Mo KnZ][rrr@Ȧ 82g. ?) hmtYr6=E" R%@KHSi.&e¸JRf4/Y UF02CP,){:G魃@+D6)+K*F*c9޽M4I6si=y~gd4_'W煶l.墲0d̻lӦ̓~9%\\[~%lܙNO|/F895F}t?~'|_N 5FS8wNNc?#?/}]8g-ۚ?&03d!8mkI~3ḛ3{vU*?vi&6!Nf&!NfcF0 9! rB0@` "'DN 9! rB0@` "'DN\N* ˌ` "'DN 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@` "7i$'w6T&r'嵍m݇?*}xB`Xj=eqCg8q&ҳcm3;Jg.r];wnYwn)i, LDÝQWWT>cO*m/o~!TU$Qғ~uaB+kJ?˫‰7kÜܙLn[T";/,nhn8ͩTs=?yyC\sCjJrZ`[ݡ*.no+߷Pq~!3S7+"p^mSn}܃dq}7OVxu>Gq*Q<0~}ӑܷ>suG Y %vl[2F[\t!MV߲so];Y`i#\o_wSwªdw kn-ݭ5}m۞O_`ٶ}Gg}Yi3,Y3ؒ0,@aIT%SDowE=/lVۓmecOޘ9{=:t5;kc;{Nѭ o}ivl{'6޼jn޻,nZZqqpw,r3j /wm]w˅bǃwg&Nw;{wZ= Cp$V:@Gݨ_WUU]k]M++Ӗ_憧BfΦ+UNص03e[/m\ZP[;z%@ɪn^\]_Wt{;r]Gv򆶭J-Ľ[Z..k%?[WGÌųYflgPq]kWmoX)sWT763u_any]u'3Ye}7XCy56h.mδ\hgkMe 0,5Bp(^Qߗ':'Qݸoe̲dGwOVOwWGksCmyi~NNN:F'/GoklnqGK~M^U}/.5-3ܑ0,ĔJx5;|u(ssG]ig->ڜHV3 aʍv7ڞO?+vV'ܙmK\r= 7'Cuͻ/Zy\'F,]ezaFpZinÅ+PkZv\]~Y}۞׭,)6?ygQ8V#aYgdSQ"'DN 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@`1~cW ۜ>yJ8"'DN 9! rB0@` "'DN 9! rB0@` "!x3ܲ7| _k693f|遒h=aㆍӃ9g_:g jCߙ#=:{+~MkJΞqvaqa;otO_ھm{kKlЧa IDAT7bat//_Vwh plt7 V٥ԟqasO,\۸[޻goz'>\p@6ʷV?.̌nTfу=3ߝݻ/'@Ȧ[o}{f<󂙷5G{mMeƿxo> )KWӃܼ;9i~K\ruWd} dSw .ҳgNk`;v /Bp{{{fs_[]"eu[Vwc(833_ 浆6mۼ-3H$ MKC~O ׏V%WZs=;F}׿|egf< M3^MoFrk:>g48C`A@Ȧ|?<8=MT*_}o~-7A6SN9e_Ɍ7=ڻq}۲e|ټ Bpڜٳog2{8ssݬvvWz3??}@Ȧey}vӦ[_]KK甖\RRrqI;]zOo~_NY"c/aZw_'~f3jӟ0wRW^ZQu'*M \(jhi?8GOJ[:w7';z±> pIRCVW~ЅKM֗g6ҭ;єuýy(ɶyY&\z՚g\j.}pc{};j sP%i^ O:5_gJA;#.~?gZ0(3;eB픹Kmӻ׷ރ?\yѼ3\¥O\SBصfAuYj+𔹫N䪹Szmyh:+ ^^Ut-XdfiIzǖ%u?JWӼZt?ˎ.,88=@wV}I}oGֻkʪݣd3d+_%7ޝy m[WtX`%Kd.(뫬$yer;[kNN̫mm<},n0eݽޔu-y_o _v4U,ҚuS=n\zg sy=5iK7w>Tյ1*54l{aCCEANJkM V~ȕ.yÅ6U|}_Sܽ͝}V~EokҸo -˛a0]m}O5j({sc!s҃o8o뾆= !Bpg[kߺEUN̫3FQ~C2Sö0'3v+*z0o^pT+jp.;wyut;54ߞ>D"Laeř v% ʊ ÈfF {ّ4 &Qy [Wa/X;m֡~ C\^sc_}:}бdMM*SnU-μpw u} ?Ց[vc(Δ+,> BpWR[kwYP\ڕӑW`ͮxJes}Y澛ݽ=XW50/''3RqiZT[xׂ5=Vtt,] WMqUIh˒ewwu67ԖDu8< T*5 ];l:-e][Cy~f.qN+ssG]iWKUUkvo؝)]p#{r˳ e$xG*qo͌;˦a(WwT.~lfZPh{sEeYΖ⦃ns}X^v qvV_2j0t&DUKמVU/ͽ~պt V/oܳѥK ;hn-~rtVXsܷd6?ygQ8f?enѾrպWcW\ڵ{[P\uw0@;`۩ "'DN 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@`1~cW ۜ>yJ8"'DN 9! rB0@` "'DN 9! rB0@` "!x3ܲ7| _k693f|遒h=aㆍӃ9g_:g jCߙ#=:{+~MkJΞqvaqa;otO_ھm{kKl7bat//_Vwh plt7 V٥ԟqasO,\۸[޻goz'>\p@6ʷV?.̌nTfу=3ߝ ZIDATݻ/'@Ȧ[o}{f<󂙷5G{mMeƿxo> )KWӃܼ;9i~K\ruWd} dSw .ҳgNk`;v /Bp{{{fs_[]+gVx3 fU=PE956}g;#x`˦s་;ڹS KC(-߮gfZ=|%(CwҤI% <ϯwj7og(Ι={ƍaH^xn8²imk n^kܢpt3/ϥ7RQ'q 'ܴw\6.n~C88Un^nцੵk׎0a]֛o1!>t=:3_:=xqˋ+y_}'y2{V}/oɥ!/ܲ#C3<33x0BSkS`dw~-ض2D Lxٴ4g? |}EZ0{;.'u02w33u`˦ hfC7ax>王È|,(0#/gݿ^^YdCeu>:Lk?lCm;񎇿П^6/֜ٳ3@z0ңsW~cWؾ~K_~W=0>yJ8Pݻw7y$3τʏ}{`P9 *^"'DN 9! rB0@` "'DN 9! rB0@`R@ 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@` "'DN Ia|$r2IV'rrpR e?\VQf:n, ,^W\ڵ{[To܂/w{i5m?{oe5G7lW^ٱcG8.N.)9o%,oW ,'J7v蓟K/3?v)8Y}sFzt|/|x?&Mt7Ͽmo 5 'og~fwpٳgG7e6'Oo-*-:{مŅ|Cw=FηO;0* p2˲~ګ+K&3K?3 J|ȚFNɤU \us?8-D*ol~<DM3zz^髯ϼ`=8i҄/ny1=>p˦r)aI6^\ywsTmMq/0adSw .ҳg&3Ͼbvf<A6wVϚU7sf-jxfyNfpܢߓz:W/ʹpS?z/nށ*,-yJNV4#xfqqzфIDATˏ?uWe*pg`Ȧ|)+7U{WrW7g_=999`Ȧ6g≯?pB#%\TV&lZ#xМymڴypҏ^Z:䒒KqѾ} ; %hY#'|Yݨǿڏ?3OO8_~Ch 8nig7_{/w ':㌺[sfF0̲8޽y#y&wsfϮXǮ>&,C0$l`B"'DN 9! rB0@` "'DN 9! rB0@` IRx 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@` "'DN 9! rFrrWkCUi"/g@~"QZ^du"''Q< rRh(dlOcY8N9 L\j.pgwԕU)ؓǩ=[PPUQ sdr{ߢQ^~aiuCkuC`"p~jw{S]Zy򺖎mK*zڛjg,n d,9HYcg߉-U7'Q6j 1:6Kضd!++:ܛٳw+yZ(5Y8o\5tFo3;YUѴܿ.,Hd~wZW޵sgi?uOG+s[ԷMT'{?r] m5}'sjiӊVx]YCWj:lT{oGo;=@Gz[tΦ5-*ǻT$~۴׽TQ+PpKͼ0r+:rضy\oʆL8jn|ou/on]r|᪭T,F^y_GN[_+2חcc7v!=Tߊy;cFoO8nׇxwI}.lh08Y]..,#qm}Kʊq3>55+ZkX_ qIcBpaU텽j8$w4Tg"ڪpLsGp~C\6Nc4DiUI`˒-}@t7U\wdUc-WҼy;`})76 TrRvT^f瑯Ewn+ݷVW~Ԃ{\{}˶#+|0Ѷlx>4:a-s-(ͯw%Ǥg,)w\'I.trc ldU5{5}8L[ڠ'g4W_OV<%rWߕj '8ɝ/8 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@`1~cW O"'DN 9! rB0@` "'DN 9! rB0@` "!x7g6G<0rB00N&Vછp i$PySef?&l[oJ_}x3|I&Dx}qˋ[6SN #dF00NiFL˽s͝oo{ۿ #Bwxfp镗=0L9}3)h羶x֬կ3kQCf3sz7ӟ6gG?b6<'DM!xΝywsPZ8u`_ws^~O;Ӄ=45Sw²ip]|s*Lq3~3{Ðνp4]w}ǢɵtۦaZ\4f^033:пHc>ᦕgjڿu0m_S8[7rrmN7ߵ\}ךi*uS~ Kc9am׿N^JFwo]:N=¤V_kkGCܑ-п"Q˦ŝy晙/{jpit}(_3mo"Q&l _<?ևx6B{}64 ,ևػfEKcmtk!8id_qէuaÊyऑ}!t^yߖ̮Ҽy;`})76 TrRvT^f瑯Ewn+??#YX6?<5sZ}Pjw O0@Բqšן``onAA=eޞYSnW͐3Г_fo089bױiKT`$?;ɪp5.3_DUKW8Ŀ4I$xY͌` "'DN 9! rB0@` "'DN 9! rB0@` "w]ls)@fDN 9! rB0@` "'DN 9! rB0@`7! rB0@` _ݰqO~/_yeǎaL_Rr_}3}󹹹a;}pY|nYHӛo/{3@Iyaްqƍٳ/3{DGC5! ={?͵EEg807x/m߶uw6 ^U0Jї—/;4}t8`PYFp:[+pG80҉9}g'm\{wݳ7y{. L Y[^LfU7WݿqYT|N KdS~뭷=3y[Ws=綦2_7V%׿An^k4x?% .+2 )经g^y3'µ}mfys;M!=3xE?ڹ.5xkjX4+gVHGP6,3 ^l186o 0e_ӟ,dBa^ktv5.#}+;3Y\&l 7VzC_3gk C`A@Ȧ!.gݿ^^xݥtNi%%%ˮ^xpxՁ,2!xQwg6ӡ6 xzO/Fkٙ_ =Q9+v+Ll_{/w E+WsNN<%(Cpݻky?LxB0pD}/`D` "'DN 9! rB0@` "'DN 9! rB0@rRT ^fDN 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@` "'DN I:,''#e;[dg si@vF0@^66}ɶmK(Q/V_kڵ+tÇ/C]WZH L&Oza=w[iں5}~K_ycu~`NuzŒ^7|K_/8՗!  ]rUW1%%cǔtjG?9lՎؿW6OS  goޭغcKWz~U''&.Iu٭)|挪SxW;BNa{-VJxR9k&.Yds?:;>QL'd=.=W]G{gҴI{ O?2D&C˿> F;p]4ޟuO>2A&u/!_s9_뮾#VaYz{!Ça秤]v^/BpCCCzKNwEѣv}5zRMĚY-̺#ؾh7óN@I!xa#Ow༢9ܸ~ GOw٥mRn>} .<}~zsByspuLIɪիCF\1"N^аSq̺%[xC6c?ÿW0`R]T^KfϩN@| -;%}0t޿M;'F$ie#jKN<}CSoC'ɍKBzP=Oqҫ6oSÖ[..8tEswl IꖜlQma~ͼO}|4=n;jvrOM^:۳>tY dLZ<#)H$RC3g&pf'Dz@&Ȥܷoys7PC ܰyFt}f7LI!8eLI]Lz_{ =yo=Üo I{UϙdÆԼmӶ[/u)*}~WW֯vo>bw` t9W;e/<喗_A0jS=ԓ{UcJJ٫]u\۷wOݾ+_Έ7̺Ћ@8V}.~&5gt-S~KB''q`Dcqt 9! rB0@` "'DN 9! rB0@` "'DN\V2 ˊ` "'DN 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@` "'􌺊YdE0@`e%@NGpSmY#uKJr$ʪV43Y;&]yz憅[s|8'@N"8jn~`;-2qgJ/c*_-햧|vA>nj"pSέXz m^~ۉAp+L8%X^7- ?M/2|H^"/׶4ly'6M/{{{n na!8mo,yy]] gIkM_ņ ?O?:OzHQZt[U w(<}²e?7ɤ#^\0u+B[o5)[6nIÆmJ߾}C'Y LZt=g^RC=o-m?@I!72|HM +$=}O BpCdKNwEѣvw&̺f3פotQ]S hVG'@oI!xa#Ow༢ufrߛ74 -JgO~#7%Z󾷾qrg󊇆y'G^5M5 =:uuLIɪիCF\1"NK]:&Ո?63(.uK|\Nw) CSS;kY"uޫf*;„W1O._v}zpE5rɒܿ*UC(I2p C`O<ٶIo淿M [6nЍf޽ek%O(tàA:".ˤ!.aKFMjtϏX:os;(/(=t)\=:k wY-̺faB,;ufKyt<@L&Oza=K:AX^WnH 9sj_;0o4qc{羻ázr^xʤ>D"54<|[oUXCIDAT_m52)wܯ +7*7huo_q:XŹe5v+8A!iiEÎ)Yc?Q[wL9{~ܲڦЍW;鋏K~e^E p溊NMCo{^»8(tڛm1umۼcP\[@ܝa4ų77dCp*5޶1~(@  o_8(u~EӖ6./Z2mٴ STj=eWYv677dO:q{{t_+l6N/HL]ܺ āS ol9(sWT4}چ47T$6L&OyiiE'>CƪV^I3k^tZ1'Mͻ0نڲ@n\"z]3.Sك ?4_S.ܾGwۼ回.tvW DM 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@` "'D!x=X@ޭ 9! rB0@` "'DN 9! rB0@` "'DN KիWkv g?0dHaȒ??zd2y ۺOO֭ᬺh.4bw̩N_Q٫o~gX>}=z&Y?'=͝׿ʆaSiJ~QCy޸_a˓=yo.|;sCMw o{c҇E%ETp`8K^k/6nH^я.~yB0CԢ*pz,V䦾C]-[ I&>tY믧Q{O^z)MٲqKj6,oW:Ɋ`dҊu/+pv9 Z,xkm۶zL Ͽ,=aCBo2`X%{&%W^r{w.JX3YǼf֭vnQWrMEpmߪ ca#Ow༢ufrɩ\3󓳯JN~oD↹5NntauݶdrO #NOjk`n}N]SRjЮWRo׆\TRȿw|Qw$;Q顩ߵwLuݛcnUW,&L|=EyO~6\ O5Usw +=zWԃ[C'lW7lߦ-\\xq>+??aՌ_\עoc}cz4hC'_e" .H[nvÎs_ >u\8 F&K/-J] ;%F}!twVRH7gz뭪8? F&}Λa冇* Z F&1%%w}3v~s/2=}53\Y\zL#͘lPv8c^]XxUa8#V7lW=d*R]*{=fΨzq 7O>\W80, Nݿ"?|w}8U;?z1+,Cpʾ}j?zx͚pƍ))(=л n!ݬW"'DN 9! rB0@` "'DN 9! rB0@` J&xY 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@` "'DN 9! r}:ssӊ~YGV.X|u難 E_XST0}1޽+XP:"(vd?lqBTQV襲RMm)ljJ2F>~ׯjKw&MK+rO-biSŵU'^WVt Jި8'@mvͭ'6OvlMT73,/.7>xԞO҅uxEpV%X^~ʻjZv~zb8|dKm9(N]Knِ@G/|IDAT-goz-vx{qE]s866/Dmc4VuUTq. M g=Һw}*oEqv? %ZI-lX^>`⊪cuNJTU_:r֊ 5wܬ#vsC K9 瑚1j9l]{#zpGː}笩GnlXné9׸=pC(U}EY5-?;8*7j|;!8NN2܎g6i]&Κw]EǥmJ2/pC_YqṪG~%ȯĥNMV4:U=uر#qN]0u8@с5E9YYYSL&OyiiE'>Cƪwז^mrӻ*rO8Pwi7BpOSخSsmzÊY7WT*>MV4÷v6{РAvwW`29 "'DN 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@`ȝ2ۻ'i? ˊ` "'DN 9! rB0@` "'DN 9! rB0@` ϮZ?ׯk׮}W>]w]iA"2PV2<}{m~vǧj~/}1;;;b!9 3:{|/}oVX82tUW^ƔSҩ!'礇?W;b~W^ِ>?M/2|H^"/t{b;V,]Um($g3NL_!8Qַv{[.*)~zCH%Sd=`_F]2AQZ\qwţ |I&=/8?54:kt5#&eT1<>zwޝF^9t+ (oprRÄg{C(qr:sSxuz{ߟӅcJJV^5t򊇆G~.\3ú&\u'F_+Uu{*S%T^eҊZw5mo9XJĈD8~ skp%ǝ*؄Ғ;'xhq:o@ ܸ<2G?ēm;Bj o~԰e㖋 /v a;„Cla~ͼO}|4wUCneRҢ&<6tRYiϟv;=5*z'eo4K&煮o]~AV B| H o4,L&Ù Bp߾}ZzްrC3hs3&2A&1%%w}3v~s/2usrǷ29!TϙdÆԼmӶ[/u)*}~WW֯vo>bw` t9W;e/<喗_A0jS=ԓ{UcJJ٫]u\۷wOݾ+_Έ7̺Ћ@8V}.~&5gt-S~KB''q`Dcqt 9! rB0@` "'DN 9! rB0@` "'DN\V2 ˊ` "'DN 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@` "'DN >9Yi9Sh:p=krT,\`~~ES66wr+6t*+L{Cڪ+.]qOꪋs|僻yЀkKs:֌ #YX3>jojM﹢Or|M;o~+MMžM=f <`ܼ#7qZm׼tUy!٦ڲc6Lߘmk;|"-CM NBڲµO"d۵bjn[5^QSSv ʺ[o^p'˫)o?ኇV m~T]=]q=dkrsǗ巼[=tkY'4V8ՙ9'tّeW;+EW=Ym^[u(NN+.NOnS- \:Xܴu]k6ŖaӺjNNtM{!8^ZRk,.QZ)0@c]IkCW׶>e ?=hPb|^@V2lڲ}K,_[S>X[{ܖ?iiE'>|\7Gv_IsMS34+[V,mڿiA7 6omrJl߿-4 W~ϼi vE0@Ԅ` "'DN 9! rB0@` "'DN 9! rB0@` "'DN 9! r dDz" rB0@` "'DN 9! rB0@` "'DN 9! rB0@2>/V_kڵ+tÇ/C]WZH L&Oza=w[iں5}~K_„n`IDATycu~`NuzŒ^7|K_/8՗!  ]rUW1%%cǔtjG?9lՎؿW6OS  goޭغcKWz~U''&.Iu٭)|挪SxW;BNa{-VJxR9k&.Yds?:;>QL'd=.=W]G{gҴI{ O?2D&C˿> F;p]4ޟuO>2A&u/!_s9_뮾#VaYz{!Ça秤]v^/BpCCCzKNwEѣvw&̺>}Ѥѓjv#g7^/Bݻ+GyE! >7oh'[٥G}"//?ۧO« |^c.\SRjЮWW<4 7"?*Xp=WsSz0uCB 8M@6\Sh;C89z0'lW7lߦ-\\xq8K0fާ>y{g>8#U_Qu(~, .H[gs;(z/(=t)\=:k wY-̺YݯNϣG ^&RH7gL&ZuO||wLI!o߾~-=oXʇa|qeo Bpʘ>\;ƿz؁[Gߺw{R99[ "N3?Ɇ yۦm^~؏-STxuaU4յ֯_|@eou?xE;p )]L5kB/[ȑ^ON!2! rB0@` "'DN 9! rB0@` "'DN d2"'DN 9! rB0@` "'DN 9! rB0@` "'DN 9! rB0@` dK9IDATHinIENDB`././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/rosettacode.py0000644000000000000000000001735715134002420015171 0ustar00# # rosettacode.py # # parser for language used by rosettacode.org (http://rosettacode.org/wiki/Compiler/syntax_analyzer) # # Copyright Paul McGuire, 2019 # BNF = """ stmt_list = {stmt} ; stmt = ';' | Identifier '=' expr ';' | 'while' paren_expr stmt | 'if' paren_expr stmt ['else' stmt] | 'print' '(' prt_list ')' ';' | 'putc' paren_expr ';' | '{' stmt_list '}' ; paren_expr = '(' expr ')' ; prt_list = string | expr {',' String | expr} ; expr = and_expr {'||' and_expr} ; and_expr = equality_expr {'&&' equality_expr} ; equality_expr = relational_expr [('==' | '!=') relational_expr] ; relational_expr = addition_expr [('<' | '<=' | '>' | '>=') addition_expr] ; addition_expr = multiplication_expr {('+' | '-') multiplication_expr} ; multiplication_expr = primary {('*' | '/' | '%') primary } ; primary = Identifier | Integer | '(' expr ')' | ('+' | '-' | '!') primary ; """ import pyparsing as pp pp.ParserElement.enable_packrat() LBRACE, RBRACE, LPAR, RPAR, SEMI = pp.Suppress.using_each("{}();") EQ = pp.Literal("=") WHILE, IF, PRINT, PUTC, ELSE = pp.Keyword.using_each( "while if print putc else".split() ) any_keyword = pp.MatchFirst((WHILE, IF, PRINT, PUTC, ELSE)) identifier = pp.Combine(~any_keyword + pp.pyparsing_common.identifier.set_name("ident_name")).set_name("identifier") integer = pp.pyparsing_common.integer string = pp.QuotedString('"', convert_whitespace_escapes=False).set_name("quoted string") char = pp.Regex(r"'\\?.'") # fmt: off expr = pp.infix_notation( (identifier | integer | char).set_name("arith_operand"), [ (pp.one_of("+ - !"), 1, pp.OpAssoc.RIGHT,), (pp.one_of("* / %"), 2, pp.OpAssoc.LEFT, ), (pp.one_of("+ -"), 2, pp.OpAssoc.LEFT, ), (pp.one_of("< <= > >="), 2, pp.OpAssoc.LEFT, ), (pp.one_of("== !="), 2, pp.OpAssoc.LEFT, ), (pp.one_of("&&"), 2, pp.OpAssoc.LEFT, ), (pp.one_of("||"), 2, pp.OpAssoc.LEFT, ), ], ) # fmt: on prt_list = pp.Group(pp.DelimitedList(string | expr)) paren_expr = pp.Group(LPAR + expr + RPAR) stmt = pp.Forward() assignment_stmt = pp.Group(identifier + EQ + expr + SEMI) while_stmt = pp.Group(WHILE - paren_expr + stmt) if_stmt = pp.Group(IF - paren_expr + stmt + pp.Optional(ELSE + stmt)) print_stmt = pp.Group(PRINT - pp.Group(LPAR + prt_list + RPAR) + SEMI) putc_stmt = pp.Group(PUTC - paren_expr + SEMI) stmt_list = pp.Group(LBRACE + stmt[...] + RBRACE) empty_statement = pp.Group(SEMI) stmt <<= ( empty_statement | assignment_stmt | while_stmt | if_stmt | print_stmt | putc_stmt | stmt_list ).set_name("statement") program = stmt[...] program.ignore(pp.cpp_style_comment) pp.autoname_elements() tests = [ r""" count = 1; while (count < 10) { print("count is: ", count, "\n"); count = count + 1; } """, r""" /* Simple prime number generator */ count = 1; n = 1; limit = 100; while (n < limit) { k=3; p=1; n=n+2; while ((k*k<=n) && (p)) { p=n/k*k!=n; k=k+2; } if (p) { print(n, " is prime\n"); count = count + 1; } } print("Total primes found: ", count, "\n"); """, r""" /* Hello world */ print("Hello, World!\n"); """, r""" /* Show Ident and Integers */ phoenix_number = 142857; print(phoenix_number, "\n"); """, r""" /*** test printing, embedded \n and comments with lots of '*' ***/ print(42); print("\nHello World\nGood Bye\nok\n"); print("Print a slash n - \\n.\n"); """, r""" /* 100 Doors */ i = 1; while (i * i <= 100) { print("door ", i * i, " is open\n"); i = i + 1; } """, r""" a = (-1 * ((-1 * (5 * 15)) / 10)); print(a, "\n"); b = -a; print(b, "\n"); print(-b, "\n"); print(-(1), "\n"); """, r""" print(---------------------------------+++5, "\n"); print(((((((((3 + 2) * ((((((2))))))))))))), "\n"); if (1) { if (1) { if (1) { if (1) { if (1) { print(15, "\n"); } } } } } """, r""" /* Compute the gcd of 1071, 1029: 21 */ a = 1071; b = 1029; while (b != 0) { new_a = b; b = a % b; a = new_a; } print(a); """, r""" /* 12 factorial is 479001600 */ n = 12; result = 1; i = 1; while (i <= n) { result = result * i; i = i + 1; } print(result); """, r""" /* fibonacci of 44 is 701408733 */ n = 44; i = 1; a = 0; b = 1; while (i < n) { w = a + b; a = b; b = w; i = i + 1; } print(w, "\n"); """, r""" /* FizzBuzz */ i = 1; while (i <= 100) { if (!(i % 15)) print("FizzBuzz"); else if (!(i % 3)) print("Fizz"); else if (!(i % 5)) print("Buzz"); else print(i); print("\n"); i = i + 1; } """, r""" /* 99 bottles */ bottles = 99; while (bottles > 0) { print(bottles, " bottles of beer on the wall\n"); print(bottles, " bottles of beer\n"); print("Take one down, pass it around\n"); bottles = bottles - 1; print(bottles, " bottles of beer on the wall\n\n"); } """, r""" { /* This is an integer ascii Mandelbrot generator */ left_edge = -420; right_edge = 300; top_edge = 300; bottom_edge = -300; x_step = 7; y_step = 15; max_iter = 200; y0 = top_edge; while (y0 > bottom_edge) { x0 = left_edge; while (x0 < right_edge) { y = 0; x = 0; the_char = ' '; i = 0; while (i < max_iter) { x_x = (x * x) / 200; y_y = (y * y) / 200; if (x_x + y_y > 800 ) { the_char = '0' + i; if (i > 9) { the_char = '@'; } i = max_iter; } y = x * y / 100 + y0; x = x_x - y_y + x0; i = i + 1; } putc(the_char); x0 = x0 + x_step; } putc('\n'); y0 = y0 - y_step; } } """, ] def main(): import contextlib import sys sys.setrecursionlimit(2000) with contextlib.suppress(Exception): program.create_diagram("rosettacode_diagram.html") success, report = program.run_tests(tests) assert success if __name__ == '__main__': main()././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/rosettacode_diagram.html0000644000000000000000000026473115134002420017171 0ustar00

program

stmtstmt

stmt

statementstatement

statement

empty_statementempty_statement assignment_stmtassignment_stmt while_stmtwhile_stmt if_stmtif_stmt print_stmtprint_stmt putc_stmtputc_stmt stmt_liststmt_list

empty_statement

SEMISEMI

assignment_stmt

identifieridentifier EQEQ arith_operand_expressionarith_operand_expression SEMISEMI

identifier

'while' 'if' 'print' 'putc' 'else' [NOT] ident_nameident_name [combine]

ident_name

W:(A-Z_a-zªµºÀ-Ö..., 0-9A-Z_a-zªµ·...)

EQ

'='

arith_operand_expression

|| operations|| operations

|| operations

&& operations&& operations |||| && operations&& operations && operations&& operations

&& operations

== | != operations== | != operations &&&& == | != operations== | != operations == | != operations== | != operations

== | != operations

<= | < | >= | > operations<= | < | >= | > operations == | !=== | != <= | < | >= | > operations<= | < | >= | > operations <= | < | >= | > operations<= | < | >= | > operations

<= | < | >= | > operations

+ | - operations+ | - operations <= | < | >= | ><= | < | >= | > + | - operations+ | - operations + | - operations+ | - operations

+ | - operations

* | / | % operations* | / | % operations + | -+ | - * | / | % operations* | / | % operations * | / | % operations* | / | % operations

* | / | % operations

+ | - | ! operations+ | - | ! operations * | / | %* | / | % + | - | ! operations+ | - | ! operations + | - | ! operations+ | - | ! operations

+ | - | ! operations

+ | - | !+ | - | ! + | - | ! operations+ | - | ! operations identifieridentifier integerinteger charchar nested_arith_operandnested_arith_operand

+ | - | !

[+\-!]

integer

W:(0-9)

char

'\\?.'

nested_arith_operand

'(' [suppress] arith_operand_expressionarith_operand_expression ')' [suppress]

* | / | %

[*/%]

+ | -

[+\-]

<= | < | >= | >

<=|<|>=|>

== | !=

==|!=

&&

\&\&

||

\|\|

while_stmt

WHILEWHILE paren_exprparen_expr stmtstmt

WHILE

'while'

paren_expr

LPARLPAR arith_operand_expressionarith_operand_expression RPARRPAR

if_stmt

IFIF paren_exprparen_expr stmtstmt ELSEELSE stmtstmt

IF

'if'

ELSE

'else'

print_stmt

PRINTPRINT LPARLPAR prt_listprt_list RPARRPAR SEMISEMI

PRINT

'print'

LPAR

'(' [suppress]

prt_list

quoted stringquoted string arith_operand_expressionarith_operand_expression ',' [suppress] quoted stringquoted string arith_operand_expressionarith_operand_expression

quoted string

string enclosed in '"'

RPAR

')' [suppress]

putc_stmt

PUTCPUTC paren_exprparen_expr SEMISEMI

PUTC

'putc'

SEMI

';' [suppress]

stmt_list

LBRACELBRACE stmtstmt RBRACERBRACE

LBRACE

'{' [suppress]

RBRACE

'}' [suppress]
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/rosettacode_diagram.png0000644000000000000000000072532115134002420017006 0ustar00PNG  IHDR<5IDATx|ua/'P?lt0 ۤ4`kpn:h7 ޱ$lpnZm;0F -I#HBP9ro<+9sL`@D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$DIn,RPYT 6=5 xUMS{Z7N>[UKpjYajXiUC{:RWUV\۵X{bE:+\VUWcec ZíMu­Lof[bťűjZ²0͹iP3ϼѦ0s_iyyA[ۑXesI< %T ɺʢnC  w (M6$eIAIU}k ps]Eq-cz7WUw ]Tpk}UI+?lF9իbo[-`xlݲ%[xc}]YUeWm,.κgcҭK ~ߙfݰ{UgYaѬL{Éo_4{bwҴ+k)=3ݟtk@XV mxâYyRfZtƗ[wbj[ݾn^n{Pnquˉ2-o5!`t0=ܒ{Ŵjlm|YJfsW ;6Џa=)N5=3??e{>T]l0z->67UR9[}nNRAeSp"n.twʜ;y˷זik  1HkE7l}wY`$1  D @$D @$D @$D @$D @$D @$D @$D @$D @$D€Wp|N=}F 0  0  0  0  0  0  0  0  0ȑ#|;yv/[?LR[?~:k S Op7x#`(9ab#^`:wz&ٛ;} }7sʔI{Wc~q{<|=u.7m>Ss3̐e8\?\zd綾\7mbA'?3+/l}_ 2 d,oܗN-/xL:m_w]0l*~7~Ÿa9=餬y曗.\φ瞛]'|rI#wqco(5_ې|Ϸ# 2Jv\~ْs`֬Nv}eSMMMɎ/8ޚd^i/v4vʦ֖N~hky>Ɏbcqї~˰OSX)'tқo_7x[2xdo:]ٸߪ{.]#//?Puwv 2ܜɎй:E~G48$@#kڽgO# xGcOH}'9sRum-+?򑀞>ټ. oOIu}肂_Sen(o5d999=|tg{O|~M~ &~ܻ>ٻz 'HUEs8γ >ǟMvCuuߞyfb^ ;sӑ#Gv=LCSa{]]zx}okh 3޳_-O tm0L ;/H03>^< 7h%@Ps ڕslM-^q琵\tQ ;θ(ipfGWvHZ|v=͝q>w.+\hjehʜ-o}s=~+_I>)tym)qVh tGG-&~/]?xƒŋ5rnx@?kKJJ|?'OO/3 p<&U7K7?ł9Vpܜ3n*⩭ՉQ+k}`]ym ZνoKbC9:묺]uzh7Ohc+\7 ӟsNC}¤[g|K.zgs̮O>9Sz dSd>}?n=fp+j!oG =P˖oLf,p; MMMɎ/8\wnQc60R9mmmɎ &S2 7Uz8+Ɏdt[SYw~/r0N`c r/~v4<^cӭg-޽҅ ;}A 49&=x;{ LvٓFef @lIDAT0*'C x闿T٧9曟TY{{~Y^L|'ҝO<57A6 ϯO&{+_ C ,6E.x ;իn(`&c=/{/[佗q{̙:uj9g õ{h۔)b c믿~'^a;v5\?֜zA1@'Yqd_?㌿_%K/@F8tI'go^ziUrrr¢/g˯VWcbV&s dkW FA `"A `"A `"A `"A `"A `"A `"A `"!#N 0  0  0  0  0  0  0  0  0  0  0  0  0  'cp]Y,''VV]:x͛ڂmSMC0wLRRp0wLN UfUqAlzNRnAqYUmc[kJ,ْ߲$peA -\VUNnrDm\:g%nئՏmw7%q޲zu׈V_R<ߴ*?5D e;{_>w@8^`d4燓nn(qu7Ob޼6# -!@Oύ 83 KJKKkZ;j㗛՝%u}G=W/s)9f$ ; t7Y<;oZ1m\AQUKo8A-,kj=qo~ũFRkR]"ΐ;=7/,)kN5|\ӂ3K`<7?vWiIE]s{ ۛ**j^S KVt$|jY0O״a|$1غe9K <:oܾ#’sj.ܕwu_ҭEٿɆXٹY76Wo6/Ӓ4 ^\P<3f/^~o('^pִpk~tqt/&)D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D€W0FN=}FpB) `"A `"A `"A `"A `"A `"A `"A `"A `"!io /T7UtH7W&;-|,'ʿ>;Ž o c8hX;{Q m|ᦊwYAh"A `"A `" RvXStqe WD"5#4YЉ}uI"z0ޚ  5 K7>< [c+xDL s<կ^yA+}+H;vpì\=gkCt*cjmg%QxC`s ^y ^+7= {M*ș{mApD@v6ܸ륰4omͲ4,"~:* WX058V{}z0f͹bC0Z89k]ꎗywiαx ao>gWWX=wZs)~gٿ󢫺קQWO 8Zrڍy\t#;e @nݶ"y4s vXX,E7'WlT^m+1KVz+0RzH_ _i57gnZ`AЄ# r::: s[s! 1?4SOP@ _{=QQ @$D @$D @$D @$D @$D @$D @$D @$D @$ttt0) `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"`+ڃq0K$R 0~ hT]z&ΖLq}8OL- UfUqAlzNRnAqYUmJ)[kJ,ْ߲$ >TW],\vz񥯪i{ȗZ®U.kNtkX J& ' 979"VZtᩗ\:*jYrZZQ:6[ r:::`I^~il,L- w?P+YiImXUmW?-XnX<^-oZ?'̿#.yoSM0!Jo.Km򡎸C7.ۗ&nWj+,^;m5O.ЁG̎{juyMq,T@|_޻u)ZVJ7v-2qul;cr *Zz:pwYjө{P#TQ]ol`+ dZA&ݽh֬sf,q2xn.?wUgȝW57XIDATJ>ӂ!UݑH=\SZym 6p+)KXV5K»~`xOUZRQyO溊S$mUMM‡[jo-N<(?63W*m{].^}AѪnom\07Fs.<0<9[do KosKϽZ@}Y,h++<^d͓E#]zo_[T}%n-dou{csE\ͥW?pK4m.5U̹i_ ^\P<3f/^~o('^pִpk~tTj-iy~Z|Go f8KM/(o=րW8mr/}[0:Yan)C&)D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$ _`hzLHHHHHHHHHwس/x.Κ=}G|ԩ%r:::^ymyx `B,\ ,}Iֻ޵9gd,t57?,p_Gno@˾C-]Iθsw{??`2jo??zζ%|ɛ6~+رc?ϸ={W?ϛжor)!Y!L.YLe8\?\zu3K.ߛ6bկU|/AiӦ=R~\d]徯d*lbf,3d1$8dYtly#o~fg>أ{ǯz}ȑOXo0:m_w]ZuY'Jx߹?i=gN>O:)+a˿v{ngv|!Y!L.Y B pɦd>}?n(Fه?_}uTxچc*_y$ 9dõ48d% H6em>%D۟~M͐ f*YdwbB&s&kiq2Kd)AhjjJv\|}Ǟ܀l*⦊O;ۧrJ9g/?`$/^^{}DϿog[y1MҬe,4ҷ M%mmmɎ N:钢0S9aC6\KC\ +} to3KecܹE];~00ox7d6lbf,3de}|;v ,x#K6A#Gwޓ|ʝ;ǽuキoɎh]^{˵cn(>}k?/~_577FEf Zu咕-30&nqK6ʚ*лp,@;dǞă`HΙM;98dˡ̗}'/^ `(s&;$;8d48d% 2_vබ[$GHbO_ `(W~y7 Zu/ oO g>{tZo'ԇ? Dz*tGGG@fs&kiq2Kd,7~~|2_rNNN>?Xgk>lrኜsp"|tg;57특qϙ{mLƢEW58Č~J=;D^K7+\1H8a2a?oLoXBFLq$/@'.bMmý~zں`-uȑ/qG0FW >ǟMvCuuѥ yfDoQyNjG;:vf{v".}i'upNu;vs0Z֘Q|bh,_}2MI;D^FG8˜ p}}.MU21_ZWP}Ɂa*H/]5O7dՀcǎ͙;ykL|@m+s>+#SgN;,,~./7<ѣG"u Ng'iـ-rEFf^KWw6+(>14?>Lv_3& C67~P@7'`TN{knp946Q-(A W;{]Y{τ 6,GL)-_Pu}5t}KR?sKFsQbp n b^tTv.HfֹkkxEpSXMH T|}~ n/ܿw]*%%ɻkzww'_Fh!68me}jj#w#{]G+v=U:*!{VxkBS_1}׆ _s$QOh|…}Yg_O:40ik]d҇7Ͽ;Hk];T!:ߣ<~O߳cAC7Ŗy/΄~ \~Gkio S'aONԖv|ݗ|bC;~C6WCֹ=B$'m%kL25v'(=vo؄~Un\}ᦊ"SOI1Hc$ḓn+^̶z rgىoᨩ YϨ]O,Q $>6|jDž!Q_1vkͿλ;<>\:ӭbI0nהdȎJլK ܊inc^JZ|{VlKlcC݉QgV'+} W_ @}-/yn^۷?'. ؜;:T]A,=G־Tx~8@š'Ycɱj#^biZݸ#<+:OuvIJpnh}󵩣t3kI5m%>wv;َ|(_}(z?Ϟ]Se̛Igzo;*o=3F/x> y.OoTf}qP}o(fӲ`XGC7Oli|_ K7> rƉے[ :/t/UNΏյA_g@ pa @?!ͫ)Y] |KN3Dmd7{vL3޳3WqpD, 2u~tmZnygwNI]Rg&ڰؔ[) cd+Z~WDKɿ~~m;]k57ޱ]]ubkSN]4e*}Wwqѥw5o<]wʱl(SeqA!np/(8#8V0w\~/͉CޙsoQW)tE9'P_RIDATZ%WoSoM<*m`(HnEd(~7I''G?{XS{c@޶94Gx:WuХw}ccc%G= a6~+{M\X8;ҝ+^+!%`kjw{zT[ZӺv{#ßWk(/ӆWCu ]K jȱc~q{<|%<|uUw=SN9, 2L52eֵ7Qq0F|Oil, ĂtOYҸ_.*fj jC6zUCM5L8iGd_q4xUo˯t.;.( 77EK[ďjO777ڻͲrsvi_<,^;w尊KV&W#HN|8m Ÿ?nr4v ֥\Sonkݗ-oYy]qK񛝓+]ѽsZu?yRun)1qh: o<@+Jx:lqc @w)Sf5O}IO/3T&.{mc֏(,\g& j:#Yg ?6vsi,H+ s5LN%kOqiy_q՟yO_]O'/)*(A։*Y#Xn#^׻{# dR Bω{Uv.jQ =֭{{45mowSi=OޯtoZ~+>r]Ot҈I7T#X=IĖxC榺t}@-Q%l'ܫ'M L6;ֆ R\zF}mkrOwQ3jƆ=כ"Vζmk` 2~Y\S'.[߂E&qVef}^mKM p ;-zg-_iK_2G;[׵Dž1'@8dW{BznT~];I3H^F$/Yc~Ҏ#ҳ3W1o ;w<;/akk҈bᵉ7F3F(_cO~" q3g@#jz7/]g =73N>`"39d ïyYrLCeju@0<pD艓[!ÌCd=IM!ZaBmH>"m_y$ 9dc2_K'),3de{7|5?/$*ΖuV|vY'HqAjӻ_f,p{ۃd}k?/~_577lp-:Yfr:~xo xƒ4E{;ޑؓx 9u `'g,c94'={X^Äimm}i?vgMҬe,<{f?ۗYs3`X,30K Hco 9d48d%H .7//H&?Mv_ b~O}z*0dlbf,3dMGnOf8`> ް#Y~gu :}dwknz72C61\KC\&؞=./&C^ [no=@6>z/8tХ\2eg\ӿ+w}=sF2aZu51믇3η 2[M$b2ζ''̙,))y綾^R4G}?<Әrْ% ϗ3gԩ!Y!L.Y_;^v뛛Ó?H40w?G'~ RO S =Lx/, JZ ɦi??}[+`r}oO\xể8B4  `"A `"A `"A `"A `"A `"A `"A `"A r::: 0  0  0  0  0  0  0  0  0  0  0  0  0  'p]Y,''VVdꢜ`dl)0/omjlR[TSu-3BR`,eaAu32R` HN-uUe9IcūjZpM9iXrUUU cӓe̐SPYT 5]NNnbl)ILdK˒^[.+۰e+5 n_׎),(LJe]/ѻoV=VVףTpsU%K_VUҷs;vLG~PGNv,4TOOokYMsl)@PsؾAG=v5s<`U}V{౶t/9jJpv;vS QM_w_K?F|LGtPG-\r^8M\L+W<7*xME=p#t͈w V4wt$Q808Xiy266ʪ;V Ǧ7Tt3}v?zo;ezwpk}uYqAWX񖡖{L'=bޅMnouK׃~|Ufʊ#WUOo\n緯[h֌^ckI~} ؙ~c u0`EEӒ]WwcKҶys%uJ׃>U*GU痬onO4uG[|~ CL ,u{TXWxc:ag h R\TV,|l\G˪zG{i ӂVK _uKqp|וşa[nizn,VPlUMCs~ [j*Ӗoo[Uj+778(X\6R"e{ESeAN(~Ҿ$T6ǯ"v?|rbj5 M 4' \UT##%o暒rB@gꑥPۦl_R>[^v܏`E 4Q,"A `"A `"A `"A `"A `"A `"A `"A  z0`8@) `"A `"A `"A `"A `(HHHHȦ|[s,+D 00onLvM#ew F%]Qjwv 2ܜɎٺ1oSOD*D @$D @$D¤ 7N[Y4R|kWtڜCƇO)]߰uNj6,;uN & 第wqwpk<;,?;&xDZo9Ǔ7 ‰ח?3JYjKӏ؅ l":cȝsn W<M ^37⶞#̩֯nw֭8wJiqh6\50L*s6X_<5ݺ6WlHW./~p0Vl-tƱ knpgDV+ ~W+߹s77,?vvi868^dzu7Fgҕ{ca̸Ά;&cbsu F_3۔n@ڵmxՆs?:gn d~G`TYx* dz@bɡSODۤ,`"A `"anaۣ%Ib@}+'r][G+@ 3X,HHHHHHHHH`S @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$de9IRוrrbeuR]`dԖY#;0߼-64'\KmSOU׵c/@O 2+Q[ d %;:60lCU>TW] 6'xUMӀ_nZVMM==VXRQS[QSTM5OZzYUmM=Z76Mew[eUuuhh\޶ʺڊڔVԷv.Xrūۜ\²vLYI֞ř n[WP]V?=e5}{kMIb%[[IAmXXsWK[}nuIQ R`dt]YΒMnoê^.Xs;TlzueK7t+oMckea7 g^pIn\`pykl*̿#L4{ަmMa|{0-w:qO.U\QJ3@bC/ݾfq^K?,~g_}˩4n\>c::m_ 8~g,Zhb]_hF=m,-=ͻrcru:uꒊx{ƅݦɗ;^޸sٷ=?rs (Ht[}w8\rQekϭs ?eI2$M˄#:EU :Qrw܏㽥6DՇpS]eYa~n nzizNҒ,p/**%Tկv/-^&cߌΥz ۗ* ֚ջ5ԯ*NK[[<Ĭa ksmYAnj[iO[SSYR7WLOweBtMru%~Kvm육"ȧ?ذ#qcb[z ύ%KXw4甜X9VOX[:XAUU״ GӮUI;wY՚:ÕLה6@dwͲ^Ic[̺OOLSKi(?p|Buk+ AE8{?K*lk;酫z+NikؖV_dNcͣ~MS}"%}!uS8+IDATSןǜ;Rw)kh2*@<וrUw<[Cj(ds-_4kF1Gvߵ$WЦ7Y<;oZn # * $[Q|kg#U^>pkz~ɪԤ{o{ [XVYz89^8:ʆ`4mwAm]}q[h@YgT3HJΝ҂T#UwẲ\9&nihN5ޭ(U &/,)k~2m,ܳgͫHc,Yr@yxV͝D-&Ap~, ’UE_@ۚnm\k,sS z_{~c!7V5Ioƴ+k)=3ݟZPnqÓUEACE;zDsEak«}ʰH`6/yHj8ݏk5[ Lv[RuKZ7ku[}V? 5895 J<7{񚍍/vQ-nyq ]m7MK,+|OʔTڻ5Wff {tx=N /?ywn5we&A4=~lÍMl㱥d7X $Yt{F;DᆺDޙ|.%K:RRĐvT'vrgX`9sǵg)^1wab|ۯCbթSZ9W0qn6mOTS+н`p7ΰ6kÅ\Z;X|`~A=ݶ,E rqq`w i涠'x3AJyρ?pccշ]uȎlo'B$ŏ'@%)a4]XFgeW)eX*{k~Wib~eK Oo:@/&HÄߡt~^gjTQvz[i76v{0$V~v ud(\d58{s_?wƦJyÚ,SvQEguYJֳ8}^H,ւwo~)}>^ԝ*~_['kopÓ*~o6ǝ t;ukOvھБ,n^*GWMX08v4<76\5Lfѹxca^Mw8;Ui6wmԉ|:7 /okN_aHYvgQaȄa5,}([CΆ8On'UUZ^~{77H-{QsT!`Gt5]=ΑtdWy >d.ZPpFPX]q4+P>]ٻ +?=tlo`JPY bo,S[[՜;W\0͜|C.*tޮؔr]8ԍ ]>1E5z6>/Hlρ ω Ѣ![eV ǚ×8 ;+?'*o!,] /'CQaaDeoxnO 7YkEW[©WV2'2 6g4dgeMM=[{NXͩU~UͥUbU)oKh<S7pA>#8MumYq{Uem\#YkvT èQ|ns?.@kWׅX0x3&#*z0a<ѢU\0[<җ_HAY t-'>'tkFݫ4#r+׻){6bs:. uuovh vXyP敽69%u5: S{`,''gl0H#Xz 챴~]@}띫<| |(8u._ц]SZ;jzAZ~=꽻2v|+8>Ll˕m$wNݚcdS#t3N1Ĥ=;\pǂ ] YKģK#iH9Ms[Btb܅|特4qv{d6ЛxpߧNlj&Än̤m<㪗>wDw76糦``0sƛ23>ᦊQtk+L,&IynO@ط=~m2j@ˢUj?ZSHȦ`%@wJHHNIDATHHHHHH&;%D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$D @$4 [ r Zh\Ͳ`b+ڇ;ȷfUqAnz#b*j[dalUyS[miG{ݲ }Ӄ{lW-i c:Bۗ'`<\dK<ξC-=Ξ2CNق P,gɖ;6h_,gɦvl. XC72ͫ[ꪖƦ΍.mjt;h W4,mjˊwPXV֚ڲvUߖ&W?'ۛj*JzȺڭK^n!VZ0;&1\S;w-ێl۽eUs Eo꺃H۾fΙ m7=‘voeu*SMY cj06;#\pJyy[*rAK&xdpQUkGf >mkM<Ooݛ!@W 0}êKx*5cѺGfxtݢazqUg+ly53xe8-K6w/~4vKGn̫hwLȗn]>3>kz0k#mک{o>Z"mJ7]Xc5:cۗ;}sŲ!/X|_KXjU f'F^]o;+4TvPPVYH~N# +iv|/ F~ filI܂ҚԎu9}̹#} :4'cp/o[X¬[JszLXL#'Ҙm]wnS}}EEӒ]Wwc8UV>sK\XVm[zkj5,2eiA6% w,Xo4v@TT'(~9egn*)jˑ>UnlxIAiuSk!F[+O)n Kaq+V-+/&+N7}AѪlom\07Ჺ×1ȆUKj|y7eKuѹ?5m<oy[TY0}MtkS׃F7W]xr0}@o}@] p\lYmˍoX4+Km{-n9wų=)xF^ެEKoXwߣ{C7KgWiZ^.>C4w/#\y Z = N,HHHHHHHHHHHH é c( `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"A `"ᤀ~l2Y#>U.}9o͝M|Cq-4`bMf^#\+{&$ /< rQnX8wE Ɂ]t^4/^${݉; f༠s Syӯk/6!U(gΥ 8$rV@ ˄ÿ= cø{ӼgSU?"=7ŧ?DX}g%<;|7>4^x?g^??{ILyo$ _bޏ^ZW#+P>rK]7C'U_o{?Is>` |Jss 3/L VgI\[۩ <z @#Q7O~yzGfoj ӄ:S^xyw'lw[s>YKdOLKw9?꬈5>t^xxa#>\o ?}kJ Zy0yu~ֹ>˙?0r:::lȧ_46O@r̓xVN=}F#Ko͹+9Ȕ^RKҽO<'&xTսJX/ē~SO_m}`8g?{_笼 +ɿr`>4{|{ g_OM?`ݍ`=Zg%id<2)Zh{7G d#G@7?ZͿ?0l _IG{W vo_^{>ʦ=w]?xzWVNNN HʦoyVil>8m9.:¿J6'~<}@gg}_Nx)w)=~Ο7/~hf$z{,gf@Fxm9L {I n޼ D"W|x}O +}䖯λ|f+ݿFzJΌׂ|wyAGZ~WtqĸTh?yɆ/eSo%Y~oؚ OAB75N{keʔd-6 ?_} {eK35vP&U~zdG _pgӦM[pA1㭗Ov~1>K/) ŽX65ş$;9//'/SOS8;8nwس/x 駟|/YRrAAAp|^?t'ٽs>J^+n*,2J655PM KƤO?lꫯ6=Cǟ˵7hz)gogJr;@7|U >;zw@YW]_|k6Ξ}a0Z3fHzexwqЈ Z|v===OYzYAy/{mC2KqUW̘ ^ Fڿ[ {{o7aM%pSE߈;X:9kpAa7+8 k>܊\y_/9t$מs]`gd/şo?M,o~+ٱ}lcoܷ.?]v]7G?:{~:rȧWݸ+`Rl;.HAdc/ɿQo׷M.uL:5(<>imiӧݾNK{.Ov߳~}%pܶJvwֻƪ3wnM{l\9s?Z`}?hllÍ'ld'W)qwXEEW5#555%;}ɻg(;Ȧ~6+p;;`/ 1ջ~]NI= 誚w6tǂn :֖!w/uߝ݂!:餓fw ?2՜ ;wyWZ O{k(.\|[Ž~vmǎw0rACW-}wKbK֟}81I7 KgU/tNao|/ZTj.Hݰ* 2Ά+r[][wnQIw9s_9|]..n?}V̭N,;~mX\X08>BSJ7lMdۮk/XyǶ}6f苷W=o9TEK7'9/_WBu3_N-u;wvK%\ubabM{J D+;ea專u,z5ڗ]:yJ[Iyִ+ܰdI.-˓[wM4.]6j}'aHňFlxNi m"%iJ ˿aB\K O'7 Lиy;}ׂ+.t|vֻ/L7dk̙駟:y/E;.RAwR᫝_]1 @axbZ=}Z'Ey>e\}O),JO}S~t}OD6|%4t5Hw_@m N޻ﺫw_VI3m B E bAcqs_O>z6Utrhpfp̡RK6c| aoW#kf~SOS^G Ι3gtޝ䜔YOVtvFs}̛U{Nq0LTp@dd9y%l=fDĸr:סLd)!4-7Nܵ,6< `f:3tk2q`c{O-I1 B +0[.}vr;~s^ٔZ,?S׮]֜0wޕGh{wݽ)$K$UPe_RvMZeTwG57& 7µ\xАpgo+ɫ A ؤµZUpk-պ,<*79OslS g tovFx@| ݊sXV}gGw'-|A)tNj/vxvl%_o7ajwvfΨmЁl5K7 xO]VAk/㻣NyȘGxUբmm2J_e 9sF7^TW^qz8{2]oG?`Z/X;0ʵaӓlݺc<;n.|dCD@nO ?Rٹ|y+)/Ohx` }huhq'߃;w|e: T4:vtM/_fLIDATftA`zƫwM$ر]WZz@{ǟH~1s@gq=9Dt3gH/Ymށ:$lJ] .Y+SnXknfq߿,5Bee~%;)o5K7%ğ^5bSVr(_+]3~'ڀvO]z+w:ohYرvDu`{kTOo_U*?,ڌ{_/R^qSsm4mJivJuXef7b:srB:'dDMDD8nsAOA ™3grEڵ{rz8pЖf&5`ɫQ1;v?PVVoioA׽X ۼX+<&\) UUU=9Qe^4^*3Rez{-# 4vQQWڹ鬜#.zF ]gUVsP.)I:wz`-qUU[mo+϶5=ɲJ4)!S'<+@ws]W]Uߨfsj ))aDJKh}O)~7)})~[6]{)*$+mHjG [~Kg=. WZz@*UUcqN lXs1 Vh6g&vn_zlᲑa.bX],O%O>۷Gݹs籱c&&= ϴKDGˎIح[72ҍ- зo{l_͗ʯ~W+ε!B|'-mЁ:$l?O^S p[#6{1qGΚ7>"\$&RjnJ ?{~:;uꔵlو;vLnq0o~!0dĐ_uD[vJ7_:H~z(p. otK\%ݟ÷?nh4O͙2 I]ަM>h~{kV:C[TW| Ĺp23s ^ _tn7SfI7hU T P0=3?Hw;ues_ WUrxƎ=Wշ޺p鿺ޢY **9,<~P(g: 1䳏?ߟg\®/;k^uRgeO"ջ]T=[FnO(4.%'*K[[Yi=\)ZP3'eWӳ(^8*a„Ofo8o׮]&G#.]yՂ5!Fޓ,\:X@- _8^Iӧg^$!Y^;yTК;hCxYUv6۪Ӊz]7a|ާ]oNt =hr/nRv]\EY]E -^Z%+Lt{xOE<7؍S'O9ү%%mۼ읷/2;IMMInR˿;ίrhA:gnoq -f¢?7E'zxR<m^]^x#e8?a7VbQAVuqaRjC_}P ޿7% /-ɢ1fN4X>̇'Qj[4="7YKOжnxBOhK>uZ4Z3]oVSO˕rİaTC]]M;. ]w{{j{3dLʪD*CmyRIuyayZIjԕ\9Mp5ׄ @ET: V-oq^nъ9sVh>wR~t#ҍXֱcǴ/(x1E7| *.*?[FM/_>#GI7ڲ,ݤ?uZRH㶆ȘGxUբmm2iG}|͵Q.e=tRw-M/]3 I]:8ʧ|nii[#'&M\8c᪌U/:6mzP^^vZw-M۠>%%!NUUUO}:fAjxM/૯,# gK۶9+8G_5z atY4p=֖R8xW|F\+rHuAZ;?Q͕nRadL<ךaC[o}:RlEb eYE9EYч'Q*-JP M`Uro[rgB{N_um{ruuŲw#յweοG5|EUAZ'ZP`O{)Gϳ~0W{'*?3e+n l[Hb+N尧G"kfI܄y~wA@;1?=/>":SӧNzΓZt, iɏ^L?,⳻:0]ߣq)˥_JJښy;o_~e/uv(j-7qʪWK:Ha:&E=R ~?ڑ}DR gok}^J᫢D#m0Ni=܊'7\fOYX*e[,&ŎZOr4ʣf~`KgC_:QuB)kCBڗ~}H7>o pڄ ~ıa~Bk""5ssߜR= V+_>#GI7ڲ,ݤ?uZRH㶆mzXk mf̛ﹹ +fPy)w# {l C[R!&)K_ƌȟzJ+1rȡڽh뿻wܲsӚM?YY(eաTI+\* P0@U o>ã?ok&?7}KJKKJJE[zÇGK/hÌ/){BoyG>?{k+_?=w%Btw޽HI;VП&wɓ'B#j⋕{|'%O{yK{iM*;PVU=,Y}Ғ>k>h](={]pSK5W/%-W7oHQ>sKO+"91i We~qiӅ׻vw mЁ:$lJ^S謕)F:4\)ڵ[g߾SfQ1ٻ"  x-P>nUYYy$Æ )o5K[ʭk'E)de,//^=JHm] tm7LJyw%ŅJk Ўe78P&gZ=[R~'z^S?Sr3gμdM_ZE-cǎi _Py[<1kF%]t=7擟V0=A)=U۵k)0*nx5~ckV<Ѓ%N^)ݶϧOG b]͖afPй܂U}gK6/aã{t)˥_㞻*?14J57%QZ~oUﯖ _u䍑dE7n*$)Lߠ$޳{:!rX)n/hG=Ͼʏ͜gMv`mkrW] P,H$N OOd 2f(7 ࡤD(MMZ‡1|uW/xo_(Ї|̽&g?&8xCD[L 0 Y+S wе ~Æ?vR(hf̛YC}܍6l'u@;ԖЦ$XJ3W6ԘѣC/U\}Ԏ򕕑7F9t]wmwwW[vnZ?+ /c;o~\p׮]'?_pR޽S_|2ֿ Ð]~ZvdK&y~,Zֻ?|'ZG hJ'7n|{+&V'.0駞_ jA?7wK.J}e {2k:w,XvRb;v(:]ǎگoHH/a&fUQQyv1j] ]vb=] ?d~+.7*+rEeFh]<9`\Yc4u}hܽb|yMwsnڒ}DR gG]7@/uG~z)~wy':ywVPY t>0aV"G |m0_uԩVN^*lV*; jg#]yM,a;IDATo.nUUW{Y[kFh$5&M i9Rf޽@} qG|!v:W @UTVㅅ;;p_$N<)9|?V_1r;|î .@u7Z,*K;ָ6{$M믿n|6ຼNww޿5vBe*W{0nȵw6WE[E@◗AС\y}_-f6/IzʁGNw~|/q/[^^Ǥ`Z+Rqۦ)^tQ^_$+6)리?eI:` ?!oyל_iZP cRJk/,?!Z:e2wvL tQQJiŠ*.sFG';fUǎhhev-!4zԢpxbmgT^=QXk[rqnӕܑiM~D%.HHo/%4, ۤå s,ʸ2Sz}}ReVW3R :ylTFhp҄iqypyL7+Vb2ُbH^8rD _Qf1e'džKOS(UXV+/BZeSn$7V$h=u i56В^~kvy5K2?G-=bJlK1QK1*Mv^4tl|ޒr.q_]ՖبmW`ڗkirʎ.}tTXqPȐܽ+(ڻz֘!!.W  hڊ{*tIc[qR@HȐ1g-vomTY?7p0 I#Ov9ﶧ<#U_.E `*4,~ǒ%_ ! 7%ƌm'DÔiM h6!|ib@:U`,*@ `*@ `*@ `*@ `*x t$ P0@U T P0@U T P0@U T P0@U T P0@>z漼]v8xȑ#ݻw>} *fĈUAcZݮxh>i'o>l\rCE֥[@J) ]룓'O},tړ:<:g>uyjя&0_h|A` ]닪17ݼ}nnw?~wXxX}tzJ,%w𫢯}Ǖ^sͺQZ ,KG{{Fr7<&u_R8l̴-dD%8K!W(Λw4?\oF*Ϟߡ5_%ݤU֗Elþn"g9R;qNA,πɆ>@S\:p #Z %ȟcߤnd=R*{3sX!bXWM҉6#<>G/7i@orOcnQΏA)'<|Z ~o>˓7qʝ_ӷqKh4j/E~t[P`-(?qUjs5fB!N'h-X_8?aB1yEa31:v:zw6607޺p{\"ڊqt+E @S.//W W sygJothޓxe|eaqT{ɫ  )^e* _ZT^j~%鉦hsaJ-ހF'_>T_-B B7$+O$zr{ؐs|Ejøqta{t?#:U: /|U~yh t{V4Ӫl;(rȦ},-{JE "A8?shй,*1*K4I8gдO;5}iWOԨې$N.]6GIֹ󁢳KAÞ{B>?ێde⅏wa=%M2)gؐ\7}(DjtpMj4ǎ=.,͞}ƹm_+lZZg&J3L>?܏hE?(&D[=ɿ2d ,"R[0V5΋bٺ|Y Fr[rȪ;˻okwZBHH- Ç^jO]{*{M]U+wde -<8z6e:/O-^.Ca륤Dec<86VNKL\#4G]zܞKSR1߸vc3ǜ1?G ~r?|$] y<y*V̉)7YI}x(f>Lck~הSv7;4?;-|A)tNj/bͨڇ7IZsZsH8O /)H I=|eĕss\/{$smۼ/eɏ/Bh_4\cGu\>2|Ȉ!COjݹek7;xCC: )^>{>T טѣ};S4A+|4kVʫ@uqϞ)Hz~ц 8K~嗬mK>s6Ș;m/w  0m `*@ `*@ `*@ `*@j ;Z@ `*@ `*@ `*@ `*@ `*@ `*@ <(Jk|O/iuINJl6P MɱT ΝyUu'%'w_pu9escOXia{ai59ָ0&ƾT,B'/-ٴb\(p`@kX6gMٙfYfZa:'s7gm@\XC6pc=UFye0 ښ:e%J!c`i٠`,йܽ7DJ"(>N?g}f7<\/h] YVkEVܙeJh!tr=UnӊNȅ qՄL - =;ʶx:\Y w aSȿVׄ\61#Ms@]bfQm8puYQfnrȴ?ju(U?tvA|5+V)V¯m +r pN4_ ,ؐQrd! F=Xpx )oͿvZCBK  $3Ah㲸0yHpx_Bg-Ie$0U5oh!*JݐQV?V%몽&Vzt~ ꚻ6@U T P0@U T P0@U T P0@U T P0@U T P0@U9^)ot wh `*@ `*@ `*@ `*@ ~Wzs^ޮ]q}S _|ԩyo;.O8׸o w?b숛Y)?)pRnu}ݏݭ OH) >#" ,^ 8~)')+{%޺p!ut0!lѡC!#8[-x$%vdL<ՠA>Pa &Poఁ}Txd&e㒿gn(1=MWM:[+t^+ 0@M WrUPU,N<%?V]vw\wIv~uŐ+o->>(=MiȦyG9Si-S p^؇`_+6D?=thR8G~}2aOS0uGˎsyo*k&$`Gx@DFM4VxQ9+(pN.G/1Z1&P6Voe,뫠MȩZmBTzzO p1d5Yh]YVkԡ"cFJA: əEu{kYm1'۷ƥklVspeVgiTMˊ2 :꤃TfQQxv@mxlJŵ(URM蝧әtsM6]tS֟E.oN:1q#=;הY2aE.oWl,0s2fɘQAg/(9_+W> 8-C%J\@[=MYШfSsRY^{'C9gC^S%=jmƒ1+ gy5`VaYjR5Zb=l_aNDjLrnh=FI 2fǪl:qyݶIeco=OcXШG{ˋ+rn Z}!*bY]JkqMDΒ@>´QQMjBd1AK >RxB|͝epɫܠu.mteKIlc{WO:vCO{^ӨԲ<]:!y^%IsV}4R4L VdjQ<ï4e`K۹qymW9c㥷9#CoЄ\?w֘wg:+QIC{^HQi64jV דҠ7 К D嵺Ș 58j &cGШ{LmЧd>*}{IjkN@lkr}9ndWJ{K2ֆ'XrUdt=?tVaIfo%$;On`}\fRW{B753ϞG}bj-]Ǣ"K1Y56|66ZcN>\5֐W^8鹘4DYQbrw;g$ͧr)G!hq^R4뢢ʁcS49wFE42%c96N^X^46%X类8q@k:_[W$󛺭הغWĦ\UOQIh5߀2Rjج[7%{N3~gu6Kk8m3G5ЃJKCϗ kcS2rLmno`խ̾5Zސe,6 gHtW}qfݤ7 ՖyAQ)ʸV}RkJk^\jClzw[hF ")[]_g"ͅ΁E{75lKuq bf"kn /-*rM6ߡG=WY^s[ l561åDyyf9vqzQg;FS:˜; 1Re 1NѺmڛ**Zcp9{MMŘuv&m&okݿJ:ouud,5]M<*,֚;_=>XYc|̓<ͭdf]x E)c|&vLc:vGCz飔Dmo"2sHT^YY0slt)1Ƅ(msX}WUڷBP|VjcN 4VӺ cޗX2kkYjTYNBj/nNTvd.umOSyG<[5\Az>ꊚz;fk5{П(+ boL-{2>݈l嵒\si!C9ސM]SV&~(8;'o-h. -kb@+u ZPQ^#PT V/dr%ok1L+2'4@3~%oeœٰ+9-X" uI &drb@SD%Ni&I:Mu$XU T P0@U T P0@U T P0@U T P0@<_W t$Z@ `*@ `*@ `*@ `*@?  sf<9;E 6z_yȘF4h-4Qy^#s?F3;n.U T P0@:*(MyuW,W'ukc4 ]۾u *>j|AF9-xu\2) % eOٷX/"cIJ osV$ک;lnD\pıo,Qg8c:]QC{<`sN| Ϋ:7TSơ 7Rj{԰*ݒzLD<`KU G*㊥0Qnxêl<#"B!6K{[eIZԷlmJeF [}rIZY_&I}};`1urbaQf IsZ؋%ssNw[hVʇs8V]Ծ IM'M4ֲzҲu6[)m:+[X;%@yTr`R;sէ_;-+.t|v;}[HaCk.8jsJegGe,ߑ&Fm:B4-249.ݹ3;)!w|vВhbjԮ;9 qRD;@Z6wq5כsWLgq:AKI-xyP~<֬FzEZ4Yz`$;2"vV/Dd(eG ' V:єcF+&O}c!::e䘦i'yaq\4IiLW <q#幯Fk8[Gkyz2ɖه_;z{5j7:n`,|{^I O7ek{mUn~p fS~l9Us- 1"T׆+ǺC#cb7ThZh"~/+EsA`6C O6ͨK  B(T P0@U T P0@U T P0@U T P0@U TAcZ-U T P0@U T P0@U T P0@U T P0@U T P0@U T P0@U T P kIh4Q%>ծ0&j5mZQgM EQ\5 3IRݜVoeŔe?fh*@a@!+YVkՐ1mCEQfJl6P Mɱ$h5g%dY `stcczAސYTVrYV\ch%Zye6.\cnuY1#%j[^woYfl~XM-ae֮Q ZOU: SgjNq9 DO̴x,Hs t{zNFB0c;cՒt}B$nLP\|5+V4)x߹͚ ++l8z4jٔwYRaN`an4]Cw!!D-ɊU62&jƾ%܋LkNv=)리?!<\ߜs9K\_FjLrGލoy*dVaYjVG-~C'/-*)Nk_M4IAȘ v=5X$Z%%vNo@Sj^9%CTyLLMe595:[)9Hx]ڜ;Y:'!s_pYVo)TplV-INϩ#g&+Ӝ^nP[iSjV d'4)JNMZVXJDpFGmhE%%K']}%kZ!!9=XTmȔΉ+c&3S :e(HBKq)Fkd;li)';*8'4VǪ%3Z2uV7&hf Ul۞XK9%~B,6L:*,Ⱦ( dȘYK ]ӯ{s⇄lR#;(ڻZ)ҠQ񏦭ظ"q %m s])BWe5v, 7h `*@ `*@ `*@ `*@ `*x ]-HzT P0@U T P0@U T P0@U T P0@U T P_9/o׮} *fĈ[ܹsgsMcZݮxh>i'I2%#cbw/0`?\}P;] TC'O2wMIT~wSO?s)sZt;A>UW ߿W8N>kٮ]JEkY?_``ho3hTF[KZ6СCS8-V7ݔbF@" +~e}1[(w?\.{j>uo oСnO~9#G޽[*۹c{ǎЊh@W pq~^ _HWo.Q.Ɇ>hutS 74KII;/5G弻e9T+<$ʁчŎ ۧXOH)\{V19|X@c8ռ-/ozzCHH/^BǧZ?`-W)D^{jgΜ7o`T*״-fՆQ׉ƊnКi +Rɓ+VowްuE=.C@Cߝwp.&2N4JuuE;vЊ .\_]ս[q7vM@ht_+wʱcFFs h^`D{ _fuyRu-  s 5@~^}V o.ju1JATUU ڻM)׷A;m)ON槊V׈'r4+r׮]7=woeϱ6?@+h?o:Ӆ22KS[n)~Q)p#mV~Wpԩ;Onۜ'F\72Ak?q56ܹK)PUme?V9g^?hI?s/ZX<9TxBϋ.;*eQ;ZsLʷ"Nq>Iv`6DիRص{@1<;_ofhC|Tصk]Zgeg+ "?Mo^)} "?&VTTJ+ Ooq^/~YV'foݪ"F#DyGi"n-TxkTDqqhMKEDh-jѱcǴ/(-[5ԩS18m:î|73%Z_Eh"l\۾o) &G[ "hm|r12&?=_Ȉٱ^C>h`If\ѹP˟lmYH߷i+XTKƍ47 V~$Deļ`ߥ?XoIްP='5bg&YN"x(gLglݪ^KqH7;"ZzΝ;&s  tn~8pr)KH-'<x_+yeJSfc$17CY%Uj(8ؼoR9HigZ[Ol"r./1\7q˽GN|[4I /p}ySWk-D -Hھh\^)t,lH)/opm)A49[*5},7M_z:;;!t6BL5Ex꾽=Y`iF߾}}2䪘#nwsL+];?Q͕n1>'$m\<o=W[i]1霹>=j\P`nI=s]@Z[I>Dl8:W(wv(M0g([6K{J(}۳$-[b&w4V^n{ [֙MvbZ׉Ve2!IxN+̆uS'q4N?թo%~}ܧt 'loSUI!iʋ+E7Os=M#wԵeA((8Q~ػږvė!(loG8Ent{04VÇ}o,7q5vrҥ uE=zfcp-ҷ7[ӄ:g$@Ʀ :|nܜӝ;Wq~<*慩}mS坔w}xNZ!};ۼΧ4V=ko6 8ù"S |qk*=0Z[Vc7a.)ڻdCW/6t>s.7t%/|vq!l{ciFhz91FyTrҕ;y7coZG~|W:tx-_yѢ9-+.ttx}ۛzDieg-9([,3-C ZZܬ~ktC{|ru)[rpv8,DsƜ)ONުq꯿ܽ|S;V׈'ϝ*~"i&gN8r4#7Y?۷亮cqRKbͣ:7{rIMS}YOK~.ݹzoe֮]r5ɵ\nM0])x;}e=Kشlɯg))Mԇ1_1jwO/l~`ppMn<h8k{M4pKBaü Nj뜼t8UߩΆ=dq]C]twZaa~b܏ǚϤZhSkކwpǎTү^Yʬsw>}D{8U3uKSjc1R4$̅>h:ɰBNtt^Oj6=eb᜷؆+zv?;#t=헶u(}666v-Kʒ>|?zBLVn*t)+عS>'(OlneM9>R 1SnDiyV IM##i:՜vU_PȜHf4&U.If䩵olw$ (%1e,ϾM7lqeJ/_ۿ焽ۭYI똘ƒIDATԧO㺵R,~5eWBZn9v?TIi?H_~i%7=y. #7j b׵vJR\2z{Fb|7ASXw(xRoxoTokԯZc[|ֱcǿ-{n_ͻBd-gyD97 $X/R:tERGܞI@[Fn]˜ϯ}0j(++۳gR~t# "kmrG?a\ADŽ|,N 3Z)i1֞[c5'h tn]zϔBnݤ !T޺\~Rm,^jܞcI@G(//W QQhI*oEj= 6Eث6Ÿ?~\)\9pju&+BEE3_|hxxNN>wߝ:uXU\bʍ11"BC5~k}\`RВSoD ׯ_?sbq?yݸ pkh6nRʋ^;v '>-}Iw?o.xJWV_pm{Omhh#GE^r%;m[͹FsaWo](Z/1;wr.iһ8*C;w,жI}yuF\읷_ODԥ[@O^~I*;Gh11j-3zogvE0 ,7IY]omў@wsvaMN@gUn+e{Z:=-_h?7__"]q+otO#?)4bwKwEkС=hr/7҇CII[6/{me>Ƶ.G"K*8S :) h%AA݇GFʁ:#v*GEvZW*w=B {ـ~\xui `*@ `*@ `*@ `*@j ;Z@ `*@ `*@ `*@ `*@ `*@ `*@ ڪjcV&+|ĘQ$UpYNAq!Ej+ ၮգ2JVoe|mI8cge%eRۤM cnlve]Xʄ Zo-%q;d*ִ o=fJt~E1)NNAYUWO5ңZVlU+| bd}Q9`Ս'?!I)qR@]\ɔ ͢(3%6\k] Mɱ$vNȲµ %Dl]!9N岬%Zye6.\cnuY1#%j[^woYfl~XM-ze֮Q ZOU: SgjNq9 DO̴x,Hs t{zNFBnw/M?։4`INii e I 8F7G}٨6Jw2)۔ҰF$ dMz- Kmi&9Ϲ朓>I'vɖcӷ4ck cJs*WQMR::?cfo"_s꺘SB&=3Qz)Kv:M[j,rcr~4;AƜ6EMj;Ҧ)UPprvJ7 ){xOJV+5%z$:^j:ajCYo[j&b5Jypi;t=U1T`wyv KHQy9FZoj[Q~jrgE.[+l9wܭ5l.mvKϓ㥢"~/*Tbm*[\`lPK;K$)d HM y]j,*(w}]jU"bk8}mI^ʆbwRY=Gq-YnͮщR8i6xN7$+;5ox658}nCmR |'"[ԦwomuMDu R[uD'rfX~QƃR+w)W)խ\{]oq˚*{j鼜4)Ztt s/MAmiu;h:ew-8it5R"f[;vo O)V0wo1lbr*iPo3'7gmjkSۓ/PP}jڍ{q8v]ujcVm'Xux֔Znulvm1/&-jiuY//QDa[ [mw(7's٭JkF;T%_[]N)EN1TK|IDATrSᾔlP;`>bwq6H讛"[IʣUkOwwu!tY쎓RSPPSUdfO6&ms-Xa2y껫:*vՔ ۏ|ќ߾r@9?_ލ 9[rk:Kr Ʋ񁋟Do6mTNmV^p9P_zb1 +d-KWTJkjSgv!&Дv0(BO.#e([ ]KKKTw_}5o׾rY9Fĥu{mvXkVnEMa#+eNGɧ*SS K˚:,PX0u{u =1u=kSϴ4{"[jmyއT|I8۳[m[qxؖ)JU*謹0{6T\3w.s\Kf{>}ҚÛd]᭽2{|oD}ނh,r4VIOIh]7Ut|_s.>gkʏ6:Dʚ[jo;o򩶝5wɚ-;7V0]RsTY8Jd_jc)L6;N]fBi{/_+MoY>jo!']v#?ə3g@3f@1cƤ+ٳo#;t_W_I7޸}۟ ""G~{rM89#7z<ނ{wqe[t`QVgx('u۶o[|}Ǘo/{DS 3g>ĉR:--;1`@TaM9wY3&fP #r5ݦMDu՗!=Z׿Mhz𶗶3rrL0SW::998%Hf2||kN,z!%%{-6\s@ZML4f)m4)>>Ng Պ&pbǢ)Sn Ӷ9W]yt>)3g;<t˺@Nο0QM|I}lxRRoر7NpQb?p0߈O?ƭ"$MMM8p''?f Dh*Fӿ~ [.җ|?;Rr̜PZǫ/BH?o[ofNu _gNQovּ{LD _ܯ&R_0[r%\?Ν;'M.WkkT55Sz9VGosTDi'}w?Ў5h~B_X¹_:.kƍ;P%hM_J!]8@#bQ_. @xԂ{W+R?XݱH ?s} P@4mA˷MU)ΛGD7y[R)UuD@֓ \!'_1W]H Ǟ]w]Ѕx޽x0DCjBO(4b5q@6x 7Pj"; @xP땖[J:},:JJ[o{f}/-{N s+^n2vM7}M-_8AJ|GwY'a-e^5_RӉhqnG3E2nE̒ILo \Hs<سG(ǡ @ c}i^Ǝ=رcK14Tt+W+PJϪQc C3[1r78<-MO(YX,UYW tuD ? +GLuvuKim%XcR1چhBB;LΦԩo/?)Sn5]L+}ܱyw^^. v8t;ڡ{f5 >uS^,pݬ2&L| e=TU-SEUŬ\2.2Αa{Eux9ɾH]tJ(ޏ #-R+B>\ᅏ +k+,)8nhuw)ER$DkW aظ°Q*BXҗ88zTx0`_|wҲ礿="zCCI}ǁޚE~/,VkmT&ߺ[F6սs'xcvw'.ݧAu}vVScͿQm)+&LZUzTq1 8KgbG׊\!~gܿ111a\u (ݞJ)kEE fQ2GBs:e5L/! С_Lwܚy㜥K+\N:%]CnNnWf|FTO 1#vJ~6CRtоsn1n]4QUղU'gU8g/ (e֣ } n޻w¹ە[{wW떪nNO6ssA;]N ~:9ơˡ+^wX-ֻ 2[KsmYtIx̙kO=q℔NKKx_V\BΝ<5_c$< 5HA90]]߫_ u` ܶCݦMTB:Kިњoo΀/..n DLYg=*m/mW3g\yn\鷨i1s?ݨХDwzV = P]]&&M$8:>iҟMJTyv9kqt)v'Sn@JOwGuu^9*..~Ѓ!3ni5k -0u5ר'O^:`s}gΜ9DH8tљ?HM8I߽zKxD)[o]wuQG֨Dѫ_|t}NCj"))Itw/teĈj* V<"P8>a=t1#vǯFIKK׿-%zEFno< Cuy (4Ҳ1F:K[oaC33]w*ĚsqW~}}N;&z¡]@ 2p5O>+Ϝ9#X!~{Տ/u:mG>8t1wby@߫&oP?.-Xa4^Op8565}Qu T~rſ ޏ=;|Lrm%3L|1ߚ3Q*}~\p{ G cE&N|+{y-uȐ!@C;}eҍ@X(Eo;?~Չ@l&L2vf@)z}e#/Mҏ2y @l**9b_M h0@@ `&4 M h0@@ `&4 @ M h0@@ `&4 M h0@@ `&4 M h0@@ `&4 M S-_mM׹JyKs-q &ϷY$<*& ;J6 Q.zp^Y{q%vR.TȧP> %耽 ;''Ij`HD٥--U(QI&%E.)Nǫm]مVOY˪U4-uڊR:yŶM5|5TPRUF4 RsMw\6Kaɠ{'LTޱ$[ɓS~.ѵcԴ]9lnSuɷogW8,_u%H3b%/1L@p F4r O,7[*ŝqY\wp9sKK.7.giᝠli}W^B19K7:ҚȮb(?D]bu/.Hv_e3LYlב:Ϛ Ѡ"cq_w*gSuټx!BGg[Z c] lbm>s_:gqYB ,5}"5uuAuqUJLsRԀ-(/j[$Ukg's}qA PXstMJ Ykv'8\$]ҰkTQ`X]ڝkaGfjM->Kivǵ?&n([SMYҿq/Tug-mש\J*(~[ҎÜf޽55Cmn(3r.^7 KmMiHB'X~xdmssMFswƌ&Qp[ , <6[)V0ko)l;oj ܻU嘆#wUӄ.}'ߐdզ'o,PqFի:#>[Ipov߉pݡ?ؾ~Rhe*eq^$Pm@KE( Ss))z:jicu|u HU*0}^;J6+SDH49k6-JIpK?}.ockO`6ѯm^[t z 8߻'+a Q>}zŏ뵖VD/_uJ6E/nll>cԏ Kx3fLرD7oeK6:P* ޼9hF(eߞ;99#7z>]m)7[ 7QQd*<o6mG9/e=wK.w/\t9@ES 3g>ĉR:--;1`@@׿mmVӖ;n%"@vo||6m" zr׿;o^a =^ڮ&fȹ1LRSG}矟RufrqJq^+{d&3c s2{dqqq^xK.1)c=-RvȑpZML4Rח_nhD3_{5C Q{:PU5fTNMO1pο?i+/kat5]W ̢/LTR o{?^k %&\xTc~LHKdOV>XJ@,Dh]7e7M3!CF\(Em;fljWgBf֑I7^1zPƬDO}}rh={/J:;}K*UW N ȤDC㯿n%"XlJ>pQc "[wہc m,=Xݚg"Ĝ_3ey̙3.W'O~颋D_4D W @baÆ]v٥jO?D/YW9b}O~要2d %_|p:"T ߪ7=X1 <1Q!w' 1xJq8wNtӈ#ġ_YԴnA>F5>s@8EG\WWWZVgzcO0JRBt^OKKUӿxI@8EA|ܹ;ʯo)ctG]>%(I }?x'+M~{KN'JĸeU"6M'$: R,nDݬBkW.__:o73L---zt44aZ< ^pcԏK dcˌD♊:j676lp\Y~'NC@"1{\S|wu#@)}*1,KB-;QxLph-W=R 5Q78 w=Q TV[(4.۰΢V:{OIxGjӰqa| &0vǎ8|!M253S}OwG+W+9)j?+澿qi7g,D4m}m.]e]Rr78IwB?=wW!֩eVoLIv+,sB>L&SXK/ꪫrr 2:kqS)ezO*Nð4Ӱ Dy RJJJ}9)D']j;.)5[zղَ^ZwmV|h-M%O8\}q eAQ-%s7(++w>\[iR4kqI?]-Q()2t&y ޥIsjc=?] iҞԩ__ej#۔RF,U$+lWh3E60XA1Lӥw{I7ꁤE}v]z/SN.=+{7HˋI֫qxܡg Rܲ:{pS@>mO-V!_vuNط\)Nb{n۽5*j':JU8P8]QHnQ|*566N1sĄ%<-T-I "5*rJ!27oqSWTtިQuO>L*gѽG0*\H>paypp@սjzС_c A#N D=!VL,]B_L~2闵Uol;[iA[ KIG+Wn#,FO8tֶ>vRW@ -ȳtn'\D61KCnmdzې,Ϟv6E~:35-K\0h_łڭRG}|9sNKKWΏ]ztW Z\W_,5 V e߂ڭRH|^sͺs۷RcYzvv902im}zѣ5jze-/{@@'N۴):_}[y D ߜX~o]wq7 G Pz{mQOs?<#%E QWw<ԛ7.몱5~?_ a  (A 09q(-{ۣtO<&&xc۳!I Mz>--݂i HS @#)N)9em6N']Urgc)}eCJL0N0nz?_pEI. >9 %"SvAI tik|\MW9sF@>?z=͔۾M54=7!Thjf߻_Mb1N{ڀbL,@fފwWˁ3'D3cgs}.[!N>LJ{q_CrW۾%hUEbґ#GDJ477o#6d5aLODz o8P]j~lRcƌu Z/ґ^oC AhD*r͗]zϛovXSSkOO>DA"}on^[oKpQbkG<ٴW9ɬ=;<&9o撙d&3{uoDX+ 4(6'w_uZDK '2ڡ|:29#innDX+3&Ykjj̝ ; ywC/6lW3x Z'X`!l 0@ `&4 M h0@@ `&4 M h0@t---XG 0@@ `&4 M h0@@ `&4 M h0@@ `&4 M h0@0@Dz[^ۚDqu:R#bv4*5yN`)6Dk~jt+\T-dsuK"zyKkl}5\r[:3d/uDhBHp}uIaȘ96 q^#bUoiE9yqiEzc& Kă-3BhLwzGq)O1(J4R<=II{jΘ! +٢p$ 7X 2Sze+0&][]pܻf#PhKRT}5^]huEvjc"{uIɯK4 J냙.QWlsv]:ߥ׈&83mMj0OZ;_WI)L\k]mG}.w7a7%N_|y~Ւˍ`Ok6:Kr ,6s{dE bK#R:Yi~n\Q8jk,*- X*_`]:s 疺Mqii uē_4Ԃ--͑f]㇌YZV fxuޙ{Xxa()[xw['ؼ`&z]ao^:gqY|kE r#֊{OHarۈ^Nn]_t\}niJn (\c-Ԭ{0rKCRo3̓+om6V-8׽8ϠFcJ5>^!huӒ}J#]%}luϕ1)[{U5:mo+pm^cDCnIWy^aΘv LҊ KHeիv)l&'TdOww氣_TĴ/Zm\.7RTvϗvIR t[#y#B4ԗԮ0bu- vZ^R>J.*dsY+)JmHYuErgZ,Ӆ&:4kZ_)E@zCY#FȻQ*.*h3E{ckj|&P6g]^o0ڪL%.7 3.5Q9碘X)6Tysq⸥<Ro:Y]sAmiM-5mUao}9KI8j:oѼnZYNԔ•]j}ktn >߲fSs]ݑ]eO-&\.HU50`wC V4IqP뛋en01&:jpK{'nD$}qC͑;iP\>nCAɪM˧Oj_]N MDcDwC V[nuލWtv~W*֕n*ɞ.p!\W*Ydm%A65IL/Uԭi+ذ!WntwAlvG-4."po.vYFh;[}zsڸqRS.Oan 6iS*Dp՝]1崗d&a]~Hʫnwzf[ u*Քo-.m5M%.mƠ8rkﺧr {Q`[aaY٩NvDw59\o)=` "l±5ņ1K<;BXVfG{nK4} Ͽndj|VeKS(vMyY tꪫ|fT:f>pu{ҒbffiލB}6V7lpW{}V<{p@X_#ޠV?>N57%X[jW^V.&Ud$%|SHUc;R(6s7ڝkg$-`U FKj+T\RJ5[v>xd޵mTWg{!`L'xfO B*}T[.bzKG`@$Ѐ@Gw}ܣtgr5HgigKDh "CڃG:o1Dh&P J@ `&4 M h0@@ `&4 M h0@@ `&4ԧ 3tXXD 0@@ `&4 M h0@@ `&4 M h0@ ںС׏?^[[+aÆ]vW]u1}RNN8Akii;ԧ "k53px$..N1a(*ӧOO~Ǿ|U+4~~bUgܿ111a\ucƌI;V~ o~7˶m6uTysrg UQKk32~y^}𡇥R:..o n@4#̳[fv{޵\"^ܹsDh*>s̵ק8qBJs? ׿͹j_yZU@vo||6m"D[nwS6l D{]M̜scD7=ߜ>}3S2ޏ{:^ 3Lf2pfcS&-RvȑDh*DV&M2ssss! hnq9i0!CUUDh Ddkiiطᷛ|$8|?ZD aLWuu a/LTR [?v=<}+|oK~wY)=YcɊ|rM#/ @~j+^{T }vێO!WgBS|kӤG \:rF{޶]ST&+iA;o̜6 /bK5ϥĐݔ0Ӌտ%v:FQ׌7C{whЃ?XحI~X+E=kY_ 8Pu ScCC\vj> ~ <'>Ƌ).!!''OqI8d̙3]Q!%ff~ujf~!C <&f=]MSR)&&0h.~gɽW xf!!B)1l.b5t:E8cF\[ ;EM^?=r@%_1Z!1b8Di 'p "OQMy7Օٷ*Hz>--UM'$Q;wtر75@*Oy:³g~YP3S^ڜރХ|_m]D/;ݴ[Ln!IDAT;*DPY;V*K*cqC Κi}ywy)t mY^0֏~3Ĥy I?IJrCO駟:yi?Y1GVt|7ٽkB8kBGG½kE9]3fO5㴭kMq*rP2{]*w"9͵ϳ]):j͇ 2mvI بZVil2NxBKlZ4 +& aC}[MCI|s&+B\H:y-}Wq}ɝ),u"cc1U_ߘcbb’]M~Nky\,=:r cF(C>`莟W{ .G uxd[e/>'[r7z ޶ux{@Z)ʫ|wRg wܞa4eK6:d7=='wvgQzʱҟ~7q7|;~{i9|" Îb8 |]z?_p3f͜q_g'6{Ϩ tHA[kyUY,?~}OpֺYCQ \q ^yZ q_֒v%z6sv1OR:{72yk?Ӄ&g@Tצz_oE޻Zr٦omyގ~;Y:OyقRsSzdO|Ug7y_I̪(7TOGg@ve?ꅷN{nҶT[^5]4jԨwsOyrȐ!B)gѽ?4RX29##sZ!:p^b5=t_J;7EQ3 &)Qht]Aط,qPnsĉJ%HQOO{:QGw!5`)?ZF' ,ݧ,fž(nن۟SC\!G Tתƶ}}?fꢟ :Èe4|KWnRHXzP O4ac9QySs ߂[2(y"qNwcks[9zuݣuMYTX|HVL%*YJ7Hr2eiYgյѾ32n477߽pQB>f]8㰣,P1bGKcZ†o]"Nw޾C(Um#A@oAV)ͷ*#w;>nqĞD^C8+.W=fsU FV/\ t.*ekY7snPj,?;]9(=}MG֨ DnSzoSЕfŞ=R">>@喯w<5nyF]~ '%Dhgߪo0ѣq[X)kFJOb3g\y)uI_|x}*[WIQ|-[DUUummȑ#e~PBMr0\_jz tԊzQO4I1*FkfȐ!R@U S7qc߫jbذa?j~B%n4ft5]W=3bR]]0z@~ C_P7_&v5 :r?j+^ GzO IEi'Oj„ [[+Bq.O<D7MT賓Dw~p=&C?X˜1c^u)[o]wuƼw711c;{B /R5m t~CM\_)6,v@K7+-=CjBO8V)yeC 7eĈj 8V:zx|+X z‡LCC{v Wy{xc:}kDis>Hh/xRMLƤ^.yiit`hW:U}ć}4=--Q Њ]ORMͫ?x'+@}p" @p?.z/}IuQO{Q|&.p聛oi]3g C@8N ~W*9o+J"=y_]0??uر5ロթC =V]}wϿ6u8_UWUtЄ} ;G %_iK_=]@Μ9Ǽ߉/ bS ϛomޏW]y]z#/2ǧ~z⿵{ﭷԁҏż@1WHAC~޴26oz?s [_|Vd&3Lf e~:u1*;8PUױTcc:G 0+2k*3Y\ T׌3dNp1*f{!-awm >)ݘ3v;5B'Xg0Ovv}xc'u۬Fc*!>(zԜuʩ[=C4)S!nIL/Uԭ95\dsUz@3C7mK.gȷ:ժMqKƯuJX`S[6;{ǯ)Q'hmTrK S.Jd*%۝:_H5ƭ%M5T%ۓ҃ ]ĭB^T6VXXllV6o4Dl^G>㩺%{]Fj {RjzGavjd'M_k,r:WMv[OE&%۸xWC瓈MJ.k^Ꜳ@kcUBOW/-PW]{]Eme@u}WG=DDY9ޏB}6V7lpW{}VĐ+i GEڪMKR܃O_&mNeoL )YK 6s7ڝk$-aU FKj+T\RJ5[v>xd޵mTWg{崡 L~{1O̞ИUw,2& DL'XfjzAnELT]dHS{ynMT>@h&P J@ `&4 M h0@@ `&4 M h0@@ `&tAA:,A@ģ M h0@@ `&4 M h0@@ `&4 M?m]QqǎtӰa.ҫʘ>)''{ @,ҵq^}Ezm@/8pwOV<'m/*ӧOO~_ߕl?z 8Bgܿ111a\ucƌI;VM o~7˶m6uTysrg A ,syN&gd~&^/ tCK[t\\l& t@T 3nFQN E {ΗG\rnnn{s ̙3^z )ϝ0 x@T_6oio~} Q *DSYnۡF۴&Λm @Lo{i9#+tͷ:v'̋ٳ^Gg'gdLf2ѕ:t/ٔU~ݲEJTUU֎9R(Mpuu4iRTUO?Tbי3gΜ7x%^s͐!CްTU$ ES-⺺:5>٤Xwѯd}[F]~% 0麺~ &?,zO{Qb i_vو@:}tCC%5*e"$+~5RǏ .@vPX@b_Æ :tu m_3o-w%qFJ:uJtgΜ@RbjfWfvk,Č0yDRRʖJmn;&tE{]yӓnĈKQt_&NG;W~IzЃCc fDM^?.}y5/Ν4b5q~O}Q_>9è&D7OQM? EG'Xuuueejz 3zS2ҟݤ/RO  >ww7H锱cok"T,3*qĉ7 @M<ē{Ь(h+{_:N]ղ9Uݘ"8vwgpCpMT1N[jɫ4q6q-zΚխ/>;eA&{W^%dG|3۾)SDKKFG;hADڄ׭ߠ~\Z$h}a]HU-"sweeˆ틣;Vb6>QDY_5MGgYrDC=kӀ76lp\Y~͢q vКHK*u8QnyJSnRTHVa]4Q*le<TQ5gK ZC:Z-DPE< oq546[IDATdx<\/ظz6sk5ش6(Κ¥&k^(ήhu9[qrl9>G?f^Xh=Z'<{m',iM<ąecm ћ5az9y}vgAU+ y&Iq΢]|{N|,Z1Ȕ;nU=}N^Yې:o߱Re^zUW'd3euL ϻSN Sh˺ҟ ~֫7DOeޞ9؝ THw!φ-UzE'llJjRֲTgkI3i1X+QEJbδ$[*ͣ8.EAe*kW϶^9Tltoe먅=c]Q)=?m_S[DU m!]AdKTbƆ_bϘcbb’]N+h;PWסx/ C>`a&Y77j"-G?M@L}rK_T$Qס Pn?ja< Ǡ̶U^ʢIڞ'_;Xa_mJ*=}gnٝMg㕽/7O}}xͷs~sjx!hhW~>Ÿ/qfθ/3~hN=&gԋ S,Žꟈ3U^}"| d?볆gޮ7ΒG)U W|y{kRlq.{^+0]%yJ8m}---w_~'gduߏ~,{tHTdЯ˓=-:{tVY,I'R{uZ"Ϫuϧ6T&ei9货g1z)G}~80jԨwsOyrȐ!B)gѽ޳,4R sh=5/VC/zٻCzOv ݧ,s[I:Mhnn{ᢪ~~ɜGڣ,P1bGKcZC_of}[z Pݨ:wsJmΜ9LM$SʣAɓoמf6lu9&v# YΏC jJg^i`r5׬[9}[(5Mwq shΣoth`YK B'X}O;ܶĉR">>w6@ R"hv-_yjz݆ o=[5qםw|MS\j";y)ez4vʰ嗷z^}]FA%w_3g\yѧnk3nw~DۅTT^X:8\=EDM|kd1?;RɓWM0AkkE8ы\x 7nކIC܇;Ex뭷: <􈛘(ze^&.&.~N͔B 1*@1BMzu l:&$ѫ8iwFZZqtU~d+@0).zLKG]yHRR^G]~yw\'?|.5tXG 0.q(-{m 'Tno< EuH!,@ק[_<]"喯}A.;ʿBӾ_0?P?dŞ='}p2p5O>-̙3@/9t GKLY!o}3s)!-h{^10Cm"wby@3qf飏?r  =qaÄ$83kڏWY}vy N>}-}99S&g7 DM\xᅢn=w͜1C}.ȣХ ?SD|7OOnѵվٶ4[^W܏ɼ%ߔ]g}ғ(kajbQpr~ɚWdkQԔ~(/^D4Sl!vJ䰮e3I띚K](4t# A Gvm^hx1Ct!#sֽ+RJ\"TbSjy_$d-/?(Wm%:&u҄5;k)4Z0.U*pԙݹ&+Avi&Θy֦4ש{ÏɃV6hJkTf.ɦ6l[Xyʚ-mJ{mU{K/$(NEuV{}TZjeTT68o;콡lΘq[hΒP7BD7wk(۠|ba)\^`ҫS ; Wo*;ԼRfs=!ka:deYԘe/)6$G`!R%lWBߏvywc~Qhm[׺Fl4-^d#\cT@D*v-%'[ʉ#v$E&D~jE6kgZ,r)Xm^\۾lCmR|y]kKwm((O wTJ;=3dJjWQiD|)4[Yj#}OvqnQWӆtz}jv~jwÜ,tS0pMi;Y̅Vw\X-_E[Wi "ռvc-g,=̫qؕ:%/ߎЛr/]NaW"`[~ qe/ͫϙ6!Q:1 ՖIKlPh+a&妊M_)lJo.NUnxTn1e%Gv$=$&'4AH䴘#-޼HkXra:ߏAK.u-_3?+%ݘO$@TDu EjsKJsvBU8do' !ݨV?SVe8A/7WuY%^[_;n.9MfQwX-'k.V;⓳ Jzu+kܲf~ Vp=bVp`E*̲jTo33w QLQo-(P{|ϗ:c5%E/}`D9>1 {1(M|}K7 JMj盛RMBY]kJ*+;"Ҷ,ǐ]lwQTVhJ)$--2R"RN(u旺k WrTϜ;sfܹpsΜ{r pƍ~ծgNw:vRAy˺g|c? [jۤVf/<"Qcg ]`dQEݖuK/?eGG3u%ydݖM=k-~KZ 5bS.utaE^Xv,ٸʹ=ڏ]\snv&մjz`4NccU_^۷-X2 (C@UYa+Z.9EˊsBWtF/WV~W*) W 4LGCTtbm@]-$`A `A `A `A `A `A `A `A `A ``A `A `A `A `A `A `A `A `A 2>KWZϽaƍKt;裏Οiӊ ޕ~dݹW :4]6`dd~~tkEG߇>_1vClrʩYtt|kQG5cK6mպ_7'FMw3@ʰmgaIv2ќ+ҍC&=4(d%~Z!qfݗ}g_Em۶}yw}7},Zy睿>~/ǏGߠAי|\:/SZ=IrECq6lؿq @F;Ϝsq 2>x0.v}訮,o~|o曝Ԝ<)I-O{'UVYeUV!}K/왯瞨PSvƍzhL&kƅO[e:IDAT|]__#@o[<_?{qϛ0|COG?ǣa=]Ss })z744ąxWgg:_m/V/ѢozjРA'円?/e Xwd\xM]\ o9{ȑFMw72dșg3#s{ˣw_A=4ƑǷ~ꤩ:(^t9gmx`T޾}cC 6,.l_ЗTw҆}}xX(xo*\ouO[c߿:4O: ׎0x?xXw'Nn=Һct7M4e-虮E.9߾bN~^Qwln{ѐ7AeG;{c2 mj'ȇ-q|>}/R5nbsMm؋>S[y+W\**L)(䔂n z?_iĽg Fj¦MMd=W貼nÞ^xW>jbG;wG{o/{W^1g׈\ c@?lS`8C³=1@ '`Dž_|7 @Ɍаxɒ|g??yi{:zDMǏ߿ _*/s1ڭ6 ;rac~#*+7ݼ72 _≸O?%++jGqxĪ/[T͙yC/ ˚ifdkwsa]u aȄ ]ܭ>IY; RkD8?;$ߺگ|-8Ĩx\ާx[:?_Ln_?I[uתfƿ5k^ {EMYKLJ^wPqkB澱׬ g-=A}}}ԓs?l۶-G;=p{}aIL(^!%%qpnh5~C< N/ ^=V\j>ӆsmR|Mvn:aBj`6o׶_/^X}c~pmq/۷tyֿ/]qK ޑ={GKN:ZdJAA|vu>IUO(M)CK J'G-Q<мxHQZ* ׬^~U!qyd²yYmֶc~ #vzزUM/qDaaCUKǯsx•]䬗V;5g.^}s_(W>Yy[N]wwӄ·}l:dF M\;~Ohu46/5Us6[N2Vמ:Sfm-ZZ6oUK ),>jYz(ZH!਻ꫣڝ5~Î>6ܝ*|vi[o=Br;[黿{7@7emvd6&ۥ3ѿSfuj†T+AՍQsIJڹ҃N_vpAcEUZ]zD˽z5פfEqnuS _hnHOPBYQO֤1RrVWziAa7 ?Kϊ^znS#gW*mZ5!C̺eS1#f]nhoSjg%IOqD\5%% MW\4l͟zeᐰjnUH /( UsmS+%mYӑ~߇ԣNGA[QTުuUkq(-{oQ~>8WOtWݵͧ[i蔣 999e鑖R Lgݭb͚ˮN7 ꮖf]SO׎^2$5wPyV#INҐӝE[I] {b,:IoJ:9t(:p޹_XQYOnj|iXuŝvY)m댾566w-wIkz[벢SN J=?{}qʇ' k*n kμ8j=~m]wL{stzچgYnGf͂!o7lު;,43u (:qG~r̿yۿ}arD!#kN"G{;މ<|{΍Nu~>lt]K ]: jH5?cHqA피rSnmwcV,x/X?;_aieU72eys[ #[f(O8ym*u۩ˏ _ ˦raE[`>n{ZZRZzü g|Gւx{hwx|?ݐݥ~ Q{фC;gu,]8aa/oK;XՅ/c/uH_T5>cDKYqkJVDk:vjX?S;+jmMo@*,lY[aS_7姗MhyS>3'Oʏ hww͗. LCyh|# ՗}Mnv7޸Ը_ί.n֬l@@ݤ6Xy}mT-^9/N ӽ}Ko?mg]5+__hM*hQꕏ?n3?:/Z#;hߕ];^x../U ]|_ Æ ;7]ӳg-wɟ9m wk=t _:ܿOB p/鸕3-ݏӷQD?4iNЇ {W 5{{E~WAt_'*Ԭݸq㡇zI߭8e\_ Lpڵk'>`De˖tMiSntމ' tP1`JCCC\MIDAT 4hRĸ]+w=Q=BݮN[Wv~]7Jc$BqcםTsL7DMk:w~x5a„xͿ߸1^T'pB)񗽨ݹ{Aowqg_8o?Q᷿qL?#92vX\h_Ņú'S G@C_9C³= ̳ƅQW[AwG;>Go9{+o?+*|+0d͛7v?Y?jΩ'[@8)?tG}}?l|h߷4"-W8qa{[2o9.|<=~^>=83967ժʫ~G--qZDžoycGo wϿƸ}W;(>%'N*Z||-8Ĩs.f_;G; 4)_ȟ\5[lL-|O G˂>Џ~A%SOm۶{^>޿ {8֮_?SM;q'~?y嗫|pE YYY o+Cf?ඊxn}nVTtC7حw:#]<2;W_ @~㭷:~ӟ4=j^jU<~ ;i}ԨCZEBW}(8]?DžW_SdKowd3N_恑#G9$Fo>GO;{]v6pS̠Ak'O@JiVo8E|#.?zх5c/؇G;7p@~_㷣4 4N q'?S  L4hРC;&@۶mۿ/GޟoPA:蠃>}RQ99#F7@_{_ʿXu۶8 #W$`Omݺ7^ohgoh=3'gtk=4ZweXܨs[^xᾥw*UVYeU޵ix~g;Jɔܬ,^G}3| x>0_7in*t]ch|{3| ?#8c3d 0k=4[ &0 0 0 0 0 0 0 0` @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @" Emy~VVV~E]4*KK*^ua~6jS'*GVymYʊ'O/ zѝ !4ܹ*+=9Ձ[YuH m`;Zm3}2dnʨ3#h3VvvNKy̸Q1(Ev 9zֺܑM׺-,oVZlfv3Vݼq3+veòs ߥra^#+.l_']\^ݦ{kmq-=t}Kjk˶elwv?6dN=9sQuEIaΰ/YTEs-3N? \9rXԴK|tI?z'ؒvg̒K]v+ְ\0sw3Wݼaǯ-=K'̬l^<ؓξ=в![SRd?%LG__jVoqn e:v@w ۰;c{tmyRBzu[R}n%S3aRa<\rvh XtlhZ`;.jmV]uݍ̟:"5mN*l=se[[ȶ86-K^\/5+ֽ^y%wZyÝ3n;JX~y}땏Bc[ڜSȞY2oŌ;1!ۮp-1L+Y6)43nN_~ʨPg81Q[ܬe-n[=gNp*XE-a茥uUr+62z'\Z*Ѷr=uUem(YTߴ?hصnvaYUu\7\T#޺>^6w΢K7y'ęjQYQn[RQ>5U\Y]DZUkٍ%uu/f7h*In1_TU+9Z`{tX^^81s%Ndk}UEIa1RcC\43%=ߏ]#Zmnhx;o̓}ƕ˝`@ tnYu+&;ޝ'sqiQE{c777G$;h/7nR0Г.;J]993.Yϟ:fNs=i9; ` tAt rrǥjwMՕu9;zhvZ^`hnnvrա3g6-.>GSYw)yi -m|SrUnu3 X>"'KQi|5hSeiCˆJw,iYYYz7ڲ'8)cOT?DrI'PO+:}!WG1|$x6GlH۶mcgo3> BVccc3zcsLK>|>oHlyW'쁁zt5qy1Ip@HRM6mذ!{hPX>񉏏>pӧ&-6mow u+{,<@+_O kyvWH~]>c>40>=m۶|@:vG?ӦT^|wk1GsO/,m=( f_|wUCf8C xߗս!2A?U=~\9uϸ3ρc$8]ۦZ8GlrʩYtt|kQGu>4dٴi7.`Eee4%:0;љg7tT|kjjnܸ1;JYvm\'>;2W^1Wi=?˖-Q隚=4twԮ$I8!.LgРA'円?}[dnKs~W_ ?n\WM0=R~ 4K~w Ѱz2\rժ0S 5uF,B[W>!C:!Wvq?~շw4~_^xc2J?QRq|9F k{Eg ٣C >\w\#O8@ok_z7>аxɒ|g?m7]YnH{J6mş?@(7ݼ0p{?Xw޹[?-YYYa_Xxd^ޑ CZuY~VeȵϬ {sgm'F/{c燅ӳ_۝%zo[5gu>3p.~tSEn_?IV^57htPT/zwm۶:л;R2> %̓>Q;sC/0a`„C&L*6۷tyֿ/]l3o׶/^X};?mxjYzZNkziG~iVnh_.s$7~B(LU4.h\:z\spՔƳ^ZxH*^ZPJEQRu5DK^Y8$l[n\PF nnlXz͗4ZPc-YQ78 ƳFޱU鋄&jMqzVgǗgGx++W7M/@a pԜ?{YK YskX&^S;X_D!>dDkV56oUKoϫ}a*n RYΪXxfMXZsܼV_YSӺἥm)SC՜>JZ8tjB ;5>wTjMmVA*Jy۶z2D7_ߴĖ DoGկֽM>}(t7o^y_XZt!״w]|Ua/[؍W^1W {]GpN٦s.&ct/ )fN-6=_N7$FɳZ:No_6;ohWO=1?_頬:j /5kI.rĶ/`_w] 9s\5v(TW#]WgG-C];=j͞+oTsQ[qlg]zzYr!#ȊNڦw;o yosV5vQs}k_/k~srFg>} @ׯ>K_zW ?}1j . \)}+ݽ?HΏZGӗfE䥯m5TvᄅyYtWPOϛR}[SS+N= SSs[Fɳ4 SݑSݘKC9䯢¶m:b 'fg>ڵO^ښr/|uT9P8jsGBcc?_y.@+<3$π o>xaq׿qk\ Iu?Ob믿H3Vlذ_.po~|tAc^e-j.r* /ܷ*-V9s+?S|o6Z#C )>;|k=14v`<6ɬױ,3r_o۶-lQGD[|T2{ރ:#967w^5*kvo933}#Foޜ7bĈox1'ZHDH=󕫦6=T><P:IDAT}L  ;>ѝ2 'N@ytEkgA:}~0xY}7o_oh``xɽ W}[Z Jl=Rhn \:˪W:ì,?+/̚f\64//+/oe5t g_:~m٪ϝ_rj[s ~O.="Tvd]xdEWǏWc˖-ߞOATFǹv)':mډ'O? =ӟ,~#*L)(XJw~jyqʈZ_XI3g/=!ڄwj=%^SjnVܹ=#ځx]?}=0@edÇ/axbKŻpNҸ5٭^vpisQU/LʦVvUY+ _zCҡ4^*NzqA~)ZzZ.T^Yܦ늛_}{ܪ0Tͽ68}ϫ>uRa`NoWrK_2Ѫn6٫)fvUpY5"+bGWjW5mޯU Pʚ(ܴ*մ\[4;߸M.:6 _8/q.Sp,j %#|iM{dHnaKy|Pr]:KC WVX܂ov/O)(|pyX@PłW}GYGbHԣ;7N-?ȅ:[olL@Ao)?O:ᶪ:z'4UsUo'*qփ`5w-1lUj/ռl`Tjѫ*Ԝ?{UW`ۍw~-/jSPWhـޑ qs׏7=|]?0XݸzNziA~Qݪի dm5Dո:NQƦfl(^^m*lGi没y YPP7*="ڀ(fpe:$gU:00ped p_%/^roxڄ sN {qo @@C;FU<ڦ5gG͂!~qˮoQłe&nL0dv 0NeCg\UMKEN^ yG/!R*٭JM|i3wL1=Xݸpz켬^zV_7-TViUeT׶ s0J*3퍑7>/uv'ڱԘX;FoL$0\7Iӳ*m`h֮O `:DHW̉`HDHDGNrժ VtM/^}Mvnڲe˷~`jStذ*#ot [~“N6ɓ'O`Æ Obc?ʨ2~@8~ӟO\"zD)+W ̫ؑYK7=izޔT/JOl쪷kW`ۍ۬gH5Vmo;NX<{*#@>y$O:f6^zf}͚۫7MP1xŕSQU\Ϙ+ DKͭ V7.( Us $MyէN* \W.r={@Blᆐ}YMgQp„C R55QM7~Jy-mQT$Ftmp޹_<]n %#0 :أVYHkV/*,Հs!m6V80 C >\39677*_*rccc%T=Z[%_Z`ɤ/F*=,b]|½?x*&_Z0Ќq#]e˖oNWȑ#e(<{8֮_?SM;q'kDy+/^Z=y 5o'6l/V?-~ |sO?}pŊ+W ά(jQXPUvjJ5_vn/5Gkͭ߱Y gUWdU C WVXV]?j{`DIDAT/^GW߯U˶cvUUғK7MϛRw{_没S{&En{u_ )`tx{>;Z~6vU.v@x=wS' >|~ Y/-(цUgW7^}Mv% 6T4mbW W6Of-o\xH:FsD骦Tc7V7'zlv5ͯvUŲڼa܅-ڿ:==+xmk~5doݕm5WMɛ~msh̊tTG'T|M{iZ$P^579 Ck;|VǯR{azV7JcsgU/-~/xɽtE sڪtתTpKh,ݷ PxFظzi݇Wu5Tmgoݦa;5iZR»wWtKڹUoGܴ{*n_א]܀<…SRi;77t*- Qt+&nO@UkᆨI9_uM5D/w?@8|AI Vt=ݺ'm+Q[tge۝UgG߻ MqKu{޹~_,;nr'LL'm{\lH7ݿV[R;*TuV+X)fWޔ]MQ/  6B{H 0 0 0 0 0 0 0 0 0` @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ _ԖgeeWԅL$;++rku[aʪ6zʊ'O/ zѝ !4ܹ*+=9N.6 UyVM=׍\W]5tfdmi))`kFl)dgz E{r4G)6wL{ߘQOO^Q'[ܬͬ ^vKl {tcY.Wr5v 0$N 7('W ~nj \g]s˪a~9f 'WkSsj;(9 ] ')n, !Dp~nSeIvVVְ@u# Qs{K;۞,_V766֗ӧNS1s#7. !D7`w;,zƽG_R诲 t@0 0 0 0 0 0 0 0 0 0 0a~́~Ј0h `A `A `A `A `A `A `A `A `!}tU>K6lܸ1Wv>v'xߞػ۝C/~1>|4>;e 'F}Ŝ~{wOVtߠA.׾;=tW  osb˖-zښ5OOyй;fܘÏ><'7'Wuu~k~Ʀ7≟\>00dX3^QY?W0n޽>97_uUkWvK++++t uBF{Z̯\rafHfڌ>c;^~|c|A2,xw=_?|Q9UgX/PW/eR^qᓧ3ҏw^3~lXvYjz݅꣎=ം#׮m8Iui1իOMs9#<\F/fյ^V7eFFj}$pCCC\8~RͶg]fyA#acR?zMo4$A5wJAUB>6caڨՄ³|ǯ+]sq:v±q~OvHqA3S~rXrN-û! =5t^X=ժ/tW1św6u7霜1Ї]{G?Qtkِs} Q>1+V_WST#n{srԮ>gw+KCmMm\5jf}.Y-rH\_P4}˺>w ݰ)fg L Ǐ {G,铿:pw7nV}VywoCKp I?Կz&N;;'obMj}e=?^g})ɟ̱MlrƕY`ͧgjnZ.T{w|~ވc9ӟT/eu#zcs.ԃA"+W*:uz\ಐx?p}}4" v)_ŷ,G?տ nI]ҳ @dX plJIO?])ƞ8v䱡Zj3=-5 u+]Ѓ}y??ϟGiN9뢰®0zx?Wi\ҋ. ``y뭷/7zUIDATaPW+֕fׅUW76@r;u*~25׋osoKV IΞlkM֔~]w}j%W/}4 fܒysAe..ti5usU-^vŌtJݼdfKwE>oHuUY!ò ˪9Ι}=uMxESo]W/;g%BZZ&ϘW֦7򰦆ܵuuGWܟ. hѼqm,S]_Ѹvy #g_>zW='޺hN}s5-u_ZWU^nܮ*~pX[7mPsںՋ wYUnaNSꪫ.}Cw]#^_]7f.}eH ©qa;4/VL3yʈQcθdҚ[oZniUGn=QC[:jԨ+ʭ<4;ZvhT;dL1n˺2vԈSGGmTPLuG]>+jɻ srumEQizWc`ξFbYo/ڋz $I 7$0 0 0 0 0 0 0 0 0 =2`A `A `A `A `A `A `A `A `A 2>KWZϽaƍC9蠃>xaG}tOLVtlnnd566;76_b}0P <νjС~Јiz?yqW.z~tkEG>|莱c=󕫢V0S 5+` ~>#›oܮزe)fӃFte7 Mo<_\bղWLyfG ץO4\yŜ]O4t>+` e5Q\? Z︂qw]D3*7o۲-w/<#&L8!r3>sʅ~wrVYw>uyT޶mۗgL {q ~c7€}!ʇ^~0t\?hP5_wщN,^ݹ_x7q1Ӻ+<R2g>~lA#@y뭷/7z!(HDHDHDHDHDHDHDHDjll 0i `A `A `A `A `A `A `A `A `A `A `A `A `aPe02@D˶666? @"txEe͗W4gYYe,PZ ²Eک~meŜѪ[֝527v;]f[^V״lvqyjllF<ǝ}CG]^S?o\\5mIFXQhdI%YrnGoky>tԨkIDATаm/a-*gw)ٸ1eGO\E'^TKCCؼdZm+S.׶4yO^Z͊.3n|amMw􆭻>5yYjN!ݰZ[YV=,=uXvaYզ8qF8'{FLc]ƕJ_H%UQݺr^ɸÚ=⢡⣕knzYtI"SK\Yq[Ev+-jUT˂EsJL/.^vnNgmmG4wXƪvtj&رڙ/*znk9EZ52x^Ksu}袮)7''MΓ7<ZWUbX;99x-m%pv̉ {MU9YYu*oH߉_]T;umu7_z[`eV\>:məEs*k75_uSm圢ܓRMOVՆY[UUyUevgC^iwI^b]63~qg.i\Ogc9ٓnh3}5sƅM%].~^~;Ij=vWadaEݖu+?ų;&5fּ%ӞxhdѢV̟1eCH 2 @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"tzcs 4" ZHDHDHDHDHDHDHDHDHD|߿/]jճ>҆ 7n avᇏ{|'gvgп=_̾?2͇>Yx C?6`Ņo_1sߞӭm|7hРKν=yO>00~>#›oܮزe)fӃFte7 U]m݆n_x'>zOw 0WTVOw#=8d WsUk㧧z{ 'tݠQ;3\Y7}Dv36#~.X&;}_~9*;;sР -}sO8:*uT3OUgX/PW/eR^qᓧtX䦻voaeˎ: r[dR^i&;7ovݢ~c̋7٥8o^OV8WoOi~kL qIa9BsXۉ生n#yh8ʱ<ՍScn>CW8~rihC/ }en͝RPrժЩMX؝ѡzEO߷电 9gE_W4Ω]}N˳܏7/nrQ ƅ=!jB[F2mW~ҐapZKQ7F,7l谡b3j|s;B8g~ɷ4wNNؓW`_.н~sڣǨg~}cBOˮfzi7=oN)7՟9|sɡƅQFoևn}|!ą_u5:<|~e;7G͹ߺk])fg L Ǐ {;QW?~eHW㳟 L '3Faʦ+g\z,v6.w}w缱鍨ORVG176L=+rժS_y. ӽqWNקzA#aARPJ\^|ZQ~.{i%=KtKǦ5-O?O2ncN>3W._21Qo)-]9=E=ӟ,~y攓O. {`/j[O >x*Џi zk{cmz{ߔ30 C&Lf` 0 0C0 0 0 0 0 0 0 0 Y:-$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ @"$ iVdgeeTn },zuٴ3+wW"?_^aZݯ>U({ p;BhsQuU<x.$A5-/˶FŌ@={5J]u ytdnܴvQT5yfWv/+Q?|Y̑|[-U(]eڒiY;ɯÍ7]-,&k++̌g˶i٢^ʼӵ鋏Vl~՛,P Ѧ t}KiɶˤNNӦ ˉ6n) W4gY^lf뫱g.Ǝ*ֵ[*KvPߵrw{?9~ꊒ1{\I13w:x@d566?'9g߿e_,wƝ}C{GrGUeIaS4eڝO-ryMqͫ^TsCm[_.l*wm/BmYNʒiwv0oumv{~Qaw>bƊE#(:ΟqqQ; ~OudÎmra:Fq(tw撆ݬi;|Mvk‘m6[i'ַk_:q p ׿:um󖍏\>6̥EsZ!\Ц(3RUnS fۡ..؋VīNۻ60NڦmLl~G2qu+.zǸ©=;j^i^ O^ZM^ӵ-;[S 15iOM޼- T^!_ܲ([ߝLy̟:4JA ʙ4;jV3FE?;7r5vhAm~cǵ;MUݍ̟:"5mN*l3vww{?ym?qghg7FGqr6:VFU$wd* .wu˖DK/x4]}yMݢt62x3ҙcsZ\_/="h\8uV8??07L77f휙mnzeqܢudž^]Rek+4^hhhݭ`[W7-w΢K38;MQy;g\YyY:ݿǷIYNyׯ[T2iJƟ%ťv>垺>g.-iJְMIDATsf65t]XVU>vsǻvcnɼ9z7nZ\Qږnzxlj#\iBӅ-jddQE)[ťa#,yə5,;;pfYʵ[ wٹnnLuEyy;w-[|Wss?kk:6uU-;#݈[Uwo(Ӷx_ =) bg:F-^Nۖ/%Ou]>yu]yoh{}um@v{?t_O @疭}O;jp淺sin*Ks?zͨJ:KnvdNN\k/ Nݩ}v Rݮk.)W2rmU7POi9COtocsҕjۻ tkuG7-^:5Q`_w%I(7?m][cweW-KPCssCN~~)3!Á3ΉP_񸶪*=k8$/0KUZr踢yO)bۦ]F}m̰unz.W[~CaTm'!5Q`_w;l4U}(gfYzv?xM-KK*wu#>G?KJFtTwg:$}W2֦eww;(z\zl~YenڪeEFnɎA}?{eYZydrTAetTF`Lq 2+k&yrP_d UPIivZB8ehG"eڐj{{1llcc{v߯uy~=}T'Mߘ_ܼwkʋ4|?#?gK얔,hzHx{muՒG1 (fT4[?YX Y/bM+Jr3.37֖6_pyeg<Mc7̞i{MՂY#^]0j~FڼhrҪTe}hQ}A6;ic)/-.˪%:tBf6jX.3?;u@gdyKMԬ!*Y57{Nq}4?3 ;76 [^1yQ{aylV7ۦ!>Z377tDmĢԡk|hQ[{i՚ ԔѽϾgcy.Ar{VOkU֔d~*UgMS9%-Fa%^#F\ʒԖ6TnŠmH;oZv/qrOO@t X +j6bTC u޾tm- JvUY Y|;x_>45;s+_:?9]Gq՝~yӈO/N#_<}?PZ]uƈe%56n)Xﴆ};[G[.P_~ۚohzsbACRyOKm'M3 ci~A =)WiO_ٱD@ ] 0t%CS7hrFJ}T pԖ%kB߷$w@?=|Բ=I;pT.h̯;{U>f_i;!c+ }]V~|͐g짩( (DA 0Q @` (DA 0Q @` V-t @` (DA 0Q @` (DA 0Q @` (DA 0Q @סuӆGCo>@JËk igVWrB:}6aK_PBx1Sna~~I [8jw}CGHioҸgr gp])?Nrm}$'GHjA~g'9&c.2)|?/MS?imoË?Sm8³/GHv7>KNo=z7nz_Y}M>Ծ.K>^>go|-q׳.8ړREYx翄W6;cIE{48'Oܢ;bMe8v|ԯ~~fXOxWi kOQS'Ӵ5)%USfzW6V6]4 /i{֝K5'N9g؎fxoj=~4GO 7vr̈'n :I&J}M?;tW6g< k' agccC*n뻧|sֆz:~ʹ;b}ygIMG%b?i?_Ǎm6| >tpSL}'~?JK{Yhmeԗ؛=nغesH?{ ;3{3tL Gkox: ]B'_M /|^R>tt{?5Ssm3oꛇ];q~t] k[ \v;'{ⶏ?q{Fp8HGcsof222?$<0{!q_ח^z9YпOV`g=t'As~s@z}@HG0&(E?#<6TWo]csرc8̼3Byסz~6"*eh}I';q/g._?ӷoffff`B'@/ xT ;m^y孷֍OS_oأǾ-_㒋ݶmm23@u Mu}N[y%ƿ, teޝ͋]ǣ?ecn߶~<>]o缲ne^flT}`>w (f!G{ܓrO ޱM~ٓO_d7KKLCu~_4yǃuPj+sn @Op hSÏ<<_7?=^t{7]7Rx^<5נ :c}Q>{lλ伤4׿.-0 >;6#sl;wN#w3ν#=w\1}>bvi%/}'iUUUF΄`l廋 cwj:>fU5\6j/(Ɛ>0aշzspH}<oڴ)8ԓsV0Ĭ=n+ma3Ь mNа'o|MX[W {֚'i׭\'C_sg ݲ"pӍ%I&;u ˖ﹳlVV1GȲe7pCGu٭bCa̼]W {5rTQ-֮ϪV]Ҋޙ7>uǹ5 k ?t_SSyB|5cK-ko9wĆG'\qS4,r( 'ӹ5/OX~]_v\枯=)b_\;TT4@Ӆ7|^Bv\{෇4_K έݛ:˅ԕ6_=v-e4j;ch܉B*mYyF̛WZrhn t'_Su;v2UVxf?F͕+ T\g} [KB޲+%Ѵie]nݚ^RRlY"KœSW^b_ih:tSwR&/iu\SԦL}4n2J_kYucs?T;yUx`rU*Jמ Nk>x 7O.u̽BT"^V =dc04pXXV^X_nG.=n;6 -Z8o:裎JnZess땝 Mǹ{G'S~床m*?~o-ዟlq8(t _Wj̢v78jر_322n{qޏ/ߝ}޼[W+eI| 80t -BoSe_@h_pVrѤ[tMz> .Їz%3.NIGPj8zAɤc^yuvTз~'`+_Ϳ}8xػߝ4o?Ꮱs`W^/>8m>㘱 mŽ\ÄF5_Hu2}`>{isaw|[$y#?vNf?On[7ؓ{߽c`=ZW]ufF7X<{VqC}7Ɩ-[::ܛ$/񦹩}222\믧I*цoph_hK%Fǿo{cnj/Y643CǽZ{w_ݍT: uQj:eҤ|[6_?Gp.WܷD=h>@3ޑ=g +aMG|M Nw;wGf8C~~}qGwh>@(OD*~׏Vvjnv>@dyѭ[6^__Wk#kj @zMh gK7mz娿'$334?־k~ O=JSG+K&{gfe}_6/~C wN bĈFf}E~/h7/+~`SsϾjkkXc]gz׻8zqރ`# #u (DA 0Q @` (DA 0Q @`QWWS 0Q @` (DA 0Q @` (DA 0Q @` (DA B|Ks3222gb_^^\X{Sْ5Xt$*YU;)?zniuV5 nXf}cXQQn32*CھfAA΀zSK*UMp%աU7%աUPXC١kT.X)(/\PL瀑,Zæ\}jVkt t'ڲCaД;o۶q駇 oe+232/nʿ۫ \VI[`Cc\ y(IR.-5 %ӓ{U0@eMɯ~ڸn3G7m_TVYJ64 De/ Oq}s$ڹB?% Wݷה-J;'6@o.ЃsTo߶q[uTLMJjWgPU_us rɱedtom₼y j G?IDATA%X^66~uCZt.|v7/б#LiUț{/ 1 5 .U}cЧoiD}c%!m' >Uꊲ¹ 5?* 겒[^ZX1ϭ !F)qG+BN|nOjE-1@ǵ'g aU她Rvł9!-W 2gTW ^R?smxSWz:$q12Y\pjTU$'?}Af¯ʫs`n+GFN[i6rƅhF>ԲӤ9@/ҧp~%T?ґ3{O6QKղ:/jrK?eXÌGM4|g{-. 싾K~@^:+p\k\Ԭ%r^|y{θfz}]_DA 0Q @` (DA 0Q @` (DA 0QBx́_<+{ث]zN<~?䧟~lѽNx_+WJFFF+ Ǝ-XH΄WLOw_S^򓟤̇Kk]1;cV^V}-°ܬ;v[=T 0U/+^}@OH'SخӺ+ﴲzmxy a犆W\\YpAwg {7!Ǐ:>4t^Ԫ@OHR1ݔϮ;oCM/N+yy=Vva/ذ'ƍЍ 5Oۡ'LX|yhQÏ ?g0vCaқr-a3X9̜5N0i9+)sl};o{tC Z?'yѕU~ne]gow|}L\`C vתyk͜۲sHW?6EWe~@ߨ}es=nm۱ÏHϯ~Q'ZxeQClʝ|wCa̼+Gl^ϞUYŭmmT>#R竞]b0䂡[]8tf@OHmcf\SDi6);fL'SrSz՚WCWEaXa^߬ ˨9K5)Ct :kdvvҨ}vuuu{yye[b/͆0s c5L)ܶT+;9.9zMO=-E\kZy|ʕe][ cڪJ3Θ:@Ii&Npg/Kn-;?l߶z؋69YU#IyzVٻU?{_^CwәywCK @ֆںesn7^=VSw_:B/vA i[n-[to{y?zaMG>v῝|IHwf @$o,(DA 0Q @` (DA 0Q @` } 0Q @` (DA 0Q @` (DA 0Q @` (DA 0QB[)-zM./},Xɒ]#(Sԁ\]Y) @` NMLث6^{-Wgϭ QuIvF h#7NL7kTTYލ+ л:G41}ՕE١7*ZS׶@, @` ~5+7HkH~nVґ pnIM]I4 4QB^Y_㊦fjuuu:] @` (DA 0Q @` (DA 0Q @` (Du@8(D@(DA 0Q @` (DA 0Q @` (D!߷l~_ܸqcQC;'uuu{ܰuл=~wօ^]z |MsS/*vz뭷y{ik'{7|9jɡY<)q'&>qB Djڎnmm۶s|/9#~TVvVQ[jͺ k7T,Xvw}ᇦN `N_ f*momD=]|Is͙3޹yx4R3S.7sޛLOscƼ/CûYZ^j\YpDz;zOŴi _x%7|㟼4s)+7#nj9fݎ;\jnݺ@I^z)iE7E'_>{l/nqιT[NSgwQÏj{cf4h{ϐ}ⰵn+bvFg~Tcժ ZRN=]/1u+WnY|nzxCEs#9?qx~jժ@OHiӦTS;?n{ZƴwZ7~̎۫_~NjoJ't4HSvh -_t>5IŊi#[bNŝ2r~qkێ~+Cx~':C Y,ѐG!M#qf BXR[KtƦϳgaVqk[h[:u>#R竞!Ia%]?%Uu!NxTc~mM1M/6_=v̘@OH<5Ω n}nRx薒,oRrʐ!*=#]_}vuuu{yye[СnCzoŨZyk?H@IQ8sS+;c=$8a,.gC}[?Ec/dqAη='{Ӝ_?SOJ[)s&:mԨBygV=~$i7/@<{jۿ|gc?b6+r!:3/tVRN}hI[hPR[lm߼替믇jnKw\8(D pb֭eM~~k'9.O>)z0;D  (DA 0Q @` (DA 0Q @`QWWS 0Q @` (DA 0Q @` (DA 0Q @` (DA 0QSm̌CYS[ZxH۫=* n auV>zdIuw5eS066\):k>-\fkTT_iՒ%'Wܢ%iXox %}µ!g_0#+AirK7o|؃glϕݣx{wzR+F\|sjʋr%tpʚ?>:T6 k&03vJnѮ\l}Go<#߶fͻffKfa/W+ -*;/Z`}G>Gkjfo#pC;:?Ǻ$f+|kShMWu\{3cmk 5Y,[ғ N8C[Cz\w:8۶m;#Ko?yi`O)+7#nj9f N<קڿ[w0t K|饗FoZtS~iV>M>휋IvN=j~G ?*tc+fg]D}'~TcժHCt UUUI?q*V ,MROmEڱw@}6cխQ>{li%]n:~:mTi+u4HSvh -_t%ʇf_04$^Xガ˟kϻW'{tqѾ9g=vyˆ?]K9f?4( 2i_>&n껧;oC}kҭusƧV&bwg7omñjhEiߺl|'=u.>=?}+f_S6ʺ9vDNr[+.j{Z+3j#Vtclǭm;vIϟ0="+;v켖15ءYyA*wKss+;-8TT֒%#nl<{Vf }S#h UT nxxG p8%mbp[ٹwo{xFfiѣsR$csVuR0/_G_jÆh{$&7yF >IIMOQǎY:)}0x^y}/jkucmѷ:tߛT2d 0)O:묑Ig<W]yE`78j?ST}l|^i37R{UkgMsygLr^`7'Lⳗe]lmohk};I<9~ѧZ?S.:LuڨQGԼPL3Y?oy5]g6lӃ~ZLr`"v!û̼YIi=O4: -d6-Cv7o毽!nSw_:B/vAGqNlݺlѽϯWyaMG>v῝|It!=.N @` (DA 0Q @` (DA 0QȨ ש(DA 0Q @` (DA 0Q'KhIDAT @` (DA 0Q @` ( 驶|FfFFՔ$N>u@ߐQWWPyAEKC*1yac;7V =]wע\[ fz@vFYCY@M!Y?1 :l//l彻[qVvNSEnև &%%JTW,֦v6}kAECti5gM-?GqESf|zHC>=#/jM /])@DZ:r{ahҚ'de儰G+i`@`=+{h,d=bƞ&A2@Z2VG -e$ΐ 2&/J~O_ZWؚܑW?إե}@K 3@".+p\W AvQe]Q/BvΝQ?U @(!@(DA 0Q @` (DA 0Q @` (DA 0QBx́#Ko?yiS~WnLG9sлwq/>ݺu?Nxi/R?Mn/ Nɧs9@I|H5N?؊cgiCرs.L5VN*8ԓEn͚9OƩZ*)oڴ)8OqY'Hw؉١s7QMzB7NI㊫)sly}[+'?ahhhЬ֎jZQ>{l@@cxkV^ʶusBd Z,~@7jw_y[v_?a {ڥ;* FxxK5n-_:ƦϳgaVqk[h[:U8\Z Т+[> U<3sH'(УGIQz۶[/{6'w97ܛGzjU^N31giFzT 5T>U#IyzVٻU?{_^CwәywCK @ֆںesn7^=VSw_:B/vA i[n-[toæ#N> @$;` 7t @` (DA 0Q @` (DA 0QBF]]]N(DA 0Q @` (DA 0Q @` (DA 0Q @` (DA ڿk͒̌2goou҂-w-3[^S3;T]SB-/Țh.XSBVо puԆ;SΘ~NOǺm3o}MInQWWם9kmg߳`^w_RE! vUܜ@@WW W]]wiWQ \RюS]7-++gkh,*.Y4^{Cqym^]vpVs jk H͋&'1@w{Yzq)V6N=wG~הEs͂ƹ+6N;bn}-nĵ5w]S:q!gzp!1W5kom&Gܚ줼;16u^꒜c~_MԐԎ'7zEXN7lFY9C_Z6}Ўmyy/=do8'o\kmvႫ5nWTY9y e]PZQ3:g7n=co]Fک|ziui~S%vnϻ?5Y]TjȨҴ?s{/~Ϋֿi͠SW80@` (DA 0Q @` (DA 0Q @` (DA 0QBx́@T @` (DA 0Q @` (DA 0Q @>/}˖/g^xō7bСGuԨQ'O8i@QWW [lOxT ;zt^g+x;Bgu&t}~סS?Qѭm۶?pΓO>Z8x\8"gQÏ EUu][jVStPn`4 ٞ?KS9r;#=Ś/^ŪUs>E0###t ЭûiNWܱḶ3s~x`ѽ}ҩo9/R9f+ wO'8A***KLߴVP>{l/K{n|;GZ<ˤSgwQÏjeGlW"_λ7=iL;NG7vl~+Cx~':W_yK}y aҭuޟq&vM/ {N֬Zj 2]:9T>#R竞oϝ6VV?g餆ƈ;)lXdo/iaЛ9$ˤS=:'h_ulEoЕc6j+wϼkvd<} 2uuu{ܰu)ۉ.K?1eϔy^_`U3EbvƕktqQ_՚Wy-I'?^/ϡsKfddUV~x=ʂ;у7ytfrӯZ,O:U~<9祗^J#nj\~zEv.|~IcV?:H[Sxi@J]1;cաg;yəxύxgXW?zt TN?jQu WvKwOvm/ͱ#p΄]#pUUXS'zR{ dRXtKY|nzxh-jUy{S޴iSq'_3,nܙmgi+^mm։&,[YyF̛`Ŝbw#njL5jjj4}nRx薒wjx?[pmn;WOuB; R_7玿 +tšUkR!CkCs`:'*GqD|}ÆҊaNvUce)j/wblwn9yL:)}0x^yu/=Qr>KZjOL:Ig52;;iԾZ;{캺~ Eʎ"ooݒGp??zb-Cs0N X|yM ,ׄ^o?M~q{Y]vk=ٕφL394߫\Y8ebޙO=y31giFU:e/k^Dߤ:K[uz~G''M >@̺okzQw~ӟ 0@֭[ݛzE''L(9 v`` (DA 0Q @` (DA 0Q @2u*DA 0Q @` (DA 0Q @` (DA 0Q @` (DA 0QDM;.N27UߩGU&[&t32322gvE^RX*n atQ,XnЍ2 t;uu]/y8hM]QZ(sgm3[v,ek^^S(/YyE Զ]p'V-(lz@ypfNAI.n./)x9 ddVܱ:zmګ3goUs[ɛԿO"îY߰eɻ~ @ыv,W߸deSS65?rM]=yCξ|FvkJrG^X5onZW/yr{aրy~tտ.~(;,vk[RSfO?ZWW37ֹ5uuҰp=ے]ˍݶjhKGT ;Ka6=xIn 8!re}gލt#毯YC)^sug7dMU7/[\|,z]^WYb X9ygzz[+刼Jθʹy 5Ÿ,_m/+$U4vSSg28{ꂪ/l^TP񒫫74N]fWMkg6̓uqrM˿* t@[83'!l[P\ݰWn=w^۪PSVFO/ot:IDIDATlHa?Z?tIŚ.6'V6Ak2|͆ %%a錼TU4>3ͻ?`~kCP*$7ؼi~3:sJ*ҹn<9YYY'MkVIYuUeC!9!Fj/#ߘU?3H8+7%s[xjrյaMQVYE *6 qsgR`4J@8Iy 7lhiصKo)]zWv!3F*ojAɚ嶗Ϩ7oAS0833;hAakjw/'{3xp@kڱ4(Fє+zmS'ꑹEkښ5e%E9َ5k:꒼ E74<`<(/7kmimiIEMT̢ΏJX{Iɂ5-hIIA΀:@2ܡp_MgےAٸf}ueSZ5K r>hSW}S7ZS+2OƦ6< њkl5l\ؾ4?3gܹbF'"|uIWm}Uea"t5ya+}arMQTq{ ټvh! K+;@7]XQ_|ƈ!;:2dȨ/6nl"NMCFqU1֟S]bAk_5l~};8>}To_>N" 0 @` ݷ)ɭ##2gM7;M TM8+p\f3r<D XDA 0Q @` (DA 0Q @` (n:>*DA 0Q @` (DAYy/PiFjΰ<ÌMgԦ#S㌤؁p0RwZ !UCA:w,=D]ʌ ѭ48[!h AGIqJ(󐓤M$Mڜo"s=9}swQ @` (DA 0Q(w>yq[7r1٧}GqR ?_7*5\8];wJ*+߱r\spM~eԈ{dPPwu]\+~,G'qG Kh (DA '㲊EK:rn^Fŵ3L_q2?bG<ː"ΙUQx}mugpJ՝-Mq{nʷmHoL/WLIܶ8;N ᬺb=YU;3+ca`, _S<*+w&jɒYwǵ״LmBI0%1Սy[nݘ$ƳT݆и'3-9 #LUrC!MlumŲ̔Y`gmC2U% &wST5{O=mi-0j-=ZU9]͇ƼSuڳr_v&6YZqV]KUYXnJ L73Xd^8خ/:[WϬLڒKIkm.[vy2y9X߼bM1Hwܧ/q{@J{YZ?eU3pu(̚uJ蹫9y졝R$ȟ&?-oi֘5H<{(΋gg{;HzKofXc)Epnd0V*mI)ߙơ)<fV'lfg,=G0pt}>`RΠ,2;a\C)o phrtî;WΔ%+W/De&9* qiO_]z0l[#k|Wo*[@X{<2/w뷙s[^ӛ$l8?@wHYp>F[N{áNwt`&ME;x/amV MGn&FlcwkN깤ޛˉôZWܾ5]=fVcs뚢HW%uAGNk[̾v~qvf9q=JHAwMQT s|׮l8}MuEOd)R4w$AVim툎'ƳCOԁ|}{ KѪ8ںWS'g$˖djGrc& YiŒ]>l)f%n0Mv;|7Y|=Sơ|ua3]|>pV& 09 tt93k'r4ӡC 8F*3Q:N(#120fثDtRn1h|\J~׌<*+Ĥ1޹P&?rԈxDzgbsp @;` (DA 0Q @` (DA 0Q @`P`S 0Q @` (DA 0Q @` (DA 0Q @` (DA 0QINiMlcgff[Rڎm ˆ:DME#nX[GԶ" @jzڴ ^p}]3*zv.򾾞);=M5P+i淵ԁ'mnk")- f73Iw ݭ{?ܒysI#)-ݝ/Օ=8`z9lM;nN9u=kt "w5';_ސ sWDb\tmۺ@vM{2JDƖPZT](8*>Л3 ;;#Vݶ|p'LvgN.pCY=32 3(KKKLs0Xm͍;{|cS *sĚ? ݙ p$d~54d5j3 8licw,L;Niuݢע@|F `=ә+WUL\>Mimr5ΤY냆 WˆTw/ aN*)-ě(CYŠ g/J_;nkIDAT% &n? VڅsYz@NzI4U-ߖP'tn,tk'׵WϮVt"M=岛):)ROsmj% F*k-z1/L7+@` (DA 0Q @` (DA 0Q @` (DA 0Q @F /7pN;}n(4*DA 0Q @` (DA 0Q @` (DA vg}B9g{mee)P7쌗^~{k$'|?8{0vPh&?֍'_7޹ctq/hsE&;w%U񤱬*5w,`M~~kwsb߾}]{<_h ? CPY77 )wvvfo>G[g_*[KcȦ/㔬wǻ8ܐdZԹo:w[?8fٓm#K.u.MsTvN:Eo_m1 o;*+wF6ڥWoK7{HWb#xǿUYKeW߾;ǟI?kO/1/]>s6տ[c,6/\n5O[o G*뜊|L?w[Nᖯm:'wߑ -}_n>̔s\=;IXp#;z Uu7>"<V~bgO jwcwB_&Yo[ԛ/&ȉsE?~7q:lA}9 yzWC;n9+ßdw4l>}u#J!u~ސmaWdm>O51H J6LOF*U8f/.6&C V kq$=ն>?7.!b3 6=e õٛ_^{IY>~N]_<z%cVH_zɟ4Rd[MM j'\{>p䆆2go?()QT~²-t{a }}}a&wkX`2R>7~[lgÌs+fwV]Xs%P`^VYvMGaFؿoqLJ~x/&w&Ix㭷|G#i?SOQ|-`Q(4=vOr] 0&?pčg>wП~>Lcfݗ?|gUN=IcsfzŽazz_~fK/S;a;pNKM۾|C!^{ߟ~oy˛ô'0'  &@ 0Q @` (DA 0Q @` (D/L @` (DA 0Q @` (DA 0Q @` (DA 0Q @` (DA ' ?scYр[Rsr˪v֦T9چG.ܶ.U4XmKߓysW5^ou{zQ\qUU&Ø%4 99[ Z\;xڦL&uȬih(`E}}}LNwms>`gcUqqwCO l;V?gܒ{ޢMOv֗eI+W nmYU6–0w{3NcޗЛ3hE/=d>ͭ[+.6~g»Z6ޓJJž=[P._ו$+M;ܗ﹎;/-IIƞҟ~O}+g'X53gko}W灏TԶ?7hwn[iK(ޚ͓-+KⲲ +wз)}Fڴ`^);9/}/Uۼojr7擷'vSSOIc\:֔I뚻vL緽ڊtiZ_]VY6)[pa/d1Y䚺d9~eonkO~i}mG6m:%]_̕=v Y&uf \fېsw@A[=y>:d35uYV'I4 05wYe]oWק_j|0)m.۰[°Aƚ]<W 픪w5f*cIfhoRX~zOctch+.ObU}`;SRuB.dwCw`Ⱦ 7TZscUO*im@g: :cOL6~g*7yĺS6ԅ#ArXBi~|rrVskai_<hvCO8lI:jÍ?xlWRn9;*?1֜0el),] +i]3]\3+lmlU;wV[gghCR .j}=ⳍ+n}hqO6uddӸls|c*$5>_KK+.Yo 6W7xI%0];uenSyMv3a/s6<<ƥzcz6Or$ƮU5HDۓLm3^nIf|k_dVɜ7DYLɹ9uކd5mt\$jnnV~r8PE@UsKI?[*jL"|A`뚢 @wP!f󶶾p fU}icْ`ݵ-չM}+7kq^v+#?K2'A(Ө,Z3;CFrZmTVBE7޸=$;и#.+= 5[֤zؾz-IљU#{U٬_O?K[nJBk~tFt8WoVUŲt?ŕ#im\Z;A=f'm o~{|/anb= ޞmI'i/vŹJ3]I[umǁƒ2 pHo8'oye=af-);%%=Q;[K6dIR'<*t x,76X@ϬdIxɼ0tԕGv+_[z;_ss:U5 ޫC]Sc1lͼЍgoY=K/Ӂ u|Cwref;Ē5'N35cse^vcM*&Xj}>rLS\Ԋd3J'2G}uYIh^ |{pJRl*?fRI-dgz4 trZeˊF}V(LrK739e{MGrvxCwtC}3Ui.gp[ tP7|7ٗ^&dc$쎲ؐZзUo.hШB)z̹T=sf~SwtaUWdwY?>2D: >#Ke6GNJZ;EG*dNZ&4Ϋy5>Gw]50 ؿZcOQv2ttgm^e4/譚:D~?G:ʿG h`SGx?lNH?o~Κw-4NxN<30@'l)x0xR.D3-D"AkB[^m.274ɍQtLB17,;pt3UR]y1Z:b6#_<&=uN2,Lg3=Q&.D*QQ\*DA 0Q @` (DA 0Q @` (D/L @` (DA 0Q @` (DA 0Q @` (DA 0Q @`pXn(+(k][ʊIʪj5i˪TQQjUKo|Sq&Ә8Ԗ.ڽ7?=jtϞܳ-L)8ijU˷[;^ח“;6\4;jR8ДnI4kKǺpkW3W޴8ӚS\V]ߔ8VnOf,WFɶtU0 9[[z3`=ܓ~yeǬ{Ʀ)eUU[CT~k[eY..̔nT8mO롏Tuvwn)s#UGV^Uܰk: s鉘ҍ0FV:s{¨Jy"Xݣ- lQ~ަ'[ˆRwca_!\3\H[j3/k]6~ϵ24P8TYE0g,M;6lMֵȝ+ίR+'=wc;m;IDATO>FL1+@` (Q*7ԪwpwKgk[;\U&}A @` (DA 0Q @` (DA 0Q1@N;}nYT @` (DA 0Q @` (DA 0Q @`(Twgo8Aޱl?'gyEo|d{N9t"CAʺ$qιNe<޵yKr߶I((nG~nW?|׍_~90=%UagL3<هs7ϟ?Y8a:Ip_uooзܿkzj(4>7,0ޕҒ}x=wR4ȟyGs۾ŢPP`` |v|]<̖_яf~}N4`( /¥?i^Nִ+\I{'OCy aG;gΜnwK^}KfHO= oh( ۿ~񞋗o /zw8Q iW8uo3>8lmo{ۑsgѝ}mO '@aسgOq P8;/Ş=?P?}lׯ\`X|L'|@H^N:W^/~/U ǿ2@;+qcr{_{zKfWg}'|tO< #i?>r|n_"i}g0y`h`&2'l#* 7 3DD𒷾5Ph/Z`InϞ=M۶eۗɟ ͥ^m_f'ô+|ëz{/x? w/,+K^Gy&/_=#هw '۲]_\w}o^h鐟v ;=bKU0S}{߫wm>\[aⶬ#PqQdv][Qڒ,vvvniㄿ*+?<+S`43.߸.¬g﬚BjC{f5df]q*#8p@R}Sx_;]sw6WYuُ@;xZ[V,k ُҷ–Co;^wVTmn*N+Mo}l;yeU+;}7!0 qM$;w S()^i-ۼd+Lɮ&Ue)_IbooYL?.46>Dlhr씐Yՙ_cOLM >%5ϟ̗'sg*YVjzOxWcvb*6ԅ=}NK.'4-mL7fU3kMdJmF:>g9r#mms_7/LiW1议C$mkW'!$;0533Vtջ%)١Ʈڼ5uUsK3ӕgq޾!ճڎL=r=ޛg|=;3i̞$f lLUْ搎I40IIJi>%sxUtl(Uh;\SoK&lPL#Y,G]Nm;} t:]fٌ֡K+W7nO]i$J&꽙Z[%֫sKs̛.|ew S}+[J.6&u|y`}KUyaf kf0Jdn=Ȭ%ZhAK^A&۹̻A)8zt~h o~{|?an S FqpaΪ9/Ǯ?糍-sJT J]9Zԝ$wNkP1ޭhG7}:ro}ܼb0Ys5o Ituʂ6ye' pA:5_um-+dmGמa+CeT<1WdXG͌<0Vp-ҝE3u!WmswAzLdgR V#B(Wc|1xe8ag0!cHK(vąҕ1; a:zji0Ukn٠X>ᣆ =5܁ +78o' +c!];{K/TW Wfw UUŔKyPID|UF+9эn ~Q9waxF$zgýi~SaMv0̸{BL=XⰫJՍUc[ @T&?p x3_Liu-L2@Oٱ Z˄>u@O^Bah`(RFyT @` (DA 0Q @` (DA 0QBQ___N(DA 0Q @` (DA 0Q @` (DA 0Q @` (DA 0Q8h 4Ug`΍eEcSR Gj[ڴ 3erSZjS JO۱f @Z>6-EEŵ-ɃU+0w媊තwֶAquSo__oSuqk@^;hmi5Da@F63_l+)) ` ^T]5̔zX|a %RmN$`P`S 0Q @` (DA 0Q @` (DA 0Q @` (Daҋ{3i qS 0Q @` (DA 0Q @` (DA 0Q(|߷s׮,,~k^8Az7v>|o SPP/oյ[vn97:+ʏ>oL?T~-?O% ='4-+~O8iϟ_㏝|aTT!Uw8gPl骐@Kw $I6xg;/~4~ď߸a6JJJvq}B7!q#zS4SHxlcK-MKg '}kzϣa𒷾50 ; cW tW47i^j^6y bIѻ8MyKvBxaYY}7ݏW^ye{e7]4SHOtm~ mWֹ3(0}UV~?ytG{?jQ8q~d7_>\[駐[V?|ǟ|Y/Ztp\$'Dw'&h `)5u;FOoe~}; 'E~vk8l+_;/pB~޼uEG Ә 0@K/Դ+wȝ{Ѳڕ[zaz ;3F0_ Ӑ @` (DA 0Q @` (DA 0QBQ___N(DA 0Q @` (DA 0Q @` (DA 0Q @` (DA 0Q8iˊƢh˗m mk-O-]\VUP^TTЕY6U4-s+-ʖ߳gДe ?i7tח8V#Vu=iAтMO ?gi;Vfܑе|'ZM\qߓ2 {M ],U3܆N 'PwƇҿ/skM̴ٜ9JLޖ⢢ږސ*HEuեavgs Q^wyɯFxW2ueU\U`8 m[ aﶭmaNt0af~?PWwҺdmm-ݹ{ gxQo )jG{=hNv]cKgQV۶M\d\VHQF1 pŪs'ܵ3>sυ383-zK~}Y*vK/ w5WO~ {m[ߺ8Lc>7 ?}lׯ1:x8O't5WSo|ի^&jJO 0_l7ܱطoE><] <Ҳ0]uwu?_^}1;moک&dJO 0}hi>,,~k^(=;wuf⋷}EEEa`;)/~[{u햝[ +&Rg^ه_m_)VH_~Rӟ4i/\sI^yC?~I{'O 0v wڲ?Rҥe_[;&X=  Ǟ={-{Fiy3 1gٳ48?Ӹ.ܹkW՛{S8ҊsB]z+hohIjܾ;?uJ33.dӹ >qg?% c9!jBi\Ω((-Ώ-9;>j/k/*;=hK.#;o膇G{͞3;p\Rq9{?n7]M탦cwIr^4W4~}fJoOOEpA6xoN;/~4~ď߸a{q]pcChaodwR7Gѕm?4 lǝ?UZuڏ};7ڥKMߖm??[Pn]EEET`^VYvMGno}+*S[V?|ǟ|Y/Zt0]%'Dw'&h `Qo~݄o~[ه_N~Bn 8jc+_;/Ph^?o޺WiLa 8'^z饦m_I~á,]{逸7lQhIDATa ;3u``k` @` (DA 0Q @` (DA 0Q( 0ө(DA 0Q @` (DA 0Q @` (DA 0Q @` (0JV"9Ɗ0ՑL;$O֦{瞭mnn|4hcKw|HzFtgՑL7$w*#tܘ&7{aέUe9 eU[;ִfN܊!+է3Em-XqUUiWm:מՙo>޶ghfw{Rnk#;kwg^;}Ij?jşv6VZƊ9kk/mT=:c#oxt`|das1ov*}tdOGȴו 硯m>gyŽt u]}+M;ܗ﹎;/-I|Lc {4g~WT)՛|˛8/;֐Q66}>3󅫪)T\<;L-rReU[ۺr6 SS<'jJ`(O]XQҕ u{W.~wM[WMʫ3v"9C2xtoGVmݭ7en֌PQY][eLA[Ǘ~{(4qfs+VU M]A @` (DA 0 0Q @` (DA 0Q1@N;}nqT @` (DA 0Q @` (DA 0Q @o}ۣ,x [x:/ S@9t[ f|/ ɯ^x{03Owƙߟvqsg pl&˰r׽}Υ+V$1xفs]Ʋw,\hM~eԈ{dPPwu]aB9IckFO]yMWX=o1GW\< w$f9uGFDk2F 0Q;eto-0L Mw5}&?I#pt\VhigŖV\+֌߼b!SN|pYŚCCUWVjYgNv ua}cOci=wO޳OQ>9.\=#"?|IR'(禪jf%-]z0ӵxE2=c-m}*l]sz;jg.w|vסIWouynӛW^T|̪V.d:llp '%uqYI8Լ&;tVRB7iHxP[^帹lmIg׍tt#$$+tMxeeE ρ:vr{2A_dOobl_ Lf^@~I)Cg dқձ=pO {$o2}OޱHtߛ1dIDATW gOZ'&cye]w2pqim6;6/[1yV?sd极!r yx$e#+ud׵~mfuxۧ!#r]{0M 'nj 3.'U̸G"sS_IMׯVъlgl_ 83S;WopX޲"Dp쥘#3%4=[˟e)ɩ ڔa-wzG]L6, 5z"lu6nW%;-|G;S79ZIgԁRgt92}>:w*<ż Ҹ}*1**X6?I2=Ӌ޳"{BÓcOݸyL.f- o:}u]|}-e%=pol?8WIj#}Sv_mC o#z٧x?+0F$m|F\ iݛ~:̤15 L<͝'0{6R 6| umEaY%C.ػ/zĩ86GܝriPw绒0C;> ~瑶GI&dFUVf9M 5~r2pT خ<~9ٵb_*xk_*.iߒKJ<_um_8VE}}_ҋ{NL=Qa>XGGx_O?8N;}nqN L{Kg~{IM,@~=ٙm/}!p:̤oo_/~_}m)z~30$w_O?[6ayL0~޼/϶ 0tK0]0-8S׿ _jzguOJ,</i~+e^xՇ?|˓m²~7/ե`$ ?Gp7ʊm4ʐ=/:̙3; ̩w^xgE#+**H 3+0ù00#(DA 0Q @` (DA 0Q @` 3 0Q @` (DA 0Q @` (DA 0Q @` (DA 0Q @Ne^OS͜IU7wâEeUzWn.\:=BwCYјԶpR{v?Zue~螫mjUKok py__ߎه+w{KO|tmE]Qҹ=,sS{jӂ̔MiMei@"pECOfP|~c+sRU[[9;iMMG]s66uIp`۪j]55Fkkі-Ȗew콧N`̎!l9GYwkLcAEY8F+7mZD)K/*5tEǾ;c][7>=|ev6֖#]ٰ4\|u]Htun,!ϩڛ^4 ]- ߝ~paMU/my6Cv;ږY䢻ۚ$H"A~vQ_p>&v=L*ϵJa lkY5y5ez35"0G7.гKzkMwݗdtѣGiٲUuvСz^v':Q$-[>XOѸq'ӟ %-}/ϊW NsuΝ;7_߼DG֮={U7d, ] 0wTE+?pxSq! ۾}z_?(8}@nN8݁ԌoV}c%#"U"e0mj\* 0wf˸q?8~i|붭ے^Ϟ<鳲GءC^7@Mh$~&D-f[2Fƌ\em.g>ȣPC)?^Vzu4TϢlrӧzNKd |)YYPm B>^#]`DYm[r_yp^TQF=Tj2HK4u@l *t}2i'"h[1'L7M$g)!}8lS&&N63B0rxM6NV3gr$eA1}mW%f-l'7+0H8[n[>" OM7Q%3-x8RCnLζF ;{B?moX"ӯ̫۶ ^k.v9Wwɲjmk'Y ʤm,(0PT[jN-/]۩3sfM#[zKy5bQ 6aSkswyA+_bzS?w^jN- WZ{>۝ZNYطs_מ]E]h-0P:O䷒=8:ۊ-3s3ϼ[>X[wugvӦ;dރ~;n ܳ_Ϟ}{ wcO+wY:5?B+ Oq饗~9\Tl'WgYpu*x*/GCI:Q$o{~wA">uр]Wq,:u*9e}k+.|=>~6Ƥ5DptҘ+V&8ߟ0)1E){,&$)"}Js7+XSzƅ)7'Tڜ{0/#1JٸL|G'D 쩋|ƘbʿblHHW cj"  5_enk839O`WI,Wm6dY6eSNfdUXeź;B8/3=Ǫɑ~^^~Q^7hOglh? ^ּ|zR-A:}Pw :ǪSW QY~u s2"}JaʱI iJONI G.:UlW i}rqTځv[NJR ,7Օ"W#lE_h@9^cjTi"3Nʉ 899lo5MtM/ϗYMFZ9nSsK&zQ^jN.5Kl5 [ M@h `&@h `&@h `&@h `&@h `&@h `&8 N KZ p74 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 jʯE ?/ĭ9:[Wm]VxH1Tv<4m…'wABt|rln}\~ײ~e97%ǗZ>E\=<(MkkuFHwS{,4ߔ#:>Y[2uޭV.ÜlV PnwGm޷G]6˽LCY՛el.ǽE*sn9Z\:Rzka%E5~is*o2Dz؜?/dxNcmsrUj9|O|aYJ+z@@0rworܕ"2׻>,Wzk[M5Ռ\vRljnY]jZTcjTLiـ;cu:"V߱x[}IK_pfG<*oC>o7͝/"[Եk& Y q?/w3BG͘1\5JSbLfOe*I_{Aj/Z=+Kxseh427q.k{ܬYkm[N߮m[ᆎK'Nۿg3gΪ;3jh _/w-˾Z=re]&<¹?۷n믋\j;j<ϝ W端 M4K/q/^܍G\|IǎBo -.#pGZg/Z۷o5SCCC9|4 tw_]ӦM92ɧKQ'no{[ B 0wT-/ϊW Nsuj ;wt"vH荳xѣΞ>}:pQM| pV~jBWV j៓c&Nzwb1c]:\}>klL3޹qҹKOļj+_A =i?~i|wCwQ d6Zyr?;قī4>q';pǸrp)~ːΏz})x~~BV-d量Vh}i,'e?V}u֢n]j9eҢ" pZZ:ʗ&#}Z״e ϲpŴ>xxV +ycTkԇ?YTٖ1jGhAڝ>wvnW 68DG/8vLC-^zY N ء|3c ᢠJiw8Ƥ"hrx`zSf֫ZXe&&w9//V\YUWp`ziNg9l-@QooWܠ\8"fn;!\5IDATLh|sEth^~Z 'ȵ;==n+d=? Ux}X+ݣF&-zWԾgE ͕m¾}*ّܬ\N]gpr=X ]7fLk>S ~Ro/ra7};m|''ώXE|w.͚51Dꃇwnժո豲P\\ZۍI,RV5:-jZ~h\t˖-_ M]~e 3#?DDV<+K~+?W\~w6jWڷrʻݝ![݅~~PO4q!?'oroE?ҹK ާ.5Ϣ?w~S2fٶZ?)v|65S+֪UǏ‰'\:V5S.x[7Q<~]-l+*..;ԉ"|򿟎1Q\ծpڵ>\Nn]{/򷛅a姫d5#!KZҗqs۷J-U2x[7/[<6s(([27V-J֔~W@9]-sY8~^bP;Kj9K6w _v!n֞(jΝ۴RFϥ +o7ecN`_pSHmu:0w^^PpUW郺ʬ 7ہ߷ϥ\a_pSn7enW~:rD ?}xlRvaɑ>'ܚΡ=l^PiPfTiRr7wR2gԼ5ew"g3 KJ 2$YwS$ZsR(wBޜWى~ˋ7L*8[RQrR̴˸CImkq)31>P8h)wl{OjO͚wɟsMӥ.*i9Aj8竣2UH69X\1)2ykl9qJs^QY)>޴)C+XwS$g WR.8&5'm,-ͬ`9߁3bu>B4QÁ1: Nͮ>~9ai @\~<)>t_DB)ꉢ_"/#FoJChF_U95Nɔ-1А8"W"c*K͈}2HkWTP%qs˚Ǧ @TmՅ/"x0m؁Ae@FuƩ\l7#=U`ZS uޯ>36LhIe/@\WF #uV۝|&=ta$KȕӇG&e,4pv蝓bsPw0'5:\ӝs9`0a4Fᦔpa,Whʅ}4*..v<5=khCgG;Ԩ)ArL C8X&cAȘ*iGGӣfAslH^Ӥ\dzٛs!ZSSjUA'.hMwpD|8gE 1;rI;x:nn1js0'6Pක4 g$X:yC 0@*(L;p}as3ckd|jp2H)3ɵ+ݜ'!zxD l4.h `&@h `&@h `&@h `&0:Q$@.i+hh `&@h `&@h `&@h `&@h `А;/#G }٨cEuԘ1Onzm*s\."}=bJ[H%6 &gZY>4uޭYTs͟u2.٭!>(@!\aj.yxИq=A R+mroR[f4?_pEnZ>]wZZ|̴,?Qڸ+ {x(9EOnUo"0:ߺD6mdlnnKTR^(=ֶ}[{,+u>WYO^-uV~%)\"k_ .ުtKͼ^1UVW:tѣG-[^ծ]Ν a7MC<|Ol=Dw., Rd{ᓥjMv`#/NGV`Skž{37o9p? ٣~w>Yfq<6oٺb䗙[9qDNn^f />'PN:SϹ7^z99\~ˮƨk̵sm ί٥5ase G~o׵ QN>=/8p?+6o΂t݅7"s(ŋ|?Wy/iI^'ϟv㦭w3*u@apX[&֞ 1#R~ڱxwm^z!۷C 92qSGئM ,zr۰Q;zީS\ ٻg>]:-=](G!o^xш;:oo {{atնlc=d;䚻t2h.\pG]v5w2msۍkV}Ҽys^IO(FݣUSԷO.YwM{V!zAp˳gΊiS㞝'ر_.[~j׶NעE nΝ;Wt_~ٵ뻟=jf;nqYYK^5.z{駟=MԻ򷌔>jB ' qIK~u>Ț~YY׭=C͕Wʲ<|G9c5jd0}cM~f͚]ٺuݺ;nz}| t!qۦMoYOuk۷O_j㏫wWY<'?^V!!p]{yoquu+^;rĝD6F?p%JVگ&E.H׵K7׸qW_ս{wK3g^xQܟώ(|||[Q#jֲ^<nl1QWw$<ܵïjvrw|[oE#E Ջ!8֮['sRk°ۆ^}iل3Ԯm1QUe4;P {ٞ,R|44v㍟|J,.nspAAZgiԨQCؗ_ePp`cff탂s''EEEuM_Mvڝt^so!LㄅU{hL_]"YU ψs_,ӧO?;_cPVƗK>|c}*3Ñ^#~K&sW2?.jA>N27?j7ռDDпSB-hǎ{) =dE=sCD5MPʼ!}OGlܼqSfZzq/o]ɐ@]~<"j{_\ps-_>4"_߾} am]Zi v"LGA;rH-nܸ&-jwYd3l]*;00H_N8O}Ƚ^_\AAͽϞ64VpXVD 햭lǽUttgt2 bnʯ SBlpjٱcCXe$NTl:ĈD,Mg^ܶ깬0] SS2&d޿TqzhteZ7lqA]Z>KN/ۭ$ن(ttῦSKv􎘙V⭗b+C6^ծ]Ν a7"bۇ._v:uJ(B'GDxF=ȟMĈ:I4 _puFI}꣡j1YrUp^>z,5M"cIT_%1 ݶ ^eU(v_%r呩u6 ls!RH4o-,< ʞZw.eK뾔ZdU%a{WtUEF%QF Ạ xes^$\+ӤilZw uq<ϥ~tSK&mb)x|O_X?}WFny蒽=myd~W6 P~ĕe?qtqӀ?8С}={O~הɴgkVo?BY&oC6/ٗ >}@Y덉^B/7nL/P:KgQֺm_@mg}[+u lr,7l]8]{WtUj徾EEEV}a}O9:w~h\> oVmADSŦ?sMgɺE:c˫lJU۔!y0 vSX~NSZ mq覟ؕՇ͏KJTvX IDAT#1OYOLcګJ zWcb'N^f3ooY?D{nT_~bWW]yXLʺHSq e)2nLRm^RsbZ>A'_KK<UΏ`旟S=M[~QLekL|Qo~WFh>K.L=* OnH}7[9J^f۾ܦGfw7~O믿<*gTڜ[NP``3&hvOT˻%ټLoRWOa6ofyKnmyO+G~1]Ș>ւp1YcD~je;d^r%+YW\~am\>?@Yg #͟u+;gױgW%ʷn/^ @ {sǾiЅYMN*uxHx8brtt_  O/<,tߠ!+U~sM¿|>J~ߩħ~35̪!)?zɪ^tW&2XV%bhK4Z)8h>-GTzUe=bq15fŋ|?7ܹ̤],Mۯ?أ5z b~L6X~j_jGGJRY&hke!/›MLz&LF SM~WEyے-ʿ*w;/ r%Tȇ8|uVC_h,kw[,d#:adڲa:{Ṭjk/W뛔,(^[ӥ);,nL1}g|5pLƅf/Z˫* OsG/uMy}>ϥ2 0jm iKTYLLOO ۼI.}]J-2]5j'?o&i,\e&,mvIpV J>iok4/VP{LO$rkT _ |8QcTC᷌/&*{yįfUuxaJkSk!íeӧRF'k/9+?^ T'>[S_t Cd5>kԸgٝTXXgtj4oy2 %=m믉 lR[{ ==V?O[^JWm;)WkjSq߶/ݎf6}fZ2t ޞvSCJVo^fԖ5_}zH`s@)LJ{V_ Ҳn}m]\MWT\Q/_T5m:k+/'Oԫ\}Lԫ/y(˕.Q'E\XGWN4w^5{;YnBy?.\pG]v5w2o9 o~5>i޼̲)q&*=^p~u&~8W|jO@nwzDi | gm7}s%a o_LoJUpX~! ۾}zW~/L|=wԩWyרػwwMݨ8h/*Zm/e%?C*?Y~z4?ytqT6bLfcZ/PѕX6w^u< o-MJ┟$k`ۧX49OOY?|k)5>ss-]T#B;)֎Lʆ dHpN\'}7e4* •pW7tX l%d/#*c'.^9/,tla`~8br οk|?0vL/o?2D_]TWEJ饾ZKsvh_3 P?1 e;ͪJ1ŬD,v(i++3acl˓`2PxNwfF{~ǝ~EY81NYǞU4Aht/.пh^RF)W$FymzYkQPI֣LS3xu{/}ob݌[KNheHwUfQjcKΪ cK}>g >x0OڴiYjՔ?-5y3=uʛ+{|Ӱ%o1΁J6FNomKb/1eYСC*}Y^%/6uez(YuZ~+eJ}e{G {q @}`ym.j7mw5Ẫ~X);>=Qǟu?(a;eO O<>7SE/m^uwQYe!^6{WK4"orK?o_L]{4H?=ګgwMuj e~qFAyLذ9Nk:Kk׮1n=p}E.5/ zSJ.Z^b}ڳϽpM7$~Xd]==L6e3-?&OzaU2&V5l `{gNw޸qcᢪ~4|poXQ>r,՗~Ȼ:p]Q3ʝ)T4{ 1,|W-<5~kcc6 _X( }Z'Wn1; NoU -T/t`u%i韩ŋMw >A95TPr~:tam<᩿G~nGQ.` 8鑗:P.ht<{^LFwߙ/;qSƚ;tLV˲e;CO䍘YϫzEjygtN(JG*(GVԭf:}PPĐjy5 p73a NN.Ż _e'kyteTB]w͛7?},ֶ0ha Lsl5q US27oQ -[GҚ?>Yj.S{Nf<׺mkQ ~*3kj`5zc$st؍7~*Y%_0?˝mKo e[^7x+yn 7ШQ>/ʐ傂cwMa:Jґ=ѧ5ݯ5g6+ן^7 jzQ~lV pQ@@o22TǗ>yV˛}ӕ۷.*,4W[WMSO$6m*_M-u+5j*u45+Y^yڵS ֳ-^Ԯ{eiUG+)O8!\שS_zyzu`“oUF7_~lcrŜݻ @vܥ]|׫R IDATug M6ja'Pgv2t.TG[z튟|ܹ*^ٷMsgQkܳ?5媥_˯+.\ oh:0jC'OlѢ>e觟~Rˡp f]ٛ۴I_W]uԸ)&7|dKVBBty]v7ƥE9?w=t:y_{c4Rw*tBݻrsOĴqm?W5=<ÝP )KLΓSRw!Bۈ0A- ~+U7R5{`'u˯NiӦ{o端o#rMʘ@F?{믿0Hv喿 6F~B.q\,x]vg>0ط^*{<ӧS.S$[&] +?]5i?ӶYoT۶:~TɆ0sF_Z@^o7mRsoNno:1brb[7nLKOVWK/[T5> P#p3w>,u{(q;&r饗~9\Ԏ+B-T:wmڼ#_;exsdlj_5kM(l O1dKUwkuhx s뭷|a&y _g^.^T~<1xu^{Uv޶39IKTtX=,3]zKppOK.YϢ<<Օ[ګ/[*_08/G:Q$-;{{￿lrlIɣ]2ع^-;zĥkkwԩ䔥ƍ`x2}{n޼kCf`ШóeOcƿ 7WQZ[oEx Ǡ 4h ! @ry! @۲uo! 9iZ^[[Бkk*%0ݾckYդ]ls=Ͽ^[g\pu`=]@븶6k/_G_xO],Mkk\տ_0P  Ǡ `&@h `&@h `&@h `&@h ^OG 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4p7gңu^^BQ2c#YD=KӮ@s@%IigO_gD]1$ <kX`lNqmpL^zBTG=_GMΈۜ{]lOJW4&GxUviz?<~ cOcR)^e˯0;).º^~਄GMrؒ-Q41#b՗lӄ(?yg3962]dBiĥOmvsh}G'?; ƴex>FupøE%g r׿9.MQ 3"ٶ(w7/6eSzOTL,()L8#=Z_jS2booSkhO ]RzcNZTLF|&-(X9O`fZ^rDuM2OJɽ;떚^n^0/༄nj ttWSlf sP:iK/J=S4ڜp5bY{&*JuVbV\FfL`Ƥ0vu+ >g]Y._!s:mْp&9ZM=OzLf-kyqqO>g ;PٓLE)3mŕl7M>95vhtMuaz9<\͙(:UQ6&EOi*ڛ1}t{Ֆ{􊼌x YI^)LK<2);mNQJTex츨;:-'=6\m%e4QW觬^(35w༽ eOqIC n9gofɉStqQ)16qoQ= J㰄Ȳ]sl:crJxR|~CR5e&7%>l/a}lrMd7?5}hGӇG&$g O~E+Q[רfDW7-21?@v^&3)I\y zUAU /?1<2JTK^fQ7(*^2ӅG*yej8;fr.3|9yn>2Yԫ9Ѧ)lAA7';4Da]db͍%͈ɾU>GCx}]L Tt@ci_kd-28]r|7CzUA)ȴscFj@597#^-LWoJ -@NlI Tf˱wi3-6lh\GJ7eWq JM(D̨gy|tRn93U]1i+cN-LQ)>Qf_=uj%v$i|"TΟ\n;sf|&+/`o%i-, 9 !:Z_ls\l?iUE]3*q F1#!' NU7Y y%_@*..hzaF7+ȀAsU͢"ArqϘlZo&ey39EiE3̸X>W"=khJ"'UN15*xDJ㕗zȌyM3q1q>_Y-ypV!U6_xB+lo 8vNZ`d6e`yf_C,jtQ{.s_clg|S}~|1ƣ_;0f)9:sZ63g>lu֠+xU?ImvrO}t񠝿ujzOZKw[ @}i":5vkPuj:cLT%}<.>ꇋ8;^R?K:SsآJTo:lNf@MuyktIDATȌ /U w XM 4 0@M 4 0@M 4 0@M 4 0@M 4 ԉ"P%4 0@M 4 0@M 4 0@M 4 0@M 4 ?^͆ v>tѣGvuh߾gysy۝pDhضlc1?8 pM΋]x !P%5_T';wny6FMӟkڴZ} *ܢZ8yթ8}ۆm߾CүOԾs@}\w' O7f'͛7URo0Pen=޴tnp۶@\lnK///:005n?ߨ Q YHEuɗFwWYq_#ȑ#ܭW%[4jf _u ۹O;u ܹc{ƍh&w i韩{V,/j|QMF:x0oup jpwn/Lއ#BG&,i^ʭN6?tm(N:_-[_r<;lEtUsHҚ;x۶nLζFz>MiL\i2ao U Ve}eY^r<@> B>=Du~'Y^g05][rw[ے*]p'(ԩ.hj9>)_3}f )+Q}8|ٓك&3F %XL˺33zٳsmJ63>V7̼>]ݴH} +Ri 39w@槽r>HY"np`SӭW7`4B-y8R2 ͝|p6SgO&S 'sN5'vnkex[׾C7yrC649{͏"fWnUeiJOd \d &m{+xpndeStaYe6/2ܬd ٓ?1oXNÎ.fYv;XV|[}g,&wd:JY7hgr.ooShgeZ ɶX;[?eu2`r:W`!dr["IONZ;l\ejJ]kiV剾&j?Vn5oJ:ϝ+p-9=ӕ}z)8A]QO$HVjrKD!hV-j],۹kϮgT5mgIC+Tۚgۿ d˩tr޷K^<_ɷj$'l?WcM6ja_ fl^s֠ryaSS -]k#[J(GPS!K}]>mBejUXZdT`ȠU}F0Y?N/x w 5pýre3fIoLNn3dn4-nd )IG*;TF=<*p[O #{ Ul01bcUBlӔ򇎼1?#[- .56l˝$,-Om%`}dGv2IOcr>UM'GsևG]5e4Up`gܐE;SL^yRMHtvʪs/qvr s{As[ޛxOSIL'8wʂ%C#uQg_=m b*OHwb?}tj,%K.=Lr؉c$|v~B]pLjƔey{Z W[zs[B,Q]LjJ믔W&:M LWNLfbbR :La^򯏏M1)AͿ4投 g.LJLQ AœXC`7MzΙr IJGp꜄J!,.֔^qa񕏰u0/#1JٸL|G'D q2NdP˺xss2hWN1f'FGĄ]ɤ%H1j.2ZMIpPty|?dqfr,*3!q,^ۆ_iaS6$lfHV[ŝ1QXS) ڱ2ӣ plhPUA'8x:3`? ^ּ|zR-A:}Pw :\m3gH(Z?>&~,uœ@sXrleREAFl\XI *]uQsijqEVJEe}g -yFh%@>J;0*M_<\9!$uب@;w~0h,RFFPln;!3N畂C>:n05JlvI qݕʉ 61&G3=p] eV?q:VNܒw~(< lyLL"}\4v8l4h `&@h `&@gIDATh `&@h `&@h `&@h `&@h|D칤wC 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@M 4 0@ ϰZzhpOBz,Ĩ'/$S^ٻ  EhnSUn>7(!o^L5c׉us*S?.bnUkk^Nԕ[mS3ߺzʬ~jV%@j`JeCsq&\xrQj8hO](D'ևow-L]9zݑso]r|٨ZޣaË"Mش[gt7<ǢOMI;r묓c.s]7njjQ=n1͎xxwZ0~Zlnn߿k, uvWY{W xB}²ܲU[ fL'Ӳ]wԲY>|ŷ ǕVtN'ʆWl-ͭvعݦ}[{ďe+m4>{WYbz{ZTPiىP[W,-W[w4*);(w)(wL=]-,srŬWzLTSe'nɦf5ܕ6{ȏM?6VIŃfig!ݦv}[/[>!UZPKN8uHuT Ht ȹ3>Y#2;nǻ(Зn>:avcѡ91cvCTl\ò+6cə37ntz.,b"͑A]6iЛ ܑw>O>1C.tԌ^*1.d??^!wFk۳9w\F!~S0vW͚5۶tڶntD{=sZб=F.ܑ`rݲ۪#G\ve#;>-}PvUګ3>{Y yyyujۤI~/R)7nz#G~w}vi#xe<ǩt!  20wq_}|Q:u 1444| @N-KxwС5mTȑ#|/u[μu:,pG5x8WVرs@7 )q+2i8=ZNgN> _TͷhN/tuj^99VhBw-;Х]Ӽ4>s̏xxw.ZDLkƻjo-ܓ&mMw7t@fkC!2sT^-74yyyʪh;([M5uj>;͹cDwy0xx @ 1s[iyyo`v˗ʝ?w^TIej|xaJk\Sk܃B~cؠ0QuA|@-=jdҢwEy_4 A\F-'c$7+W->Sᣢ"7`Pp^\0'ҡ+` 7pwj>OEn6qƲo͟o7;_ Gl/YfC#@}.ЭZ=V_]=xd_QE5M-?4.e˖/&X.2Y,wfUmqwǩ͕WNY' _mo墕ww;{Czwѻ |h:C~Oޖߊs ҽOK[]*jȟEveܳm~Rě @>#;)6\1WcmNM5FlJ7W'Gxٮ(!A2ce:MUNU.:|#虼`WɶD'd-O2j), Q~e6Ř24E2̖{>+Ȩ`u~Q qLȴ=ɵ\T pԛCJUH~JIDATs\ț3*;1Oԙ̸>leeɤKrnrƙ(Q%n;=#GDj]bYΔIJ&'\̎ 88.XJmS0vӦG/k"e7UG1-qpN1$m'9X\)fps -]16:KMg4M;x-7>?lyqfLY>)w.>xxD+(6pv)YyIz%cRsFrђغؘ=is)~#N0g@NTѨ^W۴IiceB׋#tjHY4?'ƹxR|~ aB:8/9Ai [.D*a*IZE)#6Q g“ϯU\ /_2sDT vF`]t✞{g rק9ޡ!2"s$7:siaaݥ }%?O߻̔J ` p7Nd{mʿCu~~J,ȮŴmfYSa`tXooke9bh%6#~뜤p?WvF^tE^^rt19as*%vgG9!6]=LaNjt`I=$E[>ؠl4zƘk]V :F Fs| IC٦vG'eY])NwHdT:H9! ތKϱYuNz\\\88>[~hhBŃ`h}W.;lNvf^޲UJqL`L4WDGS[X6 ?Q؋f ۷sM70u).kn!ɸ2e]=7x\uKr#1a;[4sXC{cS-uHԍ6R*p{6o-sΚiJU}XJFoeEuݭnv9=qqE)z g{'?Ҹ/1z|s{&c|=6O@vڭ;b6w45 xvcU͜v{{lc{9FrqT-,6[i5խ-ZFQ󿷄+;orBa~ӣrlT 7Èj/# rW~NQ;#DOnYtl>ykQo|Du{w&+%&m&Ն{Kf+;O{zm^lS/Ԣ dΜ7XA#kV<|})(_vu%k6 35!:ֶJ톺cSc5ZC%:`|U-|`eIǧ|_TYnxUMn~UF%y_aE~҄Ͻ>A^h9}lS;+ٹew5Ңf,o|U]]]؁ -QpgAm?:bJו6lTWyڮ] +K MJ,HN60@ֆ QY3;)Qk=]{ {ozښm׆9jW/b5朜F3OE;(/GnaqYk**ZZq47+`Zu*[*7{-cӽC䍛<2s5ʖ7ݰ&'ͩCAYEF ϯI .]53mr;oT^.a:{%J%۪@hs } Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,{gm >ATXXXXXXXXXH<}챥K˯j9䐞:p>gص;kCԂyᅐn>{~1 '2?Rj\1ib[ƍMZ{qwW]^{K-f}ﮫmX~/pROzyy^^_^^x/wjIu7t>ڥC/ d4 ѧ=sYs++SNTvgفG5W}6Og񫬬v0@ʯn1|GoI}ڼwy,*6m:zW^y%j;mOݶi}Gt?\2j铷O tH)@έ}*v:eM!^{'VZy)2.á\~}N8TA)/^\pT7oŽ[趟E5|5:Ȟ!}Y&0|7(߼Cΰp@k}_d͚p"Lm{ '7sa{ zƭ$V??;No}HCFmE ˆ]}|x$J jyf\7L컷߱R ۾{ R.khr<6^{A}5]n277l㯮KmFQpoRJYQ]һkv.ٳK<e˾{uS+C;<>}R"Q+ @H Aj\2ϊ]^6%߹?JI񩗮n7"lV=~!ۼE77G#*Ѓ3τT>'GꐬoNNS>#\jw}'s%i_mV򐢫I>1{1UWYڥr1zne嘯Ds*U{`dw7k;7j8ߙԾktrhԑO=dt=SG7j/{yK=-|GϜJ}<䓿Htruj?G>o=_2wgcSNqVVV#蔉.OoL~rTH˪yUKK/]Lh  ?-jaЉ~~*.߮'' W|vmxG~H fŌv;LkoͧM2Lz`: d0tB0  0  0  0  0  0  0  0  Yuuu2 0  0  0  0  0  0  0  0  0  0  0  0  0  0GFVM+_X:gAYY˓jfFIe4zqY~ްfZARU-KniUl?V=`3yg튇o8K갃VL,EɥOykfmM}ϭKXC׏⊚hܱͱsа'iM;޿bC*o~q+:WMYA]P^ߩ @K+N9}d_vnaieag53 Sm'/ZjdgocâmmY &w;:Mӟ NJkLT_UWWWUՕӖD?$N (bаad8 qs޽, .h}Q'+;7d5qQ\"lW^iג4_++sO/;vW.V=Yk.5}ͩ ;,􂮉҉]/(- Ӵ99E?_2r`Xq%Zy}CkN.OMےӟM, "'eW.M<isRve[:&hm.;~t&F Uo֛;h܌O]]]BBYMJv4萚`f%U[ʰtIfN3ᜄ s&l͠57 ]>aF(nY\1'vu`|Qrf3ֲZY]Gu?izq 5sJ>sMؾ?UVuVc{{qEqnԪ;Vwq5垜@ 9:w_Fpnsnz՚TNo`ҝ @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,{gm|b ݨ 0  0  0  0  0  0  0  0  0  0  0  0  {0}y!=ipZ~N/Spcf׾SBz}uK=@Ȑev&_>IV E=IDATR/M=6:Wsy֏L}!U}iu꜍gHCGF\ w\w3\. ׾lʘT8>g橽Bu¨zix뻳Ϙ5:粡K#-GO]3{̾><ó߼8g6`'3߮N$SM׺) ΨΝ4tYs֘ɶz̈́xv/2;:ˊSvQTo\_n]#˖. V&z1م( +CqfksOaI+\_3BTKMRh#z:Fff&hAThv&Ӓr9e ]ػI&]/:z5Qx,밍Ά/ Q2g[zO^;gtC =TɭaF77 mҫۛ$&'KGJ(?[vDh8֝̀PDv?΄FbsT#Nl-erfHqͲDwgM̙N{QhQ"Z_ Yuuux!];pmy.pQy_z}M0-V@I_n}% {nc >?qOL+hXTzqAN}_fMeXǟj08\ð{}7Gh-_޷[Nڶݶ^Wj|Szo޸yvGwt#zva573/K_r;/?זd;};T{o=,_?t(K55#Ǝ+ּ&qڴs !ӽ‹']j:ae3;(n!z;1S߻l/vv7}t;[Oj󿯞M2<[fߕj_6>0Z>Sw޹v+έLSOSsƇ~8!ŋSA' K ɺz=Ȑqᄌex^fM1`+~./!yQw 8׼Z`w 5>lM{O^sb {=hd`w)ݺu;w9Q}7z+mިyS^WzvXȿ_u'8 jDїۡm9{+[ϜJ}W]qE`7O~ݜj?7/t{n~g.~lqj֟ߒ=9#G^׾?wNs)8u/$_%\zg/- 'v/4{m6D׶Z6nݺ`JYj󙧞^eee]} 6c} mq4UWWY:~^{=j9޽BIW\|ŊK}QS_Bh/z]Q#7?}VL>@I)П9Tn_1/|+W‹/N>~a~X~~|gϞSzK|G,Z$jE(NB'V[vٟghځ @t z:tȱ;?V>|}[vX]'8n>OT}? i[~A}:d!:`(|5k^;3{! vo‹/pw Mq~(FJbo1g7njiTdpvvvLxz{շfeeLxM>t4Q/3Ͼ뵵o6"gm;x}~~JIVz/na, 7 0  0  0  0  0  0  0  0  Yuuu2 0  0  0  0  0  0  0  0  0  0  0  0  0  0G6TWY:@G4:˫\eIʰsuu+n[šfTбgLMvaCHtz:UTQWWZU]<0?7fלqs$OmRQ2jfj{-o-V SnA *)/''#ͯ<.RSQo&{hVk+J܋+҇oK4+/EXq̆.yXsϥ êťy!tu`۶SP1.^0']4wl0wlj{ܺ-TϋW|<(tU랸Gػ߮^2gErK*߷񫴬##m\S<{~Ѡd;;wиUsωjcFNrr=.(ϯ#۶)9!a著_XT\\TXX8nFq9qa3/7dlv*]?q5kV<}?="|‹ K.ԩ {>:O="wسVV6>nbO<<_yǯ d tzw4ߋƏb~#zh Rw3uhB8mڴ^y啨=xGzp=b/}'lٲݧOޒ?-ҥKS`WRNcs+Jٿ>=7]ޒzҪUϛi~jQ'B~߾E#Gڍ s2׻jC-^88BlvqQcQif29qf͚TcqC 5k^ v~TIۺ۸qo5t2xР@j}믿iӦ+ @@7 mvO=2Ő!F[/Ȓ%K?F=^|~Eh1}e"}?_U|m:֟:`hv-`%K=;蠃RG"8}5c9&/]*ഴf͚3SvZ`s_j5ygRa@ 磏>oMܤ#O>͍8~Q7ƸZ8lڴ{Mx'R?㬬truj??^6aRto[z rsGE|kۻgʐjO+Y^tܢu]U?zlq6; .+|a7I\ߝp:v;7FM{~vc)FRo93 Se`Fy`UOWn2'Xp 7?g-۷oMXwo]u;?oʉ?ο7Qt9 %.H^^z饭6팋E3w|ݽY3-kȴD#|7krKiUr'nZ3Ns9οr=ig֚['R޳.AY|~-/GU|-WM{G =Ϧ=!'&ϢuFϞ;]{SQ<%ont`տTkL{' ~@gE>=gR PjȐ!C[}2aяk6Wּ̹It :8G`ηW&kHVd==68]pnEĕ޹zfu~w]֝(ݻm훁K4~NִC(LlJ.5+}~r![J,h8e7R8jQb«/R_{Q5֯_?˧.\fNNK>slk?o\BloeŖfYtOzS両Cwogg ǁ 3EFbǖU_tɒϩiRKVB}oQ8ިQ;ud Φ91?|§+9U'WR$vbKQBx5Z**p|O<`9~<{KXOTƟY./v ti\o6#U~k5h؛Fs+dOѣG_v*fUؕ:TciAdҥFnn:tpg+^ur3DK[M=昰3LRw6.R1sfN #g/??jw^K7{>蟾16qz#楥 /(NA6nxMsGQxv{wSUՓ?Q5?w=i 71HJp{~?lՇ}Љ5 G_'>H0)Й/ʊw5eS>Ot/p,_tg?!deeE=lb+}LvSؕ,#@,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,dt*Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,➚9%Y-SX\d|Gg*8zCJ*öl,/xg`Zu4bqY~VkWaX|@A֌~͒_sz}Z9|洊 -쪝_OQ\fmɓϨքd@,s+jV]7ӥnCIDATUޛ9sǦ6έQMϴe5͝89 >~!Wo{S>_[YVD'MSeբlࠉ[,}}.g䏫62\=zͿ#9|[o^^^d1KRIɲfjUKf&ʾέ_V,yX%=K@Guq37T.^^fTN6N?4[~C؊E9[tr";+- ͋9YY9%!7 /ji0_ 5 Iŭ M[l bTq_Kn./ٰ9O:(w_UWWW5>/jF~v挪]4#1zqi~ muL9œ9 >\ʲ  !r^?h7ht$J%tMlsyӥ'6Zqiħ53IvϯmnG*t&N5ξ<4k͌{ K%pbΆ-*u_}@7UO}CU[ܼ[3gFjޥ nUֳ CP(nX)j[s KWvK&Um9Co?1!s -߬۸sX}MXK^b9ϵ5d-+7{b qLCx{Vڮ._b6; k_~)Ӎ_h[Cnaqr5[\UU0ORTQ[WW[\Bɒ]xpvNjJsn6W-SuT;1e,Yn\jթ9w^S>m~qSf\f _tÚh[v7OBFN[ߝ}Ƭ9 ]n7>z/ݶn֘c8ʼn`8Ct &8vu"i/nMYpF}wR Ovk&dF~iŖٱi\VzzrYtQ^_2ѻ).05EQ]5;\k}&OZY=_mB˝+12#73yE B 4$'7[W.Ey/Kt\0Mz69eM4~iY ԫaoT.C'fYmt6|9`55{9zW߷`詽?nr]Mn-S.N5!6ipm35^}$>059Y::U*F9ٲ#Bld4@ʈ'M_Z s&$732&wbè=m+”kL:ۤDY&%'ʼepƜTQwy+1&S)0Ck%+_'hc T|ᅋq?RSS3j_ H#i9yL{>877!к;X=a޽z~}) ,]wv86n4+Kj.ў: .[}vCuaE=3J_]t{~+6v{QgdMF<)57zr)H` q?<Ï{giay_^;?'ۡq Xؘ~{QvgYDY!GEg1vg_5QӦvX _M^8T{ f.Aw {ݱ䎁eV~)d~ ط۾Qw]ݢwg}R}nͷޚ5Txa!Ojϼεk=]`G?pnCENɔ{[慨G3ÈO_]Ŏݞ?dH >X5k֤༂ޡBAylo܀}kv| Rf۴Nxǚݕ׫gG}tɡ1o̖)U~ƝBE_ﻍkhۿH pS7^{ժq-s{.ya{fw VXT>]tVu9ٳmڸ)KCb`u`~w]֝3rݻ}cܹ;jN!Jū>7Ϗn/; /quW`exUW~F~/}ۯ{ꢶkoM[~vsG4ߘ3ũ[~KNNn1zO~zc^9a |m}ߗqI٧m쿴/}v~|vݶnݺ[.j;m6R6L)Km> sxIDAT3+t+{~{o8ⳇЙ|bsNzgRUիCqOκb3DTKƔO}*࣏WSQcݺwUT~1cz^{+OqD`S ;_~3(Ug?>ai ?>@??>Q!ڛofj՚ssCc, s[fk~3}bnn~7|O8~~}PΙ~T'o+T1g7njiTdpvvv?-{dYYY!S,^tӦ +<|y ̳zmm۵{Ya[9yw}9䳟=|{R:@ދ`[X HGĂ @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,BV]]]L @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,ҎY-T4qNGTg8<+'tv}TmP]Y^2(7R]9.:[h/=B;f9>[5~튇o8wƳϜV]K3ҙK֬mgYh9}78h>KRY{*E12\{syv䏫zNe}yyٓưK.I%'˚WM,(v;z~YQ~Nv 7cJ@GrꢋWbŭ,/Q:8iIJdN+flq oN߮c+fluɉ<8/4/deTֆD\8t~ M[l К充$SkVm}~yy*~m|Inv%7VlX'~tWZ;䍯ZP5#Q?^;sFU.|4?7.SZ7dxfKNAwJeY}CE']/(-mvI]\t)ɟyV\'G dVXȳ;'$:^EWL*?v^3dq’q!@ {p}CU9l>tIe꛿Pت6{93R_.--h,,-lt[կݰ5@o?1!re -oM5;t~ujadbYU޸sX}MXK^b9ϵ5} ƍXBz\A SPV_/IX2vksZzƌԭ!8- **V')H.!dIhT{@̩~`\֪:pTMMimbzujŠהO:0oԃ짫_tÚh93ꗿ`և7tNI$y3lh$g|Jp8$/YQUskS#x[;$~w=޽~XMEqYl1DŽ'j SK Fݰ"4o/Ojifsv;RWfl}OU5goE׿h{to#$*~+I 0  0  0  0  0  0  0  0  0  0  0  0  -Y9ؿ{H7*Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,Ă @,!3;on9v;o^HOo֟˔˜ٵ﮻z_hkF=2!2$~>lk׹$zU7KSNUya޹#{8'uH}U9gcoZ:gR'o_}9W7~y8C)+#z:D(;,;4׮jµ.2&Oٲ3yjz]0*w?3fιluKSWuġ&7o-N X0yp IxwSnʂ3cs' ]5f@}m^3!&3K+̎NT]+$'ח[W?ȲޥGLyvᅩ/Bpܬ\S/w7y(-uz~)g?U|mӿZl4^ý/ZZ]0ɴ&9ܺrAk/8vλ}Y{enһq,kzK+j(^ {rqT=:)5:lK,tYyևSлCOq3{*nr+oqrqrĬ yMGk!&IѩR6ϖοug#3:TF<8OmҊO3!\?0qF|i O]\3`Q&%zFz79-9Q-p3椊w]w՟6O /btT@^1yŻtE旦{i/LU?n>~Ǯ+[_ 9y/hS;?'^\SYm8V4'Z}6 Fa?0ߞat#s^tS__=oz}kvCL?;mM 7̋/?Ǘ9Əem<}ߎ-` =ۣg; G 9*z﫧v o֬wڗM ֧T{w]Gs+S|uTSշ2^_=Q9j|s+2</Z8t ~dȐ˷Lyg^3t{G!Co[؎w_y2<Y&0|v}?Z(;d{_k^{-;tc6ۦ'p£=쮼^={>裓'Omwp9$cHQf~K5Z--}m\F-G:U({VkE9w ;kvnAJ`Tt7ӟw]}]!WnٳK7mڥ硇vڭ;g6wƸsguwx2,O?fg^H53zƭ?oټh :0w}TcaYhEۣG`wH\qgQ%_C9C$s1!~MZWN=K.Qc咕O>dS/91zU42;d"Xݺu;w9Q}7W>u[n~K.O;wcx]ya _u'8 jDїm:<=Wޞ^{kSO+&?OS?=1wϭŏ-Nm[rrv _:e׋~77Ωw;enkKWU>lc|&{umݺuQwiʹ)WG`JYj󙧞^eee]} 6zRڮ~ i*ウ6t2w__y%j]rHh7+Xv:j?8_m{= tC?j^eĈS.xr֝8=t9&zo_4O}SN}T'ֽvCgkX|#;,'8`qEWJ5>{KUO|{ǛvG/ |?0Sk:`(|5k^;3{dss{4۵o /xw 8?Qd~__y%x9qUf}OK$ @H mo# b񒥛6}i\|ˣ^g}kkk߮mܻE0 ɻwm!{ޓ:^"X@:Ro `bA `bA `bA `bA `bA `bA `bA `bA d:`bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `bA `b.?IDAT6VLIENDB`././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/scanExamples.py0000644000000000000000000000461615134002420015272 0ustar00# # scanExamples.py # # Illustration of using pyparsing's scan_string,transform_string, and search_string methods # # Copyright (c) 2004, 2006 Paul McGuire # from pyparsing import ( Word, alphas, alphanums, Literal, rest_of_line, OneOrMore, empty, Suppress, replace_with, ) # simulate some C++ code testData = """ #define MAX_LOCS=100 #define USERNAME = "floyd" #define PASSWORD = "swordfish" a = MAX_LOCS; CORBA::initORB("xyzzy", USERNAME, PASSWORD ); """ ################# print("Example of an extractor") print("----------------------") # simple grammar to match #define's ident = Word(alphas, alphanums + "_") macroDef = ( Literal("#define") + ident.set_results_name("name") + "=" + rest_of_line.set_results_name("value") ) for t, s, e in macroDef.scan_string(testData): print(t.name, ":", t.value) # or a quick way to make a dictionary of the names and values # (return only key and value tokens, and construct dict from key-value pairs) # - empty ahead of rest_of_line advances past leading whitespace, does implicit lstrip during parsing macroDef = Suppress("#define") + ident + Suppress("=") + empty + rest_of_line macros = dict(list(macroDef.search_string(testData))) print("macros =", macros) print() ################# print("Examples of a transformer") print("----------------------") # convert C++ namespaces to mangled C-compatible names scopedIdent = ident + OneOrMore(Literal("::").suppress() + ident) scopedIdent.set_parse_action(lambda t: "_".join(t)) print("(replace namespace-scoped names with C-compatible names)") print(scopedIdent.transform_string(testData)) # or a crude pre-processor (use parse actions to replace matching text) def substituteMacro(s, l, t): if t[0] in macros: return macros[t[0]] ident.set_parse_action(substituteMacro) ident.ignore(macroDef) print("(simulate #define pre-processor)") print(ident.transform_string(testData)) ################# print("Example of a stripper") print("----------------------") from pyparsing import dbl_quoted_string, LineStart # remove all string macro definitions (after extracting to a string resource table?) stringMacroDef = Literal("#define") + ident + "=" + dbl_quoted_string + LineStart() stringMacroDef.set_parse_action(replace_with("")) print(stringMacroDef.transform_string(testData)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/searchParserAppDemo.py0000644000000000000000000000170215134002420016530 0ustar00from searchparser import SearchQueryParser products = [ "grape juice", "grape jelly", "orange juice", "orange jujubees", "strawberry jam", "prune juice", "prune butter", "orange marmalade", "grapefruit juice", ] class FruitSearchParser(SearchQueryParser): def GetWord(self, word): return {p for p in products if p.startswith(word + " ")} def GetWordWildcard(self, word): return {p for p in products if p.startswith(word[:-1])} def GetQuotes(self, search_string, tmp_result): result = set() # I have no idea how to use this feature... return result def GetNot(self, not_set): return set(products) - not_set parser = FruitSearchParser() tests = """\ grape or orange grape* not(grape*) prune and grape""".splitlines() for t in tests: print(t.strip()) print(parser.Parse(t)) print("") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/searchparser.py0000644000000000000000000002465615134002420015337 0ustar00"""Search query parser version 2006-03-09 This search query parser uses the excellent Pyparsing module (http://pyparsing.sourceforge.net/) to parse search queries by users. It handles: * 'and', 'or' and implicit 'and' operators; * parentheses; * quoted strings; * wildcards at the end of a search term (help*); Requirements: * Python * Pyparsing If you run this script, it will perform a number of tests. To use is as a module, you should use inheritance on the SearchQueryParser class and overwrite the Get... methods. The ParserTest class gives a very simple example of how this could work. ------------------------------------------------------------------------------- Copyright (c) 2006, Estrate, the Netherlands All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Estrate nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. CONTRIBUTORS: - Steven Mooij - Rudolph Froger - Paul McGuire TODO: - add more docs - ask someone to check my English texts - add more kinds of wildcards ('*' at the beginning and '*' inside a word)? """ from pyparsing import ( Word, alphanums, Keyword, Group, Combine, Forward, Suppress, OneOrMore, one_of, ) class SearchQueryParser: def __init__(self): self._methods = { "and": self.evaluateAnd, "or": self.evaluateOr, "not": self.evaluateNot, "parenthesis": self.evaluateParenthesis, "quotes": self.evaluateQuotes, "word": self.evaluateWord, "wordwildcard": self.evaluateWordWildcard, } self._parser = self.parser() def parser(self): """ This function returns a parser. The grammar should be like most full text search engines (Google, Tsearch, Lucene). Grammar: - a query consists of alphanumeric words, with an optional '*' wildcard at the end of a word - a sequence of words between quotes is a literal string - words can be used together by using operators ('and' or 'or') - words with operators can be grouped with parenthesis - a word or group of words can be preceded by a 'not' operator - the 'and' operator precedes an 'or' operator - if an operator is missing, use an 'and' operator """ operatorOr = Forward() operatorWord = Group(Combine(Word(alphanums) + Suppress("*"))).set_results_name( "wordwildcard" ) | Group(Word(alphanums)).set_results_name("word") operatorQuotesContent = Forward() operatorQuotesContent << ((operatorWord + operatorQuotesContent) | operatorWord) operatorQuotes = ( Group(Suppress('"') + operatorQuotesContent + Suppress('"')).set_results_name( "quotes" ) | operatorWord ) operatorParenthesis = ( Group(Suppress("(") + operatorOr + Suppress(")")).set_results_name( "parenthesis" ) | operatorQuotes ) operatorNot = Forward() operatorNot << ( Group(Suppress(Keyword("not", caseless=True)) + operatorNot).set_results_name( "not" ) | operatorParenthesis ) operatorAnd = Forward() operatorAnd << ( Group( operatorNot + Suppress(Keyword("and", caseless=True)) + operatorAnd ).set_results_name("and") | Group( operatorNot + OneOrMore(~one_of("and or") + operatorAnd) ).set_results_name("and") | operatorNot ) operatorOr << ( Group( operatorAnd + Suppress(Keyword("or", caseless=True)) + operatorOr ).set_results_name("or") | operatorAnd ) return operatorOr.parse_string def evaluateAnd(self, argument): return self.evaluate(argument[0]).intersection(self.evaluate(argument[1])) def evaluateOr(self, argument): return self.evaluate(argument[0]).union(self.evaluate(argument[1])) def evaluateNot(self, argument): return self.GetNot(self.evaluate(argument[0])) def evaluateParenthesis(self, argument): return self.evaluate(argument[0]) def evaluateQuotes(self, argument): """Evaluate quoted strings First is does an 'and' on the indidual search terms, then it asks the function GetQuoted to only return the subset of ID's that contain the literal string. """ r = set() search_terms = [] for item in argument: search_terms.append(item[0]) if len(r) == 0: r = self.evaluate(item) else: r = r.intersection(self.evaluate(item)) return self.GetQuotes(" ".join(search_terms), r) def evaluateWord(self, argument): return self.GetWord(argument[0]) def evaluateWordWildcard(self, argument): return self.GetWordWildcard(argument[0]) def evaluate(self, argument): return self._methods[argument.get_name()](argument) def Parse(self, query): # print self._parser(query)[0] return self.evaluate(self._parser(query)[0]) def GetWord(self, word): return set() def GetWordWildcard(self, word): return set() def GetQuotes(self, search_string, tmp_result): return set() def GetNot(self, not_set): return set().difference(not_set) class ParserTest(SearchQueryParser): """Tests the parser with some search queries tests contains a dictionary with tests and expected results. """ tests = { "help": {1, 2, 4, 5}, "help or hulp": {1, 2, 3, 4, 5}, "help and hulp": {2}, "help hulp": {2}, "help and hulp or hilp": {2, 3, 4}, "help or hulp and hilp": {1, 2, 3, 4, 5}, "help or hulp or hilp or halp": {1, 2, 3, 4, 5, 6}, "(help or hulp) and (hilp or halp)": {3, 4, 5}, "help and (hilp or halp)": {4, 5}, "(help and (hilp or halp)) or hulp": {2, 3, 4, 5}, "not help": {3, 6, 7, 8}, "not hulp and halp": {5, 6}, "not (help and halp)": {1, 2, 3, 4, 6, 7, 8}, '"help me please"': {2}, '"help me please" or hulp': {2, 3}, '"help me please" or (hulp and halp)': {2}, "help*": {1, 2, 4, 5, 8}, "help or hulp*": {1, 2, 3, 4, 5}, "help* and hulp": {2}, "help and hulp* or hilp": {2, 3, 4}, "help* or hulp or hilp or halp": {1, 2, 3, 4, 5, 6, 8}, "(help or hulp*) and (hilp* or halp)": {3, 4, 5}, "help* and (hilp* or halp*)": {4, 5}, "(help and (hilp* or halp)) or hulp*": {2, 3, 4, 5}, "not help* and halp": {6}, "not (help* and helpe*)": {1, 2, 3, 4, 5, 6, 7}, '"help* me please"': {2}, '"help* me* please" or hulp*': {2, 3}, '"help me please*" or (hulp and halp)': {2}, '"help me please" not (hulp and halp)': {2}, '"help me please" hulp': {2}, "help and hilp and not holp": {4}, "help hilp not holp": {4}, "help hilp and not holp": {4}, } docs = { 1: "help", 2: "help me please hulp", 3: "hulp hilp", 4: "help hilp", 5: "halp thinks he needs help", 6: "he needs halp", 7: "nothing", 8: "helper", } index = { "help": {1, 2, 4, 5}, "me": {2}, "please": {2}, "hulp": {2, 3}, "hilp": {3, 4}, "halp": {5, 6}, "thinks": {5}, "he": {5, 6}, "needs": {5, 6}, "nothing": {7}, "helper": {8}, } def GetWord(self, word): if word in self.index: return self.index[word] else: return set() def GetWordWildcard(self, word): result = set() for item in list(self.index.keys()): if word == item[0 : len(word)]: result = result.union(self.index[item]) return result def GetQuotes(self, search_string, tmp_result): result = set() for item in tmp_result: if self.docs[item].count(search_string): result.add(item) return result def GetNot(self, not_set): all = set(list(self.docs.keys())) return all.difference(not_set) def Test(self): all_ok = True for item in list(self.tests.keys()): print(item) r = self.Parse(item) e = self.tests[item] print(f"Result: {r}") print(f"Expect: {e}") if e == r: print("Test OK") else: all_ok = False print(">>>>>>>>>>>>>>>>>>>>>>Test ERROR<<<<<<<<<<<<<<<<<<<<<") print("") return all_ok if __name__ == "__main__": if ParserTest().Test(): print("All tests OK") else: print("One or more tests FAILED") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/select_parser.py0000644000000000000000000002134415134002420015477 0ustar00# select_parser.py # Copyright 2010,2019 Paul McGuire # # a simple SELECT statement parser, taken from SQLite's SELECT statement # definition at https://www.sqlite.org/lang_select.html # # fmt: off from pyparsing import ( pyparsing_common, ParserElement, OpAssoc, CaselessKeyword, Combine, Forward, Group, Literal, MatchFirst, Optional, QuotedString, Regex, Suppress, Word, alphanums, alphas, DelimitedList, infix_notation, nums, one_of, rest_of_line, autoname_elements ) # fmt: on ParserElement.enable_packrat() LPAR, RPAR, COMMA = map(Suppress, "(),") DOT, STAR = map(Literal, ".*") select_stmt = Forward().set_name("select statement") # keywords keywords = { k: CaselessKeyword(k) for k in """\ UNION ALL AND INTERSECT EXCEPT COLLATE ASC DESC ON USING NATURAL INNER CROSS LEFT OUTER JOIN AS INDEXED NOT SELECT DISTINCT FROM WHERE GROUP BY HAVING ORDER LIMIT OFFSET OR CAST ISNULL NOTNULL NULL IS BETWEEN ELSE END CASE WHEN THEN EXISTS IN LIKE GLOB REGEXP MATCH ESCAPE CURRENT_TIME CURRENT_DATE CURRENT_TIMESTAMP TRUE FALSE """.split() } vars().update(keywords) any_keyword = MatchFirst(keywords.values()).set_name("any_keyword") quoted_identifier = QuotedString('"', esc_quote='""') identifier = (~any_keyword + Word(alphas, alphanums + "_")).set_parse_action( pyparsing_common.downcase_tokens ).set_name("identifier") | quoted_identifier collation_name = identifier.copy() column_name = identifier.copy() column_alias = identifier.copy() table_name = identifier.copy() table_alias = identifier.copy() index_name = identifier.copy() function_name = identifier.copy() parameter_name = identifier.copy() database_name = identifier.copy() comment = "--" + rest_of_line # expression expr = Forward().set_name("expression") numeric_literal = pyparsing_common.number string_literal = QuotedString("'", esc_quote="''") blob_literal = Regex(r"[xX]'[0-9A-Fa-f]+'") literal_value = ( numeric_literal | string_literal | blob_literal | TRUE | FALSE | NULL | CURRENT_TIME | CURRENT_DATE | CURRENT_TIMESTAMP ) bind_parameter = Word("?", nums) | Combine(one_of(": @ $") + parameter_name) type_name = one_of("TEXT REAL INTEGER BLOB NULL") def concat_qualified_column(t): t[0][:] = ["".join(t[0])] expr_term = ( CAST + LPAR + expr + AS + type_name + RPAR | EXISTS + LPAR + select_stmt + RPAR | function_name.set_name("function_name") + LPAR + Optional(STAR | DelimitedList(expr)) + RPAR | literal_value | bind_parameter | Group( identifier("col_db") + DOT + identifier("col_tab") + DOT + identifier("col"), ).add_parse_action(concat_qualified_column).set_name("db_table_column name") | Group(identifier("col_tab") + DOT + identifier("col")).add_parse_action(concat_qualified_column).set_name("table_column name") | Group(identifier("col")).set_name("column name") ) NOT_NULL = Group(NOT + NULL) NOT_BETWEEN = Group(NOT + BETWEEN) NOT_IN = Group(NOT + IN) NOT_LIKE = Group(NOT + LIKE) NOT_MATCH = Group(NOT + MATCH) NOT_GLOB = Group(NOT + GLOB) NOT_REGEXP = Group(NOT + REGEXP) UNARY, BINARY, TERNARY = 1, 2, 3 expr <<= infix_notation( expr_term.set_name("expr_term"), [ (one_of("- + ~") | NOT, UNARY, OpAssoc.RIGHT), ((ISNULL | NOTNULL | NOT_NULL).set_name("null_comparison_operator"), UNARY, OpAssoc.LEFT), ("||", BINARY, OpAssoc.LEFT), (one_of("* / %"), BINARY, OpAssoc.LEFT), (one_of("+ -"), BINARY, OpAssoc.LEFT), (one_of("<< >> & |"), BINARY, OpAssoc.LEFT), (one_of("< <= > >="), BINARY, OpAssoc.LEFT), ( (one_of("= == != <>") | IS | IN | LIKE | GLOB | MATCH | REGEXP | NOT_IN | NOT_LIKE | NOT_GLOB | NOT_MATCH | NOT_REGEXP).set_name("comparison_operator"), BINARY, OpAssoc.LEFT, ), ((BETWEEN | NOT_BETWEEN, AND), TERNARY, OpAssoc.LEFT), ( (IN | NOT_IN) + LPAR + Group(select_stmt | DelimitedList(expr)) + RPAR, UNARY, OpAssoc.LEFT, ), (AND, BINARY, OpAssoc.LEFT), (OR, BINARY, OpAssoc.LEFT), ], ) compound_operator = UNION + Optional(ALL) | INTERSECT | EXCEPT ordering_term = Group( expr("order_key") + Optional(COLLATE + collation_name("collate")) + Optional(ASC | DESC)("direction") ) join_constraint = Group( Optional(ON + expr | USING + LPAR + Group(DelimitedList(column_name)) + RPAR) ) join_op = COMMA | Group( Optional(NATURAL) + Optional(INNER | CROSS | LEFT + OUTER | LEFT | OUTER) + JOIN ) join_source = Forward() single_source = ( Group(database_name("database") + DOT + table_name("table*") | table_name("table*")) + Optional(Optional(AS) + table_alias("table_alias*")) + Optional(INDEXED + BY + index_name("name") | NOT + INDEXED)("index") | (LPAR + select_stmt + RPAR + Optional(Optional(AS) + table_alias)) | (LPAR + join_source + RPAR) ) join_source <<= ( Group(single_source + (join_op + single_source + join_constraint)[1, ...]) | single_source ) # result_column = "*" | table_name + "." + "*" | Group(expr + Optional(Optional(AS) + column_alias)) result_column = Group( STAR("col") | table_name("col_table") + DOT + STAR("col") | expr("col") + Optional(Optional(AS) + column_alias("alias")) ) select_core = Group( SELECT + Optional(DISTINCT | ALL) + Group(DelimitedList(result_column))("columns") + Optional(FROM + join_source("from*")) + Optional(WHERE + expr("where_expr")) + Optional( GROUP + BY + Group(DelimitedList(ordering_term))("group_by_terms") + Optional(HAVING + expr("having_expr")) ) ) select_stmt <<= ( Group(select_core + (compound_operator + select_core)[...])("select_terms") + Optional(ORDER + BY + Group(DelimitedList(ordering_term))("order_by_terms")) + Optional( LIMIT + (Group(expr + OFFSET + expr) | Group(expr + COMMA + expr) | expr)("limit") ) ) select_stmt.ignore(comment) def main(): tests = """\ select * from xyzzy where z > 100 select * from xyzzy where z > 100 order by zz select * from xyzzy select z.* from xyzzy select a, b from test_table where 1=1 and b='yes' select a, b from test_table where 1=1 and b in (select bb from foo) select z.a, b from test_table where 1=1 and b in (select bb from foo) select z.a, b from test_table where 1=1 and b in (select bb from foo) order by b,c desc,d select z.a, b from test_table left join test2_table where 1=1 and b in (select bb from foo) select a, db.table.b as BBB from db.table where 1=1 and BBB='yes' select a, db.table.b as BBB from test_table,db.table where 1=1 and BBB='yes' select a, db.table.b as BBB from test_table,db.table where 1=1 and BBB='yes' limit 50 select a, b from test_table where (1=1 or 2=3) and b='yes' group by zx having b=2 order by 1 SELECT emp.ename as e FROM scott.employee as emp SELECT ename as e, fname as f FROM scott.employee as emp SELECT emp.eid, fname,lname FROM scott.employee as emp SELECT ename, lname, emp.eid FROM scott.employee as emp select emp.salary * (1.0 + emp.bonus) as salary_plus_bonus from scott.employee as emp SELECT * FROM abcd WHERE (ST_Overlaps("GEOM", 'POINT(0 0)')) SELECT * FROM abcd WHERE CAST(foo AS REAL) > -999.123 SELECT * FROM abcd WHERE bar BETWEEN +180 AND +10E9 SELECT * FROM abcd WHERE CAST(foo AS REAL) < (4 + -9.876E-4) SELECT SomeFunc(99) SELECT * FROM abcd WHERE ST_X(ST_Centroid(geom)) BETWEEN (-180*2) AND (180*2) SELECT * FROM abcd WHERE a SELECT * FROM abcd WHERE snowy_things REGEXP '[⛄️☃️☃🎿🏂🌨❄️⛷🏔🗻❄︎❆❅]' SELECT * FROM abcd WHERE a."b" IN 4 SELECT * FROM abcd WHERE a."b" In ('4') SELECT * FROM "a".b AS "E" WHERE "E"."C" >= CURRENT_Time SELECT * FROM abcd WHERE "dave" != "Dave" -- names & things ☃️ SELECT * FROM a WHERE a.dave is not null SELECT * FROM abcd WHERE pete == FALSE or peter is true SELECT * FROM abcd WHERE a >= 10 * (2 + 3) SELECT * FROM abcd WHERE frank = 'is ''scary''' SELECT * FROM abcd WHERE "identifier with ""quotes"" and a trailing space " IS NOT FALSE SELECT * FROM abcd WHERE blobby == x'C0FFEE' -- hex SELECT * FROM abcd WHERE ff NOT IN (1,2,4,5) SELECT * FROM abcd WHERE ff not between 3 and 9 SELECT * FROM abcd WHERE db_name.tab_name.ff not like 'bob%' """ success, _ = select_stmt.run_tests(tests) print("\n{}".format("OK" if success else "FAIL")) return 0 if success else 1 if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/sexpParser.py0000644000000000000000000001237515134002420015004 0ustar00# sexpParser.py # # Demonstration of the pyparsing module, implementing a simple S-expression # parser. # # Updates: # November, 2011 - fixed errors in precedence of alternatives in simpleString; # fixed exception raised in verifyLen to properly signal the input string # and exception location so that markInputline works correctly; fixed # definition of decimal to accept a single '0' and optional leading '-' # sign; updated tests to improve parser coverage # # Copyright 2007-2011, by Paul McGuire # """ BNF reference: http://theory.lcs.mit.edu/~rivest/sexp.txt :: | :: ? ; :: | | | | ; :: "[" "]" ; :: ":" ; :: + ; -- decimal numbers should have no unnecessary leading zeros -- any string of bytes, of the indicated length :: + ; :: ? "|" ( | )* "|" ; :: "#" ( | )* "#" ; :: ? :: "\"" "\"" :: "(" ( | )* ")" ; :: * ; :: | | ; :: | | ; :: "a" | ... | "z" ; :: "A" | ... | "Z" ; :: "0" | ... | "9" ; :: | "A" | ... | "F" | "a" | ... | "f" ; :: "-" | "." | "/" | "_" | ":" | "*" | "+" | "=" ; :: " " | "\t" | "\r" | "\n" ; :: | | "+" | "/" | "=" ; :: "" ; """ import pyparsing as pp from base64 import b64decode def verify_length(s, l, t): t = t[0] if t.len is not None: t1len = len(t[1]) if t1len != t.len: raise pp.ParseFatalException( s, l, "invalid data of length {}, expected {}".format(t1len, t.len) ) return t[1] # define punctuation literals LPAR, RPAR, LBRK, RBRK, LBRC, RBRC, VBAR, COLON = ( pp.Suppress(c).set_name(c) for c in "()[]{}|:" ) decimal = pp.Regex(r"-?0|[1-9]\d*").set_parse_action(lambda t: int(t[0])) hexadecimal = ("#" + pp.Word(pp.hexnums)[1, ...] + "#").set_parse_action( lambda t: int("".join(t[1:-1]), 16) ) bytes = pp.Word(pp.printables) raw = pp.Group(decimal("len") + COLON + bytes).set_parse_action(verify_length) base64_ = pp.Group( pp.Optional(decimal | hexadecimal, default=None)("len") + VBAR + pp.Word(pp.alphanums + "+/=")[1, ...].set_parse_action( lambda t: b64decode("".join(t)) ) + VBAR ).set_parse_action(verify_length) real = pp.Regex(r"[+-]?\d+\.\d*([eE][+-]?\d+)?").set_parse_action( lambda tokens: float(tokens[0]) ) token = pp.Word(pp.alphanums + "-./_:*+=!<>") qString = pp.Group( pp.Optional(decimal, default=None)("len") + pp.dbl_quoted_string.set_parse_action(pp.remove_quotes) ).set_parse_action(verify_length) simpleString = real | base64_ | raw | decimal | token | hexadecimal | qString display = LBRK + simpleString + RBRK string_ = pp.Optional(display) + simpleString sexp = pp.Forward() sexpList = pp.Group(LPAR + sexp[...] + RPAR) sexp <<= string_ | sexpList def main(): # Test data test00 = """(snicker "abc" (#03# |YWJj|))""" test01 = """(certificate (issuer (name (public-key rsa-with-md5 (e 15 |NFGq/E3wh9f4rJIQVXhS|) (n |d738/4ghP9rFZ0gAIYZ5q9y6iskDJwASi5rEQpEQq8ZyMZeIZzIAR2I5iGE=|)) aid-committee)) (subject (ref (public-key rsa-with-md5 (e |NFGq/E3wh9f4rJIQVXhS|) (n |d738/4ghP9rFZ0gAIYZ5q9y6iskDJwASi5rEQpEQq8ZyMZeIZzIAR2I5iGE=|)) tom mother)) (not-before "1997-01-01_09:00:00") (not-after "1998-01-01_09:00:00") (tag (spend (account "12345678") (* numeric range "1" "1000")))) """ test02 = """(lambda (x) (* x x))""" test03 = """(def length (lambda (x) (cond ((not x) 0) ( t (+ 1 (length (cdr x)))) ) ) ) """ test04 = """(2:XX "abc" (#03# |YWJj|))""" test05 = """(if (is (window_name) "XMMS") (set_workspace 2))""" test06 = """(if (and (is (application_name) "Firefox") (or (contains (window_name) "Enter name of file to save to") (contains (window_name) "Save As") (contains (window_name) "Save Image") () ) ) (geometry "+140+122") ) """ test07 = """(defun factorial (x) (if (zerop x) 1 (* x (factorial (- x 1))))) """ test51 = """(2:XX "abc" (#03# |YWJj|))""" test51error = """(3:XX "abc" (#03# |YWJj|))""" test52 = """ (and (or (> uid 1000) (!= gid 20) ) (> quota 5.0e+03) ) """ # Run tests local_vars = sorted(locals().items()) alltests = [ test_fn for testname, test_fn in local_vars if testname.startswith("test") ] sexp.run_tests(alltests, full_dump=False) if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/shapes.py0000644000000000000000000000331115134002420014121 0ustar00# shapes.py # # A sample program showing how parse actions can convert parsed # strings into a data type or object. # # Copyright 2012, 2019 Paul T. McGuire # # define class hierarchy of Shape classes, with polymorphic area method class Shape: def __init__(self, tokens): self.__dict__.update(tokens.as_dict()) def area(self): raise NotImplemented() def __str__(self): return "<{}>: {}".format(self.__class__.__name__, vars(self)) class Square(Shape): def area(self): return self.side ** 2 class Rectangle(Shape): def area(self): return self.width * self.height class Circle(Shape): def area(self): return 3.14159 * self.radius ** 2 import pyparsing as pp ppc = pp.pyparsing_common # use pyparsing-defined numeric expression that converts all parsed # numeric values as floats number = ppc.fnumber() # Shape expressions: # square : S # rectangle: R # circle : C squareDefn = "S" + number("centerx") + number("centery") + number("side") rectDefn = ( "R" + number("centerx") + number("centery") + number("width") + number("height") ) circleDefn = "C" + number("centerx") + number("centery") + number("diameter") squareDefn.set_parse_action(Square) rectDefn.set_parse_action(Rectangle) def computeRadius(tokens): tokens["radius"] = tokens.diameter / 2.0 circleDefn.set_parse_action(computeRadius, Circle) shapeExpr = squareDefn | rectDefn | circleDefn tests = """\ C 0 0 100 R 10 10 20 50 S -1 5 10""".splitlines() for t in tests: shape = shapeExpr.parse_string(t)[0] print(shape) print("Area:", shape.area()) print() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/simpleArith.py0000644000000000000000000000467315134002420015133 0ustar00# # simpleArith.py # # Example of defining an arithmetic expression parser using # the infix_notation helper method in pyparsing. # # Copyright 2006, by Paul McGuire # import sys from pyparsing import * ppc = pyparsing_common ParserElement.enable_packrat() sys.setrecursionlimit(3000) integer = ppc.integer variable = Word(alphas, exact=1) operand = integer | variable expop = Literal("^") signop = one_of("+ -") multop = one_of("* /") plusop = one_of("+ -") factop = Literal("!") # To use the infix_notation helper: # 1. Define the "atom" operand term of the grammar. # For this simple grammar, the smallest operand is either # an integer or a variable. This will be the first argument # to the infix_notation method. # 2. Define a list of tuples for each level of operator # precedence. Each tuple is of the form # (opExpr, numTerms, rightLeftAssoc, parseAction), where # - opExpr is the pyparsing expression for the operator; # may also be a string, which will be converted to a Literal # - numTerms is the number of terms for this operator (must # be 1 or 2) # - rightLeftAssoc is the indicator whether the operator is # right or left associative, using the pyparsing-defined # constants OpAssoc.RIGHT and OpAssoc.LEFT. # - parseAction is the parse action to be associated with # expressions matching this operator expression (the # parse action tuple member may be omitted) # 3. Call infix_notation passing the operand expression and # the operator precedence list, and save the returned value # as the generated pyparsing expression. You can then use # this expression to parse input strings, or incorporate it # into a larger, more complex grammar. # expr = infix_notation( operand, [ (factop, 1, OpAssoc.LEFT), (expop, 2, OpAssoc.RIGHT), (signop, 1, OpAssoc.RIGHT), (multop, 2, OpAssoc.LEFT), (plusop, 2, OpAssoc.LEFT), ], ) test = [ "9 + 2 + 3", "9 + 2 * 3", "(9 + 2) * 3", "(9 + -2) * 3", "(9 + -2) * 3^2^2", "(9! + -2) * 3^2^2", "M*X + B", "M*(X + B)", "1+2*-3^4*5+-+-6", "(a + b)", "((a + b))", "(((a + b)))", "((((a + b))))", "((((((((((((((a + b))))))))))))))", ] for t in test: print(t) print(expr.parse_string(t)) print("") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/simpleBool.py0000644000000000000000000000631415134002420014751 0ustar00# # simpleBool.py # # Example of defining a boolean logic parser using # the operatorGrammar helper method in pyparsing. # # In this example, parse actions associated with each # operator expression will "compile" the expression # into BoolXXX class instances, which can then # later be evaluated for their boolean value. # # Copyright 2006, by Paul McGuire # Updated 2013-Sep-14 - improved Python 2/3 cross-compatibility # Updated 2021-Sep-27 - removed Py2 compat; added type annotations # from typing import Callable, Iterable from pyparsing import infix_notation, OpAssoc, Keyword, Word, alphas, ParserElement ParserElement.enable_packrat() # define classes to be built at parse time, as each matching # expression type is parsed class BoolOperand: def __init__(self, t): self.label = t[0] self.value = eval(t[0]) def __bool__(self) -> bool: return self.value def __str__(self) -> str: return self.label __repr__ = __str__ class BoolNot: def __init__(self, t): self.arg = t[0][1] def __bool__(self) -> bool: v = bool(self.arg) return not v def __str__(self) -> str: return "~" + str(self.arg) __repr__ = __str__ class BoolBinOp: repr_symbol: str = "" eval_fn: Callable[ [Iterable[bool]], bool ] = lambda _: False def __init__(self, t): self.args = t[0][0::2] def __str__(self) -> str: sep = f" {self.repr_symbol} " return f"({sep.join(map(str, self.args))})" def __bool__(self) -> bool: return self.eval_fn(bool(a) for a in self.args) class BoolAnd(BoolBinOp): repr_symbol = "&" eval_fn = all class BoolOr(BoolBinOp): repr_symbol = "|" eval_fn = any # define keywords and simple infix notation grammar for boolean # expressions TRUE = Keyword("True") FALSE = Keyword("False") NOT = Keyword("not") AND = Keyword("and") OR = Keyword("or") boolOperand = TRUE | FALSE | Word(alphas, max=1) boolOperand.set_parse_action(BoolOperand).set_name("bool_operand") # define expression, based on expression operand and # list of operations in precedence order boolExpr = infix_notation( boolOperand, [ (NOT, 1, OpAssoc.RIGHT, BoolNot), (AND, 2, OpAssoc.LEFT, BoolAnd), (OR, 2, OpAssoc.LEFT, BoolOr), ], ).set_name("boolean_expression") if __name__ == "__main__": p = True q = False r = True tests = [ ("p", True), ("q", False), ("p and q", False), ("p and not q", True), ("not not p", True), ("not(p and q)", True), ("q or not p and r", False), ("q or not p or not r", False), ("q or not (p and r)", False), ("p or q or r", True), ("p or q or r and False", True), ("(p or q or r) and False", False), ] print("p =", p) print("q =", q) print("r =", r) print() for test_string, expected in tests: res = boolExpr.parse_string(test_string)[0] success = "PASS" if bool(res) == expected else "FAIL" print(test_string, "\n", res, "=", bool(res), "\n", success, "\n") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/simpleSQL.py0000644000000000000000000000630015134002420014510 0ustar00# simpleSQL.py # # simple demo of using the parsing library to do simple-minded SQL parsing # could be extended to include where clauses etc. # # Copyright (c) 2003,2016, Paul McGuire # from pyparsing import ( Word, DelimitedList, Optional, Group, alphas, alphanums, Forward, one_of, quoted_string, infix_notation, OpAssoc, rest_of_line, CaselessKeyword, ParserElement, pyparsing_common as ppc, ) ParserElement.enable_packrat() # define SQL tokens selectStmt = Forward() SELECT, FROM, WHERE, AND, OR, IN, IS, NOT, NULL = map( CaselessKeyword, "select from where and or in is not null".split() ) NOT_NULL = NOT + NULL ident = Word(alphas, alphanums + "_$").set_name("identifier") columnName = DelimitedList(ident, ".", combine=True).set_name("column name") columnName.add_parse_action(ppc.upcase_tokens) columnNameList = Group(DelimitedList(columnName).set_name("column_list")) tableName = DelimitedList(ident, ".", combine=True).set_name("table name") tableName.add_parse_action(ppc.upcase_tokens) tableNameList = Group(DelimitedList(tableName).set_name("table_list")) binop = one_of("= != < > >= <= eq ne lt le gt ge", caseless=True).set_name("binop") realNum = ppc.real().set_name("real number") intNum = ppc.signed_integer() columnRval = ( realNum | intNum | quoted_string | columnName ).set_name("column_rvalue") # need to add support for alg expressions whereCondition = Group( (columnName + binop + columnRval) | (columnName + IN + Group("(" + DelimitedList(columnRval).set_name("in_values_list") + ")")) | (columnName + IN + Group("(" + selectStmt + ")")) | (columnName + IS + (NULL | NOT_NULL)) ).set_name("where_condition") whereExpression = infix_notation( whereCondition, [ (NOT, 1, OpAssoc.RIGHT), (AND, 2, OpAssoc.LEFT), (OR, 2, OpAssoc.LEFT), ], ).set_name("where_expression") # define the grammar selectStmt <<= ( SELECT + ("*" | columnNameList)("columns") + FROM + tableNameList("tables") + Optional(Group(WHERE + whereExpression), "")("where") ).set_name("select_statement") simpleSQL = selectStmt # define Oracle comment format, and ignore them oracleSqlComment = "--" + rest_of_line simpleSQL.ignore(oracleSqlComment) if __name__ == "__main__": simpleSQL.run_tests( """\ # multiple tables SELECT * from XYZZY, ABC # dotted table name select * from SYS.XYZZY Select A from Sys.dual Select A,B,C from Sys.dual Select A, B, C from Sys.dual, Table2 # FAIL - invalid SELECT keyword Xelect A, B, C from Sys.dual # FAIL - invalid FROM keyword Select A, B, C frox Sys.dual # FAIL - incomplete statement Select # FAIL - incomplete statement Select * from # FAIL - invalid column Select &&& frox Sys.dual # where clause Select A from Sys.dual where a in ('RED','GREEN','BLUE') # compound where clause Select A from Sys.dual where a in ('RED','GREEN','BLUE') and b in (10,20,30) # where clause with comparison operator Select A,b from table1,table2 where table1.id eq table2.id """ ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/simpleWiki.py0000644000000000000000000000213715134002420014760 0ustar00from pyparsing import * wikiInput = """ Here is a simple Wiki input: *This is in italics.* **This is in bold!** ***This is in bold italics!*** Here's a URL to {{Pyparsing's Wiki Page->https://site-closed.wikispaces.com}} """ def convertToHTML(opening, closing): def conversionParseAction(s, l, t): return opening + t[0] + closing return conversionParseAction italicized = QuotedString("*").set_parse_action(convertToHTML("", "")) bolded = QuotedString("**").set_parse_action(convertToHTML("", "")) boldItalicized = QuotedString("***").set_parse_action(convertToHTML("", "")) def convertToHTML_A(s, l, t): try: text, url = t[0].split("->") except ValueError: raise ParseFatalException(s, l, "invalid URL link reference: " + t[0]) return '{}'.format(url, text) urlRef = QuotedString("{{", end_quote_char="}}").set_parse_action(convertToHTML_A) wikiMarkup = urlRef | boldItalicized | bolded | italicized print(wikiInput) print() print(wikiMarkup.transform_string(wikiInput)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/snmp_api.h0000644000000000000000000007127715134002420014263 0ustar00#ifndef SNMP_API_H #define SNMP_API_H /* * snmp_api.h - API for access to snmp. * * Caution: when using this library in a multi-threaded application, * the values of global variables "snmp_errno" and "snmp_detail" * cannot be reliably determined. Suggest using snmp_error() * to obtain the library error codes. */ #ifndef DONT_SHARE_ERROR_WITH_OTHER_THREADS #define SET_SNMP_ERROR(x) snmp_errno=(x) #else #define SET_SNMP_ERROR(x) #endif #ifdef __cplusplus extern "C" { #endif /*********************************************************** Copyright 1989 by Carnegie Mellon University All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of CMU not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ struct variable_list; struct timeval; /* * Mimic size and alignment of 'struct sockaddr_storage' (see RFC 2553) * But retain field names of traditional 'struct sockaddr' */ #define _UCD_SS_MAXSIZE 92 /* <= sizeof( sockaddr_un ) */ #define _UCD_SS_ALIGNSIZE (sizeof (long)) #define _UCD_SS_PAD1SIZE (_UCD_SS_ALIGNSIZE - sizeof( unsigned short )) #define _UCD_SS_PAD2SIZE (_UCD_SS_MAXSIZE - \ (sizeof( unsigned short ) + _UCD_SS_PAD1SIZE + _UCD_SS_ALIGNSIZE )) typedef struct { #ifdef STRUCT_SOCKADDR_HAS_SA_UNION_SA_GENERIC_SA_FAMILY2 /* * Certain systems (notably Irix 6.x) have a non-traditional * socket structure, and #define the traditional field names. * This local definition should reproduce this structure, and still * be large enough to handle any necessary Unix domain addresses. */ union { struct { #ifdef _HAVE_SA_LEN unsigned char sa_len2; unsigned char sa_family2; #else unsigned short sa_family2; #endif char sa_data2[ _UCD_SS_PAD1SIZE ]; } sa_generic; long sa_align; char sa_pad2[ _UCD_SS_PAD2SIZE ]; } sa_union; #else #ifdef STRUCT_SOCKADDR_HAS_SA_LEN unsigned char sa_len; unsigned char sa_family; #else unsigned short sa_family; #endif char sa_data[ _UCD_SS_PAD1SIZE ]; long sa_align; char sa_pad2[ _UCD_SS_PAD2SIZE ]; #endif } snmp_ipaddr; #define USM_AUTH_KU_LEN 32 #define USM_PRIV_KU_LEN 32 struct snmp_pdu { /* * Protocol-version independent fields */ long version; int command; /* Type of this PDU */ long reqid; /* Request id - note: not incremented on retries */ long msgid; /* Message id for V3 messages * note: incremented for each retry */ long transid; /* Unique ID for incoming transactions */ long sessid; /* Session id for AgentX messages */ long errstat; /* Error status (non_repeaters in GetBulk) */ long errindex; /* Error index (max_repetitions in GetBulk) */ u_long time; /* Uptime */ u_long flags; int securityModel; int securityLevel; /* noAuthNoPriv, authNoPriv, authPriv */ int msgParseModel; snmp_ipaddr address; /* Address of peer or trap destination */ struct variable_list *variables; /* * SNMPv1 & SNMPv2c fields */ u_char *community; /* community for outgoing requests. */ size_t community_len; /* Length of community name. */ /* * Trap information */ oid *enterprise; /* System OID */ size_t enterprise_length; long trap_type; /* trap type */ long specific_type; /* specific type */ snmp_ipaddr agent_addr; /* * SNMPv3 fields */ u_char *contextEngineID; /* context snmpEngineID */ size_t contextEngineIDLen; /* Length of contextEngineID */ char *contextName; /* authoritative contextName */ size_t contextNameLen; /* Length of contextName */ u_char *securityEngineID; /* authoritative snmpEngineID for security */ size_t securityEngineIDLen;/* Length of securityEngineID */ char *securityName; /* on behalf of this principal */ size_t securityNameLen; /* Length of securityName. */ /* * AgentX fields * (also uses SNMPv1 community field) */ int priority; int range_subid; void * securityStateRef; }; struct snmp_session; typedef int (*snmp_callback) (int, struct snmp_session *, int, struct snmp_pdu *, void *); struct snmp_session { /* * Protocol-version independent fields */ long version; int retries; /* Number of retries before timeout. */ long timeout; /* Number of uS until first timeout, then exponential backoff */ u_long flags; struct snmp_session *subsession; struct snmp_session *next; char *peername; /* Domain name or dotted IP address of default peer */ u_short remote_port;/* UDP port number of peer. */ u_short local_port; /* My UDP port number, 0 for default, picked randomly */ /* Authentication function or NULL if null authentication is used */ u_char *(*authenticator) (u_char *, size_t *, u_char *, size_t); snmp_callback callback; /* Function to interpret incoming data */ /* Pointer to data that the callback function may consider important */ void *callback_magic; int s_errno; /* copy of system errno */ int s_snmp_errno; /* copy of library errno */ long sessid; /* Session id - AgentX only */ /* * SNMPv1 & SNMPv2c fields */ u_char *community; /* community for outgoing requests. */ size_t community_len; /* Length of community name. */ /* * SNMPv3 fields */ u_char isAuthoritative; /* are we the authoritative engine? */ u_char *contextEngineID; /* authoritative snmpEngineID */ size_t contextEngineIDLen; /* Length of contextEngineID */ u_int engineBoots; /* initial engineBoots for remote engine */ u_int engineTime; /* initial engineTime for remote engine */ char *contextName; /* authoritative contextName */ size_t contextNameLen; /* Length of contextName */ u_char *securityEngineID; /* authoritative snmpEngineID */ size_t securityEngineIDLen; /* Length of contextEngineID */ char *securityName; /* on behalf of this principal */ size_t securityNameLen; /* Length of securityName. */ oid *securityAuthProto; /* auth protocol oid */ size_t securityAuthProtoLen; /* Length of auth protocol oid */ u_char securityAuthKey[USM_AUTH_KU_LEN]; /* Ku for auth protocol XXX */ size_t securityAuthKeyLen; /* Length of Ku for auth protocol */ oid *securityPrivProto; /* priv protocol oid */ size_t securityPrivProtoLen; /* Length of priv protocol oid */ u_char securityPrivKey[USM_PRIV_KU_LEN]; /* Ku for privacy protocol XXX */ size_t securityPrivKeyLen; /* Length of Ku for priv protocol */ int securityModel; int securityLevel; /* noAuthNoPriv, authNoPriv, authPriv */ }; /* * A list of all the outstanding requests for a particular session. */ #ifdef SNMP_NEED_REQUEST_LIST struct request_list { struct request_list *next_request; long request_id; /* request id */ long message_id; /* message id */ snmp_callback callback; /* user callback per request (NULL if unused) */ void *cb_data; /* user callback data per request (NULL if unused) */ int retries; /* Number of retries */ u_long timeout; /* length to wait for timeout */ struct timeval time; /* Time this request was made */ struct timeval expire; /* time this request is due to expire */ struct snmp_session *session; struct snmp_pdu *pdu; /* The pdu for this request (saved so it can be retransmitted */ }; #endif /* SNMP_NEED_REQUEST_LIST */ /* * Set fields in session and pdu to the following to get a default or unconfigured value. */ #define SNMP_DEFAULT_COMMUNITY_LEN 0 /* to get a default community name */ #define SNMP_DEFAULT_RETRIES -1 #define SNMP_DEFAULT_TIMEOUT -1 #define SNMP_DEFAULT_REMPORT 0 #define SNMP_DEFAULT_REQID -1 #define SNMP_DEFAULT_MSGID -1 #define SNMP_DEFAULT_ERRSTAT -1 #define SNMP_DEFAULT_ERRINDEX -1 #define SNMP_DEFAULT_ADDRESS 0 #define SNMP_DEFAULT_PEERNAME NULL #define SNMP_DEFAULT_ENTERPRISE_LENGTH 0 #define SNMP_DEFAULT_TIME 0 #define SNMP_DEFAULT_VERSION -1 #define SNMP_DEFAULT_CONTEXT "" #define SNMP_DEFAULT_AUTH_PROTO usmHMACMD5AuthProtocol #define SNMP_DEFAULT_AUTH_PROTOLEN USM_LENGTH_OID_TRANSFORM #define SNMP_DEFAULT_PRIV_PROTO usmDESPrivProtocol #define SNMP_DEFAULT_PRIV_PROTOLEN USM_LENGTH_OID_TRANSFORM extern const char *snmp_api_errstring (int); extern void snmp_perror (const char *); extern void snmp_set_detail (const char *); #define SNMP_MAX_MSG_SIZE 1472 /* ethernet MTU minus IP/UDP header */ #define SNMP_MAX_MSG_V3_HDRS (4+3+4+7+7+3+7+16) /* fudge factor=16 */ #define SNMP_MAX_ENG_SIZE 32 #define SNMP_MAX_SEC_NAME_SIZE 256 #define SNMP_MAX_CONTEXT_SIZE 256 #define SNMP_SEC_PARAM_BUF_SIZE 256 /* set to one to ignore unauthenticated Reports */ #define SNMPV3_IGNORE_UNAUTH_REPORTS 0 /* authoritative engine definitions */ #define SNMP_SESS_NONAUTHORITATIVE 0 /* should be 0 to default to this */ #define SNMP_SESS_AUTHORITATIVE 1 /* don't learn engineIDs */ #define SNMP_SESS_UNKNOWNAUTH 2 /* sometimes (like NRs) */ /* to determine type of Report from varbind_list */ #define REPORT_STATS_LEN 9 #define REPORT_snmpUnknownSecurityModels_NUM 1 #define REPORT_snmpInvalidMsgs_NUM 2 #define REPORT_usmStatsUnsupportedSecLevels_NUM 1 #define REPORT_usmStatsNotInTimeWindows_NUM 2 #define REPORT_usmStatsUnknownUserNames_NUM 3 #define REPORT_usmStatsUnknownEngineIDs_NUM 4 #define REPORT_usmStatsWrongDigests_NUM 5 #define REPORT_usmStatsDecryptionErrors_NUM 6 #define SNMP_DETAIL_SIZE 512 #define SNMP_FLAGS_DONT_PROBE 0x100 /* don't probe for an engineID */ #define SNMP_FLAGS_STREAM_SOCKET 0x80 #define SNMP_FLAGS_LISTENING 0x40 /* Server stream sockets only */ #define SNMP_FLAGS_SUBSESSION 0x20 #define SNMP_FLAGS_STRIKE2 0x02 #define SNMP_FLAGS_STRIKE1 0x01 #define CLEAR_SNMP_STRIKE_FLAGS(x) \ x &= ~(SNMP_FLAGS_STRIKE2|SNMP_FLAGS_STRIKE1) /* * returns '1' if the session is to be regarded as dead, * otherwise set the strike flags appropriately, and return 0 */ #define SET_SNMP_STRIKE_FLAGS(x) \ (( x & SNMP_FLAGS_STRIKE2 ) ? 1 : \ ((( x & SNMP_FLAGS_STRIKE1 ) ? ( x |= SNMP_FLAGS_STRIKE2 ) : \ ( x |= SNMP_FLAGS_STRIKE1 )), \ 0)) /* * Error return values. * * SNMPERR_SUCCESS is the non-PDU "success" code. * * XXX These should be merged with SNMP_ERR_* defines and confined * to values < 0. ??? */ #define SNMPERR_SUCCESS (0) /* XXX Non-PDU "success" code. */ #define SNMPERR_GENERR (-1) #define SNMPERR_BAD_LOCPORT (-2) #define SNMPERR_BAD_ADDRESS (-3) #define SNMPERR_BAD_SESSION (-4) #define SNMPERR_TOO_LONG (-5) #define SNMPERR_NO_SOCKET (-6) #define SNMPERR_V2_IN_V1 (-7) #define SNMPERR_V1_IN_V2 (-8) #define SNMPERR_BAD_REPEATERS (-9) #define SNMPERR_BAD_REPETITIONS (-10) #define SNMPERR_BAD_ASN1_BUILD (-11) #define SNMPERR_BAD_SENDTO (-12) #define SNMPERR_BAD_PARSE (-13) #define SNMPERR_BAD_VERSION (-14) #define SNMPERR_BAD_SRC_PARTY (-15) #define SNMPERR_BAD_DST_PARTY (-16) #define SNMPERR_BAD_CONTEXT (-17) #define SNMPERR_BAD_COMMUNITY (-18) #define SNMPERR_NOAUTH_DESPRIV (-19) #define SNMPERR_BAD_ACL (-20) #define SNMPERR_BAD_PARTY (-21) #define SNMPERR_ABORT (-22) #define SNMPERR_UNKNOWN_PDU (-23) #define SNMPERR_TIMEOUT (-24) #define SNMPERR_BAD_RECVFROM (-25) #define SNMPERR_BAD_ENG_ID (-26) #define SNMPERR_BAD_SEC_NAME (-27) #define SNMPERR_BAD_SEC_LEVEL (-28) #define SNMPERR_ASN_PARSE_ERR (-29) #define SNMPERR_UNKNOWN_SEC_MODEL (-30) #define SNMPERR_INVALID_MSG (-31) #define SNMPERR_UNKNOWN_ENG_ID (-32) #define SNMPERR_UNKNOWN_USER_NAME (-33) #define SNMPERR_UNSUPPORTED_SEC_LEVEL (-34) #define SNMPERR_AUTHENTICATION_FAILURE (-35) #define SNMPERR_NOT_IN_TIME_WINDOW (-36) #define SNMPERR_DECRYPTION_ERR (-37) #define SNMPERR_SC_GENERAL_FAILURE (-38) #define SNMPERR_SC_NOT_CONFIGURED (-39) #define SNMPERR_KT_NOT_AVAILABLE (-40) #define SNMPERR_UNKNOWN_REPORT (-41) #define SNMPERR_USM_GENERICERROR (-42) #define SNMPERR_USM_UNKNOWNSECURITYNAME (-43) #define SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL (-44) #define SNMPERR_USM_ENCRYPTIONERROR (-45) #define SNMPERR_USM_AUTHENTICATIONFAILURE (-46) #define SNMPERR_USM_PARSEERROR (-47) #define SNMPERR_USM_UNKNOWNENGINEID (-48) #define SNMPERR_USM_NOTINTIMEWINDOW (-49) #define SNMPERR_USM_DECRYPTIONERROR (-50) #define SNMPERR_NOMIB (-51) #define SNMPERR_RANGE (-52) #define SNMPERR_MAX_SUBID (-53) #define SNMPERR_BAD_SUBID (-54) #define SNMPERR_LONG_OID (-55) #define SNMPERR_BAD_NAME (-56) #define SNMPERR_VALUE (-57) #define SNMPERR_UNKNOWN_OBJID (-58) #define SNMPERR_NULL_PDU (-59) #define SNMPERR_NO_VARS (-60) #define SNMPERR_VAR_TYPE (-61) #define SNMPERR_MALLOC (-62) #define SNMPERR_MAX (-62) #define non_repeaters errstat #define max_repetitions errindex struct variable_list { struct variable_list *next_variable; /* NULL for last variable */ oid *name; /* Object identifier of variable */ size_t name_length; /* number of subid's in name */ u_char type; /* ASN type of variable */ union { /* value of variable */ long *integer; u_char *string; oid *objid; u_char *bitstring; struct counter64 *counter64; #ifdef OPAQUE_SPECIAL_TYPES float *floatVal; double *doubleVal; /* t_union *unionVal; */ #endif /* OPAQUE_SPECIAL_TYPES */ } val; size_t val_len; oid name_loc[MAX_OID_LEN]; /* 90 percentile < 24. */ u_char buf[40]; /* 90 percentile < 40. */ void *data; /* (Opaque) hook for additional data */ int index; }; /* * struct snmp_session *snmp_open(session) * struct snmp_session *session; * * Sets up the session with the snmp_session information provided * by the user. Then opens and binds the necessary UDP port. * A handle to the created session is returned (this is different than * the pointer passed to snmp_open()). On any error, NULL is returned * and snmp_errno is set to the appropriate error code. */ struct snmp_session *snmp_open (struct snmp_session *); /* * int snmp_close(session) * struct snmp_session *session; * * Close the input session. Frees all data allocated for the session, * dequeues any pending requests, and closes any sockets allocated for * the session. Returns 0 on error, 1 otherwise. * * snmp_close_sessions() does the same thing for all open sessions */ int snmp_close (struct snmp_session *); int snmp_close_sessions (void); /* * int snmp_send(session, pdu) * struct snmp_session *session; * struct snmp_pdu *pdu; * * Sends the input pdu on the session after calling snmp_build to create * a serialized packet. If necessary, set some of the pdu data from the * session defaults. Add a request corresponding to this pdu to the list * of outstanding requests on this session, then send the pdu. * Returns the request id of the generated packet if applicable, otherwise 1. * On any error, 0 is returned. * The pdu is freed by snmp_send() unless a failure occurred. */ int snmp_send (struct snmp_session *, struct snmp_pdu *); /* * int snmp_async_send(session, pdu, callback, cb_data) * struct snmp_session *session; * struct snmp_pdu *pdu; * snmp_callback callback; * void *cb_data; * * Sends the input pdu on the session after calling snmp_build to create * a serialized packet. If necessary, set some of the pdu data from the * session defaults. Add a request corresponding to this pdu to the list * of outstanding requests on this session and store callback and data, * then send the pdu. * Returns the request id of the generated packet if applicable, otherwise 1. * On any error, 0 is returned. * The pdu is freed by snmp_send() unless a failure occurred. */ int snmp_async_send (struct snmp_session *, struct snmp_pdu *, snmp_callback, void *); /* * void snmp_read(fdset) * fd_set *fdset; * * Checks to see if any of the fd's set in the fdset belong to * snmp. Each socket with it's fd set has a packet read from it * and snmp_parse is called on the packet received. The resulting pdu * is passed to the callback routine for that session. If the callback * routine returns successfully, the pdu and it's request are deleted. */ void snmp_read (fd_set *); /* * void * snmp_free_pdu(pdu) * struct snmp_pdu *pdu; * * Frees the pdu and any malloc'd data associated with it. */ void snmp_free_pdu (struct snmp_pdu *); void snmp_free_var (struct variable_list *); /* frees just this one */ void snmp_free_varbind(struct variable_list *var); /* frees all in list */ /* * int snmp_select_info(numfds, fdset, timeout, block) * int *numfds; * fd_set *fdset; * struct timeval *timeout; * int *block; * * Returns info about what snmp requires from a select statement. * numfds is the number of fds in the list that are significant. * All file descriptors opened for SNMP are OR'd into the fdset. * If activity occurs on any of these file descriptors, snmp_read * should be called with that file descriptor set. * * The timeout is the latest time that SNMP can wait for a timeout. The * select should be done with the minimum time between timeout and any other * timeouts necessary. This should be checked upon each invocation of select. * If a timeout is received, snmp_timeout should be called to check if the * timeout was for SNMP. (snmp_timeout is idempotent) * * Block is 1 if the select is requested to block indefinitely, rather than * time out. If block is input as 1, the timeout value will be treated as * undefined, but it must be available for setting in snmp_select_info. On * return, if block is true, the value of timeout will be undefined. * * snmp_select_info returns the number of open sockets. (i.e. The number * of sessions open) */ int snmp_select_info (int *, fd_set *, struct timeval *, int *); /* * void snmp_timeout(); * * snmp_timeout should be called whenever the timeout from snmp_select_info * expires, but it is idempotent, so snmp_timeout can be polled (probably a * cpu expensive proposition). snmp_timeout checks to see if any of the * sessions have an outstanding request that has timed out. If it finds one * (or more), and that pdu has more retries available, a new packet is formed * from the pdu and is resent. If there are no more retries available, the * callback for the session is used to alert the user of the timeout. */ void snmp_timeout (void); /* * This routine must be supplied by the application: * * u_char *authenticator(pdu, length, community, community_len) * u_char *pdu; The rest of the PDU to be authenticated * int *length; The length of the PDU (updated by the authenticator) * u_char *community; The community name to authenticate under. * int community_len The length of the community name. * * Returns the authenticated pdu, or NULL if authentication failed. * If null authentication is used, the authenticator in snmp_session can be * set to NULL(0). */ /* * This routine must be supplied by the application: * * int callback(operation, session, reqid, pdu, magic) * int operation; * struct snmp_session *session; The session authenticated under. * int reqid; The request id of this pdu (0 for TRAP) * struct snmp_pdu *pdu; The pdu information. * void *magic A link to the data for this routine. * * Returns 1 if request was successful, 0 if it should be kept pending. * Any data in the pdu must be copied because it will be freed elsewhere. * Operations are defined below: */ #define RECEIVED_MESSAGE 1 #define TIMED_OUT 2 #define SEND_FAILED 3 long snmp_get_next_msgid(void); long snmp_get_next_reqid(void); long snmp_get_next_sessid(void); long snmp_get_next_transid(void); /* provide for backwards compatibility */ void snmp_set_dump_packet(int); int snmp_get_dump_packet(void); void snmp_set_quick_print(int); int snmp_get_quick_print(void); void snmp_set_suffix_only(int); int snmp_get_suffix_only(void); void snmp_set_full_objid(int); int snmp_get_full_objid(void); void snmp_set_random_access(int); int snmp_get_random_access(void); int snmp_oid_compare (const oid *, size_t, const oid *, size_t); void init_snmp (const char *); u_char *snmp_pdu_build (struct snmp_pdu *, u_char *, size_t *); #ifdef USE_REVERSE_ASNENCODING u_char *snmp_pdu_rbuild (struct snmp_pdu *, u_char *, size_t *); #endif int snmpv3_parse(struct snmp_pdu *, u_char *, size_t *, u_char **, struct snmp_session *); int snmpv3_dparse(struct snmp_pdu *, u_char *, size_t *, u_char **, int); int snmpv3_packet_build(struct snmp_pdu *pdu, u_char *packet, size_t *out_length, u_char *pdu_data, size_t pdu_data_len); int snmpv3_packet_rbuild(struct snmp_pdu *pdu, u_char *packet, size_t *out_length, u_char *pdu_data, size_t pdu_data_len); int snmpv3_make_report(struct snmp_pdu *pdu, int error); int snmpv3_get_report_type(struct snmp_pdu *pdu); int snmp_pdu_parse(struct snmp_pdu *pdu, u_char *data, size_t *length); int snmp_pdu_dparse(struct snmp_pdu *pdu, u_char *data, size_t *length, int); u_char* snmpv3_scopedPDU_parse(struct snmp_pdu *pdu, u_char *cp, size_t *length); u_char* snmpv3_scopedPDU_dparse(struct snmp_pdu *pdu, u_char *cp, size_t *length, int); void snmp_store(const char *type); void snmp_shutdown(const char *type); struct variable_list *snmp_pdu_add_variable (struct snmp_pdu *, oid *, size_t, u_char, u_char *, size_t); struct variable_list *snmp_varlist_add_variable(struct variable_list **varlist, oid *name, size_t name_length, u_char type, u_char *value, size_t len); int hex_to_binary (const char *, u_char *); int ascii_to_binary (const char *, u_char *); int snmp_add_var (struct snmp_pdu *, oid*, size_t, char, const char *); oid *snmp_duplicate_objid(oid *objToCopy, size_t); u_int snmp_increment_statistic(int which); u_int snmp_increment_statistic_by(int which, int count); u_int snmp_get_statistic(int which); void snmp_init_statistics(void); int create_user_from_session(struct snmp_session *session); /* extended open */ struct snmp_session *snmp_open_ex (struct snmp_session *, int (*fpre_parse) (struct snmp_session *, snmp_ipaddr), int (*fparse) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t), int (*fpost_parse) (struct snmp_session *, struct snmp_pdu *, int), int (*fbuild) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t *), int (*fcheck) (u_char *, size_t) ); /* provided for backwards compatibility. Don't use these functions. See snmp_debug.h and snmp_debug.c instead. */ #if HAVE_STDARG_H void DEBUGP (const char *, ...); #else void DEBUGP (va_alist); #endif void DEBUGPOID(oid *, size_t); void snmp_set_do_debugging (int); int snmp_get_do_debugging (void); #ifdef CMU_COMPATIBLE extern int snmp_dump_packet; extern int quick_print; #endif size_t snmp_socket_length (int family); /* * snmp_error - return error data * Inputs : address of errno, address of snmp_errno, address of string * Caller must free the string returned after use. */ void snmp_error (struct snmp_session *, int *, int *, char **); /* * single session API. * * These functions perform similar actions as snmp_XX functions, * but operate on a single session only. * * Synopsis: void * sessp; struct snmp_session session, *ss; struct snmp_pdu *pdu, *response; snmp_sess_init(&session); session.retries = ... session.remote_port = ... sessp = snmp_sess_open(&session); ss = snmp_sess_session(sessp); if (ss == NULL) exit(1); ... if (ss->community) free(ss->community); ss->community = strdup(gateway); ss->community_len = strlen(gateway); ... snmp_sess_synch_response(sessp, pdu, &response); ... snmp_sess_close(sessp); * See also: * snmp_sess_synch_response, in snmp_client.h. * Notes: * 1. Invoke snmp_sess_session after snmp_sess_open. * 2. snmp_sess_session return value is an opaque pointer. * 3. Do NOT free memory returned by snmp_sess_session. * 4. Replace snmp_send(ss,pdu) with snmp_sess_send(sessp,pdu) */ void snmp_sess_init (struct snmp_session *); void * snmp_sess_open (struct snmp_session *); struct snmp_session * snmp_sess_session (void *); /* use return value from snmp_sess_open as void * parameter */ int snmp_sess_send (void *, struct snmp_pdu *); int snmp_sess_async_send (void *, struct snmp_pdu *, snmp_callback, void *); int snmp_sess_select_info (void *, int *, fd_set *, struct timeval *, int *); int snmp_sess_read (void *, fd_set *); void snmp_sess_timeout (void *); int snmp_sess_close (void *); void snmp_sess_error (void *, int *, int *, char **); void snmp_sess_perror (const char *prog_string, struct snmp_session *ss); /* end single session API */ /* generic statistic counters */ /* snmpv3 statistics */ /* mpd stats */ #define STAT_SNMPUNKNOWNSECURITYMODELS 0 #define STAT_SNMPINVALIDMSGS 1 #define STAT_SNMPUNKNOWNPDUHANDLERS 2 #define STAT_MPD_STATS_START STAT_SNMPUNKNOWNSECURITYMODELS #define STAT_MPD_STATS_END STAT_SNMPUNKNOWNPDUHANDLERS /* usm stats */ #define STAT_USMSTATSUNSUPPORTEDSECLEVELS 3 #define STAT_USMSTATSNOTINTIMEWINDOWS 4 #define STAT_USMSTATSUNKNOWNUSERNAMES 5 #define STAT_USMSTATSUNKNOWNENGINEIDS 6 #define STAT_USMSTATSWRONGDIGESTS 7 #define STAT_USMSTATSDECRYPTIONERRORS 8 #define STAT_USM_STATS_START STAT_USMSTATSUNSUPPORTEDSECLEVELS #define STAT_USM_STATS_END STAT_USMSTATSDECRYPTIONERRORS /* snmp counters */ #define STAT_SNMPINPKTS 9 #define STAT_SNMPOUTPKTS 10 #define STAT_SNMPINBADVERSIONS 11 #define STAT_SNMPINBADCOMMUNITYNAMES 12 #define STAT_SNMPINBADCOMMUNITYUSES 13 #define STAT_SNMPINASNPARSEERRS 14 /* #define STAT_SNMPINBADTYPES 15 */ #define STAT_SNMPINTOOBIGS 16 #define STAT_SNMPINNOSUCHNAMES 17 #define STAT_SNMPINBADVALUES 18 #define STAT_SNMPINREADONLYS 19 #define STAT_SNMPINGENERRS 20 #define STAT_SNMPINTOTALREQVARS 21 #define STAT_SNMPINTOTALSETVARS 22 #define STAT_SNMPINGETREQUESTS 23 #define STAT_SNMPINGETNEXTS 24 #define STAT_SNMPINSETREQUESTS 25 #define STAT_SNMPINGETRESPONSES 26 #define STAT_SNMPINTRAPS 27 #define STAT_SNMPOUTTOOBIGS 28 #define STAT_SNMPOUTNOSUCHNAMES 29 #define STAT_SNMPOUTBADVALUES 30 /* #define STAT_SNMPOUTREADONLYS 31 */ #define STAT_SNMPOUTGENERRS 32 #define STAT_SNMPOUTGETREQUESTS 33 #define STAT_SNMPOUTGETNEXTS 34 #define STAT_SNMPOUTSETREQUESTS 35 #define STAT_SNMPOUTGETRESPONSES 36 #define STAT_SNMPOUTTRAPS 37 /* AUTHTRAPENABLE 38 */ #define STAT_SNMPSILENTDROPS 39 #define STAT_SNMPPROXYDROPS 40 #define STAT_SNMP_STATS_START STAT_SNMPINPKTS #define STAT_SNMP_STATS_END STAT_SNMPOUTTRAPS #define MAX_STATS 41 #ifdef __cplusplus } #endif #endif /* SNMP_API_H */ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/spy_grammar.html0000644000000000000000000040275515134002420015512 0ustar00

program

statementstatement

statement

if_stmtif_stmt function_deffunction_def assignment_stmtassignment_stmt dict_set_stmtdict_set_stmt TERMTERM

if_stmt

IFIF conditional_exprconditional_expr COLONCOLON end of lineend of line blockblock end of lineend of line ELIFELIF conditional_exprconditional_expr COLONCOLON end of lineend of line blockblock end of lineend of line ELSEELSE COLONCOLON end of lineend of line blockblock

IF

'if'

comparison_op operations

exprexpr nested_expr_expressionnested_expr_expression comparison_opcomparison_op exprexpr nested_expr_expressionnested_expr_expression exprexpr nested_expr_expressionnested_expr_expression

expr

string_exprstring_expr bool_exprbool_expr arith_exprarith_expr

string_expr

'^' operations'^' operations

'^' operations

stringstring nested_string_expressionnested_string_expression CONCATCONCAT stringstring nested_string_expressionnested_string_expression stringstring nested_string_expressionnested_string_expression

nested_string_expression

'(' [suppress] string_exprstring_expr ')' [suppress]

CONCAT

'^'

string

"([^\\"]|\\[\\nrt])*"

bool_expr

'or' operations'or' operations

'or' operations

'and' operations'and' operations OROR 'and' operations'and' operations 'and' operations'and' operations

'and' operations

'not' operations'not' operations ANDAND 'not' operations'not' operations 'not' operations'not' operations

'not' operations

NOTNOT 'not' operations'not' operations TRUETRUE FALSEFALSE conditional_exprconditional_expr nested_bool_operand_expressionnested_bool_operand_expression

NOT

'not'

TRUE

'true'

FALSE

'false'

conditional_expr

comparison_op operationscomparison_op operations

nested_bool_operand_expression

'(' [suppress] bool_exprbool_expr ')' [suppress]

AND

'and'

OR

'or'

arith_expr

add_op operationsadd_op operations

add_op operations

mul_op operationsmul_op operations add_opadd_op mul_op operationsmul_op operations mul_op operationsmul_op operations

mul_op operations

unary_minus operationsunary_minus operations mul_opmul_op unary_minus operationsunary_minus operations unary_minus operationsunary_minus operations

unary_minus operations

unary_minusunary_minus unary_minus operationsunary_minus operations floatfloat integerinteger nested_arith_operand_expressionnested_arith_operand_expression

unary_minus

'-'

float

(0|[1-9]\d*)\.\d*

integer

0|[1-9][0-9]*

nested_arith_operand_expression

'(' [suppress] arith_exprarith_expr ')' [suppress]

mul_op

MULMUL DIVDIV MODMOD

MUL

'*'

DIV

'/'

MOD

'%'

add_op

ADDADD SUBSUB

ADD

'+'

SUB

'-'

nested_expr_expression

'(' [suppress] conditional_exprconditional_expr ')' [suppress]

comparison_op

LELE GEGE LTLT GTGT EQEQ NENE

LE

'<='

GE

'>='

LT

'<'

GT

'>'

EQ

'=='

NE

'!='

block

statementstatement end of lineend of line

ELIF

'elif'

ELSE

'else'

function_def

DEFDEF identifieridentifier LPARLPAR identifieridentifier ',' [suppress] identifieridentifier RPARRPAR COLONCOLON end of lineend of line blockblock ENDEND

DEF

'def'

identifier

[a-z][a-zA-Z0-9_]*

LPAR

'(' [suppress]

RPAR

')' [suppress]

COLON

':' [suppress]

END

'end'

assignment_stmt

identifieridentifier '=' exprexpr

dict_set_stmt

identifieridentifier LSQUARELSQUARE exprexpr RSQUARERSQUARE DICT_SETDICT_SET exprexpr

LSQUARE

'[' [suppress]

RSQUARE

']' [suppress]

DICT_SET

'<-'

TERM

end of lineend of line end of textend of text

end of line

LineEnd

end of text

StringEnd
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/spy_grammar.png0000644000000000000000000132506615134002420015332 0ustar00PNG  IHDRL& "IDATx |e7'mm ŦPh Q.JU[Q-Hw"heW4E][h)4hKCQ P Js&&i&i&~?ϙ3ggoyfD}}} FK `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `\ 7Ys sS:dYZ͛jˋGg|[ưtF^SťU[+Jgf7{fYe'lKfBʛQZQjbSz41k+͈i6V%UX\'c\1Λ6v:GiīכƗQ:v4v~Ϙ+75gKռ)|ObA~v.[*KNйkw{b*ffu[9%3 W.-T5yDo-}ᝏoKwݶyD]q3+ܦf,ߞa ޷y[7;o]vmyc5ך8sܕ ~ON|S Kk?>8NxF6y 7D] o&&Q]n y Idimbic~%'` Lį޶\m^ pG]qiqnjT^f̩}cN9!wˣhTWͼ+5΍ Ɲ[TZLť.- &,G94-tU'R3+\w{ułypA%+[ܥ٩ӖT΋fu{oe] yG]tA^NE 25n޲ts.ےܦF Kk+gƱjUiiɥmޘ;ȟXPJk+OHi݄1tѡ :reضWSk׵wFqS%e U5kk;=7VUfO?5UXirc_ue& E{ [ӉmY>(sײMnЈ jk*;eKDS$﬽궵.+/oneBˍxwKUE\6?^BXWT5hMegwIƄww>?v-͛K 0Pu9m[L5fB4dfŖ6Tܛ.(hf&q˜6|74jf7T"}KϩTݾfq]j;aҙ=xC(\|-*+nW8e[ M,[8!†V^po_Rj*+kbKMeٜ[Ϻ. XYuֲ{L[RY137~Q|F:D߰f^^Ny_ҶT~Kv/P3g\O&fK4]sv6)شF%:g= K5ypߺ%6>gTC1O|ɺkޞJX^ Oh9 ܰu.,rfB4t3a%?||SEK7nh5rғqn.mQEv X{O0}e}yQBF^UiqВw{uYQIk];g?ێH^ixW]PTVKM!\rL7.=xm ui߹aҶOi : x%H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yÐW>tL:&/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yl%;W_5W &/@~ąvvޗ$X**L-(ԂnS4F߇krn[C2x^}ռcIs &H0!/@ yL `MV]>~K/: B6vTn[zсt˪on =r[~ZPU=5rgTX5lSF/sbG.qL㷄u^[?wڽ&ێmlɚgf5w[XXWOC5+ǧ֯z뵷}y>tL:0j.>jveNIK5u̚5Ȥqt;D%9Z[uJZ%׬|\YT~S4@ݕ^ɑ'.jxˢºI\E#Cش*ak7CȐ{ډ'&ee^EIkլ}M%ܱxymmY֤/4?>, o02Vݾ*]K7ʂ'OMԷ!;+ sGt  i+[ԘC}b۶m>gGc.~}UrtelHB>V*;{G-}3S{++*.Çm/>/oXdh 5P__ /jJxO2eo?^Y4mZFܬI^5+2M:pՕY֭}1Tq_nfp{ˬ!l*KJƺ'e5о _4L%O:wq ާc^o/頃_}qR$a!?QS/ܻT*ݑΏ"Ex nxDCߩ 5KƦ+;Z\ ps;zˬgҭ6}GD+2J٣ nܑiwj[(9u݊Yq ;3nxS+w1mӻnp}:;v¬{ @$M]v'No ݐz֊mh̡{Y=fu-u\E)w{~'>|(Cg?HRMޕ>sQadI^q[- @$)']q=qᜳz /_qaݺ͛7 9VWWDžO>9{>O`}Q_4 ^Q}!W;q![ Q'<6ƅMZ/\?XW=~}\Hr_L>*_g>ݶkl ֭[}ٸ<I{?ʗ6߿~릸pI' Ȉ~ܨK/}~K|/ @$)>|›n˫|+sڵkW`?_؅3/ O+>H$×򿗕R#ݷm۶ __c$MVG0 ܹ3v>SO?Gs=Wo|{VVlڴ)e?:( H:&H^1IDATy/~_>U7GçJ HXs >Ο nx}|կ+r t.!odذaߗ.߷KO=@wDJJVzHD6Ĉ@b yL `B^$ &H0!/@ yL `B^$ &H0!/@eIM^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ذWLeefVl }o> 9z/BBmiU};d)c}\ЗvЙS `]jaK9Y™fdۋmQ۴viQfůF~V#^[]Q6oF4>giv >(ySy3J+j&vTrgCfGFHVm yGnˣd7kޙS`Hʪt-3sJ ۮj5qݻMyCUɸ3κA>^5'En=]pW3mIe4c7eu &,P=g\wF4 n9ݟS`GM3w%+y[}ڶ\8z6d^iѿ&Ld݆x67wBW,ݏ.-|gC{w>t{/ʟQ%kGƜdö՗4~ {#o˷oXؼr[/y}y5k!omm>-=:SʛjQSTz.52J,WW,8ѩeJﯨ=3۸87yvnǤ_l]6c^UwM++9ntHμ̹8*6QYq?F3}e򙹙M뵙 k@#u<(kt*[8cNiyE¥cCK_S1Lmy]¨K6& lZҊֽ[MT/- 5='twfθm}:rnU~3N^fiqnck'޾7ve쩢q7g#t-ui9C[!oMѿu..WQ[j*[Z.V׻ 2//]h-K7[62.utGT6 lN~gV4uim ?zqs&~ښ9EyzfEOӑn)0ewܷbFY:s5K,K]-\93T36=\/>U |ʔS74 lA9p4) ́?﨣ƾǼ#@$5ݱcG֭yd]T^z͵ÿ{o Ȑ7stǏn}eǗl ,z6~윳$Ȫo4Jx-?ޚ}ļ#G;v.NTp\7^5rȿ;ÇOlz6 lïv{ڹ# jl(o5:4J^uV_36m޼9ЁMSO= >Xp;( M^!淿}qIX`jAAtU{%[| p y&۹syW}#gJxz,:3޵kWUw۶m>gGc.~c9fmٲOzWܽ"8|ۖ|L޽?_wh|IA~&/RB;~f|9 ¬SLۖR@jGQFb'\eg苳Z:~yg/YYYg6=g#sQadɰaCs3? .˷,Ze%:.#GF 60Tw9w@} Uo޼90YtKEΌMYCCuuu\8{[sUzռȺu;~Âoܰ пeWtk'^5feh~1)ADŽ^w4TjŅ'aÆMɟek+g68Pz&[#}ŗ^ 'MO< ϻ閉yyѵ={ vzӛ~V S >4[}Cot~@>>.t>5akzGuqw]詋⋯8ЗekRV/=//oGwڟ#F cB{[l=3>?spnZZ[G G\~~Џy{W>zu\~'+++UWgM?]{5iR߹ׇAw‹X_5Q W֝?)+U5+4ן;y;wq+{Qf; >|›nU̽j׮]> Ѡ yߞx[n]bSC_Z|TYؒ5kׄJUˈs_|롇jkk N;ڎ;BZwpQ¬sbu:0kJvqίM]q[1+~X˃_onc0R\S ytk@,t7 Os.6_9I{wOT-.6tou]0siv_y%)-'_'6/ug?믇n/ڋ;}׶ŕ.8q̜=7,z*.|qyef15,6˹~ mq<^(] i>Cm' 6Rcǽ"+k5i_뽠y{nm4e÷O-zWI(K/uql^-5}zœMɼxy=%xOʚ:S|ꩱG9a N=c3r6DJDM 5]gЋ&t954: {raw刱:=&'8D5VD\6=%g* ^Rj͗E'~]}ռ^5/t yk3C{&DpdgíQٕ9m;\j=tE:f/E?.EW8sGjzZu ^}՚'{󵓧z5U#9?CfEBnj" aJڬٯ'\ڲ3_S⺐/L7IVaS;e"lVHEIN솆wӳ(@ȵQ9mjNs[,+bՕ_l<^TůIMV̚LV_]i۸.{ӛʚ|v|WxOvBz/Ho;o.o{[U5ﳭߒ`t^\5jZ/Lx-6S:Oݸ#-M35X{Vz[74OsIq~b/ \RQ(.L}t9 ~BGMe %]>21hǠoOymzQ}%LR~m|+w(Uc"P𙂑{ڌQW{>#\) kk^s]c^xy^mYc{/K`-x\Z#Br_CW{XeWhRVݾjgzx笶AY ;]ooBZU38JOdUE{\vvM֑ŗ͋%naUI3\0뇅V[-]vU L?uJ4y|'DI{3M{q!7\?eʔ ?Q7M|qk>t%F_\7\S wǢ0sGբ-\K{wƏ^P5]0l*kZQ3iWe'Z^t;Ul^G{H/ohj}-e*n^װt7VMv̎}aaĈ=_LJz0xU?|E_y^[7а]=_5075NFHÓ:]#..4.G!w;}vJ~~G o?"hqlKhxJ|#@ÚPswt] xgn J?xmm`/ؒ&UX~sԅ,ٍ#֋f} S ;v¬vذ<)F ;o.5{vPf+kK$O?,Z5+¹wܸ>8TI}S /+~Qxe 6]y{_eM+ 3Ƿܖ_g*= 2ue ;H)up'>D2I׬XOxբYV־O|2d?g?F3A{ ״\$m]'xmmҵQe?`zCv97o;Xm w)ThUێi/۽c{f&ZcHa?, >_yêzǢGC_x>دVMOYx3ZDOߗ}Ɇ 򢲛 u0p3/ .߲hQ`0k9p7lذ_rF`U_ºu՛7o Fl-RM<:7k㋦W}O`0~/e'I5L'Bb4؞!a>tA۶mʏ[w;h_ [oJO Bd'WDu!e4ގQo¡a({䑧Lɏ `KR{aÆMɟ?UF庺:o-AxXL|r\H/.=ŅaN<u ]^}ռ=&5?vxq~n$7/IDATLLˋ ٳ^صkכ#Vmc{ 'DŽ9OTn_Ƹ_!/{Gą|eeчy7x .ZM-z.R9)5 0w$.T6־ܸr!AZJۣK u#'rrV̦g7=l Z[rtU+sڵkW ֯™ő酧@%۾C=4do-8k;v .22R\S yd] mTpZKk2;{_{صs: N8oy[Ə3*ٳg; Z Ig-]_7׆L KV]?>|iӦ_W~ef7~!gyG{zڛF:j0|(I51}WG>rƃg>וC9ėC0%)=wŅ  Ǿ}w_ų.:dnx{wR[W ??f[@r$UzhuG}7W6λ l`6;8x~5@eNܹ3$Gkx[zg2%wË/׿-[@w1⠴9Q%5 MkZJ8!/@ yL `B^$ &H0!/@ yL `B^$ &H@2 `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^7fen;,Sht*[8cПWLeefVl OGo]yiKŌq]iG]/3g[Y~[]u- OGo}n/yֲt;u/ol{ OЏ>ԧ#ا.;nNM\YqWΔFg)f_5y椲J5\G޶}cE錼TvSCyE._pKF8kYzYm#=|-/xF^MYy3JK[NVm\kvE܉W=ѢC~.k9@;ˋ{ZCMiqW<ܲˎGEf˫۟XvˮG]WL)  ɾj7ذp|8je1ݼnsLSs3pjf+ǯod\H6yɆm/ow\y 7r>׫^˛WGS7ltqn 'G:ĴFԸ+ʋbUҫ5ԘU*WTT\\TXXRu٭RqH^->ֺG훗qo=htޜ-`IRk7\xiǴo5nf0$*䍌W4gie͖C6o~-pr-( CIrB3SYYYK٩Tn9KjLtݲwUQ-9!omMU]\Z1ݾec9ޛ.) 2//]Z=KgnD`߲;Y5'5uS9-NΆ~guyq*cd>^9'wt;o,?҇;xN~Bh5MiR3?y jum-\9 ɩɛi]pmU&q%U/yQMoə0¹7KKxiM^$ 6,YݓY%V+U?WT2yT螜 gʪ$$ &H0!/@ yL `B^$ &H0!/@ yL `B^0}խMM^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$8`vر{XjǞٴ}}x tN}y ,8ԏ{ȑ#$/.~5uy{[-N$|o 'L Cϰпv9wUș-^W3޵kWb _xխm۶m]H2;{]1Ǽ1mF@޽?_w-[rO:?;蠃!Ot_2e޶$J^^<쳗04h?GM JJ]yGyd=+.ܳ!CM^ڵ{ĉy s5{9ei=XT>q>v` '++ѣGǒ%^wEgKxȑQyÆ?/&@?Yq=qᜳz ɧz ?45*?U yʔS74 l`g7o9У;w;~|Ѵ3+B㬢0y~R]]N>֮[,ܾ}GT?ѣG Uwkj)ѿa?L>8]x0M'uuuqa'ڹsV?'.³=e?Tv$>yxe+ gϞk׮7M@X**L-(^ u޷+z?F17z#]S&IY~I ֯z뵷s?_|zlą;,;%s jBAhQ&eE.nܨQ1UWgM?]#gsҹuWlEܿ-q<}lo}l}qyڵ'09?9owzGQ :2g o8lB{䀱c}䐷dotU}Z$:̮)YtbWз]_2:ſlIԯ9ΎFTVfΦݵ^7<-kO4ؚzZa{En,ue< _\^Uiq]&1 -5Q\RpOYqQx]inp:G⣢)oZQ|p]uӣ[uwG3=|&jٹ댡AhQ75+͟=׬hbgց7,Bh6ηU}J}yT&ehljHOŇU.m{WqwN5cFF5r%|c>v5a;<ꨣy晽B:ن=з7nk~J/U^༢ ϻyE 裎zg:Vzʕ_ۺ~^;1HCu%|:oh=]{hrmo8Yxg՚a2;pS%U5k=#{cc20DӜKa&̮xu}̜Sh3kBjڸӽˠo!sXOpsÌԖ5ޠyFz6Mލky|q~|cH2Q|PfŢ*oK8+QׇldgO 6k&: 7H^\L_2mxb5udaI/=0%:^~XIFRS9;ss'[{渜jxu]L5]7hhljrmq#̧w4@⍾PqXtZyXadQa]YYT?] ]Sꫯ^lR|W}S4t)MW8ϝW8|@\Z+Lbn+O;_hL-H 7u]斊aݕնcũطŵFx!sUj5׉'hU٪1v+uѺoڝe5̾״CFĤiUy Ϻ.1AM+qwxTtL@8\/^V[ָd5~߇UW.ȍk9=FiyƓ<17'ugDu7_I86_عU dž'6/v؇kyE9,W8wyyE /3 eY]{۹=seMU۹Q[oI.d6JWh%>2?6>pXn+cAǓ랮Ғ˓tO-ik]M]\]~}blӦ/.o5‚b}=d=`ajie-إ=>o]un틭]-|]&jW]`wwReݾ߳|]ޠOKm&m[eomBfųl}îضm۴Yev/<x6lذs~WynLbb*kM8+Wty8p^1ݻw?weָ'tϊtAyEcC fhoV5kEƠ$}tK|H~0j$?sviq] )^&;*̇&l.+} v~SEu]|"5ũ|dE]ieӾ̭ ?x2mJ/2lXDq;OM-X|NqOX}o3 Gڴ 2fƛGoi¿YV55;jR"slHoaSY*<0}S-!s9+jY7o{i4mGwqlwJfWY33|O Gl*㻭{pm𢦄)SEӦå%LO~">yEv#{YEEs?`tnwo{E_Brnn`=I5Huu{&̴yHhl+M.\5)fyIV[> RBR ,bK^U.Gs]MxUVHiX,-ZN](ѦWq\J-oOMnjuy[-6juDÎԒp$w;ܧK.R\RI7|cذ.]‘cf{]7ˬM+W8SW? a HTy7λ[n_~oѭ3*>:81Ԧ{HD}t^c A274lÁB]v}y=\T81Oސ-yE9_v8t7ٳ甩=cQc=Ç^b`4ÁjVV'G%KCGtGL޺aƟ!/V)"[(sY~1IEΌMC܈EMݲ^kO, )'w;~Ǻ 0IDATf|ʳ O 8!/whj`誫 O>iロ}6@78&On$\W@_Ww6=j9M*`hnVɿvk`2`ļo^{C9 -y-93;[=н6- 8|͐ĹhTn߮}7B^`ٳgO\178}W; yŗ^ oi/=zt\x7@|hjA׳]k@3 z vް1.T`_n 吷dDž^ٲwߧtO~Cf]tȑ#0x<_Zu+k-u~0xG56'𺺿kSyљ ;z݄64$Gp\xw `w!/ L_z59$Ԏ;646 @h gϞk׮7M3>+}ܬy$k窪޶}O}bGv;wƅÇqeQowQF}/rMw4cƍ7 ?.6 rÆ?s4{*.xVą;,`8d#FR9-‹iϧ>8)Mot悰/_ڜ Yjĉy}x;۲U6Ge>pԾGc:ht肦ND֎Z[@YYQOv~SPN9@;N8-[ҩ]ӏ|0iG͍ /g~PgϞ~~f?3p@ Ç_xӍqyՃ~eUv s+2իh &×򿗕R#@os[n]bS;wq洖gu)я'L8r ;vX#UU?jeEES̠#Fx<@!/0|stZPU2v?|p%vO~7mo qa鏗Ixΰa/]Zoz)²䒋=l `okH0$ &H0!/@ yL `B^$ &H0!/@ yL `B^$XV}}} H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `5@myQVGk^53*AM^gMԌ؆3]/ХbFyy5n+YC/z ϚgKŌ쬬[3 a!oe[CغliU"|K}@o☬+}J W5_>rzqЗ̳}B &H}[[^;'2]☆.EV/Mw;kY"9Uާ&/@eIM^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `74:& &H0!/@ yL `B^$ &H0!/@ yL `B^$ &Hć?;XjǞٴi͡_qctLy~Âիuoܹs?\aÆ]y5ozӛBOr`!!oɎ }b۶m>gG◇f+?;>o9r\/6l?V[^;|IAzO~r++*yy Xp; Hk>}M9gGgee=0,$?QS;3?&T4 /{_Tw׮]`s=;~s۰a"޳ggOcT>q>vᡛz I5yWV'Fa $ }G_S6l_"$+'.|:=GxIf<^;iRVߗ>)8t$ 7;~6I׬tMžW?14Mպk#BrŅN྆=b\^#v?k6V=>m\ѡ S>8 CަguԂV _Wؗt2[ժ+N|9ϭzY?ϔ9/Nx{g|8$Ç_xӍq_?9 Í_zUu\~'+++$×rw?OaXc4ow/s_&o?Ⱥ؇M8u„S&~Q}`Mx?=M^FvUzܷ >_W_p@M;ҰaO7_5P8ysRraS_|߃=Ԃ?5S<蠃&*!/]$yL `B^$ &H0!/@ yL `B^$ &H0!/@eIM^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ rIDAT &H0!/@ yL `B^$ OŌ،j{TVVjfŖccin9n B^*o U:!**/0 SS?'0t-KF7>;:W4oiuMyqVVjNU;C+k:3*gȋΛQZ}Lv#U\ZefTKe7ǑҊTy^SY^:'a;j^463{G\mEYmQ61;pfFW;xgq鞱lf7\Z\=NL"wA^:giu/MLNKgegb9.-LYjml55sRmw]jˋGXˣ7d7-y{ƶ{itX>/o)`ew>D]pW]s殫]sQufBۼu<&,P=gtsڒʙ6sţsʚE-Dݔo199[ǫֽ// R13: 1ti9;{3}V}](XxїW]V?Sӧɶ3mIeE[L6(wѽ;B&߼d\IMvOpC͜qX4ظ lBZMjJ1G*f}R1#7r-om[xژA6=.YmIw3**._9Mc[a[s_O׏[P0|㛧kiSOlZ]_Ei.\ S^wیk[W@_Pq/m/9}TzrXP0|jFE}Yq;ټnɅCK<-'`ܦ׭ΚY?-vqb,ro9}\.-|gC<ˏyNu^߼Cm-G]?he›>vZ |{1朷$(0wBfմ{ͼL;漛52^~|i9y[9x֐ZS10W*S'g\Ctz o\:3/zt*dy0kⒶ ߴFԸ"cQʪ{OִmlѹEU/LMQ4siqU[tNQnvÔ,+=-]Zވ[;/o\Z;:d#q6&(o\ĤSZya}6ׅr̘M fyUt}#ѱOs ػ?-K.sVGc1)lͱ|9gƓ\ɠ^Uʻqә62sTT.L_\/@4(%syeK?wt>ՔO֖ݕ%eܽʗ_ٸcYQvv'12䛗h35sJ3_[ZS| )k(+=3:;ԭAYSsJ+.tp9M_ #޸1L'f%K[5?tA: [oYГ}:-#oಲi!㼼G[LW7^ l Z'7I*UJ7j+9lyeMj:Bލ5ՙ'[.b5qEFVXTފʰ_&(j'.93>]]ݜMm,Yf4<˪qsr{ajfY\8cG]/51|SeO˱Kz<13{C$So5T$iGvrz^ruо}o19>-ԚKG훗qo=htޜz uaqk 7jFvDnHk S<nk`;ZOs_^d 9[&ܹ.-2 dXuFb1q̊vMXR mBm&T:&Ȩ`9Ae&-\Q=wG3~{9=|~Ek;3僔\]{ߛv:'Xz-;m&z @K yk(-YfN4FoYi4FÙt/V0PAPYZLC23;]jiW==f﫻I*X\r_r?v?W/Lha.r]:3UVBiIq99c޵/YyQ럮iCłA`C/XYZQ}O?tܻxUe@i+ȟjﱮ.-S#`ɥmNqq+ܖiڂ9ciaA[,x,QYPu]dA^Tgal;(IKK˨p,3f..xM2_][Gۣ;  1q壼/Z]:: [`J 2“=n ɞzeYŊ(Ѯ<*6k(, 1 ӥ K*Ù}% 3ϻ; K(\;2 +UnYY0k&^{VOϜU2ҥyc/]HF]MtF%o)-K-VcK9]XpU&޴YZl\ WV%f:jߙp%گ(hݗQS ӾʊUKg%P?/^vԪYC%ڝ=*+gWܲ^\pS2י*K Yn+F]r9Pu)[̡AeKWW5|i9 \L7e{(gU7e 2YG]2 HR{rլt×֬j?#\<]ڭpĉv}:9R)F?m_lJ,.ۻ|5s. uׯ,)hg>sT^ oFqw=.3orKO opT:3o}(|)3rkw%}YXZCF aw+߽s\;:-,{u]ڛ[S=wedj!#N$=y{լRg/ysS}3( 1v1yĨiii9ɘS\KlY8(Ξv\(e.mi_ cx.Xuc5w]b0\`GIQPս+wc ' :f܂ c&^1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1jk{X>bdӓ Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1?ym۾s׮ݻw@1b;SN9%gO 8jjjZ|O<1?>lu8dȐIG u y8K_ϻZyx)|w3<#z/ݻw3.ڼazk3N7nSO ˪וDO8߹t%A?fж~teu&ϙ2]ï IDAT@X, u&f(ж߻Q_3/O/$G'(Ā -B^o`[-*gggݶwg$ N!ﺒ_aaС]B ..,*߽lY@-5pi+ ?{.Y{nǎ/+}=ښ;gJιSrnX2 [-la }ݻ+}vmz5۟z*ܨg> 45жAA|lٲ%*L4 ?Onuz~fo,{,y;q#taÆE=Y^~(84AUUUT<6۷oooh:Zi}]‹/g :kSr&G媪?R3Vkx[Swؽ֖9xw'=]ƍxaC3m ɩ"3gL?-s|)|K/?/ (5ж8 ]p];| _{{ß0|7g1*踡 ք84\ݷm**;%3/:,l7,%U}E y\N:3r=uK~zݺg_| lĈ|;N9唜ɓO?-33ڔu!3s{OsG͐WhWԼ߳lO9eŷuVvПݻ뷊>|pWk< R\}O3ߺ/%Mw~?&圳u~]E9S{ጋ z>򚫯>Ǎ7S8;tгmo|{Œc;7lxt횟 6,~̽Su/1cE3wyZq6u%%A/ySλww.uIw /]PSSW%L_A9u3=?]vŧ?qcb^}}iii@W^o`nW!uoV3X,ÿY曟ѣ'L8+3\C}߿?la~$MtI%k\D\v~]N8a#yr?5o~b6l, B'M8xoQ9;;_ m~[7|3苾=#*/+'}׷}6f4XtV0% J~/C~wŊ~qw<8,//g'?~}ˢ˖uBބ5 ͘w / *@_RYYSOEk>wuo| [vЧ׺b˖-QaҤI_}[ӃxZ~I?P^[IEN^ 7, ;JcG#Fjݺ.⠣}}a,/Qgt>tf4;z&TUUEɓɓSvU՟>yə' R}^?·wѶ_=V^'IvVV>|_>xq!! &Ca%5@X;yC)5C?G?~}XzCޯ~!֭ۢ¨Qn-oJ:M:O/oVTT~AښI]=_瞛 :w}TxG\+ʠg;F%^[3]9ɏQ!tVlvvg\fo_aaWb3&m(6#(vG?̖N8! y¶;N6}\\Q3PlE[nnj>) {}[vvVTضqOٳg /'N3u?_=5jG[UUj|ݧ|8WA E}׾~GTt>OQg"O:)9OX:5p =|?YP]',?@Mzn1r>tZff} ҇|\Tw߰!j}ҹSrŸNZf}G7noݤ#\rQ9.o"/3qbZ3sy@7K֭/͙s_ٶm܂+Z7m%{nXbއG\]Nysiy@J֭m]\١hvSzuOL8{,^)99-?~r757lTVQQ9O>٫T%1ܴlVl&:a޽_\iy_‡#GfЎ,gĈa2wy_+z/De5=1"1G7n,+{эeJJ C[+mvvnr_iƍQ[3SΛ1}u3MUEE 荲(}vzM}t\{6wsE]񚚚C}%?{NO>^PEi$+^\Gf@6 :-oM`̘1;wlթoO7tSiR[ͨdu9SK {čύ.teEKF4BdEO5ɘl̴b3%W4kYF&mzԩ|'tg{3/j۾}ofbѮ'f*=qWpU푽$ꧥU궓qsa(;XVTAIjp^ިO9Iz14ڣB%4Y2%v4ÚnH&ۯ?7ݜ~QRFWwhRo1:/4Z[>3hVaڢhSG<=ԳqWte ԼUoc̼W;&糏1x)3y0Mm{‡|AmLۗsMYJ_JoaKiOZjYuGv+Fǫ?G;ZA(^AUSxm[v.6HjcxqVhv4;f'~A 12`Lxc߼)L?7_:u[}KN< `6}Qj܀ʢ3%WY6땢Ԑ$_=PZT=)BP+QK/߳l' 8{2 >ŷmo Ӽ5\ܕ+\xqEU#y,~+|i+ϞxiY^]"~h׸Ģ'UMLKdTt,$9Ԧ6*<4vG6q[ޡ͛%ov.}ry^*wO[*/W_cG;Q_ѨɃB6(HWW\zx~x F3j[R 7I&FU~lsG3M OAKF.* hY^P(QdSK7.3tTam{Uzb(v&O]ߤV\t[[7*.XT.{UHoHIDAT֚D&W,!q(,k3vM8^{g\vїo{U;{9AX& ?d~Ғ R fnab55g,k߷@*.wYРYw:_>_Ǘ'T6usj֓1v'}?q5 .k;#\pq4޽S59~ks,}kw2߄{xڋ%|`ޕ G32dwF'FS-L"nm2UT^50V\y2G f'@Kn5PճZm^k*ErQdCm os֭ۚt{Uۇ?snc^ s[MY+_ZM.jNy `Qenh MaʻwWt*EG:'oYTz LoS*o/~pT/.iv4;jONz̡͟Wkw,K VJ+%h}Av0)O„Aqs/o hsCm۶߬s%Kܰѵk~6lذ >SW?tqhf7[S3w!M}nX[^'5#kvXͯD7,0KQp+;wpGKDŽ&e7yFӱw g\y\}g>nܸuN/V mkhv~OܱtA_SFfHU\KRN6N/eO8>(ڣӷ7n][g- ŷdmƎ m~Iӿ5F#·ɛw޽+sK,ufs_ iK+MY_Z.W#z۵"84wdm:Qy|j]ω`#m.d{xь3/‡M.[lXƲ}Ymб4;9VϚbԝ-n{Nrh#q/R{tިߣ5W?oW)h:dРAa5=?cn8gʔǟxbnm\枖Ϲϯ{=㉊Jݟhp¨+JmspH^Uwxĝbf%z̬=0$V v ؙi31FG1 (#1֌Y7w4޽35_;t |}Aa(Cunz@xbu)mxo~u^xĄuvI|` -[:[ -d_{XoYԞU*q{эnqL]nL{jeVDz%sHbdǺ 9j1U3>%''<{8ff34;c@tv ]3(qQdp޲yyٌ kW/P?Q6ԦwۗN:d~ᮻ>vpz[3s,$M ?r~ZwEw)?_S_vׯX% %=ub:7's |>-7kPeqeQZNEP4!S%n+Gڼ^v`kV>|i۷oƍC5GĪ3ѻm|Y/bXC_/^h&~|ȳ׫k84ؚ}_W~Q[_tPL %c5ͻG<ɿ[pmTO~m)9N ڧ_\>DzىsN>B'bb~*V~gYu{n/bk]/vС]C.N\]vYT{ٲߎ %j/DA߉3f#OLLL6qbQz/ *ypm@'_7$yG|4 vqru'E3]:jnh&5LZp(ɾw|]Q|ݻ:疙ko{PYYSOEk>wuWK7^\Dsuc;fIA|۹724yҤ<1k-AR?Pi 2:8Fb༠#I[jOI&ԕu[܎fy-hyl}Z{{ wްdyE'`PGofqͦݰ|l߽/*{0bĈ_.xqiv-Nf9k'R?ɱ {IߗTUUEɓ:+w~ 0%g?Tئ]GW]3#}I$ AGߋH4;N7;pu6GBΙsM >|_>xqtJ߫?9*=ç_^}5*C9,_'[&L-/u>Y3Hem2ᬳʊ.KNWnj>7ZfL͍~ }C޶ bC޾gСǿz7|O nnFt\G0h;SwD!v~GwtKNT8ArqFtys@Pc~C<^%N8?%{l۾]Kmݖ y32:B_6Q!l»Zf| NȻ_+;;.,l۶uh>^3EwNUwDN7, 3;_-_o qgϞjM0!5\\Q3]mv=o|⨰jOUWGK.8jeddƋ_My;;7 OvzaƲ',j!z&.ЇN SW}S55&%6>OTW O=? ,_c C/Q]t]/ƲsZfnv y.~7 z%Wk fw&^++7mظ1v+yfjy3O?07|VvݸG7+){2p^^Y0c]tɧ?uEW7$ ax >NO>bd3\)aL~x['?AW '7<#_4cFq0mi۶E₾[80`?}?w.=s蕦|m/̕AeggEmۄe=?X }3W5\Qcwznia?j^C/Q]@?`_8p;n7l7/vMuɇ[\lI'3%' _oE]tYw[z|?|az'x <@a&8p>dy33O?)996Oo{[Ä7f~ڊƎͲ-la [p[x]u СC„]Ї74x >yAZZӂ6Jp?^5nc?qqǍ?==-oyK}K y#gҨ jXɰW }I|EO}ϻ _}ژcB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL ci555'/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę c};JeEfd-Xr_㥶,Lk($DقFOhh-+ef M=~u\5kh e.(Y:'+bƬe@rlaΰqӯg_w^} BաCӇ4\s_2W]( 9[Y|9_\us=q=?d7%e[{!Y8SKONnūڨ(-̬!gieMMiGZyw}Ӛɾ-Jg*uV'МYy̘͟U8-Y(RZ48kS]vxqqE hmFztz;6''3fU~5+M_񞇯șSRUZR\ZRNѓ7`d‚#ڦ*fϵ$'P 6k NVo]V5\CUum欢-qURRpNءiii9E;֨.%g*[rf)n%+zi9 J*E[(.{ D[Yi&5VԴzuIaocl^S]R9ުϏfcҜ}%cbdzĘ Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę x<۶m߹kݻ ?u}vI'y{̋Oi555-k{8{'_Y&Yu})+>G b@8p7|Hx=+eοK_>x`@{pE7?=LOyWqƍGWu???_ຒɁ޻;κ$9tгmo|atklذatp7,}Y]xΔ)u^` _ Sk׮=xzrvvoq_ҏ|4*}??z0p?g۷qn}r=y;1躒_D СCbw}ˢ˖;{n/;IFfL׻VByݻw_xAT}Ŗ-tgIDAT[¤I/ܰ7,l{{ dyE'tĿݺ.hZݡ'O WSʺ K=yIgb 39*WU)ט<9 F'lwgۯv+sT8{Ām„ PiXxp IvVV>|_>xqЧ^~\=lݺ-*5%7l |{n'wQᩧ :/_yMW431:to^~7߬8ӃNquTYv}dR!oFƨ^N ۶oMk! M~z@mC_yV^/^/##.L5.p ZuЛ>=|?YP]',?@@,_c iAr&O|&w}{tƨFZZZЛ,3qbM}.sB#νۻudwgnp!ו}q{T_`u9is.mG23:X3o ?Ą'}ϲ 3F;1bDX̝vޗn0oe'চM`jn٨sr|'ۉ7 qͦGnKBݸG7+){2woׯ=aڕpp^@w.?^SSsС߱G?s9gJO<1ׯܴa(ۭx晩y͘>L>+;{ї{{YCG( |=AAL}d^3fΝ;;ndSͦ6_/nu=Rv{nP~iC]iD/© ]W2n޴ƠڍDXlt^^UiF僆ԫEV}'3 kfUF;tyerɺ/-68p4kY&|{n'hӈ#wr)9'M į>7x#+|7]ګYXkjG;EOeooOhJ J-0&A׭9֊i6?>N:3r=5m#4yWY]%$]58?S֯]w-o*!uԒvWU7]GY5GH1;sBF&LFi)5=pލk6y-eJl^y*EG{}+ 삚P"a{tjQenfݕz'݁nk7߼1)眭[5y)~n ]a-zX0]ŝJy'~r$rC:ؼ :PƯvk?>㗾dgSqs9'.)ԢiA>R]7 XK~Dk.mEn m1y[÷n0iD"/g?=ZBѳػm" 'M\{m^Mp/ްŗ1SW?*뱞 =#mHƕbC։Føw g\y\}g>nܸtJ r=yZ>3-9vk3dAA=\yU]#nHdɜ1v8ϛ RhU*>4h=0̡Ι2e'?sQzo~zuYUOGҫJ D=(_[ifRCg$,u;&`WQ]ECq~TcoV{q c_{tCx≹W|qGiš q t%To~ƒW]5!c/ /gk'oSBN>V[ f::![B9R2mn4T0nV Mvьm-k2W[42C~[W15MHU7WÏpSskmmw̋//wrJ' z1ZdY++Ss5̆ܨ+tZW'k6[rkA)1pل $!H74fxkinv^ea~/uo/g:}WYOT?kYX7W4^VrCаu7e7yMمߎ切{}3W}6*kGУ͵Vv}#eIfsk 6u" 򗿺#EO|db;h:|9Sm߾=,7v듛tP9j;#_ Y};ב yo0\C/ᐲ}|c]^,wCÕY>xs;~_J~%Cݕ}WI ;13gT[fNLPhN] >w?F-wH_@7(?> qьz׸Aȼ55s&C6t#qͦC6l޽aN<1uc+ }{'Mׄ-[>'lK4iRЌw˽&c 0%g?TӼu/0yr*CqiC|YUUUT<y\_h ]=n# &D!K]!1W >YYa_~w\)ʟΞ˛k?b;SOC=o/~zu붨0jԨio0 'mЛ84m7#C^o/c^nh믿-oi_a=';;.,l۶uhUWY y'uV=y922201*w|⨰jX ի%_D˱s 6|Cefɾ>Y𩚚cdAuvlU@sĐ7UdK徚\0սueA܍I6v_Y3An=.oMV7YbiP){"gNIQ/VW8dfvf8k;Q616+pqIkn: b%`d-\$CrŸ]T৅%M[4~W_}`vr{VOkup_]`Ar8ߑF퐷4V9+aIEum?}% Jg5[++/Ztewl)^:'kh筬 zū!jfG; nzb󙳊T6s&%hG%sr75ZUe^3嬸U.{p#2Mi555Z2'm_5қ(gUִK 2-3ohk(QزjVOA.wɜpSnj[+fUɺtuUy9W쎥m"_PҼQ`]=y3&Qg^xW+[LxCc ^xچ W{]=&Bϭ[`G6wɺ%D]_c$&YQO}͒zNl-uuxgtrk?dԙ{noE] =m䥮7%U,B=yAmRZf! g@@UJ;3 tm m`̴͕6yIYQNTvֵS12!oF9- z#u@uIA{:ʐKȈ'oXXQɎy; `cL.5ؠĘ Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^k5}= G ғ Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1-oMZG1!ݺ8*|}~iVSS o'蔺AZgW۹M5ziBWn6#FG Ƅ1&1!/@ \>Ö81mn{̉ig0_zP2xe#yAy[>&Lx=RT5s'L ΜGUEyKO۹iS͚yoykz'^L!7vnY+ȸ fY>og}=`mnQਜQUkW8c}Q+=;ZҜѓ_IehA=.gji O/64|)̲Ní.ܔ]7tWwIE[]눺rp>m&g6L9o\fӚlj!G/Un0Y6땢g߾S 8PZy^RC+O0䓩S]{l֠ZA#6=/J{{Yj /}"|¤8jmhGa\;UMLUeW\|)ֵ‹^IOz' Lolׂ. 2 k32˃("iO-]t O(mbQf^XƲuކAm0.UBF9\. oM^wwsRs+oT.:1*@_7dbѮĘ${ۍsG ƺ? ;j;MEqNjjjZ|[ޚ:M@eSszĘ Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^XZMMM@< cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cS]RUPRSz,X7ޭN[Zp4+)HK@cifZRKy9%GZdNε[ŭ)>rؑӢUVAս+h;63+*l{D'{Y}9G^Ӛ}t`!gmcN#g{n쑉G}[;]PQT`lRBތ̱32Z[dKNg.)[?6ՎTλry۱N޲ra~Vh,Y +yݲvഋK\Y|Zzfނ[۳9KK*ZP[0#9%GUPz*JW-]n;#vɭhʕ=:zzzZ9E;͂KyP#cbGVڠ&KqVoG9Yu5 9LZMMM{-/ye ҧܙxG^cU~z銥YE{\ܖ:qYWF]r989 yoxH[:3m)Ko׶Q(-)h8DN#GSt3olAI]ʕy'Re_}''9!Y\Y]jhWb뵋K%tԴK=jr5{^qIKtսsnj{]M ,}%Ď)h.Y]f#/lܛba~2y]m'*r Hț `47=e">,kY3HY\uaV!VD+ 2UX\ g’V8+ge6_9 R.˦gZn9 Ó?hYK5yעtT ,(Z:-풲z9{]EqAC3ߔ̠/.n|csr23R4=3qIğ&эԑwlN`Z^V#u땫~-l8*LKC>rqV.NW햗-*0^Zj+{;gҜM?9Q1FJ-;m$#[o8#+`aQqiEFaY>@3 y5;1Zl}KIv֬^˟/JJ22f&exuKi`5v*v}ӂ̶{,-*ˬw-1ٜj^97>'{oNaCT@: kӸtTCgGOWW|u_EQ^Ɖ]uTzDk~*[d# 9_e-l40̜&cTZ % [opO״bؠW:y <\j޵~ !C/XYZQ}O?tܻxUec,Hms6'+ܖkڂ9c  ޟ\ ?#2 lX89Ðv,[;`_ [}d孬 rgddYbEhWV m5d\rf2 +p_喕cOvkKZ8\!gAIE|uEq D˯((]l*W]YQjHi #clUvbǖs2Oxʊ;V(Itۣ*Wܲ^\pS2< *&裪O`tԅw6dNխojԅ+JK I(?'U5V۲83;ʉ[UV,987i%((]Q3ޝS 4ꚍKs+W{O7|9`*X96jfK4Es}ye{w~R!μVjG>9~5 :;4rCwmlb7{]w-de6`dbzg²W75̺=ڝ[T=SFfΨ2jK=L Gҗ{vD'%ur4caP@l yb/.[gR=sH-@o'/@x 1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL co'z#FczĘ Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę xg}ŗ?5,oXƲ֖]o>[FiOxdm۶ܵkw2>W?u}vI'y{̋}Cdm2#ߚ}On$rފQN &k'eatЏM 󔺇>^~YѥMpaX8]Yk\8p> y\X!>p_Bm2^}COz{pE7?=LOyWqƍA?sСg'a۶7Sä^gÆ z6!m25_ciT =y9!oJX}ٺ9S׽+222^ݸ1zxь/'h۠M% p ~']_b4I'TvULkW@&A @}'oW]PpY퐝m(LQdN;~:VUUժի%_|8UQVn~$&w6}RU>OTW'FvC:-33HNɂO63@h;G @_ƍQ?Y>3m1˃gK=*߰pe@MyKpT.'mbΥzEA&w6h&@ H? y gOek\3%''9_s[SssFo圓䓽WKs&3xM %Υd+4j9Tj,,DŽ?ub*C[n6oMpGEU yݸ%K?s;C<=F Ww#lڴs^[Wn:VԼ>:w~8B*6NG=MedE+nA#6peqѮj+k /ƯvnZ6+U.bݜxQ(^TqsrˋE~lSͲ0fS.&w#mrϾ6Mޥa򖷦wՑ#Gٳ'踂{nm1cܹ.vZ>3aFa͚y0%b*J0hֲ0 V2n. E+V{)$ϘJq'23lϠGn ځxԩ|'tg{3/K6miMr;k /n8M*[69MhCMMK/߳l' 8{7>ŷmo ռɾI~3*%Nd]_ažΌ][̰NWI,JILRU7 jzj]߽8T(zeyA[j_jS2<+(2كѝv7'xF&o¡ͩ^nGePqQŢ9kKgr떙󋏯茭۱V.?~6tWs/oߟlLJ+2,y|9`3 gϘucq༛o̾|Ơ`Wq4"CQ W镴IMc Jg3G'F9svAK\{"E-O0((Np DϻyAN|//㎫{~٫>U0w?}4F2AaUo^TWϑį`tĉE(]1JMll>!ײٷ/h#{uK;&Żܜ:yz0}͟=W#%Ol*+{>\S5omNK.U;o%*yCWܙʸXk@:tIضm7=^ ]gÆ k?uEAIwܟ-Kv;_z 8R:.8*oG :.[e7*YX~0=qnҙJnk&aD{k ]&6{^8͛8qƍ?ԠMǁYIڸ#TϿ(g)-jt*o /]8@k+rQM&kShlOy׻\52>UQ_ƿ{7iiA޴)9'L`c8q/~_jĈѓ'儿S\ mϻ2#kQ勊;6na &Vޞ{=8{Ѝ~Em-J8R=e>-yT,2=0xD!9iOÛվ3{E]^r]1mcݠ*Zz$NTcww>a̩{%%{78'yxDe}knT߶Ċ6&D[䞻j¯g=. >o_zTZkqx3]9nꩨ<ӟ^-.;FBirOe)Mu{Q*Ͷ\es'%)e9O`L'7߼~ᷗ3g?׮l:MP.HGTx+4< f쩛UnV~&^5)ܱ77j7sh8aQ+Z st k~Yʼn/.6:4UJݼ=m\G-_M$?TWkx]|F~duԟy]Mδ5T>H63XW6rmֿ{;N62MdmrRjOWʧ~zنGڹbInhX BCzI ]^|ɔc*߯ dsN۾}{X7n'780Uf %~] {RD4JG&C_|1,gggKiuuqC^Eܿi;njx㍌w#tP}I'B/  :O/oVTT~[n F :S{i韺&WMT?/e5zN8!*l۾=aTљz6~H MSvd:쬧~m?֡UU&qU(L8묠.:Du5M6]E?=_VAݴ'Їի%_@oM&@s}' O@C:-33HyɂO@?{wg].75>a>u,ږt:*+SlЬaiyӘiaC'QWbIJe'̵aNZi&L0uLmjx0quw_]y睳>[Ҳ&jgvG>o?ٮ =Rq]{MwʬoVүZti7\`83V^C`L2?xA݊<#~c&t-\tlnnd~&@z7^[]wOO5z|P̷-O5̼:|͏xRӦ}&`ĝv)@<-Y%Kt,Yk=y睨wj~&3R e Y~9 P݆vml`;6*D}g}ZEWH){p#I'TͰ^{G#<2P3fL^!{50xwFwugtͰ>?D-dF!㏧B^6;p7s];.H1uʔW6ĉ9 yقLfŸ!@}my >k`.;(z'Qj\\2nclA~&Co,HOflq'pQ㥗_lz{%[;sgZZ:찏|#'S0&^}ez+D?u/ʬ%K ק)FN{^`:e|TMy-?Խ[Ro/.#[ל-]vVN㢨a&NiCd4]zW_x矯{hu:c@mbc#-M}{gkѣⴴۿ<»mۃ23ODA[uYguy$u~AM?Ԏ[Ҳ&ː7wʬArڤIlʥ_dU\Cw+*>f.۹ŗ^80~?8oبCT۰rԼtڴwlnɓv9ɒKZnQMM蟛OZomxmuTM;t:eʃdjY>?9iی{v*ۨߨ[sN8\ڰmUa[_3q3 ^}So<銦gTރu+OJRt?A{2K}Ֆ0v,ve{~겹{g.,ttKDAp`aeJRk7Z>e!4E 柶}FF79N/q/MlLxO{MxFwugORk^x \W #qs'M^b-sl7)JxMT۷+}f#!̿)w\YR?5uʔW`.;(zEӷ(PisrYe0x&/vdi.nw!t2XoͿ"Ub5€[_^۩Ռ+{pskh t-#vK OZK=&֓ $lc ys؂ yk``a>:Â'5 8`XSk 0$1!/p2Ę Ƅ믶Ę Ƅ1&1!/0|}snUs o.ۈ Ƅ1wſ=j<Gyd_0 c=j7.pC}'x'lE=fdy^Nj<#=0)=U lnnUDZ >0)=Ύ/g>` {wlQK˚uaȿN&^}e0,tIi&tyت ;)-`3]YK.M 'q y#SL/^jc&?VR&0pYyw~8M7ߒz{qEfF){.Me +WNGMqѿ'NKD?g&md{?e62e`0,]ZWВujj:FW'ʶo& Wog}e)S\ra׿9_uKs־F][ݔXS-IEO='K+[f(fS(^9vQNx&G{Ǯ(.}e\;UCrZEt-2 ^N(nFFMaa4xAur}n|1PqEShm].H쨂[N\?\\6~^>+usn?)O:r]v . lbV!%=?Yxuܽ3Lʌޮ}`YesLԧs.N,L՞^KIDATv֎+N-_ؼMbgkqF2.l[Jxq򤩵{_}kUH݆Àcksm2demܛ\pchHU N&m[v ɬτsO:5K <$Jf[j^vKAbWfߒ䖂*ڮ9&׾Y[QFGׇ/_&O뒔D[~_.`η /į\C /8sE3~dIwnOͼ=.67,6*&Ul薌#+&Di]6ߜtŤIWta?2lyyW[6a{}.h c#Q;ߎ;x5WdL⥾%&^Ĭ/uۉwV1=qڶYQRɽ~XI%re d\k+jߌ۾:{?4Sˇ8Vsr)qB":|TIlV{ү. IJ\@So*)ᤴKYc &N{wzD{ŋ/M{e;]?_|6u\)BRǻ+6IvQEEajldi׾9jʗR{K4,6*L1IHgHSo\܆ٻS|ۿTOI\i|0۵ͱ l :=Emq{_ ԁe_c}cr=Dg=F8ajۘ?z"jjt>CΤc:qt\]Yǃ9^ y᫿!/#.ɐwq޽#>۹x`3-O<[Z >ۡ2|m{*xl>!/Эlg]+nۺq;|γFpn[kZCvB^ OybL ci=Wa|5vml`;f&/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@L^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^!neeմ-$SưUm3m,FpQSv{)~!omm!4VYFLA_օ%yYazg ĕ۱̒֒,*gm*mYMui~Nzڦ^6lfoSX^ԨI^yEjjOv ~.r+7`R~c2J*jlB9Ӎ>j O;sYߍK QSʺ1'j;=y%7) V>ltcR׬ڶK\] Romq]_&-Yv]SgLNQuv!;I~ieuiNzOjSEyS#1zEmӺ/Jo6KZkkkk,{y+Kns==wҭ5Ew-ђi?ɬMe9CWg}__3g3{0-9iUUּgJ2 m3A7.47w|EUv{G˹EݱWv]mP{kBFzGcgzOL}IfcyA?8ƟW0g]Qi :̈́ZWzmƎ EP{^tښ1JKgܷqZ{پ4ث{<ɳ֔a\(^Q=q޺b(^ofMs k6ɷ(KM8oQjoSlDE3RLށLm*wҼ߼bEؒg:^ߖ=>y&+&Y0clpk 5m8ɳ:.έM ;dΖ¶wEo٬\;4=2:&ӳǶ-huƊ1Uj/]N><ӄ)'#[}!-RV;COj(O&cOq m7f4 3+$۳T;Y:㡫+o|Qr0(k.NOW6'䬪HyU@5~ʂ41f$5 K: Ԕzlv~NfzjZb͌qyapx07i;˚T )frgڳ߸6y&٥E8`F&[QWqqJ =̿pAu5o\>k|\BvImǪiyťӒK]JOో**31ESG^P^q|^T7ColLM*haҳjj%n+7'>qwcmY~DZw,= Pgț5lH-aZYضdcy0|tyٖy+\S6,ou҄q]{??kEkJ270=i]aN/E7:mceua0v0΍ =[]WW2 -qIfnn2`\Y]B̫8,0dQvnp^EBIJ:y\b>&35uǬfNN=xmmeU]/2S%V㶴wɯB! y3RI֪ H:kMKK(iƤGqkN~qYMҋY&7]=a`3(Y0vMs|}asm3VrN*ZO~N=a  Ʉ7Yk+֮*jŹ5Ƚ뺖꒒EEa~j2;&1o;&QgT ߦ /NU#DW8162t6}sKjBu-M U%9 ӟ7&r K;z'7ԔV&u|~NRZ stb;1eW^޷(C0w 鰒[*YkIDAT$fAK\ʼnW k7X%g.]*ub^Y/ju`]Smy^i iά*x;CojKWTYӯ,Ial^nOyejvh켶|쌪\FZkkkk 2ϸg}%f]_UQ_=qmyH$??&[_-J{Maڴ7ʞ!X{mrLK]iW?6eܬMN6U朶9.kҎ$86%̺Ҍcn>XnICe^}\Z=ߟiCynu{GtkcMQF+:zܺ7gtq~E+k}tbq,筨_MU'BMaƆM rθ&Eu .mz77<>F7nI3gݸh kCHvuuM=枑KoS͊խ}fѼhر]忙6>a%)uzl3-wjݘ[ײ~-۟6twrL1o3k:-{ ٹz#qGLK]7 귌ꦵ+zT%3`3>RlӬyt{4>{vV7*VP_[1,@l mdֱnV !/C,;vӪx\X]@Y4UfDG;Q6p'e+;aƍKWוd`hyeOy <^مCLX2YPEMc`## !fF\G:5ب@l ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&^C7^[F]vF3ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybl02sUU7N3xptѧO!~uv FJ [^'xWz1?Gӫ-/80 Gz*tG&_gߟX훜o;y ?N,kڤmvpG߸*5fۗ1m=1WuAr.#0ɇáۛ>JݱɉީK[h}XMfn #o_L}$u;zmUo@F9YF9ٳ7|ozzb؁!x#_=s__=_}ߛ~êջN_x)9Ÿ>ԟh3G}girs_Oչ-ٳy"ӏjKz\FN}s7dK#7vtu3OHܴyfd}0} SYuQfazH4B4Zɻߞt;ݐ-:fv[t閎eڎDž}ٕ]s?' Rnǟ[wڦOzoK/,;'K?t9?wQdh[ɺ'ï~2Jf8~Sm]O8YGfGm{}acv(q'npQGfݞpk{NYp{ɇDuG\Z\z–ږm3Ɵ]O?&y?yt+ JܐɻO=T?OOM"/l6iac`!o>_[թB,xCNv:BO$?QeN]DʿϮ>D[eo;INK?sQe{`9^Wg'ܚ6~1ʳ~RЩnAxhxՍo08oCC4T*M} ;@Bt/bnYm? gg=G}snsXxnwoUjdݒ>~ ;(' - #@"XϮ|lwMOxO{Gz*Z0ҰYz&DdH*y;"9v V7^[W G?ߏe>f圇/ܪSM s_cv]oU7Nsn垷n66,yW=kÄ9>zwlx7\rH4/0}Nd:-YZ9>S_uӳ;lԨ1My7V?P磗^~yII_!5/%ZG5CږжBy@].A}w[.ȿ^a#O_/J89sM:}ΜnE!ɥ(E8D5j]s#[o%K~Ѩ=mΜie ^8'ץ]-W0gNA룷GwY<8ofmjjv҉H/[x?0DwNG3o_r 5cN;oFFƸ7Ы^[SZbݺZoGߤ{g~5zLYbYaIO秗YYaPk_5[s=~9a1y~&7疥=a}[/Q^vxv BG9GZ4y;>cƌ0pɮ]nڵqֲf͋/=zN Bϟ>ի[/»ᄍM}1Gn.~p1uʔM2ۧy3ƽj3B(L5vyL/\̒3_Cx߿oGͺǿ/]jի[N~zG/~;%;)lQd&ӯڅ /r'/~=L/C~//Ks,xbJxucwLK2kժg Ĭٗu6Z-v6z7ξ]zظ}-0\o~3u],{we=v;~㪹ɧ*%O[؊>rG,93~3ai/] j冯az~T{wY&@ry睨y VŹ_?[ K#<]5Qt^c?Qs٤˖;Sv}אLFNv8pH:(RvzWOaѮS{~4CFΔMv^R8Po28. 'Mʾoa:^~;嚺e\Fjb+/]޾jكy]~opγ_~ݶ+r/]ܖ̆}m 7N4v+޵S%NRC*)ֺkn7uB? `؂!믶t_QǵCEg/Q/&AJ-/=ǧSO> [^ߵ2:$f +"mRu:P ﶇ=x!Uw?^&Nٰb7D\6iʧlvWg-aʣIܱ agyV֯L5?an:ff{7pf?xmj~DatޥS;K$wq!Y757y'FҌijR*oؤܴIhP?)zE#ѫ?jճ!y;~0pOqp{`S_}lw?cO>tC}/$kKYկ2׿r ;Ӵ0rν}]VoC&^]y$ö8lҔ*v9λX>7ּj=U)\?7D_wxw.-w~j [/װ]43j~4BY~bXp00/5tYe.m-Ov`w`yܑF5{@7[U/ VCFt .uF6C׮|=Q_YapZzՀ&E+,M%=W|$JNJέ޻' 7NV"FUzc/_j_7^3~% zvW}?՞=+a)Ng=M8S!9#Od%v?_ʚo~zFՋHm}މwj֭ɰ%_>QO_弗r6-m%FN:ߍk^^~|S'yac?cѫuZ\c!r;QFUЇVN &|pQuȑO=}^w$?m-;;0V`٥^۷wW_ڀF^m͹eSFˣs0@/Jla3LJ:naƏ?ڏzW/oX2lϽ{嶐w=\~" Ae.~o|o)l-_/'ƎL͹{?4uJZSzߛj<Ӹ* ʉ'ugOO}h/[27ґD^7c܎;5|0pcO> ˿+O .}WKfC?z+kk0߻!G?Ng}yO Ţ +w3߾?{Od^|ک.y!0k{G=<;k>/2ǿ] #ó yT/in~q7;(bhꖗ^~eqǾX.ѣG/?{w]v qnWV׿>v̤;N l1y=%Q?=(3Ot3,ކ&njnu!9u٣ˣWgQ"~GSSso ;ÑGKtBleevxvVZZZ){tG4uw}0R;.l 1ɻ{i?Ҳcm7-oλ{;䐃xР?va<"z=?>[_^~}Gܽ;ӻwu=8}z!m!^^FFbL cB^Ę Ƅ1&1!/@ EIDATybL cB^Ę Ƅ1&1!/@ yb,5OfĘ Ƅ1&1!/@ ybL cB^Ę Ƅ@ 1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1CzWegIKI),ilMK(Y׽wi~N{19 ;՗euYZ߾*?Nk)/HOk>;(#--[]iFZO k^MaZd7d!oCe~Ͼi~l:BhS寧D{w,ny.,kR[A.^X>;{AnkM j]!66~}Q|ϼu k[֮^hIzl{ o<5wmeU&ܜ҆ĪE37\9 f$w̼䊬yϴf$-5ne{E+V_[gfu?ܲH/8yW6Z}#V y*/~,ј0oEceQNƘ1e5 qz)nZ1oB^]9pJ $,?;=5|zfNQeҋYCyC.Jo0W[_^@kּnk KfF긙EyM%WJ4N{;٥Kx>buUsnJDgTUw[[2'N.)xECeUťe%XzUUyj񥅙=_TRTS G70酥N48͚5oD㱋zPS}_r1=,kmm+xqmyy*=0cLAѩ7k;-S rBϲsfgᤏ~ekFF?d s{뒛ZemFAyՌdم=ǼɯYUߔ|J lxLaI*h^SyU--Յ YRE-=agǠcSS|3gUTY~O1(UR"¢n=U@ YkI2{0^PQ{C6UW6czq^Id^KCF!ozzjkKK?Z]S[TלwWXuG[[T\ո1`oCyY* ><ÅPYǯqGț[Pz_eu/jSe^ZZFQMgNN,ZӜTZTKI[Q[Ѫ檪7u%iimo;֫U *א_:+Ybަ³r۪jw%vyݧ6q_5EU̢9i.*kafq]qu!Zsp}C~ǢTK.OϞQ{;0 )}뭷L?K]C8_O?яwQ}?|=fswak}cX}-m-N!?ES>lR0Xg}Tc^x!lSq yS#=rS}v{Iٷ(˰K˻ OO|wj?|yئ677G{ԦBN~E1nθƯynffVY=;0ڏM [̮b)S\8GM:/׮ʺUi~q{337lqDVCشÏ>>jE%+ UsˢW<[0fvzߙ xSpY#&3: #6b܅ k|+ [0}Ֆ ;4o|{x'pXFө>if{f~uviok)N^g}R' +Sq`S;qbN CGsͩTBSOx⥦¶j1njg&/)=Ύ-/\6ְu׿j_ZBwq޵פڏ|'lE+WΞ1;,8SO ZB)SUW}Ӳ?-luN욗Do~00*Mܫ~t飏.Ϭx|CPԜ 0 a4=D?mX>Ty/]:t/~~Y_F!l [޻;~p^S@Zz{| ߽[˯SOz!ae؞8䍼U ^[$l{O}3g} Þ7yB ۛ=x B^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cix2 Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^F^YIDATĘ Ƅ1&1!/@ ybL cB^Ę Ƅ1&[WSQT´š!omm!4VYؒHu!5yZ[v_Z+K3ƴM+*(LO4k2?eڂҺȭh4l]iFk kºғU7v*뀽hʺ̶STsu59ϳT5ac3y[j%jnf]mfMmC C(cN{ZmT?oE}Iv >vAAëk5VwP{k:-'k3yU -Zzmk:3ΉyfXE]qfeMiKxϼ{wy k:Fjߦgɑ;w<7/$~[OjN[j Γ=9ӘɳYW]MMM ɯcs2$ɂuf a\~fMnyV7Vd G8/l Vԕe$~LvQYi2zCwEɝ'{T6.5> _yǤ&Ypھ;+,)_Wښy+*6Q(vQ6ό=i;ƶ%u2 7.r攝ME&t[ܼ]|ƴQQPѰ. sJ23ƺYyj1 ]RzN0nt5xnyc`[dI)*oZںv /<|эNjXiY]duu+pwXQI/.iXzѸĒ--ݶJOb%hlC%5N{wPP KkZ ki)-lNUN^~kuye{u-9c8) 3eU31rS({իښ´i z_=n W4VtClu/e쉳*0nUBkBNㅚhҌcn&kҜœ4w[h5T^Ǟ*? +}Λ&4嫛zLx#u8cF69߬XۚHxڦgtc9oѼSSatfΚLCIfVFT_[1,۹ZTS\;BLNz{yu`1Oc'̸q꺒0y@)cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^X! 6nc􃙼1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&؇ r?> /vwNi0Rք?|mw|G]v>ܲT㫳K|+r?u„`.^5NS?ЇjjKoGy4v=v?gfg浖מӫV};OV%uUX\6o,^B^)~5yg7n>'@vK-gJN:.X8|x[;XяoŢEv o~f /2xzU{g^~97@)}뭷L?K]`9␯W~=OG9[q yGcF]0w|%=lR [ס’ҦFN>TVB{TC|hgI᤮f&MJQ:|t쬰;=dG_y 5a@rY~']VӯCnj_YpC#V][$lY{P/[熗 :o/=/BxS[__jy}hAaYN,:-[ֺ̍F;U.>eH1Kz@3˒&rDXL;]պl36w8hw gPa3O%ć,^}/S˩46q}|N84~t98أIfuDfKJ]uɅ(?GSG{@+dy33B/ fC?4s2^u ]w_sYbA׮ OdFqy|k˖_ O[0uF۪^~9{׉_Nf0uɽ ~K.0%W,vanSM3g_VvF3v6ˀ>~yÂ{7/Re5ER+6ʣTKqE'F%οj٢;E{&>:~E%u[6j8#'3(um/76YLC.kS.7΍/3'FioVff< |.52\XW][wp)ɒ,\z}"_θ>Z{Զy*Ev-ѫDV6)}}݌zר17BC(L%WuLܠ!MqUps3:.l}0C,uQrB}F[F oGxV5vY2뒟&Vwo `-_}^5U=m|ɰ9#6an۽d2DA>'71e8oϴzz{]64mc-liqɻ>Oo^ț|YEe׍ }JC^ ǝ<#3ITmۗ{OsO=jdd Oq y'NI5672/,Y:7v( {*Wvސo>헉%ŵ_ZEמR۳'MJ/5y'?m %Ym^;pI͙nTFxr~ 6ړ>:@<)=/^jz)lRh(tmefӒ[K 6gԡ^k; yeNF=q x ggGZ.qYkkkTjY<,ݞ͒&M:A>n{ONZBC?4!zpKH?S풋 zJxmM]wOO5:?fk7ŋ?zr]K4_y_=a9쪹e!൯v{Zkc8L2K~1ծCYvO߻q6*ܫxɒG]YLQnч>9>8aqtluO,QcoR>8AzgumEw>k)9j t- ɻo+S|krHbFx㍪wF-YO{O}3g} Þ&IDAT~w #~߃ 1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1'3ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL c;,;m0 4UuUX_fX/3ysJZ#fa$:2mL^ۡ_5WegiWTQKc2rK1xMyQ^vzkօmˡ+z,,NK(I+hqnEceݮc4~TU0&KIu 54׋l_Z[[{_[S6mAǝzG}uaFEQ@s=u^PYKkrCG6cQkU~ }JȺ7uyPsC;֎2?eLm͆X_[=qʰ M}Eky==n\hn^6cg,jO3yf޽bm:s|3 k6)m)N%g޺7:!bձZ6.X7$-{ߴo?6lut,%uZW/1}fND_L8;]ԥYuӇ3j: gVKf^VVM,^`NUSw yܲ {L=&#>rYPPZ겮hڂL֬++r2;W7tt.ސe6_XukN/[1oBc7h-k?ںԡDR\9TMϯڰ*$$֖d7v.m%uwcqESȲK+/ 2_;ez~eũʫmSU=ϫ(qFhyWu_'t:]Rscr:ʲŵJ|ceazC5>z˪E33qÚ{.Ua¼>(>,gEeS]sSYU/͌bT2[Z[$v_8&d>Qɠ仂/H~66Y 02# Y1lauumo:ߴn&^Jʺ#ߎ$HaO&u.tN@feg8##678l(-%>l>3ybl=x({mdyu% ~FZʁ%U48i!onqa`FO. q45lWcܫ"]ֺ,77Ϲ9 Jfvq^ bL cB^>w@2KDRA 10߭ ^+Wtv+w%YPb?୘7?ḡƟ(a M#ymlc;z^=9<}=/@ gO @C[eM%de͟*A0wH؞[zAAɡ*c_mUt,.1 y?1k'\P3lV޸*m\>3]X45.9UZRCCm[ͫMi^4+ץn^ƸV]^3-V`ZmsH=ǺmBݼyժ0tS3[UaH Rp{Eվ/]Օ:?z9mcۦ7kMΪUqMXXiXOUp5+ CżEmv5d6oNүRzrŬG^ƫVnM"=BQ!-JoU^7:}إW}ϚQUNo:ؙO_(J-QuzUzwΰ…n>jR<_et]95M?u~Emޥ5ՅTis'q(6kkBAKݖ~5B-URc"o^Ţ03~!w4*}ܻvUlgڵы6 jUgLC̫uSG(.+(nzԼU ;*T( =A#Y@?sCo8pa( Z?tmk- ۏ޻vUұq%\Xꪶc!dޖQ҃-:v/]_[&cn/ΚF[5++o~憹P|y1p m!{lP3t'oug,Y<:͋G"Յ3[кyS^~՜k* 􊿋*쫺8 !IV^鋺xӃ2y8ݎǂh9X -04ň&4:p ayYq}P5++/TfjSkO˟5)/gkOE:6wUKjͳśDjy~F./V7 n8Vך"t2{q|Bͯ>p嚦&[75YfKW|~n@ ^GփIDATMqC/Jwql۫nUfvЉftzPCjmcɭ 6=n,zUK*'wTNu-+ɑ_)>V\;!&զ_xI,ˑƶzvnS٪3.<2l/|n3*v7z=M oӶnM/޹%uq5+6<:/K7U9;2ƶZ'élYVuHo ׷\\:dI޿s2 hj__ɨԡٙx!yw/)tgTs릭KƦ2ƖVԮNw.-.z3^c!|r]^[ZA̠QKCt_aӗm_zvnQY禟uloo]tm,km* gWUǕڥ͵;6rms.64'7'qn[WxvQnӻ3 EK*Nݳw‚MOTEeY~uN# sBo.+˄ʊƹ+tC<|] 'ܱxFveS wZmyǕ_F%[C'F]E-e&ԭ*9H/q7 GIc>ÛNv֭g2}alQTiusW`%ņγue~v8ʪЉ7vGtI|VWeC3KgWVmm7(,)ɤO[;t `58;b̽ =wUw-=ٌM+Qm7->s5.:㆏]`94ǷG-r=J8Tgwqwmya ]sCw_}EK궬Xp1#ۭٳSrJ*ؼ^țU]auU_熾&'7bsUuGaCuL!?7t4D]UETfa˾ KB4,)>뚇yKyیbڲxXɳg>4FҒno,-} ]yu1l4T̞h~IIf4U>l[ܰ+Wl]<+e?x^=+KRYYY-sE'-1{quq]נ+/L/א*]taugTquKrκn}ɹ K@x WdzݹtJnQYU][3eiKw0pzuuMZUV3miz`ڑW.i18~@m*G,;0gx]o .ܳ V=ǰo[N7ڴ|va:HMͮ=-uя>RXxֆVqjll zn: G]rGUEw.5juK^&\xwj̵+ˊO~,81>X]VzұS|MkWg&1v.jvgeguƆ]3Z_ݕ%9SF].s4Kpk|ux[jxO`}‚MU0w |[ p/_[4tШeGH!!9K_ٝM~=o}_zy '<}xu#UVYe`哲O:׿u֩O1EnihIDAT5Lg4Ix‹7ts=9u'.;|,@?_zwckђ7|x8 w~0xw< L X-ݳgϰaK/ܹ0jhy+I5Զ<Զ0?bD$@wG^|{Ϳy< AQ_~k^8Vпe566vvio{<^ۅ7\0QaԨQ{|𥲸wvqM_ʋ GnZD4pC_];o} <i[9 _? ' RbkXaC\HFzթ6lDI^;jܸqa!/$L2B%K@oZ,7 @rkW_Kcy./;6{T[>\gee ГwΧdrG?B߳1uQMNxfݟ !aHna8ƏQ_Q3sy5O MTM:5ko\XX_7lNMw5CZ1Tݼ9BawHn>{y獋‹>0/Gzv!p==ӟz6TPrUYkAAɡ~j UqDޞۣ fZ}QUUk/^4ĸ'C>TiOڗ~҂Uzgn-,)tUyBVQj9R7Y~cB!T_b*ѥqHqHu֖dkY4u^]tM(Fi5ԼU_ ?!а|~I󛿼袂 / 0tЏx+VDjmu8';Oyw @$`Ln*))4xp5'~Q:jVq˪6V^Y0T̊oCF W6-8Mۭ_Q/,^?'^X a_EyJO?-ly*N.m}Mw.om[U^Wݸ[D/Զwj&OMc7Jw˵mէ5߽CþkU\tz )G=vccc}},O|ryy)t˖1bwu Gvac:=y[~maѭV -9V}my/=2 n9:|[Ffڢ*mcwܲ; t?̛J ת++߿Q?XR:sxQ:m:m̹Q'V}sUzk\Nݼ{):vа[{G&zV$4h?vGK\U I; !/>p–3;\{8Œ':B3D No}ZL-Kt2~OdWI3D(\ؘ)8}/aݗ㭭j BnvwWi7Gq[z7]ivk?s9o?0 [NO۫3TW]<ݭ֡ND>`a%6lGCxzlk0^{W}l-۳gݻ?pyĈHIk׮K.}_gy昷c8LሪY=Tq閩Of~n}Ѽǎ6 ژ^䊪xiwOth5|\j^v? U|WۻhyM!-=So?)Xim??hPIeָzO~_yZ ~0jԨp$ok` z;6ng74kT?١N=( >A!G@ y_|!@wi 6^&hJK6Bo7n/ɇkrD!=3(M,e!ˢdҸ|zeӴO p!=ኗ^eɽ߉ 3[31ݻw⅓j7oʓ VYYYW_})}dsaq0 ۞~:~8C.ڢrժܗ_~9@59>N"_9|?u >s!=c>wޙA/~QcEλO}*Ke#ȤOP"j5 Вk (wKjjֵ,tʔ / 7tž={Տ>zEeeiV޿|ȐN'<{^KZg>#Ww'O{=Gɯ}nx饗.~㟴[>`U%y7xĈmUWWvT8?vS>t3IDATV]\x?(XmI|?KNk_{|8 >t(nν}6S{7? ]S_.}CVV֤lҫ:$W-!Rpx|(hu; Ig?_OLj ܟo-ٻwoT0OOםt;~V\^]hl{ 逸" &4hذag Ojhh 0 'gyb=M_y '7`?cv'~;SN!oNظ0&?7ӻ?&. A0&ovDj0óS!laXvv(ə]8;G!ɛjJ:jI좱Tv8ScgUnmnItsWV-ۼIvnܪN^`keٌm;XWrM a踛&:ӢtVCίZxva-x]Cwvjej\ʦ!)v׶L֯n]eq#[\4ei|锬v˷ޠzv}qV0g%k:yk^RVQ>#;=$_VcccwVHG}claecϼn}rE⢖Q2s}{B]iC..C;;f%E#=͝ ^~_}kF]u32qravu+/èK,mSͥ6jTowiGN_uI|+K:6a= ys>@WoԄ;TSs;,HC y3nWC_]EMՆ疔SŰzk'ۍ$dxpM,ɊaIGJ]vqqnfScK+jWL&3(oΐpi&nu%cSΥťp5[;:̘]ݴL-^Tw.1#9MuU #˝(2\ZܔpJ7i%csp~Ň*ׅ0c 6m[2n&u-j>Ӑڡzŕ%UTw:7'pd\x7y]m4mM1u[U?9vC8嗅Iw_YzAݒ)>%.ZRIK,-8 vd͟.s~j;[^~I+UΌr֪ܖ,>Ws˵[o 7캭[[/͎yio8.kx*[8cvْu G$=p;7J */)?ZzZMv|uqW/,|6PXT@eUU3:"U\~u:_W<ti;fM鱼6=]yײcz~)URܖg{7?]>e\kM@pH!A-/Lkyhs} GV*[cd:>TSӆ:6TwִXfv{Buv}%nM}ל_5@^۰k2dM3zg {fe몪QOU]ro?A%mQUYM"-G؅9;'ӥuޤg[S_C=d~庺YnYq4M~ k!Qs\rva &MzYϯcl-JnrL-*_Y:N4vcB(?ܳ.s*fwuÕ;|ȐT6 l(wң<@tq;?uҔ{Le~V-n˶ ٷpq]8dq*\\4*fNrř\tȳ@_zGmYY݈s]3’kΎlݒԺسTxnGzކEotG]rGUEiK*gdMYF]rwUeIA vזc_tfd1vҮ.ʘ[kj6 $΍uSݻkvUIxsk3vvxniU3qe^XQ̮up.ZuˊD6lԘW.XVc4z;l΃v5VmOc7NhKxz'/jS:fΗб!$X/ˁ͊43bç'/@x H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yӐvq `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^K|-[jՆ ڶg N8Mo| ORtVnn"/3m?YW>z?y76,@0ℑJdȻwyyGygG1(IDATaz˛w{9O o ywuɥ]~sg9mo 2^8x{ڴ$FG闷LܝJdW6ӟ ǟ Ʉ@6($7햄c?z`w>ON=唨gϞΜꫯJROޗ_~Ǎ:hPBj4KO^KRH8>|[ p=_\0}Րp\xS/&?ۭO>aΝ?]Լ`b[>*ʉ3uݲguI|o;*Ԭ{g7IRȻnݺp~L]]Hl~4zo|#O =㎋g`EM{'%iă0wu]?[KS۶Ņo]O 41B\6}R&^;Ħ[_|᠕W>H? g93SN>SO ݯ~ tfKD߄GM_ZP\L&^$ pH&]x{_>wr`x=ॗ^x'egR¡>|x\+蓒4\áˋ&Kx7ݨ+TGUȻgϞ@#F|oâomOԶ~> /B9s9'.?vm3&o|޽kkj/vk[&mD|O037=M>w:?j{{ٿ㹹c~Vn8~K9'}..o dx3?ZC5갏Ok /9.u'zAM\rժ0ݓ i-~= yׯFa_|1.]gM@cZ]wtW8}cܮoh ySQSO 6n @wymOo{0N}!m;wŅ'|_V ~ҥq/mQG$J76._ @ߓW_KvF1o{ehOƅۿU?>&!O]q?+YYY>dԬjeY)¨xGayByc5λO}*OG8|LʛzK8l,:=//kjRJr[[5'?JQKasj2 2ALzԿ~?&5s?Qt'sqYw)}N8!*L_n={B/=}1}d/-({͸⿮ݼ9^Żgѧŏp s!Wl_q0~04w|Hڎd5k۫,,.ܷ5 KSQao5iܲ! xyr4\ceagqB;.􆽵k;\^{r'9*Vutܲ5շMoz;)/-O}oY3<zv!OO?:phI+Wuک뵇 Ϣʷ0jozI5ol6mHʦߺkϪؗ.UʋG]: 7p趚9f/ \5'RվtXZpy* 5 2p3+M*,)tUyBVL͛WzOBZ7ۿo?pTUն.u֖|k[8~ѬyQk<)o=‘CHRX|rUEU~;zs7PWW.8/;4Ԇnk AKʛV55ŶY܀[U0/o3[>u?/ ݪՉ7OnXvUWznhêמp oz7O8ʔrsUxV|;C/R'*zv813@?1ys[s3ZX84mO20oN͋oM_\^_0yUgt*{qݵ}֢_gU*x{yVit_EyKOn?NkJGEl<4DmKުP2R:/kG kG8ett&}hdα7k+Q,2 [쭪jo֦,n3a[UR`Hh5.GWuqW7g^gn2UM9ݸ7QɛiVaw;ȧo=>vf>○܅? |{g-݀no$EttݢqYgy@腢= $h7dw>;<񫌮+o\&Q /n7Mxow W?^zi8b!o_;4zfSX!s mgٍˣ]fڢ(h@J{rͼxȾtb"ݓ+ݑ-5ӱ]+'3ޤ\O̹Q'Cf˫-9^oi8%m9pnv=U\3֑祢8{^/|4D TG<aѧ8؛ܾw/WoH͕g.mZ #|qվik{9<`ޖuǷOڎq3~[CL 鎗9t&EΚCˍۓ*f /o.[~s~`7^5gQ:i"(ʘƵcܕW>/}xn&韾agn·Jy֟-]jۜ2ힾ=@doԐ>+*+%M+M^]iK?ߊ44_?-{~ⷿTxQ{;ۿߴî]<}綾N}o}[=+p?g .۞~:~Th5zڊ˦U᭙vMp&5wY[zɧ~9qcAM8hk9`jv3(sҗevW3ٻ)=_ꦫ¡jVV_7.~+j]~Er2 O.,^մG*^Ѻd4˭^mo;AVhnѫ$\s Zt~_O}evRhIDATQ-o~sZa=ksnٲ5*z ۃ؈@&M8]=3d{W=pTxW^OVi-2pt@Y{4K_ݟ}]\{8tpx7?'Çڢ sL?vעƅOx8LJ7gXk{S/ $2וgt铟ǸPSg 9.򗿌~W&YX(13k4~ !f>fxۏ;]vE_Լ ohWmMR>G֋{.T?p '8Ze j;wHAM̟=B>:zQo/Z {~Q>ݣRzQl] d7&.Z?h-Y>{W{Ž;B?~|?p Q?p&u-v=gu 3wޙA/~Q !vyR0?)z= Gu 'DMݳgO`;duvK/ /Ņtݻ꒢u-K.2 &O8oܸCc~W?y۶mfeeoO)*l=-3#Nz.|.-8ӣW3 oxC` [ӮFs.5ℑ?!w->vC쥗^nV^~ˋ Ñ}RK l=#3\k_> gĈ˾?Ϳ{])oV%kW?^ziVr;@'}C*mРA5 .EXiU+_[.?{fw !|j۽nT8g~JDn}Mozk^=ѣF^|şV=gβ.6m @?B__qa/~ /BMS*}C*uVsl$ ~O\ t&^֓7dNx# Y]RYU>|xo?IN<ЯÐ@vbh Wn ] ܮ*Æ "׿uzʹg=rx~8\@kkѓ$ &H0!/@ yL `B^$ &H0!/@ yL `B^jll $ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ I$*l=~ٷfem %˚Q%ԇPoS9#Kxxzr#!oNظ0&?7K!z8aLa! !=<$TC8Jrf6uczRVMe0gxlxjlNrݽ07i’:-.o)YoЛ9'7zSúsƦg܊Gn~n̝_n :{<+;5vFYejo}CR쮭,Ѽmk[WY>wFt-;HWNqA2za4yIYEú'|Yݭ[9#Yvv+ nm]l=rKm[4G;?Օ׏Ɯ<'tn[Ks:\,6+ec/3uٷUQ;W?0[;.$Mݜa]VW$k=clf4CQ;m&r !RSlQ 'oH匊#oȟ_ظb]Qܸkݗ a)%K-+ޑ_)cӊk'W>z²V^R;]5ƩQ9ՑrFnLq5MLP}Ψt,;1gqMm7x΋rZ*[\s]yFzQo{ӹͨ\- ⁇4%#'/HnM/޹%uq{wlt$^nzݣו.ks|4_У{II{M~;,HC y3n=wL%fb**[թ[t˶V/ʍ+gUoZ_W|)3(oΐpΨ0M[m:Ҋӣ1 K; k..=p{f̮nyG:nvnuqh3Vwy#'߱jvȝ(2\ZܔpJs%csp~Ň*ׅ0cwXH02LCfhWFdTQᱝBzá9#n>}~{7nmYV]Vd焲k;2y7/1}uda~NuKKvu)avђLZgiY䰫 l~Tw9?y-/$ĕ*CgF]楹-Y|omUAz17\[5=j`~:*㲆R3f-\pqtI HC yaa7m *0fFQG;LgfWVm },?uqOŽVg~>PY~ՌHNF;wyQN43X][,j¶Go._nJ]3o~h闯|ʸ(Mךv Bޣof3N5u8mh8'PYsYn{`}v }LױrgQs;jX5]sV~/ 1 ysr6WUw5TWKFCr㉻j;Z*/c/YU$iBzDM]z`ܱS 1e͓53G=z|Iؒvgf_4$ܱ[Tu_iIeCu q F^]Zn]vpl̘EfO֖ܖ Q'Ϟ~eG[/3ӉvrIzTQNʲ(DIDAT&,R8y٩\_ZFg[T:vuhihppGXSrʪk+LY3*d-cߊ̓nغl‘*]rK*jav׭[\suO]P+P[mpxm4ڪ%ef˒ʞb:#󳶪yUS'M-e?UFhnU̜pܹ3';@ߖzCĄcn;biKX1׮.+hg^h仟魹P=hmŨK(I匬)K;רK,i5(k&-ym $΍u\٩_>G]nxݾvկ\V`S@w'^Kͨ۵iłg9f VlUq)ޱV 5K7j<* o$;~gjv-q%]M»ߘ[l\lPvṥUu5yf-޺6*}Tf[ ݻw_ç}kӜ3V=I'eF021(J$/72|//7~Ot'o !7?%K'?MbF,V|?vM\o|s˖旿ëΝ_{)L@z=~pW_}ը0moM%:++-E>[t) y=t o2rdW=yvӢǩ**5W:4$ãÎ}UOܟTWW'~?[j{d{RA%t[>ϟx,tUс~ØMw:眳;\z'n>sC]{ 5;oРDf߯yk=G3o}[; *Hy?ev#<ZPM>m_Dž7 ]T?yUwcꋮ^[oz/z_8>|]#~ (jL{l{#o QBbzʩqaÆLdÆ uyc†B^L`Cp CRtIH}ƍU#H 'OHɕQ#=|/=Fxb za詧23 /n|I'E褮}{X[tz^^EoB 'G# 6Cޯ7ӯ}uQvS /zKӂyԤTU\#Ϊc-3.zdIugO -}N$ejLo~p!Ν;o'^t?~O;vu/*̧,,NOdW7/pgޜ~*st;jT5caVIn5kViU8L=?YWN|ˏ>ܓC8y+k;F s!!1֮hq64.~ةO+G?~[nGj/x/-(wԕhS`uC 6/ =5S_yڵ#t~n|PyʹYQUUK/^֜25o^]\ܿ|՜IUҥYYyah:J>^͋E WV^P3gج!:KWWd^*z#ұ{h{-ϐ› VTjS F!~yʳ[m&r͚7RX|rUE]nuFy[qgsްa㤂z{|d^*9d>Q{?$s5olvQ`զm:ުګҽ׬, ⋐`•卥'Wj!}k[E9fc'vjG(o'WMʛz˸|̸u騪Y Q`:m$tt}UB5 Cռ[~D0ݴM7頃v'Q^zmqfUgŗ+_ƅC۳goaaa8 c_~ŋ?bDu>|QWw󜵡.6~wZ/9餓{2㯑?p-}'o}fVx_iq8$BwOf>U|}fms3Gy--:.~wo;7B]y<CHP-5_ULi~*1̼*ܴUstSFIDATa7FܿΫNk9!m5gn>݊4q4DsƵW~r+~}T;Kx8jt@s?+85{DO_ml̿`ϫCtcnѴƥo? ]ES3ss¤ ^&)ԆYodQk,ji&s )^f|;J+[Mֳ!p~\J-,X]L{5s'tȍVePtiQZn.M+io5Z1]ioDjzk#&YY}O'or4N0ƦwǺ? d,o>( [Oqmܲ6gdۭmN+xj.M'Pgv}owHίᑲ}'x*k >|jyj> aLo)z-ч1$S޼|;={=tx *!/=Af;[>. )1kN.|:7Ϋ:x@=y?}¿~;I'v ] =ڵkwȑ_pW~.49Zgq7|ݻ_%W3It.=YyȐC8B_C7oM;\ ;Csq:~'̏<8=՝11℃10@Α#O /_*'[ț5yҤ׽nV}+U+׎1o{ߕ75yM566Y#_}閭O\x!M &[_-o~a 0/ Ͽ-[6?|N~@GT2dƽ@1 B޷>ܟvҮ] OW 6N8ᵹcƜ;fС~$+ʀ:\ ;Csqp݈F2DO^J `B^$>w:?$o 6($/#l޽>/=ykkk>vտ^uMWuMwMj}^"{nظ1G }^2C B^8ℼȐw{pD%KD۟{%mll ꫯ~% ;}^"CȪ7UjΧd@ _?}ww޸ѶhjVy]C g\⡅ >uhɼY󚞥.N=5mcݼ9ےFQԤ‹>0/G8R7YpHBr%caauf.o,ME1p5Qz{5O&k'oIgϞGV҂݌.떄wb~~Kd??Ŋ&\*Ї!U̙ݨ]3-nGt=zcoKd;bĈe*/q@ &H0!/@ yLKZѥSWZlRAA 0B^$X"Cލ7}ف#_8>$ڇ^]xuX~Chƍ8o$@2C B^8ℼȐw{pD%KD۟{%mll ꫯ~% ;}^"CȪ7Y:CBbWyO|p7.p25o^KSO˟Ui…{noyKW-9peptii(_4~ayDrDǮk7o$D"{򶤺Q5L_~u5+ ? n^1XXGq˪4.,yw7WhS(-}»jN]]U z GV҂݌.떄wb~~Kd??Ŋ&\*p6jTE(]{󬪿_y}T Cr 3(۽ט?KC7Eo'f]Ko|})7D1b}mo}^8ͪڛ.d:.E_oh7!a[ŢTW5)//+/o؜/0>z c5]|{ZKk_߿\v#3취b[rT[4`q͚SުYYy6Ilc`RAW6jcW"9ڈ#>8zEeeC- m yC?OX=¤eĨ3lVS7Y~ctԼyu! E1g*{{ \lHԉ&4rQ &]SÓJ4-6XYRkҏ<[H n% b .?-qZr r#_{~o }7Hݛ.T*e_|679WBw㋩K:U|clT V(hOrÔ3;•/2CCIʋ祗57]pw:{?U>7R)쟹-諸sIl:W287I9j~Jrwcv[[ [b[TexޟD$2߶d __ h^k٧]<WuGajʏ<)XrVnnB{壷$;J&6N9B- BH{0{d[n<ѓRDV& FO4-¥o_= mÜU3& L-rw~wʕ7wT@LIJ\ÐSN9可h, ޑ͉4C7?5WӃ y䖋6fӯc,uş\j93{wmdkv^kCw?nyב͍I|P\E!p4w y5Wcx.ǔl6[+/74/~S7OcVK^Hm"cc^ U‚-A6b%ܱtڑo:rmC.7.Vh _ld휵q:CݚjQ ݅ᄆesK}a%Ӆ 78:#e"___ KwʩoE0wɈD{!/x8Ωqm˻52m%Qc3yǙbWlǑWi73q&}V_ fN cB^+fE`yӛK_b y;yfĘ Ƅ1&c'Z! Ĕ1&8o=of;;`zJ&:k >G?(BțHy8+VTF?*N!?mtlj5Wch{G?0_)Y2nɆ?fp׿'yχ?{UBOwQUE K V\%86~a^38ɞݧo.)) [3h{Nr1\ۃ[yGw11yTjA0gV<ܽ#9nw40'_{tor}Ӻs}-={Kի?x9t0r' x}ܹOwoƻk?O}⏾oE/۶-;/T,~>gAnyWUMOo+_l-3|Dc+Gl8j7+_jZs}ˎGo<𹋪6.6FrKVFfa JZx9)mm }GUގJQVTFॆv.H=9pNNd7k 6z^eğaޮ s?  7M f)y /0Ŭ\CSNykro x;{?cGvǎRAUҮm{{Sme^Cm/ޛ??SP:yU¥v4*'qafADj$7*ћ+Sѻ4.鼪]7 Kn#vtYཿؖM1X!t۳Wc]&+F/<3u;7srU nʟݛ Be|:<&SGZ^?t~B[O 2رs-1yo*Ho$Q;6!wP]=$|W>u`sʴsے%_/||5{ y#kzGsW=7RDBW& eºdI>k"YFiCW=)&HnM̴.|w{mɄ+nι0w[6vvsa6h[HLpzw|+YoN/%0GMak.-d7jsW1\Eۯ|~ 7ݒj/n-_{BR3}^yǕy4EKi{?mw4fwi}ùw,c`ܓ\URmk&).;B^JNYX сG w pSYy|]tCm-*_!jFRa(V*w4j1s#/N 5!/@5yB+cbL cNsL^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^+fd&/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^;d=G2TIDAT5%tdF<\SX[i=4K%P jit&޲8s_L\ l͆ sCm&rG{7UTlڛv'r۽pkv?kwpk]$jmˎ`ӛɛ+'4׬ߕXiw_{CebQŢDecgf'`a!oZ_;q̛io}_nMɱGM/m칡PV[aŹ]ڋt?K5(ozan\[P^rʠdund"MԶvc'/oP[S=ESiObCiM@6;Y?Q[ԓ , (nJk3qc`| GJ)}0mՏy݉ N*+W`nd 1oCcGߨcUߝ]ޝNGM+sa&!o.m/z]{FIԟ?pŊ9@G=skjU3 y0#yhl:4㗥Z{mM]xnⶖz/ițy7-/v;:kLG\qڇkǯݜ8q'mx:R0I6uVQH36\laga 7<`_#1L^b`A@l ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1& CW^>p8[fĘ Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę b>ھ?Ϟ~SON;3Ϭ>wWYLGSI6-z>/?i0/xƛ.\c8bkCm 3=:Mƿmnǻ<[l}Omnr[9!XMo.6~mZz'DEe;|gyGC k㡄reeW[cI0?sإg͟y;?Sۿx{9uB+C_?~Ƿ ZBnBq%`~{{}Gv3DsPBާè4X ݱ.|B5;̩8 kygzݛN}So_L&;tqAS}dUU#B^ƪ[߫ 7Sۿ̝A| Do}[j{ZyeӂG}Owi)~+[`ŐMo.Vr-Tʫ#^=pw ^뽗6h^;:o}ƒkM][ˇޣ"_w? fZŸ`8k//ha\{gE;;vd~]p꺱;+(v>ùfw|} lttD[PQ^LO 8kӚz׵Dtz^Mp]=tC)4_GQ y;4=:37~'Y`GAP̕ݭ䏯ɩ4xC_*pso2?ov=˗Q8>Y>G淢aoo>/`[2pcGc^D˗`~ _σv7~SN]7+tlj~77~o?O|_0 y r䄼k[x !B^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL c%l6 1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ yb섉u՗LK/t.Ai2=0=-MMCc/7'J+8}'Ǔ?wQ3ainɖzkUVG3uts5b2uvcq]Cup<$n[&kj+'h^wqu2Lamk~:̑]]m]}Aycw6) ' &>TZ1xPԓm &uh{r׵6Gl꒭GX [v}iSmT7XaJ5mˆnsG'bl֔ېhh۔{ P6zp{E*fSnNs{ؽeδT^d:j/{&δ6mI.ak_\sόӳ7oTAܼ3[~wV).yoCm 3=:Mƿmn '|vMQj!/܇ozsi_ t~$9!/pB+_y-OmWJ]?=֯i&~  1 ׿|'~nqF=2SH(]hm[oo^r f.N9X?3X+[8==wjɪ/%>e8C7sfdAyTmO+ [~ZC~ I}[ f(C y+W>}{0`*KQ{[_uƾUY5B`k.;g}ɋ}ӺnZSr6{QZmd2#ɇ8x)-.܎;^4ؑDqiM}A|#Lx]/'y+swI߽G Nf$n f(Lx; q𹓵߸#v -?ww(ztrgndO޳=\LDh34`ǃ8kxm'{ҒK蛬IZ88q܋`7v jKgg!M$S+*QȻ6fCXxX `ێ[kr5um_\rguw~c7&wڱ՗]gRL g3WfxL,5la}QKK8{1ǖ}偗G/f uSr /K&Ínqx:~_79Jx+S{'nho?Ŧ/uǵwlo.)) f.N!o輕+?󧟎;? V~ð_F/7;:8r^9CPy?|˃g{Ϯ ԣO o~+-5y\Y>G淢 x~&o/|?mK4oƫ?cf@,8 +[| ༕+?v'b!!/GbakĘ Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^+fd&/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL c'L|(Y(dk_ftD}gf^:RҒȢDe}[wog}iIk`f/189!8u Fokg\rד{vߵs]@{wp\$MvdMu۲c *nDo>{ԕimTlt&z3ū6=`v?t|@-7^.J{ii XW= eMĢܮE/ K3y{[+KJJ*myMƚ-;7V564E뾎#Nyz{EFXT۴, 6Tx2˞M fu j %zlOSrDtkkiO,mX5k{2#.id`Z/o=1Y{8~ȻuuI{&muùW7/ {ZtV7Ŋw\RRijH:ʹ>XАv)oHGݛ/,z}weo99Q=gmˆnM=ZrmiSPTS#,J6ve߹mUe ?TݦqxLkDoe%C iikҒ3t%*k[:ҽCك/޶0w+BLqqbk -6}=tt>r lmοjH$F帋J5-]݅i:Zϕ3ɜ桹;Z>(\?ږfv;Eu j blBC%׮nwtQ}i8-ɆB{h9 Bj/#%lvCK=vMsٮណLGme}~ٟGn[#KVoҫiKN*6m*j5mk޿{ۦ*_X >%ǓIf0--!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1& CW^>@183ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cyOmg? nN=<wed0m%lW^>oTO?g7޴p`;0?}ZyGW_Wmu>}~fOmjp㼕+?t!/sͥ/10ӣq ?>\S?q'**+y;˓AܼLty`YM0W %++[ڲK C.Ÿ5桶O:wWxp[WW]m׽ dIDAT:Ko}[ÇWS_eg-nu1}g?mO_J08ۺpcᢅmb6 y>?`bqIǢ]w`{cIUύ]5}7~7x|?mٳ`q y{zzھ@* |oݽ##fP뛖s)Й=s v &?x9iAPY~/K˃7JKMNNXvX5ozs,rS۷z R^4K/^/]uw87?; 뽗6tX/ .=}K#U^L˲} 7>) fZŸ8vkE^uM_/kb{w p΋*&\7:%w͂0=ΊmWVq3TSZha08FMiSMw_R.U#}!|siի rC_b`Ρ* EN3Í{'+mEؾ[_uY[<[qU[CwgoV;ݭ䏯ɩ4xC_>;98&:xU<—_ &nO?p{'?UW˗<2?ov=˗Q܇72'9:qQeCgq0sc!o&޲⊻pobŲ Ξo|`|K ܰk x]{89ٔћEJ

p=400*x]h[llY)~^IjHxx15`>"O^HUv'r=M6ˌot};ܼ,˒dШek;vieSˮx2U}xkUכVBUlڛ-^h9t[jöB_ڽmٹ~Nj(jnɌ ~p}kQ?uuCǨ:Uk7mpq맻)hx4H6uʾnQ*,xQc@>wΆd-7c}C@GO6௷69Yos]u[j /Mִvޔ èvD:9,¸/J64х!:no0߸uUn@Ww_:m+ R/|/=䟗F;ml9cPumsSX垉tSrwuQОKR_)mm l]c*4j'_)`M[{M؃Ɇ\XVLG# nkͅI^չyvOy+nn}œ==}ζǣ JkYwk[[kcks~:qgֵE HD׫ gonsɦ K[Ot9޶6?!#ߕ㟹AEߚ‚'o hj!Fd!o_o;.OU/*r8 1ϴ jkS.~+ܤ_]_}|T^Q_(r8OJu(nkH%]˭FV_Tz-]5(gQ†A}oT=!ldxHWSnnJ. 3kA,/`v"948=ws-xurckp5s|ޥСy9x#M.*twO0duT;]4IG-N3(Wd2EdetwwkO~:Y@Gk[Xw-{{7_ʫ qwkJѶ$/z8#|5)lx鶦T$B30L ]P8h⺎YEDytwtC}=ɓXL:nhm=C\*_T2ꫣgZimGwQu}0 U=vXI KI6@2Nl̓=@ws9 .ܜl\*Q[~##ٲ{:IDATj=-7?:Gp̓}t;.{|>~L||Iٺ3a'|źmݭ5ы9jVqLg}%[z[M#͏J؟9wM1ۜՓ<0aꁮ聎vPV`OGn(Zg3+=ݚ* i lʅJSm}wo۴vUE݋*VΗ2#cw޷nU®e/p_ذk(ᝥD}gzlyݦm ʢVօ|sX|!ܶ`P;ɦF xnP.ܰ(=0opyὋˢQ|xh`$D|}JT{0X]4#H)g|18nx 16eM^x ? uuI$W8㛙1f5jH&,<{SOwS2^O5PLwgں%䥘ꆵe,<<^_5ĘbL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@MSN]p2 Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1Mo. `/x cs~h/ohQ8>0k%lW^>PQ>i^yGvGLUIUq$kB8إ\@ ybL cB^;!u墒wm 8J__]RU}B^b(V_=kx]hʀ9Zo:V۽lǏlx$YyӛK#pʕOmb` ;_xU׉[vtL7xqoBDMC컽wZU$lZTƭ5-]Og0'NSWOYg61z[o~<+<7]7̳_M*E|7?j246 #qqc:b74\lm}]M%g48yĕ ¸O:@gKkp$9F}bkØNM4TU 538lP^ojkfJt0+L dʣ\\R= m=BӭKk; K܇{݅NDU3?ds[~Xݾ|ǟnIFy$[:A>UbT 2U_=Jk;FxX\_#|zg3'H5 ,Nbrs%lLGme M$WJ> |YӚ'BU_z->^lͦ3yfϬ35>uWLqcUҫiKIzSvtgfм)q]SL-[tu8VT^HѷXf>Zgdx*=:r\fN9Ïm^okiĹ <יJ1ɰ~웤uO@WCr#}ڇ{#דޗ/tW^umgow3 ͘;{j|3nLݜ8Qaxk'6]U1bUeee/\a%Sgv)_zzsK bg֙{m /xiŪu|ⶊ`n; w<վQ `oorQm3]cޙ7?sqŪ=;2cF~y]~̸3dSKF0zÇ`%za\sˑX_lqY׭`C*&cS2v%۞#|>HVif#r̫/px&/m-Yy0{bY.jѵ 165yaZ2E. =-܇RXl3 R'`0 䝁D,n b(j#-"Q_l-!e{+! tgں9nu1̂w֖3ƚ ~[G:Pfk1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę & y_y@0rg&/@ ybL cB^Ę Ƅ |?_ki3nkN6CckMm5'aiѭͨ4wOhGVl"FL15)-s4mDZu^z{qGHeIec1{/ tI>~-P_ yC8Ʒ޸LO]#^h\a!ϞI=~-P y=G3}cӏwߥxGb?o˗lC~ofhZ ؓ=j=/k;N65'޴*$;8W!yVwW|ϧ?[l{ffц&z>Fڈug/?}ƑW=>K<|Xþ#/~n dpGRk7ue˾p7{NU%*>wjU\e4 ߊ R&i>ϼ}2_33Dk}/h;}F:IDAT s|;Oݐa'nio %'ix|f8k}g1qAhoOJߺ^ȵH2m33GfFa_%q^VU岧k#_ݙ{?dj#{^v>t]~3=%™NTfՃ_/gw.u["|>S{|us9VYpsRUKg\Z{썍d~g.}웾u8]J][Sz_&G;Uml6$Iyo??}`V%Zekڪ|>Nm^W~× /g's oK(ܻy_Ԍm:=xƾcnEA>S7L;!ۡ-RO8mF:5n>{j7^g慏mj:u\xQBz-ec9hƴSOx ;^3%BSͷwzۛbw]VSSS ~sEH;qbꚃN?xz8iߥ3fe'ūOՃ2ɺ".?e j7oZ7}np%>]s /)U/Qߜq+h8R͝˾[ܱ7mzn٢kッv܅5|facFW}{歷߮[<·yg>n+e'˫_I>uŒc?X{YfnB%.'#_9@%\Cw<>KNNΐ]w%$7\S?ĪUÇ ʱz_7ܸrժxrȐ]S7n&Ê7x|Ǟᅖ_>K6U $1?Ï<o9zv};ᄏ'{<>Y|HB"ʫnߎ>3C_Q?rK'(_q2!/@d픳}աWcG o_V[ /M8p^{F36l3r^/ҡ4z}B=yy?Q5;n~t?z x,Æ _z殻PD݋/kӎ;]?7r <;$䭼A:tO}CP^x~Yt篼999annO{kkۈ{.[z?]'_;᫡ѓ l?pfh3;xiǖ;El#7ϳ_ K&%?q'NvU+W5WxFkFȻ|o;k 7~;7tӕwK[o 8p҆{ F񅅟_إly/0ƽ}Q7zPnoL9\~q/QkQӢ+qew}'>2:zsXΰlò'=7Ϲ=͹??q۞xvu}W5د` moM0x)i- Cf^?s&şD8Cx9ǟ_VT|cZzJ 6hl_o(_v~C~{O~7~ۙeqm'Ͽɧ2n~KAt|q73>k7~.;?v]+[ٳ{Eܼ^ݰ}nQ9s}Ey,njJÿvxx?:eGtoڂB/̂Ѽq*nL PˏbࠁS@_CKčх;]Ih/^[v{xϻЉg_|<‹kJsBIpѢ^khh{YIk?|jגc^ν Dաc-O]_7 }<]|yg}:]9`x6U_vg\7 F]C'?_~9i>{vvnF{[a闵GO ?:6b[[؄.>K޽parss 1cFcFtήysÈ3rןʅkCF7Gh)׷w\Lڛd&?"zC3\N)m?%tۜ#*'r[4tه5k2;/ʬпhN5sҫ陭2D;_\z NOo>htv\83zN^u}د_YԈs|Hw /p|1?vjߣ?6n\g6RzFZ\`6 jr__n3 W-JWZU'%z]?ҝ xX;ˋY ݶ dkK]/^kjW4l!w^ _wm/[V[/h`йnߊZ\[o4n8JCK{'tox)C=Ɨ=fU ^ǵ2Z?vlK{؝BUJզV7vdӺm?yݵQz+Bw ØV>c[av$gOzδa[t쾩ۯ>?sKd^ڳO4y@O=yw3IDATƓK ݗ`mI.$k9C^&u76 ahɔ0dhhR!;ߩ99S!,>Ԛw]۝]55ÝsDV~.Mqu*B4L?" lٳ!}+2|u!Gnk$=|#?|O}{ƈ#/zSt_~,Ua D*chjd j.kkW_Ժn.؋koڈl2+x#B#,jߍ~؉ڟ g}_{?uʗ7$~}\oFSS9ǝJ z|!a{C׼ٓΎ8ivmHSKO8p`x/9]ŪC~PZ +׿E0]zox}}5Oy#?~Gv!jD |=tO.R?^~mꗧ9'm/ND:t}]Y}muWۯ[~sU\Ü@_C?9cG^aӻeG+a[~Ǔc}Hjvۡ|/WWD]?qcƏ{?C׊=|ѣ=2>Wt`tV7eeō^+>_Ou^xc)*)u}{<y{nŻn7ߊgFoj9{/nlկM z>={n/ooD7|Km#3/ 'Ό'׿I7ss>뇡^}s}{_WÇ]SŒg&z[~}Kom. klT]40~G.`#|{N19'n8}!oHcN;ܺKfO| ~r?W3!G>C7i?6}܅wuO.+~'K)~nώ/[ FJwqe[9+aSʗ寵v/፴$;c7%gV[m5wy't]vvѓOܳ}|=&GODl^kL٩M$o"2&{V|H^~wqMߺ[u]BU?>C:/>/^f ڒ>>32oN}s?y&nDɚg」lcF>w}RznQju7tӎK%GGO^^]rrIS=w>^_o; yB5l˗G?7b(_yէ?2_›O8{Æ nm&$ͪU_{!++k-z%Q^-=7/LgnvKV4hPgeUcN8n.su [oX_~{H~!FkdވW,yw]H/<`}{%HpOޏM/Ɩ녿Y,]ym~vP hlޟ>!_yիW[qvva$D^d^Ix ` 'H0!/@ yL `B^$ &H0!/@ yL `B^$ H&=yL `B^$ &%H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^†ʒAYm+_wI9W66/-`[`A9yEes4:/t򊺎61KIcv)[X!oΤUMiw2e5+lVzfֈ̌&ebނLL\P~xz̼ij'6. &U СɻթO;1rUG7zUAyOW+). 򮪪98lH}seUk&u7+{JKg(оy𲲂0z驛6Y鞸6tҲtevt֕ϼ?7,/Nfy;l*31ť݋ysF>\+/@: yk˗9%wY(0w. l5sCJ'dL.;*XV^^ކyS+uuòJļF!+7|YͶ>..V_Q^jgV5Ǽfv5]ؘ9$7'ЎCޖ!wܪvS(zЁ,XRQh_eW̝8p#W8dā]z /@ @2$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^k7}-6 @b `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^K|{o{Gy{饗j讻>3aBȼ)e5557Wv]]1V\ya?Cv۝p #Fmrr7~eKT=5G%/H'gOa2ҍ!DKXM(ډ'$ Gϼ~Nz(q) RIDATzͣn3.Yru4'kСc~:~!Q~wu Osޓc5#Q{ߘrriI y}>'q{ؑg:#n{gwc9_{LV~~V1/.:'čŋK$)]dI{;[kr"۞olfVžgWwcCwqcl]sG0:wװ)}jxNׯߨF_=d>K޽paЧ}*t&`x]wVno:d h!Xz%K.m`Z-#F9v_רʢG .=@+IU rי.`QӢ3N8h_~sE-jtu)e7|oe?٫z^l F~yG{7;~#򕯝};zB^HdB^H @ !/@ yL `B^$ &H0!/@ yL `B^$ &H@2 `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$XYiU}u䢼Xv^䊚Uh,՞ S6 >pVuUYAvݼ= 9qA@O'oc8|Y X%M+_biY+:}ѥ59VELʗ_~hk&mBI歈'.Y7(5wPv^qy &eWVu\aPҪwͬBک~?r* ŕqpz^̺ЙKk;_~[;wno8pF6W]65U!,;wIX܊yƈ@Oi7䭯M6 Ur ~._RUV5TLt'zJeA]#;';x@!V MȚCpwժvhl\ 8jxzXr ~.mhgښ婟CFw₦\}TCsK= &MNw(o{\%3O>yv1(wrU}gJO,bBnܺ@Oi? E3*L\vQѤ 6VO*hY8|j^@v̚+:`R=7L&MKW]XW=(w¼S+J:L-8ut$uzDVSSS+4N-X2YUe鈷$WƐk(/L9mڅjR#о~]0v3 fxL_0xā'^~K 5wM7ݽp#;nFcWn+Wz>P<]v'yˆ#vcܼܰY?\o7ߌg~f}o:t&nB^FG-'Gy̝v)|@k8s,\O~a]VVV:!/ BZIߟ49`M'oyo\ԓw>_xᅨ=rkzM~"~N O>d}܇zp ]'/ Iɻ88h.% oH~Qמy;EB7>{gwcЛ>r vqljI y,Ɍo~{w]bN:Vk9 ɱ|~tsw = `xXVgQ-_r,6a2VX/,{СOTL*]潓?/n?M^,?ӗEC\&|ԼC.m`v6ȱ#FCC9@kI*U r[M 8|hZ(z,qgWZv㢦K (xi҉|J;_%ߟ{]'Jx+SW.ڿ,*& yzqÙ-\ڱ3j<{+tوug,1Enq]2d?Z+Ц$kyƓK ]U|!]P}CʏbKgݜ!`HR1cF?8=1t4SyGuIzr,JyG^dzӣC,ZBޱt,\+BldفnkXP]}W&E읲+)gkʗG~7Ϳ _8(tѦnm(I9yyQƳ'^<;nIDAT{S<5NxGA}>lI yjY\C?/y.K.s٥YYY`HR_X|;nW^ZO|EΣFp\O^v~`sIRM>C[&?ώ?zF?*lK.yw(աigO9O'ǿD:C~} {z'fs//OkԳ~XzʷB/'/U y#ov=6񅅓&~eW[M }UC^6 f#H0!/@ yL `B^$ &H0!/@ yL `B^$ H&=yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `BP_W^ɪ'deLnloʒAYkM}T/ y!,fnm%/ :[!gRժ@Kj5TWLTR6;l KW 7]_wU]uљmsJk٬,'k=m[˄y oZP KfmPntu'4.;xt˅=neY,|>r&WWMje7o}eNB]L8yw-]|uKIcv((x9yg]~Ń㼓Ɯ􋻖eGHE;9n0+?< #) ^gի1Ɔխ4hw\|V4o9Es;E'!:?ʦʗ1kTfzp^^*1qM+sK*ֿz'6.⮓Fn߹;: ys&D%3'N5S4━]KB'x 5eE9BԹ Ғ9 >'jg 2htYyِT=*KO+~%yJ.Y01ܮ7ij:մ,PT:$o¼tQj+yC/^ k3YçO9,:۶ϺVrM5y-uwk&o氱x9q>tGCeS⊊CӭWWvָt+.,gwIſye噀}F2ze6CUuUrZ ]0ui-GLQ%5q7ްem`nk^o<6Q'FM*n#-<9.[G/;ЦCܭG]lyQV++L_^^ph99mvM\Pj@G!'\,qMOî{;OX`t!Uԕ宷ecn5c+jB 5Ux`^ @!ouEwܬgegjA!>P9œwEOh7%-c= #O/T弹tO5O\-^!onϺGƺ&\<|PFVVt\K'N .6ڑeu͗xtvt 9[í+/$Xk,885cż E3ڬ-+XҐ^(yRO,!d555zrĹCκafACդGh.:e,g_t!װAY_QŁWTS\zKՓrjwi(.8:9Q[0[1xՓs68.]:O_GvgmyQfl._vO&ovg̚8jHsCFx⬛y-}9!=|beS*W 4t'8bсG`K+3GjUeԼ:W74۝wuO8k3+Z^`QO^>=y'.h,H,!/@  UrG]7!+3!AO^^+/}ɐ-]k od5sk@eťr;lk &H0!/@ yL `B^$ &H0!/@ yL `B^$ n+mГ &H0!/@ yL `B^$ &H0!/@ yL `B^$ w[M=gCO^'Όmvx){ F񅅟_إ8=^a{AO++g\%piS7q;^ \@ yL `B^L=8?Ł3wRCs/nc.^thز,<@ ɤ\5u5!?wM{mwt|a _ȟ2sޢ6O,<`|͚63,VBZmҿڋ 9wmJ[XQ~EW_<}:%koӼBEfQNi)O~DVEؼU NOi-svk,O_{bkVrmTSհ޳wKG.pf~ΝiQqw+ӛ SP2;hvQ7YFczr69R{+lS#o.NMŃS(Rsrg}SuoRtw|̥;U?lΔg."g]JEsɪx%s"9zht553]j岤j؜ٛ7I%t›Z2?}<9u!^\tkj,\,&k8}^@5yO9f̀3 昋7 Ϝ\q6w,=N?Enz(mrNg3;rmQw☵=sW_rřR SGQsUZ,cnxF'&ʂ[l޸l7 yN]!!,[n9o-qxNm77|t4zT:Ez [[9(բyE-t:ٹ֫` 4C7efaNa#5v-YM7m~<:5_uw.W},#_;5'o8ogO#ڤm[@z>XNW3ZۓwʷrsG4wMu[_- 鎽8$'4Ta8BέԜztfɜa !5dhhh)1! ܱOy'ގAa Cs,~rmWD l>SømCKIDATۦ̿`Y!=XQ5/ G7/SRή]=́'Z0hhy#lk7Is뀢H>kS]4肓gU2{M-[Uڦ8f Dܬ&̨hQZ:,"+?C+*XK Nn5Z|.kGW,sq5 μ?/Ho*˻ڐ|!]}Keal݋6yT{EktW]tqʾnmo_y7ն(iq3=ղ)S6d8.{:;\gs|o ^M3Hn ?jM&oғ ,vж/]{ӆvtC/Uz>={n/HY10͢FW@d55a7W^f[(='0Ѓnp^CKRVH0!/@ yL `B^$ &H0!/@ yL `B^$ &H@2 `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^6V&Uw~mYN T_Q|uEEV6y˖ؔ6yț3)`F_P̬$[AM^zʦtQg=yW5,:(/'gPs켢Kۢ|薵sFO*Z34.[VY}PN󊚺~jq ]<ޗk]xfMp~EK3yF\QӰ`&.H<.})^RVׯژ{uױvjH^䵯ѓ}Uu5eѾ[CɔTɥխZd5MdPW*`u/Z []s*d555uzrքkY6neyΫ[Tp]+B&.h,nj)+Yԕnݼ%CnIt;f4;TekZEhYU,N= >ښ\O4 9kG!~Zu!+YO,ɼw?Ц!'.[D!~ MZ{Żwۺ{gc^xn^ת+/ymru+' ЫtғwtсѿGzՋy}eʗ/گ.jTnPx_w4rty}e%{=ןYo; >ӌX{ o7MM<|̚E+0g-x"C_3iF:'Tn9(oZWC7lnڸ 9䨫o>xjݺZNxuyfWC: ys&DIת%3'NsrfVJ]K֮X9RQ[YytiU݂7Hƒ'..+ʉ+.}b֨~|zIvCi<|L4xv^%bޤSo]R^CN+-j^ 5sˊ[ :]][6{jr|wF:N^VUn[_w*-(ɜi*ͬJǕ @YM޶7jH~) >xnQ܎BA:o(/ɉ #,]R6naČcvu1icNU5]ښts6\?x`x?:<K?oYoɤ6));fǧrJEWԯdTM6˖,.D+>fY;]RW6qFY^'TW5TL.[;Zjx ؠ'O>Ό -(w=:G<(;c~M7Ҫ9YYYEs$r&ͭ:Nu ͉G?Uu5e9;LfMH4]vјUu8lUCMyq60hYRێ-*ihyy#~ҹ>}d^jX2wrNMU1(2ڠ:>fgԬ]ͬJ_&=׺EX9RT,i|MyQn|)X-grE||j*ˊG*t@sKjj3X|Rֻ~Go-{RAjNYmt5( u&]RrKt\ԝie555zr^[qu_CQ6T>NxuUrBc. O%~ȡTpzRքyjȡWDW#t_fi jˋ[v?{iw֖]?U7 О~&.7}ěTu#Oj~E[Svo! ŻYC{z75.wq7B6-'e7뉚NǨͮsY0k!3sqnZ|#"gRU닯>- 2jO\7'(Y2~ᴫ}.ICϺz եmu#.sONJxC|iV> YY:meuOwmR2~Ѻ+ixOluՇDg{Y/Xʚnvp+}}+zA=;~E[Si G8yieCy#X7^ӍW0=]Z /RG=y$#f=!zPs҉ *@K `n̼HfԵ˛$ln Urnkބ̱6 `~yYޕM,/y\Cܮ%WT-@y &eIDAT8$tqŹ` 5>$ &H0!/@ yL `B^$ &H0!/@ yL `B^$X!ol2l78oz$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ ^G}^z@|v?v5j0 'o"n}U$_Xe{q|cul78oB;gM/"{?й?$'ʕ+=|(|>{#+4k֬y)<襗]ؘgzQz="a!ot_x܂xr5Wo|}œvؼ~/="a~wu- KKm/mݪo)ēz7KROw}~1rȚt>h}܇zp $ oA%}U ?9 7~ægu߯ Z&﹯jle+[[1C!?8mIRg%Kč|3].deemvwyg\`CI y/_7}fV[f͆}vV`~{]墇aܸLȻ|hG^vjo1uG뿺מ?GnYjՎ;D_ x }m첛Ǹk6m擟D~- Ў>>ǟ}C`8paŇz|_ ѧBޅ7rs~XqVVVޟ:`}O3NsϿ!ށzHV03[K.,{_z)@WK n8?}M޽C3f̨I;UѰ%koz0hhg,>5Tygΰ2PtwŅxr;! (*=laEzQ{tȟh4K\:ާwϑ须6j>#_/&oNڟxέ DN3>}o)!5y7)_~Y輜5U.jRݔWtߜ+nJ}}y;Ռ?1N3,J/*RsrgHSRtwzWM;U?lΔg.⼼YfRuDߩVcw2=S5y^R+. 5S&SǖY?>o7oV!QtRǓQyѺkj,I'm;rpӉFȜ;*eDAR(ɻh/W- h8sos[鼖{$uϼ Q5f̭8hyEosYs^{wVD5zENRhۧ̐nw\v*m6q/(M]K"'- h~}k]湧ޡ칅},? !MMM/땳|}Io lM7E3/# ='O~@Ȼƿ+ k_JΏ~ofN鳙JS-Nv{LZӿ3_2?}}17M XmIT'gJw[w'+~+V(aѣ+֦8Ef!>יJ4Z_؜k (ȣ^vYcxgz$|}Y9z*=ܻិfo49zɿկ}e2lsϏ=MZ>soXzntf.- -=B.NԜztfɜaQSQ)%C_Gy􆵽givOy';{PK7(6X`76Fhx{yƲ*=5Nx8Kq}_ Cwm#~fjV\EK(zH;ӓw*t7[x:OasԪ5/P;J"'ilT;.JoS/nڿO6kI;9k2&{ox_xē#kSɿhەO=oƉ"IDAT[WP^ ܵh%Tgҿ]}gK*RkN[EMasTeOnR݋NPTYv_<(5z̾Jf/Z뜢sn5dŵM3m~5Cd]:,"+ݍkhiЊ*eαK Nn5N|.k,s~Ow~mS)ۢkC_{-ژ\'z꨽;߶ܳ+;2ؿ輢kR(S/ G7_(dvݡy儚TzV]I5Wz5KC* VTG$}įVexTt˻^ڜ9YUylI_RX;.NlyB͚9ak`L+aO5 GMpůEVsԧV׾ nU:g_~-:4+}t{nO-Srv^M"-Uqng+X(tYa{˾좋CW;,ʻ]y"],ٖ)qnm{-v{ͯy>nϮ;)z^r޶1]?͞6uo)S:Ya횋؋ko ];ڸmHoώ`MZk{vߡ]V[ {>M_>hfx6ݞ7K_x=/lŔku\9Wq_; _8(ׯܫ 0 jG;\?(amac455}׿{N;ƏHkjxNJ%vjΰ7*]Ad#4447'GSaB/nfk]5'eqc^hm6S6w 8tUx>?q~XdIQn='/ /ƍ`Pw%FArm@k|ˡGm=<^^g;!Ӧv{fvlqXߊ+'F`+hl>Oč_=1G?~C  Ǎ}|'/,%jtu)f!9Ƹ|!/t`v?qy>ndgg.)]{-2hРvw]]{}4Sl>;0zto)fw5T^Cܘow~h%Jqg?$Y|yyq/~1r-C#k0?GD9o(?d=} _ؘp^{tCO;ޗ')F_\:=K5,ēЎw}u}œs٥YYYmV.8nGwYӢ N|Rs{g裄\vE?z(ؿ+gǓ_AA4~;ߎۿhʕ+ϙkE;տ3~8'455Y̺'e]lvrzWvDǪ[_{ٲˏ0!??T@]~}|Uzs׮0ᨣ+n薌nЏVAc0RM8vb3\G / @ON<_~>{?nܸfE߿↷|~(#Z7^2zkxIOǻ^|1/w{mhx_؎pəyy~l쨣oc9OJ>vx9 ̘1cW~t~E_?@}D}ꓟ83a [TF<5b"0Fm;V?I;V}w&!6:kعk۾ꫯF3xהO>'L{ony-[֭?4p FM7?:=-/RWO=5w+UVYewcP!ﻧO;T=N8p; FNJ.ǟonݱc/G=2D壏>c?5&a1: Qۓp H0!/@ yL `B^$ &H0!/@ yL `B^$ H&=yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `c¡T(M~eS YX-je?jo6ejz(硪ڦ CV6f=lj``L^F{64Vn~ɼi3IUV.*ʟHToiaUKw7*/6c|jZqyMcn XQװ*:¶9jŮӗwiU]sGcyRmϫm՟͙ܸo GjWs?{j\%7%;iWoμ|i9]Jk;o\]~5 >y5罤/Rד^\|ZNNaUS'uQ8-ZTâ[]Z]2Q[ޥwn=uSQ4Ug>]zgOǑ{ Q2!k6oO^qoCUѤpחsC=ڊI=g+H \; yϹSՉ;ZozֲM ⍚*vcG6*|Z:hU;Z^|ҥtQiNءm Y;o|Ǟֵs/'^򩝭^zZ+oߢcͫu^;/?NOr֝vܺny6u4V KfҦWH|s*CYr&^vo;iD7*:){v4Mk柚^refV q[oҚ]]QWX>/[ޣxbzͻˁfGYn;(oS›>yzk'2qwnwYC,.oL;[;\%1UեyC*/{UmuIT̾]WF]եe@IDATsV SoԴtZ*,OM+i\;7PX]RSl{꒍MJۼEᠤt_qs4Ug=)~Ӳt%%=dqMuRtUs@.o߆O/Y7<:y}+־o;jv"sU'Ҫٙ}?k:qƚҸSEekjMMOg+,Oe4JuBxyN%ښ #^su՝]QUI5W^]Y=wŪiWVdzVEt歯̄3*+K7WT5tp-M^2puοmsë.q+{vƲMUc.JH0-?8k^WeL@onh꺗T&]3ƩiťU5u(/ 0#MڸwkIIQOK2S[mͼ6HeI42cNWS<** *R[uY=nPTZIynh̆@o f9on)luAuWs]UiQ~Ǽkή 䠯i^W}=x%O[T;H!TݔS۷A9~|mi,ͤHw5VN:ܲc/FޮT\egOmn3Q`Ґ70rǮ ugv{ jk2p{}xy]S]u5 xZQ8dSk元+K繹,k;_-u+^q{|[7{Dz3vVQ`ܐ7 {޼Enq^>`ce鍙Arg/m]O4V}+3,Fβ}^[VRae7a5=_Z67U\:׆XӪL_T(mt&>475]UmAntyV70 nț?-fUus:ܰjQasnk +UjYcW_Zs~cg-*!6(\TXտfs\UEE5^w_\Y'kˋN8T54g_WYwt)ﲢU M[} C+u5]s.;wMMa9Won{Tiް<=*ASUiW>[խ_:W=\Ysn1RWSi±y9sV VՖdiNjm}eMgWuO[\Л+֥φn.iJ+ O6;juWwՖg/ksuIS;v칿4:y޹9>c٦Qn+i٧_N=%+7{0&VܺqUhRsmYqͶ?L:L%Լ杛.{V}_Nq5o%ݸugAvp_TR3_[t>7_5]7:{UD9 i {ld\n2Kxz{䝺쩃lu)8al 6c&NCE~N$;OˉW4\3/u_dے7@O^m-͟s[ˁl2nƲE`5ԯ:7ڦp!oap`(+ ?\3@ yL `B^$ &H0!/@ yL `B^$ &H^C^`4p &H0!/@ yL `B^$ &H0!/@ yL `B^$ &Hć?5֯'<֭[$͚'rguE:#[Nkkk+^{eG^^b f͜4؉F1!ٳ%2я{_=@?$'Ν;/C}#ғ$I!{wrQ)_VyQ?3@ƆGwDž]8l|_ھ}ǎSs ;?`**򄣎:'O~KߝJ冁ɟ:+d~).Ћ$ q}~+7[ v߶mS淿m\0038z%.x{‹/~{)SN6cF/--]&^;Iq՗pzN=a 'xB/}[?KÀڵ-'GK/`Px $I=yȬ}}g'L`q)S ?~|\~w6䍼-<{O;-/U!ݻǍ`ػwoxt'piyƘ0Zly٪_+8vhcQ׿04FOOݳg#7}EֶOæ?31>f NŦMQO0 Aɻ9.o0m^zIP_".|];۸`x[ /b8pcƌy7믿7)aP_%$NNkkk+^{eG8(χ^kc;돢Bnnwʸ7к!P*) C7\ht6o=|Tgq@ۺA6op26؉F DžT*7aO ?D^$/=p>}Z\xq!/JFRzu\p#yի( Гo'?]}{z|~Gm/6>? t‚/.)(dc`V\SPrFuy__-;#}㦸?_=|p!?[/^t9Ugt:yї ZRFuf_|6.SUU3}Tw8s=F|_[[۾0w][2p~C8|m{$;w_:z5dku﮻lqYE_8gyF?g{#<2~ n{}ܤ0rʖ-[z[;ku؆+EKSoڍ-ۓ~Uzٗ.,*ʭ{&]wl5߯/.Um=,RV2[E{. .G7lY┶G-}[آu7 =UL1IDATRTR9ڍd7o۶Wo?q-y_Э~ΛM=Nv!UR&>wާ^> Ǹs3ۥOK/ޯ=銹׉h֬_>䔓O>3gwއ/оkv'?sAF r)<ǫ/on± w\{׆uEm}ߴ{k˦ oQP0dLfa]z&E7iÆS/>{Kfaew[GtmݸUק2bIl޺ȬA[E3O2 ziztק릷M7&ֺt[.l_&_߶IKUNc벧kƂ]7de9E75ݰli?V:m>{q_kM:Mz ǎcL_SVC-┅ue_?3IIc3ץ?|z_[<÷._3}d0aš|ƊraA #N{ ,>33raɴd'*h[U[/ [4vO̯/YR wrr~܉CMYzS?6mr͊d 77)em=Sgl-wyӂ)!=crO:2X=]B{lՎamӂMV,ѪWwgjVN- g=U3U47ӈ!_u>`.C∱c~VO~/ucm̘1+{sy 70B CGs8PD---.dCטRW~U~g~~w.hHso‚q=*o~ >sYi n ?N;|goC!==yy+ DRtmءqP4ҝڬ_mԿG5ӏf±{۟ҍ~I~>_O/Z.WF_3?1+z vъ>ޤqo;󯧷p|Aɔ?}^{׆"?s9瑇,.0@\w>RkuUWU?Hx‰׆'o{WEkX$muig>JO&$Ly)cKmvX}V '|]Dۏy9y\^yW2fL1w]Gmsu˥o~\=r_}/\οvI=n}}sAFn?n!ϐ_ML旮}2qut(32S{'>3t{~n\ 7@/b\2>wp[miyycƌy7_xރjii 4FypC}q7N#A{u[a$h7&#p\^A +OWa@ |>]Vso|ӥ۷S}a@r rG,Mqy~5zF\%<`999=7*p|O ybA f͜l\sg>$gѽ[/^t9ah@D71<7^բIgϞ9΅swn;wO~G`޽Gֶ/ڻ;׉LԆi±'ogXxGH^{O~?If\~}]wwuՄ z矿۷GN8Sh7ȡ%`4=5sL6}W$\+|ƊryN<_~u۶{ ؄FJŅo̘1+{sy ''g̙鿟(%ِO{ p=5Ņ'~"w~.,3fT`DUsJ?5.‹DCmܸqt'0{oyK!3z޽k|饗JN:?'0Io7--=m۔O8{1Fv"s]5jKqyM#r+jk :{Iy]EzҋWՔO)j $]}9;^nyN]T]t9E i\}>S/UE'ecSi rej;utYݑMxm_Z3w\Ⱬ+ rrg_qbZnw]}^ѶCHնy:iٺ-l#\'2qǮ..oL;[;\%gLg-T_Qʄ\K+3ԝ5]OOEҮڊiyʩ+[ao3q-(|UQB5,m]W˪;pƧӅqs+.Y:)yʺy<0q71HkGg0(?tx ;n+7-˄]]0_]f]eݥO]iUIKV5Nb|^y} KzVcܵ5qu8隚)oSSrTHTQ[,()ԍ 9&[Ȩ[266Y;w~$巧Q41w|q&ËS^6\W~g0b);?)>E;V_rQ9Sy*kvjާ̄3*+KEdn'q˪yׯ̆e:6WWWn*&1*O[3mjs!7зT*>_h;qWTw'WdՕ5S:DRnnh꺗T&]3ƩiťU5u(؟?^Cԓv5'4Z9sY=JLUS O߸(tuMTiUI6cwKV|sGo]kˌ1u^qOc`J2[j뚺9 JK3) Q겣`Kn^(?溪Ңyˎ<6>ԒVd.;ZZ|ijPk:yj;:1+[~<gTVϣ/jxi%;ۚ;<C[G}ҶβLˋqWcUQ-;:bdh uT\egOmnWZ;l6vBކisV;uyZwuW Oc6^]v]Mբl7+*`QiҴҊچ]j[\i^~<2qxa溚LqYBzDM}h\ӯ/^ާ:}0 KQ_ u9O+^q{tψ0'MzZr2N\g,{qUIBǶS޼Eы{<Ιh^^8(jKSghU[ Gf^U߸2N  yOH7WUEyGvCa`Rƺ(Ѿ<綖0xlMru͟OV9sVz"җ(/}aWe.RQEMfW5gl9d'έa%U *.Ychc ?v酋k{sc]uitS7@_3v7gfTaai?'(%L?֔5:Қ쑦/kiW?~qֲ҃77֧/}jhcs]" jK]PLscjSoX>f޴KVc٦Q1yjڴrYN=Mw 4)Sk+05 ]۳ϥOޑ,Kf=sϺ`ʞOd~ь%Լ杛\ىS;;'̽#6 ظܳ_V׼[ϞiҸqQ/eƭ;6_TƕWu,sJnwԚN=蓼ugsea88 +wnҢqmרl@l*=S;%ߞɷvޤ9G֍A֥tak,STJxQfo|:S;&oԗru\pCf^"MzNr@pFp a0Z_+ ]$wUœ0 k8MUFZn[UF;+.1.`d8̇kH6$ &H0!/@ yL `B^$ &H0!/@ yL `B^5}̄c' QH0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@^{v9Sx^eUV1a;cvr /m߾㡇y#SN>9 W˪g}6 WʎLVf{Ή'оdǎNx\oouEyhB4؉H֓w͝~[(ޕCc?{ /ި yO>^{M`9 aIDATzʧ?I=aw}k=!oqߺqOx{ :z„qE{_* /o7|cs#qW8q'; axWOŅGt-<󎷿ձ{o}(3{ ξxK>gqSDG8?~\)=T>|K/X[y룯 43>t_ąn yBJc!444ą=IkʿxMy%pQG3=qN:)P* }?iA\f=Cj̘1{B<> ~~=vm{@3{ Q#>mZP;7k}tuGY3gѬ?j1W,=h65ƅɓ' к!0n[o[~󟇃u. ?C'po_|dLDžT*70xq'@Ƅ^{{GF~-jzw---իW?JO#;C7x㓟.ݾ}GTw 7}?8|C_}<oŅ9l #GOfw^Thmmٟ?apެ"ɊS r.i'e'{NaP:LCއsg~˫]uNaa`${Qy۽{wp‚qGܟ#zwʔ;0 `( ("|Gzˣx]O3oo #-Vեdkk޽{e?w8餓h] akO#!Lg-r#`ܸqa3//)S~n]oN9-[к5[X'#i/*X-[~#TE/R%Ej+ZZyXm│g;(~? WΊ0h]MaqaeH]k{oU7S6lY]:w;dr]Ms$…5{;uʴpfͭw_.e]NgC{y\U[5V3?k&awl!t>ʞ#r.!} x pM)n±(g7ʦ ew+B QL\6*yz ٯܺmc.زaCzuKB ˋBT>0kMͤW=&ɪ2nYx}ۻvjvlMGu=RiX3 [pWkfogZ┅uec>F^3-/e_9Oothyvu .riSWȂq|ZtVXv"ڪ&KPtE|,glrLNd^fm[o񢜎cL_4F!npߺ]xt{xdHwaZxcӢ , EC[7tNg޴`Jh>W,;>>䳧[xsChi{,A=S=uBGWf0jK-I[k[ۧ:Kx]ݢ{~95%yiAۻ_n{dc6DݺhԪkn):rE9JFItpyxF!՗ﻰ}0Fݻ^u>wgM?=H5z;veݶ_~x#:s~0R{Gt$܏lK'k_Ǟ=;.M$OA%fۇO̓q6t`D;Ǹ_SOumI*t [\;;=uW^]┪̧zt|6I >zoll aJɂ^‚d_c\ݾN>tch|;'yO۞/kD}mϽ㗻칸Oz\_I?f62LsE/}c,MwL?~kIzg21S:+Hoxa<*k,D|Ԃt :nCzYӯ`ptȤ͙:7tlT[嚳3c.Ͷm%Ӎ:ڻyXUvaNt&zert{dLzeFm;]k;69h# tōmBDȢ[3u>!;t5= _ք#҃w9C@tmaxHmOxGM׍E 7o\7#4Bn<ڽݷsΣ:jߚe^ohh/t~8( x#\o FE}4IcJ@YǍ?'3OgXgR)FC%dG?}]w]>\CSO?^ypxi│'mK2FkVuX`^P8mFlA}\Dw>_Dž7M``?5Wq/LWc=6 @BwF_]vŅvK '4kiT8е4!qx!o*w=6y_}m=|jaY3[ Jɘx?N>SMOC-7??1y ;՗הtoqH7=Oz'!2{L /p˷}2Bn^x{> _>o##7a1zk׿h??3J!G_}ѧa1jCV]KIDATި̳F_FGep͝JeUVOJ>rхw\6:/bimm o999]^Ug壏>zy? hԆǿ]8s ߿ض-{_|i07s'wƻޕ?`Wv&ŅW_ vܲeKT8S60L8vbe4O0 yL `B^c$2^@_7zȐw /|3 QoȐ7?_=@6^RXSxch¶%}9y'^TJjsg>YʚPnÆG gT !.^;wҿ9_^{D$s w{z6n< 9s g{t\E]09fb{8@7z{m3</əΩ_Ȑt'?$~yڵWT5szT[qQNUsTSPwlѺb/.U7.O)۰eAv_T=^)Uzׂ˛,ͼG5|+p9c; Ip &LXXq[?>@պaL&װ̪|}\yyQKUv h_[|hݰd[UaR٭6'UrG}1ynj󗟽?7WwjÔ_N'Ec=i5{Q-+{pۿxJp &LJ&1쳻. c82t7^R0@_ה6[//7.~#6m̿Όð~}Mw-\l\hQ*`aisUّ.Z^qk Ӣrfk7\.YX[aMdڻY JƆ=u { aMn{~FAW3ooqvoukpmODo \ I `B^$ $XANAÛ &%y^}y{2 &H0!/@ yL*zCE8V"H0!/p~ƌ Ȑ'83˿t]Fam„  Ojii sLd yڱc/zI``V^{?8d׿^>ZO^`n{O~5$ʽuU0xF\ c)90=K/*`p%5SU s 0 D0a„;7VfTߺaúnXeyё!<>dÆl֏R qŵ k&f-$dyfyf@9Jl7.WPR<򢖪q7lJԀ(M ~Es%dOw~Q<^ի}5eAooQP +jmr :nk\6~}ސ*[w~TmקGYpA4>Ux%w;^{׆~teT5c'?qg7d~+0|冊PYx lz_[KtW_9\ s _P]/go 0pB^.tˆΑ]kݬDž :m}NJo 69f@ ⢜xSewyB ``$$ֿ5 @O &H0!/#)'!/@ yL `B^P*0^}y{8 yL 0qD$'ps?x38#$_.ڴ1.L<9 ̘'xb\x'@b=q! wiqDž@Rرgg&I!p\^@_7{\=yJR|>](Wy7Us`q˾qS\^_rM`(8 'hEg˴da4Ǖ~qaNA%ǟ_zYf\0`I y#f_|6.SURHgLN`ˆ%cp[qQNE_dM7M h=.zs/.ۙ^xIy`0 7P7|6$ۊrCHmۛ^*kkA׵6[xIš{[~#-)]]ߗ/*XھNj)eeNk;6h]M3y뚅9ES6l鈂o?`3]ߥ/[X't:%G]*~#iztYv:m=ýS ;.n@g׶;2OOFVR0h͙jeaiv ]?sm˱w;%S^Ng~ߟ;I!99;n/ $a5&LpƊraYp׺(zo;ҺaC놲)UAN,ߐYa]Ѷmc~5e{Sf2Lv2](Z]ޯ?\{Wv?].^ݟTyקKfվ>nu5^Yg~Åue~lʉ6BžGīrfpMv:!՚"*>9B-ˋ' ή\ J̻m O_+ul`K|- }./ uKDZG:Ncߥ(OWmOWk(O$g~)#Z'W"{W~t~E_?@]RK(>{liLNN]\ca+** }rYZ7 X]kg޴`J>[O}*ǔ"wݑEwlI6gZw%+mˈh_&ZݢsEHisi];EOY= Xx&@mTu/Q}0kLSJnrxڎ n;/3쇫>Ee٣IDAT,Y;3?j5c'?qg7d~+x_7T2AޛܺcU;tܶ7r孙.=>#fL).H[ryɡ.[y;r'~{熺ouO{1}}ީNxw}^=ݽ:kSץUmݐ՗X"k8[w-z ;l±(Ba!}ɖ'媣wy q=&/aΘV6.d`OŽmG/_TA"=~`4Г>j}&;*TσLi0t ۃ1pڻ6QF-زĸ}5i̛[!pn`$ rZ[{ Wv3Dѓ &H0!/@ yL `B^$ &H0!/@ yL `B^$ rZ[[ɤ'/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `cê2?'#) &H@2:&oCEvخ֗r:WzX1oU}UiQԴU{x] USmN/Za%s5iWcmimS%͚kumcNWII{W!㧕}޸Ay'~mSe-v?}W׾bc]6*@m-͟s[KEY21O @"ړwZyckkS˦v]\XܚvnaE3ܻugM+/ňVw#:hvqg]dƧ^+owYu]]KwԼ]%Nx'^~M7X}]u(nnݸx˞jm(lkees.KR2'㜜Z_ZyAnش3zm՝~}itSCbt?U].޳X)>i߸r~_F1aHlS}EQ*ӓu|~iEy&@KTi]0j(7)*b\x_mf[65-JQ~rC]Ӯ˪;pƧӅqs+.YUQ8)LJe{^<|~4wLssc߉mg=dF_;?:EH yVtia|v܂~lgkۇDt+v_\Y5;S#nmLajEGShOw{y=v{1~R|v䤣rƧREUV6*ZAe>Cԓv5֔O4ZNΤ>Z~]Ij2eG~>hx,UZW[Z6߷/3=|S%U]$9!ڲN{k<ڎ/}̆FeCE=3*+^ڸrg붦+O/l @R|ڜoeNm֝/mzozpA>feT-v㽢f[&M+mh6eى+@B'MzZr2N\g,{qUI~vwmӘ \y_fь¨1Ùl*I-j r3ʛV\VQ`>Z yOH7WU7jݵr^Q]PTfǡ.; lﺪE7Ϲ% 1buxfYUݜJ z=uKrsIqymx|UiH>+-O;wMCu2u΍]Maccy.Yݲ򰽶4?qn+ MwyUIxgZWz!oCEk6w{ʆsVg__gNMIӢ97Hsz2j5{*'u==!K^HM]&Y; /36vוepJ /0ʌKt;^g$`tS_iMx#\Լ0zF`⵾4VNIpT[u` oU`d8C޼ɝ_ZF|d3@ yL `B^$ &H0!/@ yL `B^$ &H^C^H N DO^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$XCۚu?[yf֭a{챿ַmo+9sO#LNkkk+^{eG^^' C#˿엖^;nܸ0M8vb'~冊ktm?ٳg~oCo{ۿZyYgu׭_f͜GffCޣ^}y폝;w^py屓ON6䷝+_yO>麚uwk_풒A2fb/\So&acF_֞N9{O@G.Xo7v-󅗟2eg;jcB;ygފu+(Oo;ݻ?`aߗO?ZWa]oҪ/_>䷿s{8Ԓ򮭽׿uT7~ o3fޜ>o-_$wGvr8>ן 76lݺ5RI y眱n~AAwSmz۸G7n TBޖp9g[0-ﭡ05?[3jksM:f\~}ӻf+O^ᩡ>wM ?G>IDAT?>wբ+P};0/SߕJƏ #è yߺ?776wYZܱ=aCW_޾Qz\۷>*cγLnxOqᛕ3Ȧ+m4|/^SZ~Jk'xb\ Tn8N>-.;~LK\.8pH%)# wm¡/_'7WO^KR|}/Bkkk^oqp%)=#}㦸Oaa5sf\p%)̚9sٸ\??ņ_!ko~.vD/'Mo #ؐ47||эQMO}=ѴY:דּ=+ -O??W-#_=wO~?I2 a09;n/ k̙ `_9M_+;t^x0,J.u_wapNF^{ߋ04rs?O}gyFpIvK7B^8$o5 yL `B^$ &H0!/@ yL `B^$ &H0!/@崶IO^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ &H0!/@ yL `B^$ؘ\W9oZj|NIԴEU+Tt76JjKS99`X9^XE;ZZ+ÈUW}[K-m8X yˋ~,w5[wFvƕW !w^ɴlԼ6kaW9&oSm_W.72p{l`T[YZ?mҪ:j\T<-j3>5m^emӾWg:~zN @6Keϳ*<5"#7LhhR4 ՒNa50Aa"iWA IN68ujS6 aIynJ":\u]N9vdT4Pcg/[:l|8 ;\?s\'V.}l}^M]h0i5:ݰS^{ZAeSY3/_dn3)$V+^jmݧҬmd iyv"{Ҧ0Lk[\_Q1oNaeÆSO,(lޱC~ebZ s2RFL)(mkh72۩E=rnJXQ5tX,sccS쵐~{gvqaXAQrpk]}m-U%9;]KVܱڶƨvDۚ /z`K~[}^ɛwc}CoCp6& 9Y횢)7oXw}/l{s~.=Ғmmu& >WZ\]N cݵ01##lk4`{!o(7)s9-ۚ fL ڝ4"?Ye%nooHuX[Yc׿O"]65w { '͇?#P[ضiS? 70.L4.g?s~ZZZAںu녟+]]{w`wp=ڇ֮N1CR`ySF>=ЌTWچ:w/ק68䓗2;7ǽ;+'+)̯ټqs}mCo~Nќ0,pM%,^TKu0)7Ij] o܊*?@43C|vΪU.[}xg/c>~"{wܹ.U.xC+$ҹÎ8,^޾}g.0Ro߫*O9ye/ /ǟp*3| @򮩻}>1}ʥaCV8/zrn^C㎜ua|p?鏦7zk8Uzq>4miyyw49ѺKeË;)8GD5u>sn?NFs+q=r{ԣrorTVn950_d~} /E)mllLN<eygM|x6ϻa]y;w?uMa!fha( \)yeg?;%mlrY}q@qjyoգy.*;9]V˲7/+` >u^Smn ;ߑ*r-J!okkkpi' jm|YuJ:6 ×1YO>Wd%I1~vq#;f<7o^p.iQU`;{6.;{NM[[MC3z]u©'AHB1ii] f/[V5wnxxq%u Y&hʎȵWwO5 w>XY}j?[%5{U}ye|Y$KvG<a9{YY7_3O9y/~x ?aXYZe775r%юaQliM&;yDb!;]z;/ ߾6C2Z@ J;G=g5'`qa۱Zקk0YY^;k!lvS}a 5NT4o5&{m774ZyTg:covI0kMew 6Zzxo`Fq^i۵k^[wq/<ށg {Qe3@Wӵrv\vVn;M{r[~ހ~Ϥ 7T.gCY/*bQy_0>Di$G*< BcS&fK obXԳfͫj;QEs'o\QɁSw}}N6wOEޚ}0{$f`XyOG[b ;WcK;RX,3}R;mZn075n_+/I͢pɗmZcݰA{AYm<7$yupqg/Ⱦ}5q;͙uުMg0wV̵̩gyp_CaI]0̝k㛋0oҟT9зQa9cǟ^cî d jAz5ՄIĩ .F秗%"e]3!Ck'/|?Çƺvܱ<-7k*|S23Di$﬏|dJNb׶[>H^mNp<8-/eۚi|a]-9wcnln#?wTK~Ei$|uwVo\~X, VV <Ø'`Lv {1%z E aB^D „&0!/@ y"L aB^D „&0!/@ y",=MFD „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D lʜ0ͯl ɠC\[hǣUu5l ǠCެX2t ez[ꆪܒꦶ}삍͍ qXI.| scNˈW558޻ '#B*raGmu%U7r=oɶ U6і_{<=֝oj*ڥcyk[9Ҥykk 3?2i.صVsϽ=2ϼ${U[}i7o\HKE~{Cyi>kKo,~!Y޽k;=33ny]0Hh$o~eK{M˳XfގS~[76gR[V.˱;wֲS[]pdG;y Caɉ{/6x N/Sd?ޝ!̯ټqs}mC{[BTNk܂d!`nvVuߧ~0dz}qe像w1/2 `s]ە brkMC3z]u©'il~>L?*%}zͺB%+S[tXIDAT/۴꼬Џ)'OO/|Ҳ' 5K+6kʒ-Na}zI,YYtN1C;<;7teg+gY Yadٟ{Z_7 15Jۮ]4ڿc{x'~i55yB<#=WȞQÆp)Ff}#Srrⅶ[F}|qߑv}a̞}/ʗ^Qɻ/_v]ߝ/_~_y}-/6qCеYgƍ-Jg,svƀ(;}ƌ/ũr 5x'~7Ѵmtç>-͌Iq-47b5?_r}iæO}CNԩӧFH˳-O5<rW[n6/#.^T>A?:OڌO`|w~{FAgHP[^|n cۍ߼k_KS`9{ɗ=ư`7_YyWwvؼO}O:0 yE;샢]&0!/@ y"L aB^D „&0!/@ y"L aB^D d$/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"l5Jbii0gSƺ⎋-ksU~_~eS=Zj&vQRSyMC0B kz4ѪDWBް-)-훖gh+kƂXq].;ִ`ثɻӌ9u兹9E-}X9#[\Yxs J*k3v۫0ei=W5Ť.[NU7m-uUu-oZVݸ=MN{Ċ*vڡ{nЎ]1q=w?Mdu\Ĭ7м;?5A%jsWCnlٵoiCy/n*qc%}ĥxyk[Կ]~&uk4! wޘA=nwg 7~w}nUiăsϾSoh,Sw;Jv5ob[*r;]]u]ϩ7mj(Ŵ՗qЧ囚ʲ°ԕ;Soh6陙74oMsMaFG{ִrD{}kގk/ w*倫9xp!o9+[8Ҥ5P O^{g_zCeAN2>gyO66Uw Ơm/tMeY͕.x2}j &4UOY{3ZWeo!K0ؗ=79#kh3ܶPx /xbAayS=Z H0&_!ѵ}Vϟj⺝m)I)S?&u6IpOISz9M%g.T k.=5܂O=sm7i] .(id^\]7{G5if6,MToYk0{Ɩ o.9LO\쒚VWzJ߶/iNfssR)VTwۃSr+zc֎4[_>sRngTv}zL+Zv~0;nL6)7-o(62 aԎI995#'gRGż5/ok*C]3GɄwҜ:ޯW]^o~# `_0߽>n ţڒD71VP$ilJՔ@4yꢜdR81#qͼdeeqyCSJްf~<,,X!^Lcy[:e]YA,;aG[b%f[c]EI7MŪϥ'5tI3oRKwgfiQ,If޶U%sk>%"$s܎CrKkROiʢ^'8 J:զ;7t<'z|opncNIEy2~jJRookSaC 9e]M JˋrR.~ }!ϻ>gܜSXQW<9Zhox f/9HF666wTTݝ,4'eVU,m[$81#mYyΑHU5n+H oHix1 U$ԊʞUNYar?9us}iNHƭ/ٳo(,y~X^567a|J韫*e&++kw NxUّ.IlL=Vw<*jC_wz*v3qS_gVW e8PM5 S۟0xXxHfR#1p,)Vs(Fڍ}߽;3vY(]3W6v˾b%Unom;{Z<`U ų]LsC}/ij { r ֔X>])͍ϴcJG/:rW`ڵ/ols8 ni/ f1)9e RNoRozKj ~Ľ_{9gLy;&Xm~# e y'-XV--aw j[]q'UlyeκCa?ӉYeMmOhw.jo]HaBXaI*<|mqVjOKKu&3qknaiE]#l{ۮ22=ah3$9r%RW;SoJձSNS{9^U\ׇTYm3ˊz6]ZjM&䗔Lg[R]%,V[Qv0d›յچv.s_C?mu%cV74ݖ}mG=~HIDATH2``#7]Î,X0%#W  45$T76u^]7 v|aFJkoo・(ܻ'JV7+r|vԇBTU=%mm/w$uiW3saj?G<.k \HKDC瞳K7weM-5G;`3|G~$ʼʬ]/%ui׶}MC}<Ҝ]͕9.'sϾʂnoL[]i }t#mq}H4qv=s{'HsgsmAh]hg\W`ԥ KCLSoHd֝C4x}هاksJ[^3[9 oZ;ƪA&;/m-&qY /?rӼK#w [wh_ѰuӚN=߿4;얌ԑӻyջ11qY/ դeͻ4~]/lmPˡK:;_ o7AM|ͦM;%V5oݰ:VU&emsԟim:äp缰oc۶GgL|$;Ϛeἃ~HC4gmԳ_LCNop# ڇ B#ya9opKcyH{܄@d y"ldR[KKK\Ck촔ĵC[0#y$64+T?1mhb%um=|-5E>D"[l9wuUnCz{uC`7$ y d~fSK xUXzjz%& D „&0!/@ y"L aB^D „&0!/@ y"L aB^3}- u yE%$䍇O;O}핶⟧~<}[~O^;3o?7K<ʓ7n|>~P)I7VQ"YK!~[2kOnNDuE-}-uW>O_tSh^QFy3|:c}(5qE_|L[1&qozoœ;:{:Q{R}'_O͞}UZ?rc~dcǿێ9ą'Fh~>r{ O^QFy{+?+m_{n-hc'~Ox*Qc'U\4[Ӫ>wL}:[?S>S% W^QFYxߑ}䶶ڹ) ~PmҢߟۙmi^ZݢޘRYyE5i6??2=:/w?9K={?msxEy7?e߇]r~ZO#7^v敿J/,|~FGwVwnxAy=v*/} bx5{اD8O|'?p̅K%ߥdm2:&x>^rr~_Sr`j_?ay7xe 4({F$k'Oשp_Gḅ<2D+qfÆm۶*'s?||n {}JBgēO˓=sy;ƅ7|sMݽOS'7V{Wt1WolcRZZqp Ƌ?'o||sbzz{ DWt`ƽc{cE)B^` a|Ǜ7onnFԱfM>昼3(^i {ɾ0R4O~Gx_E} ?=ob yw0B^a$/O_]Z*\|kx3Srr};Þ}`7~ya_vm[n2QE]cH{k2U]R?u[ye11m[׿{=wxWWť_Z[߷>k_T+:yEGE0sۿ+><:⮊O ƽ/}ϙ9kެ+λx7sz` 3|T9wFʧVR|C\w>qNMm^7?`^Qvyկ zP]O:8)q;RW_4.q?}R/Ï<Q8/ma>=(^xƁ埳~WuuW>8-ona7W`_2CB;?\weygMQsǀ[;g|JVs=*'V~E5/l^pcW`!okkkpi' 9+r>!׶m|Yo8*+fp􎳷aq]Czk{>0xNlrW_Q}(<Ќa>cCkڔuG?CK, C=-{>GBeY=[CД w?a_ϽU=׵+mdi9־Ji[].]媼 Eq n~ݴ.B]N?MᢎG)hDҿ[[ܥ/2ȼYs-]ܱEi$oX~yjiֵmUK+ Rz;^׆_mk4UjU؛ow;ѳwܚv9\7fk_bWh˻61\*-jGMkC7wUՅ%{$#/`W]vt/2zvSg+ @F1}핶]+4W`uԏ)p_g~Lϭ7?O&u! ~ܳKR"\ݭTn}9<#P}a|HqYYa+/ 4^;/Hn|: _r0m\1Uef0aj^~Q F^>]Iv/ Kf٫;/+ CW?WsMM~[ Kucnʻ*YKکiu7_mf8+ZUyg[sgq:ΫzׇxjK ɯ0 B|kuŽ]z"`B6 7F_Q!u^uKA0*Sl+|ov}7a9w䜽,u5g p9Cׅ}cZ n~ݴR]r w_јC&}8C=d~ϲ8=QU +y8 ͋-/..^*!g0 _>|0y燝zEnqzՕB<>/Ǘ^n%?<yWFK{aZNFӯi_lS5xEƁVzs)w~FߺS>Ѹ1XO;8&//YCi]}ݺOSY^QvG^3g?_oxyK[/u]~iO;>0BOᾆ߬MWK(t뢗Ŏ&(6!Enߡ+ P׆XzM|.HmKKK2~) KS k1/ }ȇW\;!!WdlwɋiưG޷=# K/u$h@DxEo~Qk4'W¦aXf=j9a4'>?/^|] DW=/Js4 iiH[˜ҟ[oׁ/+WxȤψH~~oh<>z/ݦMVסH'|x`/DVv{d'|x`Hγnlkk{G n:Cy_u_D{ D{5]Yx اaB^D „&0!/@ y"L aB^D „&0!/@ y"L aih2 „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&PK!908FDɛ_a am-6WnNQqd)# '#+lhm⺎ꚢ{yݶXeL6mX+߰ZFNAYuc[1w+;J[X`ֻV65e)1{wkO{9S͜sgc#n[[ڙU5%YC,+55Һxc{{}Cs{Ք^%^^$761Q;1[Z۴fޤxyʢb 7WⲆ0 "ȘfV,y-5Uw'~5s9C}]mg~~VCF6eeV4-%m,vs08G[o;4U޼=ٿ0 ysr?kkZlki.ˏsaϊV/(<`JNImSjdMYDbc^2euMmM6Wx%}ʖsVve3筮/?m텏4J^<7^h?G;cW߆if^HKe~Ӯb2ϼ4gbWE]q}*Jr2sf6fIS\xf=/#a otfR=!{&eϼ4_ Eu^,+DĄ@d y"l䍜ƊU6.86-%1uFDؘ_x$gC% e9`54T-hU]s7d~fSK >`O@,aB^D „&0!/@ y"L aB^D „&0!/@ y"ϐW%2)Qc$/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"lƒŋʯXTF6!WV c~<ڇ֮N1CR+0^|{M15k_[[nYrK 7u/*5LaB^D „_g?'?/-//.OKTv}Wյy>+j c>N[Pzto_tNgZ{UoptXn]iWӵyϕNVϮƖQC3:iҤ-[VEmnƊj 暥Owd r((8V8%Qѵ}pwIDAT!?sUUυUŐWve &Κˏ=NJW_ky率oim_*訹+E+.jEx{Ί+2;fUUVrs1=])gOwo۶-yڥp@xGՌp=sJzT+k&LSxdjHr\ү7.wIs!j]xrvOdB3Swo᳽:w]`k;lAbg^Z^^|T Ct/ F>佢ᆼ!S8 чN F>`?!k}&0!/@ y"lƒŋʯXTF_7|3Do*_Zmt'պ}]{nne-}S<0H}B4 |pm ydȻe˖W^y%U>#nd[!o,*d$/0"K.L{{{0"ƭϿpћo'_r~Ri &fU7WNJҪZWPp;<7vJig]ٺ+Ànz5K'o۶=HJu6n=iwswyoX Mg>}1^x-$~'^>Ќ0d71pi/U8ß rAŋʯXTFSTGT}Ⴂ[ S!N+ւ[I]yzD{Un ]pGAbE gD{!Bim_߮3khc>7B^D aț FD O+m`c$/@ y"L aB^?!Afd+d$/@ y7x#U`E)=/cSOx}u[׾.=ܲ䖾Z7lhJ? qG O>T'|2U2nR;mZn䓑 yl??r'wKjVX*|S23F@BYȔxŗ^tgCt_@7ʗ^0˗]*ϿpQ'|j~TEs#!J!o3f|/NYUu)s/Ǭo8&YN|/_lΚO9=]֭[_g,xOofdL[o #$b!o\kirƍyv̈́ЏiJګ#K={r?B^D aț FD O+m`c$/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@H^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „_Ս9i;T6ң*[)JIaMKWϚbŵ--ű%`:m,QUGț[Ծf^+kukVSyyk6޵C|8+۹(+iiOڴ<;ْ|S"A䍻|ISFKun!o\YYQ4U1SOM蜲kɓ'AYees ]S5̩M!sʊT ++U`Iejʆۯ=9UCvEyA`/k)R,) (#---ЫAab !5U^ddtضk[GUvnVڻeeuCW yS6.vIA=KJ&%~j޹rEE92a]cՅȯW3{.-V[SZ5Օ̾xUKd#(}ʖsV\9oucMQ,^j(vm_-5Eݺ13X[0O0Hږi̎ z3λ鑗[%^G CF aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@@xȤK0!/@ y"L aB^DRõIDAT „&0!/@ y"L aB^D „&0!/@E>]]O=s/B9r_uqf.Ƙ^^uK~cS?L}/_uezzzt!5#thF+mCm[w}_68䓗2;7ǽ;+'+W^}Wl޸{o?hNx}M2^|ט&bs#O?+͝[qWGFA<>?9V-l9O~=NtMBmGRjK6,Dλ^^S/)^rݜQrƒK=/C@Lw^Mw{G^SyMj~qqgl1E5+^}䐞~ {?3?SSo-{N;𱇇rrڕ~9aӦM`PyRSʙ<9<Ѹ;6uF3*^ ;~lA0bͩa =];:+/;zxɧ]1_]ϸkNC6,w`P>8gOrժЭSƇd u9j-a%KS\Ҳ3vc|vMٸIV?:9\|iiʓwbZWcv;rܓwYY1>'(=#= ;tٲ^x_k~u_wٸν;`hS˞;vilg^8*gɌĚ_>5R1/ۗ[u;vir^Uʺ: K1=R /~]jULwļ0ϛJsj5'M=>7ܰ4\s?GsE-/0D{弲~?{Y>dM>;C? iR׳{J˶9 m?ɭ?DӮ;<0<|D'Gޤ-[T-EcC/5K&<7qG^v#&/^ 1 b"/@D^y"&DL 1 b"/@D^y"&DLXZ"J^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"6Mři)(lh.nKK,KuU'sM }ڼ;CU,jJ$j=[X)Ƀ+/}Ao~E f-~"?5Wk:?Mɗey;N7Uev畼#s +MΛl SZ6}xbۇs]}v9Km[\M2l6VTzj[Uֶ!@yC+)n{XS!KFqEmCŠ7UV>)--tߑ7dv}߿VPZyފʦOSJs]:ۘv6wύym ZZڟGez6/@_?ֶ?䅽Ƽ5FmF\TZλ~eƍ胾Gm-s[G̪*{ccl KiDMy/m1-oXP8r׃uSm.}$\[qR ג{ 6k~lא>*K׿aڎZ @ DK 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DȻ́<|D'VDL 1 b"/@D^y"&DL 1 b"/@D^y"&DLXwܳrժg}W^ٴiSwѣǎ?3 !&-Htzb˛ж'/;^sv؟{ ye}=Ko߹Ƿ.#ǎY YjUai'L֧!fG|pdjxO-}==峧>өG9yه=<+'+;o77X[]ْӋf~I63ݟ 7ɛLgsnG͛W|#a$q\`͗ܺ5y .?>iҧ`r]w/Iŗ/Zh n(9c%vhrnmm! ;wK&|=t#&5~3 "jrHHa ÆŇpigܵ!3?SSo-{N;𱇇XCvVV9ߘ6mUL!5=螮}ɓszݷ4v>ֶwn?6t}}T1E0aꄞB^νVqӯ(dVVv9}0lذsw|Au`0~>mUBOz?&uz]1q{1>;&lܤq\.4r G;yݘN0:c|NQzFz޷wte~_Yg6. woeσ4tz{ٟK~ߍ Pׅ+ {aú aO~|֜/n. W+j^YWgz)/^;cK 7c ٗ0ϭy?< "ԩa+B?l릥3G{719ddd3yRT1E3g߬MnN-Séq!ASԸq&/ }چ0ff;<թ8 "o?~jx螇n*/>&nIDATqͲos/~c7Rg>󏅧[dwj~7qyjwS_x~amۺoO>#!;?ȓk$־t1g{\nw^nzG#ɹ?Iv0{弲~sz_^&#l!rwIO $SZ"Ė77G?{(yڵ|G$țe˖H>}00>|衳ų|i„Ð'&nD^kty"&DL 1 b"/@D^y"&DL 1 b"/@D^KK$8Y 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@Ću~<']9iANWdս{0/3#u*#3q.7Wgu*#3%гah]Yynj-}K2?4W<ܚ:̊OwPУu܉,l tțW֘X>eŠnXjDSy~rh{ӘsoښHں֙6.9=`{,jJ_J/<ؼ zիI]ڦʊ{gچk7Th{WRݴv~nrE.SXQE%5]m +*jnTYzƶᔻkKsv?SZ{)múyeU=ۜ+$[\k"NҶBǖ [53݋j*n{N⑝ⲋۆ{+{^WRfC Y3ۇ-:jY޾v 7w>Kz:7+':KyԛFn(/-KmՐ~Q+vwm2Fnhz'o-pIV e^#vöQY}_9w )3-۟kzԥy9G0@/2[6V ʐYXٮj ZS6snQ[:tQ ]mm۲s\Q}m3K*.6]PǗ5V^6dP^sm,/i/#.*- t7dW)/|usۆg.5}{mM s]LrqjX|޺gUH$8T]w]uOCUQ[߭+˜zcgfOs=uE].hy‘a%odW7QSrGm7}T)Wܳv{飲Otq^u8 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DLXw˛9xO 1 b"/@D^y"&DL 1 b"/@D^y"&DL #gU>˯iӦ >cG;6ʱ3f CLZ"Ė77mO^paɋׇw|k_o!#?SUz~s͏o]Շ GŹB=rUiN>Og{C;֟Zz7nzgO}ꩧS/>s{xVNVwlysoo\v}+;% l׷g+홹?"/o"ۓ7:܎›7-GH'3ϛl/ukky\|ҤO6,Dλ^^S/)^rݜQrƒK=/C@Lw^Mw{G^SyMj~qqgl1E5+^}䐞~ {?3?SSo-{N;𱇇>{ʴɓBƜP_߰iӦ0b GtkwLsk;z|͚Ě[%WqdžH|FkݿcJOOASmnnN NYy!eBvNw 6,w`P>8gOrժЭSƇd u9&ONNn3&x5{гqƭ~pur#7'` `tcv=p/]7.p˚q{1>'(=#= 1m'K-+yo]+ km^l\vfV;o\֟Z<رKCgwOO/[ᖊ}ܾ۱KÕʮWY^i%a^hx! uRCf0b'楆Ϭ9c']nϛJsj5;/mx!bG+l/xsz_^&#l!rwIO $SZW__ahOn?1'fv5G!#?8&mٲj/G{, z/~9_00䉼;7}D^y"&DL 1 b"/@D^y"&DL 1 b"/@D NVDL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DLذ0 vR\u;]S!+y"6+y3kIg/J^w[SC͂ₜ̌)(lh 5yW+nh'4T~yFf6n H ;>NFf^aYPݏ 0D7kXŹ)֕z ܇7.Z*xR[w]_=ҬQ*IDATOMUEym̨w7Tg;q޺iE5,(VSX\ݺ+r=qYI. t* ƥ o9~q3Guu%Y;mJ]vS>RS*cY\i׏|⚶ye{{%ﶪf7m,eqI<3X>~Cy^g׏`iOed?76nqzA[ U쾇3w4L)(mҪ+ƄTԧYPۧI~ғCҊ_TKm}uUCJϑw[cu7kii#Rf5?E'zdC]mksvqa yEMng;!$r`g[jJfh[Cdff=~Zel}a?g+y! e; ov-ƦM]Ǘef555uV]˷]ntmCm]snn{94WUuvCmMus~~VB57v͝RceQ_3Ffflk꼹s}ڊϵTW4z(hn6 +]JVqi6o,h~Kv; % ۗ.8o X77+3g] 4.(Ќ%{\S`ֈЖI'fͭnܾڊœӗCFqܶa쬂ڦP=7gܼީ!2\6.lkj5g^_0f!&'w~\ZDWZjtsw7ǛۦxG̻7Tg©7>;>GrkmuINFǁK~Q,M5ݞ# +7|Qۏ>?tCvwdW7Q;n1*wk/ۚ #v .Ioj8})W,f /0uw}%oK@$ DKذk(IKk.;"-%! uVDlZKܜKrK u9}ooPWٷ›Ă `?0#osFIRRC~"&DL 1 b"/@D^y"&DL 1 b"/@D^2nyssGy"&DL 1 b"/@D^y"&DL 1 b"/@D^y"}]\g{W6mb0|=v)ΘQ8.''KZ"Ė77mO^paɋׇp_Ws"e}5?uAW>:GŹD REޭ[Szˑ#G\z&}GduTAK>_/yMMdOO/ "/,&?fM%333COˮ*YszzY>iҧ9H Q; WKJQޤ/_z'M{Wĉy< ,RwWߧR9_  R1E5+R7##go o'ٳSoS'Ré?咋6mzpy+]5ݧ>uAS?P~ a(yO-`1mnnN S=& 6lj ~%u;֓v{H Lޏjëx{}gy655+$քs?v۵~ۿ6ׅ\x39mE'3na} y'}}c_~뭷@O∼UK晟|x̜81/5@O"_=esr>_\~pͫ}4t+o]㏧薴Ogӎ?>9$s=9_'կ7[zyYSXu?꿙~A;_Yw?7ꦝOXt{=@&o655M;K/yea_>^R,t+Tod97yya{zo(}o_O_,>>Qxya/MA]bEU7շZٞ/$$%oZE3߾dm;feA 0>ݾpAj_n?q1{7mR2s_ݔ΅ ^i;6񞺎_o'kl]5Hނw |"p%>8g?O{.yiVZJ%|I.zQh__.N[w[:wunygE'>ݫk>'~cځE}<婧<~{י|uvխ]|~6[. >yrk/Hk74~yݖ̔Ӿ4mYḾ|'[ױ=̳:ꓟE]>E^C %̶֬=j%ɻtS˞;梶]hfǡ;Wv9QC+r^U:=Ҳ_^S< NZ⼼|?t뺮wĎ}b}Lk /_?֭[OO=tȑ#. >#:cOJV[_j\e%osW7iao$qSsYο KzϻŽ9@Uw]R-;gbwm_ջ/uqz=D"q9v?Sf)tSxN Jޡmj2ަi+~0m4%`rZlBpW}sT OXt{z\S?[[[|O=9lG5~%mSp˩}}Yk3ڷîk,XuλN_NjI{kvMɬSܱO}j?9mH6г|) =2k>;wn,>{aⵡ?s٩y5+^}䐑ŋt2$⒋6mާpggqD;Tݧ>TCCCj8cDޡbذaS߅0c]9giC&MMv mG^R1ii#Uݶ}l&=̳aԨQ=WOIDATKva G<=ff'{zD޷"ױMƍ/[zUʆR֎;ӟ׆̉Ro9477W-]g~DޡKRnyգsΞҲ99gu?`_y:v!HsyϽ_6淮xStKZZZwۆxwO>9) o=K`IK$ }Ҝ4c|bFa75G?[^Sq0wUM>"@D!={Y[l |?<Ð$)5 QʇOgC#Ő-/+yg~v?L6xg} tPڬ R"/yԁhy"&DL 1 b"/@D^y"&DL 1 b"/@D^%@ 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@Ćuw(#9v<'s#3+j6l3;<#3%гaU,hYzٌ#)Mmm^ϝ^V7z[C|bcEE.W5&/n1kyM<'T趙EUMY/o]~X Э^VUmH?skoŠm5#3qˊaGVԭ7/-*_&n}H[RQZ:}vd .+M)bLuiɵ6mZ/"oSeE)-ysiuoEeS譑ťy%[?lBϑaJYiNh[f[6}XfڰqCo.k~R^.yk+*6'eEsSwcU 0zU_fgn?9tf60h۪*owAi;4;Ioh]XQ˯_kijiZRn#oWu^Uަ\_W[\PBw+ײ翔+ƴ[QQzR]ZV'g5 qQia+DކWM)攖~n~m[ˆڊӗ5 ¶YK#fUH$8TU+v>}C}cَ2ؼ-ϡ#N$'WCSuqK~E tmXh#FΚ{飲Otq^u8 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DȻ́<|D'VDL 1 b"/@D^y"&DL 1 b"/@D^y"&DLXwܳrժg}W^ٴiSwѣǎ?3 !&-Htzb˛ж'/;^sv؟{ ye}=Ko߹Ƿ.#ǎY YjUai'L֧!fG|pdjxO-}==峧>өG9yه=<+'+;o77X[]ْӋf~I63ݟ 7ɛLgsnG͛W|#a$q\`͗ܺ5y .?>iҧ`r]w/Iŗ/Zh n(9c%vhrnmm! ;wK&|=t#&5~3 "jrHHa ÆǟzySR p`9aӦM`PyRSʙ<9Bm댴gTpcJOOASmnnN NYy!ekgtC6,w`P>8gOrժЭSƇd u][ oBMKK/P|3wЍ }3f|Ng}yG.[*8;^m$Wmٗg;>qYw~' yS˞;vilg^8*>ݛlkwVhٷ$?.߮O T?pݎ]WvռRL_va^g]Ԑ9* "ĉyao#oOWSI)<;x/m6oc9f(+yAS=3Z^or֕D"VzϿ|%S=#OTzSxkX7oּTY>ĢSM>m_jj klm|떳'/GoCloڗ>>Bss NM=WH#|$9w_tBCľW+^ZNLF# C9; BM6-H}= l˛}cxOX>Y_Ys4aay`we7"/o5:y"&DL 1 b"/@D^y"&DL 1 b"/@D^%@ 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@Ćꪖyi)#s J*+7UgiMU,lwW\Qa[{=Gޖ4n?y?<}˞ 5¾f5%Ѝ"oSeь%a9ݚhuCOUEUMYW'5ř'kv=TUtjyKf)_<ڼd*yCPUp)*r2ڏed\1* W@zuRCFƮ'J|RRAIIDATƆ@Ozy'?(),ili󄬒D"QWm-sfh1 Х"oF qƸSP\i#v8CN_{*3]B /xڼ7~eď3) {U6c adaEcbڇ)F{bݒskZ^˞R][X{9cڎo~5p0L/"oҊdTKKbی9EHu%U\ fGƊv97q7t92=5tv켬;yצnCSF 5 H>=qmEZZWϝ۾Ҋݪp2_yLQQN襑wTkh²ƖzmM sfhG\TRq]~yլW *jگXS?gڮ=gkZ+K@_0&-HtyrCE'.km*ʛ}o׎ywCuqWueSol=sC ,\+y Ƅ;~S+NĈϹMMޤ7uVrgM~ݮ`h;0- b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DLXw˛9xO 1 b"/@D^y"&DL 1 b"/@D^y"&DL #gU>˯iӦ >cG;6ʱ3f CLZ"Ė77mO^paɋׇw|k_o!#?SUz~s͏o]Շ GŹB=rUiN>Og{C;֟Zz7nzgO}ꩧS/>s{xVNVwlysoo\v}+;% l׷g+홹?"/o"ۓ7:܎›7-GH'3ϛl/ukky\|ҤO6,Dλ^^S/)^rݜQrƒK=/C@Lw^Mw{G^SyMj~qqgl1E5+^}䐞~ {?3?SSo-{N;𱇇0sRC}}æM)644ӵݕ3yr]^piϨᎱǦ*ܜ&LӵBz-++;6lX;>:0 |pd?N6mU[㧌=B_du&[pGo(O>;g3>3𾍼K-kwv]|qf N0=v1 ϼpTQo w͙aXᖊ}ܾ۱KÕʮWY^;B a߾83sTT1EމR F?os+ͩyI`Pygz ?c5J^`yOg$[ue"տ^<5_z`y87 5?7C͛5/UO*8hi`yOv׾n§۶u-ߺgoˑ#G!ǟ~>99ϟ7=/rþrsu?R/Iݶn#}V`nEmtWSea%3^/ä>ʎ2#3tAmZ:mCM޾io(,i+?p/T]ƚw߿wݰ+k¶~W7?^/,.oSUazڔw?{gYP_}Jqe݂Ygneu H$:?YmkJsv)o͝]=ŵ5sw<$Xm\QT+ ]rKu%Y0-%y'-=Ҭ?-ueSo|7_5V]Ļs'P37sƒ=ֆ̲ӗ68qq]Nj2MqFy7?mooI.{)wo)xbKf-OTvq{7)W<^S㯾_e#f-PU82WfWoe?Q3}ck2 o\VXָMݞƜsڶK[X{9c587fe۪YESolܶm,z,^ٵ$MQhS/Ҝnĉo'h;'Tt!sJ%>:Jm :ҠBSAh*A+)2CKG JPQt@JB@V!Q\%E P riIY9k;g9۷ R[{E*L&St^nivsw9{7rJoa5C75 M/κO])ٲtἢ.Z=ۭߥ/*_C'])>.u/({ԕooKKvx^QQ~n{ʺ(ҢqswK}eIg׻ޖ.w>W.$ːw[=Z^ZS}O0漥[H=Y҆UufIDATk}cssU5m*^ښLg 4TWe+z.iʞ=}ҲNVִl>y5g?uqC?Uɜ-g-Ow_i?}fG,dھ~s JV7V4l; o:nUU޲yu7e󮫬n9[cۻEoGTS}vdx{obT❝Ӌ65t[^eׯ{pyTh[Z֙İSJr?W~iɘ Zڧ۾3Ӯix]ödNihk*3 }S2+j+ <;t*` d/|w_'9[yIn'gݾJ۷wS]ynyqpI|64ߒ𷵭cmK*ww**2߉UFa/:h^]s{fj^IAN:t*Ғ.\>]>`)(ΆUUK;=T[UV03F[gƖUf[wf^qU}kG.٥qiE5e~iuSknU/,+Kw󈶺lپYNiMCvnuMUy.KO0욪x>}mmnH=xNqҦ.eEX\6swd7Փsj* H&i);7LswSMinSeΕKpCx-חgN_W8yَ[N:楥9h.:_}L[’cUؙI iG^VWQp i*j+?~Vm+ۦ~mM5eηTrQI h*nO_i1}G/~~˲p5%;sgg|]YgSk W4Tttaa1lnի֖lvn`^_Q7}ܔ.kQ4iYg/iŪ_US$SܲnޔiΖƴ'_On9:ST+N;.eWO ,'N/5륦>b΅oK-3uvTfԷm9=MYכ;s!ӷoon~ѤnZbgް%ܲ׳ݼ%`$H^"1HtΊW4Y+ b;'/C,7Ht,DVzz09W }f$/@,mu'p}_s⦆y!6{Х@L K{꺖=R nB>(*?{R1GWA q3]@,1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL !0p71 4#y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"6* ap37M˳pmn!N_q5uh y]6iߗytMf>³7NOu㿥kξ?N{ޟ=}c7==g'GLdγzg v#$MejM5<}£ȜAi:J!u#bx&>zxi?璣f+8v݄m0<;!x?-͎|/88[%jZfU{TyOk|';?vpqwod~~-~irKJZc OwMO<gB~|<츲Q<8DodX{g]򬎡O=z7.tSQy.kwڮ>;:"f_{OAz$Qdz츈G 1@Fk]N{8u-mu>G-l>uWiAK_ʴ㴎x뙛xƬr?ͺ7%T^_w\LmER~gCT˟?+Or衣G {'Cys|/ { OӷLm&N:8 T>v?^1=]?G5Ƴ0>jUq6o\/Z[[Ou! t u?o~->}xB6ʺ~ēOnFr} (e`0:|s 8waD+{w<#.9?KbA<; {])9F}gѩxG)k);f̔C? 0<;ct #]?> ώ` !/05<_9?a|׿uE}aD5{I٩,+% N]I~ξ*]~v4QxZ՟.~!益l`FN?\VOi3m* oiM>xsiK'EW`Ƶ Ƈncg \t(!볅#9b&)v_ݍ׭O[gြTUw@؉#m/Psgv3!lî?;Vou?׳0`q 9;sƌVv?3//C]qL6KSq޶l!an;RkKniipمZlS|fUǜ[9[[\ hWZtn[6œK]zsg۾w;[규N 1ME6IBa}Ui'兝3vL2 o*lL_Tpynlͥ/Vg&UvwCM}3mkUanv-7rCV'ӿoύns_LwMaG˳pYWtC}~f:gg0&0Ft &L8T!e_vem/{2Ϊ:),[p[_l )JsW!˗ɋ׳K#I Yxl:ge)s2U{nabYzckα_O69S5xvzo䇼~׻l_<~a$ {~pѴ)]ܪc Slz)=occ+3qd<;Qi~uI_ ^o?ģ͜v1c; S6sjL=ԧT)iڻƳ04'?tXï~*lJ'^g-az?{w~0ݫt`1z;?駳5,7eG {To򑆏S` xvFD2vklK_H|krs n1n`E6w?YQ~ ?T;)D^|3=xGg1"yiU*Jzm?Sڹ{vtaxر`yvFQ!ZSzXD"Fk|̳0D<]|O|1E/綶:n`%BOym<~ w8o{D0Ľ@D, c"& bB^ y"& bB^ y"& bB^ y"& bB^ y"H&8 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@FvM]Y". 1#y"&X"LԻ9yۚ+>܂KkJy ݴ^XR:ӸySڲDҲl˜dwV5m>QV\WUV3eUu-ytqㆅ]?#3Ug[P^֚Ķv:)61','[^=]8oKYg*܊uҦ i#y[kJ μgOZ`'r[S*̈́. yc{~q4ԗoh*87t%9]jRa1t&mX~<4/}g޷9+5%aOᎮbzuv&YRե]o: y]ngg|MŻm+{f-~דi?&v4YҺ}g߲*Wtʤt{/k !5\1G.Ա=۫V6O>xʖ~M<7?£S5<簂-MӧtًW4dfZOɖcs *jWIgVlͪ)ze#CIDATr;']XWS*oQв}fRћ%U O..|igҹmky%9=/:.]P݉6/,-rJKw8Kkks}b~IA^Gg)48;~N*)21c'*;oLy̟ڝ#c7o?,~z y몿F?|a:.'[kI9za6msJjjK}cYUց`N{ٱ7--ۦ72^QѹXsã?\sSqUQ蟱9Oݰ_\6iSTݺ.>ͩcOߝsҭȴLWKc.z y[2Sv;{n'̼ww}uaL-+&../Ϥ45m7WoYw-bXٲ's?6 `7֯_/:i7z̆>J;Saԡa' ;kz&?//캎tWpv FN{'7mNW8}ǟ׭߰]7RWݲ`Icٳ+:p>ufRmmF)c)\~QvކnGi6g'bZv}5LTZkץ;VSzqO/u|矾iVMr +Z7eӫVܴ`Vk沆>J;j3EEy=%e9TWUֶuנ"/(nIo˴~暲m*tyeyaSQ^MwjU0<=mnқc^R7cTl6!R]H$r;Ky%u͏\8)]F[G>F;͕9+/@8]CnE!֩% [;enaIK|j[4;/m6ڴ<ﰋV7..xoòKZ__Uwtz8h5fm-MUerѯkOKwq뛸pteʆ>F;:h^]soMd]r/ D2A[}EA&݁IT[ڵ5,,9ncInZk N]9w-w⧛`ЍDK ɻgM$-;9[V&*U]tH_))H^ų_їC&yiINk`U-MYå ބ{DŽtvyQ75DkDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@Ąa+#θ&`1 bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^w;-&FDlCޯ]]-\v¾%@_$d;^{eCiǠ罻̍0 ]`qM b y"& bB^i!ى>7qUǜ[yۦW6.< gže+sSv;ޔi׾XqP&M66_ 8w~M$d26顾ʊeHo.g(bs{n<97 {{t =JO` &8ՍmWvNAޔz^/zeӦM]w=> Opw 1&U4>;'x⨢c֌;2coV^=zt7[da7]C*\|7믿lW;wӶ{$_s! a=' /׿5[uO[2{Qk~faaGsaz؇;{W*5 ?>z 6L81ӎVTlP? /й /0"HǍ7rp‰°7Ov_tQ H$nwʆ/\7z>m" /Р1_a^;&3{cw _AQ4s TzX;Ə&=*D؏/v% vZarΉo5 @`D9yO/'b1s1'/0?!3rB6f` 1!/@ĄDl䄼'ond$/@FaۼysQmnn>w1_apG|9 (GY6 c׬ C"ΐw -ʐfׯRc5˖!eK/} d2 3o>_ֶ! (Cޔ .y7ð<#`nu>߫>i}8loeWVEK)pnm^ٸK~/Ru`E93M3?cΙUЫ#3 o(1٘z~5\?7+ a3Ɋ[-:eǟpbg{LQQQ{WlѿUO렊3Ϧ],(}UE_bE]]欓Nq]`HD7;ʫwǚ7ӧwz챡VZT(̼f/VkD YDb Ovmy_Lmkț5nܸ/SӺ{_֋ o=Xvc N/|61),IDAT0$ yǍw]w^Sy0 ._ޘ\>KŴ~oO޳7TxN/]p~U=ذ[͜1;߾߮8`viܸq_8cyU;=p}1 X^K7?o__c }ԢDa5{I%3gηoxk%xᵐsSTy5O5fsC-&i. -}{Yo=._f,,ȽqW>6V?k.L&+09!C3$tmLuɴ(L3m2qM YDL v.0 1!/@FNƶ1 bB^ y"& yO H^ y"eȻv?|G{a& wk5`H ZvmVC$ΐw -ʐfׯRc5˖!eK/} d2 3o>_ֶ! (Cޔ . <#`|zQG?pDᶯ1;_rpg}O~裩|7!e{ӲufƜ3a]!^ؘLn.ݱo1o7^W޸nq-;SSTD!}?s+.[//VZT8fcW-ߜ[ƵSo{3HxWXQW׹9뤓~\{WQƍ;zWE־*L1.~k8tn6Ӧ6L7qDs~ͷ+N0fΘooV02zƍ9W<~BNvwCc,Ŷ~P[$̻>3~OƶDS )O<,??Ux>_d2~s/okې*O9N0b yk]-//^pIf_Gɖs D" Bޔ3f|/Ȗ[]=|U/]rpaa"}U{fᘹsǴh+~Tgͻ𘢢0" yS*GN˖׭Y|sά8ƛKG f/T\̭xcɒ7+ a⛓WEnWٲO81ՙlM*޽`wO>:7]E҇CkKv+=Ocx}uuN:ǵw!e;nܸ{ʫw>˭27p˿.9iaD~lKuo/m޼yѿ|;7UClԨQ~_]t{kPFyO^׽'{~9}nL9!=TS?֏^i{%[Guᄀ_ y`,M9gn(rvZ/?MO~nD"N è΄+eKZޔ܃rS}9͟{= F>c|~5,B~sG~OʇkGFHue1c\ak_k{^u[~z`H.ɽ>?p`N9-w`65ov1n/,̿Oa<\VX5ժ~ Bg GsWBA;lަyEÔMZa};sƌV = ;Nfݓwta?՝u@عUz-luW 䢼[n=IN!cڜkݲӠvcƎ CkĆ̻΍-Izγ;Y;9WK0H&x _:gxuc[_|?9UCۨ#y{yU\0iҤ?n]o)(}{!SMO'mC kz{1w֭jvss'!1*cڴl!; 'g+Oatӏ<2 BS>lbadvZ/G+S>0$b yO:S.sfzo3JV0`GN=vjM+Vru-2uobFa]z~ə?ϳ_^auI??K.<?wݛo=p}1 cFHqțk,=!7sƌ93w0 y`;䥗0R !/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL D2 H^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"&ب^jkZ wl"kln~M-u幉DZkrQV(;ZSZp=V~݃ן3P^z;VWMx}˪_~=OX|.rKkZS;VnYFP#y[lC0uM;̫\.4tIx;-<.v\IOPH$ C/>:U1qNyQ`6>~?zawoJny}2/ ZWVW׵T۶@a\ yyXlԺaan;9Co!ooYLyz )]MQekӊ9TVzjy%SSoS+JdV潾)OTܔ] HT5H!ysƤ_S]2ԧ췥zumuu]K``8]CI`_mS~S[smya Vd2c%ܷ~G}w]ui^[mYևyy0jg Z_̚:iҘ1Zp˪KKv` bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"ÐW6FqM Hd$/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@Ą>Zr͚>?pЁNzČ~ϜvD2vklۯ}/Vvn%G9- chCޯ]]-\v¾͛7/~u~5¯|.{C }H5! 9«7^Yc=/gܔ)~0$Z[jzG+md+]}7ˠ7!/Tޞ1uu͂Wn\g]޴)O|bmH$B y~o֙}lCKvc›{Pns<'{]vH7|GL~QEHo=TCV?^{H^bɻl;f옫]=LސYxk}m}ҫ=tO? B?7[ا?v !23~ Bަ?ӭ) >fZOSȻ~lcY B(;DiUI}&)Y#=/ 0FAӹVXΜ1㡕+C>rGΤن.%_uӅɋ|B?7~Xں+W}*}5(lL6xgRQo,3C˭ۿʶ3vLZd2^efk* OU}gҥ974H*Aognl }7nqna! szh藇 ,Sƻ鑼_yfv}W5g &Mօ>Θ }o{ԟ3jN޼LºUnn0$bwڴl!򆾪4dcV]ΐwG!S{ʧ?-{_l}1I/MIgŏVd˧|S`Ht≇ m/]:-7~g,|Tyʡp!SȻ^{-l_;gmUIDATaxHwK/ y`9y2B^ y"& bB^ y"& bB^ y"& bB^ y"& bd2DL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@FpOkmYn{e6oOJY]`` -iMf H^ y"6* ;!7hbAQ~`` HyMy=[-40pL1!/@viN֚ҜD"-W]ZJK%g F Ϋ:^MtV-k[M ։feN!;*HSEtPBkD&vID~7qqCx"o͊5и:,1 bm/P,;lܜ-{8e=r.ڴ5tze}g D* L^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@ڌv6bs8 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 bGk_|q/m۾}{9ÇG?ONZ2! L"Jz`0=W_3W_ o/zC qGh 2-Nzwoڭw߳%'݊N ̚k֮M&;KG;CMG?VCWvݻ|^ؐ5|ƍ3rsnj =ggWk[^[b'ִ~f-}{s7yhٚ$+j)E [0#C/Hb%='NtzoBT~UUUqueK,{Kg]s~􄏦{/\"{x¤ 7,!N9֊[3W^}z8"着^`!4/\2{?"O ν1DŽ0 6nپ}{W1EޚԳN7I$y#tZ#& .]3Ɵ2~Ȱ!@)ر#38::wtN~9q/"wv+?_47Fo'?ٰacz?^|ns =7o|f3Lzܲ}Z z>Λ['/񹧟Qf3aӏ>?C]2@zգJu];o~'O~N:) ` Iđ7m׮]K?].я~gvjD^8y9 Gn@  b"/@D^y"&DL 1 b"/@D^y"&DL D* L^y"&DL 1 b"/@D^y"&Bxy"&DL 1 b"/@D^y"&DL 1 b"/@D^ Y 5%CCų+jff'M-J&:*3:[_9=מ[~&~ycGUMY{m*Kf olݩ&Ҫƶ܅[I*(]޺07Уڝ[_1} oK5-f%KfXl f.~r"J[bkM?,o-e\JVn)78Nh:0,PWY!'';tBrvMjv;LJT4*=gPή.N&kvuV{3ypA}ŪUE>N-.s@N:}vߘõ5/@?kw%͓y7͙YQSNwjW̙0wK_%RT'V_Ԏ^xՒ9-[_9=9![QA::!9~KzMSFoQySnz`R^R3y DK 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"fݵ1㆏L^y"&DL 1 b"/@D^y"&DL 1 b"/@D^>.׬]⋛mC>|=zg~rԒ d`Tv6矿Yj}/[n2dH>"G_|unyWvһ{n%m]|/9iVz3v=†3n;f[6IDATdN9;vW_7C~y7ng1j@?)^x͆yRT[?f_wmo1E/x3}gC[j-)˟*>oK@)M.*_ʌ+W^~_Y715/ DŽ,?Ɇ /m?s'睓wv^9\y3gKjwnV>y=2~чO\T҃8Tۗ=~߆>1}%_ktIa;nM"iv\Xuw~܌?;SÀ'&AD^8w5Zy"&DL 1 b"/@D^y"&DL 1 b"/@D^%RT NfDL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DL AmYLtFrQO}nEyI~ CKWԾiBj63xjӎ=={vlz0,g@Oj3צR srnMhߑ5TLhlܾ73mTzk~&Y\Q1=8nQeA—*fgm;4;֊Ǎ?jt-6Te%YeU !;Y4?7oVINw*g4Ƀ)M-s+- Cy+6.CK*STޠΊ5ůeԬ/i|b 3:yHjkjN/)l55VlDŽQ_#3)C2S|wzB'g.ܚJ[Um/NCCQ9е5y gaDCdH5\QU֓Wn EެʆTiᅆD"inNIئ3ʆ֞P=Mi3 ETW,k qYE쯟׼ˋrgEŗ?4ȝL!y=s̒ LșYQS߼<;53s&Դqj1T*ꁚɉsN(], VԽzڨi֬(s5s3yd/yC9"zykSo^e!ީ(N$WzB5tSiM/-2/@Bhk;+>qvV4mT!cϻ /@陼cy"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 bmF];G㆏L^y"&DL 1 b"/@D^y"&DL 1 b"/@D^>.׬]⋛mC=zcVt9~HRص1 l=zWC:i~O qGH 2-Nzwoڭw߳c ko}Cz{yHdeoգ{)6d6g q1$sBʶk^~·v6g|Æ ҫߛ G"oj/+|UUUf3(c F~|d'o暵5͋>e>H$B׉@7 QyG[ oueK,›}bvJ-l>r)f{|Z믿O44h@D3^rz"G^jlI݈ѯ~M/wr{3y;vcmf0jԨ-f*N8ᄽˑ+[?tElvG>1(c yy'~z1Ei\|ho$}=ZO'b^pd2=hxa^鼶nw6LsO>$"uGf wξ3 w\wGښ,N$Oy&]/eƕ+/eX6WoN_cw?ٜ3 @_I[HVf[ ]=I?aƖs/>7r~9yyg>QfӳybMt}Uz{;n =mnV>y=23GWS.Vp};w7_}l2ׄL^8REyvUuB\TTV^6lذ0p;I"/z~M^ 1 b"/@D^y"IDAT&DL 1 b"/@D^y"&DLX"Jd&/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^~rk,Ideى( A:o- 0mDTڪ};̝ɼeUMGR[6]5uUe~痮JWtn&o-sG6͙޵[(?H/ !Y|fzLjҙҩț{+G4 6͙YQ:jɦ'- 9STCeIVtn&oE͙Wu".H7gKuv%CF?jfeC`YӗTLi=uyYtU*m@/ʍײ*ݛygΪYyyJr+)VIrv@?KR@ DK 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DȻkgcHq8 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 bGk_|q/m۾}{G>q̘ӊ9OTv6矿YjW'/=a;nz>6Afչ]=I-_{u}lРA_w}(tW~o"/z>z3v=†3n;fdNuu^rΆ<㌕O|ذa[z{yHYM_el/xlȏ ~[W\&yѧ?чD:A!*?hK-l隥XxӲON_C鵥'W\?L{O &<܃ H8}˛^NǍٴ.2膘fz*Sx 2RxCn{t׵[~>S}ɕ;f- >Rzָ .*ʌ[ykjԳN7I$yXՆkutZUmw-ȻcǎളN9!>x)?Ǟ S86䞒i}ھUDŽ^r.\TfЮS<%tV1:ۙ&LΧk{_/F~70}3|{qwvK1(c yCw++(H[z^KtOy]rqfoֿSwm!NH_ϪVe.8"\0!LlW:/J/|g8?O@)\T:$qy1 bm/M* ]]VڧIߺ07ؠNN]Mdнf%g.n=❺E3Yw;,?{/.O&Q} .[QթȻe&^oٱg-?~/镇H :oi?aV}/۴cϙ:ol Ǖی$,_ݴrlzώ],Eg}nZҪl:oUӛ/wZ2۪e;57 l[RmЦ5JGǍ˦R[^2gSV/(YɒE/-k4g}/|Kwݏ[NvkѶnuy/^foM?]QGEQ/+īSwd, ]խvCuUfnު5KiרWM͋M8+j8RtnÞ9,'t]ɬ/6g͚YpkϚT`gdv֥4(JdϬ:g$ԼyMw :/pD\ [NH\Qې),1=[X1{/XQڔ]MM,Z]kʋs2=rAWLi}5 W1쨮mkյLiō>S\эD*jew͂Ĺ[:|/k͒F}e/gLyt{~7?vvfd̛~R0]vvNzгݳSL{Xuk7jaiި!{w 76vSvي\jڃ oh[}7M5⃽CF5]=1;LIDATuwuSmO@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 bmF];>"0 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 bGN=#YN7s˻/}@xe&/@z>޶ogE? >*T*];C,BohyC-pͭ\k= Q޿7xr y"&DLؠ$ ܸ1}(L/}g߶~W&)޸҃{;ub8L?CՏOl;ӧ)6x[}t3Կ>èp#EEkֶ97!W~e5wXd[v-4~<?=wdbO ?Sxӂ[59q_~ო'XY{n ޲QWo;RM]~_/%%_@7|pU.pߧ֦\hwF[h GnxQ2d/tE=7-#~5j+F)?]zo N+f]ew,,M__ֆ[?x|iwW^|hMqXquf 斚=됿v[j-ow5r7j^}-!Y>ꦋ {ێ&M:&7ӳV4 uchZ$Q䃝os92Y! }k^4K7 {ѽ/df1a@]cyr(J |ac/ݖO+o-+~~! O͊[V, _SH&&G;j7vb}CwVvݻ|^ؐqמvک^VڙO|z}hMUnžZ|$t]?-VN.p-.=ίo1qvFNg=V⋛; =<㌕O|ذa[Wf #Ld5R]yUK=^x_7LҹXkԬ6X{caia/BL?=`֟'mIf9Y^ wYѱ+tJ.w{oZnԻY-3M?~uϦ3{{+o{$ Iv6n,}G_ʌ4k7>hР^9]o~t]?ZYaIӸm~I]Y^deu2sWwܮwo}}}_/Lkn暯_Ι|'~{Ȯ3w_̖=+:.m}M:Z{-¾+l=FyMW[ZٝޱZm{(ط:G˿|=ޛ++l^7x${izzO8r7|yh1!;v \g7;ݛz-[)r?+z\@/O|"3~ 0|j 髇 +Wuz+zP[eYYYz PLkp 78rmz ;{TvŴ&ĉ?Ӄ_gW|sMK-whWL3y]rqfP챖&]lYf<+{LH&Ӄ7T*̆8?O+;xwݑ}ٯ4 pH>'ͻ8HhWL7mrQѵ_RfwK]a{ӿwfs*, БD[w} v?=u9gؙOxĞ={^ذ~Rej3x$țk׮g|tEEk֮ Vc\xC߭8€$ 4-א_Ƃ pȑw~iـ- @QF޴A՗?^tgV"\Tt]75n@D\_,0 ;;I"/@D^y"&DL 1 b"/@D^y"&DL 1 bT*y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DLؠ,H&:# jzʒ6_뗓HUks&o~ym*ں0y+wԁ9&J3{JWQ[ֻdUzSUY!/(b&/@u솪D"!d' G* e pfF, GEe!4.CK*STd7]NY% TCeIV8Ztr-s%c]@&/@:\C­Ua@`_&a읚D"6Zv]ܬ,+*jܓWؔiIU]yP]1e~kks&o͂d"7gK֖9߿l{Wtw*?=Tbhe&/@T*'3y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^k387|D<3y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&D,Ȼ_v/nm۷oѣO3&/ﴢsι|&D*ja`{篾f+bs"IDATO㆏ 2-Nzwoڭw߳ tuzЇBwW-@z>zο`JO>cƏI愁n+^y;ٰ3SBwW-@⋼_p9E [0#C<|5kk27ϛ;-"/0(D6˯|隥q޴ӗ]v]YfooiӋ[bΕ)g29!Z7,a¤ +Lu1E'Wں.=v`РȦ!/}O}~t躘:鋛7gS.}bv1% .zeZ{$>g13㖏%QEЉ'vtns~M>ҹzS/ ]Ƣk 7|MGw[>HGcB<iut9kJv[tϽ`{GqtrQњkC><á#9cC;ו\lFg"o,95ro~D۪yS< >Acc|!,{uhla~[MK(\WӲoF^> |ťͥ8'VWĴ\CV/ߒq%#o5eaVo?կN]7v=ZX5mKLk8 N8嚗CW_^s#u{w++(H[Ӗ{nvu1-0qb~󐉼W.}Ep>nls.)tdqP{qw5ym:ܐkۡZ"O]HRص1tK'r g҃Y+Gf 1{&\agz^zN;n x1-pLH&Ӄ7k+OG/$t]Lw #3̆;guuwԬɌD".ț6/)3\\y'._lޜ~,9ggniM?aƖs/>7r~9yyg煁fmͦg7\ĚBwY8&ys˻}Z3>?l>/Ϥ!6S.V_50L>󝿻o~Y~Wf}0 Q8ڵrcdzօL.**+lg/6lXD^Bܑ#@z~M^ 1 b"/@D^y"&DL 1 b"/@D^y"&DLX"Jd&/@D^y"&DL 1 b"/@D^y"&DL 1 b"/@D^y"&DLٻ;_O"QEI{3XK$@DSjEN8C[i{%-V* D5-5z+0j S(" _滞gNÓcB^Ę Ƅ1&1!/@5;کiG"cÝ1um8҂ѽ[՞.#o¼kNK˞愊yӎJNJު1Ckdۆ5jꂢ2+y{O^H$6ٽ3FF-X?A^b(Ue{_y=-}Ĝ]Ξ,@L}ѪfUzބIUhtvBzFvu+Hp֗nV/ym{zWȫ>1 /-=w[. ̮nvBF8j_!WLKuE&<[P9CTr!% 1Si[]lChVy'xO;^޸!ړ7 ox*7~x봌1*r!o;7% [!'噇apmߟȌ4jal{Hq[ɛ=fTۣݵvJOJ$R6(67]ː^w~̩ପhtv^m{vJ~zv2.ؼi{v7z־ c[:{նKQ\TyгoJ jV{ʣ0@vWvzYJ٬I{u8iD_u3TBZ"S@l ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&U-ڜ61&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&؇>⒒u[n}WBcO|Sǎz9K02iDU-4n+Vu7Y?-<Ј9mQ'wرcwwϽƯYf7|M#H8Z @,SEoVwHl߾}W^LJ;S.]Bcyo}ns_UV4دoӺupT[-XYțF](:{#S}|閵%kË iii@+>p]; +MJQ׏X`#JVܹ잽_zd}VX@f1 ޽+|gK]vyv͛zSH(=IϽ= ox#-w]۴iSSN:QqOqiYY5K>,]sqNT׽5zSȻvmfe=8ܹ/?БEX*qp׽=o ^ZzOtoOH_7RYj y6lnN⒒pH_td(pos0Us2/?m;mzK]j&__oYO?>gEEEEű|C]vXQu oTwfH>~oky؎ KGG^=eᠽƳ>wck/?\ڷV'cv >G&53~7~3v,]:zo=׹6oFoY=W_{-Y#'W~G1@#wW~hf'O)C#f%/BCޤwygG%K8=Q_ֺuи y p ǿ'/!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&D"'+ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL csrEѽ[.= UzhLzZZ#31}s9C2(UgOhWwVy'ϫ q+yO}֍3'ﺶdƩx/.=dHXT2tޫP9WdR<&=#]ɻ~򐚄_ٞHMen8CFwC*J]TSZ8*7%n/{g/ Γ q+y7XHoU]jץc˄ Oݮj.cȄ9GN#[ UV~sFڻ5]nɘZ4o{:1M^\T-l1Ӌ֗NHK˛]Cj^`xдdl?MyN.ŭ{x*qůwtUjRv;$*}E袪cxR1;בּVmVtBFww>֟cL1g!omv~M&'MڎZ~ޘvՍZM~M2y{ōcj~ #ŽyQnc-ȺͳR;msGhQz3f頋one_' y{n=oBq靽j&1^Ks{O^W/i rVߟ:]_7\7y姟4gBh5b WV)قk &+̙wI⽹}0=wZ{Wdt/2^:}zzGw.cIњO9(B#4 q~ڢaĈM QɢpbUވ\ZZ۴wO;8l(ձbE]Bcg1AkM\lVkW!l(^{³ӌAqi׻-.+;#4.j@Rq쓢oOœ!S~mU8F٣O~[ .-}۝ՆSW}DMΟ0KhpnjO_\ռ+3&ڌcgx7]u9akgON*ñʛ:{p 71fU{w6=&㬱*K﷢w^(u} *---ovEw.1y/GRft9gzY0Ci1`Tun]n%y/ӇdgOSsz6whƈ{}O &R].XHK$7ȹg^~r6dwvy{N]dQ3"}Ԍ̛7|p^?;/:=Mn!oY' :LeӳUN2^{gԶ8wZ/ɗ}ů7{CeUowkx8=y}?Y#m^'*{xS\J٬I{uhI_g6m/@[{KիI{U ٞ(>nO wo[wݚ7Ñ>z^kn=&\GvC 6o}vQ7pR~ 4n\ @"[B^Ę ƚ1i*{2!oQ:P?-/(&m4\!It @ KK$x@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@4}m6 @ð Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&%E 6|qIIh4rsrPOB^;!n߹yr}gD"qwɧ߬,|h5}}dW_wMЮ)m0k1!/@ ybL cB^MQ,.)9سeѸ- G{U B~N/VI~t 9/7;uثWϜsϽ #¬#7nDk=s LlYjqnr"ҫ*HWfcfMYRZuOtcHNUz7|{;w @iv oY?H?,|h ^e+Cи-l>ږnf~[5T)Z0?s/Byg̨ڶ{;ߵdӺu+yHxGBޭ!C&K 0 \rUcH$Jp%/\ējGsZ#IDATkukJfe}ZY~4;.zroMO,X0= !/LVxU{!,]nݺd}x/m޼yRv ׬Y?+lٲe޴iS ey݇ X!h"ek e D_VVqCo⒒u[n}W@J;'!+_ƍ ޾I7_suRR,C;vL`&RAnNQ֭[ U/ݾ}a^&:l׮ _߳g]v-DWKxf,ʃ=\u\(RYھֶܹ잽_zdY)m0ԮaaѓQ۪UϚ%S;Qqg58k׮~Rnۧo'8Qѿ_@Bx#* y8W_{-Y<=zw߿:p?M]gqFT[Wț;*˅~sDŜm袳22BlWZ"-N!oѴ.YI7K쬴%.=,|ȯ~𬚗y /3\yC8 q yrsr'}_A;ipLܓ&3W8|JEV%q!n%˖E r>3lsݿ e>^*4W'_+񫗬=;̸-u}mzwW~,.) 4EW꫿ TT鷮ˁ"-F,}:-UuhU[ƽ?)/x:+-.sW/x"ujO([kԁ^e^y~#th}~N;3s/9mF5Dڴic;ͯn 5h2iߩn<fTͬm03 0n̼!l- 5bJi%fhikU3jYmmwD4ۆgpkܬ; - 盚8//_W+5bFqݵ5܁HŠd&)¸%t|fh5mk046hv/WVLٳK۔WY[kK7n< ov{kӦƎI>Mnۧc2O]>NC-s7O͓Mˆ{=cFUնݻw9%K.֭[ x%/VQ|ڕ5 {k$Җa׼k'\9++mx̎:<GN)=_⳿ݺ 2dMZt+W^54UxQpZ=aǬňsޚm{J%=;m^jvW?^mؓee6^3~u?׬M5μC#c5h8B^#yُ7޽{`֭K]vyv͛D Gk֬l2YoڴE2MAFCO,@4k2ZkCW2C6bٟtTTTT eyM6GE2MijQ."Q͓9 ey9sF/$)C {wʕc%ݺ]xHB^؛xӤ˖E=3NKK @؊+7lopÀD"qwh.[VZ|҅EEux駊B收h_c/.))/_eW^y%zbXroROtS5W %2ݱcǔ~{ k u/kݺuRUB۷vkvp={ڵkn@*YțH$zغwx`VzzzHIB;Oג?ߣGGkUbUhҲGgqFT[Wț;*˅~sDŜm袳22BlWZ"-N!oѴ.YI77)7'.RPЧo5kWҒ%{LN kfFf?x=Ȳ'w~_1 ysɌ6}QWL䧇bĽr͙VgJJ>;UDJkYsڎki% e̚Wݚ^1eYCO.x⊯|.X05|:`47yvw[gf:Ka˸<S J,d'.Aƍ:vիgι^Ha[ɛԦM_?Soi81&ZZf9(Ryޒa-yzBa炊"¡%_~y,r^}4Tː7]?òk;zoZMd[8okh1˙խƥ‘{%n;4-"oq>- xx~/~oΝH=lPM6_;&pB rf=yKŠwЂBfI-[21;‰e{shoY6< /P^3޽w-Ytߴn:$+yq({p)?ڍ8Ŏ){VδҚ ݺ 2dMZt+W^5D"$`q;om дԭMF8sV}Zm6x#kr T=r)ii4Φ'hkVR/5μC#收hB^R'{[.Yw57o!/4bYfVزedi- @4ݻ<(? )C D/*֮ @hh y++_ @7O:****2MĦMCHB^&HO@ B~*@U9 !/@SPYY9gܨ% eybo_rLUնdݽ[ / )C {otٲgiiiHB^[r}c nTH$8[eJK/]Vn0>TQhڜ6 #+y}%%l+4xР_|vROC+W:+[~IDAT@ ;}ɓnʿX;vsozMܜѣ.ue[@_Ȼ}.^zMtخ]g]vޭ[H%1 yW[0JOO)Yzn+=P }mٹs={K:3]f1 RSSaĩ]¢'UV?5K w aC⒒u[n?/rs߸Sǎz9K028k׮~cbW' D"r+V?z۬sNf8uɧ߬ Ge탇]z]7\}Ϟ=vڽ[!s/Byg̨ۯoӺuдx N wz٨+E  ??c>~eÆ}Єyĩ]1z=P 4;vLFk',#*+ywyv/Rg~׬Y @{[.Yw57o +yJй(mժg͒Ml2YoڴEhR'DÆyf@cc/.))/_eO?ayoةc^z{_MFC5'U]6*hV\+ϕc,+^y啃F"}嗓g&?5e;lo-CK2*hdv1i|v7 .۹sg8Z׆#*siP۷o<իDڵ{ѵkݺh6< /P^3jmwߴn:߻3ң)4!/'Rw٨+E ˖E6B5WB^h8ҮKx_B /1ձckX`#0;w3jQX4̚٧R:}}1f'}kL^ź;~W8`乕S pxB^d>}|tˌ/7N>(g_9X]~ǥ_?{/v7->/~7GxŸoW=/>4yߎ^W~6]4_}gmz{Z41[6쟏vFDn?yuFʂk;uݦ՞S{|zSyѹ.>>X:8B^4:u+~?Vܫ^Yeϭ׽.zh]s+{N{;wˆڳ7z왽gիu&V8"B^Eck݋fUͻtO{'/l{nFtO4⽙8ZH++}zFMc䥢 75yžpn |⽎l(&Twcm0ɓӾxC7ԛG.5-N _-]/}zj/[^Sw^ʿjr_Ec^6X:>.HK$xm9vQU4,Ug\t|>ݯâ}7|7>>D[f}Y~~ڜ6 J^l-yb~WqȮ;\lƿ !2ٵ [xWerv?}CɥKqr~-ϻukॗ_.zry/?055Ql!S]/(z'_os3_]V;vʰ!-`9.?㟢e˖|xzzzO|!Lz߸OzΝ:싁Xj?z@ñ@K]tm۶ݺ.xh˖-CS|s/Cɒ+V&vܙ /!//Or}7:wuNfB ppBjuqbCs?su/lk.ܹo߾wg'a#И%Nֶ4nRcw(6_juRNzGשvs[p߬ڵ+4 /{>t>Cxs6 @h *_}o3Żv#ߌ3 $I2=4gN8*;vض͊S3N?^K֭ѣǑ?gˣC>sUbU>ҲQ9%CϨhݺUoY4Kg;ӧ:yyw/酭gHr7u~ٚ?zkO[6!-:w8W\ i%gy<1=hD‰ɽu oNf-ow+:1MJ^-yoM ނMQ:)(N!off(/?ʐ9CٸIo̹0I:Wt8I/%Фc|.~sDŜTVissέ%C?O=+|XN?x.@c.袳22oq嘯%>e_rLUնdݽ[ / pۯ},oqSN׍dƽm۶@usywhZT,YrӤ7MZlYT3p eeu. u{|0w޹+_}7޹s-[c*e#U]̛޴NJO̯ΫJ&fhtZN`U}\'N;ԫ6OsBa笂\Sz[ÔAdeC:JnN⒒N5o޼cǎ/bOtE䨻IDATΚ/YÆu^~J}՜>miof.]l޼`^>#̱Νwթc^z{_6 @ÈYH6m~أwLc>D&czMx-Tnq[k|խskP=gZ!*^=fjf^(_ӊ%s-F̬}֞`nTfEOٓ۲vjxRVAe̫,:ib^^jߩQ6}Z??߃(-F?t6Fe_t~~G攗{ƌ>6]07['Ȇ{jwNkɒ'"+yq#:) kW>N\]̔LNʮߟO(9-îyNJsVVZ7"DWKxz5qݻuW›tgDsk GoӲ2z9 e"C>Ն2o-_$!FV\yدuϐc_pBrnwwju )=oAX>TaߧD{Fs{?jͦꃛVߺj-!3Uxēj@LT >t͵EuwLaf,1_E˿xW{_sm޻eK>zG%Q=FmcbY?-#c}??&MtG]ߚjo6^#v)p!Ν;^J֙ޤQp|7;~k2KKKԌ= /Os^vuVvu[leSN9%4<vݻ枿nݺdݵkg׬n޼y8]M GEOF oV~>k 9Sǎ*tߩz(R闋 ¿M=ʄ׿=Qc&C8ђ?+LzӦO-ZyWCK#5Qqg5ߝrihH&8='(5տMlr,q|ہ}AQ]A=]!/ڵk_~8iͼ W~x"4_חuڒwkOeٞjc8 hh-4JQѿ_p <׻gܓ{W~fnf=ש+'߶%&Oy՟opg\qje嫡hw44!>Yk{)dSO=7LoV}/?Թӷ3eΝ?S>|'O ;p |k@ЮFjQѢ)=o˖\{5r?yE›!i}48j**F"%:vQitml 7|a>}Y ]~ȜK/3ᨬ߰!*>ؗv ~*+g+Ŷmtԧ~p kṿFuO}*ԟ7@&%NG:{38=4i7tMp9!d{%JsB^7G\:p@v׮],4R͚5۽{wعsG>ÞO,|:uѽ[zB U7s'\7@ccǎh޼y84R?W_{-Y_G>yYjN?|7۵K/~aD 6=vFrr֭ 4Vh߾}8h8㌨(_'wiiix|ݮ]ճQ5@Sb%/Tff?Oɢ|ݗtOG:p@_o߫Q/)N i'|򩧜?O}[gU9pB%Nֶ'¢/^>:mXQC%i,*++ۯ{04'.*~(9mv 4R.謌do\9k޽+Wݺ]xH5oM%KntΝ;Pě&-],:gM4SB^ܜIAA5k +VL~ftxdgMO^;v\8hCٲe [fMiJՍ'?E 7$䥱{wW~,.) А1M6y%: 1@Ѯ.=c;'Gkn#Lx-/HB^bYf߸~>\iii99i]5W7B>]@SPYYyN~UUտأ셡1ѮN5ڽ{W%ݻu 27IK-{fhJ A c+Vo߰!:q J˖._taQQ`2}( '+y}%%l+4xР_|vROC+W:@ ;}ɓnʿX;vsozMܜѣ.ue[@_Ȼ}.^zMtخ]g]vޭ[H%1 yW[0JOO)Yzn+=P }mٹs={K:3]f1 RSSaĩ]¢'UV?5K w aC#-NI]L' ldy{fZ|oZ'lIw[WͿ%BVZVTfU&)m0ⴒ72֥7le~ݥ˗8V'f S~2N>fŹ 39Jwh*SEIB|tU%Dʜ^طUWLɞX8jbO\>o &"7'gq)sZ+w[N/~uA2oq/-p[FO)(ϲsu}~N;3s/MjӦͯ{􎩷4 #n9ԭeF/jw-_"lWxkv.-r]wU"x嗗Xq+njg͚Xo\w?wM?wւ;j5o|TUw m -}9uøPQ8rmG i 7|{;w @kpԎ`PaZ22.6bfgȞ ;g4IDATTѾmov`6^mx^x|3fTU׷iݺuh|l '+y2խakAC-|ك vmVXbG=+gZi΅Yn݆2o-_d+TYK 9ku+4.mѾQwbܺDkP; :Vrt&~kҽ?yQFJ^h8B^Rȑk8ݻw=ݺuɺk.ϮYݼyИyh{͚5–-[&M6?hQR)}AQ=HB^&~QQvmRF@пm[YjRTT4%gQQQQ!h"6m:t@4ϖGEzRU9 ey9sF/$)C {wʕc%ݺ]xHB^؛xӤ˖E=3NKK @؊+7lopÀD"qwh.[VZ|҅EEux駊B收h_c/.))/_eW^y%zbXroROtS5W %2ݱcǔ~{ k u/kݺuRUB۷vkvp={ڵkn@*YțH$zغwx`VzzzHIB8㌨(_.73wT y).9sۄ )tEgedخD"R[B͛iQ]dMn-N!oRnNz]TOk֔8&V~[%kdz %΅TV½O>iby-ISo9dF r>s٨+uwNu;8LZX5ډ긶v|խsIJ9"-V2 _!USfx  ikGVǼK1s-ECO.x⊯|.X05|ŻZ|oZ+̭ xGz~v<2S2չ"y=o .X^F4k޵KJ#7r^n7vرW9{F o%oR6m~أwLcxh1˙u9J9ջBˌ>{٧}??% CF^C};֯^eD~^]NdcH$^~+V?1c{eѸRY,C7v㻦;p`x3mJzQrÈoINdN{oU~=S^[f:vޮ* kTeA`yM<]F*ر'^{5 }J띷v }s_}!V57lӮڽ{׭[v͛7ISaX {͚5–-[&M6?hQR)}AQ=HB^&~QQvmRF@пm[YjRҲ4igQQQQ!h"6m:t@4ϖGEzRܜ߬ B>!h *++̝՟ !/@޽+Wږwv eyboM.[̸;---)C c+Vo߰!:q J'yk[QZlYiJ &ݧ* RSa~%=|ݖ[_y˟@qȻbW?qcHao?yM\ːwǎS{-8X T3z.uHU yo>xūW۵k{٣k׮ݻu $f!o"UcށY %5 Cm%]~'JxTvU-42;w8㌨(_.73wT y).9sۄ )tEgedخD"R[B͛iQ]dMnptJ&feeee, Ǥpxuuj=g/x[,>+էmt`#Ԭ]\SHa笂{:2Nyy;go[c[8K'9v;/7;uثWϜsϽ #b֮!ҦM_?SoiRTē *fֶJWYuIJm2%5SWLzd{+wھ8nMJ2M7 HDM(^u%W?{'E$_~y,r^}4Tː7]?H5%@ne6zN4.Zr2Z]CŠ'P6xGN]={dZqa0̻5Zۛ>Wb߸ .۹sgROjӦƎI>MȐaÏ HˌVgů93r\_B}^A)Z0?{^(/_wUUv},Y`oZnT㕼/ ];qO\9++m!f{N׎sˈPQP [Ci'8{ޭ!C&K 0 \rUcH$Jֶ'BJO^Cc{v-{z;gO=ByWZV6n{oK.-y?\-=?1On-fos~0kMoM3=ȴ9mFC^۽{׭[v͛7v ׬Y?+lٲe޴iS ey݇ X!h"ek e4 ׆ eyi58bgQQQQ ߠIDAT!h"6m:t@4ϖGEzRFh_]s2MAee圹s\!ݻw1UUےun. !/@Mieˢw eyblʕ^6D7Na@vvRIZ"8;om 4JK-+-]tY¢dSEQjsJ4د}۲u+RA~H=1yW\97n )'O)bرcwwϽ5 rsrF|嗵n:*~!x5avmo={tڵ{n ,M$_jl];p_<0+===f!V|ậ_B /FfΝgK/%xw͚,HMmNiv VZ|, /@BO, =̮ )]vmT/⒡188Qѿ_@Bx#* y8W_{-Y<=zpB\kVpHB|qQQn] ^!off(/TS]s>R @*S;袋5;]9kD"8͛7GӢdɒ&vJK>hldvAO8B{sLSțs^?)(ӷ5e-fhqKW%uέISo9dF r>s٨+uw O\>o &f⒒G -NOwg6`Gk2띷v }s_}!V5W8w{uu׮]]y1isJ4 bYfVزedi- @4ݻ<(? )C D/*֮ @ʰ@ѿm[YjRҲ4igQQQQ!h"6m:t@4ϖGEzRܜ߬ B>!h *++̝՟ !/@޽+Wږwv eyboM.[̸;---)C c+Vo߰!:q J'yk[QZlYiJ &ݧ* RSa~%=|ݖ[_y˟@qȻbW?qcHao?yM\ːwǎS{-8X T3z.uHU yo>xūW۵k{٣k׮ݻu $f!o"UcށY %5 Cm%]~'JxTvU-42;wy} ɻ&h@#p7;{XmNi,gffr!/@8%Q1g#u8.謌Pەcvn#N!oѴ.YI7"JnNzݏIIAyf}眓+x:3hEi9s[+9Щo֕{2o{|@h8qZzR6}QWLO[ߩ&MZUO{<*pbYkδqi[8Eu?3/?h1[yrW|O?p…GY绸$W8< ܚkG>~~[<0phɏɧ pXf#>/[ɛԦM_?Soihh;ǧ4a7?e^];YΗsZW[ @Ceu׮|s p5DqaW  lPM6_;&POC Osqjb됿j˸o5 Y<WDnNNтN. oYuYJ^hn_ ہv.ڴUWBCY[x|Z># VG;ے?io]!TLʚRsjui"^&s{25n߉C>B^Ę Ƅ1&%]k·o|Գ $w~G  'yk[)m01!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&D"'+ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^?{w]UuGQbQV%R%1A V:-ƪ(XөkFV3~hRřqƶjEKTIjUTA>$1@0'^.>{m?D „&0!/@ y"L a2^[Ң%u휾^]\h>>XO W6Yj-M_Z[_dR kΆF[}iUb_^|z0iIp sZNԴ⊗ ՛Z-x삒Lzӆ9)))9ű٣MͮySIyt2 !gjABMyyu+S筎94/E_O+cTdZ+tVfvNUDbm`s ƥ,+!/NkhӤ%1d+!ﶺVfti!y+XIDAT/Oڔ힜8'%%%xmhgtDgC޵ESo ﲂv]P]>oum@xȻnm3buIEHJ}}}Ke9-֥- lX[gfy~z`:Ѯ3sջՍ /v%0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „jMȲ „&0!/@ y"L aB^D „&0!/@ y"L aB^D „w==^{7gꠃsL/78;;N)-x˦н=r?rw+s޽{ns @du}{dq݌Žm?ß6}{1]raCCg=?D8Ӿri:B^yMKmx}gC𠴃:#23gjKݖfyxx;.8!tJ,!ϜQs2@E'o?})=+'Pz!XsZNu.mQ ۖ'_riff#@'Dʺyw«.G$;8m⢗|ß1?t."Y >y7_0Ynڀ U[⩧bE޳g|/Y>+Yv.gI_9+GsD71"eĈh +B|߾,>?@WRȻgŐSjn"m5xgngqK.yS$ߙ廸/ޱbiӦu6z]BNUWW/ft*jf}aW+6}u駝O6}qîdfW䏸rA㬆7'suM5Z{Q"~snW75ɱK!Y]<釞'L u+40%ua\0^-97x7 dk64$mvwjƝ7? %u&kibs.2eiU]#zC>Ɛu;6uihlێ:渷Xn:yDƣI眔Dkn^p9)R̯r'3nDS9(3bfʕe\aqTu_71Y8u{ٿĊߞC E^tQicYzC37Ok ŗF0N^+E]1cgǻn椙{_$뫮nRQ yw97?[UeՌI3aWG1s@Rsi};'[J/8y1t?۶n[=ۛ;LKwgjQɛT4?*Voxi÷G~+g%a_6a3Uj횊5[دM?uvyg(vz\~衇D5 ҁx::t駝bEG=^Jk/{˦нͽn3qܱdžns @dE8yK,~bE6>? :$t{B^h|zB^=x &B^D „&0!/@ y"L aB^D „&%0!/@ y",>MvD „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D i씄y)䗇=k[uߴnmI촦/=:KVh]CިZ^z6URvS~hզ6nzti1K&ȶ;m+9e]/](HO.n./IOm_\VYɟtMM]PRY܊f#bљL.YSڒĄD`܎#w^ɏN^WYRYvɵSw\wfH DKkX[2:qW/X񃆑MW/S40>hƪG2ed,o%\0iw=ZA283|O昕E Ok-CN/4xcmzSn|prJֶymuQn6){]ŵ 6j{nmSYRA훫n;w@++ Ox9{9_|'_]gnw ^M M.m5}r̀'-A~ӎxoM?/wqF|hSrKlcy~16/͎oZ0S꺝u</yimDekL?I{No`t9'V_=d2v '&ÞS6ض!ǷNV:5;髪~ȴ% ?m.^Mم%Wb38聺,-`e۟J+w+kŨJӶ?]P2=k5:zۏTWT44}j);~c2Um7q*'_wჍVBVi; {Dz}]vg&V[R˷희νgk}J^%gtÞ/- ]LhՕoa,w:.6iiCMN57e*벐7dΛmkn9lmݶy-`EaӂqU&/+LMIIɝW>ɭe%kݡ8?'нO7gXZ}܂_v₼N\-׷z ll{W=Y[pP[:>wqEϽ,?=9nicj-_Q~ʍۭ5{œڲliyGM{ϸ;M+Ϩjk*K7!minjc~;;z_V;:#k@c~M{&4?-o^֗~>7`@@IDATs^Z|vZԊwmҰ{ag^]雖,\ѳu3gC𠴃:#23=Eںu/mI~iWp@S g"b!o^0%Ürr!_'*g?.RRRB yy ?wӔ_.ҏL'}wRv @Bv~G'yc]NnX}Q:N^z(KL&S{^0[»W?umÆ˖ Z!om9_9#v5}̔#Ѱa߽K]F_ѮkvwFwGَGviɺVV6Qc}77 ݇vpN>b@Owر)uN=ftӏ~@Ow!Nve1;yLD8yK,~bE':'}s7/8B&3!/ #0!/@ y"L aB^D „&0!/@ y"L aB^D „R__&;y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D>-OOiYz~YT6?%%-='^E7(?J+3Kg{}iN>|ilU񼵡6U=zW{aZyǗ'lɚ!9P[:>} rj[ݗoA<pUfm[^\\(Θ,)oMiI+)q)I?TygEi^Zث춐RÇOcll'647;51M\pn).^*'k}>U[[:>-%%-neq}V6kdLdť-=~mҒ<7G9uT!oeBشbsYs67[x|f3ֺKʶ~65sr'K>.st.({k;izvqpg$=X\R*iE˗Lꗨ7=:%7~^`/򙅼%%G*lvAakOjwnZ^ieɘ7lZp^f ^#3e9-aҒҼPQ~ʍ-ϚjmaN¥y_`[ZW~hE\dmceQS]07kе K:<EZ @+YB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&IDAT0!/@ y"Ր-s @`'/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ze֧%B46<ҟ7<Li6?wㄑ!!oc>ڰ76P|$wܓc#O|eaٔ]awpZoIٴBr[G6̌Y B˃IV2@7fm:7m{/Z3{b23Ţ/=kPx'\r?o&];]zDŽ5_k󢉋')bb/?>W6tC⋗ x<~<{ )3FI.8!mqA A5.ժAg_f|rmƴ.m7lYV5LtEѐ7g%f\ vׅ-7%Bsa٬bp܉7LsѐC~ם_6yܠ=#mA+\wʡZ(4˂ͮ[9?Vݽ&>nТiFkvݍkw}jmW1㻀GHvm 6~cz΃ך[6!sg]لњV<+2;Yka&4F5 nja/pҠw7Kkh[*Ʋ ކeY#Mkp܍kq׭\0mQr,塵&!)-x˦.8̿kL'|gaٔUV^WNy;{v!!oͫ=qs޿= tyG1Sr|Jn{͙>^WpEnZebb+VحG|RhgW =·~jkkǝ9o>slPtٚ_HG}~x1[T[K/mAr0cБߜ8!tK5@7=~}^0Ï>ZRLyc;8M ǾZigчn)%%嘣{Kx|ypvv'B/7kSbi_?pҤq/u붭[ @;yMKmٶdk B]Ypl:tyGȶ^yֿzs6_>un*bB'OvkS;E  A,/>a י9v.nkcΛwGMzYR_)13Y眖`͂ݔ v{V3Ò~W@!dѧoE;0)}>$ @!Shڹr!a:t 7mdcwɒ}Y|V4gH"t9SӷO㏗?NyWUV&rv9yEc7.X&}GȾ Mwl<]7nLCOə!닙-+{sU5Ega`f,va w[ Mi8{i=-t䑏=YBe 圁٭YQ4d]3:sx.\viɃ]{v}־oU @Ei'o,L6߯]ZޖFue;v3r3îNvݸ[GkDU /чN9#bvhn y\`SvoOb+/2j̨I_ KC₉Jvg=^;ÒźuX~#tRժd>`@:QjPeߜKN:§ yédžqW_tQf脦N ]'J;y_ӟ_w}cźziyW\UssqO?5 ]k۷NJ./n蠃n.N@+zx?NJX{ksnxS;r;oSxAa2Y>CpuK=Y?L<_<v *Lοii@҃:̱c[c7?\8w1>|)C{`"տ_{U,xƯ.ꫣ]Cޙ3 ;}m}ݼysزeK;!v/%7.J^>{]߬=<==t?Gv%7uu|,MO"w/ir6wτV">YT,zkGefN<|+6,֖&SSSGn:~pvVJJJ)*W?G ᝼w)Ͽ[oݺ;),ܧOt{15>0!/@ y"L aB^D „&0!/@ y"L aB^D „&@4 aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D iDEazJkRs ˪yuͯ->Kk3Kg{}B'|q7wkyŦL;]UڻlbGj=L!onQm}}9Y9l}ieO];Wl};x׸% ˶%o]S\|0sɤ%>˛n;ߎK%:75;o{Όn/.oiٓ˕bPIDATNWnv[iċ_uq"m]Rs-X:M:ծ!&-gtrn]=~r⊍mVVz=yjqAD}iY;S޸{UEG<D_'CmU%v^SW]xOMMk6Z[Rx3 rCɉM^+ QdfICmuk r3OIMh؜Yy$єaѩ -.z*Q*,'Onꪗ?QIœ3ޤ!oG$y?yjc|0-/hmg xj''p)oMiI+)qM娯N[Q<;+J^=yCe(zI,rçGMrmqnIK{ùS&}θ|V ާ!o֜ >9a_=om/댫۰(y*dLdť-?iIlp=:̩u`/ѝiEosnxi.o9[m./G6Rek>,qPs%l Уt]Cz~YŜd;yȵ/MH{Ub%s,t_f?/dO;hW[-%%G*ladWvtZ^ieɘ7lZp^f ^#ܸq3yiue-ŲfZ[pP[wzJo耫mzڢ3>9{˚Cur'o\y%gn"^՝t%0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D Z y߲)@K>wPtvD „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D>gXvIi}^,DSm#HO yCDŽhʘjs7Ny|֬; {c)G}j=96>rG.^Mi8Kv9M+$oudؚ5M +$xW~/yͳW.2cࢉCTBy_1tk'wfLAfYpöٚk/znUÄAW Y.>q_|vZrn`w]hnpS/Ę;W^͚.7ϝh}1 >$w` 3Bd\u7ڬB,q캕CnhukV-lfݸyWF.jƛ|53? xdG`X:)㛵f_hBc4\s ' Zywn,k~и΃Mtk:WY͎_zn!in m C6κcϞUf8t }gG&,z/B!]hH %7.τ{mX65rxߴnݸ&w %b^Zl/R__l Q쒋tʇ.>yyvMY5kazuξsgg}~"ּ7ðKgwd3O=%˧6ɹל!yW5qѬ_&F=-6bœ^c3EsoOdBݷW ype=;A2kVg͚豉D;(~=:9^|C,z'vj}vժ|}vܙc^3v Kyd{ч>`ᇇeKպ/Ҷm$3͉B]t ycxÏ~nM׷߿>%[/73݄};v}ARRR9߿W^ =žuoS{:`f!z{~5hБ#N%;yaB^>zÏ{gkjkB:̌AF13:;Ei'oEy/~{ק]݇~$_?mN^>~'u3 ;zmz?\Ǘggw"_{ ׿=%& 'M [nۺukzAt+]Oߴd溎mۏn.N߻ tЕW1ΦË .:K'yܑGxtlۺ^ymkW^8waS覢.+;y;+zg6%PhHF{yc'616~yG}Դ.O^~3ui9 ,M bg=þ<,yNy5tO})ZXt`Þҷs@0;t;ߛ{!C~/Y/XpӦNv:hQy,)O>Yg[13eĄ7§pΔs+>%CU"紜]N^?bDۍI+Z⍻GȾ{p+?@!ƍSrrfnFb]ͼ3cmN COmƷ ]WmMO;'hTff#|g͚:(kx. niN Y7(tʑG@+vc溝x}{+^yQcF /' &N(Gp?xCK*ׅNzc!UED]C†Gsb;/9餜dz⪐1gyM!I'Nv?%_gƊu=SV\[A3ާ~qyg5wcE}}u^W6^!cNK_fL֗L|A\|V7?~ ׾w;r7?xy a ]燼?a⁰? _PDep?OKTig\ӟ7¹ G5CNr`C릿ثbiŋϼ4~uU_}Fj]ΜQm۷͛cŖ-[:6h ˯]<|b|?_:wI?qt+)-x˦ܳo~a`g.]lu_[UO8a :n?Ċb%IDAT=f9gs;Ezqņ)cǎyvSN8;}󂉱<]s oLS>"J=yO=u뛵ǃN<|ƷBn_~W^9S<JC'+%O{p̉o:|eÆRdrjj诜mYYYJII =E>o"N=%^|?ս[Wtv7%c=f@â5>݇}&0!/@ y"L aB^D „&0!/@ y"L aB^D „R__&;y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^ۧ]*K Fg$W>|γ rgaRmY~zJj,myu* vgzAE]kKG6~0iW;jBxWfkKgl\ > srmtf'O- =.B޵9<1Ve\|7m}%/[\u۹5w=dm񥵉7Jdِ'|ްr㲱xA~C̛[I3V͐dիŰ9/ULIOM egW0;5=gjYKsMN_6tʧY vj*V>ϚSVv_p\ 1ySż@ϲO"gS[܄6c1S6ݞ_Xz. yKl]=tzFqAy]nC]];z>#^VjG˓SsC{ԖOKII/sc"1/Sx%SR'BQnUҢ?NzӅ*¦%]zNQeEՌ @VNm)-ɟh*];JZPptNOV[[<Ees')ɛST>gX=v~qچ ֖ΎG!lj^b4w^EbvX}%j+K&gzu|wWNdҋż@R__mk=-p}kKƧ}2P[:>[q}%V[sނVVޤ%yY({>*K3-شϮ&fO-Ғ95wh&YޘwW9a{v^ZIi]zZ޼I@˝t_%0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D „jMZ{ „&0!/@ y"L aB^D „&0!/@ y"L aB^D „&0!/@ y"L aB^D =òKMe!jn|FzJum?&DSƴUq@f}1mxMy(>;WCxuɱs'>rlJه.N^Ұ;8ɷ$lZ!xxͭ#f֬iuvXu+qzHGG_{ʛ6׽{=1b5(AW<܍.9濷EҮ\|.cܚߵy|1‹+Vr!ˆuM6c]J6˂֬_s|s& hu玛Ӓs3.Bu}!ܹ򊌰l֌uDaEh!M_ί2a{ ECW8,9w%}&X|oòw̬5vs85V_T(9[`x||y萔OeSe\5W>tϳvhlȪY+{Ыs%Oν?/+"7af21l+h.è{'?WZ G5?-{葷y' YBǍ8kĝFM&AaE'gKzdy#O>)CTCG~賫V?\cHk(_l/$أ>?س>[]SS]]QGef 4bĈgg)J;yK.JM=#|/t믿>>#a?o5===,v@;y],Qѳm[~?<8;!ߛ^׿5)4y/]8iRؗݺu֭[}[}%6ul~tsq5,w6^Tpщ_:<ģSH ]dmk_[b¹ /:G7upO}w_! ^ѓ?)p䀢ECr 0 ;iu]񵍱[;裦M,t}BO˯ΘsNYfnJxw=azIDATvzMͫK^}ӷO¢x@KwYd}k9g:{z…6u1@zxȻdIyr>>+|ΙrN}buzxȻ2Y䜖+GH"wg}t%zxȻqd1o`f,yCOmƷ ]WmMO;'hTff#|g͚:(kx. neNfx.\viɃ]{v}־oU @Ei'o,L6߯]ڱ-w;w vNnomדnx&Zb`a>)GqD,؍!{vl.S{_xWF>#/r`ℒwݯY1z;dr]#RFL(~#tVժd>`@:QjPeߜKN:)'Y|Sk yO:u?YgzQ_Tdž{?v 3@;eű ˞h_j23fd:+1ܿ%N?wzd|ء@!>u{c8xx ~ϿT>Q<.vر?٭zۛ~.pԘQO>!=0tn߯*V̋MW\g!>۶}n޼9VlٲCmcfE~! _JJcy~d @R__l = O+. t}mUU#N<7\jux+;tQw/uJ\ Cm M% O a٠\R:fPmP#@'SHe$bSoMQl bO5iSD{7[4i <|>xsޟWQcg`B?͏?+_o. ߾QmPo<Ajohx炃$||`/~GyyM08'|Ѣ?ę>;wFW~+^'}9@eGZxvQ08M6ԯ?:uw2yR"L?&^#f#yjcSG/^W{m&A _ɟt9gs1˧g L+1yi&ag<>=-/S;ws}#jt.~ӹּy?/+++)Z}!=9?/~=kYhY|Gw챯zɯ~/}i hX'^0LƍĘ Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^XV* '#ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^;bYc_$w즥21dDWm';_\Yp`GS ƴ;v',//Cꆞz1oWgggn^"` ysJ;SIgSYNVVNYSH 믜n暱UܜY\\0RqoX7jEMQ;>mι$`$S4Zy:_#HK]T*57]~ok}i"S!oYzow PVpƎ:LYF2#yt%ںyv%WݹuOF 7+ 1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę F yހ;'bH^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^XC{އ7mO޽;8=W|駟^/-+LT*5=7}˯ɓOK^?ٳgˎ5!'njk_O֎tǫO? uw.Xpf0Q~xÛ6s/~ӹǵv,k}\N];[oyFO9W{^Wz'_† K/&$o$^S54}Xy bV7nť o/Wx҉&) w=|ß޿o}_q)uIuD+_Ʀ]> U\ 'ℰ^vy0DԞp0uXǢO|߿`R)mlzg g߸#ɿqD#Tq yעƛWPj뢬¬‹j~ӻQcݻw'N!okkk83w5Dv$yܓ6]ƾ6`_wfGnL8Q̳ 8݇w?᜞-8F޼`L5o>6>xUe&GOFܢ~>Lmْ~[?p ;?F_ >Y_PwLfˇ=ȼfg=Nۛ۳>oÞ5DAͧATxO<97 ^}s* îݟf^TϼW7wS9:^gLDrW2j|^Z'z4\{MGi-r ѡIDAT`/Zڻ|0ɥ}Zx9w=-=ח^M׾}UY,o%pQ1 ˾3c? YYYbQ0yT/qW]+V<8SeKe7-~œ7uIKn ^Cxz 'N#y7~v;?`|]ׯp-N5y#7|Giy;mo*8`,8gApX%J~[ݻ=777l^{MՄ׎W뾋w淢a>icK_󊃉:w覅f/s{sz'?/o􂷯?կ;'b+!ow]/wi'o3<#ky9xB^M@/!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&T*OFĘ Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ǝ⨩,+RЭ<(o ڢ)i R82 Aб%8j7?66o:])n5]42'3x%T}wr ]֦ڪD"nVN~qe]Pڛj 9ݽ%Uu UYYEl ݷڲtC6%Y(o~RVTod}ieW75TMiUsgw7M'W֤9MvAyCrSl219pXjKUյԖe~y]ې+tX1zq4}-?mՎNt.u\)LV*euSyֲ #[n{Kem5EWma`ʲ-l*_.:[OÐeycd;+ λmW0ՏT]|Q:-X5}a8Yј$N웆1z8'zg1ڞ7ח-w[wT65 yϾe]^}+9Hނ%g/Xέ; Ծ^^yUEݠmU%0pnݝڷg{ꥹ:{{{4p6(? /nj^(l/*-?7H&hsN~IރLMa[RLLbնtc̹'^~l:gyc[Cy~N&k3⮆AsWU9QKl}wsڪʺ.liYyH`DgL.z_CSpE1G`;D~^g[[9hkHW64%*Zgܻ“N$*kZ݃>'$TP+k)Y=wM筭_ !<ǎA={ShRE֕ _Y}:U׷ty>}8_ l΁CޮDd] jנEkDѱ 7]P4xΰDymHִ;x˪- #Dim[W0A͙7(-).(8[Zn^yR o-!ogSEQ/m1W9%ɝV,7gКnYW4(ͯlݳKԿ㾕j!4ZZU,3wY0oŽ=ٽrG*;^bQ}ldr ʫZ]Q[o]{FmU-DDACSumDuܽ/5` *M5Q%EvՕwO.5wYYYŽS]3evZ;Kv^[vOTWPRQH"X1DIy&[e"=h}SY 'gv0v \)(!o^":nWg[smeQe: ֒^Хu=_Wg{k]9Ey}ۚ77( TUU9`Bzn[UT\ӜL+\SVT]ve~w8/]︨=8(P~Gh)+ӎx_H(Q}wOqb@?!SsOYTjuMǹ~$Y]51rE7Wg>o*Zqݮ4YKT3F;oζʼ̮K.֗&Z^N83vr֚օ1+N}޽Lu#s#5EAKU: PVpƎ!l-:m_;GWSyވoΙ c=g5W 4ZMޜ͊6;wޒ/ToQ}-Et.Xέ{} ׶zU}}MO1o9Y~պܾ/=: x[ݧ&{E푝~{͟+xm$ 36uy㴞 ` f/6]-Ms{]%ʾKV17Cd}i +wEc­ pD2{^WrPsL/‰^j Vm?MrW4I`{}jo_Pӛ!b`|rW\@ -!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&C=7^^viH^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^XBޣ 88}3 ǽo}޽{w0y=W|駟^/-+OX}ÍA\{MG `̌e|}˯ɓOSk۱#||k_[߿ck={v gCO v@kΞ5wkm* ?|_׾Pwg ozxӦqo:w0L~{è1 nIm ¬۷o_ǿ==6w_y^u߼:IDAT\sO];v574?|ᒟ<9_pacW\`o}n1kkR߭7-X\PO:1a|?|\ }SO9嬳^|鮻vه?~A.hãNx a{HDԞppuXǢO|߿G46=3τٳoxG-yKԾ;kVaG\}jaa!냩0ѷ^=;:tQtś.t:_oz^uukݻNjt$eOm 'K'o6 ^9(#eKr`kmmg}Ɓ~Y]e^Ts-N鳏u:Fpd9m]v`0p\8? An0[R5<=9 o -8o\7͜/G3.^MAza /[G߱îdE6Up͋{*.=!}i0+)[lk2; j jwXjavҫopH\_4Q,-z]p yEs`<^7/?k~~LnfE79|cϧ$.+{fViF gΞktÍ#۲%5L5L?)pq0~=K(ls3ur}"^h~4L!*P{pv.8%FD={zvamGom;;j g_ѓaz[)Ӧܢw {\tW-^ΞLnew:/5G=øvwܒy^hm[mRqbQai0r C_BɦSl==2pM_~uf s掶a 4LM_ڔ|yVam?z0&>){-[%mcLQoxxS k\: Z]_5~k 3!o\kG7z8񬾀f_sCJ\1Sm?◿ Ol{ ^;mSVC{. >5>S}t<soֶɆ]om/<Ġaf}TkޫvO0r # 뻟v"S{l(h|߬_֬LI] ^hXyuOfW"j̬gYɆdmVQ-[7-Lv~2S5[t-TQC,o }C~]7siֆɖ~-y<`H\e݁cyOL`,\X0Ba{FNnx B[ s/_=tq[&5l&onI f亨m2h?[ p[;V=3q#v?Ýp:  ׾~ωC7|>jސ;5#y3_h\Ow1/yAor*lw-3@Hh4sq9vsz'?/oC􂷯?կ'n @IcLcj2>xʶ೷Լs)NxE#ҿ ^48LcB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cYT* 1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@[Ke"O~Mpʺח5<<~3ڢմԞtR&f:cC]K7 kڃmje:])lyjTjyt:=8J'SU>RcZWY]d7;_\Y6Pd}I`.?{ֶҬDeoQd]IDz=8HN%',']kU%}e5Mݘ2ƧڑyciN}ݏOW{SMYA"g]l*|_x.G+klj.:!y@#y;+ λmW%;vpSI}CkMQAp(t6/0Txhê6MmAIvl۸jUKlBm5EWm.f -]yuCL;d% \P<8Dy!r;x˪- #DimZk!~mQ~yo`oGǶ6ܴTvA sD0A`RB~e랭w^ wp|qE5SRٸnŒysٿeyM]03&ymav4JO}S55ٕl[o]{mUEv DFV:y%umܷ?x̌,#٥mm/լ} 88`AGMuð:+򲲊j.9:j-JT̖FЉꦶGd;;{Nk.>pq^qMs2 : IDAT_sxCm7^_R֗Dh*?]AyPZP\PSS( {@9.m͛vR>'RUבn/)d|U*{wu&ۚk*K rҁ" tu;j{og͵ʼn$Z'ХuI]e). ɹ}R(;[Jξisp IVt.{wSY(抂L;~/lШڢVtNK\>aMeY6:wŽmu9} jKV>wM=e:F8U$kj?m(uۛ+_7\2[uލ[kZޥ^pR֗&ƶ])0&^)nٷq=SzΝ;>x׶۞2tgscXw=! o(e#. mvn+V}$E-xy HxC:Τq}ÝIvI]{7AZR_^}=E,; \LŕC`$/٬Ę Ƅ1vD0t6''-b|a3Bޖ \~1>uఙi!oQ`|f/( :pdRx2@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&C=7e x1 Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1ro yۯTkOX}ÍA쫛\>2of \L:#yblCO vk`f$nCF&_GaVap^ 犏]q+gf_9x3%xQ Ƅ1&1!/@LߚUXxWZXvz`*rWώ~]{񦫋?H˞rօE7!Lrk8z &k*~}k)Ah7a}yQDE2w5-85m~~/ AmIszaNeS`>nܳ_iMeW<+M=*qOү{~x38чCߨNw~$zg֍z~Z{}@F aEf}-Ԉ&fHOm9ï:? An0[R[zX쩊D:upp50ޓ+P)#.oέH/OmWYEWo o];uoyy mْoҦ#-}g.57/ 5Ć O]Y3p޼Ktp|}>׭zdm 2t2I T4oT4 O;*;?G˗^):>.gk]M7lX ԩg_Yť'67$o?a ٨gDۈGX[UۿCxV w(8#jn a~q=^>ށ ӥb/Y<5h\XόMj{̪;3v30oKrأh[pž8LXdW|p[=zU\?m^Wṙ2ę0?A9Y WI^I G_wH^Wa(KxGB>.eMNͼ^hkzfqsK~mMXhxt'|my6F|u ~ ?w'/lԨWO57/̼<ѣ@8VðH:x;tVN!ӿ[$7Ɓj5\vE"xA iWwTmхE XT9Y{}}_ P?7FL<\40fj ,P5=$0̇կì⻢ ca~n_j02CV{S¬@=c{ôezrzb^bxfM|||ԗ5|Lz ׺eחzaP4 =dmd>np6CGO /0m)' RzMF.|зAxuN5Mt k 0o۩îijW?3nXb_8qŸO-+XS!7o_O·p A{LYS_6pahZ_{MG c0˚iTnbYgu{4w”^]OL[a՛)Ԑ}gkkljU0k?, >5dI*^vr( jl_?TŁzeJQ/1=7$= zATÑu Ť0dGpb~ <+`@Ic`n%`^<#y߆N<DW^{jϚ0~h0" IF G/SczPi[2zn{fh􀱙`7W"|A=LO^F{Y3݃(kmkQ>yGM}RsfL}rMQ՝)GYfFGf&z(G^25ګzSޫtS'v}_Y}t>o`0گz4v;=3ۣo趧1J]21J3)uF7`*ށ&J9f7DOϻ>o2hh\jpa|v?]qOZEGRU5:մm|A&_跰;SpwaM뿇ͳaޣھo}ucW\Qz݊i増8& 2NOlh.S*Hfʾ14T68xJs5ⲧc3`x1Q'tv= w%} 5nryL~Q1Jc3&IDAT0kTj{noˎc$/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@eRx2 Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@1dCY"kxd0ىږDyS0;[j6'F;'K=ϾiG}%U `LNv^cƕgϿpޠcC]]m%^mXyI⚖`m{ӎ*i CDi}2sݼ̒yvF 7j(Z99gɺwKݷg+ ; |#}uW- }h͝gҸB mu2%UՕQԼn)(|tz_Β,T)3!o^QώJZϝ]RLuqnk]]&|]`}TVek &&x/(Kd_yy{jQ~Hڛjc6y-Tshr 0&\C%Ʈ .<騬DAIeM}s[κZ;?P7HvcGm1ʲ0j.2B■ӯuu5T}K&&^nm06. jGpLn$ʛߺ4ގmܲTn25v''mO& Iܗi.//gRSNˊu oeW=\L7*hJ۽˗˝ݻUgk(K$H6ESͭ쭏[\Y97Ӹn+l)ThyapP!o4'++sЊDAIEu}s[+o݃{$G뎦dKsfmnAȣ}GVSegST7\]3kLeydh+fD^Iłǂ:᾽Awc]KigSy"++Q4 /nj]{$5ϫڝ-/ff'KʨAv_'d.ě|so0/9c ^sj03#?g;?ؙJ(˂{>|_^cgVomwW}j37z}ӣpMT"eaE<̙xo\ΆzcoxܾfGiҺE=[^|rS=vWvwea=j  ft>~ϟ>#guICwمUg]߲#3I/+͔PH׭>g {? f7}rz9>؏RhY#-앎KV*v7޻"7O`o8J=|7XSos!=D90=>ӛ>]r o텧󜳋xvQys^zK*?Pӽ'_Y~[H˘b\_7]_;֮}ǐ,DS/سg_k79<z}0q yߺ5q懾L&-=Xkh7F#<'H$rO> =܎'~ۻG z߾`ZR [{s;]x3}cO'3^%Od:&%kG(gRVVGyY„c f%^?g~>͞={k_. !fhSO= iH^>YϷ}׮]:ZXXXd[IDATyK_JvSO9K_`y晕෾!WD"YcG~kƻvt?<9??!C%Lŧ?//__xu۷/ i^`ZG5~lx׎_>]5Õ8}rտ}ާT^秼??>*;$]~ß>㧷}gۗ?ﯨOVsguS*Ft o)_>` yYXzK>tG_kkOO[Yqe0f'i5FqAcݽo\=#wz*T3?GwtsLpwq:o1T3.gk]M]w)|׮]Ӽ|Ja.rnϚ5}%|c^r{{H;ʽ5]FqgT`w^zKo r[w>gS` GN+/w*aKI0.'Wsrʫ^F0CVv{Oǽa?7/ 'dx;.So3|$+Q'gQ#L8_o1M^1MB׿kOgc웼-oyK^6onG?Hk8#, &OB 8.-_6RG/h&^ .=_%umٵQ{c_>]=7Ok;F~䢏`.'eKq%y7M;d'k>`R'ۢwwWԻs;[7FO?osr*NM߿__{>}yћ-Z-?]mCkwq>lxU6T} 柸:zG>u]xͫ?ӯNo^`ZJRîs{iϞy&l\R<`o\v??O_?}uxͫO/}ۂeǪ;EjU;wro~_rEsa0hw&z藿Tl~GƳ>e%% uw/~O8j{k)=y'?ݹ3j_? F7t ^,<Ƴiⵡ~?Աɓ`1L1;W::~W2k<4 bhϞ_O9c]>=^`ZqH0 ?{1hiyyާ?ݹ{iWӤsvvv {yYYYLѺ{ x$ ֿ^vE?~_vvv];( F˂o磏>c}+O~OK]@8=`0n Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę ƲRT@< cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę ƎiEKU"k$ى6jo,\VP(ogKmy_d'KI}we}u(_tpW:dF0@`wl{ O;mȺNvq/ܸ7P2wW[mIWnwCVwR3|k{+8F yTjygLڷ饛WU Lm[*VmY2lwżW>Бq{Oƫ>삊tΛ(ϥqyT,ѳDYuDvߺhA﫩KĕF'38&27;jW%h-= 7DvsN~i]k{UƜ%=KjZ4.>u[IEAmޜi,(\=a#_)0r hkk[{֨=wvi0]Q^Գmmņt B mu2%UՕQԼnJ ++ 9.`L0jݑi.+*qSiy]kӲK꒩T7m˄KV {ʪ]uu5De 2Ov4u_ M1jڃT*94|y:*ξ%.XʢK2].]xQYY9ʚ΁uv+)JpDQqngGk8fJx,+3)j<ڨWc㲬ivCNˊu o%W=\?_iKs{-.>oG%JjZz&Qcpa~rXd2d]}hQqYy& o>L̽% +vomu%rgx`C<y@mg2ʄ`" uєks++{WV4cv<ҕf,oLvc yۙL`m׎PI!;QPRQ]ܖJ۳qum2 yQ캣e5ҜE[?hQTGoY 6W״FJ*?TxGU9އVϯhTJ7 CsKZǺu^(.@{hmvgsˣrrGv/W׻wʵ`JѮt0nJ:ir2HDYC˺Q{mWwrmjꇦɨOϠ첪+3鮛˚l*+ΌnQyyf5{լݘ9nnkww0w6Q7n lmjkW6ݹEF>puݱnWg[SUqK*{U/n\W\QeOrW4Ԗࡕ5޻ښ*JsVԮx꺧\dgU^^)aJ]R8K޽{Άą:G@^`kꊋ.}hﰽ~h|g҂rZAw6dN2q-;.4ѻ}ˎ~{Jd޺myH޴ںzs߻{{KY>;wn>0 7?52$ 2{u}o}dO' C`q$!V[Rw8yeU5k 6ݸ `v6ucIDATwk( 5Ld2Lxg/X&vosłÜL) /H&lV@l ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^؈!p^v1!/@ ybL cB^Ę Ƅ1&1!/@ ybL cB^Ę Ƅ|u?5$F A9OGY1+ +uz:919'0=Ge:Jb%*T2e3)~l6`/ou_z]<||DL 1!/@ĄDL 1!/@ĄDO6]wn_/i#^?l+!o'iz q|֢7l.FBe{cӏO]IBx骑_ԕ <2{i[wu2sΐ<29Yo/fDHțGG_KOͦg /}}BO>}ل+7=KMN|obU7o;qΉ\zqT!9ہOLq@je4yμכӞRst{Lm'؜޶yYA5Fl!KKG7u;OZYpe~f5ᾩLx۟uD7VjFF~7~ākPX+ n6kn~&u',?kZW^˞YKKeo{ ]_:!]Nov4wBew=q43oƯUZw|&Dˮ1!=qZiW ;$dɬO7Jv ۀT>zZ_Z/8`j e>ܵe/. .;OvaʄNPHm-?e/lνNMœ4ON~zTseϤğo+x[Zro.J]H$x!}pÍGuOYzL}⻃Uřgm]@}Ȼ쥗L/>WoL=aF:1/UgS݋K[8_nzSZ%{ WRzB?L=`NpG>MxUŸyy)>;4!/;Lm{RVVO~rvq ?ᰭa׿+&_7oO%/^C}w\67s>{:hDCK y1l~|'|~ٲea2$w>5#,:"vVz[~}{̇>uY=C">m{l?Vi\taYW{;knMyA?ϰ$~ON81t]î\jʕ99١zWzͿwfoގdzE痆.:_0)|?O۹_LV\??ŷ^ukoOwqM=+;y7.j~ޚf]~k̋?=1'sģ/:Ɨ^YO9kf'l^|eNɴ ~fv%I-o~}e^ ն~iۮ巖xÖGvKλy?N 67nLW}=w[}??3ٷ޺bE7+iyͫΜ,7c걡5jT1:tqn&׿U6m<]T[i-GJaGֹv襉 ?;^9Ԩ_ -,񐷱18ṕ[88:oPn2-q6Cu=|؇,h+77w~ᇧN(oDF ̅k6>laƭmGGov]WbNdܙ) C׉m\1} =w*_8tɠ9s:1w ݲ^{%Ў y~iË69=s}谕3N0_l3{||LֳdђL#';;l>1U6YV;yAd$=蠃k/e ;$/,~ [gSviq'vm'l$N~dJ֨QC/ zSJd_?}R;OWdxțËя|$H&ߟ]K z7N*${|_tQجc]i?S';_z7qҰjf^6^c>|d{W\KnGq>6?.N>jyns+=Ȣ#C)ucۛol[]*nT>?Vy|g>u=+JV"h㝷V^JqJɗ?1hP{‹~PdI">OOG#C׽;O;tq_ .՝"{Lci-G}ԓO<^Hޤ$cXhGL5y?a5=l[a+.N>~9kf^{oK^sOv~#)}Ȱݷͭ]4w=xhGL!o,>5) 7ս l'zW^D~~<4'';Dhz{í{g *V7.yG|$xV]dus>2+\ҸҊų7dYxaKi1g^f)ɏz°-˴振jH$MLț4b?w{N/,^CoaEC{y* \WQ0{\|e\pLvj]/6Mìn̬盗$lZl`nY;y /y~d{3ax~֤~oP^]7EW?z>ffK)* ;R]/א_:ճ'Ofцڊt7cniKJOK٧M* [D]͒L_u; &OMm\=8Se{ Ru{RLTzZ7CTY:{jj##JrWB޵ ,K|[f{k:xB~IuSLHZ:#/lyW5eBn8oiUUVT64%+/yZ&]1{ryu)ZJwx8fsQQA̚YEYY9H\WQUXY~9f͛~ۛKgg(HUPѭZ]ݐ|5UZ{&On+mUr!4X5?ǒOM٠yrhɹ'WVwUSI.\lXU^zF'|$pC ˊSo*D[S\f) &|VX @gd%7-)8avcGּ^)sE۷ehCzEgdv{ݬCCܓXR?[3+򇜷G̬?)U_LKJs׺PS3 ̾ц'vfqE ~V>?oiGem: {_ٰ^sraEͼk-%Ӯ~`yC&e @v DK 1!/@Ą-MՓr_aE]Ҷ̺1t*@pi١k\bH$qr@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ yykE`[K 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@Ģy,xg^z˗-bРA{= _:!l%YD͎wZzǟx3'VС3qA.`[CM+4.^K~vue{s9g_r>M ۪L7+W<>S?{5tܰEտ_}ozC>;;nM ۪BjOx˂巖a+ixvAm屟[~N tC_|Kk[rN_ޤskx˻{_Rb{}W^y%6r؍اO?S:/$C.~v!t@7Ĵw^=ofO% oH[~R-]Z}-"λ4>{gWM 2رv:zZL!ommf9`cc_9Ԩ_ #%FeMydcZWe=-18ṕ;( AxdJVgS!o܍ ;[Z"v =.>v ?z1d͞d{νO6nP~^'F΂46uCޭnpa:o0dT+Mm6T:gN59%wݡSFw+ynMŗ.,PV"h㝷Vni6M]ؐzoK6ny8duN=d#;;^羷](cLB72'paʣòCFʚps}،,jvsrS;bDA͐١F76֐wA-"㾘i}ݯ76I:]IgM2E}Q󓍦כL^5->(;쭦-l1;Ì?ʹzK/OiLgW]Bޤǎ=;δ:'=Ԣ֗g /~[D\w>z1ouv? ۢ6²nv=wu_g^>Us7rV[{='sϯ7[w߽O֙UIN[?>H;d'~w9nB^VIB^Vml1B^ y"& bB^ y"& bB^ y"& bB^ y"& bYD"';y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& b}.0$SKsה?_NAqU-Xw~%ի6X1!l^gu{.;a΅umΞ:k `;ԉwDyy3f.̛:&g|UZWZnYc) m͘yykn^n[WQXTB/r-Ǥ+ncIJʪ֔l_Q,lz4䭫(*Hm/0`8(s;*ZJ6(l:y 'Me_΀TYTG\|Z\Y]r'$aVTV.I s=o깥dCkvw`qUS2mmnim*Uo㲒$tѪcHW`>cjzJJK3%ZJ5 316WzŮ|IDAT]rސ?2+kL];-,-nQQV\atYi@lkz&8/tF^z͹9˿)pR }'NG=7xrhŹ̛4G/l]v͑Eu^\!cp Elz\C~homB]EAVVVAv ,,Y~R5,6m.ҥvj䭯\|Z\Y]53gˮ99+>-J5ۯC/_Z=s?j/pXa?`Yv.+HllLMYΘ׿} /01l\ތumOy-˫K76-9af UsOcu;۸-VuL# @/+k9B^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& b톼U"lU萝DL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄD,wonx~楗_^|y`߿' :thCƍ+-(+H[+BOq俼bwao_r`sإ@ y}݋xϮlolEY3?0&lT|!ʕ+O>T=<`Ȑ!yزV۷}F<(&lT_|Kkɓg7OW^o'Ŵ́J=bDCOBw‰'eڕ?WOJ`b IUߓIx˙3%Gu'g\w]zRL9wݝiq@ou4-]|yz̎!!a﮻ )]taYӟy3'=hѱ{G/Vo؆Ĵ1}^O>c Ggڍl?jكώ{;i?idggw1hPφ:3Ϝzf`sSkI]tsțcLg @&ok;^ke^z3yfδ^NNΈO.AIMM+-s4~zcz@!#>i+?_5*M2O;{>-#~oQ۽ak9q—vXH$N;⼋׷o;'ldu:}'FZS#̫nwW,{=8(l'>q5'D"_>}ms+.>Cs=C|dw=al,^rQ2lDz[U"tˮ `}y饗=|؇ldBVeCˋ^x\_{&]3׻6oj틝*}FU6]k5ڱ᚟]k!]T8?^kE]׵N6t4hС7xX~c'wy'tљy3;32;5?w**ʞ?TώkcioMQ7mkZb'Zמm?c-?蚋?B6vޯ\{—: Ge /}Y_xͦuP5y7?|}uͥ.zLoޙpw:)P֚B-ԙIfgϞyƿ^/S%9]?L۶?I,ܰ|7_J/g$oVݒ%w}ŗL=)?x χ*1w-&g?#]x5: ί;gdc֜[;3G]z5yg']w6ػ^8Uy#{X> uR?qu5#'Ro3&zgt'.|!2'eI䓭r.nF1[Ttu>?xo9[B_] .߲Gr潽E;lo_W\xuOZuz[g~4lMml9,I% <33e |kw'"/n(;s7Iw_ڡpqn : !?9l̦c?=XZ̡{v.NqNYj*3m-;\B:N]?{ڔ .ͮ=ܟyW_^|#oy _opAcO:iN+1="?;o=\KGɛnʃɺLwzA_+Wc|ˁ{x!Cۯ:K[بk'cxײ/dj9?3Z]tYݱ|@Z7>{g$sCnj9k_֪+fLyCzK785+wXIUh.ю_Z@zcogޥE_a.M*9g,4T뭕42epf?o{0k~ݓH$z魿Zg}Ǿ+>^xz7oLۓ'ǝLQaKgu#MN8L?_ ]8}>s`+lQ|:/غr lG})'i_su̫'3gvc5[(i,ZT|@w]wg~~'?9$!/g> lIO-Zjkk3C9$!/_>}δ_ zCDeǰM)>Zb+9rl R'׵i<}_yy/0ӹH}ĠAƳ>/~:]<ֵC^Hc=2y&л-~9N ֵ턼o5ZK.[o뮻vދ.,sKj yGtP 6^GQiުjL/~1!/=s2^>}}>S6iE~ܿb#䥧8Kc;,H$g} yLgW]t?hhh{đ?_W?ȃG_su畞;[ZIDAT0D"f;o~w]'?f3CS8z= lY_e]B$(qz?on&tl9yM6oz;d'~w9nvl轄c ZB^ y"& bB^ y"& bB^ y"& bB^ y"& bYD"';y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"&XԔd_Q%9Z10')tӺ󟭺ytIu؀(vu.hl\|g_U0n'oaEC"X:#/l%uewۗL.%K<K|m멯^z+:>_o`n*VP\HTvtf'IE/*U۰jA5ek-US9(_ fյWζvVzWί[6eŭuK).͝x ީDGM5ec.{;s(yL\L&Ϋ*'yͲoʛ47tSChkQR;$gsK N-+nW9oI-y=^8/QU|Mޯ㝼5i#f<\v3#*ꚇ7$&w-7o&`ܺySy'W99-o:66ޞ}~S7 䭩R}~ [Wop_Էo[S}tyEW5Om Uw~,Us7X=b6Uv_&@~[_S:z=78,keͥtt_OϞWRaoaSV?~?{IV'J9'5oq F^`;~ț[Xؼ[V&:PU.''7\_VU5K¦/T֭5a{ҳ)tpҤ'U7ͫIǧW_3j*6InIJ*6~R.%aң)tTjb:\1{\چk+JreeeVևnWR>cxqɹE^T7wR 7moRY7,ܺjgMvԋ3*'LH$:o\0epM,gekwM[TWV0ٍ\OO^SVs'緔 r}kVu59chxL6T?cCU'ol'1,.IF;^X\Y/8fx5Wdg1]= ǎcB^=6Ȼn3ljog\Oe^WнrsCljzg_\d7%_ӧ\Xaqogy&o2i&c o-}C!uS$9s?}8}{ȃ@[UWg%\Q'0y=>l^<#t(L{a8?lsKf]iuӯ@b yU+$}6{Z>mCv׎ʹоr;;qk^[)5*k#a+zFʿvFf._<#68` KǸDŽCGRʉо;ʹZ(#18ṕ ;ʣC<OmwĥMP|¥yɩR6>} ?lxZhǎn>v ?z 7O2}Y5sZ#GJF3;_;}ԕdz{iqs甬sm`^p\+'wfVyF{Ǔ-M>B\:<k;9LDwr{1=X76Zގ d/7|NޕNۮ[ÆYX>mܒG&?}!v083++f|맇QK)]taY{6 {GB ?apX6 L5 E֚*cK-4rr@;zp'f7bDSȄ;쑒Qi7꼖K͵^9yhӇ~oN/I_\rΨpª0%Sa܄ΙȝuqY[&:ʪCvSlܨ{׼[;)u 5OwӏzDK s?_n̴GS{q_MN6]svosءU k[R ;Kךlݗiŗ.L\T)Ȕ.!8S:jX~mMS&NI$a[O~i{}1;Ì?ʹzK/ۜ%K.xa&>SțtرgۙvՕU'}> VW~mV}E~qݵC1(v}%K_/~ ~yfCCv믽F5^`6;²nv=wu_g^&#l+>Ȣ]qjwZz~~F؆?fIDATSz]@qț;T;5#}/ԯx@wV!#h% bB^ y"& bB^ y"& bB^ y"& bB^ y"H$q bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"'259YkWԇa~EIANu )(.i 09YaE]zZnu!o/PWQ^ܸҊ\qVQYMs+K>=VY]޴z][XѐH$ [I]Yy&޾|er)XhGd]2 lUMkKMWW/K=M/70`RINU6ק헓_T:aݝ5ek-US9(_ fյWζvVzWίlLӗM.lndz7w6BC[~!YʙTg )(`49=Ӻ +7e-@op!λ%+/n\s$Os֍.kiq-`tɹqM~֑.\6]CZ^7{.;a9:$~׆-fÕg7.Yk֯k߹*ЮjjZ'k78)sY|04]#-Ȣ!7qͽ/h'ǯ=nR:c#IF>u;:lM%'јl >m梖/;No#t)Bíf,MaVaVў'~ͅK^KkV%1o׹ə%/ |"Jӻ(++"5cn_Z\6t~͌MƭdIeDkԖ\ڿ;`⼺+jo|S4nvjiϚTвs2'Kڛ0+C:ɧ?n `QͅϪmrW.)YUk~e҇ǥfuTT U2pݾY˫7ubbK}ֱ5GWo0yUPUyG*8oJ]1UmYyr׋WVnzݾNNqɨj/ض4}=60Lԅ=8g}æl?{^v~fa5Gn{ZկwYuOl޲O;xm+ =lȻIj[i sv'~~ț[Xؼ+[V&:PU.''7\_VIU5K¦/T֭fY;?SvxaZPtD1;Js׻(Sي9 &upҤ1_ɓ6{VoSϫZuS $ttye%uN?)SkҒܰ19œ2)oKoW]E[NhW$Y uT5+_Y\`US}mueYIQn Jg O599b~ܫNvMʙ<+3O[הUCIilЙSX>PnIeN}E9o248gRef婥V7/=9n~UEiqIkJM4Uf>SYkWմNRX2kzD"QSq,`Āsm( 5e9c.k\#oڢ%'nzz1=6&G CWu0}1Wϟ;94op[MzRysmHUuŅg=|IΗdɞxKmUINj;xm`qeo\wsg+,,Ytތk&ܙ6Yzf{DޚsEh^+݂Ϫ_zZ J~oEWIUO߰O;"/o}?킫%OB^մ&݁9ϵkjZսvЋ bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"& bB^ y"n[+l&`'/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@Ą>^駟y嗗/_ĠAC-}ȸqJ$mv֊л=g9//c;wK.A߾}C/K?ѴL ˺I?gWW;Cr ^ 8|>K!C]wifSW{;cʕ|'|*~Լo5/.[lp~y ݒ /MS.,0︷3C"ɛz o؂[ws=I|TΙ~+W'3{# vOʯoe^uu]rN_%0y=>l^<#ۓB{Ϗ2a#?@%.ɴ⋿nΫW^I6;m>}"ۆswر_;6Ӿ݈)'3ٽGJFʚH؊^9?Qo~ǩƢE˗/!68`LDzǔGdM kR^Y:ƃN[xĎF hߝfO-ZCL!occcq;LTϙ}  0{_l]CS]zhAs;:/M*8>} ?lxZ;n{ر/X:;譯Y&۩|#%Ιj,7*9R{L_|=+91G[xiqXӕg眒<ӔTv|󗜗Mf-)[HZFHѺxӧ/Y]sЁa#=~&[.V| eN::,~\$„55lSSvT›{ʜ4ow]kå+Vmޖ{9j7mzߞdSw[BeӇ4t#=lP^U5H'[7ol!o(²Յ"-r3ԝ2h+Kչs#AȚ߶ 5Lm<:,3)w;)7}۔6x܂~O/fWVh;l1²̽F@oN=#x)kWi_B^~[roЅM2h˛՛K ݖ[4!o⛛?Izcoǖ,Zid`Ѓmv#FZmٸQ!uڔuIN:ny,-'iHIz% 7 Sg96w\VϟϞ~\ֳky[?WL{ȑ>d%6;ykE]wi]W]}KzjC/:m΄d\zڕ\28}~4i!] 3tS:jX~HmMS&Ni/=憞O~i{n34~ꡧ./}s ˡ&.l~l»j+F}mS5 $2ʧ]G}E~}-8`aÇ:v-ߎ, uر&j/ew|;oU??x#lK~} .D&;UoM>#a;~t◿Sr^O =$XywDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@IJD NvDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL 1!/@ĄDL .IDAT4IENDB`././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/spy_parser.py0000644000000000000000000001017515134002420015033 0ustar00# # spy_parser.py # # SPy (Simplified Python) - SPY is a strongly typed, easy to use language inspired by # features from Python and functional languages like OCaml and SML. # # Language definition submitted by Sanil Shah as part of the coursework for # COMS W4115 - Programming Languages and Translators, at Columbia University, # New York, NY. Lecturer: Prof. Stephen A. Edwards. # # See SPy language definition: https://www.cs.columbia.edu/~sedwards/classes/2016/4115-summer-cvn/lrms/SPY.pdf # import sys import pyparsing as pp sys.setrecursionlimit(3000) # pp.ParserElement.enable_packrat() pp.ParserElement.enable_left_recursion() pp.ParserElement.set_default_whitespace_chars(" \t") NL = pp.LineEnd() TERM = NL | pp.StringEnd() ( DEF, LAMBDA, END, PRINT, IF, ELIF, ELSE, HD, TL, KEYS, AND, OR, NOT, TRUE, FALSE, KEYS, ) = pp.Keyword.using_each( "def,lambda,end,print,if,elif,else,hd,tl,keys,and,or,not,true,false,keys".split(",") ) # general punctuation - can be suppressed, used just as delimiters LPAR, RPAR, LBRACE, RBRACE, LSQUARE, RSQUARE, COMMA, DOT, COLON = ( pp.Suppress.using_each("(){}[],.:") ) # operators - can not be suppressed, needed to distinguish among operations at same precedence level ADD, SUB, DIV, MUL, MOD, CONCAT = pp.Literal.using_each("+-/*%^") LT, GT, LE, GE, EQ, NE = pp.Literal.using_each("< > <= >= == !=".split()) MINUS = SUB LIST_CONS, LIST_APP = pp.Literal.using_each(":: @".split()) DICT_SET = pp.Literal("<-") integer = pp.Regex(r"0|[1-9][0-9]*").set_name("integer") float_ = pp.Regex(r"(0|[1-9]\d*)\.\d*").set_name("float") string = pp.Regex(r'"([^\\"]|\\[\\nrt])*"').set_name("string") identifier = pp.Regex(r"[a-z][a-zA-Z0-9_]*").set_name("identifier") bool_literal = TRUE | FALSE list_literal = pp.Forward() dict_literal = pp.Forward() string_expr = pp.infix_notation( string, [ (CONCAT, 2, pp.OpAssoc.LEFT), ], ).set_name("string_expr") arith_expr = pp.infix_notation( (float_ | integer).set_name("arith_operand"), [ (MINUS().set_name("unary_minus"), 1, pp.OpAssoc.RIGHT), ((MUL | DIV | MOD).set_name("mul_op"), 2, pp.OpAssoc.LEFT), ((ADD | SUB).set_name("add_op"), 2, pp.OpAssoc.LEFT), ], ).set_name("arith_expr") expr = pp.Forward().set_name("expr") conditional_expr = pp.infix_notation( expr, [((LE | GE | LT | GT | EQ | NE).set_name("comparison_op"), 2, pp.OpAssoc.LEFT)], ).set_name("conditional_expr") bool_expr = pp.infix_notation( (bool_literal | conditional_expr).set_name("bool_operand"), [ (NOT, 1, pp.OpAssoc.RIGHT), (AND, 2, pp.OpAssoc.LEFT), (OR, 2, pp.OpAssoc.LEFT), ], ).set_name("bool_expr") expr <<= string_expr | bool_expr | arith_expr list_literal <<= LSQUARE + pp.DelimitedList(expr)[0, 1] + RSQUARE dict_literal <<= LBRACE + pp.DelimitedList(expr)[0, 1] + RBRACE statement = pp.Forward().set_name("statement") block = (statement + NL)[1, ...].set_name("block") arg_list = pp.DelimitedList(identifier)[0, 1] lambda_def = LAMBDA + LPAR + arg_list("args") + RPAR + COLON + expr function_def = pp.Group( DEF + identifier("name") + LPAR + arg_list("args") + RPAR + COLON + NL + block("body") + END ) lhs = identifier assignment_stmt = lhs("lhs") + "=" + expr("rhs") if_stmt = pp.Group( IF + conditional_expr("condition") + COLON + NL + block("if_block") + NL + pp.Group(ELIF + conditional_expr("condition") + COLON + NL + block + NL)[0, ...]( "elif_blocks" ) + ELSE + COLON + NL + block("else_block") ) dict_set_stmt = pp.Group( identifier("dest") + LSQUARE + expr("key") + RSQUARE + DICT_SET + expr("rhs") ) statement <<= pp.Group( (if_stmt | function_def | assignment_stmt | dict_set_stmt) + TERM ) spy_program = statement[1, ...].set_name("program") pp.autoname_elements() if __name__ == "__main__": import contextlib with contextlib.suppress(Exception): spy_program.create_diagram("spy_grammar.html") statement.run_tests( """\ a = 100 b = 0.100 c = true and false d["blah"] <- 1000 """ ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/sql2dot.py0000644000000000000000000000614115134002420014232 0ustar00#!/usr/bin/python # sql2dot.py # # Creates table graphics by parsing SQL table DML commands and # generating DOT language output. # # Adapted from a post at https://energyblog.blogspot.com/2006/04/blog-post_20.html. # sampleSQL = """ create table students ( student_id integer primary key, firstname varchar(20), lastname varchar(40), address1 varchar(80), address2 varchar(80), city varchar(30), state varchar(2), zipcode varchar(10), dob date ); create table classes ( class_id integer primary key, id varchar(8), maxsize integer, instructor varchar(40) ); create table student_registrations ( reg_id integer primary key, student_id integer, class_id integer ); alter table only student_registrations add constraint students_link foreign key (student_id) references students(student_id); alter table only student_registrations add constraint classes_link foreign key (class_id) references classes(class_id); """.upper() from pyparsing import ( Literal, Word, DelimitedList, alphas, alphanums, OneOrMore, ZeroOrMore, CharsNotIn, replace_with, ) skobki = "(" + ZeroOrMore(CharsNotIn(")")) + ")" field_def = OneOrMore(Word(alphas, alphanums + "_\"':-") | skobki) def field_act(s, loc, tok): return ("<" + tok[0] + "> " + " ".join(tok)).replace('"', '\\"') field_def.set_parse_action(field_act) field_list_def = DelimitedList(field_def) def field_list_act(toks): return " | ".join(toks) field_list_def.set_parse_action(field_list_act) create_table_def = ( Literal("CREATE") + "TABLE" + Word(alphas, alphanums + "_").set_results_name("tablename") + "(" + field_list_def.set_results_name("columns") + ")" + ";" ) def create_table_act(toks): return ( """"%(tablename)s" [\n\t label="<%(tablename)s> %(tablename)s | %(columns)s"\n\t shape="record"\n];""" % toks ) create_table_def.set_parse_action(create_table_act) add_fkey_def = ( Literal("ALTER") + "TABLE" + "ONLY" + Word(alphanums + "_").set_results_name("fromtable") + "ADD" + "CONSTRAINT" + Word(alphanums + "_") + "FOREIGN" + "KEY" + "(" + Word(alphanums + "_").set_results_name("fromcolumn") + ")" + "REFERENCES" + Word(alphanums + "_").set_results_name("totable") + "(" + Word(alphanums + "_").set_results_name("tocolumn") + ")" + ";" ) def add_fkey_act(toks): return """ "%(fromtable)s":%(fromcolumn)s -> "%(totable)s":%(tocolumn)s """ % toks add_fkey_def.set_parse_action(add_fkey_act) other_statement_def = OneOrMore(CharsNotIn(";")) + ";" other_statement_def.set_parse_action(replace_with("")) comment_def = "--" + ZeroOrMore(CharsNotIn("\n")) comment_def.set_parse_action(replace_with("")) statement_def = comment_def | create_table_def | add_fkey_def | other_statement_def defs = OneOrMore(statement_def) print("""digraph g { graph [ rankdir = "LR" ]; """) for i in defs.parse_string(sampleSQL): if i != "": print(i) print("}") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/stackish.py0000644000000000000000000000532615134002420014457 0ustar00# stackish.py # # Stackish is a data representation syntax, similar to JSON or YAML. For more info on # stackish, see http://www.savingtheinternetwithhate.com/stackish.html # # Copyright 2008, Paul McGuire # """ NUMBER A simple integer type that's just any series of digits. FLOAT A simple floating point type. STRING A string is double quotes with anything inside that's not a " or newline character. You can include \n and \" to include these characters. MARK Marks a point in the stack that demarcates the boundary for a nested group. WORD Marks the root node of a group, with the other end being the nearest MARK. GROUP Acts as the root node of an anonymous group. ATTRIBUTE Assigns an attribute name to the previously processed node. This means that just about anything can be an attribute, unlike in XML. BLOB A BLOB is unique to Stackish and allows you to record any content (even binary content) inside the structure. This is done by pre- sizing the data with the NUMBER similar to Dan Bernstein's netstrings setup. SPACE White space is basically ignored. This is interesting because since Stackish is serialized consistently this means you can use \n as the separation character and perform reasonable diffs on two structures. """ import pyparsing as pp ppc = pp.common MARK, UNMARK, AT, COLON, QUOTE = pp.Suppress.using_each("[]@:'") NUMBER = ppc.integer() FLOAT = ppc.real() STRING = pp.QuotedString('"', multiline=True) | pp.QuotedString("'", multiline=True) WORD = pp.DelimitedList(pp.Word(pp.alphas, pp.alphanums + "_"), delim=":", combine=True) ATTRIBUTE = pp.Combine(AT + WORD) str_body = pp.Forward() def set_body_length(tokens): str_body << pp.Word(pp.srange(r"[\0x00-\0xffff]"), exact=int(tokens[0])) return "" BLOB = pp.Combine( QUOTE + pp.Word(pp.nums).set_parse_action(set_body_length) + COLON + str_body + QUOTE ) def assign_using(s): def assign_pa(tokens): if s in tokens: tokens[tokens[s]] = tokens[0] del tokens[s] return assign_pa item = pp.Forward() GROUP = ( MARK + pp.Group( (item + ATTRIBUTE[0, 1]("attr")).set_parse_action(assign_using("attr"))[...] ) + (WORD("name") | UNMARK) ).set_parse_action(assign_using("name")) item <<= FLOAT | NUMBER | STRING | BLOB | GROUP if __name__ == '__main__': success, _ = item.run_tests( """\ [ '10:1234567890' @name 25 @age +0.45 @percentage person:zed [ [ "hello" 1 child root [ "child" [ 200 '4:like' "I" "hello" things root [ [ "data" [ 2 1 ] @numbers child root [ [ 1 2 3 ] @test 4 5 6 root """ ) assert success ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7145858 pyparsing-3.3.2/examples/statemachine/documentSignoffDemo.py0000644000000000000000000000217115134002420021245 0ustar00# # documentSignoffDemo.py # # Example of a state machine modeling the state of a document in a document # control system, using named state transitions # import statemachine import documentsignoffstate print( "\n".join( t.__name__ for t in documentsignoffstate.DocumentRevisionState.transitions() ) ) class Document(documentsignoffstate.DocumentRevisionStateMixin): def __init__(self): self.initialize_state(documentsignoffstate.New) def run_demo(): import random doc = Document() print(doc) # begin editing document doc.create() print(doc) print(doc.state.description) while not isinstance(doc._state, documentsignoffstate.Approved): print("...submit") doc.submit() print(doc) print(doc.state.description) if random.randint(1, 10) > 3: print("...reject") doc.reject() else: print("...approve") doc.approve() print(doc) print(doc.state.description) doc.activate() print(doc) print(doc.state.description) if __name__ == "__main__": run_demo() ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/statemachine/documentsignoffstate.pystate0000644000000000000000000000547715134002420022616 0ustar00# # documentsignoffstate.pystate # # state machine model of the states and associated behaviors and properties for each # different state of a document in a document control system # # example using named state transitions # This implements a state model for submitting, # approving, activating, and purging document # revisions in a document management system. # # The state model looks like: # # New # | # | (create) # | # v # Editing ----------------------------------------------+ # | ^ | # | | | # | +----------+ | # | | | # | (submit) | | (cancel) # | | (reject) | # v | | # PendingApproval-+ | # | | # | (approve) | # | | # v | # Approved <--------------------------+ (deactivate) | # | | | | # | +--------------+ | | # | | (activate) | | # | v | | # | (retire) Active ----------+ | # | | # v | # Retired | # | | # | (purge) | # | | # v | # Deleted <---------------------------------------------+ # # # There is no behavior attached to these states, this is # just an example of a state machine with named transitions. # statemachine DocumentRevisionState: New -( create )-> Editing Editing -( cancel )-> Deleted Editing -( submit )-> PendingApproval PendingApproval -( reject )-> Editing PendingApproval -( approve )-> Approved Approved -( activate )-> Active Active -( deactivate )-> Approved Approved -( retire )-> Retired Retired -( purge )-> Deleted New.description = 'creating...' Editing.description = 'editing...' PendingApproval.description = 'reviewing...' Approved.description = 'approved/inactive...' Active.description = 'approved/active...' Deleted.description = 'deleted...' Retired.description = 'retired...'././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/statemachine/libraryBookDemo.py0000644000000000000000000000333715134002420020377 0ustar00# # libraryBookDemo.py # # Simple statemachine demo, based on the state transitions given in librarybookstate.pystate # import statemachine import librarybookstate class Book(librarybookstate.BookStateMixin): def __init__(self): self.initialize_state(librarybookstate.New) class RestrictedBook(Book): def __init__(self): super().__init__() self._authorized_users = [] def authorize(self, name): self._authorized_users.append(name) # specialized checkout to check permission of user first def checkout(self, user=None): if user in self._authorized_users: super().checkout() else: raise Exception( "{} could not check out restricted book".format( user if user is not None else "anonymous" ) ) def run_demo(): book = Book() book.shelve() print(book) book.checkout() print(book) book.checkin() print(book) book.reserve() print(book) try: book.checkout() except librarybookstate.BookState.InvalidTransitionException as e: print(e) print("..cannot check out reserved book") book.release() print(book) book.checkout() print(book) print() restricted_book = RestrictedBook() restricted_book.authorize("BOB") restricted_book.restrict() print(restricted_book) for name in [None, "BILL", "BOB"]: try: restricted_book.checkout(name) except Exception as e: print(".." + str(e)) else: print("checkout to", name) print(restricted_book) restricted_book.checkin() print(restricted_book) if __name__ == "__main__": run_demo() ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/statemachine/librarybookstate.pystate0000644000000000000000000000103615134002420021726 0ustar00# # librarybookstate.pystate # # This state machine models the state of books in a library. # statemachine BookState: New -(shelve)-> Available Available -(reserve)-> OnHold OnHold -(release)-> Available Available -(checkout)-> CheckedOut CheckedOut -(checkin)-> Available # add states for restricted books New -(restrict)-> Restricted Available -(restrict)-> Restricted Restricted -(release)-> Available Restricted -(checkout)-> CheckedOutRestricted CheckedOutRestricted -(checkin)-> Restricted ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/statemachine/statemachine.py0000644000000000000000000003014615134002420017756 0ustar00# stateMachine.py # # module to define .pystate import handler # # import imputil import keyword import sys import os import types import importlib import importlib.machinery from urllib.parse import urlparse DEBUG = False import pyparsing as pp # define basic exception for invalid state transitions - state machine classes will subclass to # define their own specific exception type class InvalidTransitionException(Exception): pass ident = pp.Word(pp.alphas + "_", pp.alphanums + "_$") # add parse-time condition to make sure we do not allow any Python keywords to be used as # statemachine identifiers def no_keywords_allowed(s, l, t): wd = t[0] return not keyword.iskeyword(wd) ident.addCondition( no_keywords_allowed, message="cannot use a Python keyword for state or transition identifier", ) stateTransition = ident("from_state") + "->" + ident("to_state") stateMachine = ( pp.Keyword("statemachine") + ident("name") + ":" + pp.OneOrMore(pp.Group(stateTransition))("transitions") ) namedStateTransition = ( ident("from_state") + "-(" + ident("transition") + ")->" + ident("to_state") ) namedStateMachine = ( pp.Keyword("statemachine") + ident("name") + ":" + pp.OneOrMore(pp.Group(namedStateTransition))("transitions") ) def expand_state_definition(source, loc, tokens): """ Parse action to convert statemachine to corresponding Python classes and methods """ indent = " " * (pp.col(loc, source) - 1) statedef = [] # build list of states states = set() fromTo = {} for tn in tokens.transitions: states.add(tn.from_state) states.add(tn.to_state) fromTo[tn.from_state] = tn.to_state # define base class for state classes baseStateClass = tokens.name statedef.extend( [ f"class {baseStateClass}(object):", " def __str__(self):", " return self.__class__.__name__", " @classmethod", " def states(cls):", " return list(cls.__subclasses__())", " def next_state(self):", " return self._next_state_class()", ] ) # define all state classes statedef.extend("class {}({}): pass".format(s, baseStateClass) for s in states) # define state->state transitions statedef.extend( "{}._next_state_class = {}".format(s, fromTo[s]) for s in states if s in fromTo ) statedef.extend( [ "class {baseStateClass}Mixin:".format(baseStateClass=baseStateClass), " def __init__(self):", " self._state = None", " def initialize_state(self, init_state):", " if issubclass(init_state, {baseStateClass}):".format( baseStateClass=baseStateClass ), " init_state = init_state()", " self._state = init_state", " @property", " def state(self):", " return self._state", " # get behavior/properties from current state", " def __getattr__(self, attrname):", " attr = getattr(self._state, attrname)", " return attr", " def __str__(self):", " return '{0}: {1}'.format(self.__class__.__name__, self._state)", ] ) return ("\n" + indent).join(statedef) + "\n" stateMachine.setParseAction(expand_state_definition) def expand_named_state_definition(source, loc, tokens): """ Parse action to convert statemachine with named transitions to corresponding Python classes and methods """ indent = " " * (pp.col(loc, source) - 1) statedef = [] # build list of states and transitions states = set() transitions = set() baseStateClass = tokens.name fromTo = {} for tn in tokens.transitions: states.add(tn.from_state) states.add(tn.to_state) transitions.add(tn.transition) if tn.from_state in fromTo: fromTo[tn.from_state][tn.transition] = tn.to_state else: fromTo[tn.from_state] = {tn.transition: tn.to_state} # add entries for terminal states for s in states: if s not in fromTo: fromTo[s] = {} # define state transition class statedef.extend( [ "class {baseStateClass}Transition:".format(baseStateClass=baseStateClass), " def __str__(self):", " return self.transitionName", ] ) statedef.extend( "{tn_name} = {baseStateClass}Transition()".format( tn_name=tn, baseStateClass=baseStateClass ) for tn in transitions ) statedef.extend( "{tn_name}.transitionName = '{tn_name}'".format(tn_name=tn) for tn in transitions ) # define base class for state classes statedef.extend( [ f"class {baseStateClass}(object):", " from statemachine import InvalidTransitionException as BaseTransitionException", " class InvalidTransitionException(BaseTransitionException): pass", " def __str__(self):", " return self.__class__.__name__", " @classmethod", " def states(cls):", " return list(cls.__subclasses__())", " @classmethod", " def next_state(cls, name):", " try:", " return cls.tnmap[name]()", " except KeyError:", " raise cls.InvalidTransitionException(f'{cls.__name__} does not support transition {name!r}'", " def __bad_tn(name):", " def _fn(cls):", " raise cls.InvalidTransitionException(f'{cls.__name__} does not support transition {name!r}'", " _fn.__name__ = name", " return _fn", ] ) # define default 'invalid transition' methods in base class, valid transitions will be implemented in subclasses statedef.extend( " {tn_name} = classmethod(__bad_tn({tn_name!r}))".format(tn_name=tn) for tn in transitions ) # define all state classes statedef.extend("class {}({}): pass".format(s, baseStateClass) for s in states) # define state transition methods for valid transitions from each state for s in states: trns = list(fromTo[s].items()) # statedef.append(f"{s}.tnmap = {{{', '.join('%s:%s' % tn for tn in trns)}}}") statedef.extend( f"{s}.{tn_} = classmethod(lambda cls: {to_}())" for tn_, to_ in trns ) statedef.extend( [ "{baseStateClass}.transitions = classmethod(lambda cls: [{transition_class_list}])".format( baseStateClass=baseStateClass, transition_class_list=", ".join( "cls.{}".format(tn) for tn in transitions ), ), "{baseStateClass}.transition_names = [tn.__name__ for tn in {baseStateClass}.transitions()]".format( baseStateClass=baseStateClass ), ] ) # define Mixin class for application classes that delegate to the state statedef.extend( [ "class {baseStateClass}Mixin:".format(baseStateClass=baseStateClass), " def __init__(self):", " self._state = None", " def initialize_state(self, init_state):", " if issubclass(init_state, {baseStateClass}):".format( baseStateClass=baseStateClass ), " init_state = init_state()", " self._state = init_state", " @property", " def state(self):", " return self._state", " # get behavior/properties from current state", " def __getattr__(self, attrname):", " attr = getattr(self._state, attrname)", " return attr", " def __str__(self):", " return '{0}: {1}'.format(self.__class__.__name__, self._state)", ] ) # define transition methods to be delegated to the _state instance variable statedef.extend( " def {tn_name}(self): self._state = self._state.{tn_name}()".format( tn_name=tn ) for tn in transitions ) return ("\n" + indent).join(statedef) + "\n" namedStateMachine.setParseAction(expand_named_state_definition) # ====================================================================== # NEW STUFF - Matt Anderson, 2009-11-26 # ====================================================================== class SuffixImporter: """An importer designed using the mechanism defined in :pep:`302`. I read the PEP, and also used Doug Hellmann's PyMOTW article `Modules and Imports`_, as a pattern. .. _`Modules and Imports`: http://www.doughellmann.com/PyMOTW/sys/imports.html Define a subclass that specifies a :attr:`suffix` attribute, and implements a :meth:`process_filedata` method. Then call the classmethod :meth:`register` on your class to actually install it in the appropriate places in :mod:`sys`.""" scheme = "suffix" suffix = None path_entry = None @classmethod def trigger_url(cls): if cls.suffix is None: raise ValueError(f"{cls.__name__}.suffix is not set") return f"suffix:{cls.suffix}" @classmethod def register(cls): sys.path_hooks.append(cls) sys.path.append(cls.trigger_url()) def __init__(self, path_entry): pr = urlparse(str(path_entry)) if pr.scheme != self.scheme or pr.path != self.suffix: raise ImportError() self.path_entry = path_entry self._found = {} def checkpath_iter(self, fullname): for dirpath in sys.path: # if the value in sys.path_importer_cache is None, then this # path *should* be imported by the builtin mechanism, and the # entry is thus a path to a directory on the filesystem; # if it's not None, then some other importer is in charge, and # it probably isn't even a filesystem path finder = sys.path_importer_cache.get(dirpath) if isinstance(finder, (type(None), importlib.machinery.FileFinder)): checkpath = os.path.join(dirpath, "{}.{}".format(fullname, self.suffix)) yield checkpath def find_module(self, fullname, path=None): for checkpath in self.checkpath_iter(fullname): if os.path.isfile(checkpath): self._found[fullname] = checkpath return self return None def load_module(self, fullname): assert fullname in self._found if fullname in sys.modules: module = sys.modules[fullname] else: sys.modules[fullname] = module = types.ModuleType(fullname) data = None with open(self._found[fullname]) as f: data = f.read() module.__dict__.clear() module.__file__ = self._found[fullname] module.__name__ = fullname module.__loader__ = self self.process_filedata(module, data) return module def process_filedata(self, module, data): pass class PystateImporter(SuffixImporter): suffix = "pystate" def process_filedata(self, module, data): # MATT-NOTE: re-worked :func:`get_state_machine` # convert any statemachine expressions stateMachineExpr = (stateMachine | namedStateMachine).ignore( pp.pythonStyleComment ) generated_code = stateMachineExpr.transformString(data) if DEBUG: print(generated_code) # compile code object from generated code # (strip trailing spaces and tabs, compile doesn't like # dangling whitespace) COMPILE_MODE = "exec" codeobj = compile(generated_code.rstrip(" \t"), module.__file__, COMPILE_MODE) exec(codeobj, module.__dict__) PystateImporter.register() if DEBUG: print("registered {!r} importer".format(PystateImporter.suffix)) ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/statemachine/trafficLightDemo.py0000644000000000000000000000104615134002420020521 0ustar00# # trafficLightDemo.py # # Example of a simple state machine modeling the state of a traffic light # import statemachine import trafficlightstate class TrafficLight(trafficlightstate.TrafficLightStateMixin): def __init__(self): self.initialize_state(trafficlightstate.Red) def change(self): self._state = self._state.next_state() light = TrafficLight() for i in range(10): print("{} {}".format(light, ("STOP", "GO")[light.cars_can_go])) light.crossing_signal() light.delay() print() light.change() ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/statemachine/trafficlightstate.pystate0000644000000000000000000000216515134002420022061 0ustar00# # trafficlightstate.pystate # # state machine model of the states and associated behaviors and properties for each # different state of a traffic light # define state machine with transitions # (states will be implemented as Python classes, so use name case appropriate for class names) statemachine TrafficLightState: Red -> Green Green -> Yellow Yellow -> Red # statemachine only defines the state->state transitions - actual behavior and properties # must be added separately # define some class level constants Red.cars_can_go = False Yellow.cars_can_go = True Green.cars_can_go = True # setup some class level methods def flash_crosswalk(s): def flash(): print(f"{s}...{s}...{s}") return flash Red.crossing_signal = staticmethod(flash_crosswalk("WALK")) Yellow.crossing_signal = staticmethod(flash_crosswalk("DONT WALK")) Green.crossing_signal = staticmethod(flash_crosswalk("DONT WALK")) # setup some instance methods def wait(nSeconds): def waitFn(self): print("" % nSeconds) return waitFn Red.delay = wait(20) Yellow.delay = wait(3) Green.delay = wait(15) ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/statemachine/vending_machine.py0000644000000000000000000000461115134002420020425 0ustar00# # vending_machine.py # # Example of using the statemachine parser without importing a .pystate module. # # A vending machine that dispenses candy and chips in a 4x4 grid, A1 thru D4. # To dispense a product, you must press an alpha button, then a digit button. # import statemachine # Vending machine buttons: # A, B, C, D # 1, 2, 3, 4 # vending_machine_state_description = """\ statemachine VendingMachineState: Idle-(press_alpha_button)->WaitingOnDigit WaitingOnDigit-(press_alpha_button)->WaitingOnDigit WaitingOnDigit-(press_digit_button)->DispenseProduct DispenseProduct-(dispense)->Idle """ # convert state machine text to state classes generated = statemachine.namedStateMachine.transformString( vending_machine_state_description ) # print(generated) # exec generated code to define state classes and state mixin exec(generated) class VendingMachine(VendingMachineStateMixin): def __init__(self): self.initialize_state(Idle) self._pressed = None self._alpha_pressed = None self._digit_pressed = None def press_button(self, button): if button in "ABCD": self._pressed = button self.press_alpha_button() elif button in "1234": self._pressed = button self.press_digit_button() else: print("Did not recognize button {!r}".format(str(button))) def press_alpha_button(self): try: super().press_alpha_button() except VendingMachineState.InvalidTransitionException as ite: print(ite) else: self._alpha_pressed = self._pressed def press_digit_button(self): try: super().press_digit_button() except VendingMachineState.InvalidTransitionException as ite: print(ite) else: self._digit_pressed = self._pressed self.dispense() def dispense(self): try: super().dispense() except VendingMachineState.InvalidTransitionException as ite: print(ite) else: print("Dispensing at {}{}".format(self._alpha_pressed, self._digit_pressed)) self._alpha_pressed = self._digit_pressed = None vm = VendingMachine() for button in "1 A B 1".split(): print(">> pressing {!r}".format(button)) vm.press_button(button) print("Vending machine is now in {} state".format(vm.state)) ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/statemachine/video_demo.py0000644000000000000000000000225015134002420017416 0ustar00# # video_demo.py # # Simple statemachine demo, based on the state transitions given in videostate.pystate # import statemachine import videostate class Video(videostate.VideoStateMixin): def __init__(self, title): self.initialize_state(videostate.Stopped) self.title = title # ==== main loop - a REPL ==== v = Video("Die Hard.mp4") while True: print(v.state) cmd = ( input("Command ({})> ".format("/".join(videostate.VideoState.transition_names))) .lower() .strip() ) if not cmd: continue if cmd in ("?", "h", "help"): print("enter a transition {!r}".format(videostate.VideoState.transition_names)) print(" q - quit") print(" ?, h, help - this message") continue # quitting out if cmd.startswith("q"): break # get transition function for given command state_transition_fn = getattr(v, cmd, None) if state_transition_fn is None: print("???") continue # invoke the input transition, handle invalid commands try: state_transition_fn() except videostate.VideoState.InvalidTransitionException as e: print(e) ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/statemachine/videostate.pystate0000644000000000000000000000153515134002420020521 0ustar00# # videostate.pystate # # Statemachine describing the playing of a video # [] = stop # > = play # || = pause # >> = fast forward # << = rewind statemachine VideoState: # basic >, [], and || controls Stopped-(play)->Playing Playing-(pause)-> Paused Playing-(stop)-> Stopped Paused-(stop)-> Stopped Paused-(play)->Playing # add >> and << controls - different meanings if occur while playing or stopped Playing-(fast_forward)->FastForward FastForward-(play)->Playing FastForward-(pause)->Paused FastForward-(stop)->Stopped Stopped-(fast_forward)->Forwardwinding Forwardwinding-(stop)->Stopped Playing-(rewind)->ReversePlaying ReversePlaying-(play)->Playing ReversePlaying-(pause)->Paused ReversePlaying-(stop)->Stopped Stopped-(rewind)->Rewinding Rewinding-(stop)->Stopped ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/tag_emitter.py0000644000000000000000000000171015134002420015143 0ustar00# # tag_emitter.py # # Example showing how to inject tags into the parsed results by adding # an Empty() with a parse action to return the desired added data. # # Copyright 2023, Paul McGuire # import pyparsing as pp # define expressions to parse different forms of integer constants # add parse actions that will evaluate the integer correctly binary_int = ("0b" + pp.Word("01")).add_parse_action(lambda t: int(t[1], base=2)) hex_int = ("0x" + pp.Word(pp.hexnums)).add_parse_action(lambda t: int(t[1], base=16)) dec_int = pp.Word(pp.nums).add_parse_action(lambda t: int(t[0])) # define a parser that includes the tag for each integer format type int_parser = (binary_int("value") + pp.Tag("original_format", "binary") | hex_int("value") + pp.Tag("original_format", "hex") | dec_int("value") + pp.Tag("original_format", "decimal") ) # parse some integers int_parser.run_tests("""\ 0b11011000001 0x6c1 1729""") ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/tag_metadata.py0000644000000000000000000000176415134002420015263 0ustar00# # tag_metadata.py # # Copyright 2024, Paul McGuire # import pyparsing as pp ppu = pp.unicode # associate "alphabet" tag with different Unicode character sets latin = pp.Word(ppu.Latin1.alphas) + pp.Tag("alphabet", "Latin") greek = pp.Word(ppu.Greek.alphas) + pp.Tag("alphabet", "Greek") japanese = pp.Word(ppu.Japanese.alphas) + pp.Tag("alphabet", "Japanese") # associate "mood" tags with different end punctuation marks end_punc = ( ("." + pp.Tag("mood", "normal")) | ("!" + pp.Tag("mood", "excited")) | ("?" + pp.Tag("mood", "curious")) ) greeting = "Hello," + (latin | greek | japanese) + end_punc if __name__ == '__main__': import contextlib with contextlib.suppress(Exception): greeting.create_diagram( "tag_metadata_diagram.html", vertical=3, show_hidden=True ) greeting.run_tests( """\ Hello, World. Hello, World! Hello, κόσμος? Hello, 世界! """ ) ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/tag_metadata_diagram.html0000644000000000000000000001331715134002420017260 0ustar00

'Hello,' W:(A-Za-zªµºÀ-ÖØ...) Tag:alphabet='Latin' W:(Ͱ-ʹͶͷͺ-ͽͿΆΈ-Ί...) Tag:alphabet='Greek' W:(々〆〱-〵〻〼ぁ-ゖゝ-ゟ...) Tag:alphabet='Japanese' '.' Tag:mood='normal' '!' Tag:mood='excited' '?' Tag:mood='curious'
././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/tag_metadata_diagram.png0000644000000000000000000007144615134002420017107 0ustar00PNG  IHDR@JIDATx \Tek2JT4T2E覵J]m![nKf!**^*!fie9  8,o?Ѹ:o4PWIe -[ѧi%H#a+\dӉW#@ᨾ}Fw s](ugnĈM7W< To_fn2HרlHosJoTЌhoNvoN2+Jశm^ݭ[C7.hĨ™Qji}-Y벅Nê)(O%;ۭm'"pBQc% pɓ' o 6s.\ݕ[Y jݞ:S;ؘ8U^E1$58P}nu$ۿ_42^v8upI͓F%v-#&\kA+}MmyX67óm۶@dgIF;uiݶ =4-5w|cKEӡW f%9|$6"h;u u<6ۍ&*P?7h?s![q;ݱߜ/ӡ;ܞס1{0_~qWƄ 0* =謾}yw̋}#ӭ}c^+R/\c] kΝѨ M…^;GmVÂ&ޯﰾt?ڲK޶foBdG;wqbXWXhŮ3>aFQR5D4}_~"5hs AL„DতWƷjc9Y%:8]S5PO`yRpaT2G'3fΰ҄Ox^WK'YIjd`| Kݚ(߽. GX]N˨t]'@vb|5? ex&q0]?)ė~Oֳ[lѣoFFJ5wv̺*&">~^cуe3l̮t$hStoX։s63ZmKga6V`QzlB?^~^VSp-N\]/RֺlSXg;RWU}NQgk)V.[+F)R!N1&AX^/)eGTX[!m9H}KhBlfG9<B]XFs2NߘcT|/wL]FkzXzo1cF[n̜SŧMBn_aIDAT 3~f͜|{u%gNK V8=!6FܑmʿbQ^Ymb=*lU6/fzE괃]š1S;8^|s m1e}Kֹ˲-_ 88,_=C}eSƈpNjR6~mFopRy45L-iE[wfhW=5ڕ95sl6]*:G̐ac=믿 BdM{ܓR޶~w r懅O9w*iENWA.75PYKw4f'UG]oL D?Kf^\H$ꤊGԄôYi9'PL3i˚̄5őڡV$_ninTB#Iߎ3uꨫFSFϱ"[;߉#TT.FQױN{ HQgyQ笳gϾh o-{_iX{N7y[~$]ԦnbY4xl YFlٺ,˩=I\t_FvY 1NӉ[aunL>1j^N{ 3H+dTY˨Tt~!_2̲Gse?vD+i@aAFi{kj3LJX_l@TZUTDdg#FcİeoS6#_~ˬ{4N^> 3j:Nj;\>Po/Nz?ZF`#ԡx9.Jr]˯]>3Ku#&*&9:^xaHpsc׿o۶vq1U]2q؉oN旆NKv:٨Z-4Nuճ8V;W*+6s[b՟ee\fIkʶkWٖU-eLy6?WڼhQe^Ug\# pANK '}ULj2{c*E]^'0NJfwi>R#`/[n3ݥ.ڗ}>>];th8l=wߵje Zjevl߾C42m <7>-֒ヒK.X~3 W ۡJ.MJc h CDв%p2v`deA̘ڮU[GN,J 'ՀB[KO \ٛ2̟eYzZo}١qlYZTb+R\Y-k"NrǨ9rv@YEt!cߝ#+W׉ [ \ZKQieS X04Qv:_0r`jRpSplx95)rBaWr6KR2l={L7͚5OK^n?w{YN믿@#Uj(\ѩ'D_}/"7o.\;wˋ?Lv㪼S+]yS+@?T㻤djlﶇhW`tﯲ.!UQg%Cl|fo8h'C42۶@U[6лeF[῿=آꎏv,}voe.5mr\-g{.r!9|$6"h;uk9F~)+s4=nuVk35ݻus$Jc#ohk1, ܹN_Q]tylV^%Y)YyGg,i3WqJSzC+:ݱٓf?r\hvzr\u6SC sר3޽ۘ>#'Fع3oy:@yhCؤYi$jHaQ|]w1yļul}cmcI'Ye>hpp﨓b=r"s.ӧOԔoI4&L@eM2H  /0w7M7_a}.Nk.yۚϭgF?R¨CuoI4^z3Ӗ6t>̑풒@DWv5m9p|˄ _Tk^O<.܁QGqԍ6m!^֕xg&S>xVw;*:t ״yƇ|P5׬jw_;_x~˖-g FC\:thҋgҽ[7h\tE#(7z=[T~!?NAUG_kE>uظQGwԝ8qBW\NM[i-k8kߗ_HM5wqßn@5].~e|6.aquҋ 6TP.9z) Ν iA' zԭaN Kp\ڋ rw+N.E+][꼌:Ǜqs`F=c|bG?\ro[F݇9_NG,m޲'渰5kFDT'e+|>g;CgL ia(k6 ˺IVl@gȲjEz(^^$|&xÒ[_0 Hs*ޗ,Ң\3tjhvmnf{y.:K7ǮҼҤ`//0L ˆhfc uuwgT׾%hT B_!fh;v:ǎ>|h2Z~27y4s ~fGײczl-N ;@"햱Dz):=4=Ҕ.MuY"05/ ҤiyJ^i\NB">b~Ónxlc.B-D/TQ'L;S.sqLC}*n"tT+]$Bb]$smԝ>}zOdֲe Y 0]?)ė~oVgh٢GJ]n"jGZQWU`jYdՃ>䂧菔}eSƘ^!&e3m I8S;2l;m5W߉>bG5EKjzjt-]?%Y6BYڑ_2k{B(J_S,9/m.d=+}WmM5tG97\$<΅B=6rOjJyے.\!S 2Gu k,@e"TvGj+u/Hsz9Z*),9*N'*ky&TMF0= 2-D# zq!we\<_oN/V2z-,(!e 9߉#T,X'8_ 6f-O7E 'cX{~T6Z}Ӥ]8E;6;ʫmѾGЀv/*uQ N~'>y]wѷg4*`,;u9AaCd\`2Jde7%8`YNةĥ.'}Ͷfjg'Eɵv#k<QuA É/S_7*J<߄_%.<\꾏pIÖ3Oۨ|/37+v:5Zc'Vj.Q>%˪~OU;iʿI8_qUjƬ-W%QxR_:˨`:]f4N;mѷyiҐi vZ>Szfu|.o3TV͊*?87xqlղTli,V\~&ΣUF)ӫi._pP˅>cDbm&|uºq.e諻iWy7D߹N„v=뉴ecߪ?7ز8GW~6&`/t)SPf{J"k,ex0.bF{_> #Az;TIr;Utx^/~l_՗(stX ȲN h,?0>0jziQ/uZ'gʀdГ^*e*rmI^k8pp;F]Yz+ t,"I1~E ]4N,a|ov,Wq}cH,`Ф /v:N`wٲEEeYGY٢Y,Q# V \QJKK>p Aڴ`4~pUy//Z,GL0ٍgլ~~&qg-1FͿ9m۶I 6*L}N{g}7?^6b̞;gv=n^UQvClB[[uG;>T7S䢅>YS!aheE7zQ܎>k:ŵ`μն-T-SХKf%]%wt629<'`(/wDDkK=UuM}wlǏh3.ɹsKlfL&]SأwǼG="yn@KJ+_V ozMl\uPθد cOrH^5^xa; 9Â&ޯﰾtPO'~ڵemy3>hFS#uSN-&8`ڪZ?k "//ysf?3FQy __zAT\?ݘC|uG!C/}_|&-ݻu@ɓ&ZmknŨCuox@ɕW^9g&¨\C( P0@ jϦ͛w~¼\uU~}G D.wyQwKz1jɓ& U?0+}mےז>|}[uGLޖ뭹O>zO<ީcG\o97 &:rla>spcĨC_$dȰ[?=4^pT/ᅲ={>O񦛷oamۡ흏nWM 3~up_ <~ܹs _޲%wúVZ:`ԡA¢59m[JJJFq[m­=/ FGjS(/ w3՚C2|FfQynu7sy>UxKQ!XKn{O??O׮ߵ{rT=`@{;"3+hGDE,ݴr2+qI]:˱>#ܸ~ÆbԡM ׶]r%/Lvw;qAGP%zHM[YRRR3gio/>/.H0|TP%_6=z{KKKmzСCѢei53-%W81,+ 6K8  Bɀ&,["c̹ёm<cW@J3}9=: x:f5j7n}pLn^ǰ9%D1'qofkUzÜ/'GfOŃ:\0%c-[7vu7#vޔaUQ ޕ4̘Y$G8ҡ5'E'SS86HZI9ޭ:sqР).L*vґ&84EVvhmĉۛ??/xpyѶcov{ޯ{ v;:=4/ch QZ7Jv 5Uj{Ya;{wXnfEE rxvDZ .^[}"JJg_>v^6vMT0Њ.Ĕ+N{^SVe߶|]q*Y? R'6GnD"gfj_`\i^zCS{GX˴^i=DT}^cΌU6WzޑyyѬY~̬b}l@/'Yi_Up=js{@!Owqe8_eVTbkYv JgUbIv[xG&jEqσ-n܈(ȚX h>ӷޚa欓mϠ-D΂,}t͒j6$nžbWŒمIDY6kv׍z e4>,Fs3yG!'}ѣ-])")(9COM2tEed:NjR43Ad D(JHa̚Nϊ]7%R7R'2vyZ$(kLL(6>Uv^f UaBH*۾XĘ d&Z#oB_^7g%yu _.y݋.ݵkƅϢNxߧx}^^rIuhKQɒdJUd4-֊B)Zgt{%"!?t*J]O!qF]wA:9zr|+E5_bQXֵz-Wz=O>l6w_3fJ֔>=]oM_y~yzʷ׍SI?,\Ӣe9UV"ʾj1 QholMUn&`I“Dm/UD}RIH\YwfshFDSP(JΩ~|WrxZSGX{T_xO#pM[g+Ưo/f~0S^{5;'GO}߽}eC0· >߻vy6x)sh+6WS׵2'`탻Gat4NKiV멶 uUVk)r~[z9j^cs {Y/oQޙˢm#Z97rzlsEmVH gʫΦ[Ei٪hh>ޠ/Zլ5H|'C`ce&BF|ja[AKkD9qνW{ʧmv^v߸,#Ov3wOMV'C[ahy=3l[w ?xNvi'xow`jVϡ,[l%oȂ(*cq)_ƵYE`BeѬ *xl2OG?7g,rr{WI%,~5jy5KW z䥬[:V~X?1gU<{gδ-W3HSR,Ͳ_RW&cջ.yҨsbZ>1,׬|(KӥNjTeE9}20sj_`2m*3;B+>9З2:+ygFRo_B|߾,T(2z?9VӪs>~֏ۦ]~SݗE3w-S Hٙ؜θ iuSq&pD _>U:֒[nBFr~,5 ۋç4H+neLx>=d۠Ԝ_}51pF޳o7mЯt*{ZN.J_S],^޴eȯ?R,v/xqeYwgS_͠Yi2Ets92z;IxmoIKY pVJiZU?B}oG+cws4i>l*ܙŮ9B[G/, m"gecwb\B,U:srzU*j(> uڹ ~dWbΝ=c_>pHaCĥA=4{|Ϣ{}ٞ[1)EBIrC{ŨnzefK!U'iI/,Ȥݵk}'FEg ; o4iQw zgX>l"q@'ek#},ec%-׿1U [v: 3N:rA/W"$HXe;ޫj_~ARe_6c|fs"X?e)5JKK>p ̬#dC{R;vh]|5Xbe8+.$\&~X^Wsԉψ9si+%`dO/p#Sk/ZŻ~y9qn1.8rȤ^N?)kW3>O0!Ok~|n:Dїpg}x:/ڱ zEK}V: ^z)e,N\?xj=wkluLڨ4f<'|1Qn j` tsbok`c=/wgF?ܳuCC/O&~uNɻ_-W^yp7@Ɖ)m;vʶL8w{-#_׿~ (L{wm%ݴnu㰡C~ 7w7;?ڹ1cu+W# jf˙]xѠ\Sn>jtcp򷖵nZ /OY!CD~_a{Ƅ 0* dY:/өc/zJ_Cܹ-~]w80 *ɢ\jJyےninĈ'jJFngϞ~~=G9yDQN8Ų_jhL20=ėE\aEnaė6W wgT0 -ӧ>ԈQAGw;thkK@#Cࢃn4oKn,ٶn_ƶ?6o޽{7~p\tE+Y~AixۧF`­ݎ=*9`p@yƛ= 1N.矿;[768:۹{=po/߮=vβo+ڿwڥk_ny_;ѽOgIDATQ_ֻё]ztWlR/_/ݵrJؾ ok9FܚY ]f{ϋ~8~[Dk h.ꁌ6d̐ia 3ғ#GNS/pբbMw<~e| J~aqM5v7ύ[rDn%9}4+ h޽G|xbNlQ7F_x=_[-Z9ߍfsѼڿsbAi{H+v7qǟW@4|k-F#5meII@+RS1wD=qtdt~{;KFM6/~ xvKkӶq̂@ǎ/ywOPO^{ucdi5\%bN ȭyUݮgϾtpcV6ڲ|-ÒD8?@~|(.W]hңFYMBS \p„-[b@ZfшC?8 q>CM5Тe w27iizYCZ`v#}FHآҌg.΍N/JII뼢&e c,^՗^z^%onh߾=7q,cܪU֭[]^r@rz$KТ*BʒIr[h6{ ϴ pYuV4'l^ 2mZ-Dpb@>PHQ&HO7E "m](I.~1ӫlۢ~ K1dE\h}K"|xc|DQsS㍗<%e4 a;Դ%CV$j~?8vFԙ^VͮOdo5ˤgɱNO-.(ݼUv}n[ثjE:0 kzd-n{}[ W'l`ZTq7<&k[Q:v65W`gƤaxݑ;vާN2zyQAÆ0h 7\xae|9Ι]ݣ.hS,%ɯ9yDŋHuh8vۢok9Zz@~=|IW/p&-LiY,zѕw`!'!3fZ"p|0H#asV.9~-ssi%Y.-Le罪7;-_88NΝ;7pkm۶me;'$8 y+yKtӣk}%\,Sv==´ie:ϚjtҮ];ᤁ-qSL  2l٬'quhp`܁slc+tdyYZ"ɁI2ʍa1Whk<Ԍ?s/YTqT{eY:4AfGUZCe/#S|o_-F«N'oqqF?ع^^6p~-hԧٶd{VgyZ8ٳ2/^}:?WwY1F{_ddoĽaF{Gjg%W"w[zAbf W]z%K_{ho>DU\z@־vRI-Kczز*ۀ<3u^|?@9x#Am^9?,hBP۽Ow>_rw][vm\?e|}gExEO=!+2}EMO'~D޶fo|Xxyy͋3JvƉcG8hM7u#FnS:EPXi!7~ڰ'?~ꫢDM4ۻ?3}m\3?7\Գ x:0*#+l8t[o/OM[~t-+ĉ[?dۧy۶m۾Cb&h6.ĕ9`PXiu g + 8 0@ `%Ͽ"33k'~媫;b?&ǩS6~˯:1 x c ?pذBhXZiN}g+ɯ;wNԿݺҁz???دs| RX5P8{l{n߾ca_gä_G0zSO9sFï:s֣aIppoj` Zne49RnW3^ݑ#G:ϧV|-_2l/L|y˖ 2Zj%ԩScC2#w8k|.ݻx _)J{,ώ;"˧ݲuYnO<|y7tSڊwjgA>)̬,Icohzef  ʘ+h8qS/]cy_sK7- n]aC Wš~#gFƯ'z<LJЮݻ@VE]dm ug$6h?wY:9s̳=o{ R2jB%%%iij  lq׍F轡nVs^a)ʛc܊[bjYfϯxިyY:tH6Zl1?mSx"GOO)&;nP8~<Ν;wStUaQZZzcr{˱nLJ[L&;;5;F{ yg yU+bݒο&oQouV|ݒk0UU7Μ9O~24o\wĨzI[?f<ڦm"j4pIDATG8= c4v =ڏSJh*LRAd}kLUUжO?8% M-r  e[ϑNӝ!qy鑦wh|'WRRbgX_&t\fS4&{UT Vmfv^^I"ȂJ%-il)^|-eV 3m:6o'*ҁ;<`/aa׏[PXhl6tsM֭[wI~u[omPEhuvBn_CG5{Hob^K nߊSb2ʊ> 3Bj([ i {~ssy8#XXyiRȎC̐2gj;g,t^MӢLrce;[zQfKߘm%v^kDJ/mCرcO>uIp5@Ř1lxM7U}n 6I-Z)2ΒYE{ dӼPL 0*aU/+]wǗuiB2Rb` EkE:Y N4NY0=\\$s*1UW&a۹)(ŵ*ka '&鹋gΨpSd^UHԱ_Hw{x Pg+SSw|UG3~wrPXivnmV |3 -浳SγO9V$u -EBWB#o^^^#>yRVTBFe^|m1䖯?ZԁDŽ v//Hz|o>%a"7B_l^c*ociQ5eÓT#]WljwDUhf#9ب4p=sFu됁/ DLF岊 D=` 4ue}zҹynzW{9zflU*-USp3siYѳY{h&8^ͅNKa-Wj\;*dM6)aK]g ЄŎ_׿6M\[yMډ0g2]ʍVqcQ!6?5 8P8oF]X?57;J;vAK)VϮlμ5<5CKZQiIU&#';0U_Jf=Me ;P$ !u+5^uFW֗o\Gۜ^c]k=D]81JKK>p O;g90bTΝڥS #zM:yl]>fh̬#dC{R;v(ꃬ˶N$֧F&82ڴ`4~񸀧kݶDGE7翹a;wnFtsǎ/Ǐ :~.? !x 0j21O# c#bri{)F. /mZ(A9|)nB`⍥Kڶm+G=rW],D=۳uϤk&JG *\u݈3b0*.=E=;8Xilxw;wM#Ə8r`:yw#unZɺQ_tZ}-Sn -kҽpmqR8q`7]~w:uJB\RD18x[˄;dgmӯ$'w] x:7!4uLCƌeƛoI4N;.xիVnZC-^|!>i/T@nBhQ={XWJ?z온׍>9|VZ w Ƃ~iS?TTCM߿%hd(18XdyPP0@ `%Ͽ"33k'~媫;b?&ǩS6~˯:1 x c ?pذBhJKK>p$|Ϗ/sfϝ3O>_}%sΉ׽[7__:pVY!Ԧ] ׺m{TL@a4 3gԼ;6Lڿ =t_uG&~!)JKFAAA J_}{wGu(?nֶC[>߷|Oʰ0-[r7hժSN ˸+|ܝ|t")\Bv6_~Gc fy]=c17llrVS+<kdȫ]<_[/ٮ7yzot}TUz'r?hcq' CtI۶b2uS8w'یڴm#SDTwdV|,{Yy~3ؙ/_,k? L=/v"#D,f˗Xϱ\wylT:¢5kj7nU!tر'~ƺ$tcppƚj b̘[6m>T'ک::EQ1Eƕ%y}w4->ӂL_h@n.MYF A(}MZ-K4NY0=\\$bWɫU^2YE6?!",Kw4 pѳ+NNtU+CSǎ ^|a}.@=zLMV=v߅rfc% 6jfo5WlɫΗB?f-r {vrpJ鵳,uMzRa5s}dsmE`[׍>9|VZ 'o /5kϿ.ӊ. v?^sͶN/b0fk[4I/Q!ֹsfOmD3zp1v*Ǐ :N~.? !x *[?(tҫ]%ʂ+^^a7Kr?x썖1w\0SԃKOPm 5I20jQT͵'=O3#~grw GfL{9Q=>doxW<߹Kg!A@e`u#"6y?bȁ2Iv$'s-俛mn6tuXĘGmn{˔[n t")u3P~]N o-kݺ_uޓO[P<2f-6|Mtq/^]ѥE/ﴎ^*!4uT]o-_jUcDnĈ'jJԃӧOiS?8@=ФQ@e`BB%J @( P0@ `%J @( P0@ `JKK 0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0 P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P=bIDAT0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( P0@ `%J @( B^IDATA%4nIENDB`././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/test_bibparse.py0000644000000000000000000002145615134002420015476 0ustar00""" Test for bibparse grammar """ import unittest from pyparsing import ParseException from .btpyparse import Macro from . import btpyparse as bp class TestBibparse(unittest.TestCase): def test_names(self): # check various types of names # All names can contains alphas, but not some special chars bad_chars = "\"#%'(),={}" for name_type, dig1f in ( (bp.macro_def, False), (bp.field_name, False), (bp.entry_type, False), (bp.cite_key, True), ): if dig1f: # can start with digit self.assertEqual("2t", name_type.parse_string("2t")[0]) else: self.assertRaises(ParseException, name_type.parse_string, "2t") # All of the names cannot contain some characters for char in bad_chars: self.assertRaises(ParseException, name_type.parse_string, char) # standard strings all OK self.assertEqual("simple_test", name_type.parse_string("simple_test")[0]) # Test macro ref mr = bp.macro_ref # can't start with digit self.assertRaises(ParseException, mr.parse_string, "2t") for char in bad_chars: self.assertRaises(ParseException, mr.parse_string, char) self.assertEqual("simple_test", mr.parse_string("simple_test")[0].name) def test_numbers(self): self.assertEqual("1066", bp.number.parse_string("1066")[0]) self.assertEqual("0", bp.number.parse_string("0")[0]) self.assertRaises(ParseException, bp.number.parse_string, "-4") self.assertRaises(ParseException, bp.number.parse_string, "+4") self.assertRaises(ParseException, bp.number.parse_string, ".4") # something point something leaves a trailing .4 unmatched self.assertEqual("0", bp.number.parse_string("0.4")[0]) def test_parse_string(self): # test string building blocks self.assertEqual(bp.chars_no_quotecurly.parse_string("x")[0], "x") self.assertEqual(bp.chars_no_quotecurly.parse_string("a string")[0], "a string") self.assertEqual(bp.chars_no_quotecurly.parse_string('a "string')[0], "a ") self.assertEqual(bp.chars_no_curly.parse_string("x")[0], "x") self.assertEqual(bp.chars_no_curly.parse_string("a string")[0], "a string") self.assertEqual(bp.chars_no_curly.parse_string("a {string")[0], "a ") self.assertEqual(bp.chars_no_curly.parse_string("a }string")[0], "a ") # test more general strings together for obj in (bp.curly_string, bp.string, bp.field_value): self.assertEqual(obj.parse_string("{}").as_list(), []) self.assertEqual(obj.parse_string('{a "string}')[0], 'a "string') self.assertEqual( ["a ", ["nested"], " string"], obj.parse_string("{a {nested} string}").as_list(), ) self.assertEqual( ["a ", ["double ", ["nested"]], " string"], obj.parse_string("{a {double {nested}} string}").as_list(), ) for obj in (bp.quoted_string, bp.string, bp.field_value): self.assertEqual([], obj.parse_string('""').as_list()) self.assertEqual("a string", obj.parse_string('"a string"')[0]) self.assertEqual( ["a ", ["nested"], " string"], obj.parse_string('"a {nested} string"').as_list(), ) self.assertEqual( ["a ", ["double ", ["nested"]], " string"], obj.parse_string('"a {double {nested}} string"').as_list(), ) # check macro def in string self.assertEqual(Macro("someascii"), bp.string.parse_string("someascii")[0]) self.assertRaises(ParseException, bp.string.parse_string, "%#= validstring") # check number in string self.assertEqual(bp.string.parse_string("1994")[0], "1994") def test_parse_field(self): # test field value - hashes included fv = bp.field_value # Macro self.assertEqual(Macro("aname"), fv.parse_string("aname")[0]) self.assertEqual(Macro("aname"), fv.parse_string("ANAME")[0]) # String and macro self.assertEqual( [Macro("aname"), "some string"], fv.parse_string('aname # "some string"').as_list(), ) # Nested string self.assertEqual( [Macro("aname"), "some ", ["string"]], fv.parse_string("aname # {some {string}}").as_list(), ) # String and number self.assertEqual( ["a string", "1994"], fv.parse_string('"a string" # 1994').as_list() ) # String and number and macro self.assertEqual( ["a string", "1994", Macro("a_macro")], fv.parse_string('"a string" # 1994 # a_macro').as_list(), ) def test_comments(self): res = bp.comment.parse_string("@Comment{about something}") self.assertEqual(res.as_list(), ["comment", "{about something}"]) self.assertEqual( ["comment", "{about something"], bp.comment.parse_string("@COMMENT{about something").as_list(), ) self.assertEqual( ["comment", "(about something"], bp.comment.parse_string("@comment(about something").as_list(), ) self.assertEqual( ["comment", " about something"], bp.comment.parse_string("@COMment about something").as_list(), ) self.assertRaises( ParseException, bp.comment.parse_string, "@commentabout something" ) self.assertRaises( ParseException, bp.comment.parse_string, "@comment+about something" ) self.assertRaises( ParseException, bp.comment.parse_string, '@comment"about something' ) def test_preamble(self): res = bp.preamble.parse_string('@preamble{"about something"}') self.assertEqual(res.as_list(), ["preamble", "about something"]) self.assertEqual( ["preamble", "about something"], bp.preamble.parse_string("@PREamble{{about something}}").as_list(), ) self.assertEqual( ["preamble", "about something"], bp.preamble.parse_string( """@PREamble{ {about something} }""" ).as_list(), ) def test_macro(self): res = bp.macro.parse_string('@string{ANAME = "about something"}') self.assertEqual(res.as_list(), ["string", "aname", "about something"]) self.assertEqual( ["string", "aname", "about something"], bp.macro.parse_string("@string{aname = {about something}}").as_list(), ) def test_entry(self): txt = """@some_entry{akey, aname = "about something", another={something else}}""" res = bp.entry.parse_string(txt) self.assertEqual( [ "some_entry", "akey", ["aname", "about something"], ["another", "something else"], ], res.as_list(), ) # Case conversion txt = """@SOME_ENTRY{akey, ANAME = "about something", another={something else}}""" res = bp.entry.parse_string(txt) self.assertEqual( [ "some_entry", "akey", ["aname", "about something"], ["another", "something else"], ], res.as_list(), ) def test_bibfile(self): txt = """@some_entry{akey, aname = "about something", another={something else}}""" res = bp.bibfile.parse_string(txt) self.assertEqual( [ [ "some_entry", "akey", ["aname", "about something"], ["another", "something else"], ] ], res.as_list(), ) def test_bib1(self): # First pass whole bib-like tests txt = """ Some introductory text (implicit comment) @ARTICLE{Brett2002marsbar, author = {Matthew Brett and Jean-Luc Anton and Romain Valabregue and Jean-Baptise Poline}, title = {{Region of interest analysis using an SPM toolbox}}, journal = {Neuroimage}, year = {2002}, volume = {16}, pages = {1140--1141}, number = {2} } @some_entry{akey, aname = "about something", another={something else}} """ res = bp.bibfile.parse_string(txt) self.assertEqual(len(res), 3) res2 = bp.parse_str(txt) self.assertEqual(res.as_list(), res2.as_list()) res3 = [r.as_list()[0] for r, start, end in bp.definitions.scan_string(txt)] self.assertEqual(res.as_list(), res3) if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1768949007.71793 pyparsing-3.3.2/examples/tiny/README.md0000644000000000000000000001345015134002420014533 0ustar00# TINY parser and interpreter (pyparsing) This folder contains a complete pyparsing parser/interpreter for the educational TINY language. ## Running the interpreter After cloning the repo and establishing a virtual environment, cd to the project top-level directory and run `python -m examples.tiny.tiny_run samples/hello.tiny` to run the basic "Hello, World!" program. The `samples` directory contains several other illustrative scripts, using the TINY language. ## Running the REPL The TINY project includes an interactive Read–Eval–Print Loop (REPL) for quickly trying out statements and functions. - Start the REPL: ``` python -m examples.tiny.tiny_repl ``` - Enter TINY statements directly at the `>>> ` prompt. The REPL incrementally parses your input and executes as soon as the current input forms a complete statement sequence. - Useful keys/behavior: - Press Ctrl-C while typing to cancel the current partial input and return to a fresh prompt. - Press Ctrl-C during a long-running execution to interrupt it and return to the prompt. - Built-in REPL commands (typed at an empty prompt): - `quit` — exit the REPL - `import ` — load function definitions from a `.tiny` file (ignores any `main()`) - `reimport ` — same as `import`, but overwrites any previously defined functions - `clear vars` — clear locally defined variables in the current frame - `clear all` — reset engine state (variables and functions) - `list` — show current variables and all defined function names - `list vars` — show only current variables - `list functions` — show only function names - `help` — list all REPL commands with brief descriptions - `debug on` — enable debug mode (show full Python exception tracebacks during execution) - `debug off` — disable debug mode (default; suppress tracebacks and print only `Type: message`) - Example session: ``` >>> list [variables] (none) [functions] (none) >>> import examples/tiny/samples/math_functions.tiny >>> int x := 5; >>> write factorial(x); 120 >>> list [variables] x = 5 : int [functions] abs(float a) : float cos(float rad_) : float deg(float rad) : float div(int a, int b) : int exp(float x) : float factorial(int n) : int hypot(float x, float y) : float mod(int a, int b) : int pi() : float pow(float x, int y) : float rad(float deg) : float round(float a, int n) : float sgn(float x) : int sin(float rad_) : float sqrt(float a) : float tan(float rad_) : float >>> quit ``` - Errors and debugging: - By default, exceptions raised while executing TINY statements are shown concisely as `ExceptionType: message` without a traceback. - The same concise behavior applies when importing files with `import`/`reimport` (I/O and other errors print `ExceptionType: message`). - Turn on verbose debugging with `debug on` to display full Python tracebacks for exceptions during execution. Use `debug off` to return to concise error messages. - In debug mode, file import errors will also show full Python tracebacks. For a fuller walkthrough of REPL features and development notes, see `examples/tiny/docs/tiny_repl_transcript.md`. ## Project Structure - tiny_parser.py - Defines the TINY language grammar using pyparsing and exposes `parse_tiny(text)` to parse source into internal parser results. - The parser tags each statement group with a `type` tag (for example: `main_decl`, `decl_stmt`, `assign_stmt`, `if_stmt`, `repeat_stmt`, `read_stmt`, `write_stmt`, `return_stmt`, `call_stmt`), which is used in `tiny_ast.py` to instantiate the appropriate executable AST node subclass. - Independent of execution; focused purely on syntax and result structuring. - Allows for testing the parser in isolation from any integration or implementation components. - tiny_ast.py - Declares the abstract base `TinyNode` and node subclasses for each TINY statement type. - Nodes wrap parser results and implement `execute(engine)`; nodes that contain bodies pre-build their child nodes. - tiny_engine.py - Implements `TinyEngine`, the runtime responsible for variable scopes (stack frames plus globals), text I/O, expression evaluation, and function invocation. - Provides APIs used by AST nodes: declare/assign variables, evaluate expressions, read/write output, call functions. - tiny_run.py - CLI entry point to parse and run a `.tiny` program. - Registers top-level functions/globals, builds the `main` function node, and executes it using `TinyEngine`. - Converts the parser's internal results into an executable hierarchy of `TinyNode` objects, using each statement group's `type` tag to instantiate the correct `TinyNode` subclass. - tiny_repl.py - CLI entry point to start the interactive TINY REPL. - Implements the REPL's command-line interface and REPL-specific logic. - Uses `tiny_parser.py`, `tiny_ast.py`, and `tiny_engine.py` to parse and execute TINY statements. - samples/ - Sample TINY programs (for example: `hello.tiny`, `hello_5.tiny`, `factorial.tiny`). - tests/ and examples/tiny/tests/ - Pytest-based tests that exercise the parser and AST/engine execution. ## How to run quick self-tests of the parser itself - Run simple tests of the parser using `python -m examples.tiny.tiny_parser` ## How to use from Python from examples.tiny.tiny_parser import parse_tiny src = "read x; y := 1 + 2; write y" result = parse_tiny(src) print(result.dump()) Grammar outline: see `docs/grammar.md` and `docs/tiny_parser_diagram.html` Pyparsing best practices were used to prompt the AI on preferred usages of pyparsing. Accessible using the command `python -m pyparsing.ai.show_best_practices` ## Reference - TINY language definition: https://a7medayman6.github.io/Tiny-Compiler/Language-Description.html ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7185163 pyparsing-3.3.2/examples/tiny/docs/grammar.md0000644000000000000000000000631015134002420016151 0ustar00# TINY language grammar (current parser outline) This document reflects the current definitions in `examples/tiny/tiny_parser.py`. Ref: https://github.com/a7medayman6/Tiny-Compiler/blob/master/Language-Description.md Notes - Terminals appear in single quotes. - Whitespace is insignificant except inside quoted strings. - Comments use C-style block comments `/* ... */` and are ignored globally. - Simple statements are terminated with a trailing semicolon `;`. Control-flow statements (`if ... end`, `repeat ... until ...`) do not end with a semicolon. Lexical tokens - punctuation: `'(' ')' '{' '}' ',' ';' ':='` - keywords (reserved): `if then else elseif end repeat until read write return endl int float string main` - identifier: a letter followed by letters, digits, or `_`, but not a reserved word - number: integer or floating point - string: double-quoted with `\` as escape, for example: `"hello"` Program structure - Program := { FunctionDefinition } MainFunction - MainFunction := Datatype 'main' '(' ')' FunctionBody - FunctionDefinition := FunctionDeclaration FunctionBody - FunctionDeclaration := Datatype FunctionName '(' [ Parameter { ',' Parameter } ] ')' - FunctionBody := '{' StmtSeq '}' - Datatype := 'int' | 'float' | 'string' Statements - StmtSeq := one-or-more Statement - Statement := - DeclarationStatement - AssignmentStatement - ReadStatement - WriteStatement - ReturnStatement - FunctionCallStatement - IfStatement - RepeatStatement Simple statements (each ends with `;`) - DeclarationStatement := Datatype VarDecl { ',' VarDecl } ';' - VarDecl := identifier [ ':=' Expr ] - AssignmentStatement := identifier ':=' Expr ';' - ReadStatement := 'read' identifier ';' - WriteStatement := 'write' ( 'endl' | Expr ) ';' - ReturnStatement := 'return' Expr ';' - FunctionCallStatement := FunctionCall ';' Control flow (no trailing semicolon) - IfStatement := 'if' Condition 'then' StmtSeq { ElseIfBlock } [ 'else' StmtSeq ] 'end' - ElseIfBlock := 'elseif' Condition 'then' StmtSeq - RepeatStatement := 'repeat' StmtSeq 'until' Condition Expressions - Expr := RelExpr - RelExpr := Arith { RelOp Arith } - RelOp := '<' | '>' | '=' | '<>' - Condition := RelExpr { '&&' RelExpr | '||' RelExpr } - Arith := - Right-assoc prefix `+` on a single operand - Then left-assoc `*` `/` - Then left-assoc `+` `-` (This mirrors the `infix_notation` levels in the parser.) - Term := number | string | FunctionCall | identifier - FunctionCall := FunctionName '(' [ Expr { ',' Expr } ] ')' Additional notes - The special literal `endl` may be used only in `write` statements (as modeled by the parser), or a general expression can be written instead. - Comments `/* ... */` may appear between tokens anywhere a statement or expression is allowed; they are ignored by the parser. Examples - Declaration and assignment - `int x; float y := 2.5, z; string s := "Hello";` - If/elseif/else (no semicolons after blocks) - `if x < 10 then y := y + 1; write y; elseif x = 0 then write 0; else read x; end` - Repeat/until (no semicolon after `until` line) - `repeat x := x - 1; write x; until x = 0` - Functions and main - `int sum(int a, int b){ write a; return a + b; } int main(){ int r; r := sum(2,3); write r; return 0; }` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7185988 pyparsing-3.3.2/examples/tiny/docs/tiny_parser_diagram.html0000644000000000000000000037203715134002420021126 0ustar00

Program

Function_DefinitionFunction_Definition functions 'functions' Main_FunctionMain_Function 'main'

Function_Definition

Function_DeclarationFunction_Declaration 'decl' Function_BodyFunction_Body 'body'

Function_Declaration

DatatypeDatatype 'return_type' identifieridentifier 'name' '(' [suppress] DatatypeDatatype 'type' identifieridentifier 'name' ',' [suppress] DatatypeDatatype 'type' identifieridentifier 'name' 'parameters' ')' [suppress]

Datatype

'int' 'float' 'string'

identifier

RESERVEDRESERVED [NOT] W:(A-Za-z, 0-9A-Z_a-z) [combine]

Function_Body

'{' [suppress] stmt_seqstmt_seq stmts 'stmts' '}' [suppress]

stmt_seq

statementstatement

statement

Declaration_StatementDeclaration_Statement Assignment_StatementAssignment_Statement If_StatementIf_Statement Repeat_StatementRepeat_Statement Read_StatementRead_Statement Write_StatementWrite_Statement Return_StatementReturn_Statement Function_Call_StatementFunction_Call_Statement

Declaration_Statement

DatatypeDatatype 'datatype' var_declvar_decl ',' [suppress] var_declvar_decl 'decls' ';' [suppress]

var_decl

identifieridentifier 'name' var_initializationvar_initialization

var_initialization

':=' [suppress] exprexpr 'init'

bool_expr

term_expression_expression_expressionterm_expression_expression_expression

term_expression_expression_expression

'||' operations'||' operations

'||' operations

'&&' operations'&&' operations '||' '&&' operations'&&' operations '&&' operations'&&' operations

'&&' operations

term_expression_expressionterm_expression_expression nested_term_expression_expression_expressionnested_term_expression_expression_expression '&&' term_expression_expressionterm_expression_expression nested_term_expression_expression_expressionnested_term_expression_expression_expression term_expression_expressionterm_expression_expression nested_term_expression_expression_expressionnested_term_expression_expression_expression

term_expression_expression

'<>' | '<=' | '<' | '>=' | '>' | '=' operations'<>' | '<=' | '<' | '>=' | '>' | '=' operations

'<>' | '<=' | '<' | '>=' | '>' | '=' operations

term_expressionterm_expression nested_term_expression_expressionnested_term_expression_expression '<>' | '<=' | '<' | '>=' | '>' | '=''<>' | '<=' | '<' | '>=' | '>' | '=' term_expressionterm_expression nested_term_expression_expressionnested_term_expression_expression term_expressionterm_expression nested_term_expression_expressionnested_term_expression_expression

term_expression

'+' | '-' operations'+' | '-' operations

'*' | '/' operations

'+' | '-' operations'+' | '-' operations '*' | '/''*' | '/' '+' | '-' operations'+' | '-' operations '+' | '-' operations'+' | '-' operations

'+' | '-' operations

'+' | '-''+' | '-' '+' | '-' operations'+' | '-' operations termterm nested_term_expressionnested_term_expression

term

real number with scientific notationreal number with scientific notation real numberreal number signed integersigned integer StringString function_callfunction_call identifieridentifier

real number with scientific notation

[+-]?(?:\d+(?:[eE][+-]?\d+)|(?:\d+\.\d*|\.\d+)(?:[eE][+-]?\d+)?)

real number

[+-]?(?:\d+\.\d*|\.\d+)

signed integer

[+-]?\d+

String

string enclosed in '"'

function_call

identifieridentifier 'name' '(' [suppress] ')' [suppress] exprexpr ',' [suppress] exprexpr 'args' ')' [suppress]

expr

bool_exprbool_expr

nested_term_expression

'(' [suppress] term_expressionterm_expression ')' [suppress]

'*' | '/'

[*/]

'+' | '-'

[+\-]

nested_term_expression_expression

'(' [suppress] term_expression_expressionterm_expression_expression ')' [suppress]

'<>' | '<=' | '<' | '>=' | '>' | '='

<>|<=|<|>=|>|=

nested_term_expression_expression_expression

'(' [suppress] term_expression_expression_expressionterm_expression_expression_expression ')' [suppress]

Assignment_Statement

identifieridentifier 'target' ':=' [suppress] exprexpr 'value' ';' [suppress]

If_Statement

'if' bool_exprbool_expr 'cond' 'then' stmt_seqstmt_seq then 'then' 'elseif' bool_exprbool_expr 'cond' 'then' stmt_seqstmt_seq then 'then' 'elseif' 'else' stmt_seqstmt_seq else 'else' 'end'

Repeat_Statement

'repeat' stmt_seqstmt_seq body 'body' 'until' bool_exprbool_expr 'cond'

Read_Statement

'read' identifieridentifier 'var' ';' [suppress]

RESERVED

'if' 'then' 'else' 'elseif' 'end' 'repeat' 'until' 'read' 'write' 'return' 'endl' 'int' 'float' 'string' 'main'

Write_Statement

'write' 'endl' exprexpr 'expr' ';' [suppress]

Return_Statement

'return' exprexpr 'expr' ';' [suppress]

Function_Call_Statement

function_callfunction_call ';' [suppress]

Main_Function

DatatypeDatatype 'return_type' 'main' '(' [suppress] ')' [suppress] Function_BodyFunction_Body 'body'
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7185988 pyparsing-3.3.2/examples/tiny/docs/tiny_parser_diagram.png0000644000000000000000000150273415134002420020746 0ustar00PNG  IHDR S7IDATx xU/7妐Z["V.hP,Vvb v@k[i8SaN)Z38gB,hhkT\^;W@Ǽkw]J޷w}}}\?dddddddddddddddddddddd^l]R7}s gV @+?+W0*ZG_=˦ŋӖ7ڽ9%V>wS[X7p^CD?$yÞsWp=ege+YR^8un7gee5.fO겒y99;F2{^)0'wGSV}}AMϚ4$kLntzі>_^ ^}۶myAӖU/Z(<:ysV+n|֘&tl |1e3,nݾbv^H&co^:aЌe& pt< uqe[vvpF彩mФ۟غ~ݭۗ]PW50Ml0o[vciPSM~p1c 'E39 +_yswÐrӬEnc9+ެs% 0&-Qs_բyO&~)0o+^t&*ʉ/|Ӌ=T]>or^2>웝7y~źۓۋ7ͯShVs}{E|䐣˫$tVrfGaߞefɍĐ%_Nh,[}YII%^8v#吒=uUe ΊǽT2~gDެ1/ חόw7~Qvf-HWj)'l=}:v&VUU GQSR)?L9,[nV]Q}smSXSs[Yyucuy2 E WXË*-<&'oVxZ=zŘns7.?u|ٹr1ue3:2iiuNYZs}ճJOk\n9p kr^iI4rҌۗe.,~rፓFJ3x%swRp'/~U*udtQ=?և0mYGCSQ>sxnnT'{VLX5iǩ4KjmƇ^^49;+>i.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ Mv=@W?yPQ@@@@@@@@@@@@@@@@@@@@@@@W{<>cu,;0{6r@-_7|;8t6 I}¥Ú-n{C7ٸ6GW6dJ߆9#C 8jƍsIUz5?oh?>#Qg\K$Y/8.ld0:#L5Tl8̿&^_PԹvd<Sil{vQ}'7 ҩW~.Ѿhqbk&{?'r(+9y3Pl8l~C厺] YT[W^s}#M|ҩ| ڑ)_-ŚEٴqUu/7;jD2wtǽ/?W~eX#aeh-~]Q+7{׌* ^d%jZ\5(kX<2V4u{m+;vaE26koᚋKm_c8|D~nHrB <5ys܋=W͂xĨko=32P]u9Q6oMj3ל=5;n{QrDp݀Fk?+ mTJ8|D(58ѼꁺÓ&y,My[:0uTmk <7躬67zk{15Ꚛ7oO(`BA3+*]Q= 'pҀ}ܼ#ڒ_}_n ~(؎>5 ?n Οp'5x8ׯzr W]Q74=̳*j7=2Ν;խ56mZo>W]qiap h^p>Sd|>4zeeefҸC5~Elz5P%{ӧOGCBشyK]?'|뭷L:%6nܷo󕕿Z|ڸ1bć߶m{f7Ø~i8S[9o~V !;wƍ8'nٳ'W4ʊd^n-pT_͂ğkbu3.Z㞋Uh/Ѝj6 #T7Wş.Gٸq9JG g$ 9vk? zqc%.xTau-`Sa5vϵچĦpp :$taٹ޿sG]YsWVNsE[Iíɞɣ-_Ns9!#+PyW&4bsV~/֕W.\_t9#HvW1"7juC%$]IDAT6qoߐ.+Z +Cn(kύZsEǿfT& #C 9BAH,nİW o5 V6Ɓ5̿tx;mk}D? q}a[Jh񎺝k10{@rXQhϰC.P}V dO([~oRuBhߴ3R36?;u0!߰សF=oΟ{QYO"5tg!},qcgQVwUbDQۼ5:_sNn윻q97Gquu>\b΋F006ⶵ+S)xԀDON+2灛C49 oԹR=3u +79@>0=B2[c+mZLBny\.MҾq#!3H~-S}ڛlٴ9Kɤ. OHexSoGԟdyBcq#wz_p~?d^WU5|pL,nCX9rmn{q/??xUCQ3F-xFy(훷+!r初 ÌWE5Qt67zk{a6m7 r'zzh9pgܻw#⩧^f͛G|C|G@B?w);.v ~V~+zj]̊gWTD'\0 @Ac$j lڴmkl~W+W~K~6?x뭷֯>s__߷|+ϳ=1SG_8;3[:9ؾ#nS:o߾97EhQ?;_\qϿ]f7tȐ'Dώ;G+m/?hG{ϞA)ݻ/?B=Ư}mԨs8~{#n^޸7?eeeњ(xsE :*NZB w3ToՕ?;f 'p ZJy:8h^{EwiWǹKH̎6_/ p{Q)e}4#/T'pS@׬u܎2کWbf|J>ɿ{_cY[؏/\7jݻ;caƍ_~>}b>vG>+({,@Km޲%{;ǎsۼ9s^>|?^6ʤigVTD۾}]  8N<ɟ/ 'ŋ/]fkYcF߾}…b?O|k:nϮ>m݇ V~q?d4WtҀ@:ѱ F~fG7.|n\6l;wРq5m{^Рw8>^:n{ p0ws7o.|}v~v_o7&Fon[z;/x cFz6YWiIMUlݶm[8=@^&OdV8^Z74$uO Bm?up :M{z׻Ǝg7n\>{Ny_]v]N;-coC_iO5oUōSO=wCUt?y;!i,N:i#KK_12>k|{~=4⸘5kFN=fpxz@c7 c4:YSiΝ0SߴO_%??nLLn۶m[tiܾS c;ruܿ%tJ [w_ϬGy__If9_LMC 9BA/}G>|v gVTč / 7O&yaS>_lXhewwHw_aXWxY =USӾ~am ; uOw FC%'jǾ]vL_gWTğ 26ʕOwŋ7;qBzMVHYxvxN Uꓟ]";!s'|rԨ8?{н:T=lxCߋD9%ǁJ߿iӦ>L_^\~}> jcwլ!XxWo G̾Z=UߟwԻ85_ypj^[WuP\:Goj{7o+U%qAjn;>7|t֭G޴۾l; a[8ȷcc#eUy[{7``!lpħnf̙ʓO>ֹs?>pӊA:y;§˲XRH_,-|{#_/|]Z^H *狉(Abo}YVIk/I4#Q7=_PC̊;>]iViVWT^L>o塚.ٚ/=m57N)Z^j/smȟRG m%R)D7{CMͦ}‘Qʄö?}}w_0CǞ%cF]S>WkxC||Ꜣ7Jt#Z*Wl_/^{cguWN5N1$* OLmL*=U['~"Qd]9Dh(L,hK .uj̒pmFϊ*z$wECŇQS.iլ_L&*q.8Y/4)6?+9ZL֊ŷBr}z$&YSF5XbD:<5 ُ(3XX8t5w=6N{+4goa<I}f_ivIl VSޯ[(o¯W+1iɶC} Ah;8;t9𮤩IDATowiޅ1ؼ!lJ{WCYN<1:P(ukH>OKeGgﲻKN2xdU >noCw-{-h MlsG]ӣ>ѕDx-k\/24Uԡ<ޅOumX:_qzF_և#Q4X{s玺W6.֎ǣns̙3F[;cݗ|!^t׾6j9S?=-tɷYف ;)1`8d'k"YwUVm apR'&xQvQaL>}vBAytYYY]z\Qty8$ϬxvEE? +}ΝԥaKo|_NQǣ&q EwjH})-27/^  ~Ƶ&<_|%p%}MkU(65lLZᘁcDMҽݐ4;Tbϰ$9aUeA2,k|Ŵ%qƓLQXpv:?ϖ/Z? _RK9٪S֕W'do|_7I5HּLݒ؉C5;Ր@gdEWv=NVZ_he-qc!~o~̚uۼꕊEyU}@ɩ5..|YeQr (¿ޅwL|q )H*k%oVS\M'0P +Y7꒒]2Ew%fDk:ˁ{p "q%ʓZ-uw.K]6E鿽o;(vysq_SQC`+_븪k۷KK_6gw=t]N= g}D;?߷VSKk9+;]shx1o؎~~Ulm|qjtɃH$1رc~7i:qj3.O\};vDA4$'$HW \FLXVX-\xY'>q5W_|]'ҾaCDc?b?2+G7.|~č[n GR@W{n88_3IƁ>|۽{w~N t54 iK~vܘi۶mqsqm˰kByDyHc[@Wtw7֎ :l jq#pg>8{7C 2,nQ#t[k_Zn׮]~[y?}=Ϯݻg~Nywvy]T>r8?f=);;_o9wTǍEQA}8޽{+W5vAGU[[W^ ot+ @g/}{_YVG7zq͚38tsč߿Ν; H+6&nt{@Z%;/5֬YkZoݹ.@m߾}K Ǎ =F߾}QW__/[ysl]/.n\ON+___zw%WVƋg1C Ќ/‰?TRRp^ Ew-?qRh1;{O3炝1tȐK\|@i歵qKdeehw?gV/,'L }tO<1@;~Wva~PEcx}+^eˢOHV>(ओN~/ ɪ)þ0VCGfZU|:GQ_N:vZdNȹ}gͻ=G2k!]WOpbo!nz{‘ԧO /8P.:gd/ˍv=0qofv8vڵdϢ3>9Q`<3>;j9Bonځ3=/j? z' #k[vf p,<̊qYy~ʜ>mxW믿.j]:pN6SߴO_u>e|_'tG>|v4tI'V])MN߰Cq#_{L8~~zj1@d׷a[CzŲ^Z.n'og40!@O6gWmڼe-Qc! 1;ܯV>[\hܫ,j\+<Dg~ &? @:CBڵ{w[{5༿kCNao~~?qW]^zyݶmxz׻%++b:3S;~+#Fܼe˒5 R8.UW׼p z}C4!CN}{Ɵǥ[k'Ki6ߘѣ몞YQ8f]Cz ͒cF2$n?Kw֭޷tΝQwޗ}rJhNv޻}5cF*؅<#SmWUUmZ&^Q4l=yK";wz_lڼ%^ӧ׾2++++^+<{FnUW5.s/} H! ڧz2uu8#1C- Y=s߾}/}Y^0aLbƎ>ajUZ{B>}D9{N9}{s4H--Gg2'15@#dddddddddddddddd95 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ z lfNVV̲Q=?/+)o~uE +^\Z{`#˦`zVD WNz9Yғ#%r(tIDATm񢊐yVk+3}~YНʦu\qm?+/ =TuisяJʪ@нWؾť7M9_N;Ğ%3,Md~o|sw}d>mtΛ^z;$9EKjxG&-oaSfɝ]^г)j ڽr僣® sف-7ꛝ7y{+f>KRdr~GGD7rdІjm{X[敕O0{\v^QqyG.?}LNTsy3UUee69YhrSKq+ftyӺՋIIߜ1KZURfV-6(jxSсx3&뛓W8{6ScEqU,mz3UQXdr냷?_Jθi}rqMg3gfٞC>zJxK[=CS.rW5LXI֑N5:1zpy=bq?|OFZ]EqA3ܴmSm_⛦5(yrIQ1Jr=躷c]qVDd;;uNC䒒Kgifϥ).noOڱ1:h\e9K?\z?Y$_{V o ?_AqE;מw &e%/F?^,)~^]__zv^jdeZB=m |K{sy7M.nU/pskjÛ.!Js7+m5BeΏbZW6=ꇷE3Vnbm_ʝva]S4'.'%atN?ǂy-ߘ4\κGW}错KZ&9/[{Wp#o =7&YqKl| MPtU瓿ԫa5hڲҙyΛLIjJKeP%3oJa5N5WzCX%7''y{̜4Q5uՋfɉ/ۗ*k+̝v8N*m%U.lNnxY%(CM?}.'ou?\ZzױϴMkp~źA9jH;F7wxFΝ79T%ՍO dv^-}c'KJN֗=yIDKuNk,r[Es'-G״y-վ:D Z=A-HW=N/.:@GHUE\lXXxdVx!˞L,**lksǚF)+*R=wiY{[ G1STW'۪w),Jl++GIWkr'J e8zp, =]CaO6o JJC!ˣ}^]__zv^8ch嫏y8w^yq+?Ggtڊ~#''A-(oX29Ёܼ1ɟ+z* Ղ4ѽnku]p LV͝HU rfJbRawʝ>;9[m313'͞ٳ#N*N]K̙g,;$=>厓g%gsl9͚֕X1˳$ӽ_ޘEKj ܞՋf{mp[tIʛhuu]Cķzyg]nc t=M;Ο>oVVVe9ݞ4xSt-U$nvfY7X}{c8ft sXյ[2-m_:%dumgRVR<07T JC)(d~yV.̉5gvE8J2'7xOUYqaۣiK&M\Mo+٪.)8BGFZYU(6[=xC嬞7O$7gEټ.\Ҥ[ˣXbv΄$|QN]E y,(/s8MZPQx-K/5fʏk:u[=)Z\uWcEq΄ZMc|ѓ|Տu|6=e3s .}c~㎼qYɩ7w p(/Yo.3ixjAG_2ga !ofyʅs.=xP>gY++Rbу4?#aC.W;'x;Y:j;'?eԖx-ٓKw{S4xInϨbUPo*>Tuwk4rҌjj;O@@W+5} Wbmk>WRV@׃̜18tMfM BV}}}\?ddddddddddddddddv]omHO%5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ zL[Ɔ ̞p| 3CE;gׅ>tI[tºp]a_}~MцL15֯ g7jMTe+>>#^\Fcm^Ai}?.k%ߴTimj,k6̿fʕMkR;"?o,2gF|a g{;v{9泋dUko_XO $ w.:N +[,y.84ߢ +^VNǘoi(a+ϹjM2һxgN+{S,qm LYmnj~t/竩n>7 O$|7ohyk$1{fG/] GXr^J!.nFg-_۸aƵa‹B׷M^~؍s+ɃI5M6L'6/4şd4OC%J'yVwC;[~5̿tXrƥ HR23 8{|Q? l̰Ѧj~ uGYZ,pdl\fcL97Fކ_wk25?y瀩+B~aw\{s7 qwD/$#n{5SG k*rVfi;?}*L0xU-Nd&Q8j/p$,6+:*rFot}sĭ/?QjxsܳtUECÔ~>OQxRǥ̜G5 Q8 <(kvݿ_̊gWT L(h\Y:5u uw/{#nϸ&Q >t4篺xp Эk/`i8 Q} K{?PZ/{lK//l<|gWTcNѱ;ر4q-Æ TϮxiݺ׮O 'RIDATH/i9?d4.^:eg|͟,\?uY8}fmڼիO\| ?@ӧ''"zŕϿW_ W+_㍸=c^:,wACrG] MY˧>zG>uG.PyvE8$_q{رH_~ S?qkmm߿ p$wnk6m~uu55{$F͍2 'zc nYRtNY6n6_||_뵽xhlVQ_Lk;73ádway8,9^ȷB"0kզCY`ME/Oi߻jN,~ժgVN8bU=UpD7(L]t%=ZvW:2]H]'0tVz۪*Z}$n9IE,0G0D00^8qSO_Ν[5eoy8ؘ*ؔ(CJ+|]Xtjyi6):JdRcS/I4z>G}MN6%6͆b~poUUr'uSZC8xdo:T X8O$ϕ:T^<~iSwwba͝{'sss{Sg=X(OɷQ$øBûqMϹYJE; CSł$-]pCxSZr5-v{#wdhxo_Sqԯx3ZطioG%k*ґaq]2q b7yWQd|W6F&MmF_P>z/?DtUG1O05^m]ڗ\Pj}%c ?]fZņ\.mTE*z$9o؇*_/t4$t%#?$L.t)Z5ԃ6Y&ٲ¯ :ԅ姦uWᶒ}^+\O'͡/@bFD<ΌOf/7][" ^$~wrU =E Ƿ4g{(dlAsKޅP67O ;աHywGgﲻK5X8bIVQtx!ۍ9&xQP4%ԑ|a6+b†>OKS9q1ļSSYl:16B׿]/5ա~ {{ߞ|8(L$|wRwт<\zw}cfvQqҜ̰>w;pe《mn?`~aYzdշBJ^Cwj^"vReն7,5cU^iA&ukD`'FAh eq 1"da=6譋mu761=dV+p@6<E_E'5= JOf-׏;4dc>'v\2M߼gVT<"j? +a6O8^kڒ$[E9a5Mco&jڒc-U[;l9|(ↆ#Q64 qb0MNƖS=$ȡE q_{k=Ot epag?%dw1}Y3&w4lP_o;l?K⍭언/^~oQq' IU}Si1lʨ|F<`kSKˣt*7.Rn-U<]kb5ִ:WӉo/qG̅7 ҚbEw5L9hɁR&"ɦ:kV(IMT5LغgYD h|\\@[GkǦKt5XئYƑ`ν`x}aѽXO>B/@hv4W[7fG lݶ;;]_[;ɃN_'a;jA2^:B_ nޒG2!~-q%F$@fh1Zi8HQ[5j z3YG껡W:%?wIJ83W53[lH'ws!oNjx8p`ϽY}ݟrI}VPꫯ#g3K^8qb.jtu+OaHN>8{˖-?k&t^~u֨k64nUUngcN>M>iq# Ty57Ǎa 7 SEN <y#Gz2jTVѱ}iu玺R6P}_k҅M/>nqF 'ӟJ[Twi9tk.p$Ujݻ{O=u!r;= WT<HkA:%OXxiݺgWT82^^WM:ƏKF+aFc~??~;jGmH;wn޷7q_5F}#}K>ի:Ę l}UϿWEa(| Md׷a[C|e{&?qk_g^ueQ^y假Y;jO޽{_pqpOK/̜qhf[xvKL>BOAZӸc[m̨s~]NyC79'3 -sĬQ<꜏??>JOۻwpآiG@nVkC}[|t:G.P h3}p @&@&@&XIDAT@&@&@&@&@&@&@&@&@&@&@&@&@&@&Ȫ@S@@@@@@@@@@@@@@@@@@@@@@@@@Wp{fde,WbvNV+ 1@ -~@Ӷx/Y-mU̳z^^;_IvΘ˪* e|_8>ï^\zӔ3.tZ(_[#C驃/hImfڲ49UU =ۘ⪶[+\>8Z/_82Y7rde%E}Ŗyeœd7TWT\^ީT͟>&'q\˼™˪* 5VhrSKqe~ՋIIߜ1KZRfV-6(jxSсx3 .oN^Ek/wc=UKώbӡ7Ri[ӞusW4/qSxza^NNfi=捩(nv*Jf60sQQEcbL,wяѳ& cS6R~gLi:G\|Ӕ&ܶ>'*c{xm/>vgKKS;dO.)$y֛f/i\'7\mcOk{t#ثoa74wfA"y}+Mr7V6봱Snm5|G GޘNa5M;,fФ_uYɋяKʪyWׯtٴsi{X_pݛU>1''xL =hPܹ~1jeS7\ҁVm~.OWW6=ꇷE3Vnbm_הʝva]S4'.'%Kr Ol/K~'es+Zn:MzYwkbsb1}ɜpgiVJ̫mtޜ)~4ۗNl@kOϸi}~-*7$,77{Ԕ6ˠjKfޔU-*;yEw?Irsr‘g)K%j#o]Wh昜R}iѬiw+#Ϫ?ܖl]r_u†K/]^q{2~qzV[hԡC߼%]^VQ} `]m|#yŋnrIRW3<:efny%_h>Y:-DϽb^7s^q },MsMn"ՍO֝ dv^-|yE}W>_.)n})ٓ&KtNk,r[Es2'-N<6='$_q :xCOg$MJGa1|}S7:/!Uqaaa^[ڱV1!˞L,**lksǚF)+*R=wiY{[  ۑ{jKfd7]GߜKS;udܢx򘜜MG.(^߉w}ct;tMYoѳ&cad^'k(A 3Ƴ0G*\pÓ[޻m{ueLqM۷ =LOzc>f_=;/]֗>HymE"st~F(O7rrr<܂>]߁%S8nIYq7۟x~s+ . kuqC7rC|!J4zc4ֽ䶙U `dmV0;+gfY*]uKmR5f$pYQ6 4i(p3I'߸v~AR]E y,(/2=;qAT5^K۞^7k.<=Ǫgu"s}եs:zc7kLjlf^gsV+h19nkq|-n8uo_*\6gԀd'nCڭ \2z𠦵}'βWvW.iłiiFúZg]0bwt-7N9ɛ}uv,DO~^-?Z'T^P8hx}ciC|읐7O0~_/ipeO^Tʲ[|#'͸j;O@@W+5} Wbmk>WRV@׃̜18tMfM BV}}}\?dddddddddddddddv]om@Z@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@& ̞<$ϸp$,;0{6Ґ࠮šٸ&9#p@tf0"Ds[P,\X XW&'_T8,"L~ =.?qk4Otԙ= \ZXt v.a54ذrC8g@:ę_4 kn 7}}E ܙZ>EJ^5;޺dI\{]-_xgn<{;ܶi2byʢx7T>pU4_xQ\(9^cM~qs˯K,&;N= zMo$"ʯ4~a+Kwܓ.{[ؘu{gfYڦk\&q(Ktι':u?^j6d_}0QСI͏ngaԜk/ kFk/^xO/J%SQ"GiQ6onSTVIDATOˆz52Q7tu:j2۰2qďDvX1Ey_Cf6^nsʯob-NT`?@)0[3ι si[㤭GSXKX~] ]~%;oZ3|{rXpКMzfX6۽co kom U__]om4ߜvsmkW6~goluu/NiZ0FL}q֔}GgO}3 /jqب7IkH44LA8^I:+~Ų2z0$H~F;旽XͽC? ϬxvEE{YguYgu O:餁'<|}ֻDdzeee|oVvWWn٫2B@Ŀ;4 dFHٳgx`۶. okOND g?~[u3=3ѿ :$$p<3'@¯_z1;;/w;Ov><}@z$<슸;ON Ǔ~wygIꭷފ}%GOoZ ǽk7>| . bvQ93Fyfaon͚;궿;3:묳:묳]Iy#GNGBp$G13Wuqs W_-{l|3-nݺWIy' ޝEU $MY4+2w % mqyﭫ!yEi.2JYzrCAA0W@SpE 92m>ssf99yJBı ,-,, =~]jN8r> ef_2> ޏ oLԥ/H҆Y{{M-ݛlB͛7<#8׮]{\65}:j׮-\]yϱnݺ>e[I{'yVvrr25ÿ92`=zaCիWOTF @۲U瑇;pwXIwnO E:>*_yBɩT8}tP0'PnݺMzӾo7 '}z>tpV:wܫW'e__=R9/?ߣu+IEV.ynG֭+JڙӾ];vƎ;?[o] xyzș˗/ @ C,Rxԍ7:ח`n޼;??~rᾏ{u+ٟ+<=<^? @CDQ\RO.8;; v`۶oOD[h!8pȑ̬ ]svع,RʐXd@p @11/F֭%K1Ǡg<= &;/ݙ3 LQK(®]΋˓~goo/UVZ//yBU\\wK@FnrŢKߏ oLϵk{=+޴V-~ܹscgH6mSS;9YyDqßm  5Wnsqqe8()|}tʤ#G7l$L~lHXZ.D>5J^n^~aa3gΜ=wi5zܺ=e*SY?vxm5k*!3+K.ު7R5*SYX5i6bW+VMp>l8d@HD8_TnO'N@ctI}jVX&3SS5)i3% c*_3BQхoua#֭+̕c\2x@ Y7 Y 5o|UWe4IDATXyuv/;:s>ũw-g$F7A}_XC$HǤO *K``ҕ-I_q3'}3O-=}@L(Ig Q9〇g絏T"1{(F7Cl{4{㜙Kn{#<+y..?G +3c Y7rKI˵A:4u嘎ccS=b=ʞ)zwn1:M_-%ŗ/.;S']\RhR 2s&|)]UgwI6F7V9ﮐ>q45a Ջp UDI+CF<lW{ {i{݆Jev\kRM琀lU~UR;Ŕz+2P[?R<tM뼇K.Nv vJ8E.KTj$='t 7+Գ%9 \){}h_L혺f (凰_k"Fm`Mc/)~\9,DX֔*F8*_gNnwKb'y?hu3K}-!},y"=K\B3XPwyKcuxɷ߼O…noMj9rrԒF ~\(k>+J}޴ܸ[EkK? +u01OըֿsMV @bډWS[ۘ'Th~.X=9SɅMc;.yA}qZY-֪a Ռp 6>ː..$-承4*J=2\3n4S]TN2d 5I}4=Q]yTbt5jxDطk:M?(>`=F1"lż%CܨqzG)V;#}8Sڮhg0yLj#7ZI}X4'+ 3q_@{ovM?'mvfZ*?l~NMshGMx" T0~BTv?ޝ{ %#J՜ zg hK]RJ$|{KFS~^f|[X:ie>ZMF%Z!N.r@4Dt9{ֶqXd9cr?V۫#6-d|?6N.1-R´/U\J{u()}erq_ۥfT5:%a͒65j5h*T#.b5GC{yy473+=YYyy9=4bPa .իP6-ZK銖-Z%`k׮3 U)lm%׵tYQ6,w!UXT5kVd&}_n}vyf-زUpj}2ׯ__q˯G';>H2sƞLht͛ ]T';u|t`'s\e{2k#i=y E!UO'rxea$RX%Gȓ>| NUK.7[~i šӚlOk֪~:J`6Bj rϗ.g(I߱ß3=X_ZW.c}OkVWڹs0IG!R2X:Xݖ`m\Y:QӾqz^(/;[*ؙ&]MzL^gΜhOXC@C(U*ajTUDX3Ú;af;L cOk@a(+{=s_^?N˭l)`}kI*kNmdpXVǎAj׮MX3a쁭,AXs8n9RA[Ydnq}IN6iҨQ#alw _~]v х.:p6Ok&!9֪ HEoY:QԶMaU{nG֭+`,eǤ_6shH>>]8JXa Bšk1-Zp ̋ 9ԥ]pA.w0ԩ7nZu!v_p5e_`ג V&j0 k\0|יf0>Z\07F2DO|R1tumid]zGx/UT;w<8U>jǎ7]F0)=XSjl$Uf@|}gg9{q֭UTFk8hɖϟ`]ϣu+!U{,tTA5tϞz}Տ'ӵXzR֯O*.. ynD,լmdwi"n߾>'Q%Kߜmv ̻"&ޥ5 U'ff4WLZ@X@IDAT kמ\޲ug +ݖ`q86KwBXZ)H̕VnxteC}b;f(ިEȢ4#[?Qgdȅ.]Yy[幽+7Afݳg[+wzgjj~Hj@akf#{Z/`ekVezrx)ml*i7uaJkh8Ps9hzPUEe Qj(^;Q0[*lՅ3L]ب&P%_uK4ճÂ?H)5F/zvge@OeI cs<%M^+*^-=t uV9uJTm۷ض=e}RnHx'aN֪V {š ّysn.srz<6xР^ARأ@e[>vX֭EU<L\aAf j.UvڭZ0`Vn&aVjaMpXsss+**l]cNղjybX1MoϟƸ|HACnU\4qjծ-ibXkqk.ui%m93;u iQ5&VYv&8~ߦGK=i+2L\[2Ssjڷ5WFRh#9~D~TI8z'7ynܻچV'6q #֐Z@/+LhQH~Q3W%o彯 %!y+M^*gXdCbQHaf鞽@ZTtKvYzuEOfTHxz{T_ 5aNܾ}!0 k5š~6UM?[DyO5J8 bՁo&hr?0w&5 jToHW.J$=!{'~G}rlwa^sKm&@{=ZN |d2Ӗ<{Wg/]t5ѲZje#_[7oݻRܴP rHe,h(捛,ft_~U&#մv֭z8"f6`FXk04G ?A^:h80wXXf Z~l<Ӣ lمB4 I"dQDEs!I-J E:qO~NtW/~2}b7tA4vӕ}䒉{>T-,\ۆpWInwtVGˮԹ;2%7u=?n|7J#oc~X.lSc¬Sphd)ašCX]zu!v'\_}N:z{{mӦN>Y)`ZZ&aMFX3Cܹsܹ>Y .,* /nlNzKéƖj,GҟTrAgW Qg3 K6sEr-Q'5[^CUA&V֚)i==`n$O*ehG|p{KLz xͰH-H/?}QU0{hT\ -P$z֚I\rT*w`͚6 2"DF a޼)kvf;^ soz>ۛV f}W0+CX5ժUI&BCƎm[#ߙ:v NO$ G @1T}ռr0?]z?ݖӊ*@D' N[foi"4# ʮىfz!Qī˥6P#YPB6U'dsZt%"0$yrz!J\RaR/V OԈ(vJ[_IV(6n߾=}ƬO>T|gO k$ZnSu,O6wU}8gI@MU2vBsyKkI/vגvv^/^l-]RT 7,.X;<˂ a9 z=ܰaCa{K6X$k>37o|S?C*u헟ui?Q}D\j 5Z dvΝ}מݻj׮-2NEOY9`A\3i5S2lĴ`RVVhiԨqc/OenM܄9Z;h .)83+r\0~I]~6z+ a &Su}Or鋥KKcy"9^LK2JuuLP'-YܳW7n=aA8n[Rx촟>j}%*8EM|3&an$ܓVV Eg 9J}ݿaԴӆ<7DwK[Ƃ /|9IFF\޽PztkBzI`Ed7pWѯ>W8UBS.QXX(ztC`֣DG8k~of/5o %N]S>s97jŋRҥK~A[s 7WZbw.=T01Ma" ǎ7p^fm.EVT=w^;v_.0GX)>9KN(]8:}3J858ᬟ( Lwn8YP \\5jP0ٳګ /Lg..7w6/oe*ϛ~?&Lga[EUw=yAš JzqwY?ZTĝ;wB:z>0GX)>9KN(''mB)Ƴg5\-CwetZ=( T %x@]6`@];VJFeg6.ʣu+!Pta0aYxvOk)T;"ʝ=wni{);vJ/U\J[3gr> e*=XTثSN[V0){{#JViXiMyjN8e[;YPأqnܸnݺ%5kZӾYӦwжMi IL:M:4Qϐ=*jּv5SIa5I Z 9G1qrPE:š戌V]aԚsZYl2I6fU{_ϝ?/="'@U޹sgࠞ\{@Vz DX3֊.eKZ 9G석L+"Ok*l35 snnrAtϬNIDAT^=ի'`PNϖJZ=ݾuNP@oo/+wmj\|jr53Hamv۷ kav OkʁZu!@s_gϞ}]{iǵMɭ[ ɖ-Z 2AV??}tV]޼{ss?_tC ⢛]XϏ OI]&mAwV y}[V!a֔q [Ui š1Ӛ5+rV]j>U8}B~m);ܹs=YC5jdڑG(tIg`dvIa=SvH&eR1k¾0sH]&] Cz ^TvrrQ[Ykפׯ_Y5š1 )qSsrƍE"`@Xsc'a1U}eguZժUKJ3OmF'N[x_R Xta֭[2d޼i2IQCRW7WpE!栌?UϞ^"o~Q֬a]k`5 k&y?6N~)/:XC5mtdWoaaskL+o*͛7-5 3gΞ;w|Qpdջ\\\5l`E:ulrbeN.*** ۪Ճ-zmݺH4tj*~GB6mGXT 8#G ޫgT)8k@ekjA?Hªr!QkN/4n<8t{s^q 50;~ܘjK{m۴i`˖-[zA<9{}{pwQV;wH7o֭[Wb":f7nȅڵk k}Pc1z1/O#[H]Y5jdnѣ~W٦Le%Uvvv[^8uTرż< kTrEƇB&MV}@xn%?ԭ[wd~4pvTR*]e̺u떰f͚Ʌ̬,kpFeT=ڞL`+T~]:u|tla0UKT...6|evS*>uR!331ba |lZٌuU`%b \ ~l\:=[4Hsgʶa:v ^T7Os&$[[T;w<89Ӿ}~ kIPcq? V@j׮=?e7ϼy*'ߜmvy_ Cqq!(WW~Hj@0')sn.'srz<6xР^A҅]ի'ڮ_k۶OJ͗BϜX?H>8K'~Z>i9֯B#p-Mox8`_,S&_Ξ;'hX{CcOHwn>p6mGРAoWݘy] 5mKJ) 8{Vk~aVZ/Oo??$T*Us߳^4)l&;'G.<P0'4h0a8!@AN9s\iNju,(HٱSTÇȅm4kTj$mؘwp}=:~ΝSz @C~77 O:ܫgz@ E?=JXGgqqHMEgΞ=tp^...-F"£u+aЁm[ʎ;w\~}Of{{yvol#T2Le*SfTvvv[Xkr8Z` jgnۦB{2nݺ%,v-L]]]iӦ#Æ_r} Ϝ9[vm@uSIXRQ+4j-ڵ{N+|O2R…Tz\tA@ shn- 15hHM;~_O:aÇ  5T8x&ms =g n޸.pqqQizIco߾!B<)}(ppu; 56Kz\~<ܺu|ى'@9nݺljǎ;qn: 4Pq?&#eLoKiڤɸM9z4*[k0*ST2LeӾjPRwܶ=Cgg:%kڴiP`GkڤɈaCϞ;wc+{_T*U4+*[K lק(} dd% (?@ J@P2d% (?@ J@P2@U\\,88J@P2d% (?@ J@P2d% (?@ J@P2d% (?@ J@P2/7>PRe 4]rT$,W&RJ,z5;?;r%',/p(}xCY5aC68`'*%L?Z\_!,i|`$chv>Nnq)wVE%Sw-;9!.:AD%zP{jf2gwEǙeN V+40>W #ƷpRSr<\hAP#"^NUsƅ6NG^6S{}eԜc~vxB{VN5ݺYV>aԕ{t/GjC* Z2#{ܭ6ot2]'`!33BtQKJ-\Ӽ*Wif9)e7WqtfCeݭn56^y#3=PU?bkk"ݵۈL*;Kp;WW#zޭ*e~_kUG[IDAT9=g{&2;'|hIsyˢC}䤝҅\a m-2^0f^=gwOLL4sCܝWU:nvV"WjGa~xr [tlֽ逗؛E #dY[Yq/W~#wK˫ĽcSxn'gۭRC~^t&}E 3^һJI[_V$*a~/%9Y7$D_QBXIpWϟ<@a)n]K7gԨekfDz diX&G /U*sˎT=Kr*wY&QVܤ/7Nnnp7'7wq/oͭ0!??3ab*}EK*Ekw j9nke+1=w({83\#b^3S s3E:{Oah9qtORܣS,z93&nYnU8I[YVPnOvӸroX|5$Džx=Rm ב?#2KJs`.Uqqk"<Ъ/ψuMgv0Ө?5e]K5hy%ORzOl;KO&+ק/%ʭEʍ#*/)q!n%Eui^W ,fYOW-FO_j_ג9;/0EeG-O߈W~j3^Q)ѹy}^jq+^S^߸9Sq__?_ڲn˝#?z5lO{uޭy Zz)`\|u+U'b}qB_Ү%DkC'<8 2edϙ9=&MŒ)KABJûywT*ߘDKռWҮ@Շ>G?@ J@P2d% (?@ J@P2d% (?@ J@PJ3W.]P5h*pd% (?@ J@P2d% (?@ J@P2K[dff;vIOއnݪUΝ{6tHzP]pav()U#k,eum] `  D-nܸ1}ǟ@#]}_vM`իWknyW^ԩOB.ۿC?q}R7o|S?C*u헟krZņ 5Z.}FڤjPYYYRk]kIp 9[srrbҚ OO-[dqzѣ6nʑgk\' ԦgqI 8@.@;TG8 н{w#WI[dff;V >زe۶m{t4(#?|U;=}Hb_>)eÇq?hZlٺUΝ;>IaݻZ^rZήLz#9}<۞9{V*$)p坩/).ծ]?Oׯ/,0lDϿ$K~7a8a)8qwJP۶K?_ܵ'Jwweȴ.>b?ȅ̜aR\Ʌ Tq_W쇔bΝ; sT9c[f sڵ{ G ũU֫S^ufvZSRBTמ=U`vȴ"ls?C~p~]E{d#7o~`Neծ^:p)%O6tktiնV.{8/'/yM浛uba#Y--Rnر0=e7F1GF@&ſ痥BΝmMo齌xz}R<%K̪&-;-R~wUsRc_V0O ~]J8ړ/*l V T*0]T,gƌ&r#ӊ@VK8=ڴVfȾZ.9%rv\ _syfu0EaB^^˗?^N=/wĽt D!OnUf"23ȴ"+?0cd V# [͛rCOG۲CKstww%0V%Ku|P^k߹\~g۷o Ӎ=VFSVu#ӺsγϏ+*R>Ӿ}~뭶>?C*w?oZkC DO">0v֭*>[\>axρ=IG?Gzuܰq0݀;J3g>?nBecGY1 ӷm.pAe [:gxVm[ lW&γ=+3N<)L7*|dp^Bs3_2v8ʂ{^ND\_]qB"dά$Q;x ˺$kמ\ҫoNyM#׵ʑiE"WTî3;SS3mgѯ rFF\س+|KrTQ'Q*N,c^mm[߹\ޝ.̲dg 6d^p:[c\pi"fQ╩bѴb#{LKiטD|tuLRwT'ʟ'w6jrd{V׏Tu9U1mq|_y{g`-:$W!x (AJ_ ٛwQ_+Bܫ\.,<%.4^ y֭cƛ|@?B]^!|IDATyKXl+ݕt f77kW?,CtG RvqFekrd @O0EFI9щiʼnc5TiqifR󷧤H޼e0{QWR].yN;ˋlALXM jII)*2+J#ҡ[^y5ZzӰa[l۶m`+m!kW?sW\QO?>~FR=oGB uXMnRWIw >fJ}F {}z>tpV:wܫԤ+]AiݏR#o_yκ륇ʑWϾ8>|jnRw[2v*VDn3mAT͊%vw X67}MShSqVlmᑧ/2f8xp? *3ʠ9?5Y.0E;a{j-X^FuTu.]u6G^ޚ]q<'uC&[q˽u `J^)"5-L)=_ hJ+ߕ'Nرsg??n|@lРn̼76R ]ҬS}JZx| B^TN9SXNSn+YTf#-ɉ;Nuᚑ]5i?ݾhW'ui?߰bfTGȵ=*޳<)b7o}G =0hϞrڷk*a~}O/u};;"zXPլ嘤i9ɹ)5]iC}[͛evPZ^<){~+Ȳ&(tnf S3EO3tTw>^wgN soڀ +ٮl8Egӻm۝:}Z*s}q\X7 )*oIXR^wc˗.y2lD]t/ ZiI#R|?bizxa]6ounݺuZffւ 6snݶnΥ+7h`qC܋G:o7F7PAJ iOxƴիٵk<+tۧ}Mg80(PNf͚ɅDuU+MM7 sϭ^X9 u^.Mb*o!Qya$ `hl,{o t]>ꮁ+ri:uHA|cǶRwBqMZ"# ԩ5+$Gl'> dLK-Yj];wHb~~]+c44Ӥ'bci^ c4T >m2og@liç䄈紣cLWxP.wf*_гga#N>} _LߕZI‰W/_uvq6m\uG=9GWGےBte2:1w2X9eIYݒw;%,2\?H}3ArSjˍ%ețҶzyŅkfg$;o67;+ҿd3ZܟU29*b0LW.]f1r=) F=)ܚ%d%4qo" x = n4~ 6>9j\_=0]pߐ 0aք,LF_*$&';wzʒ^{v]0sQߛzc?c͛tM_~6>mӘӠA(gw EgfE2{lƪ;S^1eU1`@1O?-?]H%ztݿ9jw3FϐN>JɧeK׫WO*=a YG<2MN>lI?i?''/.5+PڵkϏ@.KI?-'#gfL9XH߰ÅgqIaQ#{[͊u`O"Ѧ>AƖ T*)k _Ё 9ܑY*;g}P6um;d6m0:~!+$~x}\zm Ynn/Lvvޜowz0˒ş5lP*9y9\x Y)Y1_ɩѯ ѽ\Hfq#SbäIQҶKZJ9w`}һK^;uժ @ʅIeիؑİa?,Q܄Y~Xc䘻 l2xhp>]Fkڲp4[2l#yfL)iC0'w\v{dZyٳR!MYamf0{Uǧ}nӦʓRMzt}}՗?"խ[79w¬>eÆDѮ\TU WI e\~]ԪUΝ;OyfݺuYȴ.c_NILM ;9  ??{Wa#_=şGO{Mhw +8p[:sneg6i2cQ/IXƻmSOK;v(,`G{d#7o~`'8E篴'O޷ ƍ'GEm߲aaOҬY3%,Ӿ]U +KzQz?=򴟰j;i]&L\s)_ QPPж\>uR)ލ'`UfI I9QaOp WCu+`# +W XԞ +WÆ `.2/z[nwU9wuʟ'wN0n=>l<95՞X@UٸW.]p?gMOOAzhѢ5ܸq߀~ %q`~~m۷ض=e}RnԂ6$ ԠASM]rEc_~A.8FT'uC#hڤɇUvO22|嗫W'=wNwppdSOvvv>B*E@d% (?@ J@P2d% (?@ J@P2@U\\,88J@P2d% (?@ J@P2d% (?@ J@P2)gIDATd% (?@ J@P22bnJ7.W !TUJdZגƹT㒊]wZ,:M&}C"g)#sT (\,EFQRWsA7zaaί+}2rY3IŒ\t-aܠ_y篪Ϗ\_!*)W%@RjJoPQlIT7mqB˽Dʹ &Evqwvs&`qw,lW^F䲔q!^N%+t,] j*h~ʿ\ީ W3cEfkȤ] œoZvb]ࠬµbi[b׹!BSw,35jt )1%+Iy}&IT.34^eEu=ak Qr; 鹺t [m +#g܈kOȍ;c٫Ro/j5?).ڷ"e#Oz|,ҭ2e5į1 *"38iﱗ[)HNSҲ.eԔ.|Wyos|uw7LG@ѬH;T\ַܔ vLj]9-(rR Nq2v?}bO%s+قό9an5LQ%qؐ{5-(wg3˥__-6 !T(]B#=7.^бZ˸q[:'.51q)|5.H،[}HCɩw#jH2wF|:׸5E4s$Dž>z1 Aa ZQnFR/'J+,%D4&nYvgXEe¾YS3C`t% CI}\5訊+]Bh@DABXBuHw! 4@UWIO2=K.O,0t@I;*~ߥ'ǹN3b|fmFBXɽ Mnk񡁓~`-P^Yϟ{䚂K_ӼdM#unW;}`w6o7_j.f6?{I72d% (?@ J@P2d% (?@ J@P2d% (?@ JPiʥ `%  l>d% (?@ J@P2d% (?@ J@P2d% (?@ J@PZ&4ф#JmZ O}_'_\_Xqr*Xtْ\iҳu!mb`5 2i i:u0Oil#̱K&;DS+ށTNldƎ/Y m7 K)QHOʤɤIiN1E/JT !X5]|7s~R;:d YoߤW/fd,¿ ԜBSSz.~R%*K(#S.q[]Q@>^6A1vJԌiMH=8*d C^J]1˘:}iv JUw8%yg 1r%3a?[ k1\J^ϨĢ/OݳpHU\\wK8aXp 8l$OiU`K/7/Ϧ՟9Ú3W@)۶Tq墔qIgDꗭe*SUnҤ]7x;w|O8qB4a_0L>y\*=N9?;硶m1LP9dRv @׺u+@q׫si\nn]7khX.^xCN<7ia2'|ʗ+5l8tphÆ 72[s̟嫁R}떷3dPڭ[6oٚ;Y^E~=RԩCP8R[V޶=ҥKriG.:|DP8R//?['ڶ  jG  ܹsƑ2W] PA Ο0P2vssiqzj,=n"FMc5.ҕub2@51}:۷k\r𛑕y0_~ۿR6ӣ>RZT.q_H7G*..ֻʥ μ'ޘm*ǎ:tˣ\J8'++//_7}F *gF >_^~}ݤGVCѣҜ%m:Rhǎ|cƹ-={ȓY{?tRTom\Y:1A|W.ؙ&3g^?N˭l)`}egKJu5gg'8&{UF9[MJOw}#Æ7mҤQFzv-Yǎ)m[ua@~?]: /qrA]tϛV&j0\QW)I.GN\y1i?X{kwpx%Bqݺ#@YKXZ~؟7o:L?MVZk;̝{mJq>?n`iQg}OTTyjѝV&Tcyѣ6n*@ g_Ok?[ҬSŴiһqxWZBۤ 䙆YEc=݊BbglcKo %1$ӢZkgiimفo~ߦHeubof~Z/& yOɷn8]ڴ!u4=E!"E%O5j(&w'g꿞.Gaa\ԳS%UZ^0@.EP~!+>\)ĕ$$}?S3noRZKbq՞ _I˰pO#o[AIРi+?%HNݪj+nƑi>U:fN,y)H{siflѻhΜ9RuV-{NjҳWs_M u¯VUŋ*ygI^f8C~1-MWwf'Xf[埽̦>oH`M*k//\KZVQ'X+M;iwbMbZԉ<O]-zQ0hg[~osS.&e;y{nPw|m^66-RzGҊ̆}۲TDusjcKЭ\(((al8|`oܸqjֳ#@ ~M?41?dOuNo6v@Ήk$䶼>i-:L-fc_פ$V ꅼ}w^V3ę]-\MO#-{o|רsSϣ^g%-Tgb464熞X5RKjiϙbUIC/We/hP5oGl%X-%5_44B'߻K%>7fՖc6ׂ.#[mV({paF;@O#,NkJuB6|[_zΒ[UVSxw*hjjJwXj1Q'R7)c )陳aBxy]B%]DnۺiFo7浈)+^*ojf{VSOI!i e6~)y.'ݵ>s AbψRcjN&'q7[Qwm4)i/,BҖW\ǔt䦌'D #aŢ3uc]jq!oL6u cumy=wrrӥrӤ4]/ir7çS֚wĻ}&-VN 6Xw&tv~]%ܣ+*yv]7ԆrAoݶݩӧ=wn_Y5@Oru>=o:!HR&/(zM^ # ܪDa+ '%0]f; 2$J=Hf<4*|EuYÜ%m놝~O^ NnV>t4_ygڂSWUwsl w{yY+%%1ݵ`j;%-.ԯS7`)16ucozt4-OQiwĂ4jIk57hS&;=u 2ݺvUqqW.]f1r<3F4HM+N5I&>)iSR[BVB&.&κ *ږg Ό0R%7OVy%tg&/cBk>r>{Ν9w }v}~m%3;.??;Nߢ;J&@4>O="*G97|_lބ'qˆ@w5V\Ǟ} 2k_D'_6c[ʫ0NwHТYTV*~a:¾{_ŰƊ'hm۶;vDC=d&nmJg |@ҷy'U P*D<ȶmqܱz%j‰PVuuu)t1?T{4~g>U۷o>p@B i{dǎ}٧n /W_:Ͼ ЙSo}Iۺuk57SO>˞裏)^:1l9_.kǟ0n\غG/muo N:bH^LSģ=/Ɗ@tؿt'>C\w=_YYneW'+yYYYxNhm}Q#Gfgw;Må,{jET8~&]+tC[nyS_dСztM޽㮻套z뭿-8o߾詶o^eO9C toC Y̳ϭ]~ȼׯzW_{W_[Ԋ6oN azH>zti>6/=|yڻﹷ&/]T#j8W>w.u6)#~u;ݫWw)tE >[_~[oYYY Y-,&6qx:C :Sd н֍u$?ā@q 8@H $?ā@q 8@H iq 8@H $?ā@q 8@H $?ā@q 8@H $?ā@q 8bnKԜ%UmcݼܬyT,BWQ<9'MrDV*o[XbQaKvn̅+ۜxЭž_zMkٴ+,grIud@WBS"w0//Jn=H8cDψ]κ7<ܴ>wX^N*fsiteĉ>-o䴣]&G=D/瀑Ӣ]55dk\wE^MyK;FʴKݍ=wI2dܺigOLƾYW:wbn^89dDrZhGdCw=(qncƜ,3daܹ:\o 3wbv5К[4/oE3s/_&- RŢd[E?쉋7$yMliG[s-K6;o^av sgܔlfnQ*(.z ookӳ'.,:ʆ\d"ً Z43y;=KuzG,ذ 7T_e%VZYl ҍ.XҰ{ܣpR* R֕&7|t#s 49y[گ4ȟ[RVΝ 5D6qFK39n7;,tu֖G)Y{OϞ[֖yj{zNU˩j*9,923w3sC3)]h=9T6"w4'Iv>WDmn^rҲt$ղ2? |XQQfꕥ!.?\2cac)t_mRHUʪ'OM&X̙6o r4JjÎ4l_7s)75._v~~9ىzg{gL-i|LJfBߚ119$oԡ3oeVϝWQ紳~)Q3rcܼ U$-+9*î*0&ܩ WT[pj*N+HXox~YYY +Brf,!ixJbc;FP4u][*JgO.,L퇂œ6qZy}dvHt'-_Eɩ_7rX݆&;obYwlm~u]~8H?ΕU]]̨ygݑ>;7K&Kqѓ%ï]Q>;gQsm tE9+掼lMr‚Dל(S:i(+3gDżH,T͞8tM3rknWѮ-mNoI J6-{n..71Jgf]NulFTz(?Љ:_fxICk8hĩx#N-ظbSG X?Z;-IDATnzx&_SzI#m8h7We^vܲsI-7T~{'} bH/>rⵛ~5St3UomyҼ9b?B?qIIΰeQ>ޛ(wJ&g:Y|dΚ+-:>P e9;weiq>]FUndcoXY637>~O BN2w쌉w?ā@q 8@H $?ā@q 8@H $?fz}[@q 8@H $?ā@q 8@H $?ā@q 8@H $?āWpnZtqNS mdZ!롎C[慥C۬S;FpܑC yhʀڶN.YǦq}inr/3ŻήYB}7[촇nÚU1G:L_ v٘U%>4eZHĤܝ_5^ulԒZoONU]]vm =վ Эh׃yvëNջ”'?q\~Ǟ({27C9C :dr!`ϑ$YY>x߳%G?i? =F}:dps<__-]< ׳uƪM|);oFފS+V}֙8@>t;8[Ԋ{7@'{8Fwl $t;[c?m۶>Ldg#?>\~Qa  SN=%۽kov]<*1hСk|v`/6mz7U1Gv~!hO^~vC98Uxw"j$]>߾}{]$?_Q06?z*4jMSO%'ӇDo/_]CCW]!ɤO_zۻw_us:4x1S9;D nE7.w\CScECecVW649pZHEiH:=*;y_ZpQ]~)UϹC^xaAiE}fN-G k7o.L[zmI M'C늉G_\}U+j&.}!1tՑ>&z%wQN^CÃs.{sjBs׋5|ޱvrfX_mA*/I?Θ#λRkH+ oĠ/(ug@S#KЋnՏנgIm/,=G o_6hwm6sWcO5zܘv2ڍX:+hOi5Q_l0>}G-}ypZM rkӇSAo Ƭ0\l:6GYȳÏҴJ2| nLA-T3=2.:in{5=4eII ~oÆGǂ >aͪg=+ aMoG];կ|ikµw1.K 9=&<=v _.N5ozg61,6mޚ9z(:ϟnvДQ/QNfo֌jÍ҂:j?T{43uWw}[moxeOuk]#9-Ly¸=|+ ?85rלޝNɉK`h?{#=܎{^~ſT”qW^vG8 !9Ъn{gΜs Trh2:_uFÜQKF33am҉R'ʞ\>A zQ=Ï,D/۶m+}O;vQNΠ!SYz_=:@awQ+Ãy6Uӧϧ>ˉvXލޚ^|lٚ8t௞svhvgn+// 6vzѡyz7 9O3ZCY@z^j*0+gul@'..y=LFSNf֭}{8d5#w.K/ pکNkN3۾mk蒲>OӧwQ~kr_h`O 8 ;:Cj&wt({עƠC9Ne‰C{}V_1>8|!C^{twwg.¸MU+/Oy٧>Йsko_.Йox嵿&[^cL/++k-eX;uv='&ӟ/_nuևuÆ2z肓N\IKzS#߿dxݪo(: 0z#>xoSbyW~}F+IDAT ||z{.w ?7􋜜yoׯΝ?Fc%4J:zE컿[`t|\;7UٙmYo۶ſttnn;Y7.Q2r?ɏϝ4)d.͛l޼9'gPP zNӱ6ĺvI=o;@wmZm)ؖR̐yɯn]P}O>r'>~w-˯ӏ?}w xƌhn ۥmyޖeB6:ktmygP߿_!{c W}Lw깧2+λh/>#.F=W^zyeyX}G'!DӿqK?+uk=? ]z??H?ι /.q^k=s [o}ݿM>{CKMyĎ5+!%QaAO顽afͼк۶v|Q2TkFFg%%B'wT.=FۯC__/I, kti.?tGL ~ţzI?#F?䖖] ubUMuʗvliws/=ylh(&Y7g瞐6k})U9g/WaOOz?l:'lY5g$#DGW/ʰ{_{AbT<燚FAn/m]a[Ʀyd?c?'N}á*K?Sm͊5BΠA!&柑5kBd3rpɥYfrKgtљm|2ztQ7œJQb.|iǵ$R zKX;N}.TaWi,L^E|3!F*=r]]TAh~AD?CψR4zHAAR θ&Rp=7(kt^ҭ}[Ei_фu}\}_#(#,4B,jWAh!Cg~^{ O>/#]?g 紉ݢQW}jzts&BkaYq/-/R%@ļL:%*TWW_qUoI$d͊7/|y|OB(:#~~?&{ <<B|;!s',Zz'f4Sxgev*9CG U\5:!v;e2@ѝzlnӿ~zdzϿMooJ=W(fF&wOlN+Q]]_R'SO9;p_DMomo˝79#'gyCzT NwH'5:NEEeп뼳 tG]WJDFuWYvOs̵?s!soUx?zT`TT$ ɟzfwW>?uCr˗>yםY3}+DksC"uAb꒿rrBGSN1G=稰jSMz7ּb<#UuGN8:uw @=;%puԡbkSO}򓝺+*֯ߐ?@l۶Fѡ:dphQ=ѹ{3VN_O =@|G=Qv.rNӔ<7o>}L piUm t 'z]@C,k䭷pLJl-t¸#M2V9 ;;U"_chш}|͇~UaPkΜ9iGl߶5tywǞ(۰;vd/tCSk-]QqolS/O}_xJr!_.?瞯|ͷkГ|oh}ަ@ʫ.ex0BLJ@ >:(*|Áe `OVވR/쉲@[!y#~xew>tMwu3>{{S+>qyw6[7$oq{:Boy>[慺QzΗ {nGs}~+;J=|yڻﹷy6,J-r!MJ>}ݜnGモrߩb?:^{5fhR aȑ_eY!+Ӊ`5rGyd7!zHCot;@H $?ā@q 8@H $?ā@q 8@dUWW@q 8@H $?ā@ iQIDATq 8@H $?ā@q 8@H $?ā@q+t-%SsrTNйK3EUPy² :w=uJo[Bgܥ@>mj™9Rs +.^x '&'9;Nj$h]4YAR Λ|Ӕ}4z"gx;=y3g=pISnXx6tur`@'8VJIvYsѣeA?#U%SsO2YaeXz,[YdQɺZܒS;cZzw?ā@q 8@H $?ā@q 8@H $?f whq 8@H $?ā@q 8@H $?ā@q 8O@v .lċ6ڹBچe-;ӣK]$*L?g4[~߲e&nכossQ:_6iX:> $?āWΒK/]ɳt=v_#;KC1KڳkȪN;6v? ; ?dIƦ,^t[]?>2蕝]xK=#Oߧ׏L%8+;rhdjxig,0~sȹz}Wnכosss.lw6\P:hF&Ω>}òeNFk) f *`g2 p3_y_ruQԷL3(=o~2\]TYpK,T{*n)+KkpU5{6zfԨޡhtVQQMouF@CnUӁu}7o>/_Tav~;w_ԖGS &Ksŵgr>6۰:wR-ف__\R^{ݶֳ kڹ<ЩYo_2.;aܸ~߻t⩧m}5!\y_9MD+BNa*FK7!RXKҊGgtљv_T7M/:c~Dn|wݹg7t}|߼º @w͒_jϘsrr2]HUQ+z㯿w 'hxsd _sLߐ_Z.(;^Zʰ雷N>^XZY{M%sozꮄےkL\pJw$m—nm7?=䐨u_Gt۷5?HG̻n{4~_uK <5g6̒n}):ɧ]{}c~y/:+Q//_oqZTׯ,XyGry瞛*[Sw _<8"A;*Xrƍn;%+WL?@1>S+VUVV c8z?6U|= f{lީJFhaYKo24aa t|wEtFT(//?cg͚R8 dG @GN}z衩ªիURAnu#y٨jꯝxVeӦMjaG, dbͯo?W*@[t>Sw{^{ЁvAO]9eի׷/ggN<@&3XOn'=IuIDAT>ڢw?ā@q 8@H $?ā@q 8@H $?ts@H $?ā@q 8@H $?ā@q 8@H $?ā@q 8@H zdjNVVԒ :w]IRv]g$n etһNsKLl)} gʅ3 rsedLW\49;q*NLNrwH~ѺbeIѲX̅+.<zNy%uOxrNr '祦̎&msvjDNἲkV_GdmkҊRz'*{Z~si bn^̓(6큭-,lMkf {X25ۚf6[޹}N]PmX";#nXrL^7s⒟_pS3RhߖESS߈o-~ 7X0ex-,zڢ/7unʊ-՛ٸq7:uxjӳ疅Y9;_OOw6W'%w]WpR0t-(9,dSr(?+++gfm/;'gXsKʟHs[̕7duo ka/ZC-U-ؖLJ_7y^yXڴ 䯼?+8{[Kf^X(41\y[X{#-UVϛ_ŠhȰ5((ZliNԦߟKΟYTU.7sb^v"ҜZҞ{ vC[ IY͏-u͏4MG+?'K愪-g|5+DLR^41G64֜kϿ4.YSG=~ymZxT,*v[w^E9+掼lM!-VM7xZ❊_d،wi҈AU2eM?&ʞp74pϊZҖG(MSN>hċWl\:>mYrmRh=@'8@H $?ā@q 8@H $?ā@q 8@H $?ā@ql{@wL@H $?ā@q 8@H $?ā@q 8@H b{]dժ^yeƍN^|#F7t} SeUWW{BwK/pFt0~K='?W?`:S;۶m5)b?QN_ezۼy_<}R~;9c8G`7Ͻ_~wKJRkzV5'p(iddǎ/jxcTRÏ3>m%^/ږL:[ƍ- խ/"Jr߾},YQyux.Г'ߧ O|]?~R+Vnܸ1@צ2E]"->SR序x=V+WL?c .ln>}gQ+N?찐\;׺%2E]"-LnUFӏ=}QaEGc=Vo@6z5.l\YzM e:DZ*;槜* H]g6?Mnڟ#7ؾ}{]%h?=%K„?;a|Fc㓿s^* 4)U/ nכosshc3<9h5'p(idjtV;ٯ_:7ˏ=.>ņD+o" R_]~^c &}>&k;CSUW؞QKb)u.-nE~?@צ2E]"-L*Z%aK@qH*++qG|旾kɩ4@צ2E]"-Lw5qgq/@{K@>裏S6EGm.o?cpO~tmjlO(Q%R1)'|tnnTx󭷾1.uz'R{ϳB1Yɿ{’KF矵gVN 9O<1*Dc~'53jNYag%ZWM]8u.[1V?:+%.eקQTYm߾=@zJ]zg״WϨ IqKG˛oI=dw]7p:}òef +q羭iCGP=d}6jIDAT|ׄ=dw7QbI?su֭'jg~Ϣ ۲έMN;`bWU\8&V\7Kx2?a&SḳIw_͟1qh2?tݼnY__V=#M6{iGp kwv_wi}W2{}S_0:6$Fθ^u?-=㚨4<RK:.թ~gZ[pktFS]Rػɘ%.[7~O<ɟk֤F5a]y_4gFG B7h;K N|작D<꾎&Tg\'w\?[~Yjcǎ􆑣{7nvU5*no{IvQƄPxK1/xۼέW޷z}kIwnA[6o W69͜0[|ysv;(G'[ 0xF*0N73xvhǡ$ӑv]Z9ɴb8rň_NخOMu׽WxH..~|qsZ`<7[o:39G ʤseO>m۶ =qܻe5!zFR+5U o.h2ԂΫK!Muԟ୨75vg@6v? ; ?߰ 2dÆ 7%Rlalig;?FV+kDW5էY2r![Tru;CfRI=ۜgK~|yM'P;}Y_Ky&ߕD}]Zk^i7; i;?5ϰf`ƒKsמzsn-?}{iML^> d93(e^ |LTgƻE]JN'$f/2//\v~Hn?}7Nٿ\krSslF߱4|jM7U>Ie~"M{hw=f_q쐹}שF%^5WjyUm+n?kG5[U_Glj&/Wnɵ:mE=$?Z;a 5F]$.k~zpɞ1ߗ\NM5RQj$Wtfawַ4ꝯm].QM\W(j~$ꃣgL#zV_b(]^uKA( +Hk5^5W˜Nʫvi/|G9_ nɥ_ 9W]?2ydE l6Q#Vw%y@S䧩6QzWSVZ~a}3yֺV +u`_'z}5Dذ緽 pM/6Wc,_bJQӮn=ajxuYvDٝڂW9 ?3SV7qmu{40m]uK(ylwE9+.|-INᕡ3jCj+ν/mM˼9͝1Z84=k-1R; b]jGH}Y|mM4;d^1%"piGňIf䨃K~$tE5˷ޣFҫR yoW%Bs=evhw»yW%pl~]Wq-}TWW}ߘ:mqM`w}뿮{A:5gD!A/~mdhڬ]._''.]\Hβ8$.f_`9r.hҍmץp_]g%@JI۸u Y+6-AZ=$'KΧ5^!9ˉz gCsK'-TNДMVdɎB> R='յcwsuD'>joSj]~v*ѻov}{<% FnC?6 L~ mC9m{ J=ٝsVwSlЙFS#s>ßߏ?W5uԑG޹ȷ.?&w][Wp{pݧ |Ro#W&dW4Ym[c!H}_rYH.YcgfD]j'wl5gt_68dJ%PH-`PnKD~[np1QKR-rR-Z9 XsF3='$B_h㌑[g=ԎWu_7.iuIEQ]ѻw\v~VWwk#Iy32`ʿkt-f:_^z餿_opx^}E=?w 'T{U|UE}VڧU"2/T|~oYM}ӮPt3w]5WnIѩ-*r@t[C;v釳ctik=TRF;nUӁu}yiiy+Ĵ= 5z>=BݏzimLr]'ڡv-~adKZtdkCW-6=s/w⒒:s-3M7"?-sxкDě^T30=W=ķ}kdu=$>PWG]G-KFWځ5OzjlK|7yն^.EyV9z;]֥rj% ?v9ɗM ran y4[kO+.mqvru)+wsoL/f w(x%Q7n5D_v;M{?wI'_0?D䷥G;vrªU~Q裏n{>p}iSКL>^8K.]R"k>Q:D=u2I1؁uP>juڷvjx w*LW6ٺ>o H]wvʴ/qͯeeg(P'.Z kXrE-`-9ppnmlXQ^sFS&vW۷=e4盕hv_p~߼˟ #~\qub7&{M^Y;#<ɦ il"Q&~RmĶ7h|Z誱vF'sw2s'CZjSITJQZUso;_) H6jPrLJQs_+κt[ݰZGeެ1jMkϼb$wMKY^T{M6lMO25졊O2F! }hB̵_g~-Yk{~QMՠV9IDAT8{ǢʓKLfs7NwNHͶWMmKJ%jHXRfh)Rct.ZoE53٥m];̤}%/ 5=Ԭ3dC+ʺ縧ZqጋR(ؾ?sߏo_@Vs)K˭xe-ܚƷ.'=k&͍k~ WW_rUs-W_(;\*o ?&O ꧯߺdvo5]Ue5-v9t/,RFiW94wぉ~';nEמ^}~Gg{/oDO}+/+u˅ι04 or6zΙo޻'&4fn2_wߢ<V[~׵+l0᪆wO>?j'W*WWc. {jۻrMhz¬cvfhQKb<{59`jpoXSE/>TFCO3Ilܛ~iu\M޼yԊvXFS֥:Qc;\WMIPo tyieMwG:޻bbt]4v ~,{Š+C.uZaV?ʞsGQw%%W^åQ@Rc;\W/t{^e"btdF^ :رǧ =jY]x=.Þ~*;UVV c@]}/o׽;PݽaO5jT˯BW}:8tuT 222// ?7xc{whPog>:ԄS_EL]A'W]?> u=CW2E]"-z7>c=6@K۳>*|{_]A^zhj]8tuT 2Q%bURAKM<*7U~}kЅ=LGQHK S3. ߾^%jӦM<4U~5uo޽WU_Q([yHAAbIE3CqEo;bc֖tS δ[c}B+[ 5EQ@9; I! IH=:k>묃woZ@g2Zff1ݛ{ )Q%e`V|qa{6v0HU==mܸ]@pOތOb,,69{ҤYyo]j`%R#%И_43ByΘy{Nн2XYmrq91?@Kիț؟ə{@c???;Lر#@we|tcfY&|^TX}Ƅg]%Rƶm۾y?O[oEO32 9x޼yx={8t~ >_?K{6;=] #@SK4>鳖=VR ޽js_CZ>vhc^zw'w]9Ek_w=:@N@gJ2ᄑ%wݻ#g?䄞Й >'{s -ʽ ~@0Utɒb9i_Gz8sI +=RRRRRRRRRRRRRRRRAZMMMz8s H H H H H H H H H H H H H H H H H H H H H H H H H zESҚ^z螳 [}FFh{q^fZZf^qumy@sUMLkVzfV셫:%IqEOE*,)p1 UK,*w4}ߎup#3,EӋk,zP]yW/~jGm͖h\8bu)~9 z=y@3e.׆Pmۼvʪ̞^l_皲M =Cs3W?y@3y_zF֔ҵO[*mQs4X1sf#E'ɪ?!=s W/MK˜?n//YT0;̌]K&nb)tMW贶\s}\µ4NBzzgKL?kʐ^mX\rK}x♧_}w}w1\[9LAቿm\s%$zܵk[xzV|€yuҐ5h4!9If&Θtk]pAUwOx2av~eT%G|ѓ/iCvA'ꩱ۶n1prEqᏓk^PpJFeM9dGVop}eDSAv萋w~}Uܦ]1eQUɊ;햻 ߸kg[UEvakwM+Qŷ\}ΘcK+wh4.O?ZꪊH%JIMaǏ?#/M]PQwrNvs &}\p{eIa^NVfƮIϜ`N7;+.ޑV)ɿ). ]&cJAyͶ3'/=:<| :Npa=Τ!CB'^^8%G4Q%NxǪ/.{ᬜcvA+W-;}ZʟW߮=^$$/31ԋUVvfiI+]*7;9WM݃촴ŠF陣/M#6sN6nsq:Mg%w)Ɋ)yqn-sUEͮX]2k!RT,O{Ҋ9CvcKi}x]ّLf Ӈ.PQ\Ty$v_E5#w6߶ԋ7 Aڞm./2uQEٵyONnD+K̞2:5[f^qݺ X|a֔wD)YqZ=UҎ$3sHU%KV**u NᰮFﵤpvNfof˜0۳j}{媅ѧts''/Lꇧg&>Ӻ1~v5i9qUQ~IcrVC<|ۢS/NVSS\}e.jW-]U8%a6bkhWKvP%F'=p='W.rL`='['VъTD_5&e>ݿjQnm  9=tkWd&TΝr-рɷʊ'U.r;n ZEAZ5hEaЫԥcޚ^Ok-+}1*ʞ{z0gyifޮn~(y-6K)}0| VnhEҳfT3&л 2f, mlfFtbc:)BG9^;wy܉&-~g뒩 n9_:)$te/Qx~I{3BY]3d}33$/&ᮖ6[NlG*$tvׄg,wV??ɉ{f0nM2]4 L[_amշyjӜo fG꼻Rmm? z5ͼ,,kޯ׌;i -G[_V;ɯָ4 #=Ӱ^'הE'~lT~n'3JF$$<1zS}?=q6vjTc5NƇ~x>}>vqCr!N&I&Z6=INvB3vܹ#3,4o>@gm}UUv֙gd?-4g˖7oش| #?)gO pnKG,%^z9._9g;w|'yve_4d@O&n>|}wRVQGZԫWLPh۷Džvx\ޜ7nƉo}] E'o,٩m6Vx6~گ~uԨC~к_|իmUWo'|_֮M=Qa[%(ᄑ%@^z9. xlsD/NdiqqOdffد^~噗_=w=?KKK mąmvg:MY֊4?=5f-Rƫ*~Z|:t~1oN价t'?.W^ `AzҽDcr]wzQyÆ.[ND ]<.,FN+ʿuS-veXճ~}77>&]/7w\Qe# [5KM{AAt+6}%Q7][4emӺqKi4&g>?F6[Y&8HH/BԲxŨ59vee~#5de{A̋b<<]+ fN]^f0"O(;1j$M]nڡ;iAuu]6vd1BƑ% uqn3bAmKŁGظ7K;?|nJvFWF_z9I#F/tET`㦗SKXr.BFm_?6dO2~R7)tZa?~wxb^)9M}b?/VU_'#+o3{ͷD//}'gr X7Q!kÿ + m7vy'$k~P|5!睚(?Tۇ_SO d4qPɢ4k𠁁Dh\x? E.I!ދ~Ν;<`w=~M/?eȐAGyTFvY֬ٸqS}͉NݹhC+5S\>CO8cc =oGkoWFy^:eOʶ0/@VܱcG޽xlfâ?6D5_ss'RTtPD} <ГK:8k™K\H>{V|@q=>~_HQiiig9?}/8C9ϟ?q-[q'=lc?λ޻/Zgo|yyT~gkܩD>=7xsРcO8IM/׿c?@[L8KKK۶ma.BTgӓ/ƞ2O>Mh qO=~Nh=~ȣÊ+*6n:СC4v؜?31'j]y!{WW߇NaCE(y~? j9@:>7o֣-۲eK\9hٴ/N tWU{翌jG"_ӯϙD˘߻dڴvћݶmm23yu㓿{wo߾-4{p66tAmM3VDžeE A\h0ܵ饳/i8lq<.ܾmz^zިf֭W\yճ+V~moQ\ؗ#^G_{f͚#Gb^zjž[]u$?C oN rp失'EɗL>{߼U/UE?*,<WϺ*s|c]q  Hf꓿SO9%tŹ7S\=a5;)i"z{3O^97n cƌ W ݞq8$UUU-Z8._χrӿ[\ӯOG?"t~G^>O=_н'%Ӿ85~E.X?~oBx󭷖۾q1Gяqynٲ%C=i҈ƛo}e5552JOJ <6~^~9~AcǦE Twc{_2t1iiiK,]Z6?;/_>D>`ioGz|o̹!tW9p@9V\y}_#{'AmAƞuŦgAtgj50tN7yGמU 埞 ןg]S7;k„k 쳝8qPf̭;fVF <0P9{=]8(юgM鬖fy+ 珽PM8+&×v1.A\yaE3/8p3B:VOBb-Csfxa|9w층63u^9:!ƞzxȐ!kh =Rsf[N˯^Q{{f¸w݃]A :@] ڴiQW&|{ƍ 3|m>6M$Bҽ7qꈸp,=[XMhG>ti{筹r G}x챮ONm}iT^aRIOZ3//܁a|c9oܘ}}k[Kk&|z7 sH0IDAT352!AmMW WJF)u8W>73kC=UF}bSMޡ1V(3ZГV>βWW=h6^+nʽʢ Qv*Y &eT?Ϲr31Ʊcouh[{[+=U.-MƢQZ{ ^1vj?'bƒoYϩdޔuj8P|M3SB||}ev?jq~ƢgYL}O@ջW/;і}9InծVW0 rI.]2 w<201w硰Wc"3^_K;  YG'mf{8øЎ:x#1A涾>uW2zꩽ®EY].uIY{ lZ#5m6Vx6~گ~uԨC=zj7f‹Ͽ8~O _z»~:Ē{^ozK\sڸq=;,|y-RLOZíWzo+lI sC4v;CIk?&xZ:%:)΢+t \}ʺ( JL 0zXb E% GyNJlm^>w`.KLKcqB/&>G|(q'pU՚1>;W<7~ɓxbb>~~OSԍY?khu+ŅB7ssL?шk.+1vٲ ~.ё|8RIOZswab]kOʳϊ{ܔƒĎz7=wŦYEiW;+o+Сqᶞ!cf3޿[9otKjE%F{(aio/==,hO~fEDy7hGגv~oTO)._63MqHy»aCo- =\Ugc{c?J.ܩ+mlr=vc _JweV^ЌP\8s;nh|㷎:Ȩ!߸_㗖wo/΍c}7~!k)ώGq9}+ivߘ[wtݒ^X=߻1լZ*.vi|䨣MM:b;/tz߿[ު]Rܙб:~ʺQףCGsŦgR2kYUUU\ڸq&}W5?~__Ə9kGAw>sѣ?|}uLĐzX?6]z-8@t|O7mіMYIoش{ѽK/Mm$om]pѻ۷o٦"7_~vs~OO)zΗ_9m[oŅuTԏ_=t'@ݺuk0[[ tg}66>x2.sxh^~9|qWf꒿mODB2{7|[օ.ɓN;ٿLh7߬MD:@'HO?Bw83[ tguE~cx\P1gOZQԒ{]|х3}SWy!#H@r챟 9@RgwVͷZ[^;NM_IO=n};sLpA^{u_Ç mg__^8[ %g qzСCL"oi|?][SSb?>|Gd /!~d;,~cyg>ctAQv!^Z\UZF_c2#Byso_pGqD}}ދ |pތsz>S&O:Ȍ'K;v!QW^M񜞞]bpGąmv79@蠃2%w\`je |c ׬kɉiii!Uzn tV | qDG?zQy?=ͷ6G`iXzС}qj`3fz/_Gyszuu=h<ӧ_߾~'p!zSN ݘqDZMMM}{KS4=$|z~ftUUU;:~q>С:pO@#Wٓ&ʊ o]Ň~~O<@![O<97tu7<|y?nTB@  ?*,>c³Ϯ .+Fԏu==;;Уֺw}~-ӿ45{={rs9(ʘ1zhV۱cNJg--}KTЃz >)>mu7Q!GqD`~̫Q df:+\}YތEO|<--mԧ>vsWꦗ^ڴ饿j\mϞw@6|yN~LVc23/ᄑ%4vxT T T T T T T T T T T T T T T T TVSSΜ?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?HI)i L/]tvfZY:9 9Ӌk"K]PYSk:9 WY4}m2U&Xz% fOQ(sJ M/+W->:`{Eqљ鵯U-5ϫ{ĭg^r^._^3r Kf, U:t_EAkRם8S2Z:8/󰪪g>wCW_jvVh93ҠfK^.\lҹSN=Ùc~8sd}زѻ{dyݢyte.JlK 罧-VS(73$;?:UCܳ-jhztlHv΀jݼ-ݶ .UV=}^iWI^{[jc3_f/u%*挈c%nՕ_0楳jc?jmGOL{X7l_^S>qnۼTT@9$5ZrHϙpZ[vA"˫,Y8{JVF\WX01QR\ZfUK7W,JyڬzQG-O^.q+g/s0N'SQ2;'}''7Rt$!csvnEnIetZʒ¼̌zkwkM7;c²Uq2܉**JKwĥ>&m7cw%eyߜf7 g>-ry㓅Gϛ@9Zn//<3W躪-w4|dv2óYWN62oQuIʘk'+pUemdx Ņs IOKK.m09q #',1-2@H j1ı_- G"}=E3ê17kiZ-*厾䁪5YZvyuA._==oa8~Dtv?ˍ vyeAviݜ&k.ʚ]yk'_Wɓ{ szQe|Czﺡi6?S +U];GnneTrAyöBX|?H?H?Hn8/3mҳ P}W6;*,p _vތmz5eHIZMMMz^$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ @޷.gBX63O˖ЕZs.tR*]Z7)3oӺq'=}xFq3f/#zѦ *7vjFSǍjNLqmmG7l`K>Cvyʟ$w._%w;Q=V_և0++L}!\h ?5:n=,>=z\vZLexe_p >Wd԰Hi|~6Kxw֗aHoټ7%/k~Zi]V_;/$cqo;19i/]l?nZ7n;!t{gCCۇn_#oyϸlxq '$ /]W{];@ws6>f QW6pYֻ&]siY>u:Gˆƌ[ܨ~Փ/na) Ѝ4{ݷh;vx=WKN8=8} <ؓO53?yzh?@s6nzi /ZYNg}OX^RcQ˕;5|OիeeWYQS_sx555Mz;Q'wrʘEN^zeͷ 쳚ݶ-zD $ǝzJ ލ/q{B(7/7~C @yg^~˗O;,---(`8x޼yx[ UUE]:틣F}A޽w!cF޼ys-Q3?̚u»|R _-ϬX=}?O}ꓡG9wz.#EV<˯;( t?7o֣-z{?eDVD}mm۶efhӉo>1GhhD>xףԱ f.K86tdG[ąmv W~@[MPZO>#* 8Okvo##m ?S/rT({jI#FyRE?@;(@ӟ =6@Oąk"Y<rq, @$tg]8. .^2=._?̊N[o cƌ:tHv9iĈQFϟ=;0;O;vН{<7_G崴߿5{hGi?[j2ۡ7~p/7 4ǜf\;r{}lvN"KB5<|?&4Oe1G9c(uHZvŃ0+3tD-}?~-.Gg{F ]l*JSQ>1b0 o­5ڱcNJg--}{d`憞fgyIԠiK c{+yu7GPLF׭;+3sΙgDCl)cz!ݷv/#샳&LxJ 2dx챖LMK9 ,ڙ(sǎ[4{V欚AgURwWcN앓{tIQe vzf-{ceS9hlK.Roס^"YʆodƦeZ^{::hРM6}Gְ33o#+Kޫ}6Oui]ʹi7&?>=Pwܜ7134\zޑY{{yo=8ڋvJX}FøBû?X;|ɕi~ )|)Zײ_ ;[C޷.דV§=唭Tb'<\i]嬒o]󙛎.9+[Ko agɊ;rBɕ-/X1 WjϪ f[F&SMj|[XU49Uj^~ɫXyg#pw8Ә[w$׽L(j}.P!Y;Kn, O!P3&_p{*+ VGS{np/?} oՓz%GrBWį X*.n5]%xGد+KuҦ{R]\swwX3 j ^1vB՝Tyر7j`^9?S1YBIUy{vxbUɕK5^n*Xڦ=9.8n~n]}bmQFA捵A쩧 EͯOO ze"'&Ml2{ĕwٷ x5J^Z[ChSw^l";CiY?+~sY%7~{eMQY&cU(VzMǞ9%c䧙~P7{k ¾84;Wk_R@ғVLW 7_.ab `X8~(Iݶ3ei—'v]}}fQ36]W11/,yoׄ+Hlo>l׍$L-l6WR>|lٞ+<4DȗXvlb, a`nM6k$Ƕ]xꆟ iwڥ3i1gѽK/MmԴce̜kbfN%Wc&+1ܱ1hg_6ukl6Zrequk8&Qc{2n5j/Y,nIg rɺ1I'x?]*э?Psj2jψ'j|hάs/LBNX{nLLm8rvuמnvUKќ>:cv}r=) ׿6+*F$Q:q?RCˁ+݄Rn5`;Jǁa­5 u|O7mіo֭Q۷M oV\QGN#u޿T4?ݷn+DKx}e;[Ԭ0sС|d4?@;(bcK[>'OQQaַw?J^{}aBGtuO5hϺċ6ą?chI_3t(gX^z-ᄑ%t{o;?0SZYyLffZt6築_/-zO|"kQ:9 ^7Wy g~G׋z-/}*˯=:dԋr럾a}?KiPzzzΧ (kGd OKK tUϭ~;#?3N㟞׫7WWmB#}׷ﱟ '!={XPZMMM}{K?@3 RRRRRRRRRRRRRRRRRAZMMMz8s H H H H H H H H H H H H H H H H H H H H H H H H H H bӋCk+ 塵:Kgg5UPъ;`{q^2[{FEAV[(@Ot@$EEQSџ +W^X#RC7]PYSkMYTS(tNx'_ʹɐ5@Jk~_eݶK˜^T8X:wc鹋Ƕ,*=etffF +BӋU gd'+hESvf7\kǻ⢹SF~FVܒ}xN^.tuCm^v_VmɩmʅS9izŠ'kGU ^3Soo%m1CUd&;[|9g,-_8%Ӌ2jpsw_8tfg.s.lt˺n]|mݾ?u["ї2ML[޾'Woi,1WocUBIDATnNm'V{뉙 b&XS:kHڶau8w- v n'Ξ>$tOJBּ  69$wǪdbUQÆ^T LPT_۫K gdFXVݮw~5W^RZo>:gJoQnL::=ǜ )&s'' ]7"+:U Ծuxv QjjjZp!cyOQs- G"l}=E3ê17kiZΤrєc.^MN*nX[ߖ78o9wW5ƀkWd6^^:;VܶFV+ ^ҧP>{Hhǭ7PQ==9q%ym~ եs~K0YY6Z7/2zi5tN޿'ϹL $OYX}4|k߿m 3[2tۧΛ1 M p I @+=RRRRRRRRRRRRRRRw8o@@@@@@@@@@@@@@@@@@@@@@@I4n̏63],ЍJ>28jcl_SAzפF5Ϙp_ :sWN8|ʭox܉\|iGVz-"BЬv]OGK L.hSq,Q3cY X}ŗ}wsEK.ƸՉ[W_o.Xs=ߕo7jxѨ~1{NZ[o.6$[6qk%SGFzVj&<ÒPk҂fgҼ}!w⹉Q76Ө򾋒s.k$mZ44_}wu  v_Xsb}%dڕn~~qDiPwޒDXVt҂ 5ojNt䜑]5[YoܰIȢ3q;_=ud`uԲF:){gkwF5XA@XU/kvm~&QlTՃԮnp-k&iݸ%uGIw% ژVֽ$QӺxI{L@K>X66훴ڍ.w]8Enr%osqn3cAmuAK^@>?,]z]g+v,0zcQZB Hf5xi̘|X̳vaa>sZdW.|˨NwC%u}#pQQOguF~˟ϟscE/?;7[Y}u_73rX_c0 6~Lܹsׯ'|lѧFfsv0vHh ~sSp¢Kҥt@?V sI3vTֆoo Ϯ]zx7hˋ/~x͛ٽ{w?ijj{e_}g 7>26&t~a_ǟxw]Ø\~c&L8cDqAa,‹/nկeΝiy'0o>`߄_~-;*;m37s̟cK/5o~E F%}؛Fƍʓ^qq!$ꫯ_N8qi!?顨E`,{qǽaO7HuTv0ʼn}mF47?6czlmX<ȋ>`'pIbW^y~GKaݻW-/Or|0H`In 71ؓO=Oq7M{kYg}FÏudZm޳dU}{&Mya0Hh|0ܾ|ݲ+voyfݿ'IKʾ)FIDATݗ|ƖawعcǎD"'Qٙtm]8_|_"*Z9 9=p#>vǦNz&s<_}zh;CA] Z7R^V^TuKό 7q\M/ˎ>` #g_>rU ?ogee#ߋ % v= qA};%+Ya:KLImug0C W^y埮rT>}_`tBNvZTk_}I 5w 'Mnuƍk [۾ ۶50aw ;?`49 _ ._}}}Txo[?|'ap_I^^֕Z{6 O@A477Gֽ=.wzoq0?1ܽU{뙙V57?0jmmu/n#}0`ƍ=aʔl ̦M{} ϭ=nHn0P5W5|q]gzV00%766ZtimZЯtgɼ_nyAEmS6]T)UPx^NODAe1,޹0UX=/)]܍[7w 5^h #&XZ3Lz)ʼn{e)麺O8ib0&\3/ovWo GΛwM0c]ݦ  oӮKܴ8TyurUUVf[ݵAM%M WogVmTuGnoHпk7k3mD^״$/oIg þA 逋7ˣ3-LdU>Ž An3\&ؾVSN>?1,_6`X4~C'Ds5ln 999`d< Sw+/CmC 螻9);:Y^tYssBG Au|冊w/k@ci:c¯ }%yyYNcԜu/; 2 mݜI`Ą_ ‹;Oh[seYyf^~SR~]4ukw/Œ7VB|j3fLoA0ڴ'3`4MϮ˪lPj݌'U>~ܰ9Y>ښ(퐶)QR˜jr 0KS@Ƿ]G'sɳMϮ|>r}nxeϞ0#;6ciΌ} γ ѿC0nܸ]QwO<}k)IF߉ nt[r mgJ|3 +<&YqO[Y1grjԖdyϟy;=wRL e6L[,%ةysKkg&Jwo[15zW&˴lu.j c_f5)NNJ'%kFUvV]6-kJ'*U7W.]H{uˊ2NUmY1-K+aqɍu φu'YtPIo}(.܏=M]߀6'Qf4εX ȤI~Uj{\'$zȎ6`P򷵶L>Zs4AA@,|r€.f;[Z[[{ۃ!9`.(ذq/36%Y}B^S]/^UnFٵ{6n[W˪l O(,;wce!_p?q)e\8o6Ew LƲ*koj˂%;o՛*Sn?w=T}!m:wWۅd?0noѷ^{ccؘLƫ%MA4מ쮎6swv! N7pծ{^o ޽(Ϯkg|~=Sou{NtoՔU̞V~iʥ+tx`;brU][YnHT3kUtZH>ED7_61pU +&^9ji==UM5{u﩮lXRvt#s{/ՌMeSVRkV>'z .ɋ qQewO۩a.]Luѥ:.$lUٔ 쫆2T/Jwc[;9x!0Rj^s¦ʫ2 ~2^?%JK-}/$}8A< :ѤՔ0t 1vImT\ϘѵTFځѕqHUу>>wO4-/xꕩ9IMKtl|T}FTl&4sfgվ퍩M:mmx(z[R\xuE(΅F597qjUdu:C7)Lj+*w˜vF2'm?$?#meW7ujՌ?.̟^^0 s]ɣڮ]=?cUM\T;L?μna"2L= >{kﳻp͒~՝e+*WZiwB~JA'U.YizbFC}]Oym'ܴ T M%\xyKW 30+2K/ؾh{눶鑣t6ÑI懞 MqQT1cAulr9#QfY12lN{tjUھ<:!ZUuwd1dGyfrBeXoV_=]}ܪ~=T674Gk~/<[=GOۜcw{tW.M❥'q_uˮnY_ǶXjݥL1™k0-9\4jB\ܾ2Tf$SyVtyK)O3PZݗ5= o򢳥.U .6 тM>z=xnݵ{ R=%Oa:pžٝW8d5jO}}vW_*N̫|*H,Y>دnajRu^LuPCSKw.p]z]۳ߵU WVkkk;^~q{0$9a1 ^i3cvJ[~;=)H-X,I͋J>[tB {ffPL)[5su[SWWxtumSv:˩2oMj5[w»չgVunaʵave{\gk;:*X쭷쮞:>6-R[>ն.4W%6 >T ˔^{k{^:ޢM֛_Zr`$ ̑ÎhoXs\ N?a=CEC39Yk%T/8KG6Uf?T g2o(z<,X^AuGMX䳗'5vLPFo(K 4l0c=?C;@yYy@ LX^Z[{_@GfA#L80:VV8KK/@o8@H $?ā@q BBIDAT8@H $?ā@q 8jmm 1Μ?ā@q 8@H $?ā@q 8@H $?ā@q 8@H $?jʯh`+YiɊƀQMI4JjJ~6䯱50 pϝ0eRcEKs`ϺDM/ғJRfqĤL^f -Nt9YIM~Mya2;zƝ˒ޯ0:hRnayEEI6jgcMEiۇ'M$ 7uk{ULg˯lV56}y}>KV4UO|sv6t\le^[KJ++K{H ߿g-^Sxztu/K:,jޑFoL:f`#S0tJrYMux@v{k mMC;vpFtt+k]`_576?Y1L;__O^9ښd/Nq}sr7w?ve߹L^scnq?뾩SWQyP?vu{ߠ41[T__q^﩯l?}s/sr]]<}cUQvR sos͹|sӲ靷|Q=85%˘whm904i;oCcb[}ync.}}?]][&;9v=>z3nĄϱݵUE}>!нSzbK}y2#qJ,>!0c ٻ~},oq_&VLM ֮$mMk ||u[v*x~˺'65}a~IM)go]??zvtO _<ʎu_~rNI]~eUCSW|yۛuKgt yᲳ{ӥ/ܸ8'e'g߾dq]g9럏.~IYaפd'2:ιvqn5P4,.LS;DDaym]&yҲ5c좪]ŋOf{OmMbzYuC7o-)k&ϹiKSԲ5Ȝ\w{SS=d(MW~Axޜ®ol|";7??TN-]j~VqPYℵQSҸtzg-.mTRsJ.[N ۢe7Y^۾knadt9awe%*2#/s a3ﬡ4nNx˖'P@w HЩ>8]cw @ [TUyG0k~2~bKCeGb(mmm|D<롩Y7)vdf{U5vU;;1Z̧X۲e}UY~'^lcjKS}Rvz{h֤D"YXR^QUS05ǂىhZ#W84ŕյ ֺ`h>ӕaRԬ]k+{ve]cI&76ԖAtGn>rH_jpҊb~PF>tY׿L7CCG.0rCgUTwdyM鿮*{:.ÖFsN]7Q}oh'h<끋G@EkerJ {nLI{}CDie*u$޻K/;#J?Q\=d_ZվazG?4S_^ ¢kj7,ߌ7 %zn-,-M'{CL;bn v8wunkVsMmc j]m/`N/Df>MK~z>Uͷ\~δ4qW.jڶ~ł9S'wv~Bj9FSjx04M޹sA 36cd .0Z ?4yt [70x~4Ln~~n_۫PQy[d= H:;??7v{e5M;[[w<6s2Y'mhio fD|벪`(;F͘?G ܐoKMI~h'n>zY4hNgD0HCL9bf v!#1r[kz ZjT=?0JԟDQiחT4cJ~ii4鎲ҁ^P1(<ϯOܾvnOo}Ӱ|9EX(o>pӋʖ4I:ҩv֔&k:O=kM]-Ú8W1|VMo(WS^ 0̈́>VlٱhAG.;eT74?A~11~  zKMYYzɟ.+ %SVV6e- 光/;ȥ4d-M UEӳSuGlm}dqe}E6T..)̝=NS]\U#{LP]{[)|7noME 7-nnKkS9E;Pxk[:u̚ѷClMLkv6կ %i+*-oo\0-ONJ.]ߑ,g]Φڊצ * a34]`HFr.Nw{W3oRњm.3urۖ9S̿dźOq&%jBGIDATsLl?xbNNδs\~r3xE;i9;NΉ{숂=NDĤn[9{6rIC3ћ6t#fmEC`?Fj]`@iG- n)ڷsd8}23uŶ܀Oۄ[x6Y Am0sF0fi csX#wvA1a- ķ A_3/oIST_n݌-˂%Ѿ՛*z^Vfc_TQ;/vw WZŒOȫ|*UhZS: mzrav n[^ѤDqյ{:޺w՟k[C/ 0?郩.ypæMOՋRM ǧh׆g#M-Ylthe3$RGU6q]릲)MSf,ߵ)S?ܘS QF{/+ulb^eslW];;Z"uQ neJSe!! ^UicJcwd@I[j^Rg|mm:oI`aԔ7ev,_8%˾Ԍ0 t ߴe,0\Ri ]v )aBY2reUf'$kAuCY39Am{'1*@\` -=7/|qt'>۰],ؾfu0ӱ_:}jo Edf1ݵo+X+E>{=˖h>S%e4SbMKex{ƟѿB`O4Ӈd嵭٫=z_k=7DӛA2H3pIm'7Gb}b-u=i޻u{fzjϽt#mw5?ҹ'% 4仚{3=4Y^Wȕָ,ҡJoh3rKjj? .G[֔Қ~=ЏaO^xŷDt}z.CCE];/ZjZSe9DIMatC5u=1kVuM]>y7m~:s/?''8 &Ng~10=/(=8]c=Eu[VLKxY^snk-/LDt_%76(,*jn򜛶4E&$ ŞQT(t&%K++Jke8mŖeXlq:벢O'+ ϾvE*ZU?'1/7pr0pz0L/L. C]EE:QUQQ=KLܔuYe}gݴ${OOL]Mok;y\~btﲪƠ9 ,jҽwl{`?r?wYDvRb;oNgI\1Ь0^T!QVuej0_8=pO-phM/9K'56v3 KK;S'<aQ,l+xi^6l,-L&;N<)Q63O܏jWۛ/>ӏ:tHCdPmuTBIDATZ-3ss;G0qzwu~1:ُ]TմmsNg#7-o1'h# &LlM]]UMDtݶUET~񽩐/l{>;zMאqP&mh-ܶb.j N|wX1TazdsR]^@~iiz1}Ugk7qƚ̴IA3'eCǁYS*\ӖHk%9ZLVem_;7YTQG;j]Q7y~ղ^*:>:`gSmEakS)2R9X_S0wRgW6H絛4"KA΂U-*U^4r}RSu6؞3]}Uq"j@q 8@H $?ā@q 8@H $?ā@q 8@`9s $?ā@q 8@H $?ā@q 8@H $c>6l?SO=}x[w}vYgu֙rJ@dۃ?٢~0`ƍ/:̛oN `L9Лq{_O0d?ᄐY_aū09;v8?ɗ|o}[N:餩Ї0{g~'nݮ]3g~p衇0}c_ڿgޒH$7? y{۾'>cϔb?!8r.Zkw3`,Ks^y啿xayƌwƍڙ*;zzs̟&9uj93HfMc) x;R--omCf{lfQ6 X4lnn O$rNr|_O<`̚) Z[[{ۃQ#K/ 'o~xn o8 ٓ^zlӄ >YC'M Ν;xL",r!/<\aG:.n߮]&N^z۷R!pH/ciϽzw[n}ɧ6,o^z~upqēOϩ:M~ˍ/.dQ$ufﶷVQW^W,F/lY0H`qo:O>9;-:= ٗ[vuƲ>ow}_rKgXn~̷䧞zrcǎ_^ 0iغ5]w-~\5q#9u꣏",8( 嶙FN ؾ}{T| C=ܶ18^}/?]\s˴io `pTf^oܸqQ+u `d 7]0~k=ϣBNNNZZ2ߑ&Z7+rҕH_p'_sޜx_|D{{OVnsC7?~w~뛷_|^o.Nj.ZzQؑ Io$Ga-oyK0$nc``/W,cfG~Iopol.͝)o?FyZ~7Ac {>1~SO;~Wf 8`8kYͫV0Lg{lmm k@w_~Gײzv”㣟7q{{,*CtߕYyWK~}  7?rȊG?_~+ (:{g?Y7y3yyYyce0 sBD &^۱}nm [n qI5W Zw>d'<'= Ho!u`v_ R=!>}< dvAg3Q*+,x{n#f|0wuuw%/Gar|l', W.u+J޹ G6lvߖL7i{ An ָq†=s. F֌dN8L݇iT,iJ\ΫX=ovmPjӺ^̙`hnWM ?}iO? n]xsufx3&L;7؃ (#~dp O>da2`>gLwR&<ޫ?ОO3`)*/^U&+m[WK*}˜2;o+_TQW/vw W|ϾʧR%yyK:5Ӯ`J٦'|ޱ+_nyAGŅVx^uWnY3R ܿ<6z<=J>{IyT\P }1`:ȮCtBaٹ+ø@m]NGu ʼGNkΎgN 輫}T_{?L&֦v7uܗ;g_ :E n(.Ajԟ|[U~sߖsmkV[~uo|{`,>_nnnVVV0<<7 $zYnzEw*~IT] i=ojΫSJǮ ݯnܓzE'`"yԭI$˙/;>dHYR{|ۖ릕aPbIfWj>tRJ7x]6eDyejymg⸏4ܽ{e+&=&RN12YjUԬT=3(}_$*XwS=ӱkw ǧ:5b* gkJqbeW7Pmf,qتn WGRsڂgJ_HjeWWoݗ7+7xW;o7n |_n8a` .7X`?9/scu_0>_MA?.](V[&؜v8QZ\UY9)e8W_lz\j}Z>.W 0w~Glo:C:$ =6 gyG?{ڵkΝKw}䅥O7n1~et =SNO=CoA˖9I%Ժ'$)=WS`m)0*XLYmӒy/zs?7_(}w 0]h(Ӈ=z>T\3))5Mj)U2gk9kx]~aݪ|{gG~U`TںykTH$rgᓙ5*&)zB/˄̌pXq&9}-J]{qOcpܦF*ۧo5?t7_/ZrO2圩H{[ѱ?s.{ྟyі~5C9c>zeuMhC=gnF 6Fη3sjᓫ&.ZyN,6=0*vk(R>ifE1xզN &ޥmNɌ\Ve&ʤ9NoX.RV6ʼ v_vH؀,Rej0ce}2pæhNؼxMK Epڶ γ|ȫ /ܵkWX>c^N=5u 'D?4aK;=`4TsTjO ]~Ԥny;74^׶n: 4ip 8‚eBۤoS2cfdxHjTwn« /M=/mVVkVw ޿/(3\5ma@3W跣URRʶ 3?|7|swݵY2o}v'/_߇C.l_P`t ܌6#Z`mx#7syݺ[o{yM v4;7Fݚغ;hͭܶ1*w'0eƌ7ׇ[3_L0|oDw99h__{fa蓛8!ڣW }Fݚ4W Cx}>hk(߰+u<8g<7``o_o[>LO|cyϻ;*-OF|?%lAoܸqkz„a??a0LF@?P`tzk[mo4{,*}CUpYaʒ+w浭-eqojqmz+']8͗MK-;ngU;$N-:}Q ;۷BQj^?ү GqDmZW|G/~<-h sΕ7|W_ _fgOU+NK)fw3vn}-m$VsssTϟW7Mn,G{^]lTOmΚgY0lz?IXn߾z Jf#*47? ;3c@nh3ߕW,}1?0w| >_~9|?| mֻ. / b/jƍ{?+{!qo 삂?aa{}18b S:**{n%CΊSO9%mk 4io|3㫯𖷼%_2*w svA3'u1D?^+v߭N}#ַ۟ӟoxo}Ѕ=GDe`P/a^$o(t$/pG'x^:zŸ%x⑛_ˁҞ aŽ1ccEXGul m߾w]TΛ93ƈqT"ÌX\vmT>y̜jwA='ǜ?3U}{Om?7lO^{}e{Xzi~d2,S]@ :+,1Ƃ ?+r_~G/_ !Q9+ 8.(0~.S|`'1+8∰T0X]v0Fee׽ o8?ͱЏ8%y~SOnw~{?}Ѣ(Ҙ<٬F/_G>}Q߱Doƍ>sq4lIDAT/+:̀@xWLY7|?y)>Xr, TӟݻwN˯x1v䑲@ &^ sءoկ~g <۱sU|z{Rnom}}JeUVyT.83gpP@_bgO\ @r?" D @.\ @r?" D @.\ @r?" D @.\ `JV[WZ:UE53Ïgl]Vm e}SĠkFjrg,*. v6.+ZqO7[[íMZSr}hk XAq`c<3%E#/ d1gA߱kf.|W]/Zt٦]5ӷT$~s۱מhM>Tg H}y8E/^OXqWaժ0._TQTSQ)^Z_,^U])(nh*4ם!}m5eɹD *k{Gǵ7,KtY}kcͲXwXɲƶ}x~}@>Ӥg4}Q~ϖ[kKb=9ɜZ(`Yy}f<&|YRk+ˊ{2_Y9zU%CM( ۲%dmm-A6ZvYOdͫJgZ{wvSg罷^z13JW5 Cm%+7nNcƕKfZxcfW7e r%)͟}'w-Xbdʹ3PtIyچXUsl* &l"aĩsȀSkM1l|e2^W.35yg㲢37|XasU~xM*:kJܔev.VV9iW(Ljixsr^,͙tW]]1}Meű ǖmL~"#.a+~̞W{::u^pIG/>4O 21c.^Md5v;'մbEdŭ26 +<,(*;}ecξ{wv}{!c9_Ay}k/='߸qTct#mtSkcc+/?m]S 6 nGkCSXᅗğ} 8tgSsQgsBiqQOoHB{SC"Xt\ <.7+\]'bwݴ88F\Y/*kjr{n[|~a=o&QUTZRU:7cP6QII!o_(w{U#;q`%UbsiVlN?gVV&33%>hmuk|s[cuYQA AG q9Ot>|߹nyyy 4f7n }Gwm`=;K?΍Vdɩ0>M1R_*\;)S&s 88pEO>_>|~ARyFYglXb%a3K,dJU2!K,L|ک*[`Ϟ]} qiIyydϩ0Las---駟>uzz FLۺ;#T?&R䯣#Zi\GyL|᭞ԗxɻi pEGo`JG^WWW^zaO0μ‹Z޽sϛ~ӛ޽n߾w.Y޼ {{[bG q*9ñmS8d)=c?9'~…g3](^~~~kH9Ə4^|xGwgӽ~ǶLz9_~9\h{V~{G? &܉=/wϣ% u[~ž= [<$Z[2-Aw7ݷe?3޽;I ';9sNYpY?}ӦM \1i\Q=m-ۃē?`˝ߞ='GU?~߲n};6wkn#s$s0~(v.&ܙw/-`^~+V]G|;S#<{ϼ+dC ҹuǦLn3io޽}ߣ>,(yG?z)'Ϛ5k'0iOO?~sρxyf$CҹX{-ݷ/򺺺~ {qo,^]Ohß/pscc3[7b&_}|0zsxs0 ~ &8;}㶞;S]ݙбx^rIw޹ `(:Wc*w=/;6+W -{s1Qu3.z'Y?G@:W08+q@%N%q"wnO͍wEwa;SOxRiӦ˻vG? 3+c];~pgs`ٳ-2 I 05 ZZZO?}=!d;Ou2Yq*x;tߖ-?<{x[zܱΙsʂwA0ttRT-|!5&WSةskcha@'vt&`T=#O>rNxoYvÿ׻G C Q7]&Z`² K>\pڼyܒ)S8p෿+׽.࠽˫3|SmWWWpE>Ϭ`y++q"j1 i(m#4Civo#/Ȇ!\\ZcN%qbEN}׻Q5v[3wn͍-[9:8|b<,s7dO O `<èp*#Qqc|2$yofx+~.Z>ԓ>5k?^{-u ;:WFS `Tvv gx{G(-C:=8\x#ƻ~_ _)SK,n립.\޵?չl\ZcN%qbD.<`_r^^^0Jn Ӷ J^% ;~}0.qktC?yŕJî=o^x8wmZ|Xӊ~l4o^z& ;wɻ}DZx2Y ޷ Zp\v:W\':WcF* 4rsu0&]k^C M::6cCfѱIC&\L.ž`D^Ƃ O?tO.Xpߖꦄ`ckנ-.lz[;yt}\֧ookյ*l}j}7,ohȋej[^mMdʪRԊu͛9H$XUZ*MfWٕdXEٳ ={tǐgvp7ﹸV=>U }V%?ؾ'fH=D߲MHɽ;) syyO {9,8ݲ^z¿~©4~i}7mfb Xkwl-Ce,ز:`Z'O7@wٻ\LpeK5o==*V,K>˧'ϯ>[&[U;ܻieeMM{<.IJG7ov<&1þgnzkcjUdl U-ES6&1sU$fd$ *޲pOi#! Io{`ټoi"tS{`0?kY&ѹҹҹJҹҹҹҹJ"\͜9sϞ=#[wOskcc'Ã컎M:6VɱF:M S]]݁^ x}kqֵukOT3y^mGϛ:jM|[ۥX'@X㫷'uSZ!IDATU9|զ\?طm¦bknZBպ֨ųhG[Wlmr0Tچ ʂ GW%wdkUaU}}b䦦f,evKw"}gGw7E~\{m3T֦(eXUsDM,ӉxcQj7Ol<<]ѻJ=L؁g#^\m%MUr'%݄ᅼwD?aFnpۃ"#S347KNѾz}}$ILdӔ4JǷG$RU2{+HMHh8d?;;gV?b̀I@tvʯfҳh_hzӹҹҹ:W:W:Wt&@jXFǦKfttӱq(Ahkk;cqh׷ăṝn}4utww999^._ ۗSѡd-wyV=| Gv@|jɗs7Նg@wϋkզ|I\00hjx^^x-eSUvy]{Wꎪ[޲>jEFluSO4-~-ծ}Ok*_oS=X\}AASGي_q˯iO.+]^07q+I|cc ExE>Ϭu{]SL\!-kԴȣCmfeӫaN>ձyi~P9,I=. VA')g}aqׇ'fbyk/~fbU?Z V_$>/-\QJ>q˫``0.Xߞn*~/]r >Eƶ/f*5aoJֺ78n^m'>^J6M .X=$l|[m%? G*G#X'_$46l?_`EJ5S{ztgt+CghWÖk!w$%W |_-iꫯ>?q?ė=X[s?xӧrG~O0Q92a2RMW=SR3>\.ѸB{ʅ?.SLJ\nb.#:: C+W}tgn25ѧ~WWtgJ4}6JMbϼ 4{{̼=唓g͚5AeZUyw~Wo KnS9_:}lV<ܱ18a|OV7~ه~/X,J++\\\%no{63Jsi l32[cYбC& t;2A ,;V1wf?ok=wp|l[*Ӿ-soؿ5~ܩ>v{?/`L:5l_O[-ObUwj) Mvd&"sQ' !ݷQ*H;Hm֠qraѝ̍ %qk8XUɪI3{+H/9Mb䯗_Ӂ [G~蓟|!~%g*3?좢>+_8MpD9fѹ ttFU::WeXJjd\—j?X&бѱU:6da9Fc$+D/'a*'☿C=`6! |ve'yvt?繠ݏ♓.G}j_YѺ0r]VlSəݹՠC2?i3mx[\%Ki_)ƮYW|Mwk膦 2H[}s}S~3$?yV{2ާy*0O^{m?|Ư|5zZdoҠ53]߳ay}Mw2T~{ܻ|{/zj[iZwS%ϳ\9SmǔpBiT~dt$6#ut?&1$&1bԿgudAe8Ҫ2to/`{g2%nZyۘ{DT'}f?3\xŇj`T\\\\\\˭:Wo3{b~xu0 5Nб4;ccؤ۔MMMFcJ˝_7-,? FU} #Q׏tD$>чR=eۇ 8p̅xpyѻy4OᆜbrItrfeR40Zųއy$\;Ϟp ?qƂ]wM\sc凛w3U:WUz:W9F* 4t\ 6hcMzNcM:6I#k4ܙ_2-lmi{ &l:p_۰!r'G˫?:ӏ0'rIɜQ0s5vmFS јIj[O3$58>8ټ>s*=|q({ɯ]>=1|>Dy}p̮=o^b~>yi}{wD ;w>+U^_-<|7\vC0>|c_zOgptВ J*W\s5&:WcfjұIY<(RбIGf Mbk4L&M55q+ޚ55״,/y ~o~'IfRzQC0Mb91]hVMb?hO4tve_J+ßg9ﰍ{?ڱ+zy|ѻ9L* CJ*A*0ص9ؤcsHdcs8ؤc3ј8Nih??~&Ϟ\Gר$oYκlCns߼.YX29sΜ-[Z߿=}w?MK!s59}$wƮ̑Y!c39}$k4F?+WqY09-)2eʁv+{q*Ȯ]min~:k$?j9ꂱ$sLB#\t63UZcN%`:FcJߧЧ'r&aOrG A^{haz\GyW/<Vo>UW|ӹ&\mfèp*A5Pڔ`D ?D?b#e>rϨIDATi~k:pX`?;~J:Wr(;WYèp*ʸ7/3-O.<ˬVu*OOw+{Gy/ z\ʘv>`0*JreŘ? rWo-c@ C_~9Sn.Yr֙a+7]sN6-hxxysccϛa6#;p@o_\g;WaSyo ~s|K5'>^FS =cqhL#K/]W ܷeK0->ZݑGԬwo~pN> 3+ dj\p~s`Zc`xјʝ>OQo]7G/w̓-o`P:W@b`h]1;g~OSL\|ƚ<3.X_>Quɇ6wnI"t3ߩzW0@Z{hLl2hg,\8Moz1}:@xiwvoUg`"3`\9=8\x~n 8WSfx{G#8bn'W^ t'x/d&0V.XѿH/g.xm#ݧoY\Y}0fWQu΅egdYgkiӦtۿ=6only?<];#<^ ^|yd0?;wn #۲%[sM.+RX^k[D^G淯/:!۷SN=o>G0auW1u`cZ)ӧ`ٵ;nXb%Xb%Xb%Xb%x%~K|ڴiA?zܒc5g{. q;^$4b-ǟɯw޳gO߅\7ȧyyGuToU4}9'L6} @r?" D @.\ @r?" D @.\  +&8c @.\ @r?" D @.\ @r?" D @.\ @r?" D @.\0eXjKJkZ⼄⚶ɨqYT5V䯭j`l`?HQukWu$V^U}6WO隵rgΕU6R$LR+YVؚf`X-k U$^T6kYS}eeJEe55˺'=8Xk*>h_(D!$ Gim[k[6wE{}E~ػ{O~9i]VF%~oɔkXUfŐ7{b ާ,k,+]3*,\Vڿ ͷ/U޾wL fx5 Aè} xMcCBAOn*V5|\^WWWO(7vd<(\-voΗ\x{5 ohj,NקYXs.37f&;ͫϸ;暲֚ҒAcelɭ{z]tSKSi}+ R۳x!]x{3s5_ᮆo,5q-b[w>iCo۸ԙkwVeX=s Ͽ%uo_mO̰q@ Yd=oN?ᒆ 6DmhnJ9JYWޤiv5&s]},U_aV2М;ZWZFvxFpik+;&yv'MOqES)Ilkuw/ZMK/\mo›W<|wodu{n]S?a?Ek}=k͌ƳjZW7z~ҙE%Ea!ui펮ΦdUk}f/ y泋RMŖ5K-ɘO2g;gɝͶWFA9l|"y<+N_4!ߴmw2;6_0mdI݁:Gy?amKf=Q[R ridžgKdIeA<2r,( scZAqqRQՖUԷ/*cew{I%)##ބi5&S~HJjA!NWZe_}E&Nb[[]Eq"$_P\QגٸlU[9G+T. _VUqukJ Xr Miml Fuղ0ŷ5UŢʪѝ+RÊV.=)|2;S6֨lܺzQΊW]FEUUBe_QpdfqyIQAM̗ټyy򲾹ok{*wQiiq,|Mcxj~EHY#J$g_$6X6VT|4\m^}+׬JănojRA}-nhIYժhw5g}ا4'WV XFP{;֘, YkCeq";ᾮ:c|AIl"'_Rwx6Ab3h퍘*kJSOzdkj@`quA_k}Ԕ|u7F3'I_65k'qL# ojk* $5Uƣ>#(h=/8fF^~,V\e_Y| ۀ S b8WΝ]rUmCSk(OvUQXm$>sƚŲtMj~2-mmA%ꛈ&_~VĮ^])l5HIf[coU`kg,li `_KS4b*&IDATyܯֶLXzuuHC9.=f`^V2uѤ U |3VQ(ܒ>3{#(Xem,y$w޻ƕ.Fub,WLlu]^gtԌ>f1{ER w56cnշ9|32o0gYyleJTKK U`D7cmT lSgs} kk0Kv,9 Rmb>ғJS7PP^߾kf|>ptuGQXkcΞ4  EEy 5+Y,k̨(UƉQEׂ5`)*-M3οm`y/fkMYn=^T,(tƆߥEAFZ%k[uu}~]6t x`~Qyu]SkgW~=]>0[Է#Q\}csSpiKS9#~v6.+ge3>ܥA{SC"v88diĵ7ceT  ++S/i &hUß(3sMǵteӺĨEY}FPmyyyXMxpcE%Uk[,ߙR+ca5n~>±E˪gzkMe4OeEY ~E;.s4U:șAֲY,kL6S0_;kkړ}Me@<5;T_S]^RO;fsC5=qږޝlki](?{im[)C$VPQ߼7Ӑ!,}[*Nrg#(֦xƊU=yi\#w7ィ3`ꪯNmKsuq@nh)-YlV)\ rm~6䈶~[ ." L_U^#ʫOS4rmO'@r?" D @.\ @r?" D @.{=t; 31c @.\ @r?" D @.\ @r?" D @.H׿ >uO_*a3rG>wݚh!h?`-m.,\ d)9`#4шm[>{-WH؋O]j`loOf\ @r)cf>8g]P:oۂ c-^%`֟7N^r=F+h7xlf^Fkϛ7k4ю2 Wݱҋ.u͛w2jFYֺ0~qr6S+Y}Z.=WUFu욭w\n䛩ZѓԯXUz׊WL$Ǖu4E~2>ݚO0".W?o,E7߈O骊ao^'LEa02=ow~H26/ xQ.^yW6x{|g2 w!/s75s]W񿴓RɄ}Z/n*$>[tAxs0xuGUG7\  cl78  C8R[u\<5kCӮ9SNKTRϥWAJoWM3ngO̯ےaJyeO M>mҦ}#>6y[8VۭV>S{޵+wG[_ v{1°8x ,q}ξ ZqhyD9aoy{ ~`4{kɡ+ta<{M]E V5^7;@SQt 3=pDAIDATw|ĺG5}8^rE_xסxHh/c'Z ѕ уfRx020HMw\zې> 7VL?3Ãqφ3fi9ƍ JrG>u:Lp Օ~r^3cA09QOO%Fёo0rDHǘ?" D @.\ @r?" D @.\ @r?y]]]0@r?" D @.\ @r?" D @.\ @r?" D @.\ @rZkJJkrL2lpԯ TI6qVԴ⼄⚶;1^gsMEftE}{F˚p{% m#;ݸ,o oU5>PMC[0Fc^XU}m %kZ`Ci#:nk FݐǴ>@5͝Xql Vqɡ!:+j`R~䯨$Z]Zdc_[Qg=~3(T3oY3fytvPR\L,\'/@gK]eYܺ}kjխvCӖ* ,7Ք'6,M޹yyg b!x1*\N^tuuEqbcZ^Ŏn+,$kI+(&,"X,6ԝ͵#z,ZWѽr~qe}]'w<㨼a>CQp2r9¼+U0vZ]0;ݱ`> yL 4?Q*wU}yq4`dk*ˊ sU6\jO(^RW]V]%ál[U^қ6VuuyU,/ղ`_{{| z_kS}MuXw[OslNl}Rs嬼?1B!'a^W5llW-UM穎e%=z]êdKN64lȪ3.z0R0#. m0:D/9[ě+otq_cՀŪD^ơV n|7+;-?;Սo'ƭDC4X+?\?OYjyUYKVz=ɷK>fFڝW=ٱw/{TQUS=5ޛcƕKN u`+c3I|Oץ5=+Քt+o ѝ`b볊*9} 0/w]A;%+ן}LIMriI{v5.~{ײdI`z7M[߼q]/[0yI٢`fYiQ0b9׶w K{my~6y2VΆec 7gbHixOmG.{[/{Tɚ}ê_m82cH8kkj55Oƛjږ+NnM<׬Is}/koϜvq%i 2 *r)  ĝ-ѽ/]ւK?ؿa@=}><;[n%ۯ;#XIyچXUsXY2.@ZDҚήʁӰ嗬jI-)8)1^=߲`GyY8 0m)1Ye6+HMm>ZVQ&}EUb]4E7=1G]xWrֶ WWqko,+%c]^gtԌCHCز &1Z/95dqMyѤ+rXXکrVbUّ'ck'S1 GۓOK/ImiW~im[0 Zjז)LXAvgڲ1g_z;;?}>R)(oߵyEgd>\ʨEϺj[RuuҌ[H1q<sȰ˱m溦`)(nhQ{y1c=rl)&])˶5<XPMC[09 YjY8w65;;CVZ\t3i656D㳴kM8MkZ]@g}I]ݻnZZťQ ܔv~іYsJ_T^]ܶv 50<p[íV5tEȩωL{ */) /, &x5>a(ʺI<ܾU!ClEۋ*Oϯ( &a$2Z#۫*XUs%UW|e5\knNU'W.ʘխIdnmeE+b~AAo+`a-ZVxa=m>0EˊX)ZV w"V\uClk %VշnuĬe{Q2Zkۻ|2kin3?/''\r}! iUEUU5WJ68ylMCq{6.)w_k㪲%#f._qWTZM+ת9k*kIM Nlom./?/6*6%IDATc[ۓhkiYVH[;k{6T[]Ū䦪.pOSOG{.,/欭[gѽUֵu亭(:[f ˘EVI1VW2mzP)GEwG쟕umX2- 81׷ޖxg4o3NZr}b"ٗmn/ty%'%VqIVxÎ;wܴhfwڣ[?ꘓξpwmEG[{낖5G.qI'.k2ٚqvۯOzQ^r%ϯ7fյݍKo7u1ZmvYJW7=xE"C񩧣=q܋rӎT}7ܱD{zYGzVr6פim/!?VrmkѓʫYY"7H?ϙ,+ &=R)8aL{wl^tNaԵ3g/Z6I}=6\hv %~RQvUMiyJVXX8g+nڼmަ Ê'21F-t]8{n s>ZA潻hz V\nF_0|y]]]}',^w|R4.,U_0BW&*H%KN&0>'h&`~uEQ) 3E., 9+ `2'[˚W붵LU`1'c @r?" D @.\ @r?" D @.\ @r?#/'=Gafc @.\ @r?" D @.\ @r?" D @.|w}[<O?ݻ7 o{[w?}ɒ򓊋 uuuÏӧܑocfBF^~6SAwku9%8D`LM޽{G},zYP0~SN5kO r+Һ3?ֽsq3諳sv?#8 vA!$cjE {z'gqƿߺ!Ү]m}`۪O}z޽h񩧾+8TD`LM &㶞G~tfa?`25趯G%^olŇ>x=wo8p rD+)%կuN2"c!ܜpO<$b{# GٟG˵W c`LMƻ_~~6lImiӂ?я9//0Zyݺ S-%o?s/RbL<3J{^`6K,8LylH,"8Xb%û/b)=|9»(K>߸pa۶ݻws10M_KKKp8]0O|[zg* O"ۺ 1c۶}"0M 3;::6xʰnƿ_կM wt`OZ7 eʔ)gΏ y]]]i?x=87D /sdn/|'U0o|c0|;}ꩧ{^^0uH&jڷoߛ 8=\CY&\>}'?#03Ds8i'7e/z?߆/_}Oqh^ `z̫ 䄉4p~i'\prS?xg'~ҺR{Gş/|ıd9/v '\&-6mZ /<_\7MmO<3wEoxַ(%'c@r2зFyRqǏ^~Օ^3cA:#\_wݚ_&\ԕ>}`0frgφ}j/_?sܚ^{Kܾ[Nf8rƌrgϟ"y?lѻٻws裏E/ f^яrɳf͚}Gj=?߿ws ξuÿ]Pq~0R%%uuuzn͜y~X,{p,^Soҽkwܩ+Ȟo a;}gTUnL6+>{-o~s@-ѷ{WEs\7//|2gdIߒ%p0Oxׯ~p!??k6LX&sy_^xa|u@-o !6D?3Zx߹KY>¶m-woI*}KA-~?} &O]W~?x;g̘wpmw1A6>wݚ_&ƁBFВ[6}Kqpq貽N$)?&u c:::0M2rGol[JCi}>ia4˳=-6o^Apꩧ=M¯dIߒ~-Clʔ)^y׽u g&6я}~s#mo`D\&NMo .cw!0afxJ, F{LBoy[ǟx"6}Kҷ1YQa LߩzW0nL\=Oyꩧ_|`x-H8-\ N@`ݖbXϿ/àoIZ!v$A^ ;p_Megpy'=29cn◶0(}Ko d;=8\x]]] u r]+xh弼O0l2cfyy>O߂ #-COdמ7/<yλ6`t?>,i-?\\^7mW@^%(]P:oįe=Z.[nㆾѷLC2#8bn('W^ 8\ ש1:p8Ï"6/;﴿'az~D~4\+޺[74wmm47xj0,sDl#Db ǂ⣃SǶTO=uj0 !}4 D*v (,rY[?'⣃,Q0}Zo9[}qF2 }W]ɒ S z嗃:5|ScujqJu 8y FO|p ܷ%ɮꦄpatj?jaORfҋho^YzrŮ V'rĪv RJ~ֳ=Toie-v串(ñkqU0nM'Goxַ(%уR5|_K˧z[?ht[ SJ4*Bk8o^RUwg+m݈s@{.wkFWO-fՉ>yj:AoI_ɏ;x_'UU݅eAJR&}NhW.~qVVVԽGCw Ӗ|+ٛZA{i7 }q}&ZJEN*ʞm٣,Z3x?z1u]dTAԊuE?2TSؚ{?=U qdG Ni:nJ==!G5`nj ? pXWfm޼ %?zֺQe-ҷԷ/}˙3gٳ'ӧ;^`ǎ7ͳfZ~ASyias`4SSruujb|57QՒ+ lI^+¦zM bjrSmCPv_|kוMK\bKE|Ϭtk;E_ѵ6,k>^ǷuuJ GIWx6V׾>(↣_7%cφ(睤>ߒ#byfKpwգ0 /кssgYj,s}sіq|z-Ϯ~xmgZ? :.#IgnD -)ʬnL[k\7ϋWVGߵ,hک͉Cv_zf Q2 D)lkUaؿ8I_ɟ^}DS\τ]x6FP+y- {r7VulmbQ"íN~{!e*WG|5:M|ú&׻[3`M~(>Vv2Mѷ^;Oz }#zD4ٙvZ1B7`<\b\XI^M ݷ*'gӯ"x?[N=ulǪ%S#~{|/gw{m,]e,qTFe---Sq-Sfqs[gَa79E<#7}[ׯM{rrʖTJ1N{ !25`%[EeGx cC|ǖopNGꎭyV^̀߈XqMWt%J_2H|ooiNn6>mZSokSr5J̍"7'wڍ_~p6̙sJG'--ۿo` ةmn"&g|BS!t92׍G2WH>ձ>?0*yϝh1TM剻C _BTK]Vx([iAJO[*K>J~\tS|q[`nk%_1/J~ UvJ{9-aqjU= HX=c^{e^-냫[(>q?6zݔTfY_ɟ˫M`xě8Sz 1>Fdw4,/nj}W=sӃWpSD;]jyLmoUFQ}/n[[ARRr-y晕`TpAfO[ rsۣF )Wﰆ\ }֊}x`3ȂcbLz|Ksra߫t;ūٻԕ>}媴uvَ?'\Xv킊%.) _kdcjZ&_LJL0Um냾2ݔz`ꂿ^J)_2U>J#nb.T򁏿zw)G[4^NcBꓱIҶHJ>gn20'7\kݻ=c˂}rYfxb0L/ F,I2ͣ8H S=/ w^S>;Ŀg`FcAlbL1|>պQ[ooe-??q?ėհҜ~iw3fdfxc}WZwyݺW___|G~O0ש\\2pr@o P9fCW|8>iDmϴlΏ"5- _3C^a4=yA]m'k Hxٻ~',4VBY/Caӵ A[ nJ(@-iv68ԡ [aHGAZڂt6mܼ4MN_=9=\/9kO~Wܺ?|O/w٩!m~t>y*R_w=UH̓zB+kHa՟a͉- E,*LOLr©hí<(ve󙬚~Kv9|%|[/2^OcG8+Wnf+î?\v?ns}aj),n(5қ.ijj[^=/\3pl0(/ӟ<'+0왶j%E*˼d~FB^ye4o`YO4i?A:r1n6=gxfGU7H| |'-e|췞?[;6ys^/<Ѓިyd mo{>w7}}ۖ[n vr==O~Ou.=o,+~ Ř0tcVnk7[7 a˾-6/z5];{zt/^9}Ue}0yTeu}mnۦnH翲&j]m{2-E-vEw|;:/yG.χ?餭[@zosˮf@dYݺЦ[V> n".fhY\y-j|]0%5mzb-Wfn{*=չȐ~0d$6%/S?>?|G?>˂>^ڪ FGգ'`8xzo~_i}o{>voH E7!V#y~>[vg8ٲ >[[ous|≹rau֏o9zr.=5@$0zghwއK+W@쬯/;a„o^ݧ?kȱ|ðNV7.,?t + |ԧ'R3SGKL]Mu]vJER-\nCٍJ/7nCʺ{3y_xľ:cG"i j #WSk9? {j4ٲG>[Ƃϖ]2N{yZC(TTZzmlq,[&NgϞ֭sLp85y;{j :#VW}~XOpK۶m gqFG9`$rl --@?<uaaks eZF~O =$E\~cƌU0 %|\{7hhh 3`G9`$rlyhÙ3hnaa{м!{ 84 ~RZK%O}fH-;`yg]w/M롚@ox8tl 1ϖ-'.+|f9oVo񶷽-~OA ;7ߗ{|y*wTXg ``;ب<bdǢBNNNw(QaX--!r„ Q7 UQzo>l}{_={ j߁sU}QXSo"џO>[B\ϖv ĕ@erc!egyW_=#z엯[o^`j;@ox8l q5-"?c_}:CSW#03Q"K)*㛷@,444TY/G>[B,ϖq|*|?<zĒ@P&|Qo޲`{뭷>ɢay){0\|ϖ߸4 Լ‹/~SMMM)߁!N] #-ӏFkxC6Eǿ `l 13?[va+n9*)7{~OAq?ַV1iҤP__?{9+ g<23ocet꒫f0|x--Ϟ=s٨eeg~ѭt)߁|x2_I?{eoyp”ysu晳 fs10=iSMmY_Uղ1 kR;z뭰o{ -aϖ;::H{;W]{m ;+|)qОS0z w CI`H~^Ok0ʝyv׉' 5>/>bc-o̳0,;;Wo9w='|ٳظ1 Ȑ2'>tl `7wy>u/-! DN0d3\{ݴz; 0z b>8䓿_m۶;߹(q ?ĉϟ_",aHzԼ‹/~S t筷'o){0x$[v؊[n|^o;kxC6E7>+++cO%}韣rԩ+o/yeΝͫKol0}V,0d^s;Gl`޼ΜUP0ƍ m߾}[}6լj~vѺcpOw/,\yŢ ^{ҏ'?igϞƍuη?I?RYoRsJ:~Miw;wQֈ"I;O0ƌ󗟽?[K:uf#۶?w(>}U* /|oE,ԑG@T|sL"4gޟWu0[q| S~U|9s0*bǎ6䧿ٵ+*5 >Uwɿ=-*?'u0*ݜܱGcx9C[zA07ټyɖ-'=tΜ.navsٳeonwG?)lO?****uiMO9;~[ ?%wv7,Uɕ;昨=瞛{”+_g{ FDSOzL"d555uWvI`*c $?ā@q 8@H $?ā@q 8@H `3@q 8@H $?ā@q 8@H $?ā@q 8@H $?ā@q0W Jk襺ҼҺ֫䯮˪`l{`C$$`S~wZ]\3SW<][ݟ{wm\hnI8<毠>L^15}3Lpk՗'d8',\cOžv]xBjS},j;0`yͱ_tKkolŲ3k7m(IDAT9멺ۻ\^q5%yo}+LNmy9y%5{^Z?rvܰ&4ӊMMŹ%maоovmp3f]bA޶ݾ/elSwYy}EQwgx)]=u*NkjM~/mLv.g{U s?aꭻwK=浞zjiۑ3m~vxrGUX8t ފ7K'\0/ N+,ߖIvYVN KAU9ז//]篮^j[KdW]uI2{"YR]WV*(\RRpS&__]=Ĵڨov߹<љ-)*  sriQp/f°ݜg_WL܂DzvU+f噅f פFINiݲGSj)htxOeUp䯾tagJʢAzo/!bGmY|ꦦ҂-%vԔFth0`YYh6W0d}S|fۗw7b-gں⼖-=('dGh^s1&$y%U&; L77n.bjĴEK*k5MMM5ŹA4ϔ-jgRc>)-W'dNy[]]po[u4,w9Yue%y>6u55ES ;kj;=64-gaOB 7& 5joZ2p펦Ԗ#LnAA&=={G֖&2vo`A** *}nϞVj[ަ=/]{h%;88!wnIyumcSTwX83'zw.# ǚ.mi^p@JWIbnQA=sӂ`T)(*FS\+kKzTi/6synW}S9Es %^&r-^^UtM*JmV,]"Xϱ Jfv{굥E,sJPDA wVgRe%DKԺ|O-(A{k+JKNN!`yEKnWXAm*[ ;!<#D_pم5-`Ae7boFVzΨopsZ!U3wZk5.Ookl1%ҫNNcbtѹWT9nzeCOVSSS/*ʝwgC;sT_ZV[6 {hi],g(F* MmdncZng xڼ۟654VwwmX:Y-ׅWWF7+LdMCSvIpO~sY0v]iމW4\$yIĬ[{:XdUW7]$1vMGй:!M[^ګLܼer9Zv=9΄]߶pԜ-9޶>\=Rpe-۳c矞3uqu=ǹpDNM谽,S~WS\zK-_3jcrXԹB.eOi%`y͞]nvT6!c8+- ` OqumB>C;>1+|[Ș? FЗC\$/Q,n}֔- {.Q-n_Aœo,>46F?ā@q 8@H $?ā@q 8@H $?n^CI`pq 8@H $?ā@q 8@H $?ā@q 8MGf0Ĕ1}ˣ—[׽0Ҹ";藖99Y罽lyszmF֌0nЯ&l?ā`Ll`kƪf̘*`7xMA֌Kxь USfȺ/k=b*>& w@d`l^2Rӧ My9A/l2\ig !\#ٳظ1|vKuؘ {?G}:"nu]?*_Jښ-,S{YUSf=|xtHv/.ʢ 6} Qܴ.JHuqe+jZqɕnn7^4ci}Tl9]L6TG'ut?׌_mJ>Ps7r|=t^]4 }7vzF )GݰysS2P8暦D,]*>rqz*Te ɕM J x.xo7v-z6YYBY5wx #һ˥/$h=h!EϮL zc\VMY\SiD@;oWv밳eA!h5 \ׯ|} K c7^sC}xlظ,8{w736ZtCŕKWmۘn3hjdåfe/&}eϵ6Ha]l,Kc(<9wԲR-ɧ[|`Qe]Ӄsݘ~:|` _ע!Y,IC ߀䯭){2fY<!`5M&8K-^5#a1 3jjz"^0Grc0>ir0H q06` Fc $?ā@qc8IDAT 8@H $?ā@q 8@H `3@q 8@H $?ā@q 8@H $?ā@q 8@H $?ioUQ"++6Tue%w6>\YS@ ]f. VcdEU{z C*dETDҼ>!l֛}mjS'pgyu0ZRҺԗ/}_pµLɨ,{8Ც zM S zu@#`jTۇÂm6 3Li5z >=>o"iA}y2+++,*mlX[]V̝5 {5!;s|vv[g҇}fyqb[g`V4E*DDfY"mP*5aÝW;5Ѷ5zΕnxf_l/~^>B5qn^μl= %%AoU%3sf%ʪی\jtDVMyɒm*WNhsMFmO4kdDˉt&5%pZ;>1>W@S'MO.()+Jᙓ/*m}>wIyiYYeu@{}H2r4ҵ OϿ(7#UfBξLY|IG]|Yޠ~ 5K &8;7ܝٴ{;<瘉Kjwk74a睘H} ;7zy1J LOzĠឫg.j>s.7HUO?k.u <%<;/?ClU[n}wܴ=1)A nOXpjߵ={Ud* ?'g^_t33Khr>~ Y7=9׮߱'5垗vjfj7JFs& +]OhLYq7\~Һ5%yQmŜtsmg|M,N5D__Om޽fYE}T? Hr,\>3Y}q;,i@ J6>uM՗mU-S'}3m^3}Wd/m# [k}Iө\/XY'Z/B|6 3/+8`~;篭^>7oBtysKkv8=ucՅm6ο$hw@Qy}6tHTDuřݘ<ѱyKʯ 9ŅͱgW\)JJj~<}Ŏ-X|I:uuU ð /ya˫Wř $ի){{z9__1|5 49ao[%bMPggf _Z?,--%TݖsyٶNGμ|AvJ?z~ ۚn'KWYhy-V:.:@75s[m0Lߏ󗗴uBnk9;͚YYa,>mnђDqM~% s0AUY&[]"-GDQuSc遇ԕ-']8$٫#ヲ:=sD0=îӻ<"YTٶmoxMf<&( K`l겢d^" k2;a~쭂e[Wа;osN} J}IC`4S;1j/eU. 1t˗D^|Y^04@%^1;77:`0dQ{k˒cι ;vn}?Z܊ׯX8g{mu^nQհŜh1_jZ)כ0R_XɟY`Ӗͦ਱*% r;캯#ꫣ%RKҍ6_|מT +7BWKҮo;?^Ǿ;1zv׊3sһvyAf?S[lC0sG+S\iƪRɟ)uqDceIRhrwu|y/\_WU$NѦ^[UJ7{H%ԮbF$foŒhY^|Ц>M.L{ͼQ|jI2wޚԈ+wK(,4{ɚ +2,,N׮nXn[Uْ aUPV]"w߶9V.țxt`A w<겒d*]K~ښ 'ʷ5eQ, jjj jAּ5sɁ+;'\nA]㯾pڥ4tkUkJfnh9nLdͻ&_1W.vɚjN%ӚoՖc]u F{r\>}6sgߵc͒ĬUXh~+vTb̘aR|I\|AB{v_1|sXv_=>d-۳cM3uVu= WRW͙:Ͽw5'-{zmgv=ׯ~ey9]liFtf߰/OsyjɟXvgq$16`UnHf._6b?FCdς9A( Slʼn!2'}V_`%k:mϙv[E`1'ā1@H $?ā@q 8@H $?ā@q 8@H $&;Igā@q 8@H $?ā@q 8@H $?ā`'?6n|ǟ}]v0"M4c=餓 f1oSA^l?{W?S*v_gfǏ^;|__Ouw0I'}|駿?zGгїٳ .ܲfv>}'xSN `Djl|'cݽ뫪v؝uI ?/<ۏͿ 3g;W'FU%_={\~Hz6&UZbb?FEԆz^X޷oߧ-~뭷Mcxگ발?1cFYr -?|G?>Gl4%gb &|{jy}/4*߾re00ccݽ? ^0=97<ēO5ګC3g5FpIDAT惛jT*]Vƍ uWXغuۮ]9FSm۶pg~}}+=?9O{O;mĉ{ ˏnz4afCCCTy{S?șrl?/G6Vov k̘1 fF円^0G^}<ܯ|)|;'0{wgeر\ǹ'L e,eEiX|;|s=Mczc߾}moN9tΜxA?O o{X޿{}~0aBT*{Ww>s 󞅟|a X%l|^??O08⏌?>H?=$oa `qgYw .8Gt{đ /75K_nɗ[ҧC_Wݩyyu8C3|Ujg HL0sɿp9|LvÎz׻?nܸ`̓ݻ# `Gɠk#o0ظ1,={=O{Oc&۷?rrrؘI&MC;6k3fC5٥;r抿eW;rûP;e]]a}uK:g{=`Fl$DNqqGG<1(ђMg|0*<̳j_#khhX&*_0<ܯTD~o(Hz뭏(Zo){uYm>qE3.Z@=_=& Aߕ|Qo޲~5_M?geeuYm~Qb%3_57V]5cRg`0 bSP˛ AY1':+,455-ӏ\}p^ Gpwn^]rլ`l kF%}IRcUSfqk=/S~w7$ޜCoD_?tUwL4),Ϟs_/ʾ}j?(\ =i-+J?g 9õ;wFƿJ0#r '/?5^W5mPS{Ü`iU~/͇_%o,ݿK{#ֈޞ^kk67<;8wq+o/Ƶ߿ȟr׮] q4v`qdv?N2g}SMMxٳg?)zLyԷC>WW[z]{5$)TּelaU3peL2ãCڶs|qqPUHܰyuQF+\xFVZwKirV8>lN8~8|߷vw5SAEߞxͪ³l௔}}y _Y4K}6kyK,suN۽Ey456yKWkm0d*K^_5]k-ھr#m_g£+ǵ}hu -[X]]I&w'tR3͛{j^^ }?k7yٲjww0t @g`^***saHo>bލ 4<6on V&Rg\TeK]GU.N/KMW֐\Q/r7v-z6YYBYߖf*4eVR_.}!@YE .zver\xww4Ҫ)s3ߐFO-˱2}~77l^Y2toD_7U}vjW Mn[:&lzHH W/R/ɠz鍙|E<,57}GOK~7h/HZ_JûHWo)̼Ջ5AØ-"p+;w-e3gvC:6\xq!7rss󾚶[4~!hwC?6;306 zc57ԇ69ȿɂ7~wc?;lE7Z\tƼՋfiÀ -g~TDo'W-ƄߟP9ci`Q(+5#\umuizJeٌs5vzԳ>}n2UMᐃcIivPΰto7'ajƥկ6]WO3.Jd -{NM-CZ9ݼos 5%/ͭ /ڕ6uZ1aa`36A3曷?{]v)'m۶w.DvW;6߫/7v2eb{&ӾJzI ;KIQl-'6(:fv&l>$_خұ_d38yiP1s]tWfJT[qnݳg\eˣW}sciy<´c58;%_nI@kIR =_jpsNB]i'UL7vv'=` :NKS/uWfa5ӌ/UP]_Um9\K /7<)]W^eݿ'x'z9].uvל[\Tld ]uQfk=hTot5WvNҢブiY/~ᚹh T-qxsAbiKNP_6%Rzɕկ^Hݞ f'چՔW`Ft%f}ybjs7=8~wL81H+Z^&%PLO\[(2*~~{\.>}Ndp͓5tlNӈ0F94oRĥ;yjͨ׭R8?.Y\8zqE̓$;3sͥ8Ahffhg7O6gZ3 .J;i;{[ ~ﮖ1C-.iƌ{MQ3uh]k/nwlmDr6_mN/Ɩr3^t26O6ᮨ~ҲX%3,03yr:c딉WkRjiR˛էj.fATj2|~t!7\O͚UpG.۷SoH3gDmy8嫽O^~yG}{O9O7;br.[ts筋g^kQoN hЛֺ^o_2l69m۶E38#Ѡu='ٳ',?u k{PϢ¤IN =fƌ3`fTnhm >7Մ?a! ïWA h1ctݒ~hoȚQ&_# `0K/uܯ~Цp欂)ǿ;ӧG-f}D| 裳gώ>셅`?rޗ,70ޑ O>麨 =6*/~˨plߧóg? G{?XTH$rA彂fvZVSSS;^{ew @g_ݰ𗟽_QkBT'vtCT2Y ?锼]>#8xx\O=c`\ kмf0}㛷D3>ABD~wː^ $߿; `d8>5/5_dѧ_ pWo(U\0J>p7o$p0=_E? v؊[nW_7x#F{|aQrNrN >묰?8j`Hٳg/>ُ>5F={|y_Ϟ|w ofgOwC[4iR^oszW36~eك6E_Νg'Ϲ`޼ΜUP0ƍ ׿u?{~瞋6feeެyqK/xSSyˊysuf~1c `Wjj`n^*^|1,\G]ڥO~Ϟ=`d{~wG${ظ!|}ܱQoa; 'M^|f|׻^|w$~ڻ_;JdgOΛz $ }C> / a˫,N_f?F|+o ^ ^VcO1'@3x{O;5*oy8 /l`O}1cƌ?Լ }7߿jpP bdҤI瞓<17w#JuuO/߻oG/i{<\YcS>$A"7'!7D"7!n49릇9׮߱'5垗vjfj7JDaE}S[ԲU-S'}3m^3}Wd/m# [k}Iө\w 5V2kޚhy&X,lNqH-ŗH_ՂIz_篭^>7oBtysKkv8=ucՅ]wU$(*4ֆuɒꚨnX<ѱyKʯ 9ŅͱgW\)JJj~<}Ŏ-X|I:uuϤ-(Kdihqfa{C/_nArr0'95w6{*mZrN09Y Am4(,--%TݖsyY'im ;P†em͍w]ҥ +n, s⼖P+U`cZ;ä8yI m'd춺Q'feEK*k5aYSח/aa b"œEi}DKU75Cc0[NO9uܮ::,L@k.Hgm6^Y+<1( vtM]cW%٭ OH,Ȍ/ߏUb[wMW^rΩ8aZɰ/i}Jz="j_aiArT[Գڒ`h9BKtcvnntaȢ֖%ǜsv6nݼ퍑~O_p~ܢa9b?Fܼh6՝5]G5U;Ӆ%G/kOO1gܠ+ OrC*9O=/z~ sKʫkGkwX83X@[Che{:XU\|_03ŝ.h,)y8}@Qzׂp}]UI27;3nBvv C0lWV%^ y%5Ѡ?=!&2~5VGڪ%ykR#&ϯXժ# ˶EG쭯.M^&e gkW7Xlɂd0*( .Mo[uMV+KM<{:Կ;ZnxhmuYI2%Jj~?F>IDAT}mMCφ˓Etcyɲ(ULme555C|n훳zWu ꛪYE+9 +F+ ]zOCW^Ruy'^^uMiULGԘ +LdMC5~}kiͷjK N1㋌m/UErT>\z_гUtofIbMEs4?;K&m ݘDQ0V$Tٱ~s2 Yb{j~m̿+:`rG$=nώמZ7~N9Zq;4o(\^IK[W_5gVO?q0Lڭԗw`^-ty|NЍQgz`9- E>\05 _#> 80@q 8@H $?ā@q 8@H $?ā@q 86{& @H $?ā@q 8@H $?ā@q 8@H F}}`{۵kW4iq{I'ro>HOnu#cƌ 30\$h7ݴk{i~?G'z߻+ M()[_u߯0a„o^md 0l;~Q+c4yEg?K]7=/~⋿{W_K/F՝3g5惛jTr\+>s֬4TǏ?#;='N=` Μܹc H30 @/ Fm۶E38〕?ݻ_CҾ}OۿAI{i'NܓGnPLĭ0\?Z 1cƴ mhm@3=0B>82;*rcO>T{O{G#<2 />Aoݲ4,__hg`H^M}Zb|9#8"=O8w?m7q.` |7 hCi80p֬?BТq~g~ v6O='+rjڝsکy'=HE~@gS{O;-*?%ncy?'xꩧ7{;OzIa߿Sgi3~__7;{ 1f~O??j K/5n޲җ?St}0„qzg}6OWq7w0KSOכoygnX#;˯#'3Y]rgϞ/p˖_ٓx'=fYc_O<]_Un ӳܹ[^=*ݻ7fe455}b-ߙf띫D@AiiO~bտ|kɗ&o_1O@#CVVVTx,Ċu2j߷^_-6ӣ}>h[o0$)oը?_3F {O;9*?Sap}欂',#U׿ &LbAqyK/ʷ\0w5 Ĉ+eݽ? ^0=91`|snݶk׮!36 m8{82;tݒ/_vĉݺc __/:_(߼~#1) Qa ̳j;z`$_CCCŚ5Q|$p7ofn$|ڇ6meogEY3.1->2BSS?^luYl $^`:zf5Y3fd(dkJ~ydg~%W*(sU3g>Y5%:U}8b5g~yE3W}k&M ˾o߾`كC- u0C~=Q+}g\T]CD#1{hӦ[V~skw6܍`/ky_/ cqy;+ R2ol06/9ćt[y{Y4r߼eEõv I@ayGQr'-]m_[A :u>yЅTfо+@ Gfc)S}7Ԅ={lٲ괰ז'`O?*Qw;_1wJARyP+ 8|ß^V~gn# OekX`z޸OGWMQ\T| 5oI-OJ7[ s賫i 7.MW\v+#ղteY3ڵֲ+Hܰymw5W;]MU]>.֍<7?("ctwҤI{I'T0y枚סG.w_Ok^-f3[/)X\}C6v`W8`ߏ|Ԅ\\IDATe ɕM7?7U}vjtg7,nȋv,|, 5Lή>t6£6?^Zܴ2T/13 'S(k(=EvmbF9ś[*=6ºwzԭaP3"+y~o͜u֗_y}pYH.Q/"+j9Ջ3s6? WUz T~;o_%,JV pу3kk‡Y{ER3s)v9m cw $3i*u& 623_kƟ cQ7$[:0jmƩe/^șzaiz]Dj![.h=$ػƖWχ=vo'].uV (-ԗXC;D]nsMK5.i7V#:&jBtiICF1V.auV)à^>-G䯽-9~oiD~愿JMZP:y0fn_goo>u'{۶mws?xw ʪT ˦* d԰| qoH_[zԸʲYў03ꎮ_ .EK::蟍ݘ d3lMnxQDsponLi~I25 Rޖy/}gp[*tV]ԏOf\rH\s}Г]{Ѝp՗;ol˽[Ji_%y}=8A4ޗ[31L x nw:JM:<ܫ9vZIuf0bܿ?L2w*kq/w'u O;5;{r\]US0\ w7^T\ԷS2nSޢ+mLح 9Ī)e=T`F챯7O|Vzn3}1R9rY~wL81Hq+ly4N' 3@6ϳh5zUK!_ge9]W6RC,s1ٸ0þ ͓d my=bFqE[pL_}v ~ilc/?=zӈ&żx|>++O||VAAwfNXAv KߞOfiS+HN_f06')8e*_Gs6O  #pWT?qCqbiY[2#;kuĉH YZYOu5\͂pnmE y8EԬY}>}>h-361 7O89pe9}vKZ7nό ZgLxwC$+U&S+)}ѪF|0L*eפ`rM=뜴[첟}<nL90+Ϙrj]@mN@ Rԓ>ŕ'p|+*8L/H_IEnLv`kk'< ڍȿQ_+j3뻻RdQzݻ[ '!ÆRMd߯߹7f':}?@zGb?ae>xӷv[@!Jn‰O||$'HѸF~ex]? 'm޽{w@6É'\4OEE^ŭa޽Ĝ9s|aAiddw%Kpb~ ysMYm?/?<H?_x!x˛w '#dss}/LSȣ:~Kv}goʯ~\o}k8SOdO>NPRҋ{߸kClbٗ(.x45>G9;wo|c@ݻwq+;{'`fNַNl<sGՋ+++[*믬 HR2zg~ïмw~穧56? ow 4oS77M'6]{|@p=/\YYL3o]@g {oGn?z׻ ':s~>f{ }Z 5ѿž=0?߷ï~ [> 1ݒguq@5 J²o߾]Kք_Iɜ Yżꫛo?Il#.hܸ)݂m=3s߹iy//^gws??mp9o+jkO;S{ d}}>}[:bC7c5 Kș5kV>~ȏ A4f?̽}v5_#rE5tkxpF#XSYx]\հwwsՄ 4'/h`` <(hKo[mID #Tvʍ#SZ r0-}#wfm[buv6*ik9v0wgg3/;\{sb[V_ WΎ_A, \ /_\ɂ&^」]?fÂ|߾SlmLD%um[VΉػ+Z]pᒺ֥APzŪK״5W%e%;~;(o__{=ٗ5W5lXڒ˲΁k*+1`[6 rF8o>|=VJd —6U5KÉykȠ<,䯸lyjo׍-=p(eUWϋo==5eEEEe]Z-H|}Ս={X[UcY@h(_qGKx:1[OkmeͰww6ěv7W.zG9KWnn+?_ Z0r9wtA篸w+VI3b+mܶ{`rUgohiE졅g.X~њfc? lLkI $?D@Q (@H $?D@Q (@H $?D@Q (H﨣m $?D@Q (@H $?D@Q (@H $7>uO>gݽ{w$-XpҒNY:# R~ҋ{{.Y{d[| '⨣Â/i?Lً?+Sxm۷=—%%sgN:]ϯx;`fxWqO>M_ڞ==m# (g~o-ᛇ~ܺsf*#LPXۏ<թX_VV3\ǟzG×: w}(wt={?wl9wx*F)̙7&&(}w^z٧OZ_j7͚knvkʏ9?/xT۞ad䗊G s&H E!%T,6paտ<<kMϟ_O~?H8 ?W s&$H E!%g[:cX^'GqDlz ֲe[n-#L"³ߺ/Й+VYQQ|Y8=tǠ@]? 'm޽{w *F)̙7&Dլptww}{7@W{r{{?mMlK1rN2usW7e?yM`۶{l[TR^?ܾp4<nQ$c~_7y׻L;IzݭܹO?L%_. fT;Dol_em *F)7&DO$څhسgolx0Ho?xbeel_ c`` `5^~y8寬bœ|c@@w՟yGMEEE4rYE%~BnۃӶsU_59e9AK㧶l2_(Y1FY{OY^d_~_cOlկJ0mm:Y[vvg_uHo^9NMĞG_t?uG:7AF6`_]1r6O!+oǝ'q=Ŀe64bpHNmkkK~z(K'y<`o=c}}}KŁ))CqXbdO)_q ;W֫.Ͽ>>ٱ3\Sc^#({-W_}+kw=\|S(75`zڊːñ`ɣgٖw4m)iyo,ҙoCt/}eڭ?īAie Y7Oӗ,yxn?~Q볱g|qk;_MQs['}' 3<%# ۊZm\c:7Û!UέԦ^;}2cCڱ g=UQ%W2šr?'61É{` lj:_`>bwhcroWSn(y8dG}ގaxoGBFsM<)\ 9UguKlǞfi-Ѹ2L9lZC4xuLpOTcR?-7f{i_eSޚF1n=:ǜ3dWaRl싫kê>Ae.y+.e׿/>ӰcW; n{|කڿL<HkP|dG@=:.|+嫝O%=}rsl:&2 fs#sWj3!ck GvZ4<`7ei=MQmNF*/4ǭJ1Q³:4|țG33$b=w_pyqL>Ї<3ȳXau/7yi}?Ԥ  dL[12ҝ{J؍q#%nKidJ S6{!t⿕u%XF~p8v.t4 7st_^"Ft0^o̴D`v/HnMHl"^f ^r3Ezڬ*̈;b_bm:sT9"oHe4onߵI!`T39oy2JuDiW{N{а+[cO H⏦_}Q>|lBjS6=/e&N>yVlktzDɇz ?dV>Ķ~cűqS3V^Ttg9%2V U>(2c(ϱTxo0'io4SK3vb/Tlߛ>Nߘc~Wg<ג/2M4Q6op+Xvh@^G)@'L2:kg7yyZ? uw_0mN<"H>a)=SM}YGwmk|5!380`L͛Rp,5ubf*Fa3`줻W?'|ꦯ}mϞں~ܷ#wuSʏb[ӧלq?13WU-_ d!sSIJy #_T܌Kd9B#fƶ`7K uaNCd97i6^Ca$6.۷oz/KJ\Ϝtһϟ_w[*j) 6c@;- ”hΞWW]6)%r9)${ve/3LuYEMwDe|D4cMvc8^<d$鲫hۢNu^ء܈[;6W5G<& vGmO<3g<5kV׊5=wO=}]F0b;.Ftc/$ %śSdԈK[~85b4cgO|ukпoS =*!.UcCXƛ M@OGT'yrKd%јiP>E^NJ1V?e{1Qa8mޞ4ҋ=IYi_zqUZ3cÛK\M+'2m1Ml;+_@_ (If/vR>~Cf=v K/ &%?56Gg= hhiDDGܖc-HUgnmO98~|MHyx~+6޷7ړQSSlpؑk3{^e<#Z{>G{b$Gl%y9}pO25`CsG,5fÿ~3 šw K2{dJs $AזzoC8ejUޱ=- 'WĞ_i[n _m֯h$c^0Fs0qQc*赍7v4r6%VVS|gl΢ mR&}QR3{Jŭ^wk5s~_Ħ~ ۞aw*C.%\wI1Zd9a}|jRFН?sə+F;@oq;@+ۃX.7xcgd$%0S6fUல_j1+U2}iNH5{6n .[&ܞ3w_Ÿ7'z_ ӭ'ܹ67Ƅ߸>NzժRk?Ď:zN@!Pr}kzҧz*6=~Ȉ=kۏ8Ν?e>xӷv[0}ݾ`'ѵ+[_?p*Fl֗G /30I9m?aI`_@tTVT._No}I8m[ݻ$1ݢOa,Xb?tL\1(1Xc&9pfHaoikt| GYOcۺ yG4m:`X+}}r4t:WmDCN[1x{@$@,^<;z{3p6A#_>7N,~{]knyhQT bϲ_{_`RIO>9$;~o[c?bœ|cNO{\0?\Rqq1?/~] (X;wn8Obœ|cNC۷?NbD[pɧ (dN%)y0g8``WV6(_ `ª_cO>.iQweh]~_o|c~&J#9Ɯn&E? j9DoSp6# sZ s>&EDͲ~'@@jp_Y A#9Ɯ>^{ ?Ѱgt;a"_t)W^ (Lt_ri.㧌DEG s&9}\gkypovSQQQ""%K>'%?zG&ny8IDAT,=ϯx*F)̙7{Y|˭/W7^qJuuUW^_~˖||y{ q6]85o+jkO;5v:{3G s&xG{Ѯ-Co tQG (? ^z/1d[e˾mGuT0-I >Ȋ=;~-o 9是?~s~m{饗7|3G $+?9#M?B! @OQ (@H $?D@Q (@H $?Dh`` 6?D@Q (@H $?D@Q (@H $?D@Q (@H $?Â^[4V}G}ˢzlw4ʩcO9FdeKoPr(Zۋꖞ}5T ⲲʚM})v2 w"Ԯ};@*:;ںMy7{:O;ցm`FRs !VH_Y}@ҖAյŎm纊LO4Cu̿ ްbC<[pö/}/s-kʰղp趜nkMފ +.Zڛj:W{E7\5 -ZK(Ni8GOWSeQQ-'1e| Ã%1{1LԷu6ԔUqUq_#rck̡Nv<:35e3\Ş܋1i^ԩK=^;[c>]7kLgq9{Bn}v4yᑸl-=C3䖽y7޿[{oX#jzƮnձ W\vㆇvW/^k=v\ڛ{n<ت|̎{6lroDVgSjRo+g^l_ܙx!kEoqU5Kc?{5kk?{lC#-5&\9INrom|<8q;\8ЬsYsW&_M])wtwE̖5KzXP8"mͭs;٫nrQbr 5WcmMxE؍vH#g\e`UiqN\:/uN''>.[ppo[Q{ZjNTE_szk|NX99K%Kg/31r UػaEC,,~fGTu;ǔz-v<GXF + uE%Ҷω__9:ͱ˫k)]zѺJGuo/=bHsͻt muAI]Kk,+bUMBV]P8ǚm Ab-+ ,k=PU^_Vzi<| ^sVnP؝\xkӦ}8(+1+.69@gWo}h) k]"ݾ5+&Q; @Wc%,88]sZҼjGwoppJJF]% [ZGKT6IVz9ь+Ş欬:Ѫo{W"\U6J0AuUepHU46Ռ,pGU7wtih%lޚq_\טhz2hWKˮU5_ve)܁3,(:֦RR۾)6l:؞G(5wtlG:u^$ouiww-ςQ4ΛϿ?98oϦڪyKv3ۂښV&D?b!9]UuMM][!vtƃī5UA5;߿ _]}gd tMM3lLzR{cW7`k5bUwGxդ.lm,+>e'8RʽӱϽ;LVY^dȾ O6ժa؁{+%eiuAw8MT6vm JgNn@*bO ֔{ew<FH(ooȠJ9ѭ싶v4֔MKwө8=R"}{}Ս={t4VŇz^^6/oOggOrƞ7?*njk Vֶt OGc ڜkXSvx`qScmC9o䥯ϪڦhzvojYv(A錷ij]mP'-Q 5mW;>wm '^ޠg2{^ܾ2ݰoDt6הK78(eՉKvGPfkFeT{Vj:l4Xekm{udU9ήp˴SSqN'yE@Ϻ+^#1lIDAT¥+7v׍x:u.ww&h&'+]h_su^{O0vwD{F.8x` `VϿ챌+>G`Su)+\WYGVt}WgÈr(iκVrKXܵoS}qйwVnhK9sZ68Kx:rQ_bCK/VW2򭞶3kh/{X<79W<%Ww5rˮm=MU}?oh(O{ɆV!N}bRŸS7wnZUYquQs4jj{G:{/_\qξ|Ҋg.X~њl۽3֣wu+ 9bE6n{`+_–5K !Y}_qW,|cN|K̾>|1l, Qu'<7phfq }cb m J ؎ו{4w3Ǭ{NiZyźbŲgd69KvcT{Jg'KG/Ȳ+^sVL9ԑbV>D@Q (@H $?D@Q (@H $?D@Q (@H $?K/ ts`@Q (@H $?D@Q (@H $?D@QPw[>S?}ݻw0Ν{޶`IKN;~n0 O]?IO8aw/ 3L9M~_~?ܚn`JvaW\/\7 dM7f'o|SI8_l۷oz/.9«.x o+,` >g/y1|y}=#IoL@#+ZRc=&Cپ_y憻QTTNaAAƝw ~b?b>+?2|LW^~ŦO<;waXr @4kmQlz?xr_m?fϾa 3&{䚢 8䞻r5Av]7/Gi+' .ڳ9FSCƝkhYHpj{O1c֟d+d >r'ם7/x+šFUq:$W\p52E:W\pY+]H[E:}- :*䯿?8锓,~}VrM״;V~6>ETEܳP6F4Uq&_q@hRy}L:d'Eۯe8l¡TRKrk-\蓕Eg2m ٫wgOM$BZ89S!%vKn%?Hf*\':}6T2'󧱟3Je;3ȋO%d+wV~y }MmZV3`z!o#5bϣ72-Zt Tټ!f5O=Px{Z;G,˲̑l&2G Jc?aYޱ Mvݽ)Pcɚ֥>Ydd˰D6$4*u맶b^&iל7rQX2Ey s u6F1y듸HOꃞwYbx<3mOǚe_a`ۯ-K^U>^bkb#5v={0Jx}m0ÆmI?.Z1mpV<2;[O死w>]MhH[| HabqHσsS<:VidkMR3ݱ t0Kwֺt'k|V DGLI*[{D"+/Sxֲ1nTeO|"P{{.bSuaX^^;/3[vS0oxI4B'bFL4% rIٱp]l7Jw׺RȨhjh2ΎelY@[O痉s<7Q[2`XδvWl>uW|xLnXD Kf4srlmG߉:rUHmַ?Q0ybXx2J=_ԳV*+ݮfXf1Yp"H-a!~G9vv!$輖߄&ݱct'}̪gΑҝ.3^F=bhx# kƷ;D[OoeiؼƏk$kl `v:6?KϜsť\gQ9["ݱm0+++ ^o-\XN-KD8gasפ01jmcrX ͽ+dwy+F6uHflp+_A,#_Qj e>ѝ[Nt`yu5euoZ̳h;K9:pJw$|dїIVK#42X}vX? v^SԺDJ=t塿W2>߈[^\q1ުYo}PwފR~ҋ{IɲI>Z(9cʎfffъWC؇2X:'.^cݽw8eIDATq3U>ďz7+|r> s;Ƿ{wN2sLֽ\vima 3>īe!E}ď=|A3樣 SHm}'Vy~5+IY3ϵݰw9R|̪R=ӽA lMLFz`E=vyyn*|9"؃hh7xWlTדu2RbRubyH^I_W.Kh+xŅ篝%wUy4K.Nj^kHSUBj֭gN_^W ҟ~ptR]N? _K|O>NaS]Ož}bՍWL.Ȼk:`}}UW-8mS0vo?7c߷&K? fvM4K/ӿ~8/[h !f;d7K9昦5KiL? 8y饗7|3G `dIʏG<`z Tfz?D@Q (@H $?D@Q (@H $EP(@H $?D@Q (@H $?D@Q (@H $?D@Q (@ڢ;T_c`iQPHm; /vl;Um 2j*;ƚʒ⪆M,xp[YGkS}MeE%5m{CnhEb_27uM}#gN=ߨuW;vʺpX bQY]KWR_UܗⲪڦ坜9b9`+Hi,%:sJKig+XVu=U|}gGCȷ:Vx3]A:E+6]e688.?q4 CGuTX^s @1[ڡ&]_Kup{/mkTImk[Z:&HYeyߞvdGAqώzY^6[ZGKT6I{9/Şܒ5V3ly匢q|Fy{65V[Rr?֔6$rWwI)dVӱj-ƾ@@LeyyM"ch_!B8iT, 'yf pdWqg^~ݻ4 :Rt6'9;䯬!̠vXn-7&bvU&+.)+޿'S{z-͛ƭ g_P^DUޒu݂'V7v ۿ#|l^ߞΞ=eo^qG0UVU'}myέm*WoMY&n@T r;2,\rcw{]{Zk/{hoe_dOGCe69YGcϿyߵ,Q_{]\pmcW|…^SV'W;C &0gΆ7r()!m+Wu~拖Vzwviiy˶/wu+ 9bE6n{`+_–5K !Y}_qW,|cN|;P(f@@H $?D@Q (@H $?D@Q (@H $?D@Q (H(G='f0m $?D@Q (@H $?D@Q (@H $7>uO>gݽ{wpGܹ'pBXQ{bee0 O]?IS?ٳi쨣 nh'>wuSf_Ͽ77yȻp?_`o8}ɒ$O!.TNW{r4[~懞xˣK +*v+ȇkǮMo~x֝LJ,>|_su;ِ W`rʏ_tPW{LyKc+sswk\{`߁K?O~w0oyזp]T;oyw|-O~*~ ){W_U8}'^_hB84SHߖ&fϾa V` s5EswV.#E:YTys,\y VO|(i³ߺ/x{ opG-*JDPϙ•PKZr_nP;+vmzdMd{s˫s:o=^h'cr$VV2A$ gm3YW ?{a8m[ݻ餐p]+e*wO &knݏ<~ Ei⽎1ZCK dlͽeD) zR6_c6v T~gWIF?y֬7qt;O}p۶I!%It-r]٫+nŊ*V=ysw6>ɗgp-k_3q[lRT4emh AcscH2Υ:s?,;-L'SM%20IDAT=t=_˾s;$^lKXΊQo;e C [Vs^qW4ly|05ܗi;&:aY kn=v^Y1rME^yyK/ڳbqݛƅa?צhx⼟z 1t'1]EMs Ჱ LN!}~vG0|=O 潳2q\*c%=ѽƂ7,lqeY[DXxgyI;O۵k$_7Ѫrd9Ѻbh7g w]Aa˰ǎkZ-:I-X\ώKL~? 'njYpDO&o '~=oJ4^9NR~ҋ{IyJ‰}{fif[::cJڟj?b˻7~;bU,Zʝwz9s-睽\zm=/Jb;;fLz-r oGooq6o՛f;z&]u V~6{N_qgi}o>aWR2n5~f?gv~=x߇WuzՂ,8uAӾ/%6=RZZL?OQ5p~N2~J[u7gu%aM)?!󵿽K__09/4f? 8y饗7|3G ~-oYя~tһiO3\a'p8$?D@Q (@H $?D@Q (@H iQ (@H $?D@Q (@H $?D@Q (@H $?D@Q (8,E`u5 l ^oKe>W75t y*l?h y$T \W3TW>00Nyc@cyU=m5eŃޕT4lj/*7Y_{mX jۺGiĈ{m] 5僋U5IM#V_VUѳ?ざ$7\ۙΞ|=d`r?Ҿ +67q[{ØCm˶`\9beM]xlQ!Z [3h\@.5^ƒcϿ,+ צY>ަSn0Ӝ[zkKF˕ο'Rwl[{:WUqˮ u;{˃ɉ%|?Œ4_| ,ygת{jO񱔳V\`WKͨr`J<\cg{w}vii?PRZƙ0[pg^7oc i̫e߼6>Xg6^4o,p``k\݃?gNݰ}dccտ\WwhMKtt5obq'ᐁ H /GxF2`nҡCລs5-=#R3b f0qe,{&0A4s*kKӉN'\Tjk*IjVWXwqe][5&XtgkihnJFlWtJL[wh%woYHn꠲}hZsmK34G=MM9te5]}d׶jpGs'fk=9Ko~/\X-[,`$%awùYT\VVYSѽo` >\09]mm^>7ɱs2.qTX<ݽޓ}iۈHJj[[j--aڲ+Sg#QWKxj>ޛhK䧳/m#AI}rq)^sUPJ4lLl䯬uD;XZ{Օױf\S\]Sΰ_p3yP=} 6ETYW;;dc;`88ߎgjkƭ >^Euu&m,_P:6[z+,`0)jh?0ݻwnr働75wQ^]Hwl7AYN[@=屙3nWA, 8} 61W7ut[WOgA|ʜV5&3XJVU+Jس'ꆆ9kj NYmCYg qGrAA()Wdj%-cqO{cI|ʜt>6uIOOGSS[|zimU09+9 +6#Pp| >qhloi*G ù?/9o|oNPZUՄM6%_ܿ{SK}Uq`k-/ʺsv6הn *%Tyhk Q_bCK/VW2'jeW=m5?7+ Tvʍ#?a[OSUߦs7{?> kww6{ &RѾ ']e|^h_K4zeaXtZqKxuiIUUgdbΰٳ^Cq@:U,N׬Bp79 };[4Q圊۲Uqp+Wu~拖V94:,IDATy˶_LIus׾p_ Z"( 嫺^x9{X|fԶ{fÇOjpW^ñ_|bip]W2$v˺wrKf29#ӍJ:d"JEP3ſh7-I,N)x$ѣ2q ʀҁ):4wƀmH}:Ju_zѩeNL:R ._褶'8,33zNf{Eɉ V I^:3bfvuxQnsy%=X89 wlcs._&@0pyDWά/}SN!*]\ @Q (@H $?D@Q (@H $?D@Q (h0{~D?D@Q (@H $?D@Q (@H $?DAOVXns?/Uw.ܥM_7tԣG.^}'T@J}@z[]۶m;S~}/fd 9tHfvfҍޮ|;9ѣξ}iӳ#@],S893.>0DZߝSO9e-OKK 'Kͷ~ b2Ɉ}ҩߜ{J}>O/#qc7ŒرcƵc3>xϞ=C3U])9[Z|o2ݧUꔱK7g^VB>M-[FWJdSjȡC_)iW/*z'il3s}3x:ز>bS%˵k%Ѵ-&\[zuٴ&^jճhg([3[x skieZ ]+۲eKpG+yJڔCbI.޴: ˜S+ vIrϾe+j m,?nC+VF}r'ClKY, - X;s/ͬ\8v0ii2w(]t--)m∣G$ ]NW%y9;߸8k9tK~GcBK;M3Ls7pߤ#~}iu7a6 Y0xZф;wR~ K^) V/xx|a{<8 G|=g2Y ?W^}5Vظv#oֶ!siB,>7k+'.{e+CeffaS6-mTϸxw9+L}2vq|PxW/K/lZ})K B35^躺R:(YX1t Ȱ/npaa]}2dm;旒.-aMuڗ1(@,:^*;z}?^:xZٝ<')Sc{^˰u؀裎 P GLϝc{~wϗfC jg.^=c1o鳮[93xXOp׵^ⵊזni~6@oI'Ȏw֫|򲩗UUUm.L;Rŗ>kshD !%v19oW+g~ '|&@wZd᝷*tZb)%\KBq7g&W|l^^h6=; ]_qo$ ]x~r!֗}őZa]_O?ĚO}S9sF7rؑ!BJW}xmPXw}š^!.tN6ѽ/19s'LoVh@H}vsϯȁΙ_Z@]8yw.5zxQǍ+?o߾stѩH:P?D@Q (@H $?D@Q (@H $?tq@H $?D@Q (@H $?D@Q (@H $?D@Q (@H z^<=#--czqeh#iIhjWY2 'Ouܖ?sIYiQNZZ^Qٞk/_xӖܴ$b}VOϞjmODy~q6v> &'caԶm/?0A#M\Xpb/,|0KL'#fq=NZ^4)m7y_2'ca{E邙>9ӗ?Xp;lA`Acș'n//.mT ] +t>{dCЧϮ rf\13cbfH}V71tS3C+,:EuveMXR|-;uG5=wT.`/}r&ys*t˜QRUUUR7˘^=>ҩKvS2# +ꮿ:K,S{&*\^=lSĞ2f/'*ԍ{E/i* cQM=u93i/)%˘^4bi}2 /.°/}<1hqE3C댜TIa~Fbs;(dNx7pQMdO^Pf]@7|EYmࢫϟ4iӗwc=U6ӗWUU֙Zh5W)Y 1¢]G 9W~.@/EeU۞zygzzХM93w9w4疟1qNqYspo<3&zN~r֒e-%E9}TN&pIDATxuѤKlQWoUUU5({Fx%˧g׳?V0{ԥ9h 'gTOU,xp2llɷ\\ۢdNƱWo$5esr*䜱h㥲y>}O]ZpbΩ>0rޚ8䑃ju9?rE_|%o>rԝ[4h̾UcN({MK9tS}t^# mҢm*shT剟"$4h{Eɉ}ЉWGiaK79̼y:1}5pydfvN-*]> $?D@Q (@H $?D@Q (@H $?wN~@}(@H $?D@Q (@H $?D@Q (@tonhŊu?/r"9_~_Y9YC9ʟK7ǿ{cF;ZM/А.Ŏ_XZ\Sxku*(MNz)n}ZZZh>!z.7R\XpC7HC2bi7&'Eo:R>G⋱GM=ztNnǎ_<n\={ ͤ!Rrd׻O]%#b`}7m*oٲEt쮻I>u:$򛧤N)z)t+/KM_9;v77V2tnG wdt~])+--M8R/MiZLEjk'1xZkP|Y,qxyvY,Z\Y,Uz655M-[$ G{dh )eVM_?si֊W䰰/J?ل:rlu۲Ea@z 7+B>9操6龝S]plb s7_\:Me>kslzkä:rl؅$)nm>/kYY6-&ܤV=+WgΝ!qLKW_9ϸ?xU1dϘrgd¼7JQu]f98;+dd{9\4#,TTT6~ VWbyդ oZ:>{}7,/%VGYg.Ny_,^Uzߏpubr׷ȜxilsKN~0X&݌L.鳲ji9sOO J9va-{oҔ$XXꎌ ?ҋ>klbo1|nV[ݤϸ7NV~]ctql}O?}6c,֬]gdrX"|2b8^]MW6ba\=C{tw~My6Z3sB(-EVw-7+ynI!{uO,_y}C7vcY| .T@N2-Xyı UoR.UR^Ea+bBQ\ıXc9(.LՕ'+WO QՆ;oU9vz6n꫱Ƶyx+&'٧6:=wGL0I#M^ݡD[ iu=zţʱYoX%S%ekksРA>!4S@J}tAҍRєo=LMg׭LN{5i7GV3gx:7OI˭C=&6!H UkcS^ S6ϝX(D̆5է-#cP"hF FW0('\[?x5Ck&W3儥L%lZdʅEsO/\pySNO M66Iq5ͻsZfXY8 kW/ 9͓|ri3^3Dgr'W3k鹳BMWVk%WW"PuMrON^.31贲;C.xj(AV,8Lxb.;}V|O6fM>EUUUջݷiP-siqY/L_~N/Ņ֍Iz⵳Gv۱X|'fjK ~@}hN:iDvrU^62d]°@cǎ9gI~Y~ ]DWJz9o'ďg8tJ&^niفV溟_5?|7G}]Z U,ܧ$xɜ95̞py K2unk|ޖ^}ƈ656Ss*x&7l?9wy?:F5.v%[bIك>wSoƟ fX;k]cc~4^:U|sծR^QeL/^tSVdFfݽ7t_cK4T?5nPl֖;]P\يOLͪ|G<5W> RvxW²m5>+ZoԥeKgLJ퓑_xE"ۼdI@bYkㅑ*[09r蓞=yA۫̌/>iQo]UO/SÌKʖN+o]4yFq}I1}ym/-.YrHw`q :qRu(^wF7*_X6l™ٻ{ۍWsSb;?{}%}%EEKI)UYVVz:Ee%' g׷89Vnx?'Oίoqɉ/%lɜ9}v>1=oNr?DRWZ{uf55CkrTșͻ޺@e'CayiwJK>dy+]^92/;UL霚/۟zs[i|ÂU6Ȭ7=,+ W0=p{EQy[([1x:K̂c?7_]籔M:? 3fULqQT`rvzu>}БRe%~.Y"4m(]03/cI7m _ Ȟ&^Y^`zsUYN!-(۾s%E9/͖1cYcYR<9bygvќXT|yuml,[>?UVUUŠ%9g,j,ʺjMٜ:3 ?Mə_MtQns~\ ?/c5dG w!c]̌ckETLU̙xv/_2#?]E>i35b*g7%4¼O< eoy qͯGR$˜Qbsࠑ'ϾqWeTȞ57>y䠁;شdد~ANlU-oiϼ’mcM|7+kcI|yF̻=eh?OQ (@t3ҚO^QY DJܴ%4{/. D3(4O13&f!*]\t}?D@Q (@H $?D@Q (@H L}{k6oT@Q (@H $?D@Q (@H $?D@Q (@H $?DG yB{h 2h)N = H)۰.>3@z56|tl9j{&Ou7/Kā.fayk7}3W]S= Ҫ][{t|a^\,{kfιOLN,[vI's9O^nB>[@*\oUaeߒ>;l粍X3{Oξ}oU^Ⱥ@IȫwRɫ=!:pª@έNNrɔgO[v^)JؙvY+oJu̬;Xh0' U$ey$@jIRET?~CKwܱy?R*K+*~-13ڳVЇ>O||qc!H^{{;g^I+WϞh=z_m۷ם߳4|1'm=B"ƀg}jaɝ=zM>nh./{#5wlO1>߲?g}o$;m|okJ&'~ӟih3_=gن0#?=,dy?VT+;+3}Oޱo̳ Y-Xn_{C 9q73B*' #{K LZ -$"N>đ9/bFKsjlonw}cM[,Z -ý]dS&}͗5 rm}6[oKBAPZZ,s1SS{kjY+t?Z ʫH^lْ,9ftƌly%Z ʫso]<3-%N_OFZjTNNPQQh-Vr@g O>> $?!*yB{heЕq:I:3퓎D'2^"ŕZ_ֺ>щOO3N}u|\Wo^wf}EKl~:^=sIyb'9,Kv=ۤoGlV=$w^3yC36 LMҙit,-&J}Ck'~0zw޺_]sěsbu_Co;Kף׽Uw'bO^-ҍ{+uӫ66^4sv9_^?9gb7]Pֹi[a/\z(<"~n6?|.݁9cWݶ8\'{Ҵ#frM5ޙFL I}ұ@h=o;?cXڿ_|Uuꨯ`ͺm}['_]AT=c `UYudQܴ97Wq;.y}|UG?uuz}=7>/MY!V&̴O[LB*it;QM6PW5B8+G9SVu[|5?4ku'&[}+LUO<\JUMQS5Hv)daf{ά9`Stf'K  z݌;Xʛy!6o ޿fێd᪏ǗZ?zKG^wMN'?+F^3aW)yj6{z֪GR;,9~=!\u~|9Sn{'1*ZE5{8sIkŲz[܍mNmy^Y+~$I~Ҫ][e~sSKFP6z۲sGouO{,Ve36S{haM&,{ LkAg7&5~m~O?rENL#k=6cj'~d#%VNtm߾}uXVm#vVmIm䗯8F]wK ęȫv]뚞k|mYWS) /RDcitO].RoZ*wmbMiy裏 )K/߻7 CzrϺ=b},17qthh{s]qt|O}mTW$I pnQg&z׬ tTu2)K/|ēۧCFk2}ұ+o5Yw}?я|pFFƠhb~{Ƨ|K6ϟ5%ZNYgu5!Sn|Hdj[]k4^G]NJЦ}vs~]uy@t?E=zHp3@ H/2~qKB9I'ZgϞSv+b@lsϿpO>f۴δO:5 ' /2qB޽)>|yÏ>*6u>`} p 8pϿS'!*briUeeenmhg'誏}QW|jqС5*1G^!R^Wpo皤-ht,kjG;8s遦QW&̴O:^E'?k?Χ3x)O7$VUUUw:֧Or'?m$x7?vq ?{d5^{ idϝ_ >{kMl:!?[,|♡@**Ls.mܖW^y3#[vkm۷mۖ1(4S+Oowߚ={h/۾r~a|ƩQo^it,-}?H'W6zVJjV#7-?B a4™~k'͜c>qa|5d~~ʵ^wkl[o~uvdaРoɦ;#yWcq t/ƯF6Nl赢к5)%?ko:dPᭅGI܏^' S'|gw<%6ϟ.֮]RށdAֵY=m guO  zzdy9^,Y~Q݊MnY{F&'/͛ 6w9BtÚ5*'YXn}iڨ6{hZW@$It$ /C?ˀޱolٲpѢdslHVI;.5V4,+t'm=gkZ $sy7n[d} #?~+Y^t[n miǎ_d~ '|&HwZN:iDvviyUUUM^HBv-qݶ}F[kvU3ᴴܡ74xhnnlnmw_sI[_ygⒼtiqf<_O Q|Yne+C~.-7K={#$?ڴ"ɕN)z)B{d={Λdy{꧍Z`RyThkùEWh_yn& Nfm֜qիGgMii3.g+,m8{mfvnn{Y[5ǓrZu1寒f^tl^^HVӦͳkz;MMiq ϟ'yg>\_$'S+^}F[W7$=֞Jhc=Y:#rfްz_7wð w ]֜a/[[^y%G;|6lHΌ%. )[xpߏ5ٸ«p;ܹ%_MwȌdi'vͯ Cs?Nj\T[d|F|~b3jJI|yyyCF,kT^:+.}~nIثGHnbdСC{=?RRNWSΝ5P{C 9q73\{g+4bcջ<5_2~ccזT_n;Wqƌ_ %.}gb~b^Ք?hj\7vhz9dȐ͛7ސĭk&u5s4l ߽~]ЁR SyZc%3qG5?ic~z?p0~TɉE˿xz_-fd$VoU5w8$q?7IM.VW/x/;KР2?%k{E,Km!7t3[sw&WKo1,/3M>CgA598ư/ lс5^znsG:zw_]xՇ8 1feKY@걅+?;y9jk2_oÒt+ZlEYZ):7K%5xgORxgssDw:xʿ9nl[؝ܯ&*e]`,;lH ?>Wxc[P o1x3 |E:׺P^^φ>oIDATܶMg93'|?vo\p~ٓO;6ƾ1$.+t+aۿvKkmR.~]J׊Sw[i>yrϙ#Dջ5Z?ԁG%zѽB@M-5>b[ך})?)-.³O>;12? -_I>kʂ:tA)ɘbmW6n|g׭[uUVnݱcǼ<{o߾uׯyN-Jg_2 c,/K k¨:WjGgvkoqo\h6mv)>0=}EG1|C?^ %uUJB[^_9nj*/YKC6rf~xh gPNBL>$T\~Zh. 8sК%+.Kk7 4bp Xr%5wvovZp;#% K7BiK631hPRQ/-9d}23\dg[|x&g>j9~Xcy2cuVbx;7Ys5[O-j_96H=o]2cY_Hٕ#vwV 7dWk ڰ_-dgB<Ň 5=04w~Zɽ*TO+{dCMͯþ}T|?ؖϻ䡒'9_Kr/jnZb]6 &ƚ7>oE_}wGձoܚO_bϘss/5тSvQ9B0v0ii2C ލ=ꨣB'15Y|0l^~sVW;!Cݻo;M}=n߂7V|$}|cįd7-ek}Ǿ=s3򏾡f^;ꯋj~-K f̸=vîX xZhgҫuVkZ}ߐj5n#?E8T k|(=Zhܴ0#`zkȰ?Ү1'xn>}nε}V>HHŕ\Xh|voȔ_t-=`cحoOZf╫Wޘs->˿Е&^Yzc!55 ]w&F3:|[MS}{˖WB-dgزeK0!u\]K+N(-V']:K7`z+Vxy"NnZn E^d^W]W&'_cҾku85Drr|ϿBSV_2oY=bm ץ}@WlEgW_ Xk,MqkBO譟&o䭽ky;hVmܣ;-۰!O|W]>|Ʃ&ӧO ر#Yիg7Q{} ùE·.I lm<R+=oȐI6o۠CMpօS<#ϟ}V]+Yٲ[u85Ig}ұ@Օ(yXak=Ve ^y N;,4_){뭷C+L81Cgk}jitZQ[hMw Е1?>h{nڔ,|C[Vէ,>S3& ~m>c57YFG[OcZ1sGdeE"+%1w\nرGJ;6/T79eu5n챡m?nlRh'B7kXx?{o;c><35Sj3>XZ VN^Ze+C_?8#fP|_gǍ=CPXņ꫇ ;euS=̧׿EOzcǎX>g}I~гgй]@ՅGJY^xk33:sr䳛6-ve NYVl /^IV۷oUۮՑ~ï$.޲#8Ϩzꩲd 5tg=Bu쬴@J]m zlGUWmeg%_]tAºUk׭K:y:kκpS&=6/}W^|vnBcwӿ7_cO4^7ꞲNu/>찏Qd;fzȐ@}F_+[MgT&GuT]Z`+Jwoo ]M;ou\ZZ\| BbJV䡪Ζ-[}Leewa'蔺w`R @pI#c^KkOF;v|Kӓ_ᇟpg)I؋={Λdy{|A{K={#$'vݵ [oK{?n7dkQتUs_*99kEHx ]#$ IK5jԾ{'()yt#%Kkqyh/\ѯ_$>yv/|_9,]{DVDBg ~z?n}w,w PCNz@}wm{uU>@Ybg?7x#Y ?jgd$ O@z /{/?Iqc"*--mq?Ou-6ߞ}6Y8>)]+O3ڃѯ_Ν{hw}tdЏ@+PmC :($u=~wG?Vt I.?m> Gj1E;tpFƈdߨ @ؾ߲hk 2:?]tge~}~@zW"{}dɧz9#IFtׯ?#Bgkׯv m2<33'N>iﰲ>{ZՏԸO|'~&} ڵ뒅A%}H9蠃uׇիWF._}Ύ CzYL K몓ݾ>$@,[oOj%WAA! oǎzȐ@&G塉TZUUU }{kjxrc%cfIDAT+ yt[l9j1'xB:70 2ᤓFdg 7DɎ;/O83nIDJϞ=Qᇿ=u|{GIvݵ @!fq ϟ1O<&DcVž~_%'gͼؼ@w9@4tI>&o̘ŭ|䑒GW>Rvf;C9"w=bE'Lo/tA?T1'MwaՅW}@t}kpۭ]4 "w]+>@ľ ~~۷oHI*I $?D@Q (@H $?D@Q (@UUU@Q (@H $?D@Q (@H $?D@Q (@H $?D@Q (@H $?MXg{yq>3Vlu촺2f(廭]t>3(*NSwGEa{YqQANJ*tK{K*K>iMnZ=-ɹ=syOuܞHWV[lӣɃW=ckbgXXW^קIp,(5>G㥁{mU1^~`6Ee5f,^ҩ3s2c)_؏#=UUU|FfșSҩuj9?U5nPl_|:szqmnQd{|yY$#{쭋XXi,+S-ɷ/'#y# ΚnҖ>qEy1km|jԥgf7Nf)_09z93%ĭ7, xOU$,{΂by3&gvIJ6' c_P fK,\XۢKω ['a伒z__PEcEo6˗Ȯ>4jtQ_yII==: %em>qASk7ƺLsf' %en5 mda{5[.)kdAvHOή5eUw-۪pn[OZu+(l荶,\X_0xIg^^fH& w̘pnK.}ۧ&uѤ:m`ee3~5x{hy ksK+^Y^Z<NA~f[T%c0r^‰vV^ĵF,.۞{ْ#.ݐ˂?ثƖWș͍1G**gOiK.z(o{OtaA<+.H:屽&'*䜱hKk֔ -˷=uGsAzѼ[xj[, zwKgwuknAkuE7y6bo}Ruyffz@9m0;-&>ğYӒ K@UUU@Q (@H $?D@Q (@H $?D@Q (h0{R~mI?D@Q (@H $?D@Q (@H $?DAWJH4eΥs݉>O~pUaPoƗQЊVƏ㚵 ߕf{W"[]:_/y/CĂ䩹9{f{/30'D@Q (d%yiiyg )QiE+!u;\|]#DZmނǍ{hŊ:Xܴrɿ*}T{yE=ÚKzurƌZWLd|]M:~?w>yI r*WoUIlGCs?XV\|_Q{;+*Bf[?{wWU*"$(khAR"A݆dm@X+WitY!uR~` K A 6DRwf4I43M<|ș;9̹#_ι;QvbR+W6 g♗<}r(KRLzunQg-G^Wׯ5h%޽3|"k͗4dWKѽoƲ%BV}ck+g&R^{t_5Sױҽ-3_`UwcK/tn}wAۇ5#z3;4v>bNxɪT\m5[zhKo(ʊ3۱#~گ_Ȭ']X 3:=|zWm 0s_j_5'\/;3Y踤w_=泺w N>I%gdSػ愜}K..J뷡h%'t i|m҇?] V\P`s᚜uWLy+8cfLTve|-d,73'}FݚV]0WdKRQg?=M3Pj,/4R]z ޴sl-~V[\t}[:;y%%!Q]tmu>wu-}F&ʸI l$pf0{=acSyPi2oyWC3TS3Ge+7`z_qSgtpw.x>gtԗӝLluj͟<3˛-(PN=_M[NªM]~]PT ”W(قDYVO\~3-mQ\ދ҃~ټɋ=9v7~ե/ū~Z=Q;;z!Ֆ=w΂]]~TQOJg-N KV4x %LD^my|jJfa*:X؛(lj7xJR2TLyڛkJ{wXD}DjKM8VTb[00)Ś u ϮaH;uuǧJ)LKQϛs$%U MJ;,HiM2jjrXXհ`j؁GPeaإV6W$od aԦ1Z\_@w]5 jNeeer7VN_2̎_{T kۆ:m궺-&*IV[,g1޼Dzmxs񁉢ҊDeYeiqjߚ֭OW?\L8#]MSaU^,kmk='QQgIuܵ6wF$ڲr0δ4ǜV^:HVXV:98ٌcӪ픧t?sٺ3.~⚖\^i}[z͔-bAT k[[8V%g1 v}%sSooHkjn@Zª[pں[9x wDaA`u44mymʉĠK R7m>FHf7ϙ;9i׳ϣ F-+*.L]kmUO+ijյqO?jOK`uMKFfI$ R{Bܦ5azw6gՖ]a wQ\>2:S_.v3S J:Wyâӗ#d0;½Ξ[,/QZN^^^6SsrrU=Ȕ(+*ijTs'/oۛof֙)e'> [}^[(y2pq"ʊo_V[ty&K_,'憥sKAlJ="08d,alnjHDK;TO>C;:\WZ~`TYgW Fo-={CںMm UEyɤϦmɨf7J{k'5UWׯKm9E%Qj:[kˋf+ufJyMm6wmk(<[(.C\WUM2񣸦7+,k5U$3:ʋӱ_4/Bs7fe1ގ䱻(om3.Uh9 d15Q)2RkjX$kw: Nes#6%Zk gúdPWZ|]9=\^T3w5/k/Ϲog֙Ζң./lK{;Q65U]nϽ#[e򢓗VUm]/:竌%Qq`y!SMEsZ;Ls-l(?zP]k{m bڹwԖtϘ@[mfLfw[]husUa{tӶn*~tvˠ`ڹ[jK{R8~ YN`5IS +;s999??,^=I[d`F\j}Ǡ_eM߹zcז3L^qMǗ/:mι׭iaL)o|ٹsnis杻hYԛju}|+k߸zق dH^f:ounj'׼D:2xm0ݰz5}ޢolѰg6{NNɮl(oؘvݶ%bm50,COq0XImY:7'-p@5e")ŵma_(kDGCY""@Ku!3kjRbB!3gU t1 nR&>ā@q 8@H $?ā@q 8@H $?!_[ Yq 8@H $?ā@q 8@H $?ā@q 8@H $?Q^IDATā@qK;y=v3&thab㌉p͝/pabzΪ#`l~^\tu/ &GЬ{]猟% ?yGѽݟOҽ0o#MBk}dwͨ͵=H3=r8dj0=6}_''Duݔ|75So--9gڧoƔ>7Novm/55cΗ/;5{j>{O~ڗnM}ȇ5_x=ʵ䅛Nݫ]}ڲ^v glk61Kz?֝qƅG>>xөw.&`l=ixa'/n:ӓ gM~zN PvϦ~Մ~Md7ZZ ?#uO=|C's>ӾwG^؝qwm5c>󦞳g>A>z@rkG؅Gצzs5aM '<ÇLSSYM򵋿xiG]CrCN̵;H8 ' ;N/gpKq<N~kΙC}λO|b͑7,Kf$צW8۴pЃ=q11؂X\{' ɣ3knkJǖO}2o4G§{tn H-=η5VLv3ӾcK=mO?#S<,\^ft)=y3N _d`O+SFMԾ>f8ѬN}SYeç}?.>T}v֪>t{;8^n -wR놞9˃0`&H 5%w\z̳{#CBW}#ke~0y䔛^J\WsXO =[ϻ䁛l*zS裊Tq_{_dqҪtM :ڻ/U{[Fr?k~0 )Ibᥗ_n[6g}ܿ{T'mz6YzzpΖ+K+jGrF}7]֐5W_qON1C';~=|8ଅ CfpV ؋r)G|vOn5G} }^}_s:*]pnX& -,|n;.,JuK~~ҷo&w]ZbW^is??s/ E p2!wltyv;gD"> ȋ/y߭^iSO g7ݼqӦwL=7ya /̟CSO)>)&^u߃=s㧜^{XxW7ȣO<)=zt/g1?:E'~(OqyK)v]8#^}esrrrz;?O4)]wݵpڻ׿>ԟS&OC2񖷼izOO쇊?}vwzQ'w`L5 74eMozSSO=u?C|CN$aMtY${ZZoi޵>\{] v^y}Oرb}tabwg^y(80{[P%(Q8c]:m޼b7nܴqD"?tn3~^+oݺu>_l+(wV~7/[-{)'WܽbET8f3;w`aK#to2{u/O:=y[ʦ?<Wy<_?꿾Vik߼¿_ke`,Nʫqyc+>_N>8h㉎}7r-wȿ+r5{[%*⣏*(K[tх[g{ÿ 9?ϯBw|wsi7/uO<ʳ #~}ɧ}ⳟFnw c Y0S8n>se;e]wW6fzW{?T_xQ\4hK( a_^k>`YpEk7W~qb&O| /_=!Wta=w歹o ;ʞ{}ws^zYqG!]}؁>tN:=]'=M70]_{Î7ͿKoqÆ Ɠ믿 >w>AEW_sMo򦮮SrߞHM̹螐8q=w`cymrf< >Ӆϗi7 ^L>:]?@bjmMfm=30t}a G8X8sf =GV\PS|s?ё.vԶ~)93O7-;ejCɼ|EMax޾^@Vb[.]8÷YxjނAk5Sϯ} D`߰ y&G5F[V| 7)9m.(´/ kϻrȼSM+6͓4N&1yY{w|ZAA^paдӶYg!S{v~Iɰ%lӡG.n~ˆE>3V#t3L:.9daR-f$K+.(>Jn.Flk|-ugkͯlLz;з~39g>%`3%Vi]z{tW*%De׭gy!Y^{evnjKJ} KJ5;[/#qe5OD^J4aBd]wZVG8.,֦K.mxȿiR;dEv,ƭ/4H`6c62IDAT?ojqAؖS&q'VdR*Zٕ鎾4spWn>f +ޮ.^ik %w'O+|unī2В>yͰ`̺u%W?uu3'_*ݫD̈́x ]5ٽu7){7U|rtF%Q;BxVޕݟߑn>OOt\2vvvf .+=ִ M d +ڶ+^t7&Jycߪo+~Yg9$.L{(]ֻx-4vѡ#!}DT?X\|VN5^m?[Wf^Rw֓[ۿ_)K z(><3n ))rf֥Fx̜ԫݢlV]>]^^\ݫ SXuvoFt}Oormi*luK#=:>ػ8. f;+d)!{t㧞Rw~Ց-sPhW}6hϦ ߹&\#|ی#J]Bf3=w{{e}B*L.KV1ֶfG&}FukZפ ]l뉃=|:_(D3 w >oAQ YZ;Hl9(ƙu\&w 5ӻ5̜sB#ө[rЯ$“u3{{r tˆy0AC:AH uX3>I5սhXu_ۭ+#{{lx~ki5ŧ?qxG`H}6xSPSGx׽G%ܛO? d7{ƛ__\V|V~Qؖ\6֕%S73n%W/|%=tF7j~%dURN(+BcNfȅ3ye3wWʫ.HzߪZ9]en9% & n9%\Hq!iO?Qje(<>^#ӳhώU2 +'M>d+. }ϻ5uk>R>S > ;4dsde"%O!C'|#_G|侟7sO;{NoCo}nsKO2hfEA`Kflì(ƾ޷pfפ]_?zxkve02Y {dYe'2*cv%ucis=^}{'>>PZws=Ϩtڗ:^{\Xz=!3v<{QE?Q{6`̜Syɓ¯kLOSkq_~ϺK~F<{'ޖ /\ QSCvJ/]uiF Ww\/|^]G9g̙P=o_8?]29;[usE_?ߟ\{ H$gv]sU;!CO=Ǐ1v˵|߾ ~{[K>W3ˆ &.n(g0qeɊ˙G v9vT܆/ӗoYΚq̌Î:{5l˃|0iw+{s?X2' =F.99BWWfI~'קFi)LÏ:ч}螇{[zŗx$G ®2']Xs=_xᅨ/fHeFGk^Ő>]Bf 1_BN=揖=x{^~w;[ov 3{vߢ0n~a/mO̓ gqą_m͚Cү~?2s޶W)hp}7pNc?5_ܓ]'}kTSzWh!//u#{E|AaD_Q4]g\ 3#^~qCg_- t.=.3y.' 0t5o2c'>jяc!"|G8=3`;ncm{U<-wܗӅ(1rvXoFQW_}?1]>xVR&Қ7{m-֯iٲ+;1?SLkk6tG>Dȣ?`;7oK/χI)&n[uopڻ,>c죏z[{\vz['O|{}GwoyKh6mǧrrryD)1{[bǧ~{`A+}y-C55N*O2 7nڸ^ gKѱnC]v'M0]„5mڻ-^}aݎ=3믿U^:s>73s}gg0\@s+{~7MW?ve{oo~ng{nͽ&=nuky!!tuu /nd-{08@H $?ā@q 8@H $?ā@q 8 gā@q 8@H $?ā@q 8@H $?ā@q 8@H $?];ӦDNNNqm[ ۩몖~ {cW5H3ՙDEӦ04TIN,OȓœonHfpKcHjgzZꓝY9ֶgr^_xdaꂅSFuXF ӊ GtBF2n}(,.dpZh]xW0h[ &>&~'Z:Krrr%Mm=;ۚJ նh}ިsr^^gmjXxigT&Fup&j"lM;1dPڔ\Ŷ%ݵ]]|jk#h}qAa=o[xK0d['5rgisoy* BWrfgsMTᤚ:o@$!Q`Eyήϟ`I7^qSkCeqv>N% FWmNrϮ.R&_^*t66rCSc[I#n}I?/ί8IDATjޕ*̪YXڙS&_AqInSRz-WmH\hMFqdN-).QM ՗M&]S9|UNWWW]M9sD\tsŔK7wi;V6]4L\9uPCƩLPrZ2kH}yeuCU^Au>',0z&Qh2>_xd!@CƱ1HJ[»RY5 "k*m} (u oIVU]zMpRLCt/js{vuM#7ޕ*̪YX`+燐?$ %Ӣ_W&Lpv8@H $?ā@q 8@H $?ā@q 8@H $?/n[ Ě5?ā@q 8@H $?ā@q 8@H $? ewXC?O?t!wog|;[NWWנo0?Xة>{7#co#7k}tKVg+gqPves?_7M![c:n?o=҅^ݑظq:r=>uM |/v>wG[79deLM{,zy-ojJ,]Tscv';.>9c0zcϗ_s5;1$OD}/ӟ.&ҚW_}==SQ#]%2._S#><_?뮻 YHk7ݖ&O|(|{2:%Wov{ST~#5[t'~`r2I .sѐ^Xn=pGf'0)kmmM;0u\ptcj[3jym8 Uv.te-FWz ;̤0q[.]8C)~U cMc=0*t>yѼqš+N̙9mTkp .3믿^;_}X9Cg/!de=҅^m{Ŋ.o^Ɓ}k7ύno:8dnL-{bm"3{~3r÷>npQzc.4S_zU|EMGO;D`߻o`-kh~>?/_D?a:vcoۋzN7{]gKǬ E^~冥7F?瞰3{vO7M{;c$7v<ā@q 8@H $?ā@q 8@H $?Lp@H $?ā@q 8@H $?ā@q 8@H $?ā@q 8@H v oMDEӦq4䯽0')m=/Yº%a5w=myWPX.L+.I/˴qxZPTXFض@ldg^DޔTom+d.Ǒ)yyyamF_{Y"ol[K==.(q 9h;αm}Luo9FqmE_HG-EycXJ$ ѸiE&_^*A|M>.M_:DYCG6gG%< %aLmĤL*vv f Wghcel[ &2Y7>Kю7ⶕ ]k*@q0zѯ9Ecc/QѴ";> $cqb~~+JQNWWW&8}@H $?ā@q 8@H $?ā@q 8@H $?/negā@q 8@H $?ā@q 8@H $?ā`'7p+V._uDJnOӅoϜ)gS\qeS=tѶN>.ZO)kmmM;0u\p6y}iOAՃ{7ONjU10u֥ uxZr}{cGלe]zn30fv3/w=+°;aM[}2+ﹴt[ rg znUre5OL5cik K1`-h/KV.opiw#Pzqa͍ mͪD~103҅NpGnԵ]yOMuOKgqD10NhَgCv~'?0Iab'l?@𔢊}K>ӿE[OގҜÞK]Q7*-u%SzSQ6:0| YXӼոG3l_}V8 9#y_qO8`س kwvaΝhukUNe`󏿮dS)iۆϬŏTdۙʢ^6 iڢ۪ B6uTȟ=J6{_g_n݀=ׇ^=ޚF:[KAߛv-%yݯjλoKGs/TdÖs6$N^ιDQ9)7?úN foRtw7ll*;J9U-j(a}ւ{j{F}l%wҼȧ@mg ׄmzu%y}{2{|^ȿ  ='2 b5MquoO߹`ztJQ_O_:YkOMZwMljH'^n:`dүd_fM~/tϝFE~@;~u=Ei}sw;'u%/Kۏm2x!u=-[Ꚗeќ5`Im)jԵ~E L~u(-H5l>wQ:Т>kR{=_zP/79y4tf4{Ч4䞴xݵׯ^A'ʛzgG6ڒYˏ3QxIwa܊׹f4#Em[ Ŗ^8}ZX!-ٛwa5FΦOݪ˺[N+e`er-ok(KSS%5 S_M gܕ*M]0eM+,o}3ٹEy+`߫KK]wagZ˯}MU%tږՋ+qZū;SWRX]T%|]CE$ +mj(ݯ77lUw/R:ށLT5tUM0a[eUŇ`-ozQ|QWQ?fS^>=yeus^Y|#apד&k45/Jsʊ,%M}l}"dw+jSy-M!;@Em7,)|fHKMlu{}EQbqYZV9#dߴ5 u ϮaHiTiU}2)y0jғysΔDuSI}ǀpɰ3-u?ϪaaUÂafȟ@cZ;\R^+HQR0kq}VY=w4x9EuL8}Q0;N~ٓS/*hu[ݖV$-N go^" g9ܻDQiEu]cs[e ڲCVXմ8oMM]֧Ϋ韬Mrk{{F7)0h5 fq{#ٛw:vSg']W=0*ԭyimVPFoZK}>zY{Nϒ֭k7;m(IIյe`fioiNm8ttrqU/,۞ea}qyC״ Jқon_ ETTZX:ęp(9ap/l2胷-?x^oRT܌ ?}C,o]Ss{k @yYedNIDATsR!alfoMڔ%5JRokjۨ%)j]OCߡpKXgKCkk0tb^AAMۑd"ٛWELP{ߜtg5?j2πD2t~;k ,s6j_QIzM`u0ڪ WTQڱk~| ~Ꚗ:H* M-MkŽ8| I7l l-I?ۆ(.z m D͍/jraa{f;)Um]aYK^RQPrMs`Ng- v7)a\1 d*ٛw:&S ']Kqiksz&N/. ۨ%Ҋ^^^6SsrrU=Ȕ(+*ij7wnmoYgU6lym o pbǍ⊊Z[*+Fwa[mѡ=,[~-i*|܊␱̇=ٻ"U/S=`OvZie zgSeej]Y\7)0Xm5W Ω(⹕ ӱUG:mJTmvس;؛:;ښjJIIښQͺoVNok_,)-sJ Fcm}ϣ6u6֖MzfR^}i%=u+ pV%&4U$zSq(i m Z;|AMu%ɯΦt/ji(+kh#~oh-)8yi2ɝPEŰg6{;Z:ϸWܒ,4=9*[oԓBy 5Y KYN3 ytߪWde>{3Nt $*C KaEcoh%=e7.L$9]]]PVp-ɟ,ZS8_}<$Æs0ι?@7]:t~sfu ےގCMMssHVt놩9UmE[׋*+kIT:}^TgSeܫS#{;k;* Ey76G^[{v-%3fi:Жi#Vg-Z\U8}NRoxZt-΃i.o-JKujd9F>YLm5GvHgowaQ?OX+_v&[4;ϟ3-˞?嫞ؼeIaɬɍ*/nAcHAe{ϛۿsƮ-g֙⚖/_5[uڜs[uehRZsLr;wѲ7[YǗҺ-8~@e;J'5/N& 89py7EMhzcd4Daq Sl~-}"$;6mmvcS`ew>n[bt&eHtj\T0A ƙUSw5쀇1t񶪂7)`tc<3tnNZv7֚73@aMkYq`_:*9R\&uAt4%cxJNfMalU 6ڪM򗁖%Bf6W&7Х26̬[RF!3gU t r䐙ir0M '8@H $?ā@q 8@H $?U?BHm@h *%,#N(-Aa$uhP1 Ri)@ &`-4)4-b[@߇!r{0N:$!s{+[o:5O.^kptv+]o㓡P?IIͧBx'\Ě{Oo'SpSO ag~9'oz6'';-ܳ'g8dzS;vᱩ1C\aN8jjv]䯟}f+[۾jFi=%Īc򙮇XbfT]؜S*gPٱշO^_;wM,fm$KΩ:OŹS^bK6LE'̜1Q>~Ī'o̹-.:g@+;%`u/Y~񧗷O7-?u{dOOXhgG][ {9]'FӸO6>_+ }zG I'ĢΏu?_%)lQNzon[Ρ9ɍxiG`h˟^wU?CϿG=aB,bئ$mLOg/RzE!s,ZtNLM>dF_fO,?YctoF5kB꫍okkf8]16.gl=שoN9C85xuoߑZ9m8gNFc2'h_T{~G},Z*Z]Mr^N=3Ø?&`w aӟ{?ܲqcK0<2oԩŧSrqֶ ]xWwmqıy23\Ov|ou7sssn'#:cFȏUf6=o~{L~0| +?% fϝ;7d.m۶oP5!IDAT-7wJK1tׁfתS _|E*|eϫ8#:~{al߶wO>zݭ?S^_`t}u00ة:F=_|v?)UV[tlQwE?{isO+6=)Z͚ȋ/ `|'o.O-.X؊QzvKt[xnT ]NMvIMθ>~'t;1O^|n^j}C [{ ޺e0ߞNƣ'+W6G <+./̺&-^pw`[svQaVѥYzfVaԥ!.vx9φ] S1O֬]Z(]ӍW8p?sMdMۛ:;w^!.v8a1:K&Qsa|{?q- >sN9,mqONs1[mO[ZZAjKf&W喷ߕ pN-yc#SΚ.O{uy5ա>GP%d]}ʨ0YL{-:]gil_,ٽ!;:3ckKסϽz]WnysK_BvW󝧎~}&wA KGPZ>G5}/JߚCҙr&ѳncQ\1}}*s+3k_i|⼾ :ӘAv[ð~iG<۲v:ӊL̞Ʀ_mj_]~D2i_:ʥ\:fS7NtMz[ynQe9[>|sK'$h :h$xթS^}!'Tn,/T<(^mRo:?UK_:3yĘķ6ԇ^Z̙.?<}!˧Dgjk^(quP.cMJ꼐h'Jp}G$q`|ԉ;^onLmn*QkJ N}5PrQw Mj'ҳ]M肧?}i칭W{PqXqW-1ƤQ7;ߨ%~ѓ~8νkaX8(߽?1s `JQcONȍɟDA]!<,VbYUWu|5ɓ/xa5}FM(i;.ͪ mzZ%Nrfb\kMVaM$3 bY']r^4/]jtގݯ[5ZL˽*O=Ak>0 [%TerB]yUk8tr_ݱ={MŽBW|gDlc0=yaQX50,C22;uޖZsͷrEG wwð5\^xo0 s_%,O||4C<=+k(X<ݵQի2=䫻pfUW\k_46>ƮS{~h;/h>9]Pׇ/?{kJ.GuHשυw?Tﯺ{t8Ujir|qWis1s%3,/R7+[_{:1dOMvce): ڣW1:Zns’^qX=uƠ7890S_N-|Ce֭O;sVVu?n=k߳7kX]wR/~|3~Ԇxae鐁';-M&&߮${x`^Vk22:ٮC0|I&_6?Z+νa!O +z d.wyjSe>+R?ؽvxaڒ;u0 1O"rՕtP=/n0<%׬pKϿTTfַ+삥S NdvTo/xE_b/,?vѮu']Ӿz|: !|Koc|"Zc>Fٝ7/|cKISoҜo>onBT^XLjS{`4:wEN?}3Z[g:k3=7MzS!GM~sK_|J ɥ1;bu0|wevp&Mںuk/g֫Hkݿ*׿uF_VV֕5/bЋ/Zx]PU`uQtC0z8'W h]I<0m}H>.<ˮy[]Z|͗?7{>(`RGة ᇿ-ecN;UvkݜF'>~Nt_4=0gΌo~svvXjA@]4=ha֗.8$eaz? {ek[wbU݊m<%tPѬ:&!q R |;ַ`u S9}'@R/wbQvAV{{{_-a{:Css0t{Ml_/?\ٰimӏtN m/o'7sFX߃ME?L#Ximpwt1qvvv_Ѥ G?=+++G}0t8wA3N:W~ֶ^`OpT5n~p*O(xzYb{Kոt`c{ Dl;-5ċWtUnB>8Jkoϣy'_z7Wܬ!-oؾ e&C]߆Dv=G{vOs*Z7Y#xrͤ({H+tW\+foƄ  Yz0Ȫ켒^gܼS6!tCmcNYƬ!4dvs䃛ۣ/oS 6{SPVk>meK}C;Px4mcZ1{s0&d$ͩU!KȪ!)9zfۺ;zly=Y-Y#ZeM C2墲aYƶAcd[8n`Ը]kmڶWZ1k␎2qVEi^?iUcǴb `L$+*N).UVYKeuΏo^9񦻯=y}&g1}HZkJ3)80`h{;C0eLB}=-hhYdVNJϟyPAU[Y!My8bZ1{u0dE`H\_^-JUk4kk.+]pg|qSN_X[$oi?rAt%ӗlh ذq{kcMټ/1毾.o4:cEܕu%a,5yseueczHڞ=XƱM27hĻK쮾yΞ3Vk2 YC[0WwG>kvϲ_d*;?5&FsYq^ػ͟9-eUjxT#cфUԷVt[_^Pzd8(n {QE-FnsIDfUO= =Si_ZY q 8@H $?ā@q 8@H $?ā@q 8@H $&zyKXxこ@q 8@H $?ā@q 8@H $?ā@q 8߻裏==\`vaG~q͘1 /0bժ 7m`y;ޱKޙa {こ@܍|U+.!zWk*<>s_r} 5F F>;`RNjᕭm~;۶m;C~_>s^ <'yʿ:? ˨67g_Tڏ=weCCc삪[9t]ЇVݬ95q7ܼ?_*ۃrȍnhŭ/'1ڻg<31g%oO"0mwXhƯ>p7گ9)d >`cbi7) bȇ:](j@LjuWnb<{sG>tҵi_}Mxt6n?/o'~zjjpxxg[ns6]??='f_W*6p֕}¯ uu}k^}^^:/ P=w{{F6+[˱ow;zx䉣;MR\2[]v2իR Wt2u7𡆠w/|aʖ= \5ͩ)S!C7 Sxַ5(KIK$m4+wݥBBL rv ^{c֯I}S>a9 %C>ܰq?%Q^k<.ۣC}ɴs7]1CRGPL{xwG??n! eHa .U1Cv.xտZ_X>n7vG m/]>/-O?|o]@ٟ^I9WeNK>tfjy]K{W>[O~pbQQܨ6789x9yϤQIDATw}ՏǚnAg췠~q6/`w~y3Nq1G5{'6+f=w2`M#*ۿO~X'~iڰ vC\{[9r/0 qӟTx {<{al{PHȿ$?ā@q 8@H $?ā@q 8@H 0q 8@H $?ā@q 8@H $?ā@q 8@H $?ā@q 8'7rrhk)%좖@Ea^kZG b| C6ƺBش)7-5E5U-;3 My-L[cyo4}Ɇ押03i _=I{ߨSMzU^`etܒ kyʒ}_roSuqNSsuQ :y&3oZ{kr+ ^O>eYScxm&OeSh6 ZoBt,xhlk׽z=7dY l*޵+[Jr Jf^>Ĵ][Sӽ$CvCo0{AnYfe޳ghMPi.8r#+'Ny nȬ^`w4`x_=q7e6omݻh# J*Z[|hiwKlھm;OKtEz^WzzE+SN|ͲX/1"ʹ^z~&7M9}ɽϥ^YaD^Y^EoeVvhc)+Y8z|ڮ Za[L<ϏTV5ajO?yN>^29n_\d+o^9wrs^A^T ?(-nOߨ-LAAQEUZJ|܉]P՘:Qʒd>0\NI]WEEǤDqA'=F=v]rsRsJkNI\zyq̫=ҒOWT:'qIҢ0L!QgXUYRog^~sJjS%M?p\7,ykp.0=[sR䜃ܽڋ~1]Ps܌ |CnqirߦƖ0چz3lJ--?%дvgߍ 5!UUKQR0چ+Rӯ4^`SX7<k7YN6y1EPFY[S]Îh.7!9yyo߅ %ޜ +?e^[xgx=݈7J14)t=:Fq6PCՍ"^ {⍗^#ۄi ׵"9eU k[os֬~TV5Ȭ0yɍ[{7av=yyEEgݲmוڳ8^-_4o1Pw>y&g>wp=֛WRQ֞|ݽ,?kJ꒗WյOͩmh7$o5Muu傍 Bz3B~Q55mL㊆vhkWzc_\=p;njoL6b_nIYkU7i܊g9QWPR^%;>䛙&nXT|Ջ#-OF=Eeeq/w }cRO']y8c"~eeE!cW{fw{CYnyqmk/mj^zYpm_5'K¨fͼ wO)+<ͼfxOG ͫHǭjo.KSyJż0چ//dݶuSsb>`w{n74cF,89s{[ksc]uEIANgϚi7}s ˧9OAqe}umkWIDAT6dϫJm}yՍ6חsȍ-*w}MIgi(|"y=EUuM~in7r^q^մtmqz5-z_X]wD3y~]03kMu_\V[VR\UDtߨ$8eܺaUKzOįj^W%e2oQm嵩*%>][F ^2-JMkg6VgW6xoP/YYZWw;2ukgC1cMIm䄧,{1a^+r;kKs~RStk ;3eჭ|,8%XgPyg4Ȗi,]t*O\q++k-;sj3n8/y,gUoM{ںyѵTw/8b4޺mZLfwgEd]"Hj+9ܝ 5=u?u-8~KV6Ut2k{l7Pfz5 O_4iV &2nT{+za>p6NϞ!7ꢂu+ӗ4'imVv/0M >c{=g%d7>wO>kNΉSL9 _m]Ngw o+os<]&iۆKNt),[sadԶlSO̽dQigV%eۺ;U!q%GkzDk}[9޲׍:n5w>=֛_4Ml~MaɝWߺ-U-E>vsW[ /wͲKrWuskW7#nUk{Pq`_r2]Tơuuh+ 5QP_ ho,C!@SM!3;ih ^t!36B$(*?%df0EJJgM 2(8qnB?ā@q 8@H $?ā@q 8@H $??%N#?ā@q 8@H $?ā@q 8@H $?ā@q 8@H $?}B<&0Si3uXy)g7 = O\ι항7ƧisN8:3?mgemG OLOޡYz]$$&pwkߓOvI#97y;o -cn,A8ʔ'V=Rirr<Ěg~&{h8Tu;w'SwRsWw bEOxJu[mD?->'ԛا?<5}k|#?vۜ/hb˭~s[o;s<M)N):ڌUf8x~11ZJ\[X:ϻNx,sf2Sj`~~α6Ho;gy֧&s;/ѵulG{{(='>ҽ_8:Btc9u'?t׭zt]١GO~ӏMxyDŽuGl|򱣫ng]DbG-~SNL=:䴢.[iE=ńA'dzS;vᱩ+\aN010$:Ȟѩͨw겎yOzc/sno[^ CZ=! OxM+n?'*|x1ß~pi޹N?S{x$LL73^U3- zJ}WꞛK~bՌu[h}ZmR?oJ X1]+;.bU!'| WYo':]o]kO3n6'§ޣu'U}~Wϲ^ }b2g/NN]J.mWi]+Ұ85j9yg _g`n传ѡR^rBdO`T75-9m:wyG+gt؛>(9ՑsozQQiGU?|߼ԡur6q~VvT`o4!@}~j&?$&L wTq@eV>#x}X|5Ě931؎#t\wϧĊۿ>l2_+ }zG I'ĢΏu?_%)lQܶ;ɵ7=`Ӑі?~09ӏ>z„X ơWS>K/76_|EW| /$ygzm[ukC?rF/n׆).79y?`ŗ^ S/\(dE*36M /]E'1: ǿ7F=ઇ-hu }vQрk{s^hQi_.[#?Mo {^&Ϋxqi /ncΙP޴?sYrφد~Zozhnn=4C[#/'_nӦsQ۷mߞ8e[MƛW_}u֭>?Lؘ E?{Ǣɓ&}|tPW_{meO*ZFc̳ϝ~ f13]k~ףmo~awbv r^N=3k>dIaL2\{\LIDAT)?ؓ$H>?ٽ>-7l ##MZXXX|)/>%!L ^*2 MMk~g^|0ry{a?>я-o l7ߺa^eߓMMS?|;0,7-_u˖⠃r c0RF~ߗW} =ja$??aw"ƙs .v۶۶m͝FTۖ-?/iFiӦO_6v͛?qǷjW=qю~ɳgɳ3`wAkv!g }boZW>#gg~l߶wO>zݭњ[^pE|xͿ*ӣ}o0\W }[]Q?ĩtNcy?}1GN=jjԑT'6Ws靿o5'};ߙѡlwbI'eox]~Yeloov=_1֪c UsO?miWwŦ7EYSyqE`lh0D7=o~aD9b3냳ڂ^s{_,؜3q 0]e fxl(~D[{q~qƍOqnewf_+_u71{e_v6e/]/t@խUoL:hRt?K,O>yK]]j|ons>p^yw7lh tŗ^稜x9{尷|?Z^q[l ֍7~/Kş ?.qx?ƥK<[=Rop f]@G+Kf)snEYEfYScRW_Zyoгsבv=1:uj M̓5kצ ftHٛ+~yR7?vk;3iؙ_z5|;{ajs T +3-?5E apniٸu@'6mJ-8qN7+'iD ﰰ3NJ}χ1]w]2M_悻W~*>-G=Gd뼼!LAsXgZ0'?1]۩¨9`R0=y購G?EBϜmpj8DXvI-n~E2RWCtjaӉ֫ J,L(鎙/-:uU_q=g+9;=: }ΕQa_] yo}ʫCU qku>VYz]ȄCW|㎯R-p穣_>paU^PƁJq&_=UY —,[m^]]zMSfqU20!sQ>;G3=ړN +~|W5'#o=uTiNr_=8v{ n4z؝Ә u}0Q?ٖVvfb0V%xB2fXݞ3NnuRfUB";hئ i~8u+Z,§ ~:W.0eu{cU\Z.N(_v')Οk k뢳4;3Jh% >"mͥWv+̯#\jv!g56h/xa5}FM(i;.ͪR fEyՀ5?X]UFʻʿUX E9<*eЦ0 [ OLt!1nړ74  ;z':^UzYP t U8sLN:5v^Ʀh>O0TmW]9gߎ/;-:uVĜu?_6s0ju(7#I 2嚇_H-vE]b =E33gTf12|Wj(p*ѭTIBl3H?ܜUnb!]zf T^5J<MeMss_ t#m*fsߣ P^w_h(1KxwAteW\VFYǟH[[®hA_>UG7/wLo=1f孩'>ﰼֶ<iC)S318sI2GJF%wNitjaaztDuunxlvYzUAҧ<;1.(z8]b!5YejqJHMܞ}NMxk5~q~SSNX'w k5g_jVAj~kreinT53kW}u8`M%EnHQ&}2Ռ 5?е'L\̯Xܞ}OR(dQR]19uK[\~pw߱mGjytxR >qwy{stZN*;-q{cyaL1hW/-cTZ]|i5Y5+񎙉w]՚1bbO~79)ufiq]n'tk$Tj:&K y#B=kBr_e՗&K8] I̺M[9R7(lD RnF9Yf:&q4J+QW/MRbXz_ݕ;OKe,>~i.YQ6P~VWPOwT:j>%x7^k.y'.xurcrכׄȿySTB:PzaݚV]eKoxSR>.lW;D?3o"#,n\W~<wE?C6mƍʍ:C2@mvfI#4iRCV{{{_-aXsWfU!uç?9++_7Þٛ?o;O~&Zo<0z^ݾ:J"ya BN 65hh*E Úlzhwb+IDATE [>oyΑ_ K{0/9_G_lÞsN#!}N4Bp^qm/ 傇W}ZXq!3/pS˟:,/J:S?`l'F _.li\1>kI~Q1>S~wTɼ bE+>h!8狛9 O5ۯhKϿTTַ+{4^aaV׹͖N->11dMVaaKrʨ9#ϟO-V =ӎoe fs~xo~siNy-g_}a!'gW'/{;FMt߬_//{饗 ]H 0e ?%1/meCr,݇JN X練'ַv׏Vk^v>C U<߆dxY cN 9z>蠢YuLC> w6b?`8({̂kӿ}jY Ә6߃M͛n7揕~4=#e|'/ҟ_s\Z[ Oȼio;vWK$HO}Õ 6=ޖ?($͝ơ͛^xwO:MozSz;=&Nx5uQzƛw \?1)8Nlz(?L#Ximpwt1qvvv_vm۶ظտ\oϝw];|Kk릁66g}}ϻ~55 G?=+++G}n7q~'~ߤIB\/嚵`o2|Ag~茓N,կ?mnkW" p3}Oد~z^|qǎNu{tAxG7joo?%N#3ā@q 8@H $?ā@q 8@H $?s@H $?ā@q 8@H $?ā@q 8@H $?ā@q 8@H  Qüy eYYe mak)nOQuscJGs4k+G~uK`i[)Mk(R_QnٹjK<PMCKy{cs֘52]=<ߒ^c#+.>Wl(ŒǔJ]7h;~{{ҽMưԥ^WmME #&%}uw̟C4o{] ; _2?nH[v +Vv+_\V]_G9ZJL<}ꆆnȭl1i~UC}eIANgiJ+[;ťŹWT'9u삲*{i+j׶ǦnWWTSVY>Sk֖$78cE3zWR>T 7$M87;*;ڵw㦊d\>q#{MXW]QR`ҷo֕w馎{ RV{{ζ^WwF /zp{y}k7Eκe[6W ֯oc32הkZ :?Fߡs+X^6MYڂs1F-Y"?ͼl}W&қ4Uxm3{sRk7 v+[JrVD;? MyaxZ9^Pw0esmgyįV)WtULKu pnNJTþ41w&UTiOwV\YפLL rS=TwE+mNoܚeL$;ʹapũدsmݻ][L_!ZZUtÒN9kY8. V<2fÂn[훗u};nm[WuUOSE~:"6cfgq/N,jyuvnY[VQceb]*^v)"+*NtmiYl%QY[{sEխ3vQ둇&hSN3lZ>oQ7fxCa|Oxy\]421-WTJ~~3ҒbWT211dIUC>Jz lmM`r~IA^NzM+GД0<婡d-i꘣2;)*{έYtaֶv5۰- }1[RF\nna_i>ě:)G;KjSo;|^nz]nYYɅՍ=.ZT7k>-hȈ *zgDe5Q ;6mZߊ(R:#1,yC6&PZR⢰;45Ňf17 ;u ۞[sO>eb^pbq.|{kcMYq~nNWd[2 z)?'oHGwg7Tx=Y)kݰrSOu|^QN~k-%0VdW56nGT 34gIDAT\S{/^~M[V4k3 ^Ov^IEmcs[{{=ܺ{oY2V*#ڲϛr ʪFiRr qeOO}HeUSԛ|8cW^QQ:h= JG=bjommm*#U1/Ϸ UukMQH;vmKGƷemmŢd3ۑ⦯T64wFۚ*+kG a|#  s[QU[V_Z[4T+ˎТK Skz^Av@vX>趦˞Iũ#( IW~jƚ܎7ywmlJm.nG.x(ꕎn1gek]ɡ=4WvpM'^.ϺÀf-YX5@a^+|;kKs,S?N幆y /\oRStef,{l#zM .wmMqNX\`ktE %%*~^JT덹e=Po긽@LFNn~є~VO2KVn=0wek6v~ÒS\ӲyͲKN>$#rIta7)iٶ7erS{ɒ[]-^?)SDN]GofDTPz0yϭ[d~WUuZ"%-V&5mkM]k~ESQqoFJG=b1R8we{]IX6ۛS;N {Y}mMIym,NZJ νsSS毬4dw8KR[ F\]T2ef)x[4dE6-m C^I!3S }@L'8@H $?ā@q 8@H $?ā@q0`Hzこc1?ā@q 8@H $?g^*Ǐ?xEP@SA AK[[InjmWv~nRL](*MJ(o(*^@SAMAME̙ˌ fu^993syw        p8p4Çv~v#ϵa l;'oqxݽ FhqV)=6:LQWL>ׄj01xřoM&Hm~N+ز+8dK2iDκxML84WNBr\~3en鴍ںڑRӧV#ϥ8)qU&yDS)h>i}t~:ڥ#Ь|+Ju5}Bc3UӄZ1lн[VKv8mnےiEr13lEq%Ņʴk9YAmJNj=D/|+s5DjV JӞT ckPm3tx̷&LK凕0Gg>EyV'LL-lX5%?T6k7y>Gά!WLNoꮘ_mi×&M~+pTBnѷo]ҷC8y2nqĖL+DU*:TRrT\l; ؀ƿOJLV0oAЎݙp(RɭiBXNpG{ )4hF[\ӑ{81 ÔhB_ۚ1|qO9:Pl؊eÄzu Ҽ;0/j3cQiV.<6o3:dKPKP42+-NvS7Jd8Vsc9 !> 0h|5d8T_ wAhGS +z|VfVa 9WA]x/U͟ܔqB33+C+/;7 }[dLHJ ߰RrnTh~oNVh-2RR)'yz-",_ګ^ժ"ý|t!ෲҌ=nB w6x|,'>54|bN/9ZG޻ktV=ԏrBB&w2$+n X2; eFj95~%IP>%SAOz2a1ӸpTSӼ|¦~=y2 Ο7O/byͽM3WY,O+o^_mWeeevܝ. .g)쬢ӊY#]qʕ~5r"GSN3&JVoqq1/;~ha#݊l SfL~C}jYfzk~~~;t 5_s._5  j._gۧW'=0QXGV7Pk'<̿S gSr+G{bFd+S}sȟ|~ߞ,Yz`¸֭[ ΕW'w/Þw3b2dʂˀp W{QyUIDATÄVZɓj9z]Nq7oQ}‡FVpogD5gNYW [5k֤Iye˖6ոqАnׯ_W%޼yH`9SX]6mڸQI'-!*UͬW>c.Q7Hs瀈>7c}g+ NB0~=scsǘ?p|DGq=Y{33b'=Ѣp W\eJKey; 8'"\'"G%Ņa$~͛eNucǎ{4pp]mߏ{dGh{bD=?ϻv6եKP`CXyGCE3EVIpwo9 7mڴR"ֳyGf̎'â^ֵ벏qԋN;v|MB,x?1}0eЯ:?D}}???Zk"lqj᥹s]jZW\9`KK/ 3ʯo^o, ]dq~?핗kެW.6bTvLʎ>9/^uE#\<4i05~_`1I5 3Դ,X,[YSnjn7ͬuec=wڭ>l $Dnv_8??PxAygdknQYLs gf=egMnVF.^>Clݳffqfn̪k_?pX@F2M &mn9Y->dӒ a}5t uÇ̙ZYB>{>=;&DP^o}?1i៺_ׯ 8ж(O/ϸ5q-[K>c Omzߜ/DP'믿BsWoQ|%o|FfMe7lp;ZˢvWYSTdmS0KÌ-yŝ#"d1K=xOLQҵ7e]Z뾻 Gҥ{Ae넃[>\ohQv,\~]ƶǘ<~lGc(1H73EDTsfJ2\4 jgމЈЕ' lެU^' I '6(즕k Զ=VƷkwvW] }I-.@-fu;)EA7kUp洨6mlvzNruM͉Wݥ ޘGXaA6oqQPPP瀀7m2;M,MD5,wk\7|B݂&ћR$zl۔| Vێ3v{Գ>&J*,F*~#""Ir[jGgS\8?\5Ϭ|h Q[/F̺ɦC8e(j}5o޼ aMvQMmFd57+xMk,i<͢gܳ9^z8ТEI%X2QYjPϣ86g)/S^2vR=&:"7i2mnX,crSھ)5i<Rv,(Z<{)fi"%ڵt;c.^^+fUtqǏ.z_h_O QtA|D =_4[hW]9⦉Sl崎a7ܽp Fڪ$&]e6m~kjChx-_6+)j-^ϝ/ošVԴYZ 3{imӴh>[J5Q %xv8ݒODDRQ gjT/},s[n&rWN I4IcjȡaǎDY_}i񶚒}Y7h7mC}CJy$ a[?,T ~~GNKKY8HD=9Zx`K?g /Isl]2CevJκ%_r2/y1n6$1ĵ/4K:GDdk߾Z8qPXjkV+cty/ '3~RN6+FIXT[Uo$0CIy% MbXULdПbت]og%ԋÚڱL>WIP N۬<Ԅ2Ցs):GĻE+6OʏwޔSIB菾 W\1ep R(MvPV}-)'"4Ȉ˦]sA5֨{"]Nm`k;׾NNOǕ=rEXQS_ԋZ~da{jfp4M>}#{yڪN?sVwnݐV(+7d%^xPqpn5߼҅"aZ 鄁-,)`m9''O|0V|Z֯pg> d/ [;5oMȹMٚnEd`b.ׯ_wss[~,I56Q_'(,O {J5kvVZ ׯ[3C;>{h³/NzdF87ny` g~xyyM:eK_z襄 2,s27cğVYc_TӧM5+G+X5n? 3dlP^]㑫$+K:GhrǻEDT :W^nӺ,p_&<'giYsɀ|^q+/$DZ^ުz<~QRkX5f=?*J'IԕǏY~sK6K>@-pg~@/!I&"n[m۽[{vG#޻ػޢNȀ͞-{俛nϔ1_9b '߿ߗߊ,Zox=lRŢ)TÈ "+8wKM*.. .oV[vZMaZ~dz}ٸ,'QdOצã%Y8sLvUkVdHȍS۱ON^_v"de+/)>ɋ/YkJ e~MhӦ0W_$.zoC/ڶxWi?gtΟ/߼ysa>+; wE;srDGoq Yي p t?Njhn@Kna>>kD}GVTXd֊ӧMpgΞr_u m>q32p6ׯ@-w(gި9}|pT8@L6[G{hH[Fԉ#Gۺvmޒ#A!!D>zeoKP-mv\_6nnnkձCaqyj\pJp<<<<ꄿ'z:~Ľ2;[,W2׶-갿 :u#i;r̈FXt|8i][yyy .]0/=cܹ׮38ƮNw6*姟v>4zpf׮]ۼe|/!c%lVT/^\ioЇoz{7n,l:zi$VHH!nnn6'k\#ۓu]ޑ~BswJ}[gvz{{ wc׆a?ክ~=86[gԀQ{?}LaaBRnj8reOOOV;uMڥa~dgv9ÏA~_u!8&Mۉo '{t M؁t:qpK1pDW@pDW@pDW@pDW@pDW@pDW@pDW@pDW@pnc             峢C}tBc$勺t9yBa{vݸci@o94*͘UFxɱAݧ맜"V5.vU˹IEwX#QU+ (X2+OP<+/qWҁZ>^=jҨ\.g$ωsU <ϐpaR2B+6=6O=k0rZ 3ω ӿv؅ٕGonqIr {;'%FouΦ?}X/6{fg*DʈQb3:r t3r~״Q SD2J5["tVJbO_T_=zeY1.tjrw{`Fuoȋϙ;j\H^zkh0*ꅝCPTtsN5*'C1T1%II˫v4,zyޛԏ{+˶?7cyO-%OaS?;[J-lNvENU!zv2xj[Aˣ;<&J8YP5{iQȢ^6x-͛ս=ɶ4 ] )cӄŢV(C4-cf-\]xYXoj|3㦆iMM a9R<"Q_w5Ep[E?m4s䲔9tyՌi?iJs 5Ȃ~&X:vNj {줩7yO-/)aNȉiƟX+x& Vo}(g0YAy"WQb+WÁWi.n&yr߻G nɛf"jToMSm}/Bj/X+V |>:t mravh5r7dVlPaP˳/f$- S<_ @͂씔lfSgEe/n$Mhб񺗮?'6:H+,75ޚҞGJ.ԽU gńU*iڽUrWtx軚TraF\heƪ~"ɱnVX3}/ȍ2s,;2կ0yjw(37)&%5sT!fv?ϝAX?/gD՗jlC_޺Pj] Um* {ߝ2$[7oqfV)Á^iFÙZ '@571|YaɲS@a[_XV5l7ѝyDpdՍ2/0( "Tڙ 5С=};^h_J> & )CFDzzxtLj抧4uޟpP\]pmXWۨ ZcCl~4Q%:oҧ<(7\8~ʘ;#Xക+nXlp[>eĞ]6LF/+LM}cʢ7 :`\P$ R=>=2>xpk&:todUڦ~klG+o4TD 4l[;pիWMT cB*STrOoM瀀nݛ x@Cܽya!\rٳr9y!oCH6&?_/_*-6~kp$C=1# g>}ǻYf#N9s;ءc7''}АD^]Y32bAgrG)@CFOh@֭OV YYW\/aajSp MaHأzڥ G9z]nC@K'OR"#j֯ONݾÿ``Z8"hȸ429_N~/]S-ׯ_(>\Zx [F-_Yf|h6@w^3Vvڍ7 \$2Le*[Sy>m]o*3r߬#//7mޜuny&8޽{ 8pq?HݾC-jJ^V|lWzzFƞASЕ+Whݷ6m;# +N5'مHK{2#p'5GK^}e/'\#!'45 rK BTT?aӧ,YlKd @:P_ܹ~U/^NPPpZ؍ XΞ3wF'_vUí. ز-Uda@,oΗWa'N$~-mL!ynwwwaO2TȔi߀bFiTL'?4'n&4jL{l(`^ Ny~5id><{hp<|}rZ~jƌ ߭'/?A}oW@`-y5B3dp}zzxޣ{Z޴uIիZ{+M8ߚ߳gOo^~]@}#'ZYlR!Nw=z;hQO>_Uhr~lYF*NF6K8ʕ+G~aèVTZzjxh2׾};`֮V-gԭv 9B-4#"k?=Ȉ-Z j'##C-ypZt 8]פ`-_r@-3RN_?m䯠FlKU oȈ80/=eKksmۖgNs4^r ?U/'YrzH- XŜ ӧlY[=IQq'$ 0k1آinRV5cj>6 ?~`[w({w6PneV]>|Y[" ?0ܼw~zWaI38*"l`A3$P(s%LG?/ʈJ0]fXs4i}+ \Z '53'ԭc9[Ea 0MT֍R2>eZGM4՚}MgVZJ?)yVEy& H)>4a|RqafZ[p0ޖ3"?^8eN~m9ڈyEx[3?o>n@a+OT%fjȑw(3q_"oSyOHJJƪoO"SS$k~ʍƟ h }gV*7Xac]lx"%WKD _ZR)w,GD[9>)kZ1R&:5WW'<1\^>(UFU}.#J3QG3:(D\BSB9O΄rk$RWS^՞ p}3+ B2X5pcdeMCB,S&*y&8|EfQJa#G^sA1W˯aFFzzJedJw]d9jDL_dn 1?SәUiy2 $Ty^>P p+//q E*lKݺ-Uh.VJ7‹s4w0-Pؔ 1h-1l#~9\ptQQqYY~~,XH=<<|}۷oNskM vG%8q|aqqU~=UTVm߮];.ft1Ύ8|䨼$`#.]:z4WNܲe˻{wᨼ$Fnnlӧi~=4dAZhbF =7..^b#(}Ή㴝Dٲ-UbrKvm=ZΥ3gΞ9{vϞs9:=4a8,$a5N:UXXԮ-ͳ39WW3avbz-}d΂>UuoD-yvov1>h l׮]"ѣb<==3 ؈vS=w}:P7vNoҸqX^9;t"6ҭMcV+"p(t1{k׶b80-['MߦMqssW“NB&M=Tn}#Gd٧j֬Y뒓ݻO-m/P=yנ(k^@{t1N1̠O%P.]8!DNNzGw&܊5?7/OE ] ! .\P ZsڵU qEcD] !'3\xQ-xzz 9pUF됖%~spatzDD0Ír&P5.8pDg@"8"pG%00遉 j30ka{yGzzE.ʫ /'Y0kEa**oqOkrgǮq納u\pBN<M[Wyg#@uv[W_?1apa{Os!;%+ 6Etpr2 lv$6h{ta+"V'υ`Z2 v]O-B?Ø?p,'Stg7R?J?S]eHߴSԙ0]~.Js(a}[l!)!D56NÚmO[uhРL;(z#oxERԍ8+rʴH@n yL?`-'&ۣ74|piPSiӧLz@ٲ-USMgVZJ?cM:j'l3+e 8&"΢ KdfIq%8sտ?11+2K33.SxylN~u^c3 |*-i$M ݐ҃i_̞)YR9G>oHok'ZMC4ԟ%' nDNNWf8P[~LS;KItXefjdثq"AL:cm+-N]=/=V(̠pڰY'iO`JvFe&NTOlN=yq).mz/2S+nB!/>u[: 8ϬTo [<6mE3 .lNӻ ]-423)҆W8zXwL ,LL{Z{6F8/]K'L&=P}$ wCN^X㓲QHMt! %x ~+O xLWS0"tY×ob]g L1^+5}aٽ1By4цg&ť}sUZbhjʨf =T_6uΡᓠ3aPRFˉLП"oȜ=Ґ/)ځVVO-}Z3oügLNs>y"GW@VYEy[EUc0\#C?qBYOiOW4yڰ*q.'!xCAD'K+άku`mR}V Uc0Q{\ghʴMQP3U7P\zpt1cgVϩ47Srx߯U"%߈>O`pdŃ ӵYjiՀ/m0KgbZ0=agɤ-꫻Ce^vi<-z_۪\%PxdAu8D[ϑ+g΍^íұ1Aw40ͧǂ߆ޔ_&_Óuij3 N3ah"1[5u!;ҨrNqV'vI[i t㢊nc4/OWs7pfRdDÙD!>woهǑӟ{VOJ?vG9<(ʼnj.NB>|xPjf&W4oMeMBi"-d5QIt5 ԨbXnJbzvr翹UBT×&V}]$vu壔'0گ}e:MC+dC>UhTdݻ.e{iNMgVaRBڛf<46/S{ky^>P cs+//q E*۲-UQЀQ(YM|c~ܛdŹs^;GV@ Ÿ%PLk>O54+DIqa]nUOcv4P1ϡrܼEEE5\p_oP7o۾ݭ]t p 9s/\,)zU诰j7o|[Waޣ$#3ܹs12ZϪ<@IFeY1>r/ N.)$[ TG~c8kݽi]XeFAT~@ѐ%"c?9zTk׮mߡ̒A>a@-\re{]MQEFޱ!!Q"kȶ-u:uxh_0S~~]HvkY 8~wFԂ ZkO/[AGm|ac,{K6A^j PU jӖ®,t .Pʙg ؇ewtǔ>>;tqwo.qŝv9( ꜦMNz`B??cXsG=r?'RRRt'/l2W:oߢIϜs-[zs^, ٱ'~pPP6pO 9;-cb]~E ,t1y1;ljW\vm ԎGY׭O{8ՙ+F T#6CSƞ[^|Մ/}:>L=*Ox@oNNUff'#Q+UPt 4_3b2|8X-o䉎IDAT؏)?>rDh5r'Gqnob l~vGpo//cu//an֬@-u]>]JF ._.[mGqv"`[mK޸q{toժ&=0t'N|"g-0~ Mֵ09@9ƏO|[W˺8@lHd!cOfqY±'U}JZjjgss`y-RN `JKlhn"` M\&!1!Z4P}N.f't1.ȟ>ߏ?]D`AA݂oSo]-aC6oQ I2-m S77/,r;4 }ͺ\^{̆F~9|Xͦ;vד'ղr VZzYXƍb梋p%N3/7mޜuSN:ѱc޽{ 8pq:tʕ]ݿTx9/͝c8gh#Gs]_PpMjX>9uÇ+,/^UV:vڵkT;G-\tR Qeޜ'SF h9Y'Nk==sFKYWR\h}va3Mf rfb{̘&OuBpOO*K9թJsmٲk~ce[Zt1c],w/M9~s^VGv=_u;>hɫ%} W 1j V͕ .Z+--Wߏƍ]p!;'GNvޫ=+/7o\MaJꗜpSrɋ_W=su" أߝ<&%?*a?XGP5'jxfb{̘v^wZz뭦+Y&/>"t1 MX.fC ְ} ȃ*cYj\_LI6ww??M6_s Z2]L['˗KXjr;n!*K9*pDLd߫jInYVNhZ~Pl¡L,`UkB/-#9Fԇu;2϶b*snӛ7m޴y, 4Z 4G4{_ii{FV>~ᐰAANf nܸmٲ۵_hBXD-){ÿ-mٲZ&`BSM?뾻?$0$]e#I6{$lZIh.< |ק7~ab5`@EjU+Sɿ='ECe֗B۶mLǃYҥKjC;5eB[E) K9™q2 ),կCZڷkwYٳ={2Ղjt1Zv1ӧat1awGn8=sT^ 4'Y^^Ȕi?ŭkVzi~y3&+˔i3777GҨQ#p삻w?9cZvp?{.b%y@9 _PVZ&?ē#l'S{UoV9i'==ˑ9ș8Ao^ id6WC] nM`F©|j9%C~~5L$o].iʔ?noݟ:cbŒ +vhӾ,2'ҖmXPN2Ձa} ;pNd]Chg&dƉ923#} PbVv'jϙ"W^}7rݟyOzwS˯IQra.ߖlފyA!A9vm[73gcM\p$Ii\4r2.Ӊ,@s|bEw>s3 p2{ªk -ZZ{ﭱ] t8]Spp[ݯ* ݛ_=_±Wo4mT7lp$SK".X-7# g6pяV|;zD9ɂQsrʩ~LiS>Gaԉ,`~+Eup2 $lF =4TۣSR[ƍ?:U/]HnwB_tgl̙~^[p}ww$#""bִЈ74aIa.ݻ =S_Ҽq&tӘEw^ 5Е3[xOSN U9ɂ3̚2uzqjh'l>H#wԋz'Np2"1k~WK:/~a FD4FGd3j_a6OfeAjܸ Q˛l:/emgwvb _[.ڬ&vk굠;/ c)򗑑z-5s.Ξ\wL:m f[пt4Nj ?a;wD4hwVzMjk.VV4J掓w7Iؘg]hw;{%٬Œ1 ;zmLiiKuАΝ}|?Cau"^{ (>(,w vfO8BI~4v~4֖_rrW L6_9Zumϋodݻ-s;|!ܬgGqko*BYCbw{T0\3uKտv RԱ|7kZ!75OU w5uIz}ڡw;BkZ{R (ijhԨ|/;6*j+ȖY.spe?sbb듏?q?an' ڷqVY5-ޛ'BjZT'ۋqg&RlDؓgʓp-;EAq%{GډmHFvN5p@u~u۶[O&ȘZ6bu.f\bƺITT~pMY(;F<|,X:xРMoS;!nF ץVsrSJ!]eƨ5g"V:Z޷ZϷԵ'"t (Kگx%"O\Q~3>.,d[|k;׾ukڍMVhx۔%j3+ڵhuT{mW47읛^5xs~עA C+'tYiv s[57薧F,дwYVEEk y*~m88g7BUO?>;KNve\3v{ܠ-<Y`ب*Qy'4k) ]6f7kJ"^Syo2\RRR&>+,qڵ+WVN${̫GRG'l3_۹Jv[_t{FU7쌆qP'v"e&j@`a(*}Gn|ptWi=LQ@+[4cG^zeff[~g&[c#|獊6//FiZ~Ӓ۰vwyN,55>{<0)ƾjlqc\Xߖ_xEQU6rI_Tb7م@T>T;*jjӛܲ2`O$ ;w>v옱jƖ`,b )*&\z߂ÊOL?{ut1gbAAAf ײlM*MJc~ 3e4W`TCe0Gί߭@+M9_I(F+hIDATMvU6wo. Y.6Ehz?%+ggQmD7)37سf?;#>}ME75f[WoShJ4%*VQ2*y䔥R^I6?)kƦ͚֮bAlJ 5`T#(+n﹐tg !Celv}^D,BkNҥK7 3:Q`ߘ^!u{~}Ȃ.7K?%#rt9~>`39~sF3~bqG;[ ~b=?vMv'}{ٕoהLvRk*]+i:]Wa??efU6bQ' XMW;b} ƿajC5چَnyj<{lqucKQ:K:W4Wtg&Y*ˣ&ϭNtŞD9;Un02VQq P x&&!_5Atk4o 'R+IП}|37͑5a֏0_g]̢gw.VgjM4a?FAT7*sٛ0IN#qՃY<6 %16)隌|~|kI$-$_58)ufʏm F*v})HC]D˫/WTbW^k%7-矮hZ9b@ֵu׍.2\TyOqsO>+W 5- E)2Sv|Ӷ-Dg_uUJ͟-9.1iډRjPNqrv/˕nDr˯Fy2@ aM4dRxΠrj|Raw$z c3پ؁`+FG$)5 G A_^Sx%ՇUWF/ĠnxB-;sLF,R޴ WQFޛkиmy^d\nnnXa}7)6z,<%PPagf*%)ךEmj'<7%QO/Ss, o>5_7;=ꐹMA,y{>pO\7c䯤>qJKM53ppn |}}fZ&Ah~Kk Ijҷ޷HҖ5qC%WouCvY|39|ve#ȿEAm yŹs^;-RnSr 50GK>d#*;[cӧ Qwyjo6kק{R6UW5jJYn )z&U.]u4fӟN-%$~1oܸ>}=cF|[>>5bNT5oͨtfl˓ax%-fQ풅ځ5nr;n!*K0#GVЊ߾̈́vw 5;̻Ó\Ϊ 0MTǚ ??ov83od44z5Z(>NN]W٣E5fTjb!ZѡMDmKk׮>zoѢ"u߮EXŪF _)P_E h[,yheCu1 }S!WP(,aS7H X}o^-8(ON%??_a'NPc7ra"}Ou240O\IyB-}̔+#B̢lJ\K[omʘ%ϵ2F_t=w<6ou[c#"b_>`$!V?Ofxr +s YVMI0dp L=h K:G{Pic^O:%T܄"2&'/'ޝ䌙jc{Zj壏Eg͔^$89{ac'1To[_t3mɚ~WT\ MJf`S_n@`a>eSx) Jb:r`cl|P/:h~yXE[ڼ]9SOj>' Z~ wf C&MBu3/޾uˀ;ҦL{\Xd˶TufU "O)`RtV)Ls/6;=vX7uh#~/,Mh)gxx}a6yAzosm.O>WgO>}DܾIXO`}%)a9:&'6a3t2ãҦѮЌQG_D؏R46TuyHBthBwgZ8{%?n2x|lu(m}{S~W.t &N^ 6 urJvtJ3J{1TSڹXtvHZD߾1]IԐ+PT." ҴƶUt_諴X5.7"Te΢T=*eV ׻G5E06LhO}~]ڬhm'_1>殙ʯڵCTyj э1y%;&ϕr͠+:f^^&{F} m 48p]7s *)wTb~mws2W;*؅>A!M8\۵+]hF[| JY VntF5R{Gڛg&Bin;_/cJZYvL''WxQsbL_WuI|2S;RyuKSm-Jl{дϤbAC3daӟz)ޛ'o"4~a0鬃w>iϓ{yO \*0&7\K=3K{o1s\Y~0{MRE6g&dFM].՘!TQ357n <$++Kt ڳ{Wƍ.V]&굋YI7i G+o4TΔsCCelዓ^8%ɋ&sҭwNzl?l;g0|c#WX)ZԨpuԉ,`}r3 dVQg5j|f͚ѣo0ڽ]Ū*gl̙"7~w;jY^; 3dlP^M>&BTIcmB  ( c_<o3Y99s'U/% 2lJs2MNE%_@ݫ_ܹi>ht7z׽w =wE؜g例3w9h"( ,ҩS>{Y~߯~ИA}#^C?//67?˲~? vʐܸqC-4i45qAh4@-DEqNd{F04{ ;™ɌiN{8hѯߝjpohݹu=ƍ?rj~\X{˲PVVּysc7Gu𗓰νcFElx.]O\hSiٲ}>;ȖgPN59sZ6䔅ùsB^\Y~?(\)+3Qe u3 X2cڐ{MWT}XN~  S gΜ.Vt1+kdssnAԋ`R>Kɸ|otףKmˌ?<)]D۵s/dذlW[Ǻ N-ykm INV8yZF'͚Y;l||ŒPg&ɌiwF©|8 ݵ"5}]J -[[YMNo7# d"+ 砎=zk.V8_XM=Dl=eXN}n}qqqNGlmب;UFUvJmcO2' d %gx:oڻOhq{ZyPw!>bv"XaaZ vNW$oi&f{++ӗI__*-&Mg-x{{to7&ӕ#߭ aBk.AAGss===GN6`؊Z[߄ .F3h@ƍ ի)?oؓ>.]lsͿםZӧ ؿYf&Soܸ!w: 4Tt1;]@vb\?s/2'4wշvߩcZN8y2;''?@#/v>o1aXzϯZ/i ԭvm>Poן9{Vh7s*9_]$w৯ôչvFӏjҤ %6[6wo. rWkש"*..ޝ!'Rʟ}~ =BC5RŌ޺7n(++ۓ%'INeO[mr@oKJ_.֖mj.VN\DNӦM'_^ݖ]MViͭP7#ZewwwÇ=wk߾윃2֫@pc]hn.]b?eO>Cw,m׮>}/\G+o4Td^XkjeVx;?0~\a?J Vy{///'Qqŋ4$DFڟ\z9{߆Աc>M6+tϛ\t)رNj9+WBƍhn"+4?=eyrZή*[nܹƥ?ۡV~_`lST2Le+>}f{8no۶0V"8" x{{IX}j!3+6/^x&*Uz(ܨLe{WCC︽j{23ՂN&򎕔xzz߲e˧f<G_(tiBhӺu[ڴ e$OۧNέ. 4 NOϐ?y}E\BAAA; 3H6na,X,F3j.ؼe87nlժ,2^VV&NhGZZԀA|Y5n$Ǎ7E:uk׮s bb?_ڽ;5um듓ȅ2@ТE o K;ftRbC?r%0/XIA6m\e#>dy&QpT-pwpaa޲#ά]۶ۉ]?@XEO[YPpZ9x"Vh Ed߾j!u'Nk! ENϛ,y붯׮z4 ciҤGČeۖ=|yɥK8&`jj[niӺ~R7֢{23w-[yzx0k\pB4)?oJ۹҇O?+?/2Le*S9z]}p<P1ÇKsssPYS]:KC:N-Z8w>{!^,22y*<:vѧahP \>А1pDW@pDW@pDW@pDW@pDW@pDW@pDW@pDW@pnc               ʍrssZ-~nn~S 8;N@f4:GFp {Yܤɹ Scܵ'4zVRv0#aU+ (XyJe$7\as]d8lбUq?)\|lf_cc4oojQUӭF犺}7IaCƆ5}dվ, Sk\kVJ?<5~jtv ^..;pVe|¢рٹWk> rZYܨ-bל4gi)RiᭃfT 昵܅Q݇>ܿd"2M.AS$;U> w f'7#&HX5{ԚEsվ0תk抟kbZ:P˩j,+,4H73ytRRZV,=)ʬEic3ase'lbSW}04`PVlwȔw8My`J*)Z$792OX,,ffI.4i4#Un=uVh,e(k)OTWvo|eGK˷=={ĥq˯dT{-Z=j˖S'gvravҬS~w^n4-E\]NKwб3ORP26;VZ/lFRFъYn] ,M:5~&W+Ը?/Fuo/4:vN|rF MZ_55]h>j,jh_5-Rܵ5n&URhjGZkfVȳ?Ǫ寊JShqaּ¸~ q8.+^2E]]laYAOߚ9*C ЩIlN->>p IV$Q 1uaqF:|K}0ԭ}W龀coo 5AflSFTTu]](ꘌffw׻bAΊqVޣNԊ72Gm5c4wዎ϶Aׯ!a~>Brv|_3WSPT1A=p09#PsGeSaEgY:2A)ꖹc|RO}~u3HQECD&d ɂUj z$'i 2녫vGϗKϟ:xs ܢs+u <{$̓< TZK}&[-}04:N3U мk5720dj[]|YAι˦j M.>oaje^mOsqMZ 3p8/tV2-gn( y{Ԭlm˅)Ί SnB755.u<򩚸y[ ,-HIn57#ialh.mEE*/L׾PRgE)۟*P~1s*^{~a0#jhuVעyaD/Ϸ;C)n\N[yyy RܑJ*Lb씔E'TɱnV;rYJЊcjQMFT<7)pLAVyIn_%̕0s9Ɨ{YbN+Gui]h߫imv¥~6ܖ/׿mRV손sL7HuIa*=vSٻ說{;NLѢ!%*:@B`բ*R_E[_iZ >Q*q1 "u "8I #&7Ϻ>{ wQ᜿ԡ9ӷ[IY昹Ek3oT٬}N>ʛTmqݓ.pDی/QQvaXj=slG-6uOv+M/\yf?GaD>ph5Ӯ<7}so~rMQ_1y=wG4+O'm~@5yb}zNJeL^Y06=5O?$ZWs&fDb>#.9qQj?H)%%%)99ѓ PjU~ojunP=͎3(=@}S>h$Gy]IDAT $ $ $ $ $ $ $ $ $ $ $ $ $ $ v}a]Ơe3^<>:Uߡ]o<*Q7ݸʙǶ<1iųy:_p.U[v-jϜ?ʭ^$t}fZI^}nZ]>.>]/}o\|=O%CrJ:l|Wo\_nW_]1j߫΍Gyn[y݂#\Np]a_?a~?o?kP[}R%/.غ%^%v8;G?o0/N9/<:?\?-y87} ~wBή@N,_sE=~W8Xg8tDU/{J(# [uX'wf#[%/9!6u{%wy-yI<\rëF <0I%:tg٪M|{ؽݷo6gڱZ'vamJ=̡mBْ~aVT ҪL84 >l64y6nܸWVG_~#>_v.ґy7N}?>wd'jp(|A;}:wxA'#gTj%]M0֤޿+=23?v@֭@}+jٲKNZ[n[PG̻k;הz?AtW__vi5:A4-|)ݫg}T\޽W#Po$:Mƍܖ-[\>z@59|rnEUb@S-=|I=w@]3iYˉF޽ڷ?8r|rGq uʜeݺƷسRBJXU״߰!h=렃%~QkeCYo+}Yk?H?HeYg^sWy|tj6=kG:UU7iա=qnV#Jn8xv8/T[K^\nZ%@CsON wMȵ[?UVN`O*s*{ l)=0> F.,_<Q1.}&cmeT+tXĹm;魉z v}-O?vkYW67/a $~wx}:7孺oYu 8sI'\}ؽg>uΘCS&^а[(;bƥph:'DxM D &&# vٴ̸DcgVU/9W_(1sđGܹOvݝmR[U쌭wU-8p^aEΉo}Wjⷣ{_raGҸT I$1nlؓd¡k5U_dײunxX6ndƍٿ_17}.osyy7N}?st g:W>#֣G۶m '6-Z?xݺu~ye&5M6oâv1+EEk`K&dj[=?osؾg˖-/,|q/}g*[=.h4 sii;wڵ%_~ܧ4<>DЊj&kh$״`o+;xVj/]jrO!6nx^=|p-[{|:ulٿujh͚5+ܩi~hɹOxͨgoy'h0ZjuA;PetPڮs˯DIj4HeYgz[o9{tRS:d{>|W=!ݺovC{[4;lѢEDĝ)..Mv]raЄedN=у;{3=!wcw>P#|IѲe] ^8vͰ~P}gIIɏ]{{=}]HFQ=S=W#hޢx̼)))&&(>E:'ʙ5iܤ͛6G?Ν:uԑ, wfШ&#.q3&kWQZÏ<2 4H4% ac|`޼yy_hLg}_]& Mϧ{o/46z7V۝40e'^1%sr}wFͮy1IDAT^{5 }}7j\Y㏇63@DcsʏOI|-~ىWiLC?h7与:kNhߍ:ԹS+4)òRUMYY)W]:$֬Y[;'>ũQv¬fW/)[hQqD#v;8@\=?4$w !))]U K?{~hL]}żjz$:U݊{9O ,:|'sүswsnwk֢YR~;,1u5j9[Nt趌^n׷k&=.a顡YrAv;3ٿ]^h>/€:U*Yrat1v±z2Q{Wcz Fy۶mWVmRkIa}x؝ugqs=c~󮉵wnƝq;ۛ^XXX_ǩq?N4Ɵē9|ܸEIs^;(Y6,4^qWIOϨ9O$?ll _/= !Ԭkͪm~w:6p1ߛ,;di̘8<7 Ξ={.YdgGUXcYmCr\jIa K&ݘ@uRƜX9kNƤYWU2(җ$vM͸|Ȱ)‡Q7%L=iHYeD.-XvXR[1K蒝vYfO_lQ{P;v`n177i ':$FHe$^ 1+Jn_ѭGGKc:E)`bٿ(2ʴ׼?ĽnYkP`]0]cpLį%?՟bbdi57ll[I<nKr~_ߤVtׯ_hStLE*l7`axKMKXVnH>|jٔL2=&BQXo7}09BE̬P ;u츳hv:j0;'+%1W*J1eB,hn5W}^lVdU+"ȹ777l5j~4Ջ|l'5ik/ Weg[> _}Uz씜(>*Z=WeFfc~5?g-etY}k8nWqay2zha85뚜 q7v]o=v5 MOP 4Fm\_cgyJZߣkQc{u5e,Z°ĩDO]8c#b_lBa=J8xeEuiCshxWW8[E^7jgjuQ񠺢x+jbAm~Q[ï*d s=fu %@j1U<%/ZNQ'&(KѢ.%+Q3Ī},^06X~j!̼#/+%^ Ub]?|Nʰ3WòeƷv4[OM:yEi;82UlU wr?_|E嗻sVV|i᭜!+\ݹZ+Ե>|e P]缬zm}sn~;zmQD٘/e?22v Eה?ҷeϝο&_T_ɅolSPt܋sBPsTGffK> 4K9'u͚ee]a]/*B2=W4y]5"M?cÆT(튝*'8Ƹ\z!)/N(LߓgUzH5'"k)mfڕnyhe{]?c,ƈ|I!J.8jee ]a(96go*"حԫ${s0i!#ҧK'EԲKԅ3Z;k6ѓIs^;Zo4|ooo~3qG%Vo3݋d$g/ y%Q\Ct^xT˕=cp.1ǴtjBiٴ]N-=նO hvX,ʤ̎Co8df%ƻgإT BT[ }>~sFjKgKkW,,\V(`C~g8kC3fso13wܻ:~’!Y͋Rvd-Xg6zԿQw^>Tg˛\^/~-y/p…!Yʵoټh|vj5jٺmhSOnΝFWzge/ǟ5>}]OwC% F@cDD{̅ɓИ-Zv˟헞~iSB!Y)YK}&hޢD{ڭ~[#0:Ede=EVW%BNa`h/O%VJthb:!Vcܔ[>?>"ԹJFaſo 쒬BNvV?M-sO ڶm{㟒0,W`X5e,4/O{^MZFzۻ1zȢy?8󙇞)엝}~75"/Z]4oiO]-ԩSRRBwu3t" G'W_5{G9?z&6 z&NC9c[4@e&Z &ojYfƖ͛w1//+PM":4qur{˺ݖ-[>p߬o~ڵ/Pd֑cӆLz!RS&ohHM\Y/:oԹ3f??$c 1gբE@V}=--Գdzv>Gg:X:OffAI))|ٴO6 $گ3|w5c˖-Q3u\2u?ƍo`Ԗ&)*ZjuTM7DwUAU:Gqiݺu5-:scr{|˯buU'Nwo޲vܧ/jZa?I״tqcHMM45~_`z<ⵂe_|1;~Mf6|uԑ{g}E$6{qx׮Iv>^+))y1?W_#3m@\|-[HlvO~@1{׭[UIDAT5^X`C}:tF?K?Y[Z':O4T)QSO6 4U_~/,|Ԩ5=3orI~e,O?d_|c. ԿUy֮]$2iJJK Ґx}˯km@eV{kt 4}6-o{Qc.l֬YhThJ:uk__|d`O)\:'_ӻWD }./P<κӻW{썟|w˯w{K~X)ڴӿu׺u{z9cw@]G}W -/3>Y H|Ï~ff~v񘔔+Wκ5==J7 :ho@&U˖:⏊59$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ RJJJș@@@@@@@@@@@@@@@@@@@@@@@@@@`ШRܰG};*-%%mTnq{|R/o|Z4O=hOC);yM8vv)SR8z;ֆyIOm^Oڢ4lJ[3<ԁQihⵛK{-{Os- ?1Z\f_Ģ(R[99#1yeIMiXgIYZEӇ< ]νM'd_A9s>9\);,WhA*f1%Y]-?b`fZxvۧSFlwًBΘTMl1yѵfnJi)NޘPOZͳW QTaAĶM[^TRxļj=G>lLӦeu N>-.=6;ߟVŶzM0lnj12C+ *f6O:}ќmcf_q]QspEGNOMO81bͧrmZuHi9pEEZ'93F7i5K7+S0{Tf>xjlEew-]x=N9`=9|&\ьf?>Gɉ/ X麀;H+FXhG'Rq]sN u ;pe['m^쩙_4[d]K OZM54MMO ux V(EzPuB>7elgܰI?xlܶ!קꝖ|B-M}Ё;B)%^{ɗܫ}8=sJVOZM5 ԥ*&W&]+wԦfq=NknڽF:tEzd {`鼻.WV c=3ν6%voh͚'/ke]EEU\4wn))))96O=jz uaUaaj}jmo@g.դgڈy{%ګc3JD1 r\Î`̲u皧5tDzGԄ)W<{┵v ss~jvNy:+OދM;]۟]L/{iqSF-7pzQ?i5^^M{PO .T#o|ZwȥN{MEgH&tkܹξua玟fsGe:*;sEcC{촻 gS2^l?-oJz;9VVO rO=fV|?;{|]>/mېq]~U;{DOؼ%hbfIةI3me[ɛ=>ڷosyNMN+Lޫ|dǟ;'˨i#f}? 'o۾s^{xCkriW-[5E~}|g}M%:g4m~@Rk?'^!JKS 4nɖMcmhԒ-unP=͎3(=@RRRFn4~?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H;M>ٰ.$H:@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2R4"IDAT+ڪyƣR[u@]{Vm+SVܧQh$ImCSޙ7>=E\?o|5$j%{Y ꦾd}oM{X;'Jm݌O>sY\[΁}hV:·SՔ~q}o{Sqi'7f}49K`B#>y?w8JkТ,clgYzݙTۣ1F_ܒ뇝޾qKE%qOnvXl53ۇ|ncqu (}Uߥ{YUYs $(ZPqˡaGwPZ tİ{7^Yav(R:!PV/ }MOdamR67^\&vdF_tx}ɡ׽EdvNݗygV/}9!v#zDу1;\_Ac_qpWbdl}@(m\z#Fz^/m 5Jr*p²/8oki{/RwIrW/{oلīl *QP4좳C,WFtpNƛK3Ká7q{Pqʓi.MNV<{XY慎=f"ohU7 =qc.htD/{h(;jMȉ#л8l~؉ڪqQ׋m7E}MXpEbhm$_Y寿7Fv1ceo>\ NF/ZܢEmffѽ>+7iЅzdv1rOt㸓rnKSK߸wފS6^Mǿ?O^IIλ>}(dӦr77udSoO_t Be9a™;s{Rkt}[$O>b~~~lٲeSOY{N m%UQQOj r{|˯$!׿־׿ xcW^͉Ν:?PkI%ղ寿kKNg9,4H}$ߢKF۶mvgy(JlQdݖ̌yfWdf$s`Ν؝~ )I&G@R'4ry,Y֬Y:tرW9fתjk |_|U W:յkzΝwF{a .Ɗ9[izd !θ͛uÿnWW{u+wyK~_#7bI/_ݽUe˖kssb.J+^v~}ͯj$}VƊ9M>ݴiSZZPM;qSOַ'?>|sؑ:fCtӧo[x{n1coMbI?:wty{@LlvRuǞr)ExsGdOII s?7~;# :,zO~/Gr[krrͮiBhtĭ(b:Eo{Jk'>#3;bś㯺:юKgS췝Zw/1WUVjLg}_]& ϧ{o/]cߪMLܿaOis@-ZjLߜGy睨Ѭyf^^lbEћݿw}ʕ=x|κ/ō\p$3gݺ Է=#qCحchJ^WӵG H?WS֝.EĥcK]]q3͙[RR5~)?:%|ҪM_D|Ɣ-Z(8n9{̬̻ Njt_W/e>Vbީ!!憁,\'4=Fw;8CW+Z~E YqvDg!=Sw_^gv{tC%!_|>o y%cҳEƳ#{_ T=&ڤ`<3o^إÏ>tA3*ٖB|% zL6/ޱp_{wkC׿˻j˰;̉>uwcxL痳ugF֓% 5P_hoח:Uښu>feaQTwNsƴ kֹ=ƛyGȊWV$g9l+5j|p|Pg:<^[%|Y)*rWDŽwl~C\Z410ȲҴ/-}hX)]sꭥ);.\g)Y+y)uh>}ek9++7bT'SF5YmОURIDATTc٧O_y%$"sC5EǥfM2n嬑*f28gi%k3X;7땖L̜;9+'%+>1m}fd<萜) >\+:+AcKklofg]sAVJNcjWW2.TV3`B~_a(96go:?sķ*LJD #h*}p'VYzdU`H)))t'օbQ{#FjKgKk?Y7Du IS7vǽza@ud-X>wUjt/RRRn|ƣOI#]e .>⨱~^u֡$H:I'#33j_|wY6 _~'bݿ 4Qzx=M6GŦF/nᢓ~^/qu}QՊ&1%{I7$/=14Z7\zâyqjJJJk~uxa_0ښ:7|AhS9vʼn3:WyK}ܓؼ|e<[hG=|onMMU$}Bc3k}^ʏ+_[?>>wcz+4TQ|џWhl,οNЦMG 6b@x`*~e2]71 DPRRR~^PMW{oH2ur#˺-[>p߬oCyЈԮ]酡vڴnW?Ff>y;B+⮬ꗿ*X,:w;jy$d:]rErL8v﩯_co$+ Wk_Ze't 8=ԧ:3 ykZ+:lѣWhuX_oqŁ:_D;CC+ENW-P];k<73+Vht7>&<ʲv̌v> ͕+CuٽK׸7v_~ /Ա4ⴵQ~="lXhl>/>zii$WVl6@1/9׿:u옙=}?+pLV6zxNڵu7,:s#jśoo/o$+_x.(ovno3Zʕ`g2-Z /PǢqQF~ř瀴Ak}`_Ģ3[Wڜ>y3b O<|Nvlhw]νMyrVͳNoZimεw :(veУo^mu]꼗)J*M6粣c#F&sgʙ{ɱ?O 5V8cS'O[4}hfͽ}z=7=5qFa7s'V2q)ƎJ uNR3M{mr,B]7sO\}FR{L\TPARzҴ́lQ-K47c&Ć=fPzwwvbز/mUSv39^Oǎh^%sx y j~P 5L>Iv3w607gqcql1y%%%3V{񟏎4>¬𼱙!;S<=gf]~#YSfT}W4}Fc:/slE]*n_Ֆ{ħʼn7>ݬBjsR'歹.9fnNg]%nA NII=ekW0%;)iGM/3p+.%j^*ț;7q큽TM}79Ŧ ˙ ssG?nEkO҉py^(;gx躧Fgmnu__%^ &WmӱX ;zdWq~[_ڠʼnӢEGv۟<,uЌܟ'nۮ%X_],WKeQ\JIII;Ƨ~'߽&wD#N9TOcc)]/_m7wT~fOgo>ch칢)eZDViw.`s4ΟKrkY]~:gQΠP91Csj.}.!&ڕ'j߬lGیϽ5Eد^dqe+_jKX_6-B9@#O?$$$$$$BIDAT$$$$$$$$$$$$$$$$$$&lX`Oiٺmd d d d d d d d d d d d d d d d d d ެf޼%K~5kք=C:vիcv)lX,1oXRt6[k&5ظ{6m:{K֩Ϲ✌uLL{DaA[o|;x oCh"4 Jj'?k&6{=.|E*_-(y7@Аuwy7>sWE:Eaφ'6~䑙ois>o;DG;ګAD_~9G|ݵk^{W͜?Ih"kּu3k _$z'wo^KM:{Gױ[PN1]ޕR6P]{tpʀ'LN-ZhݍxwU={w&q,\ۡ|Qxݝ]嗽Oؙ}BvDg!wgz_[([z8>&=KXtxz؍{R=&ڤxo;`3;w;&maC._ke{`֐/[f ;萙Q=jݮ߇*Zj>Kvzcg-,Y.ۏtm?uxç&J}. &d:`E͚7 P5MgD9߬PGhpP:T;vto?=?qnC| h߾/ u/+ر]Xl}**v) jp>i՛+l)zѣ(Z~};|p|,/Mڇbo훸ѝY@נ[s?f;vuOމF »d |UX6iHJVVJְ)FN/KY#+O:Pw?|Jw|a]*քY^ oaœ35RۥX:]Z`_Y=P!j?p߬Nn OΝ{ꐡ^}cǎU<οيZn=/!8;C9{dfF~B=/DѽwoT:vP$W `[K/ozۻ1zE-~vq3=Se~O<Tw}?Wu@OkW_5{wῧ颋=ԏGy'|OG:Po_&TS=}ԉWj9ln|aJԮ+1zP%6>3^Οc 1gբEP?$J״HUݯy?H?H?HM4{{+VqhZnu}#33@eRJJJ*Ɇui&5ظ8ԦM&)_~ehT{K__f͚{XZnB#gyŗf]/4%FlHRgAAGY;wiw[Z ҆ +^^j٪>3Q+V?;zCO k$(%KV7{ \h7oS~~/${NirfM7iQO.sNGudζxI ' 5jK, ѣ7oef_k;_Q~6f/qF賜w$IQ&3f޳vڪi+W&C?hb{Տ،3IQ&GWRRRDcyC/4f >h[xԗ_~yΏG $FE=/>Ȣ_~9? uݻ2R2z7iD#?њ5kv;>KW=H^5ܔK/zX/$Zڣܫ<1BG ul'WNû5k,~)7 Tuv TLN4/ZYY#v1ŰCyiyw JvWaC%iiRRRRO6 L6U?[DiѪfu/_riYΓ\>eؐWŶ2=8!;[9kdz,+ݛ଱ޭxHC&,vP}<0u`ڷFW{l6P ɟE?0?Q8.šzԿQ}>ǫu Y%K/M4]7_ |o[}٥? $31cFII#^n-Zv43 $uQ5(G7^u[BObꏳ~XԶe: x#X!ÀSyܑuPBThiQ{f 4(TuUJ"O<O>$4Z߾30Ԉ Y5j 'gy}/4NCO25HbMk_E;w~x9?P;$&5Y?dO?$$$&ks=Š+y"HIDATݏ?84H[Fݺu>ۃꑙ2)%%%dújhl\_jjӦMݔ/24*{%~UfBM=-[ ^)yŗf]/4%(}.]#t}^qC;dtnS[iC/Xlsy虨+{ܝj$F-~K(n޲ϧ N ^I;zf̚4nM\paN:jm@j>,YǣGo̾kwtg3l̰;^g9 B5IXLf̼gڵUV,L'1!=#=4N~ȯ:~cŊݱ3gTL:rmƐ;_h̎|)?>%-T/*.^HR2{_\yUUFˉQ;N]=?9D#?њ5krrsWcM"7^_H4ZnյG]WGIչ*:dდRw;[w_X KKUgH5#$˖;;g ?M{J^a2U^{UY֮}1{n)g=;=1K~$Oh}'gb9sW8vgQ}2nW2a]'*2n嬑a7rSoͿ:'Yx]2=?llnoNJHFr_˖-oځV}۷j3+lE^Is.,dL꺻QR8xٸCQ?e,=qg ͚7 UvPvTp73^Οyؽז=zlc* v>y.6uoUNouΞ8x+ + ή3m*Î0`𳇟}V-I'!>ѣ.rmcٰ.40ڤ&Wn3g>~E׽ҾVof&uخ3g%C.(wU>:0~eW#=ZnO"(jwyMr_ר}:Vgd쥗&Ӯ/?-Ѿҟkߙp1QW/_\e]54 <~iC5/riݺux?эWݸex|ө V55m%@&_?zxovH0Gwdcz .Z4t. g?޽wYMMNqAh_m#Ar&dϔMBVjF@}Z"3R+5CFMo` NQD(5 yߺukHY=mH/?j)}8=r?R_>ч; Z֜n㎻*yWAΝG8ԗ;W80$U MZ,@R'$@H ̹/_C}Q{7K-fn2:t6ol'W/ա1W{|= Omw CBʫ>{Fn "ћӯz@}XW^{믟|rI|ھSQ'c R>r߱em۶M 6me˖*%-_b555_8!3EW_4A " wFo7.~ \\-$Vj&n来eeq]0n.!=zoǧﱧ 6?lM ӮCrwmog /Duz޶CI.{m۶Q}GZ*{\C=t6l{I7yc8m1pR2{/=eiqתuœ[TGwC(׬?|6`tC@j<6˯j?w\29*{ rr+/*(GaYh={ :kP\7|ط/|@rĸg8~K,O+++׀^[&8bz~x?=zV|Lpe& tXWM7=>VVU r ;y-9nq?#T>'EUW3tKzfЈֿhJvпEIs38ҫM7;߱{U=;M۱>ghiގ]'յ/ k' * =W^swfn{*%m;)9>;OUN[܉]]`xQsԞ3|BvNS4|ʢKSյϝ2έpwӪuvrs*%W]v%cG_8xvt,(o} T1tKh֧LncÛ0.8>˝^SR֕e޸y;3~l *?6m-P7o=?ϨXlէz*4_Թ%JoډzC(+6/rK+&Łb'V.]ݺu{/U#%Wܣ#<2.VU ͕9$/++D´²郵sN߾/P޽[%I9;;>O=t C3\YY3GNrjgO/0oްkSΪ?oFfU3zixa4W 03;;*60pofRm۶scO}?hIzS~K]rCKq?_?azZZZ%INOL3!V,ZώO'-Lrk0xiK,m8=N3O{;$He E>ye>Io֭: -̙w~k۶mGTZ3E_)v#:w-C.]usK[nU<;:'nϿ,OcHoWܞwq^/y/`r@bf+*\oq}]upV[]iukp$ ߬6le_rYq_6N?Goݚ5aD_lVqq R2{/=&47j۶mQyB*uQQo|-Wu7*% .|s'. |SYaNZNt5e?_} +Uȍ3fpb%K6_yeqk@FzWKɛ.[NX31c׶( ,,oֆ_[]v͡?D~yD;,}UUaN8~ j}dffEfRfPylfcݲdjߌ Gݿ|E/_lE$J;o>P|ziitDA?)#du!w<6+<´qVLZ7;Gڐ1qjVфYY_;Y aQT?Oߜ}ww837o 2jm۶wNɵS&ѹs/M/jW5unEMEfbհ@3G憰h.͝ң(2wc>MZnK.]us}@B䜿e^2v􅳊gGǂFwOz\Y{JjM3aEQϺ*c━}B^V_Y6kN-6o T144[~+4A G8M6DK/M;ftt4ʪN zeuOהl;O>6# *.>ħ>&0)~;qM/}14SyamЙ rr 5pPY^|قek[^ܹ|GuT80?j_d͚:p;ýdd|,0@R}9G.me_?+ r5xngup1nj$@Idݏ͟|=/$==裎A'_ li555{u˦piסS\yc?Wz_W-'97o٬o~j۾cW^3r[HϞ~w[oZ\sŊz_ϟKڏ>YGsTfvfHU-l۶m괟.XP~if,[<P)9o{l91 _A}~/Ag JXh_tEw.3zӸqO\8梽l R3[w3,-+qg~=% a[l v:E#X[n;_}뭷>s\^x!{ŷrHw1ܛm۶;jղUQݣG%Oz;wذaCOڸmK/|,KcV[M.ܢbH?G:CQfM?i竵b?'U \~U;uQѳǠu׈}+. $W OqƌNd2.z 99i`R=3/-of=s]#Cxۿ'/o9hԷqෲj>?lnqktpYޞ'33X?.*-+k:(%=p}gqzW绛6obwlc!=;-u#of̼a]Ci嵳SMiez۟;&ֶ(Z¼a{-QeU+ׅxԌn(?1.m;̺ɂuse&J_RmA#GۦM@p&3::1?TOwN4ayx ?bw~ uﮕKWEnݞKUH>#U»g |װ ߨVyy! /P%oP>޽[%I9;;>O=t C3W,STw5%#3]sl^q9fM[;iԼz5gl7pVywZ 4T;T椹SgM>5c܄iOO(% wL }Z=^غeS8ȴ).^ۼqee(N]:Z1K.UVm`y[9%gq} ?@mw Ύ/m,/[T۶m+/S:Z$zԢG\?ީ݇vuе4lɸTί0=---В$gؕW7u=~p>h+yvM|:a7?[g}$UҒ!-Y:>O{` +-Xkhп5QT Lnzި|œ{mv}$I}D׽sJ2ΝCеK|ݜf; 8֭[gώ!T?"ĹmڴiJs*$aH}?H$%??O>dڵkC #3crꩧ 95vi555{u˦piסS\ycs /%}㡇_HOM{ͺk{mpHH{G%,Dot|IwH>WXѫW7~¯~ӑG~ɣ?n:7^㹧{//+_6Q桵IDAT͛Wɥ?nJSFXly R2[޴g?!vt)ߤEttyޙWzg{\rar@bj˗h]yUa\ԧxEqJ~ѝ}rۗ_vK`)*aÆ}~hסݔS>!Y:|C^mڵOw},$WJ&/˯rWɜ˻|KH]gųgoڴio=m67n $TJ& \~U{ZZZxg\̼ivn[7-/'-(,i:~쁽uW/\HTM"7Θq‰,YqgPF)/8mx/ofuS/;5c3,ܣw;[WM7=>VVU r ;y/а qktXhݟ1fdh̬F;7/ GCc…=^pQiYYCc@䜿3No8|ϝ9_hסSt}Ͻ-={>e"ٺ;_3{̂qǜډ=ֆ0o؞.ūz4kba汍Z=OWwܙþ;9Jm۶)v#:ww}2w̭:bKp\cA%C*zjtEEME-L^*rK.TRME͖qlvZn]t͹kv ]v%+yg?v{E}˚xкnAΪoŷ_бddf[{4xРlOk_ $ZJנm۶cnjw_0zLɜg~!V?:.='_*"}8qrUu+a\3fVAҪޭ[J9{ӷo/ T3,g^m;qjƼ e{%㊣a!g0axavŤQ^8gSK2έ_0gX6.nҊI3zmO׎KҰ;`5$} Ti555{u˦piסS\y{n޼ovZZ nwFb\Kϸ4*?Yݾ}}o7|m1pgƌ0*\r[^ZRaAa\3KfwDE]w|5$+xsC#vWZ&Gt|Ϳ%.99s{[92>nj-Z2kpU? 93>>Rʿ6kقeѱhޢg*ih04q$U“ȤS~4yJHk ˛~ g(ggeḑ?}s`ɟנY%s)nĹDǰCCT-(#H>$@IBg}lW^ºu׿A}'=caÆ'i555{u˦piסS\yc_gr۶m!z街}}VZ|BВ<_\y:g'lJ>WXѫWLs<᧜S321;-~jڪc|,jR|pYD }4/ٜ[sϭ0hp_붭5[_ʗBJ)QR4 u=^ #cq/k}$LJ|L#~]>%w\ɻ8ŷ޲eKo4keHLfްaC|˯~晨8C~JfVfHM8-B]}}YJ綾_`ؽS9wE7'>Do%wĻm67t+nI/2«iJϗ_y%vs~8HTKIɛ.4ӨoG!hSn ɕ_d ??~K,wxv`v#ϑ 4,2GL nGudOFE^K{O<}nE R2XYU5xi7=;/EƧ2BfFU.^|q.,:+ō'7Pe:O/-~T\\z7Wͽ[vO$QJk۶sJ2Ν~סڴY;.Y1=?(˝^SQQ;ou:"j5mߴYo_.˟_ѧajFd۵K|ݜfG-P)9/v٥}ѱy?q' ˥(T{m褊aݴY}Lةˢj'ՕijsݴE̪EM~.[M6xР#mӦM R8 uƎs-?[Q3υBkJFf.q- cӫbhRrf9#bUI?;/#-:s]}CrGLX^cW[1)ji}bؽ{!-A]NqMk|*;cm5ouOXKS;qay~q{n0Θ:d|zף(.cĬ EvI_C: Rխ[3¿;@ȠS,]Zc ^KC~ۯ=*N:??f+H?~L͒GTſoNHA'555*ʿ*yڐSuZD-7o>*^zsοCx7_> 6\ kNuMk F~4=3}=o{wMJ~ŢK]f6thh>$U J">yߺukHY=mH/?j)}8=r?R_>ч; Z֜n㎻*yWAΝG8ԗ;W80$U MZ,@R'$@H ZP#>OV][]6=23>!zڐSlVSS [l v:k76 /\r7z9wެڶ8w=_bHFtgqq]sŊzjJq'׿i89~gNџ>u(hgM[hdžw;[WM7-%}UUvny~:}7th5:Zfulfx UQQ3iUV7,33+F;77 MvΈN\감FŧFGT 4wu|VggݴV+f {ף6#E\VFF* ϮOsɻ׿ H)gzd\\C搼r=0K rr kܾgyaZm{hUqѽ[@Kso>q_Hό̋3& sͫ5qʑu^T)R8kznڸ[B(GXRY} _߾}-UZM͞ۺeS8ȴ).^ۼq=7o|TF~;--y7; ~-Kۚ۷wY }va "5>/\)׻/1Hd&~HTDyWCW<8s||>!kӿ-X-z♆ ?A@R%޽ty@˖VSS [l v:k76yO|u|c~[=ў臨;!!q_qU=#~MO|{oVEJ>WXѫW=^zYO>$>mߩou1Gefg^Y__Uزq˶mۦNqn6mx˲e sX//t֠~aE\t;7?ąc. ˖K+5{N~7Ҳ.Wpcthtݏi7xS`i{u˦piסS\t9ŋʻuշz3y =o[|!$pýٶmۨV-[=zd.[䡇s 6=Y_ۼ1Lڶ8)̲8kպ-*D;?kTӟvZ ^0! yR5`W\s?.N~QZ={ :kP\7|ط/|@rĸg8~K,O+++׀^[^VXԺiy93ׅں9MyPû/5?D~yD;,}UUaN8uK}Fp\#dfwCS!TzfFrwMVpQiYY/\(D)9;N/-;ݴ~cYhy3f s쪷(L>am|0YXKk_X{K޽[%I9;;>O=t C3,ST9k;6Ǹ}&_?/0}&>.-5ed݅Jss͝85cބy㲏;2<~#ӣ4G^XS2䞼qu} 2+f5oaCwB߾$fn2:t6ojiY9# SNVҽKha^Zҹ=ݲqKT;3N߽Ͼm>s?Q񥍅{K4j۶mW{ee}S@KCZ^_ZIʸ -IrAKzY~g* IbъMg|v|:a7ha_CN[di)uJ}zܻ!A*W.[,?>e~+]H&[n=o>Phaͽ[۶m>?Jj(wNɵS&ѹshvrs}~$X5غuѱ<$A G8M6Mo@R%9cw?:,OI $@g---[իWnݿpPj߾IO?c;iذ=IZMM/lݲ)dum믿ܶm[H)ze_{߹UVa+ж}8$$O>n)E~NI.[<Rr+V+4]%s.3᧜S321;-~jڪc|,jr}/f$XJ&˛-Y_׭۶ִo}+_ (3Ot|/()XoF};N۬і-$VJ|L曵ݎc)Cy-󑝣:z+$ ߬6lhz_7kTo~fVfHM8߻{qի{~of*%^~ckjj[~p怐NvY׿&޵m۶Q޸qS R2_+jJ?Sq}򂜜(,;]7-tG~Qqti/ؔ[} +Uȍ3fpb%KۢEzΡ0 »eଊS3NǗTҲO?cZiKSMIDAT6x"JHQ){|\+4*3sg(Z[1qMu;OX&NSTT\waܒq;=<4'=Oڹx=~3ss֮Isڶm{kL>s?ԴY;(*;Jz.ș>dz~UEOk_31L/Yk3BhպUh]\5;nJ9.d gώ[ 8f΋7,gNU+ׅu&^6n^]{ fL;23nqšiyo5A G8M6DK/M;fttͷjoEs<SIMJޱff䯩V?:.Oz1/%Wl#<2.VU 7ptnlSX=3/-'oں}0oXoeÿwGҪ޽[jjjxaM ӮCxmƦߵ~c>׏6횿e(eMrdo!g/ rK+& 9W̝8gJ#̘:d|zhmאNCTu֌om/2!KVF±Ґ_1nN<YJ*}FƏ%. lC7}#@߃N>9*jjj W-۟ UUW_O ҷɽw [bъ.}FuC]g :44}%|Qoݺ5wϞ6$@R>cgq9/`-k_eq]w+wD#F?+s&-  @@H $; -zٕ^xW^ .G?sÇב]hLZMM/lݲ)dum%ͭ|{6t/G:Mя.y/ỢmpHh6l_7_W7^|;gK>WXѫWpV\І=?_zO~Ǻ_jV{˽^OxR'?p-[H|Ŋp^}uiF|}OܞYI~7;#o=⼸_>_?Jo%W\Uv.[>ZW]k|H,%Yų7l˪Yl8~#Ǐ5k~ج@Bd/_0zlMMMhoնmۢ"3;ɗT_?꘣߾[BE<7n $TJ& \~UsO\+ 0-'<_Znڸ˯(_0\En1-Y鷼+ׯ^z5һzf^ZN޴uပ5)Vhkn޼94'/o9hԷqෲj>?l߯~awV[}O6̬. TS1)4Se0p2gc3;OV6|ͨta.\Jo(%Q?C zlu|!4:1جԮM nsWOg(Z2&N*0o"EӊzN4pY aQT?Oߜ}ww837o==D)g۶mSrGtKw86{%5sfҚ947E];1=K5Kѱ#')q\֭~ڥ?n]HK/YS?鴓ly?M>redĿ$=Og T1IiA?g^q׾H\A۶mǎM쿲k^YRMUeU\,}O}M haRx~8qM/}1| rr@ߌݺUjkΝ?kի*W}4㣡g(Z[[ O+ʘ:ͫm֔ 'o\q]x%ρ禍;˓V-wGw!jjjxaM ӮCxmư ?!*wƟgrH zܶmۘc^tTk~{a+ж}hY}F.kZ%.凷T0;3/^iqG?ߚ7লevo_UW\޽{iq}F r+Ag k|K8lO4ПpyR}$UKL"kSNyՍGn7!O}܀>Y^|قek[^ܹ|GuT80?j_d͚:p;ýdd|,0@R}9G.me_?+ r5xngup1nj$@IЂߟy'|z!葙 9ӆ`=^غeS8ȴ).^ۼ9^x˾C/$_ؽ{fݵֶ}8$$E7:>;j+VիWSz?WM#?sg[iR=痕/}e+_[_7)#,[<P)-oZu;۔SzoR^xpO|::<ܫG^ Q3f|=.kl RrW4g箼0 S8cwew>w|˯Xo%HLfްaþ?Q\n),>!z6ħ;iG_lM+%^~ckjjW^dN\_~]>%$Qٳ7mڴ۶mu7*% .⪽]---sGt<~Z73;''țiZ>fx.-{`oݾ} +Uȍ3fpb%K~iiee\ԧq 㭛0qnMEEQ2>=jL_sfwCm=sU7[;Vn-~+_߾ʪCN;7i?:4x܀-F:6sEkCzz홙Y!de7ֿ|¢Qp韋R8@BRwި|舊=6=jt WW)8wFRws9uK/jA v\Z|W5%#3<6+<q1wEGw{vG| Rr_۶mSrGt:C)1o褊!Oh,]sX5Ҡӳ& )PIDATM~1 o8~WwbfFjjvrs*%./U<;:OE9p`o6cI|a8f4[~koT?"Ĺmڴ $Z 'n1S2x}_x_'_Uuu6-T. Osɻ׿ H)gzd\\ ˛Y523[YB9e:Dz3ׅfZZ`n-Ujۛ}%Q7|ںr\NO50TQqikxfL[2>}ଊ)5V>dg4yTN[q`M1jȘ!۷oJㅭ[6LsGexnwC3ާ?Z|F5۷oMﳶ;@2WСØFEk^}_:RwK_*,(cF7`L"5?򑨈b.dy\yqyd׮߹@ Νoq%<_{ns+WƧ-:Y-EK> g?3'}?^z}ÇCJצ-[,:[L3 &b?Jx4yʏ&O IvMUW^qyo$UbWlEcw쬬,{Nb?,s9d!ō86thh>s%@r'$@H ̹/_C}Q{7K-fn2:t6ol'W/ա1W{|= Omw CBʫ>{Fn "ћӯz@}XW^{믟|rI|ھSQ'c R>r߱em۶M 6me˖*%-_b555_8!3EW_4A " wFo7.~ \\-$Vj&n来eeq]0n.!=zoǧﱧ 6?lM ӮCrwmog /Duz޶CI.{m۶Q}GZ*{\C=t6l{I7yc8m1pR2{/=eiqתuœ[TGwC(׬?|6`tC@j<6˯j?w\29*|MI˛Y7=zt֠no_~E…Jq7Θq‰,YVVVE ''<4Umw׭=s]c}'˛n$a!{|<v[3r܀!F<634Ge00ǗT>џ>/:|Ҳ_hQ Rrw7_ZzwiS&v;ҳvo[3țV7Ůzf^Zθ_' Ƨ3˷XKå²Ϟ9`G]՗,ڨ z3.^y|;~gνgN R2k۶sJ2Ν~TTs3GTL!k^8bԌ(7!L\SQfbpCK R'}|I8UEOh0k !c܊Yw=fhL֭voڥ?n]H\3v٥}ѱ T1tזc3BѸyYniE&1qM̨2&tϚxYh+yvM|:a7?[g}$UҒ!-Y:>O{` +-Xkhпq mݺQ?C937om۶>H*95{\;e;k.9ww@%p_[* CB 4 Ds۴iӔ$U?v'H$?H$A MyҲE/^z _ c9 3;;-A]Nqaom۶r衇^KkZj׻ mw CBKKN?r_e*V6ke듿%IJ}|X|Eh ƌynGܱ䎔!QL }pK+.fްaCoկfMu\gfec?[]wF_lVqq\+,~s=⥗_`ؚ&x-c8s@He'; Ί_|sڶmۨ Foܸ)>Ol YR);C$/XpW5?Sq}urfVwݨoK+_|Ŧ˯(_0~@Rwg.}|I .ZxEe;HK"yKK#|lݕu|VhTfΝM>anrLk9X0mܼb]G˚8OQQݍS疌O =︺pfnH[3ֶm{\;e;7u̬Ǘ̝QULϏL[3wbּ맭UQQS̝Z5.{NmhT=55ÄửЪud]t͹kv sb]zcIDAT* vٖulfQ'3}y=vL l|ųfU\{ֿjJqn6m_7vGoߊy.b0unEr+yOӦ^4vLK>#U»hSkCFug~cVEI'źuzsnEzUE V-Sp äSCQ[S3jƫD0oX]hqŵ pk_#_9' =^غeSHAY2*G7_w{Tt~O!ڶ8ɟ?n\\fo<$-uZDwN:䨨),(\]}TUYuUU4ӆz"V '˖-Q}a"xw~oG:u\nݺ'j)_`N3}aPS>wᠴoW,ZѥѨnhkaCE|Fu֐>;>{ڐ,?"kp/x쑳>>ײ5\vwuW˯zGt?b|qBBpZhFp @@H $?H$@I $@H $?H$@I $H @3@I $@H $?H$@I $@H $?H$@I $@H $?H$@IpH8(TON=o}tƐrgޱ=yZΛ4ÞtO{)uZ+ón†n}ߞwoT3~Hvк{VSi/T=3z|FYuxLrRp7a='n(͏{]~Jp 2ǯ̐]ܿ.x?zOg0+aefA_Ue;Tkթ{ܰ~٭wYtZuxceٴ>gO["{X8tuh(Iux;o?c[7VzOKԽO>gl/7Eufto]ԺSٷVyz׿g UuUzse7V>ʕյ-x{,suǙOvv=P=6=M(^ͺ NYQ#Ǐaӆel}+^yZB_-J/} yy~ 7Y{d>qѕ6G65 ^O6 qǵtŽ7]S^x̀Kn{d zۘGש{UMzXY׵WaPvvf|{=o.{}77PNmTY q^NeҚwXtqo83j6<0JڳG:[wZN;uφTyOͶQzzg_5?/v}m_,=ں wZ?O=vPӆL E\rW,|4Lh=9ۦmue?V+ago в#=77FN=l7WUW޲d}(ų1Qugw7f]<摺*㊥շzu)Ԧ+3N+V;nѡzx_J>)\fw#٣gL{䦲Eaq`{;*>dËlŷcnW:( 3WFt#e2zS]4e ٣\Y9{OYI}VWW?|φꢿu{ۅwW?|qvl@}~֌{V_uJ]u:cFzZn>r[ť"Ԭn.lx`€Z7?C/2ߨFi&\9k7V]r#U6h~s>NK]=_UU >CMBal,=-]½֝N)[45^#ualuvK 9k^}=_LfSx0{oG`=/{|g=$Gn}ԩU}Gk-,-6ivo8;5oRi KܾjN=){/]EގCSgg89`Hm պzd_!{ݺ~+VЧuZZڐ[ku=cjk&?l7{_i@1}k탯,rȐx;Sd{3j1 }3^s/to{Eqnc1M0ʯK6>{Fz͸`Hfm3xoGoФ7hijjjq/婿yqWV65tڍ) ,kҕWi8]473do!؎CfF;7N`2C:~፲љnK׿i{;wVSˏoXvqa\7>}WUMV jFZIybna0/9֏>{X/7^|-qWvhWz5op3j6 <+* %ͮ<=3>_|'zxNPc/慱aXP5q/wOg\F]}65X0)&NU[D3B먬QR pܯo߱:$1ŧc+ص0lGG9ӭ/-[vM;hixMwk퍏"- ck`Tb.`9Il^D1m}+f&.>җxMlZQUscc}9~isvi1QχX@xYo?mUֈe'R*++I%K-*yW^y7v0ii222gdQ#oB=4eN)=7o δ<{SNpy#­%ݵC@%5kL_/"׮]]x/9(X}lx׾ٿ&o.˭I̞cŽ^ :׏wi]}ǥKAc {tOۧ[h{+r3(zT_\F'_+(tpW~{gh$lI駟qyZeݺuooG{3&L8#lS;m}cO?ǟ3QyȄ Cu 9AH˺dBfk7g}-g„3f<~rv-6!KfmĨj6O>SN>G{eJKTTzqɋ˖|Ͻ-*jV^}jп̘>4細՞|j}l+`h/Sx{7箤~_Ftݺh~fLZ<[.*뮿ϛ8j@[nw/֬Ywy>p77lbއr׺ϾZG≒'wIM=Cszw=gڵΝֵt钞޾}|'V~w/~7ި[lgOd"KZ'1{}#P /xwNB|,|z~6mBxY7;Q cF"|Sn۵k7t14w}o9qT:GudHeWs}kz2JY-$FFp:fm 6qʟ_y?__ް[oiP(lksVaCOK/ѭ.QIMSoI~s;ہpguV|7F)+[Gm۞~کڵ _j%+W.)- ͩC=kݻ=МSgFhffLB(?=̞=g90Q~y.]{wZ --mB(yG{<*~ÿwF I ܜȣ.^܊^{뭷BkӡC}:C ZԜߋK̝[+Be]֬YYF%{SNi&]=1/Wjzk^jUZ|'JJ^\Ro$_6s}98׀Y-[+N?~WBk.]}?&7_]uVrD!+/m^*Ysk*M]mڴu{8@ᆵFTM%%]ۯgσiTu+Ukt}/~nwN'w?-X'쭧O>_lnV?y:;r˧~fyjYh?Df+3ڬ:%ukׅ&Ujo}_m.>}uMS7cR۵СC#>Q9z`i-f{Wouf͚O:9:{=223BkaŇ<ˋ W^9cCsN /& [TfۈQls1Nԭg~@ԫEjw}>4?74mu8O]vI ?apĞzޫ{]ӻS|KˣwBll>Y=xlЩ{'JQՠc`/mmy/;V6geeG wg^] VEO}N;9s&]6iݚXr?FŋΛk3 8D9uԟtCCݵ{' {.4/|A&zΨ1wv;f6zؤ1-ħ9}أ{Zh @&*~ܢDyç>2U~Oc=B|y\nժUz7F%ryϿ>VmI+r7' ˗裏rhXzk}BE3%ʿfjkn5ͲWZ֔}駿^le!xȁDW^_o ?NJٿui5kM1!gFhBlddz߾}N ´(s1}x~?sznpᢷzG-^܈*+cK=(SlV^^'߿az|x~Q\774B㺫3>B|! 0Q~v)lsREN-LkJ-Z(:/kefh>DTtEzu!ۥ]…ˬYWr?LKt7mqɓO% ;ޫ{h#g.n5YPAM#ӭSoСC' XqG%}Bޢw;i/a)7l5.+[0)[re{@/kOFdޑWW.X0:--m`yH/iզMÎ:,Q^5{.Y~̿?z멇b''4^f=^ẞOz^vYIjwux&N32zq99:q|o>[nv܄ ֙ڵ_k^₨ُL ߾FN-,=ʶ977*,uagfJ> }=]84p{[5>3sO]D^;r矌7mh $1 -+|̿_3ɼ!6_:> Gy^s*\f+,{B77eV`A͠(P>Us{N=32—j.4z o>IϏ׿zY&=^ɺbբEUxpmヌFm;ۏ=2N +X}s?+o^YЯ V.D([pזTNj JJ2z Ʀ9{Wɂ(ʧm ͧq_h{ۈ-om_Q5gÊ&>=6鏟3᨟(:V3O|HjUf\3\ȫ+ϩ>>z{^vxU|U1ˣjc?=sRb`e#9 u]N_n˟ulv]qۣsK'6Go{46n”Jb.X tWpՅW&J&gꅅWM T K.{o9tN{bIuhA8͘}bʚI>ܻe;D} OfϰtҤ[ng]zil^-<^+/(\?Fs[r/iTgZl"&UX-{{[zSse9mԸOâϤkhժիV>gtرS]gs K+/mZ~xM{ Ka+ƏqU>DO$;{F:fN:z8WfN.]zx#BYiYخ.Z(,|z~fVҚf{a)'ľ +iU!g4"%6#?pǫnoX.J;&g<3C>6XiԧFyIKTYYYy>L#ÌҾ}6k9w^tySrXq.,m#i?˯woW됩\U.c]w믻s?0ժvZVh7Kv{Yh5M [5ٷo_x!$"2ò3̈YUkzWKdQKE;uXIL &#{B!S}Hl˫zȰ /|?򵪡^j jG|fٛk>ZK]vຟ1N /.μ46S\pׇ~$=)K/{d؜'Uǀ jp}5.8Nio'|2 >=Mv݂(+8_t鿹G/:8>g CM ,>m bCIa*jyUT 24n], W1pϿb |SCcnݺ._{_.ݺxܳ W1;66њN_z[T_?+}0] >3,Y];gAf`qQVyu[5Qfz\Qzzz.\(*Ozſ84Tϸa7tu‘:<[Wqʟݨ+v?Եߵ%\Pk#> 0so 6t˭^},Q`J\zkb~rN=!*6鶣stcڲ9KOin#~}-Lk*ޭ+*++C2zOIrfiКmMwpguV|7覩$ ?.vE襝멡J/i2WTlqtQ|쉒?Lʏ>MfҚ|+'U r?1$?s|"<6{PifpưuTrw+^zQ&[]׏ VW{g9;$<+<߅R6X5 gF>Qnz#~zY|Tt{QhWi쀿r_ciM_USμ~w U֮Y{ϯAzoU閛o ֩7u!*ֻɺOBTeY04Pb¶1ڒ ?ͺߖ7 !YnwowN9͉z?6,{>UӧO"{wBՌ|)' (14'4Pn]).NNΫE?}B;k_/4PEEElF`G/)]w5nӔU!S'=lʡK[pq~yW^ 5Iw& }yhULnxj-)]מ{|uz;&CuySn1l+^qcީSpW{蘣F`GӊJ IDAT_|?#C+{\r_bzskޏ~xat5؎ݵ.USZzݺu!Dܽ;/?Ф~W^O>iii5/-y+xD'啿xy钉WqλU?1Zַ_myFF3?C;X O}!/ƏkAŋKJ;ݶmC;%KwjۧK(qcOhcB"&Nh&;Qɧ2uݿ@V~rD͠F7 IO?}#МZlYBߜ%&/yC32Ҥ";ӹg逯}-I[!'k'Z+߾mTT$6O|bV^Z~30@33';ʿ;u!J:v옖֩5kRB.Vb$6۶m{)'瞛k'Tl떽ۮ]C~p׮GIjhm֮])))^S..@3۳:*-- u׾QS_ڟ{.]k6r+oۿ{N;Ӈ>a,ꮽ+l5k>CQaݺu Y}3r6mzSS[M @r0';Z}msυ+ޔ 6CvoNmgdD5l9zQ;v /xfۖ1fDa}QCSo}weڵ82n-WZ'?/޺uj;n|{ضR*++^:W̕7Z];t $ }BȽD?Nz[pOreA8c:**TVVusM_Y#G% =(S2H ֩7u!*t/'wu戬YWr?LKt7ŰT:ܚnݺ<#uD.]Ž^{jsrM;gFhL$Cs6ov㶿~@'H&f;ۏ=2N lFi>b@A-zskڱ{}sz>4DH&? @'d d d d d d d d d d d d d d d dRYYVΘ?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?HmWV_mmE8v MJEfJwUPͥco4hȢakO=:3sRk7/[v--ʯm3='bӦyEș37f֨͘YgUǏ #id򷶤 ę,嬻cSZrK-VQYf3Y EQ4.6-'=gf37kk`;׭L$KM~5K&ƪW͚0<ѴI:6mkrk*3xPуVi1$PInf[Y=sFRY2:3c;1ync3N;STr NZ^Oߏj~NM{uM?̻>~v\^IN^uyGuլ!#gmr NVfe nylW9zT|Fm²9-S2s/{f,纀MYR^2MPFo̹#3b7!6-/,ܚ/}dޏ]0!v%%5=3{EM0d"*/;8q߱YGUE%eX0sdFjHHovI̜Xꆶ9l򒒼xּqt¢g~]v5'ôz⚱j3 hz^ N\P_u#*+Y3+89!opZ튪.* [#lO+\rY\4o]R2GnJJOOxb7]PsUPR3-*"pڈ0UF5vd҂.^4cҕW@k蘿8jͺze.N V=(Ѣ%[Pv8Y)))YeԦ9tn|TVuѼXD7WR&՘>ӇL>,Q^~yG& oԴ5L\WuE颭)<}=9!d}U7ɮvKO==/>+fsˊr3WKMK k-Ь'@u2sU ώ%7# g-*Hxf~>EGm-Kz?j}4CKsGɸlx[EëPUO:kg*+1 Vȍa-O(OD~ E[ʳB9qa> Kŋ3s2κ{]kyע92_i}hcn~AJGfq'KzrĴ;펲o`OcehuOhn9shvGTVVkO@@@@@@@@@@@@@@@` ֮:Qd d d d d d d d d d d d d d d d d d d d d d d d d&@Gxރa[ؖZ׾cM-ҷU?P??64ö-uΘS[[nE W/fX$Xtq8vKy]/yzf8>%SѴ/yz5a}񜐓q3V/_{~^T-̵Z(4Ahӫg$Ro}1uuȰsέ9}_ovOf1}iE zϟ7ޓogy,b̙?_aӫG\r":+ԑ^&*[[V5Ϳ[ծ[K(^Ј~27;jvThe Js[僣 ЈQaƴboy#­3Pt ' kM+਴9o f8uTV^+ڡSŘ? %>U_[C_ZOX,MX*-%c/9OfG}kbiͨv/?۟U4w^:j&bim+T=xkMĺꇘ$'nZ?=TU\>o|()?4[ϟP=,)=QUi* U.o~(4^Lgjo/>}Q BkmXxC7b~&[0wqխnO^&^{j' ; '16eǥNE8lF,S8:l[X1OЈ×zQNX?u6QR-u$;k-{+^{7F_xcO7!N8-7nЙиó9:4+^{tF8 CBMNXqdUտ<{_5BFyS yAm۶a?h4}֭[3 <0*$j>@iYL XC3{|&wƄ glR{`6mT?O8{56}g]|V+z!Qy׺tIOOO.~e/.YR[wư"͸=ͭӪ| /KjcmڴI;uaCw}Кubݣ5F@ʄ,b'W^yjӉC}hhg~;D7*'=}Bcm۶bv-$|+=xh3]*C S4>w8+ߎ ۧ ۾VWЩS^`u~Z$}@Iv8~=xs'|r->^&*3_u@ozGkk[!>axQN_'shuF5.z6*yIv駟.[lyhRݻgtڵ_~كm劆-'O͟G+apLe7yV-_ڝDN7*4;gv)4oq%M|ߺiʟCr@ Mw_н'\_Ŗ' 8}?~uՕ˥iUѺBí|Z+23_6v󟰭Dc~ߜ?u晡ᢇ]f5k;@#4qcҽe'tO?٧~엑HYik/Ңǿ~Xa޿<: *_JD]hk4w-N<;k_Z.]/e=wpgMţGy ywe 3}'8ʳ\tĨgq[JJJhwNtbm?~fA"sY'p 8+_[k_~`&*~ܢDyç>25YcOc֝_O|MW=nrCznV3~udzwva>vرO?o(:e/ ;J{՟y`{^ݙ[¶qwi_5o[kJoDv&ΚئM+i睢򫯖=ߟ=oo~}Y<;Wjڜ@rhMٽ#Q8c;`ޫ&52wnQeeeTgrNujE؁oѢE¡|)LJrak?_osg_Xä'l5?A}q_5W_[kJV\(Kgdu =Mae7}2vz+lWB6x+;ٴֈGȣ-:C—'F5wes2iyTyKώ%+e 9;#v)>Y~iw^oHl 홧NZۺ#ky\:&vn>'8~nM9iLT5KJ—uxD}8a„⸨˳.jm#% f]XsV`MAzWww¾a%Ć^xզCfv߻.HO):tT  ڒFog~6B2uOC~QdьG+6ν[oNTxٗ:H݆l%l:=egP4Qܹ- Qmޓ7L׹D?n[֊XS>{DE/sBxҚ7noX|3Xc;22j- cmeª/=sh(K|Bc]ԝ]|~YC|~MI._,zQ'mkj_ү&SWsc^ i> /D2"4P\sR~br;dXKͪnV '.+8Ҕġ!gwyUMze=0K3{ȩ)NUz>Q}XxuNvKg X0aC kbÿ]\y˳.RPUswڵ_k͕ #/%+sbهO>z`")Z:պkK$8ىQC>V%E>N~fGּ^2TVֽ Rϙ1ܢ37<*6{v0^è|wܷCuT.MgЬ  /6l8vu矧 Gט ?YU O6S|. ;W_СCh~7ٵC4Jk*ޭ+6Y&/bw%bo+]uqUY^`o-:᧍$W$٠/J:$֔}+_{ԛoL4^gBֻ5ILMK3I&چ&oՏ=319};Î<,$(yg>r#5Q_w84OQy{~_yÝGDߣ::V'zO%( >6{PvxM]1~\sCLlEByz w? W5/`:tᇱ56hO;vyz!旒re5硁{Da= FHs - &Hn_k(3}wIOo}ǴJ|bw{*_vB>7|3*={Ohxp/,]4l7}[dž{iwsoTq9~'$v0m)4R+[篶K.<2$~ m}yD 噅 ~;OwߪղQN8?9ΙN{FtJo\'s$ַ_myFF@_-‹Kٿ_kt ]k矿Dy}3bQaV2xpiBߥ/-K{dѺ?{Fƞ{YcHII _G>쳨Щc}t uKsdW_M{ǣgIlyPCy?w䀬3 $#e:f]wf~+?=--O<~ib['\h:-Z7G:V*}WGmj' @r6֭[w˴u6q95~9w6c5/jbOWH+F_ω}Bj}H^#߯m.lRm=8 oNrNN~=s+j]駟 yGL۶m<#|ZΝ>;4~4YϿoSQQAEEޖٸ};to}pUضv)b $$$$$$$$$$$$$$$$$r@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2@2hڢ))#*{DY~fJ\f~Y Em^qܑeYMd嗆мgoIv'j _yM2䈬x挕!1$$eEU(ٹœϬ<֖fg> JJ <}=YPT^%qZֆ@Eqn.݇UUUV.wݨ݇Ē' B#/6/m_^=C+ڥ-]κh@Vm.mW`xv'Vj _zZ͙s+7,v[x܌T 8QӠs|&vk>xuIyiߪz%w%s4\{gÙA+Z+*7Oi97w&Zg/*-=2+=ksn4fc֧X4=Ԛi'+,hdT㟴J ̹ey3Rci}FN/}'79`mqó3SkbE^ q{)ʿ1RT^9q⦍~c7>hkmi]z/*[g0)izce:AvNvL͏S,㭉e= j7-&JzχO/)^&yR`;hpW'F=x52qһ9K(ѤQy3 5(7xEQgIDAT{Q}\Yk`T'3'ðvgΜ>8mYɨ*ݥ5o;u5J% HEG Vس\_\ctϨk 'ޘ2q]7&'\쌡m3jςM쒙[{5jE3-_+cxQO:54++*x6z,]TYY(7jfЍK^iA{jWw>mZb5o=<6'>;f Ħz =GU3咻Ft[{ՙ[lR6dtF7h}gejɷN9-6ngeOO PTxu]ѳ;N[jU/VIxr[;ede}&g䆣RO~ Ϫ_{N~u7 6.tó~΃FL3r͒iu]q .!ذOxa7%+c+6*?V3ёU3%UfA}Ƀb^wlD7+|?#VxUO l?OeVO״:9pdb `byaa@`XtzNͤ9Uddv! 6{N\R6}di'.,{f,mY5+gt3 I,1 .#>8Jk.*';)QAjNn|=#rwǾ`Ʒ6xfaOgfĿKKB˕>hɔׯ]j_7c{K昦2*M^3_荙g}i cVݘaVmfJI~x)Ӈo"3wĈyy36=̼ gQ]TVGc.'l&%ٙuN hf(1~+''كsjmi}SSjeKt6[(R3Gyk)cԳs+3 {+)\[^\02;3=m}ǤU34Ң xl&v?v ]JJ{.5X0,-iK8Mc2xa{Y52%v-2ԴĀw(KʕW⥦<:ofqirysV |v̸]hƼ+W^W{kl*++fm+-->ki>(-3+1QT (=;'~3+g|%))YeE 1> 爻|2noO:hd(#7\A15-sp^QI`3sz]4/u>qïWN℡%[P,#+jiwg@rku3L*JmlYG'lfBiB5aS{D{57/c732PdVdAaYU#&Z:='3jxbjZzX#iL=37׊oc-*s݈eE{&-lgs#_o9SpE#֫i>Y3AEswKlRvxĵt|̑UT\k+MkԼUaeIFCd':Ob[.{z#>96ixvLt/[=Ȍ^cm6` J҆Ϝ{f,yv|ʫ3~?nOVYCfw+-.ꍵMm#= E3setxtzv֨y_w툱Oe5M{8Jr\%WQ]κKޏ Q4szNG УۆUQtOq=w^~ç,_>oU?ja`ϐ8yuC#:V_kC57?Fgjײ]Hh6 <";g,zӳvQ[?sg}Ӌ >t-?rF=/慱\=; 煱3Dg ;s5s/_-3bUeUwWge(-l?Zؐ zkY+ `7'ج+^_[jF4 V|)_=/ O(Zպʪ,-)}i_>7&|pnU_ىq/wO8.^;Qo9¦߷b4ĩ(}F>5X`i xo?'qz?wpǴήΛxXZvk'^3~T^|nϰ{]U=.q.:w~ZḛX@x;էLTVVֹWFV0L#IDAT/{̟qFSN[o[z֍拉ڵC$G\/?4ɰI䛻}?,/w`~ѻ!N8ڊjGaR~ܠƓt^:_8+3x?H>fdO{./L0$^נ3e]2!ksϾ3aBNTzi3N9in6w{3Qk>!};wΞff{wu}tIOo߾}hm>UW=bN5Hf#c;x>(*gͣ:2$+P]v=|w->s=<=Cs)dt:.Q?6a47zx#'ܩS"G;"$h1-b\1~/Ə ʷy%o{^{ϾkSO_jh ZSGkW/)~={O.Qn6_jժ{Eŋy~뉿='xMnb^P瀰-%UZD/lDr/¶/`J}qLjv:thЁzG}4*=p1Gl^`[noAvrtӄB|'B.' Cá{uڣkztW/i+ϿrԻ_yᕨͬǁ6T=Q%QYGjбQcbM-vLfd۩ CQ}cv 1lIc&)S>yv߽1M6Mo+/_(~~ϛ)]jS_$6ʖ__JGKҲew̜(s9:[a>;D/W@$[⋨qK6?~ԩEJo))UNmؖv.zJKʈFЅw,UK-[aa0;Sڥ.(}=EJojׂG/\{ehrxkkv~ɎwDssN"eK7,PEWDE_ҪeeW^Zl+Cۓme(<ۤ .4+W& RKZgdOCd~I}zۥݺ5b;v -L3&;5b>a+,uagRRU^~WņfW.݅şĶFW{xٝ_5oss]qoOIXe]˳._”~SҾf?RrZw~WV\n7w?e#T?w[U<}tHZ\YYYh}{iCT3sOúOZ~ f˴ݩm;>d}/lCg`ǔ}Ƨ9{XV5g]yGsξ׮[?e~!|R\xGȰj]xgě>$U[5/ֵE:xSݜ_nBz}cVOpտ{U[6~zKmgFƗ7j.`:g𸁙{Dvok]d6j х: }n۫?iȵU-3pV]h~gh٥sޓqʳqՕGzO@ ֌G+6ν[C+]g=|( [-61^ c6㈿+Əq.]zx#BYiYخ.Z(,|zA=lI>ߙDYt5^UcsRfFYZJ:ڵ_S|OoV3ίI=u}s\"z{uDaZVh7Kv{Yh5Ν@˓}F1XkRRbmsn.+.7直.=;myayA;h}.y9+({o{WC.<_GZ?х)$vL~ā;g߼ꃱUWaѱC6{[NI)RP]]=6GJNY-!^X+X]M^>Qᐯ}s{ޭ[WDԥ[o,6ggYj߱c$awlnf^rߪ37.lRVnz7uwa%XSLlԾZ_ls QI۴i@ղ9KOi>Q?ω{Fhv>i.vEg_Om)J/924RU/(Q{ ]b/HZ5}wq[ORZ:$ BujY}'4{.oBUTT$ iii8015}-f{hV&CuySn1l+^qcީSp~:ѧq{Ivwn66[|IhNᚗpxw=#4ͭ4{1wIvÆӥKH^g˯x8f3g-}QCէ~'Gf1,>b]{9ǘ?H>?=N;κuG-s?$}=-{ﹷ]v=d}ҥK]w ڵ_#%%kmBvfgQsޥKz_n|+_9CRS}v&vҮ:cǎ!Y|,\cnڴiCsϿo|fڰͥD))[n;־8k`{Hs @ڵC$c H H H H H H H H H H H H H H H H TVV3A"geemE=B$$2CYZ+ WyziY+CX9czk)IDAThz[:.x OZf>J+Ys3o\Wu򼬰52rK+Js363<{7X}{&Uu7f|zu7[[Z<3?wp 2S /*s@ZInz,W%#3Rk?rzi׶Zl83Du̜Ժc=yE̜q囻ڲ}dZfҒq))k+>8~!۳lܧYe[^bwqR^}z{֘vUՕV>;k̐#*5jE3-_Wsze /j4OYɏ%G}6zak,?d5?[9}ͱ]PEɸ]3=jcp,v{F^}GE7r}^FK}LQ#}UY3gn6j9XHr͒iu*W>dSgo>ͬaGc~kM5d&ʊ -(*2sE[Y53h{I^Lj]iYccyc0+pM<]9⮪\F-}dQշd%3j޽WQ4|V*$ˬDͣ$10;;݉qM\͋d׵;{pNU/3 uOkK ӻ{ьyKWZ_F1xtliFČU;l%.@2gRg >7jbfNB'N~TƭWZE/ VZZ/yZfVbcIq.*.; 7Y8vD ٛ.w݈eEiU`jZZX[MzF纪+Jmf _ӳRGm V%M*cxn| fJG^Y3O|ܬ݇XVv ɥ{e:F[VoxX[ʟ^vO'5%%%{zyh'&= ώn4q/k̳&Llg)T3tFV3Z43'Kpͦ{/+zd|Npxt}IN'Oguɞ&CUN㭢u[eY/%}fNYwU]Փ2_i}\:=;kԼ/x'pKU%t *%v>qJqF=)ٻ(;_AKDD&QPԀ- v4ٶ8u'Hb6"Ѥ_DAICD AAE@E@޹CEQUL\{{=n:55Y}tpᒃ[x͏'/ ~^v)6ܿjB˦h7}bw,m"գoKJ3i'\0ʅyM{~FlՋ{X5@i'8@H  ZfU\ -߮嵱/. r22ZVAAA2\d>ā@q 8@H $?ā@q 8@H $e&>_8kj $?ā@q 8@H $?ā@q 8@H $?ā@q 8@H  0M/K/9ԑZ;V#ݳvxy>H^%%/:2^Xە|L{</"PWjX6P? nǪvIyaOs{v uA_UNT_|Pym3WvhWu @FIt~P{(Q*IW$+]zh,4$c>nx9.SKҵPūsJ;%yKBNO_JAʰr/'ҥZ&Rү‹*{ǥٻ^<.LY:*cyZ8“-^[-.tI^ގ% K/8 >5{6-ody?۰nrnktvWϝta(z G_K^q^r~q҅aG\aO獟X8jȤ='6_8zʉJ;Vbκs?pƆC0qn|,mK?"s(9]>ĥJSv̾XtMmzSy_yޕo˸JΣfpިEaTޅj巤ҍ޺cR=WIK{MK,/7^Fy^a[4QYpT^!_Qs'arYw*TF abE\u%y'%b_#/_c&zy#=a+cMoWa˒WBz{zX>{H:xpA 2>{5k6nܴqr}jNU3g͘9k\TBsWӨđ{+dTk a;@]_bÉWM9krٌ ԵPt=Uڼz5_/q8GWn4`}U55uFfyORTs3sL!>W^?72rP}Q2skg58ft:6lؠA(jҤI}ݷs_}ՇߨQU͘ڒ%KS3N3TԒMFڥ[ʕ'uX˰_t n~+P1m۴Yٺ?$$'[5VG׹S,vmۮ^ 8~EUo>o*j޽i2Ap1o-X%7njfUOW|reV8>FVV_ sr@TٽNF=oP2fw=woܸqOg7 qúo4ie5oݛ5g3Ͼ:}yXGUVmZ>n}N;- B}ʟ׿mΜ9QlY~QGվ]۶9998no諕J5N}+񩁮^2o^ ɹ@*(((M̄I/wH J$5~0w cyNvS&mt=]^yϡNy?ꑇ[lꜾ'>L<;FQdO tʮ_'^3V<<"bk5:~n?-0Znz?2ظ3'VYuw=s*Y~G|DYoBE'y7onٲE$}Uq}N;uÆ 6m>R: xUoNuѷOԧ6{Fn]:+^,'+'ԦM63pМ9H>$?~:>uC}lѲXƒw믿~1cs$JwR?Tҵ]/z;6}W~oer-xooxs˜ ђ(Rvտcܟlte_cN5~|uUZ\|۳~_jU{%oeĮ^z{\AA%]QF7?yT2zwoz߈^~O>/(EQv5Ԃ(%z\4ඡ^:ZرG}5{ *n?z*yb/b}{u\F~ŵl2[z  л7[S(:}zӵe7<SooS33}"mv8nGS u{}8 $ԕC#8= Jɤ I{ /?o4Qqy%f}e/MħkNL}ӘbV?N0ak S@fZ⃿ϜF[޴m: S{>8[SgŒ[rr.jQuMEV^xłq:^5'*8qꫯ47WĕP {V|A2ܸ99Yƅ(jE݌W ~D U}νQnoѫ}VAY9qo]OVy|R\4 ՘[xj@'9i+ϸ8lo^  ]baNoՉWABc.O.*?6aU- v}[ Gg̎^۬[ՋdNeV^jt;m>KNj*T_{ޕ٤G?CRիׄ:Q> { Nh_g/qF薊x飯^SG'^ޣoh^Ee] Rh!fگc2(]]0eX ]-W`/Wwg7§}yuzo->9k {{{P>jy)'[owDkUY9'ogk3vŎ-{A&'|UNVrQt{zy5vՎ+z67[Ǧ6l-u%@AWg'TDY=ܾ}e˖9O+'rB؝D3݌[}iu=I׵ u~I+='nâvۀnX|}jۻ̣Vd6meuf9:uuZu.sy)~K.TcN^ª|왾j/򺡻&|M%Uvsʹ(i[Cjbڴ`𣳞MB%UXle*>%ah,99.+5:zZP{{-j.}7Ԥaۄs$OI׎$c>)*s߬Du`fwzt—hIF7 _?;kvNŅɻæ.Lfæ2y[|vo6vΰt1biWݿ;]3h^ -xh@2՛ ٳ_IE=_PϿf-vq{;yiler.z]m,v:U~ z\Fj9F7 ukU~ۅo-+cW5itЕǦ|/ne̕LJڷojK+{>bj:R kp:]nU'<}|~ N0WUw~dKFL"vE{E:uN-iwB睖'ҖzRX [;;^پ91鲷EO|mJڴn\*xٲRƲJj3rOkTsCMjF ;UPbWMIDAT{%?1NL0c)ZIފJ,s߰6E{)d$8 v]X4b?/7\WΞ+c!iߣ96nNua𣳓u!jnuvX=AŞUfz7;R{8T>,QtXQcɛK:1Ԑ(:3ywS-Ztq}\vg-|*jBPtWE'!yס^tj>TYUtPn2Pe z /xh^47$yz,Jŗ N\\[oq-#J,Y3f&f}jN*I>K=v'jj .;g[O{k,h{hG-xuy5eMљ*.*QWd봫/[xB'kªɩRꕕ낪EYB*O5$Ԙĕ Jk͸Z[PeN~Xa'ƲMǜ-[щWAMicCڇˈd9]D6oE ٸ"9 :gzl,wWwLimΜԹ$p^U4]s4A߯Ĺ=2dZhlbnzТraS^]ԫojy~wkpǴnᓳ^SU}uUߜĢn0v򴫲]s(9TS&wH79Rj/Ν4mСCY'Wī`ղiGLLZ}U Ju+RCGДsGnopUWmtcM%0?Q8T{gg=zAXTHJCzk5p|t}SSGO)^Ы̣^ GO ݗQ 7(|vh36+'AgZ(+sd({U-e{Yޖ'{/i޲y7}oAѥ -n\^VP~•id'_Sow^|*iW_}%)gUus1̇ەW^O;6lsubՌQBbSf9 u[ G Y%_蘭խ[׳:3ԉ/KKFwnz2TQOO*';oT/;蠃*0 u}5cӡT:-m֩Wv%G$sUR;(+{cLw[]US}E?~q/BƺޘF}}?u?!dzSM}YsŎ֮Y坩BVJTNj_UU >+wҚVT ׷O???zצI.!s̟5+|SoO+ԡC5pHbn(@rܐa ?~~=iӃCj'*ÖwġEGuY͞3'jG%=/3g|i'P_17g9os?7haSNΟ:wEO%9āSҽovm$Ԑ/ߌ^^p¢Q~gL^e>*2|w-#i8D/@iV^j4iR_~%6Ҋi"~XVްaC+ P5:v W}YYYG|SO׮M5m,T^?Q/}UQٺ7oֹgÝʛ> ѫjD 5V^j:PmE =xZ!C W?n}dP% O^xAMΐ(ϚQ(+$ÌTC w䑭R }[-Zj,}@/[2ԭ7翕j|rso-M49. x/~Y}7jH2fB3gvjPUzOS_ysѪUjHZڵ&>Q;n7Թ}GY۶n ҧ_"j{_~#[チr5n|oDi]ĥ%_4n8N6>}-B W8V~ѺCi7onٲ~fc^ز%fKvkb-G~?$$|y7lhذaV%7۶mۖ[:F}jgY˗ؾ}{VjҤI@}?̛='ʮTʑձñM>Zqġ6 K__ڐr/|d#B$ˊn+ׇ*y3f5/?}!.zOze$+}ꩽN ԕ^>cfYf%3GZ*b֭o-8Y+.0GV7?M}M~#Z ՁX˼Eg(:_w{/P ԡN:~vKJ3o;SۯG }U 6[ Yu>[ 7n}AluFUeo߮ĒP^\Z"Lrݬ9^`O>2'Ğy $?ā@q 8@H $?ā@q 8@H  @H $?ā@q 8@H $?ā@q 8@H $?ā@q 8@H $?ā@q 8@H $?U;IDATā@q 8@H $?ā@q 8@H $?m\IDATm,% cIENDB`././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7185988 pyparsing-3.3.2/examples/tiny/docs/transcript_1_tiny_parser.md0000644000000000000000000001233015134002420021552 0ustar00# TINY session transcript Local date/time: 2025-11-22 03:45 ## Overall plan - Adopt pyparsing best practices (naming, `Group` + named fields, punctuation suppression, `Forward` for recursion, `infix_notation`, enable packrat) and apply consistently. - Build out TINY grammar incrementally: expressions/terms, statements, control flow, functions, and program. - Make statement termination explicit: add trailing `SEMI` to simple statements; no semicolon after `if`/`repeat` constructs. - Localize concerns: include trailing `SEMI` inside each statement `Group` so sequencing stays simple. - Add tags (`pp.Tag`) to important nodes for easy downstream processing. - Keep tests green; adjust tests only when grammar behavior changes intentionally. - Provide a railroad diagram hook for `Program` and a README reference to the language spec. - Maintain a living transcript documenting prompts, plans, and actual actions taken. ## Transcript - User prompt: We are going to develop a pyparsing parser for the TINY language. Begin by reading the pyparsing best practices by running "python -m pyparsing.show_best_practices" Plan: - Run `python -m pyparsing.show_best_practices` to review the official pyparsing best practices. - Note key guidelines (naming, use of `Group`, suppression of punctuation, `Forward` for recursion, `infix_notation`, packrat, and testing patterns) and apply them throughout the TINY grammar development. Actions taken: - Applied best practices in `examples/tiny/tiny_parser.py`: enabled packrat, used `Suppress.using_each` for punctuation, used `Forward` for recursive elements, and built expressions with `infix_notation`. Results are grouped and named consistently. - User prompt: After defining "program" add "program.create_diagram('tiny_parser_diagram.html')" to create a railroad diagram. Plan: - Open `examples/tiny/tiny_parser.py` and locate the `Program` parser element definition. - Add a call to `Program.create_diagram('tiny_parser_diagram.html')` immediately after the definition so an HTML railroad diagram is generated when executed. Actions taken: - Added the diagram generation hook after defining `Program`. The diagram file (`tiny_parser_diagram.html`) exists at the project root. The call is currently left as an optional/commented line to avoid side effects on import, but can be enabled when needed. - User prompt: Redo stmt_list definition to just use OneOrMore(statement). Add trailing semicolons explicitly to all statements except for If_statement and Repeat_statement. Plan: - Replace `stmt_list = DelimitedList(statement, delim=SEMI, allow_trailing_delim=True)` with `stmt_list = OneOrMore(statement)`. - Add `SEMI` at the end of each simple statement (declaration, assignment, read, write, return, and function-call-as-statement) while leaving `If_Statement` and `Repeat_Statement` without trailing semicolons. - Update tests in `examples/tiny/tests` to reflect the new semicolon rules where necessary. Actions taken: - Implemented `stmt_list = OneOrMore(statement)`. Added explicit trailing `SEMI` to all simple statements; kept `If_Statement` and `Repeat_Statement` without semicolons. Updated `examples/tiny/tests/test_tiny.py` where needed and verified tests. - User prompt (update by user): SEMI is already defined using Suppress, it is not necessary to use SEMI.suppress(), just use SEMI. Plan: - Ensure all affected grammar pieces use `+ SEMI` directly and remove any `SEMI.suppress()` calls. Actions taken: - Audited the grammar and replaced any `SEMI.suppress()` usage with bare `SEMI`. Confirmed behavior with tests. - User prompt: Insert the trailing SEMI terms inside each statement's Group definition. Insert SEMI terms in Declaration and Assignment statements, so that Simple_statement does not need to include any SEMI terms Plan: - Move the trailing `SEMI` inside the `Group(...)` for each simple statement (`Declaration_Statement`, `Assignment_Statement`, `Read_Statement`, `Write_Statement`, `Return_Statement`, and `Function_Call_Statement`). - Simplify `Simple_Statement` so it no longer handles semicolon logic externally. - Run existing tiny tests to confirm behavior is unchanged except for internal structuring. Actions taken: - Moved `SEMI` inside each statement `Group` and removed semicolon handling from the outer composition. Kept control-flow statements without semicolons. All tiny tests continued to pass. - User prompt: Insert a Tag expression in the new Function_Call_Statement Plan: - Modify `Function_Call_Statement` in `examples/tiny/tiny_parser.py` to prepend `pp.Tag("type", "call_stmt")` inside its `Group(...)`, retaining the inner `function_call` structure. - Re-run tiny tests to ensure no regressions. Actions taken: - Added `pp.Tag("type", "call_stmt")` to `Function_Call_Statement`. Verified no regressions; tests passed. - User prompt: Add a reference to the TINY language definition at https://a7medayman6.github.io/Tiny-Compiler/Language-Description.html to the examples/tiny/README.md file Plan: - Edit `examples/tiny/README.md` to add a "Reference" section containing the given URL. Actions taken: - Appended a Reference section with the official TINY language definition link to `examples/tiny/README.md`. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7185988 pyparsing-3.3.2/examples/tiny/docs/transcript_2_tiny_interpreter.md0000644000000000000000000004627215134002420022636 0ustar00Instruction: ``` In tiny_parser.py, define number using ppc.number, not ppc.fnumber. This will convert numeric values to Python floats or ints at parse time, so no additional conversions are required in tiny_ast.py or tiny_engine.py. ``` Plan: - Update `examples/tiny/tiny_parser.py` to use `pp.common.number` instead of `pp.common.fnumber` for the `number` literal. - Verify that the parser still builds expressions correctly and that numeric tokens are converted to Python `int`/`float` at parse time. - No changes required to `tiny_ast.py` or `tiny_engine.py` since runtime conversion becomes unnecessary. Actions taken: - Replaced `ppc.fnumber` with `ppc.number` and kept the token name as `"Number"`. - Reviewed term and expression rules to ensure they continue to accept the `number` literal without further changes. - Left engine and AST modules untouched, as requested. --- #### Entry 19 — User Instruction Instruction: ``` Open a new file in tests/test_tiny_ast_nodes.py, with unit tests for the Declaration, Assignment, and Repeat statements. Use pytest form, not unittest. ``` Plan: - Create `tests/test_tiny_ast_nodes.py` with pytest-based tests covering: - Declaration statements with optional initializers (verify values via output). - Assignment statements updating an existing variable (including expression evaluation). - Repeat-until loop printing a message N times while decrementing a counter. ✓ - Each test will: - Parse a small Tiny program with `parse_tiny`. - Build the `MainDeclNode` via `TinyNode.from_statement_type` and execute with `TinyEngine`. - Capture stdout using `capsys` and assert expected text and return value. ✓ - Ensure tests rely on existing interpreter behavior without modifying engine/AST logic. ✓ Actions taken: - Added new file `tests/test_tiny_ast_nodes.py` with three tests: declarations with initializers, assignment update, and a repeat-until loop that prints a fixed number of lines. - Tests build and execute the main AST node and assert both stdout and the `return` value. #### Entry 18 — User Instruction Instruction: ``` Implement DeclStmtNode (which may also include an assignment portion). ``` Plan: - Review the grammar for `decl_stmt` to confirm fields: `datatype` and a list `decls`, where each decl group has `name` and optional `init` expression. ✓ - Implement `DeclStmtNode.execute(engine)` in `examples/tiny/tiny_ast.py`: - Determine `dtype = str(self.parsed.datatype)`. - Iterate `self.parsed.decls`; for each decl, evaluate `init` with `engine.eval_expr` if present, then call `engine.declare_var(name, dtype, init_val)`. ✓ - Keep return value `None` and avoid adding new scope (declarations occur in current frame). ✓ - Update this transcript entry with actions taken. ✓ Actions taken: - Implemented `DeclStmtNode.execute` in `examples/tiny/tiny_ast.py` to declare one or more variables with optional initializers, using the engine for expression evaluation and declaration into the current frame. - No changes to other nodes or engine were required. #### Entry 14 — User Instruction Instruction: ``` Add an is_implemented classmethod to TinyNode to detect if an execute() method has been defined (return False if cls.execute is TinyNode.execute). This will help us incrementally implement AST classes. ``` Plan: - Add a `@classmethod is_implemented() -> bool` to `TinyNode` in `examples/tiny/tiny_ast.py`. - Implement it to compare `cls.execute` against `TinyNode.execute` and return `True` only when overridden. - Leave all other code unchanged. - Append this entry to the running transcript. Actions taken: - Edited `examples/tiny/tiny_ast.py` to add `TinyNode.is_implemented` that returns `cls.execute is not TinyNode.execute`. - No other modules required changes. #### Entry 10 — User Instruction Instruction: ``` Add a do-nothing execute() method to the base TinyNode class, which takes a TinyEngine as an argument. Then implement execute() for MainDeclNode, WriteStmtNode and ReturnStmtNode. ``` Plan: - Add a no-op `execute(engine: TinyEngine) -> object | None` method to the `TinyNode` base class. - Implement `execute` for `MainDeclNode` to: - Push a new frame on the `TinyEngine`. - Iterate the statements in `main.body.stmts`, wrapping them into `TinyNode` subclasses via `from_statement_type` and calling `execute`. - Stop and return when a `ReturnStmtNode` is encountered (or when a child returns a non-None value). - Pop the frame and return the captured value. - Implement `execute` for `WriteStmtNode` to evaluate its `expr` via the engine and write the stringified result, or output a newline for `write endl;`. - Implement `execute` for `ReturnStmtNode` to evaluate and return its expression value. - Keep other node classes skeletal; no CLI changes required. Actions taken: - Updated `examples/tiny/tiny_ast.py`: - Added a default no-op `execute(self, engine)` method to `TinyNode`. - Implemented `execute` in `MainDeclNode` to push/pop a frame, iterate and execute statements, and stop on return. - Implemented `execute` in `WriteStmtNode` to write evaluated expressions or newline for `endl`. - Implemented `execute` in `ReturnStmtNode` to evaluate and return its expression value. - Left other nodes skeletal and made no changes to `tiny_run.py` or `tiny_engine.py`. --- #### Entry 20 — User Instruction Instruction: ``` Implement ReadStmtNode that will execute "read x" by using a Python input(f"x? ") statement. Add unit test for this class to test_tiny_ast_nodes.py ``` Plan: - Implement `ReadStmtNode.execute(engine)` in `examples/tiny/tiny_ast.py`: - Extract the identifier name from `self.parsed.var`. - Prompt and read input using Python `input(f"{name}? ")`. - Assign the entered string to the variable via `engine.assign_var(name, value)` so the engine applies type-aware coercion based on any prior declaration. ✓ - Add a pytest in `tests/test_tiny_ast_nodes.py`: - Program: `int x; read x; write x; newline; return 0;`. - Monkeypatch `builtins.input` to return `"17"`. - Execute main via `TinyEngine`, capture stdout, and assert output equals `"x? 17\n"` and return value is `0`. ✓ - Keep other files unchanged; do not implement broader function-call input handling. ✓ Actions taken: - Edited `examples/tiny/tiny_ast.py` to add `ReadStmtNode.execute` that prompts with `input(f"{var}? ")` and assigns the value using `engine.assign_var`. - Updated `tests/test_tiny_ast_nodes.py` to add `test_read_statement_prompts_and_assigns`, monkeypatching `builtins.input` to simulate user entry and asserting the combined prompt and output. - No changes required to the parser or engine; existing coercion logic converts the string `"17"` to an int for a previously-declared `int x`. #### Entry 11 — User Instruction Instruction: ``` Modify TinyEngine to also keep a dict of globals, for variables that can be accessed from any TinyFrame. Store any variables or functions defined at the program level in the dict of globals. ``` Plan: - Extend `TinyEngine` with a dedicated program-level globals store and a functions registry. - Keep locals in stack `TinyFrame`s as before; the current frame remains the last item in the stack. - Update lookup/assignment logic to search local frames first, then fall back to globals. - Add explicit APIs for manipulating globals (`declare_global_var`, `assign_global_var`, `get_var` to read from globals if not found locally) and for function registration (`register_function`, `get_function`). - Ensure `eval_expr` also consults globals when resolving identifiers. - No parser/CLI changes required in this step; future steps can populate globals/functions based on program-level constructs. Actions taken: - Updated `examples/tiny/tiny_engine.py`: - Added `_globals: TinyFrame` and `_functions: dict[str, object]`. - Frame stack `_frames` now holds only local frames; globals are separate and always present. - Implemented program-level registry methods `register_function` and `get_function`. - Implemented globals API: `declare_global_var`, `assign_global_var`; updated `get_var`, `_find_frame_for_var`, and `assign_var` to consult and write to globals when appropriate. - Adjusted `current_frame` to guard against use when no local frame exists. - Updated `eval_expr` identifier resolution to check locals first, then globals. - No changes to `tiny_ast.py` or `tiny_run.py` were required for this step. --- #### Entry 12 — User Instruction Instruction: ``` Change lines 71-77 in tiny_run.py to: - create a new TinyEngine - build nodes for the nodes in parsed - save all top-level functions (including main()) into the TinyEngine functions, and any top-level variables in to the TinyEngine globals - extract the AST node for the top-level "main" function, and call its execute() method passing in the TinyEngine object ``` Plan: - Modify `examples/tiny/tiny_run.py` to replace the placeholder post-parse logic. - Instantiate a `TinyEngine`. - Register all top-level function definitions from `parsed.program.functions` into the engine via `register_function`. - If present, load any top-level globals into the engine using `declare_global_var` (guarded, since the current grammar may not expose them). - Build the AST node for `program.main` using `_build_nodes`, register it as `"main"`, and execute it by calling `execute(engine)`. - Keep CLI return code and error handling intact. Actions taken: - Updated `examples/tiny/tiny_run.py` lines after parsing to: - Create `engine = TinyEngine()`. - Iterate `program.functions` to `register_function(name, fdef)`. - Best-effort import of any `program.globals` into engine globals when present. - Build `main_node = _build_nodes(program.main)`, register it as `"main"`, and execute it when it is a `TinyNode`. - Left parsing and `--dump` behavior unchanged. --- #### Entry 13 — User Instruction Instruction: ``` At the end of WriteStmtNode, add "engine.output_text()". Change TInyEngine's output_text() method to print("".join(self._out)), followed by self._out.clear() ``` Plan: - Update `WriteStmtNode.execute` in `examples/tiny/tiny_ast.py` to call `engine.output_text()` after writing output or newline, to flush the buffer. * - Modify `TinyEngine.output_text` in `examples/tiny/tiny_engine.py` to print the buffered output and clear the buffer (no return value). * - Verify that no other code depends on `output_text()` returning a string. ✓ - Update `examples/tiny/tiny_interpreter_transcript.md` with this entry documenting instruction, plan, and actions. * - Quick sanity check by running `hello.tiny` manually (not executed here). Actions taken: - Edited `examples/tiny/tiny_ast.py`: in `WriteStmtNode.execute`, added a call to `engine.output_text()` after `_write`/`_writeln` to flush output immediately. - Edited `examples/tiny/tiny_engine.py`: changed `output_text` to `print("".join(self._out), end="")` and then `self._out.clear()`; updated signature to return `None`. - Searched current usages; no part of the codebase relied on the previous return value of `output_text`. #### Entry 15 — User Instruction Instruction: ``` Refactor MainDeclNode.execute() to remove the conversion from ParseResults to AST nodes. Instead, this conversion should be done in a build_contained_statements() method that is called from __init__() after calling super().__init__. build_contained_statements() will iterate over the statements in the parsed body, and create a list of statement nodes. Then execute() merely has to iterate over those nodes and call execute on each one. If those nodes themselves contain a body of statements, then building that AST node will in turn recursively build AST node lists - this will be the case for the main, function, repeat, and if statements. ``` Plan: - In `examples/tiny/tiny_ast.py`, update `MainDeclNode` to pre-build its contained statements: - Add `__init__` that calls `super().__init__(parsed)` then `self.build_contained_statements()`. - Implement `build_contained_statements()` to iterate `self.parsed.body.stmts`, resolve each via `TinyNode.from_statement_type`, and instantiate nodes into `self.statements: list[TinyNode]`. - Refactor `MainDeclNode.execute()` to only iterate over `self.statements`, executing each node and stopping on `ReturnStmtNode` or non-None result; keep frame push/pop with `finally`. - Keep type annotations in Python 3.12+ style; avoid import cycles by using forward ref for `TinyEngine`. - Append this entry to the transcript. Actions taken: - Edited `examples/tiny/tiny_ast.py`: - Added `__init__` and `build_contained_statements()` to `MainDeclNode` to construct `self.statements` at initialization. - Simplified `MainDeclNode.execute()` to iterate over prebuilt `self.statements` and execute them, preserving early return behavior and frame management. - No changes were required in other files. --- #### Entry 16 — User Instruction Instruction: ``` Implement AssignStmtNode.execute() method and RepeatStmtNode.build_contained_statements() and .execute() methods ``` Plan: - In `examples/tiny/tiny_ast.py`, implement `AssignStmtNode.execute(engine)` to evaluate the RHS using `engine.eval_expr(self.parsed.value)` and assign it to `self.parsed.target` via `engine.assign_var(...)`. ✓ - Implement `RepeatStmtNode` to pre-build its body statements: - Add `__init__` that calls `super().__init__(parsed)` then `build_contained_statements()`. ✓ - Implement `build_contained_statements()` to iterate `self.parsed.body.stmts`, map each to a `TinyNode` subclass, and store in `self.statements: list[TinyNode]`. ✓ - Implement `RepeatStmtNode.execute(engine)` with do-while semantics: - Execute all body statements in order; if any returns a non-None result or is a `ReturnStmtNode`, propagate that result immediately (to allow function returns inside loops). ✓ - After each body execution, evaluate `self.parsed.cond` with `engine.eval_expr`; break the loop when the condition is truthy. ✓ - Do not push/pop frames in `RepeatStmtNode` (no new scope). ✓ - Update the running transcript with this entry. ✓ Actions taken: - Edited `examples/tiny/tiny_ast.py`: - Implemented `AssignStmtNode.execute` to evaluate and assign the RHS to the target variable via the engine. - Added `__init__`, `build_contained_statements`, and `execute` to `RepeatStmtNode` to pre-build its body and run it with repeat-until semantics, including early return propagation. - Updated `examples/tiny/tiny_interpreter_transcript.md` with this plan and the actions performed. --- #### Entry 17 — User Instruction Instruction: ``` TinyEngine._to_number() must be modified: - do not convert v to float if v is an int or float - if v is a string, get the value of the variable v; return that value if int or float, otherwise raise TypeError ``` Plan: - Update `_to_number` in `examples/tiny/tiny_engine.py` to conform to the specified behavior: - If `v` is `int` or `float`, return `v` unchanged. ✓ - If `v` is `str`, resolve it as a variable name using existing lookup (`get_var`). If the value is numeric, return it; otherwise raise `TypeError`. ✓ - For any other type, raise `TypeError`. ✓ - Ensure arithmetic and relational operations that use `_to_number` continue to work without further changes. ✓ - Append this entry to the transcript. ✓ Actions taken: - Edited `examples/tiny/tiny_engine.py`: - Rewrote `_to_number` to return `int | float` and to return numeric inputs unchanged, resolve strings as identifiers via `get_var`, and raise `TypeError` for non-numeric or unresolved identifiers. - Removed previous generic `float(str(v))` coercion path to avoid unintended conversions. --- #### Entry 22 — User Instruction Instruction: ``` Implement function calls in TinyEngine.eval_expr ``` Plan: - Inspect how functions are parsed and registered: function definitions are stored as `ParseResults` with `decl` (name, return_type, parameters) and `body.stmts`, and they are registered into the engine in `tiny_run.py`. ✓ - Add a reusable function invocation path in the engine so both expression `func_call` and a future `CallStmtNode.execute` can use it: * - In `eval_expr`, when encountering a `ParseResults` with `type == 'func_call'`, evaluate arguments left-to-right and delegate to a new `engine.call_function(name, args)` method. * - Implement `call_function(name, args)` to look up the function, push a new frame, bind parameters by declaring them with their declared types and the coerced argument values, execute the body statements one by one (building each as a `TinyNode` and calling `execute(engine)`), return on `ReturnStmtNode` or any non-`None` result, and finally pop the frame. If no explicit return occurs, return the default value for the declared return type. * - Provide a small helper `_build_stmt_node(stmt_group)` that maps a statement `ParseResults` group to its `TinyNode` subclass instance via `TinyNode.from_statement_type`. * - Keep existing identifier/number/string handling and operator semantics intact. ✓ - Do not implement `CallStmtNode.execute` yet; ensure the engine API is ready to be reused there. ✓ Actions taken: - Edited `examples/tiny/tiny_engine.py`: - Imported `TinyNode` and `ReturnStmtNode` from `tiny_ast`. - In `eval_expr`, added handling for `func_call` to evaluate argument expressions and call `self.call_function(name, arg_values)`. - Implemented `_build_stmt_node` helper for converting statement groups into `TinyNode` instances. - Added `call_function(name, args)` implementing function invocation: lookup, frame push, parameter binding with type coercion, sequential execution of body statements with early-return propagation, default return value when necessary, and frame pop in a `finally` block. - No changes to the parser or AST node classes were required in this step; `CallStmtNode` can later call `engine.call_function(...)` to share this logic. --- #### Entry 23 — User Instruction Instruction: ``` Implement CallStmtNode.execute ``` Plan: - Confirm parser shape for `call_stmt`: it wraps a nested `function_call` group carrying `type == 'func_call'`, `name`, and optional `args`. ✓ - Implement `CallStmtNode.execute(engine)` in `examples/tiny/tiny_ast.py` to: - Locate the nested `func_call` group. - Evaluate each argument via `engine.eval_expr`. - Invoke `engine.call_function(name, arg_values)` and ignore the return value (statement context). ✓ - Update this running transcript with instruction, plan, and actions. ✓ Actions taken: - Implemented `CallStmtNode.execute` in `examples/tiny/tiny_ast.py`: - Finds the inner `func_call` group, evaluates its `args` with `engine.eval_expr`, and calls `engine.call_function(name, arg_values)`. - Ignores any returned value and returns `None` as expected for a statement. - Left tests unchanged; future tests can exercise statement-style calls using existing function support in the engine. --- #### Entry 24 — User Instruction Instruction: ``` Remove is_implemented from TinyNode, was never used ``` Plan: - Remove the `is_implemented` classmethod from `examples/tiny/tiny_ast.py`'s `TinyNode` since it is unused. ✓ - Search codebase references to `is_implemented` to confirm no usages (recent context indicates none). ✓ - Update this transcript with the instruction, plan, and actions. ✓ Actions taken: - Edited `examples/tiny/tiny_ast.py` to delete the entire `TinyNode.is_implemented` classmethod. - Verified recent files and tests do not reference `is_implemented`; no further changes required. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7185988 pyparsing-3.3.2/examples/tiny/docs/transcript_3_tiny_repl.md0000644000000000000000000003051715134002420021231 0ustar00# TINY REPL Session Transcript Date/Time: 2025-11-28 07:58 (local) This document transcribes the current session pertaining to the TINY REPL work. It captures user prompts (issues/requests), plans, actions taken (including code edits and tools used), and resulting states. ## Session Overview - Repository root: `D:/dev/pyparsing/gh/pyparsing` - Key component: `examples/tiny/tiny_repl.py` ## Timeline ### 1) Prior Work Context Provided by User Prompt: ``` Implement a REPL for the TINY language, that will run interactive lines of TINY code. Initialize the REPL with an empty TinyEngine with an empty TinyFrame. Execute any entered TINY statements in the context of the engine's current TInyFrame. Add support for these REPL commands: - quit - exits the REPL - import - parses the input TINY file, loading all define functions, but ignoring any main() function present - reimport - same as import, but overwirtes any functions that were previously defined - clear vars - clear all locally defined variables in the REPL's engine - clear all - clear all variables and functions in the REPL's engine ``` Actions Taken (previously): - Added `examples/tiny/tiny_repl.py` implementing a basic TINY REPL. - Initialized with empty `TinyEngine` and a local `TinyFrame`. - Executed parsed TINY statements within the current frame. - Implemented commands: `quit`, `import`, `reimport`, `clear vars`, `clear all`. - Added parse error reporting and simple multi-line entry requiring a blank line to execute. Result Summary: - REPL runs, supports imports (functions only), can clear variables/all, and executes statement blocks. --- ### 2) Update Request: Improve REPL UX Prompt: ``` Update the REPL: - do not require a blank line after any of the quit, import, etc. REPL commands - always print a newline after executing any TINY statements - change the staement prompt to ">>> " - omit printing "bye" when exiting - add "list" command to list all defined functions (in both the current frame and any imported functions) and variables defined in the current TinyFrame; add "list vars" command to just list the current variables, and "list functions" to list all defined functions, either in the current frame or imported ``` Actions Taken (previously): - Modified `examples/tiny/tiny_repl.py`: - Primary prompt set to `>>> `; continuation prompt `... `. - REPL commands execute immediately on the entered line (no blank line needed). - Added commands: `list`, `list vars`, `list functions`. - Ensured a newline is printed after executing any TINY statements. - Removed any exit "bye" message. Result Summary: - Immediate command handling; listing variables and functions supported; consistent newline after execution; updated prompts. --- ### 3) Update Request: Incremental Parsing and Ctrl-C Handling Prompt: ``` Modify the REPL to process input TINY statements: - only prompt for additional lines until the current accumulated input parses successfully - intercept Control-C while prompting to clear the current command - intercept Control-C while executing to interrupt the current execution and return to a new statement prompt ``` Actions Taken (previously): - Rewrote input loop to attempt parsing after every line and execute as soon as `stmt_seq` parses successfully. - Added Ctrl-C handling: - During prompting: clear current buffer and show a fresh prompt (with a newline for cleanliness). - During execution: interrupt execution and return to the prompt. - Preserved immediate REPL commands on an empty buffer (`quit`, `import`, `reimport`, `clear vars`, `clear all`, `list`, `list vars`, `list functions`). - Ensured that after any execution (including interrupted), buffered output is flushed and a newline is printed. - Updated banner; no exit "bye" message. Files Modified: - `examples/tiny/tiny_repl.py` --- ### 4) Current Issue: Create Transcript Markdown Prompt: ``` Transcribe this entire conversation into a docs/tiny_repl_transcript.md file, capturing each prompt and resulting plan and actions taken. ``` Plan Established: 1. Compile a comprehensive transcript of the current session, including each prompt and the corresponding actions/solutions, tool operations, and relevant file paths. 2. Add a new file at `docs/tiny_repl_transcript.md` containing the transcript, with the current local timestamp and clear sections for prompts, plans, and actions. 3. Verify the file was created successfully and references are accurate; no code/test runs required. Actions Taken: - Created this file summarizing the session. Outcome: - Transcript added to the repository under `examples/tiny/docs/`. --- ### 5) Update Request: Execution Exceptions and Debug Mode Prompt: ``` While executing, handle all other non-runtime exceptions, suppress displaying the exception traceback, and just print the exception type and exception str(). Add "debug on" and "debug off" REPL commands to manage a modal debug state. In debug state, do not suppress exception tracebacks. ``` Actions Taken: - Implemented a modal debug mode in the TINY REPL with two new commands: - `debug on` — enables full Python tracebacks during execution - `debug off` — disables tracebacks (default), showing only `ExceptionType: message` - Updated the execution path to handle non-KeyboardInterrupt exceptions: - When debug is OFF: suppress traceback and print only the exception’s type and message - When debug is ON: print full traceback via `traceback.print_exc()` and keep the REPL running - Preserved existing behaviors: - Detailed parse error reports for syntax/parse exceptions - Ctrl-C handling while prompting (clears buffer) and executing (interrupts run) - Immediate command handling, prompts, and post-execution newline flushing - Updated documentation in `examples/tiny/README.md` to describe the new debug commands and error behavior. Key Implementation Notes: - Added a `debug: bool = False` flag in `repl()` scope to track mode. - Added command handlers for `debug on` and `debug off` at the empty prompt. - Wrapped the node execution loop with `try/except`: - `except KeyboardInterrupt:` preserves the existing interrupt behavior - `except Exception as exc:` - prints concise error when debug is OFF - prints full traceback when debug is ON - Always flushes buffered engine output and prints a newline in `finally`. - Minimal and localized edits in `examples/tiny/tiny_repl.py`; no changes to parser/AST/engine behavior. Files Changed: - `examples/tiny/tiny_repl.py` — added `traceback` import, debug flag/commands, and exception handling policy during execution. - `examples/tiny/README.md` — documented the new debug commands and clarified error/traceback behavior. --- ### 6) Current Issue: Update Transcript with Latest Prompts and Responses Prompt: ``` Update tiny_repl_transcript.md to include latest prompts and AI responses. ``` Actions Taken: - Updated this transcript with Section 5 capturing the debug-mode request and solution. - Refreshed the Date/Time at the top of this document. - Corrected metadata and snapshots below. Outcome: - Transcript now reflects the latest requests and responses in this session. --- ### 7) Current Issue: Import Exceptions Handling and Help Command Prompt: ``` Handle exceptions when importing a TINY file. Add a REPL "help" command to list all the REPL commands and 1-10 word descriptions. ``` Actions Taken: - Hardened import routine to handle exceptions during `import`/`reimport`: - `OSError` (file not found/permission): print `ExceptionType: message` to stderr; in debug mode, show full traceback. - Parse errors: keep existing detailed parse context and explanation. - Any other unexpected exceptions: concise `ExceptionType: message` unless debug mode is on. - Threaded the REPL’s debug flag into the importer so behavior matches execution mode. - Added `help` command at an empty prompt to list all REPL commands with short descriptions. Key Implementation Notes: - Updated `_load_functions_from_file(...)` to accept `debug: bool` and wrap file I/O and parsing in try/except. - REPL command handlers now pass `debug=debug` when calling the importer. - Implemented `help` output with concise one-line descriptions for each command. Files Changed: - `examples/tiny/tiny_repl.py` — improved import error handling; added `help` command; passed debug flag to importer. - `examples/tiny/README.md` — documented `help` command and clarified import error behavior with/without debug mode. Outcome: - Import errors are user-friendly by default and fully verbose in debug mode. Users can discover commands quickly via `help`. --- ### 8) Current Issue: Add Version and Echo in REPL Prompt: ``` Add a "__version__ = 0.1" to tiny_engine.py. Echo the version number in the opening banner of the repl, and in the "help" output. ``` Actions Taken: - Added module version in the engine module: `examples/tiny/tiny_engine.py` now defines `__version__ = 0.1`. - Surfaced version in REPL: `examples/tiny/tiny_repl.py` imports the version as `TINY_VERSION` and: - Prints `TINY REPL v{TINY_VERSION}` in the startup banner. - Prints `TINY REPL v{TINY_VERSION}` at the top of `help` output. How it looks: ``` TINY REPL v0.1 — enter statements; input runs when it parses. Ctrl-C to cancel current input; `quit` to exit. >>> ``` ``` >>> help TINY REPL v0.1 Commands: help - list commands and descriptions quit - exit the REPL import - load functions from a .tiny file reimport - load functions, overwriting existing clear vars - clear current local variables clear all - reset engine state (all vars, funcs) list - list variables and functions list vars - list only current variables list functions - list defined function names debug on - show full Python tracebacks debug off - concise errors; hide tracebacks ``` Files Changed: - Modified: `examples/tiny/tiny_engine.py` (added `__version__ = 0.1`). - Modified: `examples/tiny/tiny_repl.py` (banner/help now show version). Outcome: - REPL clearly communicates its version on startup and in `help`, tied to the engine's `__version__`. ## Tools and Operations During This Session - Code References Reviewed (read-only): - `examples/tiny/tiny_parser.py` - `examples/tiny/tiny_run.py` - `examples/tiny/tiny_engine.py` - `examples/tiny/tiny_ast.py` - `examples/tiny/tiny_repl.py` - `examples/tiny/samples/math_functions.tiny` - Patches Applied (edits): 1. Modified `examples/tiny/tiny_repl.py` to: - Update prompts and immediate command handling; add listing commands; ensure newline after execution. 2. Further revised `examples/tiny/tiny_repl.py` to: - Deprecate `_read_multiline`, enhance `_try_execute` to handle `KeyboardInterrupt`, and implement incremental parsing with immediate execution and improved Ctrl-C/EOF behavior. 3. Added debug mode and exception handling policy in `examples/tiny/tiny_repl.py`; added `debug on` / `debug off` commands; printed concise errors when debug is off and full tracebacks when on. 4. Updated `examples/tiny/README.md` to document REPL usage and the new debug commands and error behavior. 5. Improved import error handling and added `help` command in `examples/tiny/tiny_repl.py`; documented in README. 6. Added engine version `__version__ = 0.1` and echoed version in REPL banner and help. ## Current File State Snapshot (Key Paths) - `D:\dev\pyparsing\gh\pyparsing\examples\tiny\tiny_repl.py` — 341 lines; incremental REPL with Ctrl-C handling, listing, `help`, debug mode/exception policy, and versioned banner/help. - `D:\dev\pyparsing\gh\pyparsing\examples\tiny\tiny_parser.py` — grammar for TINY including `stmt_seq`. - `D:\dev\pyparsing\gh\pyparsing\examples\tiny\tiny_ast.py` — AST node implementations. - `D:\dev\pyparsing\gh\pyparsing\examples\tiny\tiny_engine.py` — execution engine and frames. - `D:\dev\pyparsing\gh\pyparsing\examples\tiny\samples\math_functions.tiny` — sample functions used for import testing. - `D:\dev\pyparsing\gh\pyparsing\examples\tiny\README.md` — includes REPL usage and debug mode documentation. ## Usage Reminder Run REPL: ``` python -m examples.tiny.tiny_repl ``` Example interaction: ``` >>> import examples/tiny/samples/math_functions.tiny >>> int x := 5; >>> write factorial(x); 120 ``` Commands: - `quit` - `import ` | `reimport ` - `clear vars` | `clear all` - `list` | `list vars` | `list functions` - `help` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7185988 pyparsing-3.3.2/examples/tiny/samples/calculate_areas.tiny0000644000000000000000000000547415134002420020744 0ustar00/* Compute the area of a selected shape in TINY. Interaction: - First, prompt for the shape type: enter one of "s", "c", "r", or "t" for square, circle, rectangle, or triangle, respectively. - Then, prompt only for the dimensions required for that shape. - All dimensions must be integers > 0 (non-positive values are rejected). - The program prints the area for the selected shape and exits. */ float area_square(float side) { return side * side; } float area_circle(float radius) { float pi := 3.141592653589793; return pi * radius * radius; } float area_rectangle(float width, float height) { return width * height; } float area_triangle(float base, float height) { return 0.5 * base * height; } int main() { string shape; /* Prompt for shape type */ write "Enter shape (s=square, c=circle, r=rectangle, t=triangle): "; read shape; /* Square */ if shape = "s" then int side; write "Enter side (integer > 0): "; read side; if side <= 0 then write "Error: side must be an integer > 0"; write endl; return 1; end write "Square area: "; write area_square(side); write endl; return 0; end /* Circle */ if shape = "c" then int radius; write "Enter radius (integer > 0): "; read radius; if radius <= 0 then write "Error: radius must be an integer > 0"; write endl; return 1; end write "Circle area: "; write area_circle(radius); write endl; return 0; end /* Rectangle */ if shape = "r" then int width; int height; write "Enter width (integer > 0): "; read width; if width <= 0 then write "Error: width must be an integer > 0"; write endl; return 1; end write "Enter height (integer > 0): "; read height; if height <= 0 then write "Error: height must be an integer > 0"; write endl; return 1; end write "Rectangle area: "; write area_rectangle(width, height); write endl; return 0; end /* Triangle */ if shape = "t" then int base; int height; write "Enter base (integer > 0): "; read base; if base <= 0 then write "Error: base must be an integer > 0"; write endl; return 1; end write "Enter height (integer > 0): "; read height; if height <= 0 then write "Error: height must be an integer > 0"; write endl; return 1; end write "Triangle area: "; write area_triangle(base, height); write endl; return 0; end /* Unknown shape */ write "Error: unknown shape; enter one of s, c, r, t"; write endl; return 1; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7202857 pyparsing-3.3.2/examples/tiny/samples/factorial.tiny0000644000000000000000000000075515134002420017575 0ustar00/* Sample program in Tiny language – computes factorial from https://a7medayman6.github.io/Tiny-Compiler/ */ int main() { int x; read x; /*input an integer*/ if x > 0 /*don’t compute if x <= 0 */ then int fact := 1; repeat fact := fact * x; x := x - 1; until x = 0 write fact; /*output factorial of x*/ elseif x = 0 then write 1; else write "Error: x must be >= 0"; end return 0; }././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7202857 pyparsing-3.3.2/examples/tiny/samples/fizzbuzz.tiny0000644000000000000000000000111615134002420017516 0ustar00/* FizzBuzz in Tiny Count from 1 to (limit), printing "Fizz" for multiples of 3, "Buzz" for multiples of 5, and "FizzBuzz" for multiples of 15. */ int is_divisible(int a, int b) { float quo := a / b; int iquo := quo; return quo = iquo; } int main() { limit := 100; i := 0; repeat i := i + 1; show_num := 1; if is_divisible(i, 3) then write "Fizz"; show_num := 0; end if is_divisible(i, 5) then write "Buzz"; show_num := 0; end if show_num then write i; end write endl; until i = limit return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7202857 pyparsing-3.3.2/examples/tiny/samples/hello.tiny0000644000000000000000000000007015134002420016722 0ustar00int main() { write "Hello World!\n"; return 0; }././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7202857 pyparsing-3.3.2/examples/tiny/samples/hello_5.tiny0000644000000000000000000000027115134002420017151 0ustar00int main() { int i := 5; string name := "World"; string msg := "Hello " + name +"!"; repeat write msg + "\n"; i := i - 1; until i = 0 return 0; }././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7202857 pyparsing-3.3.2/examples/tiny/samples/hello_user.tiny0000644000000000000000000000013715134002420017764 0ustar00int main() { string name; read name; write "Hello " + name + "!\n"; return 0; }././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7202857 pyparsing-3.3.2/examples/tiny/samples/hello_user_function.tiny0000644000000000000000000000023715134002420021672 0ustar00string say_hello(string name) { return "Hello " + name + "!\n"; } int main() { string name; read name; write say_hello(name); return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7202857 pyparsing-3.3.2/examples/tiny/samples/hello_user_function2.tiny0000644000000000000000000000022515134002420021751 0ustar00int say_hello(string name) { write "Hello " + name + "!\n"; } int main() { string name; read name; say_hello(name); return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7202857 pyparsing-3.3.2/examples/tiny/samples/if_then_elseif_else.tiny0000644000000000000000000000047015134002420021576 0ustar00int main(){ int x := 3; repeat if x = 1 then write "one"; elseif x = 2 then write "two"; elseif x = 3 then write "three"; else write "other"; end write endl; x := x-1; until x < 0 return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7202857 pyparsing-3.3.2/examples/tiny/samples/math_functions.tiny0000644000000000000000000001026415134002420020646 0ustar00/* Implement some basic math functions. */ /* basic arithmetic and algebra */ int factorial(int n) { int prod := 1; repeat prod := prod * n; n := n - 1; until n <= 1 return prod; } float pow(float x, int y) { if x = 0 then return 0; end if x = 1 || y = 0 then return 1; end /* handle negative powers */ negative_pow := sgn(y) < 0; y := abs(y); float result := 1; repeat result := result * x; y := y - 1; until y = 0 if negative_pow then result := 1 / result; end return result; } float abs(float a) { if a < 0 then return -a; end return a; } int sgn(float x) { if x > 0 then return 1; end if x < 0 then return -1; end return 0; } float round(float a, int n) { int mag := 1; if n > 0 then repeat mag := mag * 10; n := n - 1; until n = 0 end int trunc := a * mag + 0.5; return trunc / mag; } int div(int a, int b) { int quo := a / b; return quo; } int mod(int a, int b) { int quo := a / b; int ret := a - quo * b; if ret < 0 then ret := ret + b; end return ret; } float sqrt(float a) { float eps := 0.00000000001; float y := a / 2.0; repeat if abs(y * y - a) < eps then return y; end y := (y + a / y) / 2; until 0 } float hypot(float x, float y) { return sqrt(x * x + y * y); } /* Some trig functions */ float pi() { return 3.14159265358979323846; } float rad(float deg) { return deg * pi() / 180.0; } float deg(float rad) { return rad * 180.0 / pi(); } float sin(float rad_) { /* Taylor series expansion of sin(x) */ float x := rad_; int mult := 1; float sum := x; int n := 1; int exponent := 1; repeat n := n + 1; mult := -mult; exponent := exponent + 2; sum := sum + mult * (pow(x, exponent) / factorial(exponent)); until n >= 12 return sum; } float cos(float rad_) { /* Taylor series expansion of cos(x) */ float sum := 1; int n := 1; int exponent := 0; int mult := 1; repeat n := n + 1; mult := -mult; exponent := exponent + 2; sum := sum + mult * pow(rad_, exponent) / factorial(exponent); until n >= 12 return sum; } float tan(float rad_) { min_cos := 1e-18; float num := sin(rad_); float den := cos(rad_); /* Avoid division by zero */ if abs(den) < min_cos then den := sgn(den) * min_cos; end return num / den; } float exp(float x) { /* Taylor series expansion of eˣ */ float sum := 1.0; int n := 0; if x > 0 then repeat n := n + 1; sum := sum + pow(x, n) / factorial(n); until n >= 12 end return sum; } int main() { int i := 1; repeat write "sqrt("; write i; write ") = ="; write round(sqrt(i), 4); write endl; i := i + 1; until i > 10 int a:= 0; int b; repeat a := a + 1; b := a - 1; repeat b := b + 1; write "hypot("; write a; write ", "; write b; write ") = "; write round(hypot(a, b), 3); write endl; until b >= 10 until a = 10 write "rad(180) = "; write rad(180); write endl; write "deg(pi()) = "; write deg(pi()); write endl; write "sin(rad(30)) = "; write sin(rad(30)); write endl; write "sin(rad(90)) = "; write sin(rad(90)); write endl; write "cos(rad(60)) = "; write cos(rad(60)); write endl; write "cos(rad(90)) = "; write cos(rad(90)); write endl; write "cos(rad(180)) = "; write cos(rad(180)); write endl; write "tan(rad(45)) = "; write tan(rad(45)); write endl; write "tan(0) = "; write tan(0); write endl; write "tan(pi() / 2) = "; write tan(pi() / 2); write endl; write "pow(10, 0) = "; write pow(10, 0); write endl; write "pow(10, 1) = "; write pow(10, 1); write endl; write "pow(10, 2) = "; write pow(10, 2); write endl; write "exp(0) = "; write exp(0); write endl; write "exp(1) = "; write exp(1); write endl; i := -5; repeat write "mod("; write i; write ", 3) = "; write mod(i, 3); write endl; i := i + 1; until i > 5 return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7202857 pyparsing-3.3.2/examples/tiny/samples/prime_numbers.tiny0000644000000000000000000000114715134002420020474 0ustar00int is_factorable_by(int a, int b) { /* prime is not factorable by any number >= itself */ if b >= a then return 0; end float quo := a / b; int iquo := quo; return quo = iquo; } int is_prime(int n) { if is_factorable_by(n, 2) then return 0; end if is_factorable_by(n, 3) then return 0; end if is_factorable_by(n, 5) then return 0; end if is_factorable_by(n, 7) then return 0; end /* n is prime, assuming it is not > 120 */ return 1; } int main() { int i := 2; repeat if is_prime(i) then write i; write endl; end i := i + 1; until i > 120 }././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7202857 pyparsing-3.3.2/examples/tiny/tests/test_tiny.py0000644000000000000000000000304515134002420017011 0ustar00import pyparsing as pp import pytest from examples.tiny.tiny_parser import parse_tiny def test_parse_assign_read_write_in_main(): src = "int main(){ read x; y := 42; write y; return 0; }" res = parse_tiny(src) assert "program" in res main = res.program.main stmts = main.body.stmts assert len(stmts) == 4 assert stmts[0].type == "read_stmt" assert stmts[1].type == "assign_stmt" assert stmts[1].target == "y" assert stmts[2].type == "write_stmt" assert stmts[3].type == "return_stmt" def test_parse_if_then_elseif_else(): src = ( "int main(){ if x < 10 then y := y + 1; write y; elseif x = 0 then write 0; else read x; end return 0; }" ) res = parse_tiny(src) ifres = res.program.main.body.stmts[0] assert ifres.type == "if_stmt" assert hasattr(ifres, "cond") assert len(ifres.then) == 2 # optional elseif list assert "elseif" in ifres # else block exists with 1 statement assert len(ifres["else"]) == 1 def test_repeat_until_with_c_style_comment(): src = "int main(){ repeat /*loop*/ x := x - 1; write x; until x = 0 return 0; }" res = parse_tiny(src) rpt = res.program.main.body.stmts[0] assert rpt.type == "repeat_stmt" assert len(rpt.body) == 2 # condition contains a relop; infix_notation flattens to [lhs, op, rhs] assert rpt.cond[1] == "=" def test_parse_all_required(): # extra trailing garbage should fail when parse_all=True with pytest.raises(pp.ParseException): parse_tiny("int main(){ read x; return 0; } $$$") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/tiny/tests/test_tiny_ast_nodes.py0000644000000000000000000003132015134002420021045 0ustar00from __future__ import annotations import textwrap import pyparsing as pp import pytest from examples.tiny.tiny_parser import parse_tiny from examples.tiny.tiny_ast import TinyNode from examples.tiny.tiny_engine import TinyEngine def _run_main_and_capture(src: str, capsys: pytest.CaptureFixture[str]) -> tuple[int | None, str]: """Parse the Tiny program, build the main AST node, execute it, and capture stdout. Returns (return_value, stdout_text). """ try: parsed = parse_tiny(src) except pp.ParseException as pe: print(pe.explain()) raise main_group = parsed.program.main # Build a MainDeclNode via the registry node_cls = TinyNode.from_statement_type(main_group["type"]) # type: ignore[index] assert node_cls is not None, "MainDeclNode class must be registered" main_node = node_cls(main_group) engine = TinyEngine() ret = main_node.execute(engine) # type: ignore[assignment] captured = capsys.readouterr() return ret, captured.out def test_declaration_with_initializers_prints_values(capsys: pytest.CaptureFixture[str]) -> None: src = ( """\ int main(){ int i := 42; string s := "Hello"; write i; write " "; write s; write endl; return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) assert out == "42 Hello\n" assert ret == 0 def test_function_with_no_parameters_call_via_expr(capsys: pytest.CaptureFixture[str]) -> None: """Define a function that takes no parameters and returns a string. The main program calls it in an expression context: write greeting(); Verifies that functions with empty parameter lists are parsed, registered, called via eval_expr(func_call), and their return value is used. """ src = ( """\ string greeting(){ return "Hello!"; } int main(){ write greeting(); write endl; return 0; } """ ) parsed = parse_tiny(src) # Register top-level functions with the engine engine = TinyEngine() for fdef in parsed.program.functions: node_cls = TinyNode.from_statement_type(fdef.type) fn_node = node_cls.from_parsed(fdef) engine.register_function(fdef.decl.name, fn_node) # Build and execute main main_group = parsed.program.main node_cls = TinyNode.from_statement_type(main_group["type"]) # type: ignore[index] assert node_cls is not None main_node = node_cls(main_group) ret = main_node.execute(engine) captured = capsys.readouterr() assert captured.out == "Hello!\n" assert ret == 0 def test_function_with_one_parameters_call_via_expr(capsys: pytest.CaptureFixture[str]) -> None: """Define a function that takes one parameters and returns a string. The main program calls it in an expression context: write greeting(); Verifies that functions with empty parameter lists are parsed, registered, called via eval_expr(func_call), and their return value is used. """ src = ( """\ string greeting(string name){ return "Hello " + name + "!"; } int main(){ write greeting("Bob"); write endl; return 0; } """ ) parsed = parse_tiny(src) # Register top-level functions with the engine engine = TinyEngine() for fdef in parsed.program.functions: node_cls = TinyNode.from_statement_type(fdef.type) fn_node = node_cls.from_parsed(fdef) engine.register_function(fdef.decl.name, fn_node) # Build and execute main main_group = parsed.program.main node_cls = TinyNode.from_statement_type(main_group["type"]) # type: ignore[index] assert node_cls is not None main_node = node_cls(main_group) ret = main_node.execute(engine) captured = capsys.readouterr() assert captured.out == "Hello Bob!\n" assert ret == 0 def test_assignment_updates_value(capsys: pytest.CaptureFixture[str]) -> None: src = ( """\ int main(){ int x := 1; x := x + 2; write x; write endl; return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) assert out == "3\n" assert ret == 0 def test_repeat_until_prints_n_times(capsys: pytest.CaptureFixture[str]) -> None: src = ( """\ int main(){ int i := 5; repeat write "Hello World!"; write endl; i := i - 1; until i = 0 return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) lines = [ln for ln in out.splitlines() if ln.strip() != ""] assert len(lines) == 5 assert all(ln == "Hello World!" for ln in lines) assert ret == 0 def test_read_statement_prompts_and_assigns(capsys: pytest.CaptureFixture[str], monkeypatch: pytest.MonkeyPatch) -> None: # Program declares x as int, reads it from input, and writes it back src = ( """\ int main(){ int x; read x; write x; write endl; return 0; } """ ) # Simulate user entering 17 at the prompt monkeypatch.setattr("builtins.input", lambda prompt="": "17") parsed = parse_tiny(src) main_group = parsed.program.main node_cls = TinyNode.from_statement_type(main_group["type"]) # type: ignore[index] assert node_cls is not None main_node = node_cls(main_group) engine = TinyEngine() ret = main_node.execute(engine) captured = capsys.readouterr() # input() prints the prompt, then write prints the value and newline assert captured.out == "17\n" assert ret == 0 def test_if_then_true_branch(capsys: pytest.CaptureFixture[str]) -> None: src = ( """\ int main(){ int x := 5; if x > 0 then write "T"; write endl; end return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) assert out == "T\n" assert ret == 0 def test_if_then_else_false_goes_else(capsys: pytest.CaptureFixture[str]) -> None: src = ( """\ int main(){ int x := 0; if x > 0 then write "T"; else write "F"; end write endl; return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) assert out == "F\n" assert ret == 0 def test_if_then_elseif_chain_matches_middle(capsys: pytest.CaptureFixture[str]) -> None: src = ( """\ int main(){ int x := 2; if x = 1 then write "one"; elseif x = 2 then write "two"; elseif x = 3 then write "three"; else write "other"; end write endl; return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) assert out == "two\n" assert ret == 0 def test_if_then_elseif_else_falls_to_else(capsys: pytest.CaptureFixture[str]) -> None: src = ( """\ int main(){ int x := 99; if x = 1 then write "one"; elseif x = 2 then write "two"; elseif x = 3 then write "three"; else write "else"; end write endl; return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) assert out == "else\n" assert ret == 0 def test_return_inside_repeat_exits_function(capsys: pytest.CaptureFixture[str]) -> None: # Return from within a repeat loop body should exit the function immediately src = ( """\ int main(){ int i := 1; repeat write "before"; write endl; return 7; write "after"; write endl; until i = 0 write "unreached"; write endl; return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) # Expect only the text before the return and the function to return 7 assert out == "before\n" assert ret == 7 def test_return_inside_if_then_branch(capsys: pytest.CaptureFixture[str]) -> None: # Return inside the 'then' branch should exit the function src = ( """\ int main(){ int x := 1; if x = 1 then write "T"; write endl; return 1; write "after-then"; write endl; end write "unreached"; write endl; return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) assert out == "T\n" assert ret == 1 def test_return_inside_if_elseif_branch(capsys: pytest.CaptureFixture[str]) -> None: # Return inside an elseif branch should exit the function src = ( """\ int main(){ int x := 2; if x = 1 then write "one"; write endl; elseif x = 2 then write "two"; write endl; return 2; write "after-elseif"; write endl; else write "else"; write endl; end write "unreached"; write endl; return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) assert out == "two\n" assert ret == 2 def test_return_inside_if_else_branch(capsys: pytest.CaptureFixture[str]) -> None: # Return inside the else branch should exit the function src = ( """\ int main(){ int x := 99; if x = 1 then write "one"; write endl; elseif x = 2 then write "two"; write endl; else write "else"; write endl; return 3; write "after-else"; write endl; end write "unreached"; write endl; return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) assert out == "else\n" assert ret == 3 def test_all_operations_arith_string_boolean(capsys: pytest.CaptureFixture[str]) -> None: """Exercise arithmetic, string, relational, and boolean operators. Verifies: - Arithmetic: +, -, *, /, unary +/- - String concatenation with '+' - Relational: <, >, =, <>, >=, <= (numeric and string comparisons) - Boolean: &&, || with correct precedence relative to relational """ src = ( """\ int main(){ /* arithmetic */ write 1 + 2; write endl; /* 3 */ write 5 - 3; write endl; /* 2 */ write 2 * 4; write endl; /* 8 */ write 5 / 2; write endl; /* 2.5 */ write -5; write endl; /* -5 */ write +5; write endl; /* 5 */ /* string concatenation */ write "Hello " + "World"; write endl; /* Hello World */ /* relational numeric */ write 1 < 2; write endl; /* True */ write 3 > 4; write endl; /* False */ write 5 = 5; write endl; /* True */ write 5 <> 6; write endl; /* True */ write 3 >= 3; write endl; /* True */ write 2 <= 1; write endl; /* False */ /* relational string (lexicographic) */ write "a" < "b"; write endl; /* True */ write "b" > "a"; write endl; /* True */ write "x" = "x"; write endl; /* True */ write "a" <> "b"; write endl; /* True */ write "a" <= "a"; write endl; /* True */ write "aa" >= "ab"; write endl; /* False */ /* boolean ops (with relational sub-exprs) */ write 1 && 0; write endl; /* False */ write 1 || 0; write endl; /* True */ write 0 || 0; write endl; /* False */ write 1 < 2 && 2 < 3; write endl; /* True */ write 1 < 2 && 2 > 3 || 1; write endl; /* True (and before or) */ return 0; } """ ) ret, out = _run_main_and_capture(src, capsys) expected = ( textwrap.dedent( """\ 3 2 8 2.5 -5 5 Hello World True False True True True False True True True True True False False True False True True """ ) ) # Normalize potential trailing spaces/newlines assert out == expected assert ret == 0 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/tiny/tests/test_tiny_grammar.py0000644000000000000000000000364715134002420020527 0ustar00import textwrap import pyparsing as pp from examples.tiny.tiny_parser import parse_tiny ppt = pp.testing def _test_tiny_code(code: str): print() print(ppt.with_line_numbers(code)) try: result = parse_tiny(code) except pp.ParseException as pe: print(pe.explain()) raise else: print(result.dump()) # # code examples taken from https://a7medayman6.github.io/Tiny-Compiler/Language-Description.html # def test_tiny_grammar(): code = textwrap.dedent("""\ int sum(int a, int b) { return a + b; } int main() { int val, counter; read val; counter := 0; repeat val := val - 1; write "Iteration number ["; write counter; write "] the value of x = "; write val; write endl; counter := counter+1; until val = 1 write endl; string s := "number of Iterations = "; write s; counter := counter-1; write counter; /* complicated equation */ float z1 := 3*2*(2+1)/2-5.3; z1 := z1 + sum(a,y); if z1 > 5 || z1 < counter && z1 = 1 then write z1; elseif z1 < 5 then z1 := 5; else z1 := counter; end return 0; } """) _test_tiny_code(code) def test_tiny_grammar_factorial(): code = """\ /* Sample program in Tiny language – computes factorial*/ int main() { int x; read x; /*input an integer*/ if x > 0 /*don’t compute if x <= 0 */ then int fact := 1; repeat fact := fact * x; x := x - 1; until x = 0 write fact; /*output factorial of x*/ end return 0; } """ _test_tiny_code(code) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/tiny/tiny_ast.py0000644000000000000000000004164515134002420015467 0ustar00""" Executable Tiny AST types. This module defines the abstract base class `TinyNode` and statement-type-specific subclasses for the statement types produced by `examples.tiny.tiny_parser`. Each subclass sets a class-level `statement_type` that matches the value used by the parser's `pp.Tag("type", ...)` for that construct. This associates the parsed results for a statement to the corresponding `TinyNode` subclass. """ from __future__ import annotations from abc import ABC, abstractmethod from dataclasses import dataclass, field from typing import Optional, ClassVar, Any import pyparsing as pp class TinyNode(ABC): """Abstract base for all executable TINY AST node classes. Purpose - Each concrete subclass represents one statement form produced by `examples.tiny.tiny_parser`. - Subclasses must define a class-level `statement_type` whose value matches the parser's `pp.Tag("type", ...)` for that construct. Lifecycle and required methods - `from_parsed(parsed: pp.ParseResults) -> TinyNode` Factory that constructs an instance from a parser group. Implementations should normalize the raw `ParseResults` into explicit dataclass fields and eagerly prebuild any child statement nodes. After construction, runtime execution should not need to reach back into `self.parsed` except for debugging. This separation keeps execution independent of the parser's internal token structure and avoids pervasive `hasattr`/`in` checks. - `execute(engine: TinyEngine) -> object | None` Execute this node against the provided runtime engine. Implementations perform side effects via the engine (variable declaration/assignment, I/O writes, control flow) and return a value when appropriate: * Most statement nodes return `None`. * `ReturnStmtNode` signals control flow by raising `ReturnPropagate`; callers (such as function or main bodies) catch this to retrieve the value. Other nodes should rely on this mechanism and not special-case return handling. Notes - Keep `statement_type` as a class variable (see below) so it is not treated as a dataclass field in subclasses. - Subclasses may keep a reference to the original `parsed` group for diagnostics, but business logic should use their explicit fields. """ # Note: keep `statement_type` as a class variable. For dataclass subclasses, # this must not become an instance field. Use ClassVar to make intent explicit. statement_type: ClassVar[str] = "" def __init__(self, parsed: pp.ParseResults): self.parsed: pp.ParseResults = parsed def __repr__(self) -> str: cls = type(self).__name__ stype = getattr(self, "statement_type", None) return f"<{cls} statement_type={stype!r}>" @classmethod def from_statement_type(cls, type_name: str) -> type[TinyNode] | None: """Return the TinyNode subclass matching `type_name`. Iterates over direct subclasses. If deeper inheritance hierarchies are created, this needs to be expanded to recurse. """ for sub in cls.__subclasses__(): if sub.statement_type == type_name: return sub return None # All subclasses must provide a uniform factory for construction @classmethod @abstractmethod def from_parsed(cls, parsed: pp.ParseResults) -> TinyNode: """Construct an instance from a parser `ParseResults` group.""" raise NotImplementedError @staticmethod def body_statements(stmts: list[Any] | Any) -> list[TinyNode]: """Convert a sequence of parsed body statements to TinyNode instances. Used in statements with a contained body (e.g. function, repeat, if-then-else). """ built: list[TinyNode] = [] for stmt in stmts: node_cls = TinyNode.from_statement_type(stmt["type"]) # type: ignore[index] if node_cls is not None: built.append(node_cls.from_parsed(stmt)) # type: ignore[arg-type] return built # Execution interface (must be overridden by subclasses) def execute(self, engine: "TinyEngine") -> object | None: # noqa: F821 - forward ref """Execute this node against the given engine. Subclasses must implement this method. """ raise NotImplementedError(f"execute() not implemented for {type(self).__name__}") # --- Skeletal TinyNode subclasses for statements --- @dataclass(init=False) class MainDeclNode(TinyNode): """Dataclass node representing the `main` function body. - Prebuilds and stores the list of child statement nodes under `statements` at construction time. - Execution pushes a new frame, executes each statement in order, and returns the value propagated by a `return` (via `ReturnPropagate`), or `None` if no return occurs. - Construct using `from_parsed(parsed)` or the legacy `__init__(parsed)`. """ statement_type: ClassVar[str] = "main_decl" # Prebuilt main-body statements return_type: str = "int" parameters: list[tuple[str, str]] = field(default_factory=list) statements: list[TinyNode] = field(default_factory=list) def __init__(self, parsed: pp.ParseResults): super().__init__(parsed) # Pre-build contained statement nodes for the main body self.statements = [] self.parameters = [] self.build_contained_statements() @classmethod def from_parsed(cls, parsed: pp.ParseResults) -> MainDeclNode: # Maintain compatibility with engine/builders expecting factory constructors return cls(parsed) def build_contained_statements(self) -> None: """Convert parsed body statements to TinyNode instances. This runs once at construction so that execute() only iterates nodes. """ body = self.parsed.body stmts = body.stmts if hasattr(body, "stmts") else [] self.statements = self.body_statements(stmts) def execute(self, engine: "TinyEngine") -> int: # noqa: F821 - forward ref # Main body: push a new frame for main's locals engine.push_frame() try: for node in self.statements: # Return statements propagate via exception node.execute(engine) return 0 except ReturnPropagate as rp: return rp.value finally: engine.pop_frame() @dataclass class FunctionDeclStmtNode(TinyNode): """Node representing a function declaration/definition. This node accepts parser groups tagged with type 'func_decl'. It will initialize its `statements` from an associated function body group if available. The body is expected under either `parsed.Function_Body.stmts` or `parsed.body.stmts`, depending on how the upstream parser groups were provided by the caller. """ statement_type: ClassVar[str] = "func_decl" # Prebuilt function body statements (if a body was provided) name: str return_type: str = "" parameters: list[tuple[str, str]] = field(default_factory=list) statements: list[TinyNode] = field(default_factory=list) @classmethod def from_parsed(cls, parsed: pp.ParseResults) -> FunctionDeclStmtNode: fn_name = parsed.decl.name return_type = parsed.decl.return_type if parsed.decl.parameters: params = [(p.type, p.name) for p in parsed.decl.parameters[0]] else: params = [] # Locate a function body group in common shapes body_group: pp.ParseResults = parsed.body statement_nodes: list[TinyNode] = [] if body_group: raw_stmts = body_group.stmts or [] statement_nodes.extend(cls.body_statements(raw_stmts)) return cls(name=fn_name, return_type=return_type, parameters=params, statements=statement_nodes) def execute(self, engine: "TinyEngine") -> object | None: # noqa: F821 - forward ref # Execute the function body in a new local frame. If body is absent, # this is effectively a no-op that returns None. # Caller should have already created a frame and populated parameters as vars try: for node in self.statements: node.execute(engine) return None except ReturnPropagate as rp: return rp.value @dataclass class DeclStmtNode(TinyNode): """Declaration statement node. Represents one declaration statement possibly declaring multiple identifiers with optional initializers, for example: int x := 1, y, z := 2; Fields: - dtype: declared datatype ("int", "float", or "string"). - decls: list of (name, init_expr | None). """ statement_type: ClassVar[str] = "decl_stmt" dtype: str = "int" # list of (name, init_expr | None) decls: list[tuple[str, Optional[object]]] = field(default_factory=list) @classmethod def from_parsed(cls, parsed: pp.ParseResults) -> DeclStmtNode: dtype = parsed.datatype or "int" items: list[tuple[str, Optional[object]]] = [] for d in (parsed.decls or []): name = d.get("name") init_expr = d.init if "init" in d else None # type: ignore[attr-defined] items.append((name, init_expr)) return cls(dtype=dtype, decls=items) def execute(self, engine: "TinyEngine") -> object | None: # noqa: F821 - forward ref for name, init_expr in self.decls: init_val = engine.eval_expr(init_expr) if init_expr is not None else None engine.declare_var(name, self.dtype, init_val) return None @dataclass class AssignStmtNode(TinyNode): """Assignment statement node. Holds a target variable name and an expression to evaluate and assign. Example: `x := x + 1;`. """ statement_type: ClassVar[str] = "assign_stmt" target: str = "" expr: object = None @classmethod def from_parsed(cls, parsed: pp.ParseResults) -> AssignStmtNode: return cls(target=parsed.target, expr=parsed.value) def execute(self, engine: "TinyEngine") -> object | None: # noqa: F821 - forward ref value = engine.eval_expr(self.expr) engine.assign_var(self.target, value) return None @dataclass class IfStmtNode(TinyNode): """If/ElseIf/Else control-flow node. Captures the main condition, then-branch statements, zero or more `elseif` branches as (condition, statements) pairs, and an optional `else` statements list. Execution evaluates conditions in order and executes the first matching branch. """ statement_type: ClassVar[str] = "if_stmt" # Explicit fields for all conditions and corresponding branches branches: list[tuple[object, list[TinyNode]]] = field(default_factory=list) @classmethod def from_parsed(cls, parsed: pp.ParseResults) -> IfStmtNode: branches: list[tuple[object, list[TinyNode]]] = [] # Initial if-then condition (defined by the parser for if-statements) branches.append( (parsed.cond, cls.body_statements(parsed.then)) ) # Add ELSEIF branches for br in parsed.elseif: branches.append((br.cond, cls.body_statements(br.then))) # Add ELSE branch if "else" in parsed: # if there is an else and we get this far, the condition is always true branches.append((1, cls.body_statements(parsed["else"]))) return cls(branches=branches) def execute(self, engine: "TinyEngine") -> object | None: # noqa: F821 - forward ref # Evaluate branches in order for cond, nodes in self.branches: if bool(engine.eval_expr(cond)): for node in nodes: node.execute(engine) break return None @dataclass class RepeatStmtNode(TinyNode): """Repeat-Until loop node (do-while semantics). Executes the body statements at least once, then evaluates the `cond` expression after each iteration, terminating when it evaluates to true. """ statement_type: ClassVar[str] = "repeat_stmt" # Body statements for the repeat block statements: list[TinyNode] = field(default_factory=list) # Until condition expression evaluated after each iteration cond: object | None = None @classmethod def from_parsed(cls, parsed: pp.ParseResults) -> RepeatStmtNode: # Build child statement nodes from the parsed body sequence statement_nodes: list[TinyNode] = [] if parsed.body: stmts = parsed.body statement_nodes.extend(cls.body_statements(stmts)) cond_expr = parsed.cond return cls(statements=statement_nodes, cond=cond_expr) def execute(self, engine: "TinyEngine") -> object | None: # noqa: F821 - forward ref # Repeat-Until is a do-while: execute body, then check condition; stop when condition is true while True: for node in self.statements: # Return statements now propagate via exception; no need to inspect results node.execute(engine) # Evaluate loop condition after executing the body cond_val = engine.eval_expr(self.cond) if self.cond is not None else False if bool(cond_val): break return None @dataclass class ReadStmtNode(TinyNode): """Read (input) statement node. Prompts for a token and assigns it (as a string) to the given variable name in the current frame. """ statement_type: ClassVar[str] = "read_stmt" var_name: str = "" @classmethod def from_parsed(cls, parsed: pp.ParseResults) -> ReadStmtNode: return cls(var_name=getattr(parsed, "var", "")) def execute(self, engine: "TinyEngine") -> object | None: # noqa: F821 - forward ref user_in = input(f"{self.var_name}? ") engine.assign_var(self.var_name, user_in) return None @dataclass class WriteStmtNode(TinyNode): """Write (output) statement node. Writes the evaluated expression value, or a newline if `is_endl` is true or `expr` is None. Output is buffered in the engine and flushed per call. """ statement_type: ClassVar[str] = "write_stmt" expr: Optional[object] = None is_endl: bool = False @classmethod def from_parsed(cls, parsed: pp.ParseResults) -> WriteStmtNode: if "expr" in parsed: return cls(expr=parsed.expr, is_endl=False) # expect literal endl otherwise return cls(expr=None, is_endl=True) def execute(self, engine: "TinyEngine") -> object | None: # noqa: F821 - forward ref if self.is_endl or self.expr is None: engine._writeln() else: val = engine.eval_expr(self.expr) engine._write(str(val)) engine.output_text() return None class ReturnPropagate(Exception): """Using exception mechanism to propagate return value from within nested statements within a function. """ def __init__(self, value): self.value = value @dataclass class ReturnStmtNode(TinyNode): """Return statement node. Evaluates the optional expression and raises `ReturnPropagate` to unwind to the nearest function/main boundary with the computed value (or None). """ statement_type: ClassVar[str] = "return_stmt" expr: Optional[object] = None @classmethod def from_parsed(cls, parsed: pp.ParseResults) -> ReturnStmtNode: return cls(expr=parsed.expr if "expr" in parsed else None) def execute(self, engine: "TinyEngine") -> object | None: # noqa: F821 - forward ref value = engine.eval_expr(self.expr) if self.expr is not None else None raise ReturnPropagate(value) @dataclass class CallStmtNode(TinyNode): """Statement form of a function call. Holds the function name and argument expressions; on execution the arguments are evaluated and `TinyEngine.call_function` is invoked. The return value (if any) is ignored in statement context. """ statement_type: ClassVar[str] = "call_stmt" name: str = "" args: list[object] = field(default_factory=list) @classmethod def from_parsed(cls, parsed: pp.ParseResults) -> CallStmtNode: func_group: pp.ParseResults | None = None for item in parsed: if "type" in item and item["type"] == "func_call": # type: ignore[index] func_group = item break if func_group is None: return cls(name="", args=[]) name = func_group.name raw_args = func_group.args or [] return cls(name=name, args=list(raw_args)) def execute(self, engine: "TinyEngine") -> object | None: # noqa: F821 - forward ref arg_values = [engine.eval_expr(arg) for arg in self.args] _ = engine.call_function(self.name, arg_values) return None __all__ = [ "TinyNode", "MainDeclNode", "FunctionDeclStmtNode", "DeclStmtNode", "AssignStmtNode", "IfStmtNode", "RepeatStmtNode", "ReadStmtNode", "WriteStmtNode", "ReturnStmtNode", "CallStmtNode", ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/tiny/tiny_engine.py0000644000000000000000000003542615134002420016145 0ustar00""" TinyEngine: runtime support for executing TINY AST nodes. This module exposes the `TinyEngine` class, which maintains a program-level variable environment and provides helpers used by executing TINY AST nodes. It also defines `TinyFrame`, which represents a single stack frame for local variables. `TinyEngine` maintains a stack (list) of frames, with the current frame being the last element. """ from __future__ import annotations import pyparsing as pp from .tiny_ast import TinyNode # Module version for TINY runtime/engine __version__ = "0.1" import operator _op_map = { "+": operator.add, "-": operator.sub, "*": operator.mul, "/": operator.truediv, "=": operator.eq, "<>": operator.ne, "<": operator.lt, ">": operator.gt, "<=": operator.le, ">=": operator.ge, "&&": operator.and_, "||": operator.or_, } class TinyFrame: """A single stack frame holding local variables and their types. Variables in TINY are stored per-frame; lookups search the current frame first, then the global frame. """ def __init__(self) -> None: # maintain mapping of name -> var definitions self._vars: dict[str, list] = {} def __contains__(self, name: str) -> bool: # allow `name in frame` return name in self._vars def declare(self, name: str, dtype: str, value: object) -> None: if name in self._vars: raise NameError(f"Variable already declared in frame: {name!r}") self._vars[name] = [dtype, value] def set(self, name: str, value: object) -> None: if name not in self._vars: raise NameError(f"Variable not declared: {name!r}") self._vars[name][1] = value def get(self, name: str) -> object: return self._vars[name][1] def get_type(self, name: str) -> str: return self._vars[name][0] class TinyEngine: """Runtime engine to execute TINY AST nodes. Responsibilities: - Manage I/O buffers (text-based input and output) - Maintain a simple variable environment (name -> value, with optional type) - Maintain a stack of frames (local variables) to scope variables defined in functions - Provide helpers for declaring and assigning variables - Evaluate parser expression trees produced by `tiny_parser` Notes: - Types supported: int, float, string. Numeric operations promote to float when needed. - Boolean context: 0 or empty string is False; anything else is True. """ def __init__(self) -> None: # Dedicated program-level globals and function registry self._globals: TinyFrame = TinyFrame() self._functions: dict[str, TinyNode] = {} # Function signatures: name -> (return_type, [(ptype, pname), ...]) # Used when functions are registered as AST nodes to bind parameters self._function_sigs: dict[str, tuple[str, list[tuple[str, str]]]] = {} # Stack of frames (last is current); empty until main/function entry self._frames: list[TinyFrame] = [] self._in: list[str] = [] self._out: list[str] = [] # ----- Program-level registry (globals/functions) ----- def register_function(self, name: str, fn: TinyNode) -> None: """Register a program-level function definition by name.""" self._functions[name] = fn self._function_sigs[name] = (fn.return_type, fn.parameters) def get_function(self, name: str) -> TinyNode | None: return self._functions.get(name) def get_functions(self) -> dict[str, TinyNode]: return {**self._functions} def get_function_signatures(self) -> dict[str, tuple[str, list[tuple[str, str]]]]: return {**self._function_sigs} # ----- Frame management ----- @property def current_frame(self) -> TinyFrame: if not self._frames: raise RuntimeError( "No current frame: push_frame() must be called before using locals" ) return self._frames[-1] def push_frame(self) -> None: self._frames.append(TinyFrame()) def pop_frame(self) -> None: if not self._frames: raise RuntimeError("No frame to pop") self._frames.pop() # ----- I/O API ----- def input_text(self, data: str) -> None: """Load whitespace-delimited tokens into the input buffer. Example: engine.input_text("10 20 hello") """ # split on any whitespace; preserve order for FIFO consumption if data: self._in.extend(data.split()) def output_text(self) -> None: """Print the current buffered output and clear the buffer.""" print("".join(self._out), end="") self._out.clear() # Optional helpers for potential node use def _write(self, s: str) -> None: self._out.append(s) def _writeln(self) -> None: self._out.append("\n") # ----- Variables API ----- def declare_var( self, name: str, dtype: str, init_value: object | None = None ) -> None: """Declare a variable with an optional initial value. dtype: 'int' | 'float' | 'string' """ # Declare in the current frame only if dtype not in {"int", "float", "string"}: raise TypeError(f"Unsupported datatype: {dtype!r}") if name in self.current_frame: raise NameError(f"Variable already declared: {name!r}") value = ( self._coerce(init_value, dtype) if init_value is not None else self._default_for(dtype) ) self.current_frame.declare(name, dtype, value) # Globals API def declare_global_var( self, name: str, dtype: str, init_value: object | None = None ) -> None: if dtype not in {"int", "float", "string"}: raise TypeError(f"Unsupported datatype: {dtype!r}") if name in self._globals: raise NameError(f"Global already declared: {name!r}") value = ( self._coerce(init_value, dtype) if init_value is not None else self._default_for(dtype) ) self._globals.declare(name, dtype, value) def assign_global_var(self, name: str, value: object) -> None: if name not in self._globals: # If not declared, infer type and declare inferred = self._infer_type_from_value(value) self.declare_global_var(name, inferred, value) return dtype = self._globals.get_type(name) self._globals.set(name, self._coerce(value, dtype)) def assign_var(self, name: str, value: object) -> None: """Assign to an existing variable; if undeclared, declare using inferred type.""" if ( isinstance(value, (list, tuple)) or hasattr(value, "__class__") and value.__class__.__name__ == "ParseResults" ): # Late evaluation if a parse tree is passed accidentally value = self.eval_expr(value) # type: ignore[arg-type] # Find the nearest frame containing the variable; fall back to globals; otherwise declare local frame = self.current_frame if name in frame: dtype = frame.get_type(name) frame.set(name, self._coerce(value, dtype)) return if name in self._globals: dtype = self._globals.get_type(name) self._globals.set(name, self._coerce(value, dtype)) return # Not found anywhere; declare locally with inferred type inferred = self._infer_type_from_value(value) self.declare_var(name, inferred, value) def get_var(self, name: str) -> object: frame = self.current_frame if name in frame: return frame.get(name) if name in self._globals: return self._globals.get(name) raise NameError(f"Variable not declared: {name!r}") # ----- Expression Evaluation ----- def eval_expr(self, expr: object) -> object: """Evaluate an expression built by pyparsing's infix_notation and tokens. Accepts primitives (int/float/str), identifiers (str that is a declared var), pyparsing ParseResults for infix trees, and function call groups with tag type 'func_call'. """ # Primitive values if isinstance(expr, (int, float, str)): # Identifier lookup: if a bare string matches a var name, read its value if isinstance(expr, str): fr = self.current_frame if expr in fr: return fr.get(expr) if expr in self._globals: return self._globals.get(expr) return expr # ParseResults cases if isinstance(expr, pp.ParseResults): # Function call group if "type" in expr and expr["type"] == "func_call": # type: ignore[index] name = expr.name arg_values = [ self.eval_expr(arg) for arg in (expr.get("args", []) or []) ] return self.call_function(name, arg_values) # Infix notation yields list-like tokens tokens = list(expr) if not tokens: return None # Unary + or - : [op, operand] if len(tokens) == 2 and tokens[0] in {"+", "-"}: op, rhs = tokens rv = self.eval_expr(rhs) return +self._to_number(rv) if op == "+" else -self._to_number(rv) # Binary or n-ary left-assoc: [lhs, op, rhs, op, rhs, ...] # We fold left-to-right respecting the original parsed precedence. acc = self.eval_expr(tokens[0]) i = 1 while i < len(tokens): op = tokens[i] rhs = self.eval_expr(tokens[i + 1]) acc = self._apply_op(acc, op, rhs) i += 2 return acc # Lists/tuples could be token sequences if isinstance(expr, (list, tuple)): acc: object | None = None for part in expr: acc = self.eval_expr(part) return acc # Fallback return expr # ----- Functions API (execution helper to share with CallStmtNode) ----- def call_function(self, name: str, args: list[object]) -> object | None: """Call a user-defined function by name with already-evaluated arguments. This method is used by expression evaluation (for `func_call` terms) and can be reused by `CallStmtNode.execute` to perform statement-style calls. """ fn = self.get_function(name) if fn is None: raise NameError(f"Undefined function: {name!r}") if name not in self._function_sigs: raise TypeError(f"Missing signature for function {name!r}") return_type, params = self._function_sigs[name] if len(args) != len(params): raise TypeError( f"Function {name!r} expects {len(params)} args, got {len(args)}" ) self.push_frame() try: # Bind parameters in order for (ptype, pname), value in zip(params, args): self.declare_var(pname, ptype or "int", value) # Execute body node return fn.execute(self) finally: self.pop_frame() # ----- Helpers ----- def _default_for(self, dtype: str) -> object: return 0 if dtype == "int" else 0.0 if dtype == "float" else "" def _infer_type_from_value(self, value: object) -> str: if isinstance(value, bool): return "int" # treat bool as int if isinstance(value, int): return "int" if isinstance(value, float): return "float" if isinstance(value, str): return "string" # Unknown types default to string via str() return "string" def _coerce(self, value: object, dtype: str) -> object: if dtype == "int": try: return int(value) except ValueError: raise TypeError(f"Cannot coerce {value!r} to int") from None if dtype == "float": try: return float(value) except ValueError: raise TypeError(f"Cannot coerce {value!r} to float") from None if dtype == "string": return str(value) raise TypeError(f"Unsupported datatype: {dtype!r}") def _to_number(self, v: object) -> int | float: """Return a numeric value for v following Tiny semantics. Rules: - If v is already an int or float, return it unchanged (no float coercion). - If v is a string, treat it as a variable name; fetch its current value from the environment. If that value is int or float, return it; otherwise raise TypeError. - For all other types, raise TypeError. """ # Already numeric: return as-is (do not coerce int->float) if isinstance(v, (int, float)): return v # If it's a string, interpret as variable name and resolve if isinstance(v, str): try: val = self.get_var(v) except NameError as exc: raise TypeError( f"Expected numeric variable name, got undefined identifier {v!r}" ) from exc if isinstance(val, (int, float)): return val raise TypeError(f"Variable {v!r} is not numeric: {val!r}") # Anything else is not acceptable as a numeric raise TypeError(f"Expected numeric, got {v!r}") def _apply_op(self, lhs: object, op: str, rhs: object) -> object: # Boolean ops if op in {"&&", "||"}: lv = bool(lhs) rv = bool(rhs) return _op_map[op](lv, rv) # Relational ops if op in {"<", ">", "=", "<>", ">=", "<="}: # Numeric compare if both numeric-like; else string compare if isinstance(lhs, (int, float)) or isinstance(rhs, (int, float)): lnum = self._to_number(lhs) rnum = self._to_number(rhs) return _op_map[op](lnum, rnum) else: lstr = str(lhs) rstr = str(rhs) return _op_map[op](lstr, rstr) # Arithmetic ops if op in {"+", "-", "*", "/"}: # String concatenation when both are strings and op '+' if op == "+" and isinstance(lhs, str) and isinstance(rhs, str): return lhs + rhs # Numeric operations lnum = self._to_number(lhs) rnum = self._to_number(rhs) ret = _op_map[op](lnum, rnum) # leave ints as ints if op != "/" and isinstance(lnum, int) and isinstance(rnum, int): ret = self._coerce(ret, "int") return ret raise NotImplementedError(f"Operator not implemented: {op!r}") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/tiny/tiny_parser.py0000644000000000000000000002001615134002420016161 0ustar00""" TINY language parser (expanded grammar with types, functions, and control flow) This module defines a pyparsing grammar for the instructional TINY language, including declarations, functions, and boolean conditions. Usage - Programmatic: from examples.tiny.tiny_parser import parse_tiny parse_tiny(source) - CLI tests: python -m examples.tiny.tiny_parser The grammar is defined to be independent of any evaluation/model logic. Results are structured using names and Groups to support later processing. Grammar definitions are based on the Tiny Language Reference: https://github.com/a7medayman6/Tiny-Compiler/blob/master/Language-Description.md """ from __future__ import annotations # disable black reformatting # fmt: off import pyparsing as pp # Best practice for recursive grammars: enable packrat for performance pp.ParserElement.enable_packrat() # Shorthand ppc = pp.common # Punctuation LPAREN, RPAREN, LBRACE, RBRACE, COMMA, SEMI = pp.Suppress.using_each("(){},;") ASSIGN = pp.Suppress(":=") # Comments (C-style /* ... */) comment = pp.c_style_comment # Keywords ( IF, THEN, ELSE, ELSEIF, END, REPEAT, UNTIL, READ, WRITE, RETURN, ENDL, INT, FLOAT, STRING, MAIN, ) = pp.Keyword.using_each( """ if then else elseif end repeat until read write return endl int float string main """.split() ) RESERVED = pp.MatchFirst( [ IF, THEN, ELSE, ELSEIF, END, REPEAT, UNTIL, READ, WRITE, RETURN, ENDL, INT, FLOAT, STRING, MAIN, ] ).set_name("RESERVED") # Identifiers ident = pp.Word(pp.alphas, pp.alphanums + "_") Identifier = pp.Combine(~RESERVED + ident).set_name("identifier") FunctionName = Identifier # Literals # Use ppc.number to auto-convert to Python int/float during parsing number = ppc.number.set_name("Number") string_lit = pp.QuotedString('"', esc_char="\\", unquote_results=True).set_name( "String" ) # Forward declarations expr = pp.Forward().set_name("expr") statement = pp.Forward().set_name("statement") stmt_seq = pp.Forward().set_name("stmt_seq") bool_expr = pp.Forward().set_name("bool_expr") # Function call: name '(' [Identifier (',' Identifier)*] ')' function_call = pp.Group( pp.Tag("type", "func_call") + FunctionName("name") + LPAREN + ( # fast evaluation of empty arg list, since it is common, and the recursive expr # parser can be expensive RPAREN | pp.DelimitedList(expr)("args") + RPAREN ) ).set_name("function_call") # Term: number | Identifier | func_call | '(' expr ')' term = ( number | string_lit | function_call | Identifier # infix_notation will implement this internally # | pp.Group(LPAREN + expr + RPAREN) ).set_name("term") # Operators mulop = pp.one_of("* /") addop = pp.one_of("+ -") relop = pp.one_of("< > = <> >= <=") andop = pp.Literal("&&") orop = pp.Literal("||") # Arithmetic and relational expression (Equation/Expression) # Build arithmetic first, then allow relational comparisons arith = pp.infix_notation( term, [ (addop, 1, pp.OpAssoc.RIGHT), (mulop, 2, pp.OpAssoc.LEFT), (addop, 2, pp.OpAssoc.LEFT), ], ) rel_expr = pp.infix_notation( arith, [ (relop, 2, pp.OpAssoc.LEFT), ], ) # Condition statement with boolean operators bool_expr <<= pp.infix_notation( rel_expr, [ (andop, 2, pp.OpAssoc.LEFT), (orop, 2, pp.OpAssoc.LEFT), ], ) # Expression may be string, number, term/equation, or function call expr <<= bool_expr # Datatypes Datatype = (INT | FLOAT | STRING).set_name("Datatype") # Declarations: Datatype id (:= expr)? (',' id (:= expr)?)* var_init = (ASSIGN + expr("init")).set_name("var_initialization") var_decl = pp.Group(Identifier("name") + pp.Optional(var_init)).set_name("var_decl") Declaration_Statement = pp.Group( pp.Tag("type", "decl_stmt") + Datatype("datatype") - pp.DelimitedList(var_decl, COMMA)("decls") + SEMI ).set_name("Declaration_Statement") # Assignment Assignment_Statement = pp.Group( pp.Tag("type", "assign_stmt") + Identifier("target") + ASSIGN - expr("value") + SEMI ).set_name("Assignment_Statement") # Read/Write Read_Statement = pp.Group( pp.Tag("type", "read_stmt") + READ - Identifier("var") + SEMI ).set_name("Read_Statement") Write_Statement = pp.Group( pp.Tag("type", "write_stmt") + WRITE - (ENDL.copy().set_parse_action(lambda: "endl") | expr("expr")) + SEMI ).set_name("Write_Statement") # Return Return_Statement = pp.Group( pp.Tag("type", "return_stmt") + RETURN - expr("expr") - SEMI ).set_name("Return_Statement") # If / ElseIf / Else If_Statement = pp.Group( pp.Tag("type", "if_stmt") + IF + bool_expr("cond") + THEN - pp.Group(stmt_seq)("then") + pp.ZeroOrMore( pp.Group( ELSEIF - bool_expr("cond") + THEN + pp.Group(stmt_seq)("then") ) )("elseif") + pp.Optional(ELSE - pp.Group(stmt_seq)("else")) + END ).set_name("If_Statement") # Repeat Until Repeat_Statement = pp.Group( pp.Tag("type", "repeat_stmt") + REPEAT - pp.Group(stmt_seq)("body") + UNTIL + bool_expr("cond") ).set_name("Repeat_Statement") # Statement list and statement choices Function_Call_Statement = ( pp.Group( pp.Tag("type", "call_stmt") + function_call + SEMI ).set_name("Function_Call_Statement") ) statement <<= ( Declaration_Statement | Assignment_Statement | If_Statement | Repeat_Statement | Read_Statement | Write_Statement | Return_Statement | Function_Call_Statement ) stmt_seq <<= pp.OneOrMore(statement) # Parameters and functions Parameter = pp.Group(Datatype("type") + Identifier("name")) Param_List = pp.Group(pp.DelimitedList(Parameter, COMMA)) Function_Declaration = pp.Group( Datatype("return_type") + FunctionName("name") + LPAREN - pp.Optional(Param_List, default=[])("parameters") + RPAREN ).set_name("Function_Declaration") Function_Body = pp.Group(LBRACE + pp.Group(stmt_seq)("stmts") + RBRACE).set_name( "Function_Body" ) Function_Definition = pp.Group( pp.Tag("type", "func_decl") + Function_Declaration("decl") - Function_Body("body") ).set_name("Function_Definition") Main_Function = pp.Group( pp.Tag("type", "main_decl") + Datatype("return_type") + MAIN + LPAREN + RPAREN - Function_Body("body") ).set_name("Main_Function") # Program: {Function_Statement} Main_Function Program = pp.Group( pp.Group(pp.ZeroOrMore(Function_Definition))("functions") + Main_Function("main") )("program").set_name("Program") # Ignore comments Program.ignore(comment) def parse_tiny(text: str) -> pp.ParseResults: """Parse a TINY source string and return structured ParseResults. Args: text: Source code to parse. """ try: return Program.parse_string(text, parse_all=True) except pp.ParseException as err: print(err.explain()) raise def _mini_tests() -> None: statement_tests = """\ # Declarations with assignments int x; float y:=2.5, z; string s:="Hello"; # Assignment, read, write with endl read x; x := 42; write endl; write x; # If / elseif / else with boolean conditions if x < 10 && x > 1 then y := y + 1; write y; elseif x = 0 then write 0; else read x; end if x < 10 then y := y + 1; write y; elseif x = 0 then write 0; else read x; end # Repeat until repeat x := x - 1; write x; until x = 0 write x > 2 && x < 10; """ stmt_seq.run_tests(statement_tests, parse_all=True, full_dump=False) program_tests = [ # Function with params and return, and main "int sum(int a, int b){ write a; return a + b; } int main(){ int r; r := sum(2,3); write r; return 0; }", 'int main(){ write "Hello, World!"; return 0; }', ] Program.run_tests(program_tests, parse_all=True, full_dump=True) if __name__ == "__main__": # Optional: generate diagram # Program.create_diagram("tiny_parser_diagram.html", show_results_names=True) _mini_tests() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/tiny/tiny_parser_diagram.html0000644000000000000000000036706115134002420020177 0ustar00

Program

Function_DefinitionFunction_Definition functions 'functions' Main_FunctionMain_Function 'main'

Function_Definition

Function_DeclarationFunction_Declaration 'decl' Function_BodyFunction_Body 'body'

Function_Declaration

DatatypeDatatype 'return_type' identifieridentifier 'name' '(' [suppress] DatatypeDatatype 'type' identifieridentifier 'name' ',' [suppress] DatatypeDatatype 'type' identifieridentifier 'name' 'parameters' ')' [suppress]

Datatype

'int' 'float' 'string'

identifier

RESERVEDRESERVED [NOT] W:(A-Za-z, 0-9A-Z_a-z) [combine]

Function_Body

'{' [suppress] stmt_seqstmt_seq stmts 'stmts' '}' [suppress]

stmt_seq

statementstatement

statement

Declaration_StatementDeclaration_Statement Assignment_StatementAssignment_Statement If_StatementIf_Statement Repeat_StatementRepeat_Statement Read_StatementRead_Statement Write_StatementWrite_Statement Return_StatementReturn_Statement Function_Call_StatementFunction_Call_Statement

Declaration_Statement

DatatypeDatatype 'datatype' var_declvar_decl ',' [suppress] var_declvar_decl 'decls' ';' [suppress]

var_decl

identifieridentifier 'name' var_initializationvar_initialization

var_initialization

':=' [suppress] exprexpr 'init'

bool_expr

term_expression_expression_expressionterm_expression_expression_expression

term_expression_expression_expression

'||' operations'||' operations

'||' operations

'&&' operations'&&' operations '||' '&&' operations'&&' operations '&&' operations'&&' operations

'&&' operations

term_expression_expressionterm_expression_expression nested_term_expression_expression_expressionnested_term_expression_expression_expression '&&' term_expression_expressionterm_expression_expression nested_term_expression_expression_expressionnested_term_expression_expression_expression term_expression_expressionterm_expression_expression nested_term_expression_expression_expressionnested_term_expression_expression_expression

term_expression_expression

'<>' | '<=' | '<' | '>=' | '>' | '=' operations'<>' | '<=' | '<' | '>=' | '>' | '=' operations

'<>' | '<=' | '<' | '>=' | '>' | '=' operations

term_expressionterm_expression nested_term_expression_expressionnested_term_expression_expression '<>' | '<=' | '<' | '>=' | '>' | '=''<>' | '<=' | '<' | '>=' | '>' | '=' term_expressionterm_expression nested_term_expression_expressionnested_term_expression_expression term_expressionterm_expression nested_term_expression_expressionnested_term_expression_expression

term_expression

'+' | '-' operations'+' | '-' operations

'*' | '/' operations

'+' | '-' operations'+' | '-' operations '*' | '/''*' | '/' '+' | '-' operations'+' | '-' operations '+' | '-' operations'+' | '-' operations

'+' | '-' operations

'+' | '-''+' | '-' '+' | '-' operations'+' | '-' operations real number with scientific notationreal number with scientific notation real numberreal number signed integersigned integer StringString function_callfunction_call identifieridentifier nested_term_expressionnested_term_expression

real number with scientific notation

[+-]?(?:\d+(?:[eE][+-]?\d+)|(?:\d+\.\d*|\.\d+)(?:[eE][+-]?\d+)?)

real number

[+-]?(?:\d+\.\d*|\.\d+)

signed integer

[+-]?\d+

String

string enclosed in '"'

function_call

identifieridentifier 'name' '(' [suppress] ')' [suppress] exprexpr ',' [suppress] exprexpr 'args' ')' [suppress]

expr

bool_exprbool_expr

nested_term_expression

'(' [suppress] term_expressionterm_expression ')' [suppress]

'*' | '/'

[*/]

'+' | '-'

[+\-]

nested_term_expression_expression

'(' [suppress] term_expression_expressionterm_expression_expression ')' [suppress]

'<>' | '<=' | '<' | '>=' | '>' | '='

<>|<=|<|>=|>|=

nested_term_expression_expression_expression

'(' [suppress] term_expression_expression_expressionterm_expression_expression_expression ')' [suppress]

Assignment_Statement

identifieridentifier 'target' ':=' [suppress] exprexpr 'value' ';' [suppress]

If_Statement

'if' bool_exprbool_expr 'cond' 'then' stmt_seqstmt_seq then 'then' 'elseif' bool_exprbool_expr 'cond' 'then' stmt_seqstmt_seq then 'then' 'elseif' 'else' stmt_seqstmt_seq else 'else' 'end'

Repeat_Statement

'repeat' stmt_seqstmt_seq body 'body' 'until' bool_exprbool_expr 'cond'

Read_Statement

'read' identifieridentifier 'var' ';' [suppress]

RESERVED

'if' 'then' 'else' 'elseif' 'end' 'repeat' 'until' 'read' 'write' 'return' 'endl' 'int' 'float' 'string' 'main'

Write_Statement

'write' 'endl' exprexpr 'expr' ';' [suppress]

Return_Statement

'return' exprexpr 'expr' ';' [suppress]

Function_Call_Statement

function_callfunction_call ';' [suppress]

Main_Function

DatatypeDatatype 'return_type' 'main' '(' [suppress] ')' [suppress] Function_BodyFunction_Body 'body'
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/tiny/tiny_parser_diagram.png0000644000000000000000000161145215134002420020014 0ustar00PNG  IHDR S vA?IDATx xU/7妐Z["V.hP,Vvb v@k[i8SaN)Z38gB,hhkT\^;W@Ǽkw]J޷w}}}\?dddddddddddddddddddddd^l]R7}s gV @+?+W0*ZG_=˦ŋӖ7ڽ9%V>wS[X7p^CD?$yÞsWp=ege+YR^8un7gee5.fO겒y99;F2{^)0'wGSV}}AMϚ4$kLntzі>_^ ^}۶myAӖU/Z(<:ysV+n|֘&tl |1e3,nݾbv^H&co^:aЌe& pt< uqe[vvpF彩mФ۟غ~ݭۗ]PW50Ml0o[vciPSM~p1c 'E39 +_yswÐrӬEnc9+ެs% 0&-Qs_բyO&~)0o+^t&*ʉ/|Ӌ=T]>or^2>웝7y~źۓۋ7ͯShVs}{E|䐣˫$tVrfGaߞefɍĐ%_Nh,[}YII%^8v#吒=uUe ΊǽT2~gDެ1/ חόw7~Qvf-HWj)'l=}:v&VUU GQSR)?L9,[nV]Q}smSXSs[Yyucuy2 E WXË*-<&'oVxZ=zŘns7.?u|ٹr1ue3:2iiuNYZs}ճJOk\n9p kr^iI4rҌۗe.,~rፓFJ3x%swRp'/~U*udtQ=?և0mYGCSQ>sxnnT'{VLX5iǩ4KjmƇ^^49;+>i.$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ Mv=@W?yPQ@@@@@@@@@@@@@@@@@@@@@@@W{<>cu,;0{6r@-_7|;8t6 I}¥Ú-n{C7ٸ6GW6dJ߆9#C 8jƍsIUz5?oh?>#Qg\K$Y/8.ld0:#L5Tl8̿&^_PԹvd<Sil{vQ}'7 ҩW~.Ѿhqbk&{?'r(+9y3Pl8l~C厺] YT[W^s}#M|ҩ| ڑ)_-ŚEٴqUu/7;jD2wtǽ/?W~eX#aeh-~]Q+7{׌* ^d%jZ\5(kX<2V4u{m+;vaE26koᚋKm_c8|D~nHrB <5ys܋=W͂xĨko=32P]u9Q6oMj3ל=5;n{QrDp݀Fk?+ mTJ8|D(58ѼꁺÓ&y,My[:0uTmk <7躬67zk{15Ꚛ7oO(`BA3+*]Q= 'pҀ}ܼ#ڒ_}_n ~(؎>5 ?n Οp'5x8ׯzr W]Q74=̳*j7=2Ν;խ56mZo>W]qiap h^p>Sd|>4zeeefҸC5~Elz5P%{ӧOGCBشyK]?'|뭷L:%6nܷo󕕿Z|ڸ1bć߶m{f7Ø~i8S[9o~V !;wƍ8'nٳ'W4ʊd^n-pT_͂ğkbu3.Z㞋Uh/Ѝj6 #T7Wş.Gٸq9JG g$ 9vk? zqc%.xTau-`Sa5vϵچĦpp :$taٹ޿sG]YsWVNsE[Iíɞɣ-_Ns9!#+PyW&4bsV~/֕W.\_t9#HvW1"7juC%$]IDAT6qoߐ.+Z +Cn(kύZsEǿfT& #C 9BAH,nİW o5 V6Ɓ5̿tx;mk}D? q}a[Jh񎺝k10{@rXQhϰC.P}V dO([~oRuBhߴ3R36?;u0!߰សF=oΟ{QYO"5tg!},qcgQVwUbDQۼ5:_sNn윻q97Gquu>\b΋F006ⶵ+S)xԀDON+2灛C49 oԹR=3u +79@>0=B2[c+mZLBny\.MҾq#!3H~-S}ڛlٴ9Kɤ. OHexSoGԟdyBcq#wz_p~?d^WU5|pL,nCX9rmn{q/??xUCQ3F-xFy(훷+!r初 ÌWE5Qt67zk{a6m7 r'zzh9pgܻw#⩧^f͛G|C|G@B?w);.v ~V~+zj]̊gWTD'\0 @Ac$j lڴmkl~W+W~K~6?x뭷֯>s__߷|+ϳ=1SG_8;3[:9ؾ#nS:o߾97EhQ?;_\qϿ]f7tȐ'Dώ;G+m/?hG{ϞA)ݻ/?B=Ư}mԨs8~{#n^޸7?eeeњ(xsE :*NZB w3ToՕ?;f 'p ZJy:8h^{EwiWǹKH̎6_/ p{Q)e}4#/T'pS@׬u܎2کWbf|J>ɿ{_cY[؏/\7jݻ;caƍ_~>}b>vG>+({,@Km޲%{;ǎsۼ9s^>|?^6ʤigVTD۾}]  8N<ɟ/ 'ŋ/]fkYcF߾}…b?O|k:nϮ>m݇ V~q?d4WtҀ@:ѱ F~fG7.|n\6l;wРq5m{^Рw8>^:n{ p0ws7o.|}v~v_o7&Fon[z;/x cFz6YWiIMUlݶm[8=@^&OdV8^Z74$uO Bm?up :M{z׻Ǝg7n\>{Ny_]v]N;-coC_iO5oUōSO=wCUt?y;!i,N:i#KK_12>k|{~=4⸘5kFN=fpxz@c7 c4:YSiΝ0SߴO_%??nLLn۶m[tiܾS c;ruܿ%tJ [w_ϬGy__If9_LMC 9BA/}G>|v gVTč / 7O&yaS>_lXhewwHw_aXWxY =USӾ~am ; uOw FC%'jǾ]vL_gWTğ 26ʕOwŋ7;qBzMVHYxvxN Uꓟ]";!s'|rԨ8?{н:T=lxCߋD9%ǁJ߿iӦ>L_^\~}> jcwլ!XxWo G̾Z=UߟwԻ85_ypj^[WuP\:Goj{7o+U%qAjn;>7|t֭G޴۾l; a[8ȷcc#eUy[{7``!lpħnf̙ʓO>ֹs?>pӊA:y;§˲XRH_,-|{#_/|]Z^H *狉(Abo}YVIk/I4#Q7=_PC̊;>]iViVWT^L>o塚.ٚ/=m57N)Z^j/smȟRG m%R)D7{CMͦ}‘Qʄö?}}w_0CǞ%cF]S>WkxC||Ꜣ7Jt#Z*Wl_/^{cguWN5N1$* OLmL*=U['~"Qd]9Dh(L,hK .uj̒pmFϊ*z$wECŇQS.iլ_L&*q.8Y/4)6?+9ZL֊ŷBr}z$&YSF5XbD:<5 ُ(3XX8t5w=6N{+4goa<I}f_ivIl VSޯ[(o¯W+1iɶC} Ah;8;t9𮤩IDATowiޅ1ؼ!lJ{WCYN<1:P(ukH>OKeGgﲻKN2xdU >noCw-{-h MlsG]ӣ>ѕDx-k\/24Uԡ<ޅOumX:_qzF_և#Q4X{s玺W6.֎ǣns̙3F[;cݗ|!^t׾6j9S?=-tɷYف ;)1`8d'k"YwUVm apR'&xQvQaL>}vBAytYYY]z\Qty8$ϬxvEE? +}ΝԥaKo|_NQǣ&q EwjH})-27/^  ~Ƶ&<_|%p%}MkU(65lLZᘁcDMҽݐ4;Tbϰ$9aUeA2,k|Ŵ%qƓLQXpv:?ϖ/Z? _RK9٪S֕W'do|_7I5HּLݒ؉C5;Ր@gdEWv=NVZ_he-qc!~o~̚uۼꕊEyU}@ɩ5..|YeQr (¿ޅwL|q )H*k%oVS\M'0P +Y7꒒]2Ew%fDk:ˁ{p "q%ʓZ-uw.K]6E鿽o;(vysq_SQC`+_븪k۷KK_6gw=t]N= g}D;?߷VSKk9+;]shx1o؎~~Ulm|qjtɃH$1رc~7i:qj3.O\};vDA4$'$HW \FLXVX-\xY'>q5W_|]'ҾaCDc?b?2+G7.|~č[n GR@W{n88_3IƁ>|۽{w~N t54 iK~vܘi۶mqsqm˰kByDyHc[@Wtw7֎ :l jq#pg>8{7C 2,nQ#t[k_Zn׮]~[y?}=Ϯݻg~Nywvy]T>r8?f=);;_o9wTǍEQA}8޽{+W5vAGU[[W^ ot+ @g/}{_YVG7zq͚38tsč߿Ν; H+6&nt{@Z%;/5֬YkZoݹ.@m߾}K Ǎ =F߾}QW__/[ysl]/.n\ON+___zw%WVƋg1C Ќ/‰?TRRp^ Ew-?qRh1;{O3炝1tȐK\|@i歵qKdeehw?gV/,'L }tO<1@;~Wva~PEcx}+^eˢOHV>(ओN~/ ɪ)þ0VCGfZU|:GQ_N:vZdNȹ}gͻ=G2k!]WOpbo!nz{‘ԧO /8P.:gd/ˍv=0qofv8vڵdϢ3>9Q`<3>;j9Bonځ3=/j? z' #k[vf p,<̊qYy~ʜ>mxW믿.j]:pN6SߴO_u>e|_'tG>|v4tI'V])MN߰Cq#_{L8~~zj1@d׷a[CzŲ^Z.n'og40!@O6gWmڼe-Qc! 1;ܯV>[\hܫ,j\+<Dg~ &? @:CBڵ{w[{5༿kCNao~~?qW]^zyݶmxz׻%++b:3S;~+#Fܼe˒5 R8.UW׼p z}C4!CN}{Ɵǥ[k'Ki6ߘѣ몞YQ8f]Cz ͒cF2$n?Kw֭޷tΝQwޗ}rJhNv޻}5cF*؅<#SmWUUmZ&^Q4l=yK";wz_lڼ%^ӧ׾2++++^+<{FnUW5.s/} H! ڧz2uu8#1C- Y=s߾}/}Y^0aLbƎ>ajUZ{B>}D9{N9}{s4H--Gg2'15@#dddddddddddddddd95 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ z lfNVV̲Q=?/+)o~uE +^\Z{`#˦`zVD WNz9Yғ#%r(tIDATm񢊐yVk+3}~YНʦu\qm?+/ =TuisяJʪ@нWؾť7M9_N;Ğ%3,Md~o|sw}d>mtΛ^z;$9EKjxG&-oaSfɝ]^г)j ڽr僣® sف-7ꛝ7y{+f>KRdr~GGD7rdІjm{X[敕O0{\v^QqyG.?}LNTsy3UUee69YhrSKq+ftyӺՋIIߜ1KZURfV-6(jxSсx3&뛓W8{6ScEqU,mz3UQXdr냷?_Jθi}rqMg3gfٞC>zJxK[=CS.rW5LXI֑N5:1zpy=bq?|OFZ]EqA3ܴmSm_⛦5(yrIQ1Jr=躷c]qVDd;;uNC䒒Kgifϥ).noOڱ1:h\e9K?\z?Y$_{V o ?_AqE;מw &e%/F?^,)~^]__zv^jdeZB=m |K{sy7M.nU/pskjÛ.!Js7+m5BeΏbZW6=ꇷE3Vnbm_ʝva]S4'.'%atN?ǂy-ߘ4\κGW}错KZ&9/[{Wp#o =7&YqKl| MPtU瓿ԫa5hڲҙyΛLIjJKeP%3oJa5N5WzCX%7''y{̜4Q5uՋfɉ/ۗ*k+̝v8N*m%U.lNnxY%(CM?}.'ou?\ZzױϴMkp~źA9jH;F7wxFΝ79T%ՍO dv^-}c'KJN֗=yIDKuNk,r[Es'-G״y-վ:D Z=A-HW=N/.:@GHUE\lXXxdVx!˞L,**lksǚF)+*R=wiY{[ G1STW'۪w),Jl++GIWkr'J e8zp, =]CaO6o JJC!ˣ}^]__zv^8ch嫏y8w^yq+?Ggtڊ~#''A-(oX29Ёܼ1ɟ+z* Ղ4ѽnku]p LV͝HU rfJbRawʝ>;9[m313'͞ٳ#N*N]K̙g,;$=>厓g%gsl9͚֕X1˳$ӽ_ޘEKj ܞՋf{mp[tIʛhuu]Cķzyg]nc t=M;Ο>oVVVe9ݞ4xSt-U$nvfY7X}{c8ft sXյ[2-m_:%dumgRVR<07T JC)(d~yV.̉5gvE8J2'7xOUYqaۣiK&M\Mo+٪.)8BGFZYU(6[=xC嬞7O$7gEټ.\Ҥ[ˣXbv΄$|QN]E y,(/s8MZPQx-K/5fʏk:u[=)Z\uWcEq΄ZMc|ѓ|Տu|6=e3s .}c~㎼qYɩ7w p(/Yo.3ixjAG_2ga !ofyʅs.=xP>gY++Rbу4?#aC.W;'x;Y:j;'?eԖx-ٓKw{S4xInϨbUPo*>Tuwk4rҌjj;O@@W+5} Wbmk>WRV@׃̜18tMfM BV}}}\?ddddddddddddddddv]omHO%5 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ zL[Ɔ ̞p| 3CE;gׅ>tI[tºp]a_}~MцL15֯ g7jMTe+>>#^\Fcm^Ai}?.k%ߴTimj,k6̿fʕMkR;"?o,2gF|a g{;v{9泋dUko_XO $ w.:N +[,y.84ߢ +^VNǘoi(a+ϹjM2һxgN+{S,qm LYmnj~t/竩n>7 O$|7ohyk$1{fG/] GXr^J!.nFg-_۸aƵa‹B׷M^~؍s+ɃI5M6L'6/4şd4OC%J'yVwC;[~5̿tXrƥ HR23 8{|Q? l̰Ѧj~ uGYZ,pdl\fcL97Fކ_wk25?y瀩+B~aw\{s7 qwD/$#n{5SG k*rVfi;?}*L0xU-Nd&Q8j/p$,6+:*rFot}sĭ/?QjxsܳtUECÔ~>OQxRǥ̜G5 Q8 <(kvݿ_̊gWT L(h\Y:5u uw/{#nϸ&Q >t4篺xp Эk/`i8 Q} K{?PZ/{lK//l<|gWTcNѱ;ر4q-Æ TϮxiݺ׮O 'RIDATH/i9?d4.^:eg|͟,\?uY8}fmڼիO\| ?@ӧ''"zŕϿW_ W+_㍸=c^:,wACrG] MY˧>zG>uG.PyvE8$_q{رH_~ S?qkmm߿ p$wnk6m~uu55{$F͍2 'zc nYRtNY6n6_||_뵽xhlVQ_Lk;73ádway8,9^ȷB"0kզCY`ME/Oi߻jN,~ժgVN8bU=UpD7(L]t%=ZvW:2]H]'0tVz۪*Z}$n9IE,0G0D00^8qSO_Ν[5eoy8ؘ*ؔ(CJ+|]Xtjyi6):JdRcS/I4z>G}MN6%6͆b~poUUr'uSZC8xdo:T X8O$ϕ:T^<~iSwwba͝{'sss{Sg=X(OɷQ$øBûqMϹYJE; CSł$-]pCxSZr5-v{#wdhxo_Sqԯx3ZطioG%k*ґaq]2q b7yWQd|W6F&MmF_P>z/?DtUG1O05^m]ڗ\Pj}%c ?]fZņ\.mTE*z$9o؇*_/t4$t%#?$L.t)Z5ԃ6Y&ٲ¯ :ԅ姦uWᶒ}^+\O'͡/@bFD<ΌOf/7][" ^$~wrU =E Ƿ4g{(dlAsKޅP67O ;աHywGgﲻK5X8bIVQtx!ۍ9&xQP4%ԑ|a6+b†>OKS9q1ļSSYl:16B׿]/5ա~ {{ߞ|8(L$|wRwт<\zw}cfvQqҜ̰>w;pe《mn?`~aYzdշBJ^Cwj^"vReն7,5cU^iA&ukD`'FAh eq 1"da=6譋mu761=dV+p@6<E_E'5= JOf-׏;4dc>'v\2M߼gVT<"j? +a6O8^kڒ$[E9a5Mco&jڒc-U[;l9|(ↆ#Q64 qb0MNƖS=$ȡE q_{k=Ot epag?%dw1}Y3&w4lP_o;l?K⍭언/^~oQq' IU}Si1lʨ|F<`kSKˣt*7.Rn-U<]kb5ִ:WӉo/qG̅7 ҚbEw5L9hɁR&"ɦ:kV(IMT5LغgYD h|\\@[GkǦKt5XئYƑ`ν`x}aѽXO>B/@hv4W[7fG lݶ;;]_[;ɃN_'a;jA2^:B_ nޒG2!~-q%F$@fh1Zi8HQ[5j z3YG껡W:%?wIJ83W53[lH'ws!oNjx8p`ϽY}ݟrI}VPꫯ#g3K^8qb.jtu+OaHN>8{˖-?k&t^~u֨k64nUUngcN>M>iq# Ty57Ǎa 7 SEN <y#Gz2jTVѱ}iu玺R6P}_k҅M/>nqF 'ӟJ[Twi9tk.p$Ujݻ{O=u!r;= WT<HkA:%OXxiݺgWT82^^WM:ƏKF+aFc~??~;jGmH;wn޷7q_5F}#}K>ի:Ę l}UϿWEa(| Md׷a[C|e{&?qk_g^ueQ^y假Y;jO޽{_pqpOK/̜qhf[xvKL>BOAZӸc[m̨s~]NyC79'3 -sĬQ<꜏??>JOۻwpآiG@nVkC}[|t:G.P h3}p @&@&@&XIDAT@&@&@&@&@&@&@&@&@&@&@&@&@&@&Ȫ@S@@@@@@@@@@@@@@@@@@@@@@@@@Wp{fde,WbvNV+ 1@ -~@Ӷx/Y-mU̳z^^;_IvΘ˪* e|_8>ï^\zӔ3.tZ(_[#C驃/hImfڲ49UU =ۘ⪶[+\>8Z/_82Y7rde%E}Ŗyeœd7TWT\^ީT͟>&'q\˼™˪* 5VhrSKqe~ՋIIߜ1KZRfV-6(jxSсx3 .oN^Ek/wc=UKώbӡ7Ri[ӞusW4/qSxza^NNfi=捩(nv*Jf60sQQEcbL,wяѳ& cS6R~gLi:G\|Ӕ&ܶ>'*c{xm/>vgKKS;dO.)$y֛f/i\'7\mcOk{t#ثoa74wfA"y}+Mr7V6봱Snm5|G GޘNa5M;,fФ_uYɋяKʪyWׯtٴsi{X_pݛU>1''xL =hPܹ~1jeS7\ҁVm~.OWW6=ꇷE3Vnbm_הʝva]S4'.'%Kr Ol/K~'es+Zn:MzYwkbsb1}ɜpgiVJ̫mtޜ)~4ۗNl@kOϸi}~-*7$,77{Ԕ6ˠjKfޔU-*;yEw?Irsr‘g)K%j#o]Wh昜R}iѬiw+#Ϫ?ܖl]r_u†K/]^q{2~qzV[hԡC߼%]^VQ} `]m|#yŋnrIRW3<:efny%_h>Y:-DϽb^7s^q },MsMn"ՍO֝ dv^-|yE}W>_.)n})ٓ&KtNk,r[Es2'-N<6='$_q :xCOg$MJGa1|}S7:/!Uqaaa^[ڱV1!˞L,**lksǚF)+*R=wiY{[  ۑ{jKfd7]GߜKS;udܢx򘜜MG.(^߉w}ct;tMYoѳ&cad^'k(A 3Ƴ0G*\pÓ[޻m{ueLqM۷ =LOzc>f_=;/]֗>HymE"st~F(O7rrr<܂>]߁%S8nIYq7۟x~s+ . kuqC7rC|!J4zc4ֽ䶙U `dmV0;+gfY*]uKmR5f$pYQ6 4i(p3I'߸v~AR]E y,(/2=;qAT5^K۞^7k.<=Ǫgu"s}եs:zc7kLjlf^gsV+h19nkq|-n8uo_*\6gԀd'nCڭ \2z𠦵}'βWvW.iłiiFúZg]0bwt-7N9ɛ}uv,DO~^-?Z'T^P8hx}ciC|읐7O0~_/ipeO^Tʲ[|#'͸j;O@@W+5} Wbmk>WRV@׃̜18tMfM BV}}}\?dddddddddddddddv]om@Z@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@& ̞<$ϸp$,;0{6Ґ࠮šٸ&9#p@tf0"Ds[P,\X XW&'_T8,"L~ =.?qk4Otԙ= \ZXt v.a54ذrC8g@:ę_4 kn 7}}E ܙZ>EJ^5;޺dI\{]-_xgn<{;ܶi2byʢx7T>pU4_xQ\(9^cM~qs˯K,&;N= zMo$"ʯ4~a+Kwܓ.{[ؘu{gfYڦk\&q(Ktι':u?^j6d_}0QСI͏ngaԜk/ kFk/^xO/J%SQ"GiQ6onSTVIDATOˆz52Q7tu:j2۰2qďDvX1Ey_Cf6^nsʯob-NT`?@)0[3ι si[㤭GSXKX~] ]~%;oZ3|{rXpКMzfX6۽co kom U__]om4ߜvsmkW6~goluu/NiZ0FL}q֔}GgO}3 /jqب7IkH44LA8^I:+~Ų2z0$H~F;旽XͽC? ϬxvEE{YguYgu O:餁'<|}ֻDdzeee|oVvWWn٫2B@Ŀ;4 dFHٳgx`۶. okOND g?~[u3=3ѿ :$$p<3'@¯_z1;;/w;Ov><}@z$<슸;ON Ǔ~wygIꭷފ}%GOoZ ǽk7>| . bvQ93Fyfaon͚;궿;3:묳:묳]Iy#GNGBp$G13Wuqs W_-{l|3-nݺWIy' ޝWQ݋?QdU)KP`A@Ҫu) mh{(vA){_VV ( DpOE@d ɽ~;93sf̝_=9g@X~} k7mz3Ͽ`P^[ի)rzSK٫WL6H:~;n|\u]ۤil.a'37r?cIKKkc@ٹsOSxį0}#N%!qyeT>8.4kp-Jq!\qw^=7ߌf_hY_Z6lXJ# ZNr}כ5knX~P]6m<r}⯞阴@sPң )Ԉ^ĸ?$qi5l *|k׭1F֊+_~yv4s֬:@mrijUVN:KSO|хb_G嬵k۴nKd*dңS&6[w>rHj%6y th>2999_W'w ޶MOu@lz;v|{U ? v9wyH(oZu5?ϛ^m۴rG~xC/+JŅFy̞3'.7jAN?Yg~c +y%Ky][w}?ʫ3%JJY2#p iiO~ڵKXi߾[#~Ģ6, Ianml\j=v@hժgG+խ-^$@YӏBh45.|-{ߵ7>.9۷o+s5Qg|كrxv}׾pᢨ|͝Ӱa%(^w@Ú"$4i??$$(|Pyg3 eq)Px@蔸0!ZiӦ>Ï6%;ޙ/ϙ;{\UNk׭_~};BeXti\xVj?a GX5ƅz kIN .:C/tQ͛7m4$>a !P!֯/amlذA֭;C9$wܱj=a JOdЋަ߱cʷWuD$a 6mZ U#j 5 OXd oǍ P$D k"0@BH*n aM^>3sx.T*{{5MvPCfHmrZZI+IØ?)j}>kqOV.} k0+V5jp P-%呵rI.UZ+UirYKX#Y%QSj$KC"'ߘ=|]S3-\wfWLajȔ7Phyy|^ҏ[ 2.BX#Yy%QÄS<}:\y~uwK~-{Z ;*[1=[=^wb^E^e%{PD؂ېTxo9ߦ]=}H-U8E]Zef^"# s!DocĥlǕXɍ۲yc%,,#M1 S2ϋ 3&[D=. ,soZ֨f)@5I9M|ٙ2jISzW,Yhe vOŽV*Ly+ϔ~68P Ϳ1ĩ.<9Ppt7ȯk\S*̞6`iy\ʠp[ᵘOl}şhWqJ`.,T[`μ!sǰz ,ӥ;?pe粪 a|f%jF NHhr Ss[02YٳIӂrGKm:Ohzcn1wDmۇ1])=_0*}tCfGQ3GUo.8ݻܰ2{«7LqKà}R0Mmc;9ܹ'27FIg?eџpե6)5{7;!wK{.zcK~ F}KnMSWmR7V]|ʂ[%?jҾ¹mw)1>+[=+歜2`$hyB  3wDR_oAOͶromr=q˪LJZ֨~)@uI)vŧo T.E9[ m.Ϙ\{VWصwxGUkvFﻶI0'۲];֡aWϺW K̚ A"a"mJ޶fߪwYM'~'%;ޙ/ϙ;{\xSj.tuf/C'^;ocȻ'tԬYPe֮[r{7}xǿTj.\QF͚5ؾcUյzeSN [PsyٜFǟ\ U|qw_{]UyJ)JX[`{_0jOq:nr|Ipk T:Z0%Ub k{omɕ]ҽ}Z .UfҮ„SؿX6mzoӞ}y[nC9s_yilyhqtTn0㙙l TXN~Y4}y;W?YQsC'J5/|K6߿Pv=lƟؼ6EǪa{nVֱzqUu+9/7:gf<]Y*z̫o ɪڗV=a%(kX+˷5a2ZNNΒ/_"z@%zX)_dNKbgmZע"}&5Ņ:1iC%/,X0P5v1{pNeP,>V7nxN6[!-Ef֮+[z!%ʺTYjݷڤZ{O|{UjTŷj_>۫qf+V.^4+km ̥ׯsLZhy1ü7o<^e*/ZXE7zXEʗ FES'k#%vy@Z%}˖gʒa{%e8Us.KޠA@l/zu<įvKBfM/|ᩩʳs<5*ų]:xg -^4*7k ?vDj3+VVǻXU$ kתwމgO * ZLjE+D.`VZa_+֪BlX=J֟ ]@]vPH(֯ Uzo~wfxvo>}8c۵4$UC9uJx6;;;j_3qwwL)+֒%*=Uok@a$Og)vݻ6V_i(3N%|Fj](uׇP>`a#U}|[a-kuZ[2i ݻukҤ^k VAlvzѯӣ7oڴiUsV*|kk֬ ]mѣg|) k]tHXK86Uӷ2N k5E8(Dmݾ}E?;PҰa6[w>rH֫){wG]㟡ʬ^&f~ܙg~OܝЋ?@VAE,Z kOuC 53ml\ٍcʺd[n ͪ>hJwرU22%U>,-E( ?_~zØ %jq eWcUmZ*amyAaf k5.Ւ 'fZaWu?:3 oK*y9C#GڸPSg/O;.Rb]3xpї~nد۰;κ^]FKm e[EU /^Z(Os^yAa4SuaT*NXK85"Gu|.]ڹsPyniUgK>_}waK->:sfe6 qNqB4sKiݦh&{lQ#jK nڬ.U:G}t[R陿*s @]q)~ZΘo]vtr5%zG?rҩ'ų?(L't?@#KU*k֭k\XdiTUN*_qI&c{hCCuizx5iBM۴iӤɓ7?:O^7:ʴUi.ժ `TmG@*O|SJH}xHG7O|]7?y^G<_\P-x*'0{ΜwY(/OŮ֒V*R- U#SXZcK/| 7JRu{. 7<~C UNGKAZ+r[7ڔe#_{k;Qs^8jVwoyǺgEqk߮<{X6Llz^f1 3T_7{^ӽ쵣;33FZb֪H^0U{fVmN~U\{„(Z$8neUp缡!ڻSJ>+>y^ʄ7D-DR 9O~/¦eO2.|[{2Ts  -29a}77'zһ+g NL/v݌-o{݌=eznJzp]tysj4{Μs_=g3 F_ZJX%jUK.J ūkV֗̉r˖/?׾1p}+WPuZnKi׵<3zߨYg)Pw#ӏri45Ti}K[3++ږqziJ/$YIȼܦu{/ 7#g~ڞ[9m^k;p6%%䞄F~ 5x8w}C z%JOO_f֖p ۴n_ %*98EƽV+8 j>kƢ;^I/Z˳\B{|y_ 7ǧFjg33n1']oKa=Ytݾ6|ϟԧϞ1ׄ+ifڵnYyʱ6kZ kDWGkK>TC>UVYYY*0LaMX+@XWrXKMM߶dX#{&f\0.\Wl?Km١QPw%hÇ?Ceޠaׂş?9`/̟?r ?u^B~vﭝ_ɽ>'8;?gdZ1 {`a^+eZ^ycքߋl1ޢ6f5e jlXĥwp* &DG#>_K5kU 7~Iܳ5 ś4gy7=E6aSG~&;e1jH﫡TRRZ ,ߪ63=H B kZ-_P,I"LaMXj=JϖF __-|z!q|7eEߟpGfpr}ߟv}!jZ_nZ.6{wڬ).7q{Iayڮ'hZߠ}@~-EU1饿Q=n_WFUp֭ZU'xv:pP5/eYrԩvʥ*j~CbZ] k_ڵ1bsjm,ք5ʡty~4A)@UaaI -Ǡ%7>H׍.aep٦Zޜ{s4$K^CRtro~:PǾ2 ~ͳv䩟ѽ7yU0sч#øP1 ivU}9Y1o|#T1oEw|~rLóV*.\ѨQP:V CU8-q/XJ>+ G4,X#ƷY%nz_=f-q/dԴ8/pЧrP]Ӿ0;f*e66A?܁& PfJ FP ܛWT(z+IovM&OEJO`Gut\XhE(]CXfC( Dž-e!ZmGWOsNʔ 0gߔңGDsZCX+:y 2(_7WV|DWtì Y|F~j~P.uy~`'9T~͹_{KkqϭvE~#҄rXPBEvUߋs ے k1kV|t~0**t mM=.nKC9 MnW^f;v^ٙ3 ONm︺i qu9+%=RzS娛@&H|p7{lP*0[^| UCXdt8q0@Y }n͙_q>S WmdNww7R9#8{xѐͼ׆trםsC{[73H$- rJ$f֨VN9剿?:K8D2~QyG[]:WӺuЦJ[oˋisߜfkGk bңS°Kb.ձiӦ딞@Jkz߈iN*KgnqLזOk(Ұj=RzSئpܴim۶E?_8͛‘GʮXco5׷gxh U/%%QPFiUgJ 9G@qc\hҤq(VG&q*xʢݻ/[]ɧM~P[Pk%dmf:%P:;vwNM\IDAT>mZ;{3c:*PVz'.wY e2ѱy߆q+߱qZYEao*5RKRqP%`V:a|[KDVSa"*V·Hef<;sOz?CO R6oZP^=5P]ݻwCyvjPS{g$Cֲ劄:rR0+V%JVEj0XG>u\eOM Q.|kY4jkJ_-UOv+')ౚ蔸0! k-/Ra!ok *ZMNYez6[999 .|73:vѱY\<;#v5n(my1u>uV)Hk"-El^6iҤp1ii<5}ƦMG),>Vyoއzh5GX+}yXa-9Z*.$`VVm-:Z%JVS'C|W }ᩳ羲{?|-o>AYzco'I_9j٫pC)T9s_~ÇɾYܕ5jBNYֿn4 ZRaÆUt*Q ?۾=*DA&r5$FRhpG%`@XK6Wa$OPY 蠃ZIow챁P:ݼTQ]BHSh;XЋSk6 ۶m+a'Zik G7qF %*QU֪B鿭՞V&7>B%_8%!Ŏ:ꨋ]ɧ[6mh󖨍hP/̽~&_;wtᇟ}zgƛ~͛dgDV'I&M;+-ի ){ǪWZqRAMV%jNN:Ǖ3^a->P5}%5RK*R]|y\8#C0KP^:5?Ha+JmRS?:@eI)vŧo uC]?ntj~П/G}TTMƅO%}*@(MXT6%Ƈ5 @]vEZN\8c+=P5jDB> AzuS{gF}z#P#IN .Rr.z{ժڤIǤqA޽;*ܹC T؊o kPamǎq#,?0!m5z'?Qi>A^=+UNʍ5wi5?? *,[s΁ kVXSY}>ֲмysB֭)TC9A~5wmJJ!]U]e~,ݵkWzG}t\Xti2$DXSWxɒ`\*>n]t>ͷES) NUM4iza_iyL׫WFuoD%K~@ea*\V~*IJNNN+>xk@~;n|\@ͦϘ1a!oWnB&mڴ䞧dgzoS:aPW$g)#e>bOՉ޽~;t8̯$:s¤GS|Ǹ^~nܹsgvQ7̞3't#H [>N~U\{„>}_{maFΛ?x?ꝙ+~nyyΜ8l}'jxurn?_ks2{3f.B-qsJ%P!g~ZF3O?˾s<=}z4/Rlņs˟WJ~}ys\8#ByF @B3'@ң_=c @"hܸcSAjP5>(?w?n9蠃jԲ7_??OPRRRNηX:͆*lpG}uQƍ1<@X;ocm8W@Yꝸpܱ}Q:F?J0ٙK_#*z'~P2{{ۧwƅ(=w@;]t&?0!bz6[999 .|73:vѱY\ lْGj}OmҤIcu@hӺU}ᩳ羲{?|-o>AYzco'**ܨQ~*BF @e8蠃zguܱjx]v b׮L 5kH@T:A|o֦M>>8@MKWڔr&MvWZӾUC=4&nH@)999ŮYz1Ӱaal@ݥ@us AtjؠA +^5g+.K/o޲%[]shҤIJ^Ͽv/m6 egoSW\lm/EwH<K t [WҨ yڵ ]nu{p :;@?d/ŢKj|w/+}g꩏=ۥh**rUءyxA d.(ۥ=goK5HfGuT^Hp2{;yoG7ZNֺupkTM4iza_iyLFFcIh< u> d @2d @$?H2 d @2d @$?H2 Rrrrd @$?H2 d @2d @$?H2 d @2d @$?H2 d @2d @A歙9~Yg OKII>#;@_oaQ¬8 2~hQ%LJ+f o֤7H^e/aDnzfD0ch@P> S3'E孓GfM?z@״/G:l5t;:o@v.ϛ]~mM^o|h@ '=li5+k8(陿I (:Ifֵo{kf/#uaS7@%(hy2F?tC'1?׌o]goڴ`Ov`X{/4ɋ NI@sd6j7ڇ_XeaSi1zTP93!t9cY3f)XٯEO3.4PڗIDATc[[>G}o6nzx-sE5Vߑ=z_0Fav3wdz2fYΖGΉk5:ӆc،旫r<θ>M<Ft:~͗U}+{U~;}ao|e=3:ܙ5sLZŹ= #5N5>a3 Qu{O6!a\TtͲ[fR؛ٓFߞ[h0t|Cp/yhXꞋ2FA Q(m8k~i) 2TPU=sxgF8t1a]o_֢E{Z3wWFnqj1\5'Wk\eQ|/+~^tvȐ[8ٖVsN{!?_;icFz~6xfҴbzn5my 22`zffx7ś4 @y7l?b՚%\>}͌SGlJ05-H ޗC~y `GgO=B39|xUJReӆw1[[fƋ|Ѭ,6~XFv׾R23|YȬ [wg&hY60{6Qp|gLo<['4aQ{8k| 'D/4>d4>1c˜asI5+%'' zM%mMZ8l|fpy|5ӆэnϋќQ{_3!ݨmyƃW#S{`N}Z3>ݵ~usK-${ȮMB\1gу )de?:c%Zt <#CKcY؞[viWlϴ_$u5 |Y9OG"@E_U؟o:=gҀ5^Fy΄:0d10vXjDQ%5L)xqRR2.ڻaiQv'.mشj> Rrrrd @$?H2 d @2d @$?H2 d @2d @~3~5@ui|X@@$?H2 d @2d @$?H2 d @2d @_O<9sֲ ͡F5?Ȗ_iyBF޽3/:*ӏ:֭=~\,PmcnSֵiӦMW~ߞB>?M;U陕5i>ٖ]ֵfgP8񝏿.lש]mڤqƬY^_}zcUG>7jNY? -[O=%~ߏߠ~e>kM05MOo /~xj!2Aƛ ~ﺾ" 6o5k~8u.bG&M߾_v;sș4._zs{Q!=#ۮoVǵ _|Ž`u.i°kRPoJcP]4l۸`u+7n˝{w>@5<~C)]rv͚m۶Smڴ).4hؠ}1-Y֜' ehM)̶:vؠQ^2McmfͶn崾}_|حA0~b6|YyegLn\Vh{]kWE]2.v;sn-LJ!T依'(rþJsK>Ԉ:XČ=[:?gwciS!ks.{Fr94/*nݻ`4l`?_mkRjy鲩 ^76NL)Jc玝 3lwa@Ůڵs޼s¿^_~h&o#l={E5քD|pm޼ '~lJJwFޙ~׿^^񟊒ϝ!@jVMQy޼y?'=N|{ŲR踰u;1pI}ʴwq9EPw>g´atHd9={|w'nz~PGqx۶mE+B988f.H#r|69O\6|[!~_}&ٿ5Yƴ_d[nڴi|;wa]@H)OsO~5K)DŽhڵkWoz~qCCy '~'Taٽ{#x-O?MJ/"*7jh7*f HW˟Q.T?hРATx_B"p8F Tmc"S\\d" HKKSX֭[??͘8#nOS@\ CL{+_9"12'?nub~w9.?}0>o~7lݻkCżaC\֭k $`3gS^I멧eK^z wҩ'uLJr%,~y ǟ <∿*Go$RnS%x8*޽;TX۶m^5AV^~퓧T4ZcZj*,'''.|[ eTEgJR ˧o Lqm١2dgoկo 5Wo֬Y ~ +K*t/2ioZj;o w.;cBHV2u@O$?Hu(>¿`5YYkdԮ]z6mz3Rrrr][C-Ӥij\d[vY 3$3;--L[VƇ5 TA!ܹ?9g$KE[S<ر#re˖uܹ45}}Flvdssn( 3zHɟߐh%754i$*|gaDžș??o:eQ;چʐG̘uk&.H7o\TWyQ $|rl};ʎ;Oһ6t<1}kf-C[bw cƁ_KqDž?|9?a_;({gfTyo]G<Nŗ^*Zc[ˌ}̸gJ']z,ܗ[w<2q P~fߔrM^kR^z酻K?cx=X£;%Bq!rNCGUy*}7nؔ}mGqD5H( u~;0xJ9puAx=tYx:}n5kbmOԠa+ռ;9:n$}"tWb&?M/Ϟ]l];wx_Qo@w]' Rw}nفOΞԧOأ/`g2Zz;w,vyJJJSO6\ܨQ@RK_qWM{-SXTxwz+T}ɷ|͚gYnگ%gqMdX.2I 9}qaŢ:9ohxvk7 |6 aò!?/S8k&wfLlh|r׸P_ڬ5=\;OLn\V~kRrl{SG3i/hc\޺hѹ][zqh'w}Xtyl9pAx` 3'|rJ)vŧo Lqm%ܶm[⋔Y4g{^uUQ~kW:J_cX,P9gӦMG <*Dy͟}g֮,Wep7 )._1b~$EqQ!J]?-l e\<&Nj}Q7g:,i3Gq}1.׆t<<~q(}RS P%s x gzW{ݫi:|hCCB4ٹopu׎;?d䙿]w߼k׮t9_>jT7HVI;g>kA%-~w׮)S$} mݺu+:o-XZ4Jjjݻҳ)=zuJf$@C?@'@$$Mc/Ғ%K׮[{$Ҳe֭ZtR: u[JNNN+>xke4M l>`W|{ժPq'w;`2f 8($;v0Ưտ"_zΝ;uR"yQGQaҥ;w.g}v7]x.evlu\D,[u+qǻwc^~yO>ѨQb7YxI\hѢE $R>:.,Y 999߹|Daگk߮^+7~/:Ӯ,y$KㅯΛw+7%4?dHn[KGϘ]3k~LZEgzɏo5 3O>9\R?ӏZ& dXTh~䑯Νא;wjnTԽï>|AIٽ{e'_bܮ]|E+lڴ䞧dg6 IÚ* rc>SFFT𣏾;rg<4lpT/~ׇ?$*^ٙ3 ~wxءÙg~=\)=v1wq_}Vm?GkBiש]s£7̞3'.]wKu;oUq k EŅν;p?rPZz01GTo_Xp4^7/:Jӽ쵣;33tD3[_3'N-[~_>oH]̶aщ,,u*I]֭wsN1pm/_ %y:pvlݺ5=׉Cˌ.G4x|^5fr]*,8x6c 7)\?ca{D^}){NEz*KSNqa7-E~ĴTBf7nߦ>#8"[=͸k;ޙ3~tgN͙:^D[sk'he6\zׅk]ji9zj~{}x~r_~ gmxb>E7oA.Ru^a)wx< !c+^g"[qkYFQpj(6\ܨQ@RK>7n|ňxmGuTpv{vm~顖XpY\hѢEtLf<˿+P$v毨>:.XTaq/3oxԬ<w ώ?o?iii-uInݺ!]c5=&;^IJ/gҝS e\\;s7g/$(;xM= #<߬krW]{Mo]6?}X_a'꒔M[CB>cƐKE橓Nj<$ 3.:򉩣[i7~xq?8*?gufHkgwȈ f4e4YSeK޽{c_<$y2|~_kPr7q[ik~Eq3%%%P$h17_}w\nש; !-Wb[kGW!-9^{ma'zI}N IdK8OXwfs H0駟~?H2 d @2d @$?H2 d @2d @$`hIDAT$8} @2d @$?H2 d @2d @$?H2 d @2d @$?H2 d @2dpPi+'cP' H)b،P6|Fvi(_2R ȆiiRP_5M!lzjdi^Xp6-a{hcjQ噿a3r"Ӈ=T퓆;鶅[>K?; ^)Q*TRN:=gҀPg Op˙4(@M9PRrm_3ci ku6~ڢ%SeТ{v՛; 7,ؠ ȫLߑ9aM۰j{ @Xoƍ5{ۗ9 i-SHP<粇xś>_u^mg(O|012FOjޣ~! ?`p^޿xrm 䖷mMό#%_A}['2"Hj=ir 'ֲe 0i˦moec!/ydͬ77z;N[ڑ^a؂ 2z|ڌP]YXeq moX@f zhQ:yؘ%1>cQ{=cdy 2Mx&??:cUͽ?>+랇.cC7o /f:vWhEkp6Nx^uu&L8'lqckf(|`^Y%Ze͈; oߕ :c%k+IG`X>%E>=.뙂zg2(5P "-M3B/-E޿7dEf =3A\#`ҀPt; ot\NP2]{4 _icokY >#;T! n6t @TZ/d047u{Ӗeo[}2.>3NʫN1h¢a{E3&/aJJJ5B; Nв"0mP pIyv=Hfo\6kF;m wiќ3g6N[`|5ӆ=cdׁ*jɎv?wLZo.ua]/iEkn+7kxZYEc3ݸC[4iP |/0 s [KþG`oP˕6l- [٬IC#C:`šzsNj˥Zxo}] +s̹gIoA's D˞: 3F\^@O_gPcJ$zH|2 d @2d @$?H2 d @2d @$?H2 d @2d @$f>xk4>Y$?H2 d @2d @$?H2 d @2d @$?H2 d @2d @A2{W P$KoM6\=ݚv{~VyC*U25$j;jۺ|ے$I/ke'ySu⮬xs7_x̂=s;፸'~AWBPm _;Zx#6O~7}mJ$(qLZ2ol'ۢiɕ!^n4a1Q>﬇ael[rsO e\:ep~sKse9=mGfߖ\W%jF5ۊV%*"#v^DIlsQ@s鼫mο2,v7Fh~q)VZ^Vf{,S^&钷}7NYy }ܰr=qmT=x̉ᲳT$cz߶0՗:Q*17/y=-t,cXB"oMޢ+ :Sa1ڼ)IFK= YwvڼKR0]]:*/37՗,ꭘ7uފ]yeW^mA.¼o]w?r I 7vnm O\۫dpc,<;7)x˜yS/.YaCaEKvyEwyChڶ_@X:<W]:ij3djvѷ۳(%''~5$W\x 56uHÚJ oM͛rO~GPOS{gξ<2?8l޼9@H϶o 4h~qa-D#@ANX{W&MSݽ6wnQ9.B=ݚY]n{sq>Ydpuwje/ʥCf?˟:d?ڷٟ̓\zMj^7:@TGڷ-22\9pSYy3]k;7]歈=:;Oj\"zP> s.GIDATy:15zfK"={F3϶9sevmfrs٠:Qq^ڠ)\sl{`~0Cr P $RoVʷ<:03S[OS{gξLj%hy g۴nM}t>dgY:Zb39T}[Z.P:3{ųK_U (2/4O?}t+VJo'ddW^H@3gun[}e,8˖E>ިQ=MdV׽[&M쵶I@l.:{衇^4肣7oڴiӓ)2OgΝկrqW_Ds%z@͙>w}7*4hɷtTCG~}iKwعzgg8`@ $OzMV O>t\8[Wega)' IgM)=zL7(6$c←fԣ]v} ?r@,U?iY;XO<,0v]kK7/^/zܼqB{"o&%%ἔ UP3-Z:*&f\0nyTh{꩗.=5XRceu_\3t{c<{b٥-C͊5(wa[K6 ׭a`XI}—4;%c<hyó̾o5}# X>?u^,gheƛ3Rܨ{1oyN^orO]*gdZ\O_^{Yos_Kpoy?{_Ey " bZVJ(ABM/*V[c.-*^ukl}\)/]c -hU[⍠\5sr#9 IH |#ϙyf̓9wgZWaJ{t U>_Gto:5knvA8qv]P}š~Xڅ%mZ#Dynj Vz&1 wO~F*=v-6m%j‚rD+'٥h$=:VUz> =tiY3g,K ]#.-̺x+¸~tsi*9Z朚Q.6F~}JJ愩S/n.Mv%Ⲳ-![S[Wӭok\?+B2;܁vv5kvfgZ!/n giHߒw{dp ^-+^&kzMMRO{{mjv.Z}":b{ ߻vwpIE 0 ~oyoFaEmxG:"UftO7eʔ>{:Ϝŕ~(M]nDt^*Nn+_Ŗj䜺fy@nEl C yeY9%#97W~7,vq›^mqpvnX[&%{U<6 LN^S6 LvI7&Y&ݳxKvr«MHFK&k뿳+ccV_wcbS~Qó=ubX[\I{ݕ^e'.i˰]pnȽԷ02٭0$ZÌ3'F[V@z򒥾_3~FayWO Yw.˚V6Kx/粌ILبa휗Bo6i_H+߸2 [}y'0<;af"vW4[rm7*:5ag[Ni |vHήְ]ڡŭ0KByaOfm5e Wg'v61 Q:xvkc+ i:AM#\Ϯ,MWy5M_ ީn>~ s[f$;c%kF.(|Y/Z͜nyӭ8=q>K\6՛&D"SZps+涐5m&O{bKh?:BcغC?yo}GRaa=$3ӿz݂D1I`h%ou_͸n²5gG.oi=j,Bbddz#(`uuq췣M<>T/&r±*kh"[8=J~'.Y iȷErr+VT ~աSeP]S`A-e Z(kTH%[a឵OMLg m98YqNH3KNk:ه, {y+ bWg_{y aU+p_=4/ypn~.O&t[䞆uöfMf6gWd;/wkEHT¯'ج{ClqXWV7}7}/#oa=[aO(cH#IDAT]}ORxa!'>4QSSvn:0gZ~k^,.㿤oL dbY.ZODV ҲdjFxͯwߍw~ᗾЩkJFsx GD7/xIKN:v^X&t{A;శ?Eo_@#=iO=뮙Scy^B>{a١8슅p|KWq ibLGLƏ<ȿ׿wdǩe`:ît'ʟsg^L=p`{=)¤of]u_~VD(|.w|F8vD}+W.]_'FohK..ֽ˭=s+2 */#/NU¾vs_'@g8.u/_ t~V?I}t~LިNx2UgN{u~~;@g8fxڷzN'@ReUUp>vw.8'{l0~ܸ :{}9S@׋a*+[ͶlRrm:aCz+'|**゚6eo_*(n}L`˖-qQ}$Zqc=PFMMM!t3?nvLoڟ3Ϥ~9 L$ml۶^{Oy:A{ARO_~>|7o"M8|?0'hg~ /pѝ-$;vl'c GZ"}2O}_x!ΫUb'%G}m|~SO?SUUSײxW޺uk Fz}Ze˖Ш#33&b?"*3:B7# =͛ǿ-4$~T6,@ӓa; #ߟB@ou-+oG 6tHާ% 6t'O>k֎; A++>SSN:Kzz<,hfg/EwUVV^ceqC>qz߾ @Wy}R >7ǻo}˃ ;f̧ܰΫ?4TVu.xrbL[/#fڼbe5[XLlf7W:jW=G ]7[SZx^d9WԬS;2hՎFfXƓ6TvDxA*+fDiEʉ1-M*2)jZ 3|ZvϮl(եrκ** sքj+OZ3v߰4]OtBS R> K?$%ͣig[}ieu=gNv3{vaf9KoJv[=8Uߝg7=|c};h~z8{t'2w<f(Ou6,(I7;5Vg.V&‚t &&,Zۏh?>n|k˒>iBΑY[UZ((<>:g{ZQyjYEQ?.>%1v9١˶6j@V5w{hVy[}mzYVsï$E]<=;5=g555+]+331fX]r7j!O{,/K{semD>FidN|4lۜecuyige~*`|XYYʲV/6hZߘ3 ]sW5Q]:IS 3gBż̌)Mİ3eOګ'5.z?}Rvd痕7aZ*sڔҦ示tZ*iSrLW6]ouɬU C~s7$ =kZVtn򗓛dDrY|kUY%ä3e5uߦ5+M96&r R!Vy(=)w@FFFnY]4<~a\J*RO%SăOAצʲ)W'iP0db?ކ'L]V:&*J O^M?+v9Ek]Ξs-o~Zе2jjjZUY2)#~Zt֚C$fU+*fughE+f3ͧ' _KxtV~f;s_+"Yctr] cN'TV2-yӶi?lJNrϺ3 6IDAT2lڍ?wkJk2Ǧ: .Թ}BȞV~Ɍ9hf]qUCgșRVڊ3N1xP[77j7M1XSўy7FTή,vAÏ+~I%Yr}c՛|7V4jkOhC#&^Mlmӛe?{vš9^Ҩ.!+l_Yw&J'n}@U,J~a،Yb?]G/U9p@F#^9V>mTN9֪,+˧0gQ>}_d#ťkH)?fڄFxOq 8@H $?ā@q 8@H $?āw7jQ8@H $?ā@q 8@H $?ā@q 8@H $?ā@q 8u8*sQ7Q:VJ}۞%_/u?2lGu]Dhϵf3>!i$г˞ G6є&'Ss2 >77M=2YsR5jEqF:idjϹ֭^}x_hs.D>M>'0wᮯ=kw,9|fGzo]Z.:e% s}u7~mީNL\{仚|)CG^K]JwG%%}ֹ_pv#}.ZĤ삡nмЯ3Gj]v4~e`({T?=|iW|7],Zϖ]?.(]GۭTuO:aFC&<7Yet2⾆ pݍjC{ϩ-0@WseQyGwwA݌G:*sD鰫Xv½sCX6ѫ^ׯ~wZy?=\rt8xC9 7x:믿q衁}q$q}#wс.λ o`:R^v_<[+֭["8@Hi &}B<{>3xgZ{N}C aνqm۪{zzhY\\X;9!L_Ϊ}x莞]Dk}5hILυaBm9%$Kպ8*>&L7{Nm&_Ϩj;կ!k5fΆq4YC). W…8~Go񜆽ÑEqF:5?tv"&„4Ư-;ՉQko|W2-97O lh$o#ӮZxz:iEͬILϢCzODh\~9Кx$ivީٲL(86eGQumO$&?Y{۪F]D>mV#P'&z苷2ĺX:K/iR^!&kh~ӝ :@;Z5q9) sKΨeOPL!/ltpU+[㌺eM#?Kӛ*ee561qĪRG<=P륹ۮkw&AT1i؇u7=A;}9lU8*sFAb  EGSTW?GSV>#^r%G&LtxuTVtĄ]m2&9a3I<'=]ECmFMޛ-znᶫ}ޝP{ bgTitbFG̅ۼp.hUFMMM!;9:}G=$ѫg..ͨx]_{~gmN~]Kvkߠ=JvKKzd1g>ǎ?nl~ÿ>|NxϬ;fw4uavJV.6g0懟m޷9)Ͽs{{;=K/G^9# vء{{ay3g;s3MTrj2^MFQJˢMٰkUVVtG>>/< i@ =H!e˖ǻm۶ ee :@:UU ]E;ڮG{xT_~'>(:c =;w]sO?̦MS 3Ձ̭{#p :5?ڵ~اNʩ,)w/y}FQe>] 3NCO60鐏|㖔s&g‰'.y?:~a /DSs{N>es­önO~۷o!.cjp@QM 7C>#A/Ͽ:(sMm׀G _~%zo >|#i+?pyp!ngz/eF?!>77|k!y:j\{ z)QhqǎP銊ߖꓟ ]I;ڮ&¯vKn{qƥ7azޘ/yG׬]XIDATfЩ=4{СyyyCsϥ G>4@#SEVpC7@oQSSvn0!Çs~apM v0g9鸠&$]M;&-0a:O*m]oٲ广?DNNG3/*Q22Y'vvM7n)JR(k>wÆXwP;imu6u~ci{J>u?nvLo?<{ٟ>COb@ݧmM/qӾh q/]|I;.w (i"݈F^[?nv't94Ug>n}î2pg+*;\P;bw,}|ց_(U^p6tkLbA;B쓿%KJkjj :O ФKJC|3p,);tC B'57Qݰ@ooʕBVN{>vpWNh2rrn{5@W=[zQ~FEK۱Ċ_"γ^-5͗gyWUU*=V&;Qґ}}l֫^=*Blx49>3;0wq.MY,;;{!y3gv>r:MRHn;f.YmXE%u`6[qQʶ?[`5œy/%W^wYrF-7+l YjO sN(L.QWhUz $ |ҋǗmKU|蹕/ZjI-ΛhK[mz/R73=٦z-vlfg?ص͛4wʔ)}#9C+ʶv\i•'4XzI7f/\vl떭CrHminU9F %yNzЮ|3*Đso}o&zרnbG.֯KSS.$;o!qN{=얖ݶua;'ʗvn),/9aL(&y3gzmMO=*|3?fF7ƁG.*_sũ-1Pg_v[/HJ;P7*ښm1lܴGuB;~[=1(MO:TٕφɊaWN11ԌS3eTqE疂+Nϯ[q¶77gh^^ƩQ7[Y"-\Ų6tkM~B7y|ı@OғF¤oE>T$"gCT^wYm9Ӯ߸kn*?nn4W-19ӢI/ -(QJwީW$z \tSA3w-x/G^yyϫ3ʼn@ tIsczR/v:Sc>ǟ}G|!o?_~'O8)HiW;g[2څuwMyM]yinI;:&}8)BMMOI`?99^oVyɤKRsϙ~}ٟ_7;/JR?^8رv4/.#8gxC;WNhB.zQ*9/O_y,/!vgfdžI}vG?9kg~#*?<\S͝7 ooH=hhZߢ%;-:v?t ~xƌ?G;pIo=ǣ{ʟ^t ڮ=zݒ ju~wEۺ;Qwm׍"2ZWJ=|oOE?edd\vzS~#{z@:U>:vv]j=Q'?iL~D'"!uO.X:>ȫ~oU|#vLިNMݷ ?ͺz>8䐏 /Y:Oxt#w>7~f?Ա8$R| t3DzBgIG?򷨰zC 'O׼z7V?\<®;Ձg.8;w ;A;ަ'%1nj9:0 /*|ꓟҝ}ruc ͖-[~_rgaC3wezE>7 Dχ~ׇˏ:da{}ɧBfu~GUu9 Bܱv4Ò&z}Bǎ?!Bۯ_@F}3?(:v3gL;c͡ۻpu/m۶-#dᄀZW^YѬgouDՆ ofHUy'z!?u[瞩G?}ZYꡇSNͦ{G}. Ofg/EwnRyv '?n޼UOD?g<رc?;M;ڨ'ÇoW~&W7v{vIyƽګ}2O}_x!ΫU{O<;thG/|'zߨ^_]]?7##q匐ʪvo}g~?OvVƛo.>/O8x ?3UUUo{zO֭[mRG^z _}}oPO rhTʚ G O?Sׇ]o;n!#rHwt ߱ɧɣ`r8۸qwm6S?%w{:Ctlׯ_SOU~~b¾}z2Ǒ{￿?{i/EwQUPT>Ϟ~z8=nI1{O<f~t=ctިcFR ^aȑOUF!`5vX?&FHh8@H $?ā@q 8@H $?ā@q 8@d7gIDAT@q 8@H $?ā@q 8@H $?ā@q 8@H $?ā@q'tMS22V.еk+VPuv3uhBWڵ@>mz9Y2R2s .)^x&$ xMLjS8)7IgGL*]V~m\i6.P;+ڃҊ$nZS:{R}Y9,ha @dԴZtJɉ;5xƊYl.717X>m@ɤT6q+gk١ڱ30;|ܲh]OWBxrV~AM°^5 _[1w4LL=d0U8Rt7\V&M@4lƊ5 sd[dă &5Y9oʅ' ïz|Yʟ~Dΰo@fV N^r &M=t如y55{2n=_|g9z~=45mY5Isv;o_֔F6WU~`/.ڴǧ fryMVuy'e\J+nuh^U|fKLH[2{^6UYY2{R(^+WvB׬={pK/<"z}MՕegOH֮&gfAd.LNTY6 tN8yA˳O^T105Rg=_Yx=n3.ϚrhW(mڏZٔ^M`CˋlL˦ 9k_Nt qҌ+W"?|?8Zdfc0 Vޑ/OL+|&?|pI=%+^۸3,]E3Njxփ?%Kf ZG[3;'ٹQ?vJ|?>`嬜P=**@dԄ.sUYWO Ѓmy").]G[?e>LGh; @'8@H $?ā@q 8@H $?ā@qbt{7(#@H $?ā@q 8@H $?ā@q 8@H 303\\A'?jVcYs. Ǎq @gV+>[^;\Iw!מSWYW0͊ڞ  Դ]ySͭLM 9}CYbxqwO 4ܶظqI_>GK=~裏:۲E@küD>WR7~fzɚۍن׹֖h}Nͱ\|גԔ=ֹ9!?j֕W -Y?.F~ǎ.pIm[S3N"K'GȜRťg$\!d+NmrktL-Kʼn$8=?/v}s\:QquOx 2kh|}ﷷӦݽ䮬(WKYxKCqTطvPx5} It LLpZ2K݄EKɯ~+lM/e [QEH-p=.Y/+7sm_zMsx`T޼yS=SO֭[#G^=>}ڛ\N]\}jm̺卖: xy1E`+'6iv>_zTG?7=POW^y%* 0mG'xg*[=SO T/O$ +V|=POJV\*s1#kRV@=)J3:y36L\Uz:%uxn6NOjyyvGeQaƏ:Qs,l';ퟙoDGuTT!333Ə~:6ғF<蠃RUO<TZ*de @SOEUMNuC6l/yFzﴯ~%U@'ץ nj=x>=ROJN<#rr›oOSέ R'%{]*/_<[vªUOLrN*C|}53/2~ܸ򯊋c+qƟ\_oG33-7z| [ڲeOرc>;rd~-{W_zOKJ_zČY'L HK"Y&Ǐҥw} Bw%h6g{QfIDATzUG;.KYwhE ίx_bqh(1`ڴ>ԧ=_^hm7=@q 8@H $?ā@q 8@H $?AFMMMz8} $?ā@q 8@H $?ā@q 8@H $?ā@q 8@H $}BT:%+##kJiu]);+VPuvISv^)t]{w{>mz9Y2R2s .)]~i&$ xMnś*WM]ڧ[v_{S/Գr'.ҕ%VS8)7U336;Ԍա+ [UZ-YEen555V.sr~si rVn(>ͭlM/OˮX:%[[z3sMh[Yw}O[X"=}AUh׿rzv{V^_1;7gV6)ߦSR߈o/yfƚ;yxʉ K&O\RD*G4cSk3F$=ry;yMM^LjY4yXbRO*Y+V6ō5p㉋>~hVyV^'ly6CY_8bg#(LERr&fgHdNWdr P:.kJYcmZY:kJd*vDҕ6͟vҰ++I<3p%%lX0|N*?%{@L>Q5;ATLIlb_g&ӽ%%vY7,8c{e )4}ҕ U$H:]VNvߊ5c*ߙ,HkeN(.>)Y٥no2:qIgΚxBW\`' ˚R|GV?u(*,vҦ YY2eN gg4YwHإ+鳣 9W_1wI#o2ȟ&tXu콎80yC@[0dNUrSM%78ixjECǬ,=k=~cMRb p9ǧ f={O`}r Ƥk=C|?ā@q 8@H $?ā@q 8@H $?ā@q 8@H $-&!tā@q 8@H $?ā@q 8@H $?ā /zpUXKZbsrȈG;zJ~V555igГmٲ5-@L7K~ꓟs>ّoPR;[lQttz裀K߿nݺ5@>7n<˧}b8.2E["- vf]rӯz<#XpDׯ6t舣]iLgіHKà]`K_GxoT׷{b{g΢-ADofN~/{t@oxl]JNɟġ}_R+Vk7-7p,iiKN:1U-k qrTci>w%⢶G^7nʏXq>Wͺ*7YhKa^Sݮc9\VԽkobL[j_OTa1tW}?&Uz=@2E["- 3 ;I[w>?Nnگ#>wg[輼بQ YhKa.#ss?|7nݺ{m :/.}pҨ0~ܸύ׮@wߕf{WvMR^sy;7 O>do뷾5[F e:DZ핗od0~7***:!ņD3|wF>^s &}>6{;蠃RUO<b{g΢-A{i3tm ^(nߨ~6@V+ʵk׽{7-7p,iiȑªUv@/䯪ji_J-++ϯ.@2E["- :o/=z%z}OS7D/~!@7{KkM e:DZr '|rnMMMіz|wяg<éxCFFF6 HhE^88󌯍;|??9lϧ F^qjivUzSOmKɫ<N]6e_4Э_wME?q֭[_oiKIDAT5S."=8۲eFͷ^8cN nӆ}VsdKEC| WdWo7snoBee?f͛Cix7;jWkY`7DE5Q-u]bn9^Vuy5xV_tEt}g|]y{Q=;/W[~iLg[mi55ӲT4 /23p-ZypZ`ؕߵ[?nwTWǎ{Nk2wlWKO"j<υԚ.mK!msꢯ޳'5v:#Gm6g%}@{g~cxBթQwſ[I.N^fMK}`A(9|m[EYɉϰ/HƣoԬBUE{ߛ+_zn۶7?kag%M]^fN7d0q s:,ޒhsJ5Ŷk[쥋׽:AixZZfS֕z^Y(%›eNs /Rh}vֻ,G/J aȴT{Ka(;o|G85LpnK;x@" #|9e~7_^锖]^S~͸t:肹3ҭgk`o|>ٿGlvB'.<"ⶾMQTR{›+UЖZum)iN]?WM{ݕ|N- sB303= :tݺu[6%Rlenn꼒?sjFsuWpKϬ +nJJnn[rʴpYj[Y'VpuU }ho]>i]Va%(7 lYIt]>;h4dcN>yBMwߟ|C;}_jNmۻ&ImP7ٷn//Yt< .+KMpQʚzןhhzW}{DM7gp;E9 -`n^IB󗚆_BԄ%|ӿbמV^{[zZ,oj}l~pdM<6f+-iSӡ7Q;xH-{OnKl!4?akb^d0b"8>wo6ug`-|˒ǡOjAKNMh] ̭5k\07Cp*nނЪύr!#F=r)kR'j*QM;֯ɩ][kFYW}WHi_^Z<߶t׊4+-mޡaіjԊ٩W\VRwLV$wV}7N@uvO+ONH.m֒|5oY?yhN/i_+Zi]>n7⢟\\o+u?7Y45Fty]w7/_"y_? ]};hmUՎבqKe_6rNr+Cfq!MHͭnniP$/Pr^rdSvG*w8>ɥYa[f$o-MFѾ?iwm%I'\~@ iD*Mme&gRK wλ[z]e:s.CZ}K_/N9/ˮ&?׿G_H2M߱me:o(3shެv9O]FdN#lm2Euyw-)- ɷ >ߜ^xZʹ#yhOuUŽ%"ԛ)%W pq1d%J֏@xC_mW.{S[h'i.ng]Ojw-ҍ̳֖vZ>˩._gL/gxZ]b8#gseo)Z\7D۸iԜJ*cmWv‹p_~+?{w_euDk%ZT$UAAbIUpiK v#Xљر:ڒujZL[[+i5օ("[+A[ 5q#(H';IHB|̹v{so9;mߎ;|š5ktMQٹs炂>ۯų򢯰;/~$+GDـ( "=0I1؉mۭ-ՋD?n:QIɀc[1o]~"KY=<91c:&똌~6{<kŭ\[_sG'ꆕЊ<ӭ2/iOCH25CTN"U՗$wxn^?ʲ}\lD 'h[v7k'H:#6{( O/.k bӡK}.Q^WfTjO+C3c{"і&Ii蝫ɫIDATjޠgƊ;ZꡫvwDM> qn-6~ֺԾ}?PX,ɦgokHRY~B=)W[q^(L4TNcyiWmޢb^?{F>dZ|=RFbwK.Mvܝ6ta첗FIvBZo_Ў_k7.d-?߿أ>sڴ_?5x˗Ϝ&;JNK\Ͷg%%ZHiy]'*6]b+{rM5̰N-z+;xxEE}-9aw5_~.FCaʒh~$p?{zU{JTN9TulK?[ͽ[Of/MG}Q@Ϳݶvܖmoh ?7࢒f|C ׭nCc #e>dBk_xrk?JswG[/M~w7f~{;4 shO~kMH_ϝn ז?^Ȯ҉f65?-pvk^3ӻ5 /P]ז^EA +)yafP}-nԮk0u?e~?[n*oF'֨_X):̕.atC덿A읇}q6GC9wK{1a_%hb"IZ?wgr_|h6 CtP?UnC:>1hA{7ܹӦ]6*=j+gNK=}neUq_O~"tvFsOn%[^O<1BRRUhK4Kà][ 7l(m>⧷,.|_H?V +WzC/cBݍCob-f̫| Ɂ* &ct4Kà]Ǝ6|oQ)s\_jв௓iȇ?~mݺ5*?rهzoN[.sR6_~=sMOuyv.v"?4ΖbbY4cI'7EV>D[|}-um~>d\,q9>{/@iK5k̛ϙ{@c?;nəo&O۷oSi}LgіhA6yW銸S&?-2nkmx#z1g4b7w]hȐ!cǎWD;w.[V讻߰ߎ~}Aϡ2E[YrEHx;VZ=C9d} 6 /xns1nܸ ;0=])aykK؃/|w ssBJF铟c<|YgVGT{c?=ªU?_x~:hg?/| >$@w@WO@@@@@@@@@@@@@@@ :> $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ޣbѴf^0;:삲6QpU ר;4azObQjX^wh9sT=U(Z\3x_i9sqxM_uvay=uMY4fomVP\2s JIhg,,-UUUu+RMGLʚpų732?5r3oѶR Eu8 %.mfJF]Y^;czFVUK'-gkΔ]"5tҲ99CCT>1 !% Lʨ9vV^aA2R\ZldF rvNgl[wf^|a޸3.*AYz/ʋO?ɰicQўDy<3rf+,^U Mv]&L-\7*=dH>veܨXx{I u+ͯysD5^qo'MT,*7YxqeL+,,mIA]bQ\.pYyiΰi9YSefQU[++?̼(q*rNT[/+״2-*,Yq₢]r{MÞ.,_ze}^|g?t=IpWPoF]2ϩ;xs]ATWF:-[Uwj ]xj++ e ~d77a2jQ UdefԟHz5+[u9Y]uδ8ܜVLM~]qI6 ʪ{WN=~8/kjow1?tԶ8ك8F ]`[Yd-au;Wm|}Ydg̈$bբy3fݱ>1ًu_iII{NNrq9S#箫nEٜQvqbXR*tEѰ ڰyk[7au++;Xّ.Wēɣ ;---qy ˖& ;8NeV{o98@&e lδiyqmn-sڌIE͎XU2{Ԯ!R/O8p99jgcKh=:xmٙF͘f ”93FnP^\D$vE5#c`;Zmv7҃7 Eڟm*+u5kg.8>YZ}1s˪l_QV`δq2kǝ̜]8wd}+.Ve}'QjDIQWVlY`F~z"왎<3;;‚֒99S/s¸ޣj+mFWՉ/(L'g&imH͸x>͞tq9񢢂euqQ,؃jo[G<)+E3Ɲ]G^tUᴌZ)\RCU Z0;WHl^hڡqtԊw\:11m{gytUYQf1UrkO}oh[qި3hZ] 4t޴ohMhvVAbQpuv/ F_JEr{iI^3f*i3zr64߂2#y'׽asfWW׎F̓oht!v}OHIsఱS}&_$=kvI83^\C&ՠB̰~G֯ Gw `H?:_pcͪ߬zf5&;=0뚉k 5CFa^o8]aMmyMs1_>{DҪ][[t_ooM~/HyfGYyňf]n'^2w I?:߳k:՘lrm+=|M+G;~wqLic䏮#y&&;g!9,ao7m7'79zĺen:ai}YU۫.4?@g;%?1(Qsׯa+.ACj7`ۉo#>.4xمwW12f\йw_Eovzyns~ 1K?:A߸os٧]e/+m :<#Fw}]LG'HKKv^<cIhd / -۱c#>+㇟Q#Gz3XgbgetUxΔZ3>C-?G5jg?/;[~O?6bϯYG7TUeΝ ~c߯Ф} \UK:QZuuu+ykK6b\1@׈ޏ~)'?wܞ`zg}Ǘ-}YEZZZh .|shU_._Y]1{[*'8ãxe{2\'@#og\?~ Г|=ظ|$?)^ }y{ҳDmrm0 *oP$)q<zcM=#.׵Xzf]KlYIDATŒ^V 'tRjI'7E-BG[⋁TYY&41@O5iRM2]YJ'AODž&Ə***=vHOO{k_?H?HBjx!5?8hě6fxK{ĮKG^ǎleg m񹵡 t zzky7pģF;Hφc{5?]9%]xuuGm{n5yjMMkU vKdcm|.4mX5 55ĒdL6M7|q}Rג2uG^<ɛ.4|5k00{?(BBJs]={&>foV}wqkjo~Ʌo8</k0Mu7|vӑW,/Uw$}W$ G'9.H ~pfYE 'k:_>=_:]&4p۞??kv?Xs5׌Œ pPmK~˷vZ{q?6qn;1w5o7_~~Mk&.𸚨م5Iu Nݍu];y$-_Mh:Lh~Mw/}5}ӓ_SF]ltk;9nsk7ŊP?saMvm#>嵹qQ'5m5c5(ƣnۗxͳQ|R/\\ͦعݰ>yG;مu&6 !ģ(;ny~Mw?Ub^Q=:p}}υ͛X}c {kx6\\/J2EF ?< &4(f6-l3K4 gY۴~Ⓑڵ޷LѰ.}B;HH/5B<Ӆ^].]^ a~,A>$r9>{Ӭk&NrBwtӏ UtOڥ|b`b4ӌ#K.mfzSF]ƃ7%KQ0LP{]1"}SF.lDϽ #]urM6?fx'IJno[>$cPKNX31aq%^OM-7ܽfɦ]$a#j07_ܚwGH rX3a}NO8fܺWܽ)J/Ubݿ9lud8憵M.nɼ%WId-WhvV]]wh7?feMa {&DtxFq&\8Qɥ?"tO'&?DO=$iM Yf1<М( /_<@LJ^tגDZ}ݨر#imzſoF822)* ;tȐ\pށz!ICM>ui6#j}vВ^6 / ;Iõ_@JKK;㓟ș򱣎b 'm9zSq /qh)'iii[nosczSsŅ '4hPdxͪ8V>xȐ! &o?>bŊ7N5z#FL0!gʔL {D7 .|s^97osU1c ߑGHQZ>p~#oh^ze6l(JӍ'>?ǙL;h]'y}~\5ڻu[l C =U+odeu ]e~]4}zhnݺm֭}vv]:?NwjSO>lBڄ5F ?-!W Æu$ʊЁeU?󹏜c#;o>m[=_xՏ릻%o%^n~{Û~dHm5t!+֮]{dž],z4'kjn׏aÇߕlv9Q ^4g|s߬|2Z#}!'k70# 0u߉'kMx.Cwë>wMcqqa͚C{_eeŋT.ƅACߕBwr_߹>{Vh]Q =v) ް%WSܹ _ʋ{џ?no,Wq7}C냇}kڲeK8ӏʊ .=v))1+7W=n1aBZuέj0aW.q>lY\~ҥq`3CaoO2(*K^V> ~pc\~Ǿ>Si@ҧF\y;iɞ>]7o='m9]lzaDGxCWxr'NOo^5ʓCwYjU\7yn7~|F~ˬ ~mWjϧomuWM".0jO?ՁcGh@G7{7n}NZk3>$´sB}eʲh /[VZJ-2o ݨnzN>nV}tThF%QnN9K+zزeqW~i9?3O=%j˓'Mji}uNF9Чta7hHF֞6y#>^mK6.J+DAϙpmEݪ랺[ңWgV#Q*4mBrv2,L/16A\y^E=.8|SB:Vֺii!1݀g=Z8 7d'H鍓C[TãF*//?~k[hݝxז]Z[,kwSgqׯmA%hqht :1bĦMv]eBWg}97n؁3vnsXi"~cN<&.?IDATKfnm&t_4 -E1|y3&_pF5Zn?XTқF>3];܎d2!䑒QJfm='/GيЛdf}۴ݸwljbdn30}`q*sV>z%=lC4ro[C0|v|7 ;z/sn=oܟ&zT\;aµGՃֽhP^QZ'[-ū5|%kfU3}kQק,.Wxo7v9lwa}/tm5a;?eSO-jfyoo@7v]X7Xk[$5;MT4[YV°Ps+?R4/ndroy*9e`asIf<ז? f䬃CIqDۥ0.t`Ω8Ht*kPmmOOFO<Rw锵M:b֭S:{ŊCW;ѣGyYwꞨ3O:}RKŅ\x~ĒYG7TU%^rĉ/~y?ӛFt+ϻwC>O7&5'krG=Ir(41MKV>EaEVCOc!Qh_F5ЎskϩD4_';J>Q7b$.e֫d=QU8sV]w'xiS=v~C>xH\xvճFTY{+DžaBGӦמxEK\|/wx\}Wg<:'s >ʫ&FϬC;%=R}Zu9-ĮwSzl]Vxiڄڽݲ"&$ șۿҴsx]фkkh~9qи_ Wn?Gѷ{* 'mv=u??y@I.-uQ%!UֺT]0bBaڄ֙9+* Ӳ)-FXO-^ͤs.+w̬msiqq\bӯ_Mx%qag/lN8a\\أD|}ϵwj:u 'zV?;7'wφd~ѢSBGvzu֖!mac}ƅG|У%G (5_s<ӛPth^x1.~k{Ow{#Ǎ{饗bСq\|G~nM>ّ^pK&"O+>yET0` vE[lBڄ@snp@Gns/kI\ [Lw76 Q8~ܸ]<ފ 5X$ 2?ϏɿD_륥}+DNF\A=ꫡ'o6躟@O7[=x҄{劊0h^x޳sθп3o!ߛODB2p|[eׇn'^&9] =X'yiu?_Ϩ.C }谸|c38}'ܵ ]鳟0z'KXm>P\:fUeƺc:*t6w}#~rSQ7 {iӢ^x{^y>ǎO[ݻ9>cJx2h-7nʞtRm}ݢ{cǎ|!9bx |ࠃw1YcNAo:Ȩ1 ~vزSO=9@+z_w`FF\"W^yu'0 Ъ;ue}&Px7~J:ѣGE}ߤ&Yzʕ~晬G5v萄@{;oazO}ׯ_݆w}woWVȰ m\'rPy/Ϭ|Q"p&7So{/t韹0?KTXf?:s:󔓳g^yժUUuk{Q{4hАaGuϫޥ.;B4V]]wciq񅟝~>Yar>3z&TUp'?:U'޲zhqdeE^KyÞعs~c>@!a}Y=tqQs_,~_7( $k6yW銸S&?ˣ?jΕ'ggzVw-{Dk {ɻ36 :SO2I'?`m}O?]ZJ-S?t@%7vIIB8 7DE_!^rҥWH|GYmfgvQu۶~:>ii[egސ:(@{߽Gm,tw8#8tNcO?CrEETx~C_~|\QiiiO=uNgxp [l^~w. _Y =hաf2$$gK=vŅ[6z76ot%p>ǖ>LJ@,_<_޹W^ tO~b;)+KKK;6IDAT رcKy /l_~9^u۶+>̩!}gϚy谭[r떿w/ZkQ[ ^}jG9s.##N?ɒ( ?xJJ?:֭[KE6-m74hА?tءYYc tfW֖GRRRRRRRRRRRRRRRRRAZuuuz9} H H H H H H H H H H H H H H H H H H H H H H H H H H  }IŢii (ݥtNfZY:> VՑCw.aL?H(˴ti3*+K.=wQrݶEs̨[9nFAq]fmɊwNW~`ƸgHKѪ6ϫ}ĩgYbn_Z3r Je,]:_yA1Wnp{W8Ҳ2Z۽8/s{ѫ[5'+tDœYoidK\[U|ѩp+*-a;JH󗙻(1-;ύtkuŢăhC W{hmE3usEM`[m]wCw̘_Yj0ޖo{m|S*$t@œcolpSyyk~9Y51) zfLI{XÏ5ܾ f׺u{fۤB?MVȟL/hʊ=Q9w~nm,diY‚)Җ;#/[|anVz-(vnUf=(`]YpS7ll^6oq%sr2kϙSRWͮ¼ocך|=5Aݤ_뫳OM3n骂X-L?g\ح̚l7h#fD1bAvh%Hd҂ ܼpFI,pxYdws:iz+ 'fn/d̘Yv۶h ɠlevkVQRV'=sFzZduNX8N&sssv];тqMFeiMrYV>=' 㞏G.Kk~doeݛ|<6^N-dxx}> 2;iαY OB& ovds7V(N|æ.xhI[7橡{e^QQU%%ν欛hZYFFr%vӋKr̉w޸$G97F9S\Z^<'gTF􌌰*tqyyHUQ~AeEyyMýp34?saœ̼b ݥM_Țnqcoj&SefJ~߾"xm*_UT0#kW=Yּ0o GUܶiY-tEÖgf/pތQiiiم5/Lvc\1Yy WWF|e3-"@HnӆC-*nEYA1m{gyь̰*?k5[p{V-|r]to6=Vz岪]0'{-Oa8iDtN?͉ rYEAvi[ȸ9'o.ʚSyWN;vaO{CE XB,m|2o]wܩZtacLrZ(+xyM8,~~@*@*@*z̴I.( Чt}?QX\/_va}N=mT$:\~?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H-&U%~@@@@@@@@@@@@@@@@@@@@@@@@_H4BwH>|]`wRߦk}!gΚ8hHF5Ǜ,hpM'f :qhɉ7ߔ75nq 6\h!#j˟$\Uo丟6%ך/gC+\\ڪ5oxo1ƛsǻG_/?->})EYp3qc5 촷wr{ň0&=0gᄚv <ٖ ԚަaL<|Q7쐌>ƗQ'~~M'.y.8/Flj±7̏üg^|lM L~K.1v/?ڃ7=Q*xccWѲ/yW|nA[-9q3?X|ډkf5 ʍɨs kҪ][[t۷y5knz1GG m;o?㏛|꩟:lCt^o}+*ގ)'gzrvǖ>Ʊh˕V~C;fGm/QS# yOz'z˭QgpG/N^xoc!uk6<ǒ(x ۿͅ-1:Q6<>q|߯־zxʕu%̩gy翭[N=+fd +_9cG}GtEBz;v5k覛ܹsA{~6K\0`QGq衙;@Gy>̺u۶m1^@>3SN>=Z//[?<Ыb7w)J6WV9co=0p!C1zq6oeK'w.g߱6WVD󟻨jS+VD{#<HU>+~ŗΚvFW=IDAT}'G??܎M{}q/RT?~ܟc~Ν;O9mڵkѣV?b} >5#F pQ}} Q!==}y#m֯?}ݨEgNz{XOIDž:SGd;mq!RŠ!=USZ*.tIuhh7餓~چ7%Z>p~#vnVYY&41@;MTWV?Ϗ ߼f^{׶W}c$&[mݺ53sX{w|ף>3~ܸ5~ܹW_}:]uTUWW7❷±١#[_ۺ .|sZ9SOcBڄEi[zSNXT6lϭu71jT(}c=6t?xhn/@XfM\hogAs!ą5kU?J]w 'kƉ]F!KTVV.Z8.Os?]x-+jThηs/|)*1Uأ'!@qdeE^Ky4/)jw9i&#&L6H;ZyW:}ʚŏ^a{]/[?~z4fҬ͸dS{$؜vE,[z*Uz<|y)[W͹%2NI./fg^3&O?]\X5)8t=̷z(M$tVD?;°f71o߾KKx|YQ7߮ IFkfGYIAӥ)}*tmhv w-[~eןu%%|cu!(Y\uKN(49E\)3FJ^LKu_|dR\驚U +%0+/y+n%s*r#].][7vQE}ҿmg[=ymM{CQbž^ȉyqwFtF܁+ϻ5q<朁>a^}S@ׅ_Սڱ1ZF>>H<#o%CŵԎKXg֍X4i7xfL8ۡ3MaGWNa:Iq tiɻVx-1_<ܷi2^h3W2\Iَѫ/o2IdGb@-/1*D]YV LH=Nhu:x<[Z9icOYtג0r䧪[ױɰ z5 13'D?Csn~$/16 DYgO28i85BQc[2vнj7,C]$ٳCa:Yצ5Iױf4iVS{D5k/M9rGC5ic5{ĝ73G Īt]Zj-[DAц-Z:G_7Esz{?( _VܦzGG@gyH ?H?]ktw䏾a u~kuxm oFzk-m6!mBqKFO*[Ҫ [[Bs}񥗢f|Cd!=UM<_}QaQG~SSd4k<4@zP\P1-֯ =Xo#>'›oT0Cʫ}..3&t6 ̞t1Yc[5(͛^{=SN>ꖋz^-+}"‹/}5Y;zԨ ϭ{ wsoKqC9;-Ы رG56---ЩV^{;J/wЁs֙<+VUUm[$L 6 4h谣:r}{0}PZuuu+ykK<4@ӵ RRRRRRRRRRRRRRRRRAZuuuz9} H H H H H H H H H H H H H H H H H H H H H H H H H H  }@،sh삲V]qs2Ӛ*(oÎ]Z8/zyUmݣ =/7_OQ^TD@Ǖ,2;jIնdTTذ`lzD50}bi.ҥ⣷S:v5zNHi(Tpi3*+K.=wQrݶEs̨[9nFAqy3ݴhFqVj᜜xqyEUh.urg/.7m\gd+؃ǯ4YoU_5ioYվQ%MvmϩW,Pg./> С V-@fzLWTItNW^}U,^zUg.Οlᴌv/ܯ8oV f5g{$g}oiEz.aعwf-HM] nƏN_:JE0IDATGv~ƫνskd(2*;gXhؔ ۼ59u;4ZXynj%y-5șZ鉧X}U~Iŵ=E mk4ݰsoO=>yuI53>KfYվ5n]w5=DȆg1}ij.=ѰxFVyʗg78{/ʚQ\U[%o1]_k+g(l_<a +Da3DVqRQpδxyzV^aDiKqiy؝-\07+=dF rvNNC/-+ʋO?=3'~2fXTs=3jDu|nNMme\7l^|=Է-;s0u e&&=s좲QŹ> %k}uּs-]U0da9nef!UB&-XWVX eDPAvNc7ΦjCj\YsVEYުqk=k^8E&p^Q:3-*Jqݾh/uZ & 3_߶Eoؘ( l~^Ӊ϶UdefIϜfe5}@Iw6~=WavnnNss&$LwEI?_*/\yQalF[n++}[`{@^V0vSI`wv/9;?9axEU%G5ܬjQ1q3lꂇ6lZun"=S^ZJJߏ =Sr,;o\O'J#h42g%xNΨa[U $"3tX-~2ku326jƜIoQKWVp;eΌQgjS矛,lw?IߧQWV$mU嫊 fd7'd&VUVR8''3 2甆q^ ޸_YibҲx=8q9Ӓߋ UcrqQ=LH>.8>QX}1YyEeU)UZ70ӳ[ΒV]]ݦ W5>e:-*nEYA1m{gyь̰*?k5[p{V-`Rhڡn7ML*厺>.X=ol[qި3l~aW.(۟(,.З/;o>'͞6*@_V]]^z?w@@@@@U4(#i C胛Hmqk[ nJP6ҭ2+ mlؐ#  6E$ -s4I6~?{瞜\?98@H $?ā@q 8@H $?ā@q 8@H  ;uƿmX/8"qI~taGd6v㨧o z{x o˖/.>s>vG㨱7zr쫧x@ob={hE͙S?emɝ+}]nq35Wtn|O.ǵ!1Iljl7?ru|K?M )ןw?eé'kgu7~/0*?33.^og{Kf#yw~N^E_rt{G\q?tƴ^ˑsR>pK/;wDs[npM͹L~GmKlʇ?DQ4?om{}]0=_=qo7'SkWt/8{´ɠۓyXrYhInG|_~ݩ'후, >-gd'WO}G`GOj۵HzY'=-;;) l|򹎼G{"ɇ߹;m}q?m۶z{ۄm/x]ucM<?.;wu V{欽dc1Y]N>pKKym[ç~bt jז>}ӌe`dԇ)7S낆0ғn.9OA[sŽ,0ʨ[Hfyۖu;2/O}H.^֩~C[o?nQطmghu4GvA8KNqDfb']Drޓۣmi?]2S\mw^7>|˷ Xo5h +:z&?}~AFkkk;^yi{0Vo񂙿G.6Ge>~;ݶo^r%3ǴC'c>{z3n(ۿ }fɹyiygg|g]d²LoK>/U|ATk䛟Zf}ϛzƍD̝;w׿޶g~E;ʧ,x`^G??OEK%K>cR[SվX2]'%3k[^ԙ Ϯ]ytG7hK/vXMyWkiSSܳ>8,{k_񅖱1CO=gwfA@crϚ?ET?~/9&;;;c Ơ0{񥗶<_n޼sgzZS& NU-m9ߑ1<k^~o5쟿|.`0*Y؏ޜ0<蠃#=#숔0ƺ{կ Àp]{W0=û>"E_2q™s:9xI{]q_Ǎ~gz믿>8q„'n O=GN;K/=??tlvGf̛&L 1gL^~cngo¤IG\ Qj~$^{'~OC9$W_}unyeǎO`lǎ;v hsdf:]۵sW0x#7>>l=n Ų=V#<}<*wᅲM|0877TU`}톊'͸ v;O{3=oα0;>=U{V57?0hmmu+/m#20;? ə2yOׯfc=}yƪӻm8 k;> T͕e_ ?Gܵs Lxˍ},YRk]᲼ٵ[l:7oQujҍU.nJU{3a)2[Z,QٔVzV֭וs3r~ g[;I~2V rʽq|^Ξ+5~,ܞ?]W&NƄkή=a:ٹ f۸ 9WaSbmܵl+MW'VYY|eƼU* jM}:(X1~fU+.#a7#_V>9pSdYyڅݴBz`, 6_%:Oz O>NE;ᆧ{n+aSCTͯ#c3 S&sWdm_چhwwS0SwT"<31>O8 QX R#p/ת؏jtGG' ܌99m?B[6Ӿ`Ą_ ‹KwNi[seyyf^~K~Zhe:8dӹ׾:.K3FXZGX?f̘_"hӞ|׻쪻6\7272e|ʵ3VMɭ|&aS4/ 2 }"5`檶Cڦ FIaRX37}]Dh,%vG>nX;wO}T0x7Loz~wEs>`m|3mƫ:ʛobmݲnDŽ!U#*}~8% -Ϸ\9`tx7ԓO~P'ci|oXVxOz/`Xe~ʨèmЦʌ^XU ߿[XFՃ?z+=O{/筛F/-䴼`$ pea*cLBKg<裛r}O>{3M;}ZOog]aw?%a5ߕWyo8_|1,K~s~D? ~;z 5?Ev/JX}U 0#7>OovI?^|Ax衇^xAIa\_E' 'eX/7;ޗ_l Ʀ_{mR#̛SS417[FxGerr7Oڱsuw|,###j[aaG{1mjg/gA7*w{mC?Z_ '4篧?O~}hFO;ᄜww=ȣs|0޽{%xJb'-p]MssǽatLv(+^x?&}{xG)C=ݧv\Kˑ@݃>^>>pBaV =!'c-j[X{g_%'NXڵ[kiF{wN>clԓOIL_{mw0~/ԭ33vU>Ntޢ|XЫ1<ϋ W^qd I $?ā@q 8@H $?ā@q 8@dgā@q 8@H $?ā@q 8@H $?ā@q 8@H $?ā7/MdtHT4@SUaFw5`Bs7F6eqpЀjl_]VȞ~^f- U=ag?'()Hdv>wm`?֔ى%٥5ue]6U6v_{?6UMŝ 5m}]Tgphmm{oMq5}:Λjw6r֕vTf]@Ҽ̠_ZU ~L޺4TM]{'-X״0)ɞ{snͫJ̸bK'0;;?!++hnI5Vf29)Sݼ#ne;Ot>k)ND nl[r mҜץuJ| *},&Y~o[]>gRrۖԖDY͟3=gbL Io|skkKmiNKwfni]ZT 7FϺ<IDATeuQS¶eVu+*/;%u7xet;cGZ\VmҜ67E-K$ e6/aVfs]7WT%Ӽ;'|{d՟:UTUoiUc]$hiYsgW/uSfaԭnyiU/7ZfQ\WZ["¼'I aܗTTT) RSS6삢R5kKDaQ,lh6?cւ{%E^@MM9;;욛¹k;8qP]mVf¬^egF[ZF0 (R[[&P9mzr["/5I/5^c7-/>w]onْ*:snڏnG6TD6L~y5-}]N l{TZj,MsJsrR{➕*J53甥* KSo ,-鑕Ԕޓ,Llia0JJ&}O Odiu/v~-k_o}ӰԬ9%P , \qJ!ΦʢD4mեQ`]zdK;U.IGdӖW[KSaY% +jn)/ȉ=i~^^08Vvt[-59322*ۏh)΋)̢+#@ &!Ꚗkeu!hmmesČ(񟽷 cCK]yi?[ݬn.ML첱hw6V%* 3;js=Aκٚ!g-5t?5&]@KE^KMIbuMy;kJrm[}U95s}⬳n }h.~kSP>=N4/6[>ZVuxig]~˦~̼u;t%sNV{.nܓY| b}!q浗5-kRIYYS̿dmn~Ar^|}uno0zݽ|-!c*=o e9 q0I ?~i"#\32" #s 2Z[[i)I̽y0L,>V. z11-n_^ɂ`p&*- `Ljp`c@q 8@H $?ā@q 8@H $?A+/m'0Zq 8@H $?ā@q 8@H $?ā@q 8KaGd+ʿ|Ey 9ß}Q:?]a aav~{fj/uß]owp$[7@LʊKVC{C+{f{j?āRVM͘*æsr3.ɪySum,Of#ޫ}n Xm€.f»Z2Z[[{Kۃ!9`/_a36!Y5%.[[;#YpYm -KFeT6/(={Ce!ԾK7n[8o6EG{qwrciݕ[ܼZեT ֻRoksJ*]n?w=T}!m:wWۍ? n[=߱1lLQuyr\jA⦠J7מ쮎6}tqEGV_rײ=uJ ntx-FE‚W5T3 S]ހ|?]ܩ{Nto䂂]̞V|eŊ%+t_<Ch>n۸q}TƄOG1>vvk4+VV듇ص`|*h-N>ED7]6!`et͕֕.4G&|{]仫+GU(Ԝަ0K6ccUZχ퉮Ź!=.>4}䱝qHf/kMX]FVN¾j(}zQW'/WH樅MW'V|e5>+y[zv/ww#E2tIIaN*mc~w y,1kɎZ5ũٵ;97/d.ܖ: Og7-/xݪ9IMsswl|d}FTl&4sf$fվklܦE6<]㪻6rW.zɥm^]jQ2ʺkaѤhMM^x+H"qAmeFnej[xig$C[36]vuSVX3g:ڕ8*ڍ3ZyلE+{$WkfgTµ}¼Ϟ>\m_uWbsCP ŋ:MOLwϷ[+95vՔ{{OBÀ00sa ﺺ:wq`aUwh ^!#bKύk{h9Jg?1D?_nzIi3fTw9*M2g$?,+F&#RԂS^g|NJٛW'4D)YL:*Qt-/unUJ _*BS5NydCe\zޣ7mJƱtžW.M❥&q_uKni_ǶXj%L1™k0&-9\4j|\ܾ)e*Sr3VtȪyEO3\}5= or%/,DUFFm7h^qO=nw2.{_y~oGSN,vv ;tŵk>/We̫|&^l(_C%Jp7٤0뼘꠆J?=׽'Le6gϋ%׵U VFkkk;^yi{0$9a1 ^)3cvJ]O|75)H.X,N΋.*x:<߉L% ڥLϠJ\r檶*Nڦ.tHS/Mj5ۥ;v]NBGuG;:{/u]=|r-l]7/>ڎJy↓t[w}vW]6-z[M ^\W&6z*CeJh=wzd_Vnhk|SfWVX"9C8s'0Z9;V>=0OX<PЌ{}xh|Zr Ջr3@jJnjȦʌ _ E7u=*յq{=,ܶ1|)8 *Ȑ E\rau]f,wR'f=IDATW^Q>0;??zȄ._yi{0vDf0”F>)jc){Ŗ9?ā@q 8@H $?ā@q 8@H $0ƙq 8@H $?ā@q 8@H $?ā@q 8@H $?ā@q 88h@+222*ƊDFJ1@TS⚀! (k|0ʚ2Z[[X"q¥[` e90g]YvM/2.1~uy*Ӌ+jz5XWd5ΦeKw/Mt^AQAtĜ$6{kgcMEIÓf' V7uk{%Utg˫lV56u{}:KV4UM|{v6tlvQE]ːzTTWg+z&~GL/,_]]>=κwC^׵WwozR 〒 -P?.w91ꅦՅ]~sa_6VwY\н#7v! ޮ;m똁#`oy)5)*@p?4t ~ ɓW6knl{`]cv~u-5%g/>Nu'eemo~˾s [`]S NK]yi?뾩[WQP7wunPS=[T_Wqgﭯl?}sο]]4]cUafV sou;o oKzpm;j;z1\Ѿ۞umahvn.=24=8mƊ'\X pu޹kkwsn[Mtp#&}9Uk*Ӵ^@Uv=;>Ft.fi^[0lݺ|jcv%ikZ]pLݼ#Ya .8> k:O[:{/_X;BehA]-gduɺo]Z5i?ue7ϓ,٨޻|Τ-7YPV7QVu'?L ;abO[onmm- 7tàkiڛuKu yegUJ_quQ" NLO?}Mqy]g9^,~IiAW'df'uuKmyn}5P4u[cmYAv삲ںtإ;NJUNf{OmMꆨoZ\_Ls榨e՗ȜҢ\w{SS=D(MWnAxެ‚ol|:oN^^";]=3QvyYEyCf$GMns=eMQio&cmDTqg-]s Jˋ턭{Q!(K]Z!0;`G }g %Ts{]$=]]=o=:|:S`@2Nلkk7s^?b`ؒ;S ]u㕕$7W*;֦gt<4uQ2N([}yjLpҪnjS_{u7FK7KSs[߼*Y KaLjZ]mI2BǑVOܾcɘ((.YchZcW8$%յ ٥uu9д}g+˻aR䬦]k*{v]c&76{ՖAT|}4Ч!V%}V N;bnC`꒥]MR >{ qt nUQQԽe57,1O8䯾6šlS}Cc_,1Fc]]u]^|L϶ϸ> -uݿ,\-'T\TscvQT//)+FBgTRZGr}kn3¯*,yKڗ4L-:=^gr!uYBppk+APPX` }&7# }iŅ= !N;bn }8OunkE>L-uU5>4W/w޾iZZe/leM趧΋O뾲^faUu̙:[]8 W[1PSÃٽ̜Կ;w=HAN9bz !0~m`-^M\ |sk?rQ&'//e9Uݎl(H- \U[$P[S7//'v{5M;[[w[7+_㍃s V6F7{{uiUS0u%Q3 b7RS-,s^. jSD";!AN9bf }!#1r[jz ZjT=/0J^ԟ’积/hƔhӝ%_b)Q3i^X-}ܾaiͩBsJ ໽2/###𗛝3tiM]-`gMIvX`uSɗ|k%zX* %sʊs7~9g;6_-إ}'? 겲&6; G`!Ϟ?F)0C4zaoRSZZtgK b@_v^TV6- e_w KO+iHg;[j* g&ڐ{#oiU7l,/.ș=NSYTU#{tP]s[.|7noMF 7WN|useu_~el(9wM2bF 12>{ HթnOJa O]'ͯZ:n8eΚ63/w6T]|~4gkS_/M̸bK?5毭*You*g]8Ki>.so~.y"$ѵ+EYo*N68y:чiv;>nc[mX]"q¥f-ߜ ҟʲOKRK]yi?kųn.m;w]yiw9u=G<IDAT Ԁ"o<[kJ+NLv]]}-{Ʃ[WQ! Tqpcο'Y=[S:!TUs:1G@0OA >;mɧHW;;{S/YWWQv}dIm[&eM3k7=#Ǚ(mzޛ̙5 YYYZpMʵfeV6ؼeM:)+ݼ# NvX.3;J&&v}̩ݻK:ͤs.e M z;Ǥɶt?[,_uG]h(2x6-ϝnJMޝ{܏;wrdĶN}WSS10bOvcC{34)r h샧H | .nuKgエ[ cL],'6k*o,; `@ = MDF(gh˥'dDKM/ 0O3gcڰ=6/k L;"s{g0֒qpM|4 5r7EqE+hߒ}ui2ڗ}ƻjysUzTvi] MMXTj VZŒV>,4-]ܩvK7n[عqw4)]w떆?ͱxD~0L p`e/XqckSzT;kq@nU"ڵũHsV>_2U?=ZYtں ɣ*¸ucU]3ژn̪]…6F how%нMȭl.XjgGK.+jMU&7U_E6 08YxW@ D ջ\ֆsW FMWtSzWs+lHΨ ŒNyf]:M+LUŵ+X2&+r+WQe:ًӻfT75#Զ7x|.C &/sc"_ˇGu# zٕkl.f*k_4VgW>3aS౻(L/Fj+ʿ|Ey0_m[cj P6^s[X49hZwY:[5oqS0ya{*ִx^z] ]\{ٟ/ v׾/ZH3uHFnnꝽEf^+z\J1(;h_3}y~3izqQ;0[msM}Wrڎ-(*#=Emތ0\^4&,}5aqnCȭtJnetɥ++̝аrW*_vSQޢC:X 27l j^ oL_5ovdT;/xW0/9/Iwwm FY6lS`$/9}3խWXt/i@p] z녺5˱u@|m7n9.5UnWk-`H'\i`+( 80ϏLX^JFkkk;^yi{0vDfXt_wz  q0_l ޘq 8@H $?ā@q 8@H $?ā@qc9?ā@q 8@H $?ā@q 8@H $?ā@q 8@H $?RS]Rs`*222*TW4 HqM(3䯱"1ܧnA|ځk* yq3D@Ccuߕ510/'1=*LK["ojT `l{23' Μo3`KL W Z[FA/;=.;;;ڐ޶l()HdLT6u̎k.P\PSQ<=5;tىM=j7UMtԊ; E۳*Zpzv{KnJ]YNtKKO 3ӂ{TC;ueʒ/Yɻvza  }/9}ԕrKoo[39$j̽tcmw5?ҹ'dnw5o fsH+qiC Jmhrkj;/ǚ[֔~=ЏaO^pŷttz)nCCE];/8ǂ:kA$AvNVߜQ0/9/'oVΰ \nЎ6dVrןVP 󲋪=[O8rҜ> N^Q,sg]>gRrۖόvo;[;]eWs|]r5K9y_L֜m~!u)UoiUcЇaVhRI_m; qK}C K˺,";1}7gffI$IDAT]1㐌0^XR^Y]ې]Zu9j0_89pGKj[[*XWZNsjqao7]P\Suϴ^(()IEOL./>&G`nj=mT[YR85>2~%U'=^gr!W&JTmzDhٽ03''s_DQ;* 9[ҼcF>q2 [`Izƹ9%5,m$Dںނ-B^"{{9:UB"z%݄h9hGUa0-UE\|_2:k[_H_b n`r?Ĝ²յ -]>ۖ/ڵ֥UMITXҒ+FԔޓ,LlilZL/)I-FWR2{qT&,XXSVV7133wXu80;kJ322 V{Md' V5ŜM-&*_J㶯(m⣝ 59s$gM_ &(T[Qs&-j{ aT4TL `sRK7"}87mcȭW + zNaYeE90H#g,5UO?wMsYWeX?s $?ā@q 8@H $?ā@q 8@H $?>W^2>)zcā@q 8@H $?ā@q 8@H $?ā`'w` m<=goyyfq'm1W^n=JS0;? 8oN `L9IЛ1W_b?! _o۱cYgG>ffN;q 'L=> s=}?]kwm9]C9$?KDO?SO}{<^sw322$З1ww[{ݳN0o;ğ~&û^ Ҝ^{/9w]X1czAo<ar{>8͜?XJ~'N[nA۫Ənm(`w_0Co~맚{_yyiygg@*(|dfG7SN9?Nb³>_}Wz-, RW__w~SS+ZZŸl#fsLfQ1 X4lnn }@gggM|\_O?`̚S47?0fe㕗aGdF_l!۞TNΔ7I/ʯ8~ K>}ĉ^عs[ |/1:.n߮]&L^~۷R!_+`@_j{o[n}z3CxU~/oc˓ <~ո .~ zlp /~^z饅pOvXb/_Q_n޼n]M݃=Sa;z'xbެwϝ[xJ"쵯^e}o0 O !رn<`} > -oO:iǎKVyo[aZӰeKû^W~_5a„#1u?EX~p@m3z@޽}0#Gytno?iĻ/ AޯڛOoXaCX O7ۻvc=zҒN7غ1`X+Fw`|G39O=Ŀ<ÃRKO<][]_?ܢss?]tђƎ܌`H}۷%;-oy x;![F{_yEyl3}>x: `<見J//` ßs>swvn̢L1cOMc#knnZ&*0[%9SsQmZOQO=n#Uk>rƠ1tI'jcObշG.igg=CPTyF?S [[[ƚ1]Q_^M|\06\w .^}՟QS}*Ƚ8/7C/}2*lTsf[(>7,~^{-`߈_FuAkyU!]zžO3gcڰ=6/ߴ3v⯎U"99S'z<%J>IYd\H }1`:ȮCt|A*Sø@m]NGu J_o'5gGvQFnt>}WǟCI jkS;uWzHc=goyyfq'm*=wO~?IuŸvHF@{䠃Q2f|q{,RU}87^&.~`ƍOQՋK]uJD<8V^rV꧷G X[!٬[֍Xkc~1vQ۪z m.~m'g&V6vQ5**kt4xeѨroXũ9909~ 'LCfwUQr]cOvW/s̬&a)ŢڬҶ|er-MWk+Y1PSC( BUUyW]xW4£ jaV?7ҶbrUBp{F9tDkJ,h ܢ7\JP(5:58'677VUw~[9C/-o~s0R<`,'G"'?9"D/?M BuyUEp9C}Zz*/pcW7N^wQ XH:umIr7&k׾:'mK]uWuӊ0({qzWr>٫ f%WloWl>ʈ:kOűo9{ګJdL#;D/`KgfUQG.l mn:wUS]Vyڛ ] W0.ٌUTe?eXԨdzNok7.)j 6cOVmn\Ji $u#ɕ-\\q߰_]˟+8}~FpN/ؾ~]{n(H/s![)97'ųk%jKgUgTVnJ?Y6ªTW{FUE]M-m׾f]r)`o+ENKj+ʿ|Ey0$ >7ވ>~}le_?旿 F~TTF\x` +셑֫IE+r+/jF۸7/^?aFT2un+"v=a' oKչWUkڥߖ^1&ǟ7Ҳ=SO:C:$| }c0&|=܏t֮ݵkΝ;qWv;z%O'i1}\1ztNI9CA9H%Ժ'$I=WE`m)0*XL^my.z?7_}_ 0]h(ӇM<|?T\3))5Mr)Ugk9SkxM^~ao}S|gF2lgRdeBfF8_Xqӹ''9}-JyWM cp&Fg*ۧ&o4,o}K_'e<9c^?;Ӣ-= > |1|ꓟXM{gG3v=BrGiyy}~~=@pʆ e?&_5%2}nGڙ2+eᶍ3[4;7Ƹ;- ]Xv9%3Zs:Z(jjtiɕTNhX58{ޢCOMdI*+3/q7Fs楖kZ;/xW-ꖟ{w׶`teC@^O_p]G}Ϻ|IѮL owr!h樜;hm/:CRe Zߐ7{Qnں0lP%%p4 iI{HVGiMqW[\|_Z۬0׬ ]/(=\5ma@2WwURSR$ʶ3;ﺼʛn9û^,7^{ۉ'._[{!MFG(0:InƲ]{-6<\VﳩA.\8\us^/ԭI]۷sV[6F啕7uzʔ3fLߴ>,r-~;*SӜ~,E86.qCGkH Bݚ4W pO^w-eDZewllmr+7Y0蜏MMM.jr_v@ILZx]?;>#w1o{|>G~1_u>?0ηW^zgT>u٧.Zr a玝+iwo믿~̜+NK)fwM3v}#m$VsssT˛W+o,'__tTOw]Θy05=QĦn4,o_?FY ȝk P`+ʇwo ZnFnaQOН?O~W^ ?ß`?۾Y_Y_Q^Ռ:7xk7)8ijKf] Ϗ>, v/7?rޗG,2:9#o~kZO?{蜏,钖ay'} ?S [[[TWq7%_|Io|켏qFXc|F^{>7 >x ˢrW 8< J.3 ;I}{Պ?<,4559|e׮]=p7X}*`Hfo?2n 8`رˋ1Ncfo\cʸbo}ʛ+'[[[w~s 8[ӏ vy晇{]gn 񟴵Ma0\T7ꤩTBYL"Jͭa5(HpSRlQpR6[ 6UYÃ6QXSC[ {47M&/r={ιߒIDATONw=[Ɲn򋻃qe /,qoxC=]z^]~Y0\a,! Tz9EXu13 7~4 @o'>=ƛ7w_u~h~[߼q oxJ.|ՏD~~?/?o|=pG/"3a:{¯|~d >WwB"I&ǮhOtsYg0gŏoS|F]P^׼+OO9h0c}fGӛ &0N]QwoLXIB \0iҤiӦΟL _K\g1r1DŽWg͘`bs;5mZPx0Q>/=,W_=jg~_>s:1A $ߞ{}uf^_IݱhUf6'L?ā@q 8@H $?ā@q 8@H $Y0q 8@H $?ā@q 8@H $?ā@q 8@H $?ā@q 8@L +H]iV.`z\IPUZCaU V%zΞ(;]T~es04V=z9 >g^~Al'fl޶Ҽ%v~%\K* f/斶 H?/K ?/`XH}LKNd>޺d7c]{v_hѕwT$͹a۞]V_h-v՗%|i99KqM{8` KttK$XWn_+|eIeTW 6T%{WVVהu!/ eʲDsʪ[{ǵԖ 9vyV/nl7wKMIaR#(z>QRkM5 \\`Yf8 zzLde,n*+*|YuS +]+kWl@Yx K 9>L47n23>VNdltlHCx붶vοuKf&}'Lϯ(Ji^U==z}'ZZ s\{v(yeu{ Údw="+7%–҂ֵ24>TY8{Ќ/2;kK{[W(MV[jO`pY׽cĂ{mX U+WGQ1fG)i޶EL|fƬ \5gNw0_ѸKt :-wβ+/|8-&ږ=6,YްcOSدwFw7wh>W5ٶ~͝h镫۞a0aזg^+n۝K]0y J~=paPל_ioH:;-^3{`s-PuK"{pq>?ā@q 8@H $?,KIDATā@q 8@H $?/qB?ā@q 8@H $?ā@q 8@H $?OnO>;w |ٿ|꩓NrÛ6E{ZVVVd¡06>;b b?O+.Y8EO>d8=sf'xwmC_;w~qox /kmdeeۻwO'Oݮ`XJcxPl~|˔ɓ ̛N8! 'I?ϦgO;hQh^ r(iσz饗zx~_x;ǷLxJW^ '~& ֊{[h?g_DKw_|ݿ [|O~M-{|pȾnO>;w `SOts朶w{NѸbҸUIu֬S4n Rw; ,>ݿ&^LHNy?5ַ5|E N `A_]|F݋/F+Xy}^L~oߞ={{IO<嶶X]yC=|ߝ}D4F_hb޽Ėޞ_1G>'xwm_/TFɊ sa=ҋ7E\?XH$؞{K>rÛ6E{ZVVVҸ4Ơ8CP#3!2ܻ)xu}Gw=F Ҹ`Tŧ3>M|҉A ~_s4I& 8pً|pz̼?6yqӸStTP#s & sLegguZW5SN wh~4`pWWa={_ ~g*^|^4u@ZWpPW)AMq_1 8}w8ɈC ˆ47n|'yٝ;wśNVEzeo|+(zw͛[P0iҤݿ^C+\[ۃ#-+?C9k\Ph\8p6CPQF>ܠpuDnnn}`X.70EZSS;`XJ2سgcG9/YN|yya/ybۋWWCswOdN㊉F #۸lN8á% ~Fa3JQZdR0Nl}R"[3M<C. |gg> [ 5;2DOG]uCԸӸ aD8ƈw#j 3wn'І8T_Oypq'9a~|i{ܳ 2qCq08Èp(#kmmY.} Fbw&5>õ?GӳO՟ ƆSMs{2YZ 2q08Èp( ;p_UY[pz֩{2zk:=N< U@hCݽկ‰inXwäIcUM}]8cG/qҸ aD8ƈq]oM_ F譙!rQἬ«6悬yN^I'O^=W߿?^0/8]ـb/;¬ym 6OMķ%3g\ޅtW9BӸJGj,Ѹ5Wih\աpgqB& DfhؤàtG=]o+#a֜<+Ո._,3>Xyݛ,2Y4z566FXϛ_{y?5?xuAtjKg9qæq5Лh\9k{6 p8 tx=iSC#ojP}*xЌޚ{im  K6mnM۷]tKufx0ܹSN Ơr`>.}fX75 qpJ^ഃyo+b;ß`w7W O (/8<d6F*ѡq5h\qFWɊ͐iؤa3:4l 44l҈se 4/O~gz ܘu]Wln³_Th[sg;>|3ɧ\TxYmrU-"U׶[nZ w?6+z)yǿ>oU5DM-*?cUSJnoX?g ﻩs~kUuϟ~ڔյ'JڢzdW~KpeVwikkRRÊ h=?~DM.wlIEE[ѯ25oS'x9-<]Ͳ_~x_GP:vzmoZLvηRtצfZ7K. йtm]\1IޕxUړ˃hmϰSjZk"ޱuSr;PLpJ,5-A߆gvJ`>-t=whKF8r|ޔ482)qoLOU~Vv'?= 0{n=\:/}?M%NuW@=IDATGm7ٷwYt++WWWW=HW3fؽ{#|6ְѰUA]FFFæ ~P s>CT]]}ׂ#(o.?)oޜHWEU]%ۥD@ &oYOͷLIŚ=<][l|qg'Ku{QhK[[Ϗ v{U'QyWj, j]:/=cC6_ֱHUϗܾcUSz"ɍ|DzWW׆ϷI-Uj@5|'T͙o*YWk(qE'—A=<\|bRhޥw|wKI--׎o}_] pQG7o\u~6v%dz=k;V3?0]z}@=t-xͩ!^6zۋ㨏 l3ɓIcEsߦ}cv/m{Wu=6HVWmF' vY}ny8Sn@{I)^v!2*ěn5v/q8xJL}^)q][9% ~dzJή2۟ܝR3  yE:+xzҳ o/4-{Zpi\i\k\ ++NWq5zXFæ]fdhhhtҰqh@Shnn>1h6&C7=ֳwwgё9/c{5%ckͻ.sow{ήO)&#k.H-UYzI%]} ZaU'ϫpRy\z}ɚ˒'3֜\f7Ÿ>M2o<1]{ZGi{<pso61/Tɠf. VAOz _;؛x`F.wmeDy]5g_٠ Ek3OU:Wpi0-iQo)vχ ]|-xWnM4*l^5OoX=%drJr>7Hz;%f#o{_B uy6sm.7+>ۮq5DWWWWiLUp}hhv !ҰѰѰѰIc6l^#/ u4lC4Hǚï˓R-O 6\ho Pj~m jx֯Kr QW6aꫯ>IO<嶶X]yC=|ߝ>}zϙ:_R3"c VkS0p)oG-=MOJ;z2[2tlt\Jydž}<@ӻ+*B{JpW8@~ !pJ mٳg}ǣ993O;3gΜuZ߮]3?Sd%O}>ax'<{]p~)Ḳ-MDnnb{04zѸҸҸʌƕƕUJ|Wo}[3yx׻3326666iaӋM66d\5<,;ijb|F֜6/7}GͽcwTB( $sMI"T= aZ׳coE\|ud%7pM6?[:7E_)S%+>w<Й DG]nzۅɁQ%gP=0i|_}( 09R>0;Qu}rJ%YsrQ25宅%ݻ߽OJE_?q)lyrxa՝O>>VO*}o0h6ZvIW.<+>G>wW/^|oe7`܆Rz/}rVr0C}KGڗHcUqq54ѸʬWW0xjBe3 clahh،( t4l2+0Uѓ5w2Ġr<|̦we;yv>t뾠<=']6}հrie!qE%w9}nIf;m|c>sU}_ꮮ5ƤkiISEݥM\{+XEַ`+:e}}{uOL{~wX*|KJK뮤C< _{+?}˭FJyJnULM{>v>[ѱu|Vt*,:UԠ{=\HOZ}?ہwΞi>|Rou.{;+ĆZI}8rJF8ʧĞ_F}w3>% =Spwk_E+/Y Yeo\I:c/*⓫?dyXqhɁ@g~sh/#%e_2QWWWWWWJqտϙ]}"6NѰ4aahhhؤ[MUF'Ʒ?@02lÍ}A{O@kRm}UsB8EO>d8=sf\#-}埭bYzqLXh\9FC Ѩr jR[w5588y٬^cʟ5xqt+0^mjZ|z>}y75ة-33Y N955 /atqwpbKcc0@OdD=yS Fr,k])Sc32te^/}/Y 10F_4Q]/,Wn]4}+`ˍ+gc%`WӾ򋻃qg&N>gmkj uV=wgeesKMSO}Gq;9ф?_qLcql #¡L#ҰU~Oɓ'MƇԊUZ5B_{%W1W0"J1 ~?M[UU |K?~5n.rAaa0j4x/+gc% K&>}+ry{6_3ówΝ;u`yxӦG԰uL8p h{ᷯ{h\3⍫TyqNEB }"gc% ~FѨ/_ >qc0->jQG ̷o~pwӸbW[>qN/ГCj43g7 OjW ^xqηq ?>x'Ai\16"O<M$q67RWFU|g{. bҤI+~/\y֙g ~K_'/hp-&xB?#ظJN;l 5WFU|FQFʆyi8qㆇssGb:-y|O.O?1gv~~8 /Uهs+q(uIFɓWhzC}jtէV1 {~gٰ! R=ܸ1SVO2U{^{`bOwGGoۣN Ɔ:joU˿ C[So׽>qߛNHDϻ1&M]|ʳ<3``aw…_?:x@OYi_x;wGf0'`i~SNHhL(7656կ;淿 ַӟojg޵wK/N?:xqݿ۵kד?iw=^+2eJ03{|K}̼9wlf3f6lf3f6h)}6uolm5{UVH ߿f WV׮,6Ր5.{j}ko)n*+^-C#굕Q-Tºl-9giMSߊ WܷƇ m=>ΊRSw8 Uu9])YY'~5Lq:A a88_p]i],W&c[.;O ۃ!lCKdaeIڬ+o,xTYX}}7+K,cwni/ɟ{A 7Vu>YyսiAkX8kW{Ks]eUAg f߹3Vh`˞{ᝍanֹ>{K?jdx\jpy͕3ozr)W^nrʾhmC}O)]`{o>0;{{ϲtC{Mu[)Y"? k>-a2ؾc0iWR]tBS߶'9Þ]/;%T뽗T* Kǝ_KBUw ‹+6jߵvqJܐ7xj"#8h;|NQeS {wmX:q^A^X 2V_l깅Aٹ sg{{V̧dnH>{ui)B9oض+5{(kJ_5M+Sь oٲc]6Xv} 4?*)nٻZZ8詽gE_9m[{d,)9RfR9aixF~~2Y)TnW⼒Uc۶3dvA)}1ҺD=?JYnGuyʦ&IH[S~SVli.OE9%Ս)u+_)o-SRY(eyQ˹+W9L֯L`8VvtS[|gs}EQ"*{#ٺgS\RaʊQo0QI6EuҊfƢ[D%_Y}e,*/Iʼ[ZpdF~qA^Nܦlذ,\onqQ77?WX='xU]dh5p,Һd/Y7lk.+Hu%M :?U+Sy]TrdWw|eI~9a}k/l./,pޛgqT[*NKeO֊F,k+51cE&S[+fT՝$[* {);Oxx*+ d-ե}V_Q"+x`UMsIDATSGYwxs4r⠙O\5?[W c-w0&խ, ڳswYىD~QiEeM]ޢdG~$~l[;=y߻DAqʪDyC{{{Cy^0uK)iٱaEf}֛CLS [S]TV&9yy{?HHi{̈/#EׂSVlkDSE^0v޹gYn\RX:p/֚t`}]mwaa^V{NA٪Ɩ{vܹcˆ[V,踶u~w+ojkvύU5-pFP6.m1pwamu ;<}9E[fҠ6NOޛg34ciRy$ˢK+q,tWyGl,e>3nصk}4|uK~MӪ[Sg ڛ YM& W5m2kQ{E-=O筺imtaU+?`ћ*ˢq*UnxouDsVo۳hḼbmD(++ 2ޛg @ )K#T_UQouŠ`o[KS}MeEqANrQPK7jeiQ^vXª%zt[NIMv(nFko-˛}h-eèdzsIʮSe[59{-M 'GTW\݌aU^^=,z~YmGi4VUê˒3~+WoW]]loK}eQEe5ffdd,0eaueyKhMbZboSUqdMO]o\?̙t}cMI|nR8wɺ.j+/XrӃ1Mmmue"UƚdAJFZ-kx7dR-˲M%9]+g.cz[2xPXp`ez.Im +HR_[޹7ZuT_ Ր뱩`#xms]Yp=eڜe9X5κʢj.0Խ75gRS|[|κҮ#t@KMIwa`}wrѬȝh镫oٹ;/oy-ʝֵ9eC8sXS\ռg~vFnw޿mO7aN"J&mV/m]Ʀoxdfd^1 6>^SVh x:-^S)0I x?qU~V(9ghYUAKmi"SC}--H =%wfȴ*⡩`#2Y$wن`Zee8>`b@q 8@H $?ā@q 8@H $?_@0q 8@H $?ā@q 8@H $?ā@q 8Oѯ &O_3W `8oXM2 ۏƍ  3zsf{os nn`X`/:~_  q 8@H &5'ϛw`rQiWm ƍ1o0C悬qv@oUThs.( +hD;>a˚wg4>ax$wee9.;s#m^1X r~`jhZ\w`MvERrm-p*O :{*# m?,{jmJW˗ݾy30}~}0^={7؈/_ճɉ)%ܴpnyUA~\pO0Nϟ4)̮ZSi( >r.p]jr*Q3AIFV>dm\5/ZtMϽ_ /l^VްyUF0=ý.L/%Nw͔TE/-j]evRyyP׉7}M*C:H+ -*K%+;$'G~>4 Ÿ`XeYƯo},E 7w^Oi/O-a7/Gg~ns/L&6ܴ~?.퇥j€$ N0b75yh+ɤgw҉OowKJ9]'Sznua}Y}nNnUASx V5]9RqEÌRGA<7(ST-?) car}Tk9?mqݵH^ڽv|;]|{QkUԋgn/K[wg/Qv>cAxQw{ބߥQ =JڂTpM0޴Gy;(F$[l]}.pw&Sb Q*_,p27V](#mhMKsR4DI.de׮ JjZR\ŒK޳[apg-W]ңTso_(Ghrt°dsG08m_o s#![R I}TW7VJ5&d##૏u ڳ`rڡI%_KA]H3ڑ #+ynˠ>}\2?wv6(@ż_:QTz=K7A཯(կn gWm;>nt^7oN5Q+_Rd 9Wmr5\lwipipRUճU|Ҩ]+d0hBX+a~0U}[:7}a:Dv…96Ub =z/;c~}N01)gFO%FQÌ q0~q 8@H $?ā@q 8@H $?ā@q>?ā@q 8@H $?ā@q 8@H $?ā@q 8@H $?I5UfeeV5 ^[]Y"++QV7ؿ`RGEeЗJɯlqo_Һ sm %ɋ%5-e6t]i(^lz$Hems0F`YѬC6זd jLCAzGu}0D;PeC[0b|Z5nl̮|bhD Lm[Y8v揄Ao͜_ZYDA~^0p=ϼ莭`{u};gX@(V>d1>N' 숯|& Fə"ɞUaȲ{['f-[_Y+]uWϋ3=H7#[,cpv0;{ۣǹWWLj}UVMM>rs2x//U;^^ES{JSE^{$)Dbs5TzVu,T]ҹpv~YMӞu._pl/w!/(e[FcYƔv0;(Lv쑝nRWQ3kSjhٵi( 'f,1>N' l|os]eYQ~NX9EeU-=jROw_UX]Q^qzeqAʺc +Y={[R{k*+u':KZ{oɆg.*/[>v,AaYWҖYW.]%+:!tmjjյ+ 2A1azV-b]wXiW%u+ +z]>㿦卿F֕x^n!e .av$X34eז0ꕆAsUa~kŌ3R[3,;ڽ;8+ۯ>g%7?u_7_2ؼ>'xKnwk[-_2;ԕ%z\ +j,}oY`_j3F>԰,xQvvK. n<焂4Tm/ƭAHm1L`2HD^23F*dݳj ="yū}3D^ܼcfD뱾`HZoS1k@*;arӮ0;PxgSPVݧmw\[Ⱦ`(=RYۜ,>N;ӭ<3HME n|$hņm{ZٵmÕ/>rア(*XrZ`[.L[s脋j=m뗝{/),ji&[[{ϮK#n]c¢.Zzö]ٶɕQz]C -L}h7zG{o-iJM=e-;{WK]wmivo^6*}S҅t<)uILn)YtRgl[ߧʺϣd%.Y#ZEeheEAeԧ:Lve& nj,4w}&6+?mHk6$/z3X5=3HDik{~9ŕ V'S0*I;)+4wv N6mXvQZEn{k/y9%ՍѼu+-)o-SRY(+ˋ:_/\Zw]Csp)[.o ۚ e]IN3nH~J(Zu]*|wtw^aa~G䧴~u2_R辏0d$yE3EE^۸`*z[&_iӮ :/{㒙 3 g1}HZ3)80.V[8ᜮ/]! k+ꚷl㒹j+k;koCy^8@?iŌ3RCee*Q_YYϯ%Am_UwiWSUwߺfor˪jq\Y $<7Uw,QVKea0{ nol Mvyʾð^}*k糮[Uܫ;>ͽגH%֫NO)1QP\)Q,]2Iʶðel[/Y> $q;2+6h)$/4xerJjZzt ZXrfoir|ق٩Rf-[eWʂCit`TĪ#`Jӭ0QT:׶7y(%vAC2sk:n=m ގ^WloK}UYQ~"-5:^ ƺhSKJ~[W Su5Q/ɔݭ[+.:gӳ *- `|(L^^Ws:F쮶ih'g&0_޺D֐$[W{G^u [Y2a(ƗqGe+N eV5٠8q3RvwK䦿`"'zp}oSUQs}S\Ӳcefʾ7/ysE`F,KIqon(?k#C[[[냉&%v;F8=ƗM=Ɨm|dߐV`b:h5N c댔¹!P}dy_iI7f}]m4rx)6ذMy0Ք̾dOص'Z۞];wܲ88 3hC}E{)Av^qEu}S[;eowi /-V,[ݭV[2̧͉:Lk .r//+ &dEy5ًq!nemgڞ{am=b!p`b5N cT\]pWyY#S#rθOXZ7jZU~k*_T<4Q\hyYsT-\WQ񍘝̕3ðVpvK*nLLqQEi^0,{ʒ=E;ܸIDATӽp#E Mk_kPFSX^ԫՍKRVv^Ku9v%:m6x=fWIKUD0lhՋ򒹙/ZRR.wڴiU^y!_{ %j8hUmq-woSʢ%=f,Yv[.YT[7w՜meU#T_SYQ\;_bxU&yZ: X[YtL`a)۫6__UQL 0JS^mjɡ-XVsVW -M ɣKʪۺJX]q]%YC2j_Jj=GKM5Ws Q`G2Eg[?˪ǰ+6b;8U-Kn;77Ys6Tj/ٳ@=RM+RJ=m^Q-lk곥$ ;6,U=GqܙvzfnLin򗒝(JZ:y5’KyG,+Lz$SL Kaٲܮa)WKG5ɀi϶ vƬEV'߲߬Ez.peSz.;e,1o;glزsO0…T!ft>3#\[vA.nޱ-r4-Îr W5٫DӒJUKytcNTC[se~¬;w)8Ҩ 5dl:j._S`; }?HS)rYYQٿb ָ*??-M+SG qā>?ā@q 8@H $?ā@q 8@H $?ā`w#cf@q 8@H $?ā@q 8@H $?ā@q0og7>ē<Ν;c9oz[g,YR<;??(= /;~裗}O=C3yõL6-8:fFq+?|喪  ֯V3ߞ={{ozӂg̜g%[: M>}O߲归?Ӏ35asY/ƾ_կ_`kp0&MZP8?@NLSf<9?:=裏ƪ?;o>|W skt3g hCq:‰M'P=|ɟ4my[:?|?x[c^~yNYNN>\[p'xgݹsg@s1o~ӛַ?cɒ(ж-1mڴo +@&Ӿ򋻃1D/-M?~>Z˧ H&O7_YѶ-C=S&Oz a~B< >wêpW+w13`g6[C+Xy}ر\|F/;-`Xٳ>ÜW~㧝3g:-㩭m϶ uu3ᅹιc\Tra0\ږ%GuhooвK.͜`ޱ6HZx .ße5+?"k>zI'~;i[NLږq}wFXyDsG>78p Ȝ%ږg9;U z˿Eӿ|]!mK"ږ/TF?dB򗴡_WDvvW׮4IL\ho2mImK3!={_ >&liܹsg mKzҶpgգ_0}ꕟz6}={ӏoN27 ` xwmabigmxӶ 0-S]S{  }Z[[g+`›4i҂tkoLh[ғ%οIFz< Ļ N?> i[҇%pM4_0ɝ$wxDF>ܠ{Fغh"777 Kt]6o?nn`X7E?O?|}4yYGR aI-J&#޶DSS;`X|O/=7!w`|O2zSt8 h[踆HrI'F?H ㏏&x`ȴ-O8̜vȈbf%53~uݕ駟y饗Ѷ?mK0; x A{ bf|$5E}53%) %ii[مY)A߁vӳN=s[31POD7} z(%ж2w~̝'ᅿ*p{{{=q2>M|YYYigƷ`ȆfF͚ ;yM0&}O³ '#-#O{^0/,]ـb/{¬ym 8DUbE]5fMIDATwx:y=yMӶ<Ҵ- mQme:'O^0Ԋp3|OSi1GO[o=zsE?H9**5s1DKKEuo߾` ek`є!:ޮqXP#e^-WM7?i[2ږiDF ~?M[UU | T7=x47my9羧igC3zkզ͛47~޽QՉFR( JC+M!l/J ]QVtQ)+>+UI]ah%,mm jUM$-T{h^M/CΝ9sfܹ3sNeՅs|{kvN GDlKZͭޣ(us€d`|A F_EAA0}vvku}gH5?#Pu~\UXy٭>z|h¾gso9ʸ{^NLx:+y]\q}_FNe(: )P\ȣr0wƌO=TE*.~hc?'[re]Zْ(|zXt*ѴbΜ5zX7T,;oce"-zށ_v 蜿}b1/K%8:o&W}kQuekՑBr;\:ێL6En=W^gM:c=餓枾ph w5߽}^ >SNu.;VtѨ:*nYΜh^.u|j5t-cmo\0!6]Mvl7 8rz?ȏ0|wV;}:=,oA|uw._hWK1!̫kۣZKj27>tzڦ˷ǎw9#u?-t~sB@~L$iߣA+kMfx@T袏:ZfKX^ AC]>?l@'~}NtzBV[I? vH>ʜ9}|%3}Q7wҽ`ʽ{ro9mڴݻw5eg7O\q{„ woxMoÆ=`Nu::56_20jqƊԯZ}ͭWr^)Ϫ6quΊ~ןךu5AA7 INH_ZKEاہF5*Z$+R[u]XLKAfjOaEHeQkcڌe7 g#}\V3,Բ6pҳR;&.S2󎤫'V@"/BΝwߊ]9wޙvEϾ,s~;/i}TOG3+V<:ZVVDeǧH2Dtgt*omZ>6ھVDZ 1>ч/n@0[xK0\ߧZ~?}זD^]OHUuWmB}Gk NnY]^Y"T7] P_5Zu4D_T%߸&ӥIӊucgksBtw@|6h7Uf`^PuB4D9s~ܟggd ]JpfsA?sfh{TcGRĊ=m9~vv۪uFY[΁U!ӿXO}*{٤^Ɇ.>ҽ`to޲S5{8b~c ~3?۱#<|ҷtE2eU׿F`NNNupȲ~ #Hb/TAy옺ֱ[S?iSaKk\0gE岧{FeJ.K]:(UjiϪK?%\K}TiuJ]wo9֫kU7 YtV{Aa טTdk}SO}gY'ߩmۿouwcn٘]O{E?T{ Swccq7Ht1` Sx3~ DkkRjj?̢n=3R~;_ :ehTXµh {kYi ߒlWŅQ E^cj^)|֤~UwVe_v4r*qs*;k3t;#Ϛ{<'+^۶6ZJJǪi;AnT?>3?'Sg'^d[Ү_/F~u,3Ǥa g ʶ`?{'ю~>=vmo>Zso[toy[>W~y[&N>}ܸq?ZzwW!&)שprr:|O#/>sb{^WnH}˃5͙m=u9-DNWkT\5]J\sؑⶫcMz|[;L{M{Hywkji?ܻ6_wJ.y֬SM7~%חXc0QQSTӟ= YVoڠkmz`|G.._:Ȼ 4Z`I]C8{ːo- Qg/wcZ瑱R;G}֣!Nza7\ksyomn+>w'x̓OײEpDt~ |a!vaYTWw[_Pd[l;?C {G݈ߵ<ͽ{>to{˓_oc=D9]zii u4)ש>NN@ P5&K/KuQ-[jz[^&{~H?+g.H\‡: V4vСI.5=SJ7Ȯu֫I&k, sg̛#;7)-Zx~859[L~᧙"Bd>te{G k?8Np0`iIc NUE[nm[vFx(pJ O%Alȭ]׷;xMr Ӵ"s~<.{<'ڒT]X|TO+n^LK.m-?|j0ϲQ|XQOatTs4z/I})RW&5UoqxXFjh>HS&'mϢɎn [{޸{!r.Xpg?#sl?я\p`^׼gw۶l]Mߺu[xNC:N To\z:5dyQ9} `H[lk}n66lr3/Vۇmcv{t/[3{m۶e}$9vtsQA;W=>`Qs;=%}޾Xtnmej~~O wo~0NںGH߻]]~rS";-֝?NU>zqltۋ]նh\m-m`Fۏxࡪ~ߦ'[.IDATzT@8ʎ1Xt[2UyNzYQR֙lA۲39m]u淾??QVoT-{ê/(upGZ#T+:Tp AIl:JrV뭻ܣo?gL2d-[{uoٳxoFY^[n5zkn[/z9g+o%uujP\R\:ճ $LY#w`#$wTH]Ku!? JW?~C4^mmwdc^Vu 0:+o_ap?_mˎE"YHA5Z?wϽe[Ɖ{^ҽ嫯zY0}#mO9Xr\()\z:5g "0vŧEx `|⋣k@l?4i7n}P?kβ[B 0S&LO<^ĕĞpxW}o^:x<⨽j"_F[ڵ+`LJ l!5.ξxAz\p9]z?sof8[78E쨓|, Ma4|55XhS {~qo6Â3n%~܀ڇK%fϞ0zH `ygĻ 瞋fÇ{K![O5g<0ꫯ%+yk!q:|NA HC|~?3Bw q%~@lX /|%Əhro q5{I&E? K7淿 Knhhx;@\ P=o\OW+a;裣c?1]o"1^WiAq@\y-M[3=_?S/G9e?ryQwi#Ð{K[Gaᬟa䃃Zup:q5jS@ŧD"K)J7@,477W[/|8([B,{ 4=ngrX g"лO}*J՛6>pq>RҲ;L~Cmm~Q ׿a߾5 `0[5/=ܳ=3 )Gs{ny rVX8a„r+@ji5"p.Ї_z}{)SCuIoo&~xGbc۷?vY&;{f&k-#O;-Ȧq'.hu _?H@L3`Oomjk7eUssi:%}>gccz' {S 3>ҏ˫Fa'|9:#VtcßW^y% ՏlZNNN#Go08˯?E邙3Zyi?;W_?zO;w}WS/@ּxk.Mm@i7 }ӿ K;c>@7>qy~7Wy!''e,|Gmۻw_>wjabI>vĉ1矿uףǗ~ ^ Y6 ƔW_}O8a_%~c#?۵+J9(AU䷾(y'?.,+κWCkozeqU}ei2cҪఖ03yK64V-> Zͺ^;҂Υ/O̻Siyy/{Uƛv0mɆ38-̻^ͼdn]CEѬ+mAmib;οe[]QuA5>Sh[IDATO u]fڢ rۗxNXxG_k[V<%S|w]Q33W?P}o{ޅwnYh+C8毨) >zfmiK*yL&s’;2yn%'&5i VKoݰ(z~n7>[ٱa$Mϵ>wmz}*o;VU_}yA&7mvE۾󧥦dEC[ނmX4->V~X ?m۴zGkkK]Y~0kyC= ͮ\Nyֳ;K,۹e~-q}ju+3;;j[]Nϥ6%3{ ai޲uW&s;6\}n^3L[KhOXr]] :6=}tȹW}N;npZFV8| FKLNzkcUIA:$8)j[&J{r7<-[RQ9?(KvλjUQn4:婼n aL3sl+O&mO$WʲaJrԻi6ԕ.uUV;W5߲)ڲUWe%p(9`(p/~Òܼɮ[do~QQA"=`ںsܒ6L ץZIμ~GcUDjYWR[磩jϩttp5bʻӉWd*JVY5}kE?w4Tvט(kmm(\RkoM}EEܚ{KnW]n<<۬t,ܭo9 8kT.U}X[=nVWW 'Fh^w1s&%յ&5L7nprjĬ+keeдmďW.* 5Oܷg,Z5:)ԈEE-ς}.-_Cc_E,ZY^0cX_Dˏ7Da`g}C%sT5D-鯹_hqIDIt~[CK\`=QZi^ynⅅa0QR=Vct/:M4KG6j% Jﯭ 8R_]Msͪ~2%MNdᵴQ ʷ==5obUݗRTub'6^2nmya GV[}1bYɨZp;ZP2EE؅wo۫t[" TK `]mMoQQ~0XCYj5mmܮ]OlpΌfm_LjW5FwPS5;RJB7=3vTzY75ԧ&>xij[cK*_EpZrmm/=ҚmVVKTR~rZ[[momi;{wŦtE?߾.ٶ0 z!om%f^b[u/Aj-'1M-E-]"UmՋSR8}zwuaћų.Zw7,Tp[o*mXQp|LsW+/h<1=|/_0G{x-u5eme/O̻KQ=8ߤUObimS͜ǙTPV״[̟7}yyy[6Fk{vSuLӒϽ-ݛ&Ԥn[9~E6so}=74ʘ:-~DAQ^/'ղd'w$hU]j^vfSjˆW6aemL;h(`O`14VR]}v^ybN`նF69AԖ,y0Lz[}yAcXz\/ƴEJ3qnقƴ 0@@@@@@@@@@@@@@@@{MSN F6"""""""""""""""""c)wQ ËϷ1Gt(kv.6g`immuK/O^{VKܺ93'J 94e`@@@`\0lhī r̙6 xUQΜsr\ Θ3'^5q؉/{ٮCzo䯸`zL]sN  fL(=% 03kr=7?4 8ߑGaYmfܰ% u ȪS8{zpߠH 8ƫΪ/KEڦ/)+Ԝ%kg*`9O--ҹʂ(C\5(k'!e55,ӥYkإxMQ}28>l68Zu&.&F %8u\B! =Vam$+Soo-KʆѬ5]lNiHXTjea/ m|]ԬOES5%T5,\_90/=+=ҜjC[ 5 7?H WtlneuyeKeߡVx;4U̩ 5A[zOk}oXZ{û0lV ֫k mkWxEgmƠ8Sl۬ו]VbƂsurt*[ȶV}[޹YahB0TkWÄm-s]͜5k?~ifV#ֺ0nYS9'm d5-='w Tt"iG!׾a#GQ۬T5mtǗtt/(Y9H2yi7=b|acf{LnMGG0woKf_nꜺ׵E\~Uf0a0W|ISɹ`m?+k/t:\˻Vb9s6WKKڻl۪VD 댗^ H U !LS'i kh0|$9.׹_|D ]?}v̚,;oce*hCt t^QĎMJ.q| gU6VN?e6C(94e`4#"Œp88A#7,GKGHIDAT~YlNN3ObF0P|c}k@@|s,3' #" _zaw0yTn-h2e``,EF[-=88888888888888888imm 1N????????????????????????qDNNNQEC wH5V})^/j͖[R=BZ-I FUw-NdGce`U.Ή, ƈG+  Nf}wͶlT_ژ;%*hrAS['\r.ƚG?V616_~(1`@ yݠK= fFYX,VtbY#^:FWCO,Do}O 999diEmCKĖdYt8GIQGss7<^#]:ó5R #Kd%}զZ5?xǕ Ox]4mŧ}>/WJڶ8`[Xt䈗>{k+JDs uMZ5,NtX\P[xVmIY+jIdyնK&uZGGӽz鉒.%7UW/hߐ<'^s>cS1!;t +'1jLuǹbS>o⩋n,^hs0q֭Z.\`K?EO\xܝ{w\~1  \m}]Dစk͗3 WZ㪢I@ r^ڶ+N9+o{smI~imegP1XwHSS:bt].AhM>Ln yk(Һgdž%3;&Nٻ(wXRD~oyS[ӑi_@iHλ_aǞT{۱ኹ0/ɚ(n g='9%2 ~SfU4// w;o>;ٹ⚽V9eq}ju+EA7 !m oc.;ZTԹ𙫟hjAO,maQ02ڐUM] {u{57~]#y \.[iXL/7@|Zjjvv][p>DC%bU+{haDi{wuLQ~SSo_Y)ɹw6֕'](jy(o,߲)Z`yak~YI[3 5U/() J++Rkexګtt`݊66G E̞[ --){_ /JN 'g(_}ق[ο~}s> J%yoA_U6|*@+*+[QQ=XP^{KUz,9Źx \nVxy>!zpUucЇ%a=ՕBܹ!8H^VwuRfg56vz~M䜜0,>kAʚDY}/L/ô8 Vf~W//VU7HQR+WޝNP^)kKw9s*:,I7@kk6^HCOn۶7,>3zݣCa b}f._Yr{*K܎'% @^1bq}&OU~Ї4ƂAE&F-KErK*kɱquG^jeA05@BK>cn~~ރPLswD-pR_% ͺ%'$RCM&_x~T/L]eV]Ornpp cR򪺆h/wxKghM"bU+GA[PwwYi#[jO%}gl%ZjM/PZڟi}ƪU鍛dCcmy2?79pRnZdomi"'''Y w"Q\\^Up{ljJ[<nWOj^`AE]S>P9Qev?ſshGq_?_Xtq3;nO$k?={'g0IIDATٳO ߸`Lַl}? c}7}}tW_}5W^y;g׿Ӆ7nE.^D6K GaI&}ۅ|⋣k3>;(qy /_67/ҋ/O39ÛT/2,̽f&LSoygغuۮ]9`Ro۶mQOH[#m|ǻ̞2yr0To&OgϞ0[a,u%O$fFO~}G~v jܸqFÐ댗^2G%^|e<~_x^;-/߾){_t0#ao՟LmTsKmb߾}8Mr7x#J}m޿m!4iR?ӿ?~ǓO=@7/%ǦG UK߹;dٔɓK.|ĉO8 /Lqo:)S<(JhhA\3 O}GmG0 />(}埿f|jG)ab>gܸG;4s,Y|"ϵd3o}[8XL|ڬYG?bް &Gן?w8v%uT9 ꈶ6Jc?Y|V0|#r/5}cQ"// --ԩS)gslNΜ  ݶ`x..[yY3"G o &Πdh{Y3\oL/ .>(0.##O;-{ēO>/C56"E FÛW)HΊ_MP߫F%nM~81W?iSZNNNf[/*39sf! ,*뚂 ,ToN9EWm ?+>0ںҏ=>saxU:hzۚW+* W)h0QTۦ?\;c [Pmj✱_O}~}oƗĊ !2JYD4Rmԩax FppЌ#6ݴsӰsg41}}!88 م=.Y0>_ jlAUXy̖^.u槖^>S9g+G~OH^w 9Tf>(OzrÖ&ZcqpX9Zk߿WoZ]8]gf׮]q2vAyTΘ1㩧9}S}}YmK AC_3?L=z_] jC-νt$)Tm*^N_~}ΘSt"9,2$|ϵ]{h^R]V^sͲ99]J5!f_d+dVeVq|2\mph=WM\MJ>4}壿A/npsojV]2oʗ_lFwߏQz5}|ڦ$ʮ *3GW)קm7Hg]w>J Seʜ9]Jkm۪*'Kդ|tHi?GȐ+W :wԩ{I'T4 RP-.8w]K'|W0rnw=goz Pii#FZL/8|ËJ0|hxV6on _k͕֍7ַ%`MeÊhVee.*kZ.ZjsAt Yn|]ԬOES5%T5L7zH(|Z2=+=JjC[ 5 7?H W"32_Ɩ%k[~a !oְdD{RohTy]i9dSD"A~(9>_.H}$_̜ ھ/i[T+ԫ=n>tH:JU붔dNDAݲhL0LqH^xa{o߮;]g~9?d@|eAw~,g]lwb K30lV ֫k mksPxEgmƠ8Sl۬ו]VbƂurt*[ȶ [޵UD0kWÄOfm4/JWP>3M\Sٶmc}6-3T޶6 ӹn 9WoGCv~"a)ڭzpٶ3ص(AfVʵaKjͩeWtӭX{;mlqf=v e5(.lY)RjVlm?7oT~<䷾;޶m7ͻ]0vb-o9^WnH}YФH =Zuff:i[G']_ҥad2yi7==Ӱ1TWKT{k}gϞs;˖Goss]O, /|j [O~zd;埿fpk(bT#7^*B1+ c[~~㋻~@H" tr'QuezMƴ&1%{7FS8;nE%Ûٔ]GVk?%◿<+yv%ϚujƯrOc\wַ唂SY%]dY|zdx /9oɶ^uN ڢbk.*4ta, _R TWMʧĊ8ASWyE׽.,yz*3'o_64w~k֋oLo ?]<嶎 ۶Se޸os=_W4y Dc.k.M) O(8ڇ?zYQzʔ)𵛿S|Ca\\|z 3'1vt7 5:*5YSzEW=TW˦&k3˝#qҏ}t޼ wo~}}t鲭[~7yEQbdK>G.4裏ý'lNoɵ{N][?RYKg@JuwpG{W gahyyIDAT KboTJ8b '`}}/_޿RY.,Vm;o{ۭE@3 C67`0Xh<;QzM-~c>![6_:LL4~B[^܍{^|qu͚`ddsȇ?w0F2jF}$5Qg5`=-|O FngݟH!46jf9z*s?S(u]v#'{%:1'?IS ;Iiڶm[8 {pm{ ?޺c FHJ~?(1uԂ3m [cٸq͍Ϳᩧ&8`p_NƊokyp,mNΜ?%o'c2{nm+ =\ϹOWlg+q={vT OG;#-7ӂA:8  |>`B.77m/~w#Ʋ}1J#c#ӟ,J;g5 >![>(ǢD"( Fd[Nkkk3^zaw C'_0WU{c?!Jwu<3tQ7~}Gph?L7m [.Euin3 ՛z׈BDan+C%G;_w^}{N)Hyg?RѾuV(}ŧ>dA>%nM~8CdU|"OW+#X}ӍQ:|٫yW`LyǗ^EN/O,xYgpEK.P88G;YOȢ?TYYtF5Ƃ={|~O>߅ossۂۦN+߬¾}8(@l_XMQaγgpg+*{Za `4]~6>Ĝ:1r!:Zy%jmmݿWoZ}wp3s9FZxGB9}= 1;g .7!Q㥗^CmYmk_;?9;OM=/=6D.r8rZSN [|z|^%}w&SLY׿ް70\i3O>pp~wz h_2ƍO\gqFnaee6>[ :oN?~2? 8G;#.>}^hwt ?z_|u{Nқ ~3?ܼ% 1oܸq'N<`fYo߾ۃw/R:u9g'Oϟ60wGN|˼xQb ޽l{챦O,3@b毧={=꫽=1?Vx(eYfeyʔ)7w\p<}c}O9ɑyrIS&OFGV? /t뙵52eS1wVU?`?ż&D D D D D D D D D D D D D D D D rZ[[`@@@@@@@@@@@@@@@@@@@@@@@@@@`\pXh-M$Jkn+rrr*H`x䯱 ѐWwT#=JTP~8h|4hemcc̊3 *3fv-})(%f#.4 37wbo"w@o}0D3A>LMN F^vKw [# 1bDY"F^vKϦ-/JdɂL_ʺNj'r:,nX<+ѶĬ{RDAj[SM%:#ݣh=DIE}K+JoH[R_ށܙ~s zANw|ڐjrqU}ei2RƗV5Sx:_fAD2rf;얞U9gJo_^4ąWݙIw>xg3hy}auuۛ׼}ݕ OL$X|i1 r5*49ZϾ滯mƊSξʛܾ!m[_ZoY0z ]:;|2ڿq)vCCEu~ ^t x^@7Yjҳ)z*nx4LL{R}Zyndž+f>züdE:(n g=zfǢ~`WDf^zʬQz`ii;o>;Szfm}Q/Sw[Y/JKVo\pKn0UxWwѢ΅\DkWMU t-X\>oâ`d1!8jLou KF/2]lݕӰ z7_n:*@|-{Y.naKڢ8+}4K$vqN :E]`"Jÿo[`R;Vzʒ7;ʓh. V5e _|ssϼdy]}7\VNˎhقUWe%ma(TWU sL*(Jo 㩫wԯjUӁɻkv+do~QQA"ajVBsKȲDӂYϭe4]m(jiɢ +FtDinEEIXbAy-k;WUR8J<2ݾV]}B:ƠyK8ZYA{P++=@{ǶwnkU]:m'&ҭ$N .kHՇD8LKa%0oIiPJu-EAvdu4g.^[E'%h͵uftmgF{cz6k,! ; \m6U& OJ,δ/=hC heiv77o.S^7yҬ>!0 *ׯUMQklцnCPcʂ5@[!D0G = 1g_~ǃ;wwLw=X'6^2nsmya~iA scE Tw8jݙNwuuM/K4դXPH I71|{ sV/L]eV]Ornpp cR򪺆h/wxKF kw߱)L,=FԖݟJLxY\/KԔ?^4݇kQi{HIDAT[cժM\֖/])5 ޹cļdvgj}uN/QZ7 +$4ٱaS2f_z{:Ytgy.Hv] wAe>#o]viZS~:J=ܫoy`ǝ]p҂'w]05T1ԆyC\PyoToZ9Qn|}sT)*]yKJa'TxE{L[~[uF}@hqāāāāāāāāāāāāāāāāāāA^0jL:-iq q q q q q q q q q q q q q q q q q_c㓏>_|={yƼ3}xS#ek3+{7Cf8qQGuxқOy[F˜w?}6mWD83?m immuK/Ʀw/~RPiGuT6^ڳg3]X”["=[̓z#<2H Á…&M ?7.O 3g+ ڵo=pq2//rI@'O ۶?v;q@ĭ_DǟַDK}s}mc?o}[6u=N*{… N)(`'|Ws^gphee/ۧU\F#߮vĉ2OxGÂSN o =0W/Oa?_ӋؾFydx_dbu ɞ={=-[~͝v'?wO-aܸL[?j1>[߾3jDY71L۷K*e")◢taV}UC[)J◿ ǿMg+ _a"JP{01iҤo~߈x{/ҷY079(|bD+{矷o>1`|%nݶk׮۶m~zϹG0fYyɓ'ٳ'Lx9&/]ׯ `zc477G+`7n^(6_jkkS/3>&8YFٳ끺0zdtx_=_ƍa?>xPs`F>~c{_Zo Ɏ QbW![7pnmm}=cO~`..[yY1T&ΘW40>w򞱽g!?cQ" iG}tx8٧0ڇN|ɧ^|8#E H$ 3'~7da{W?Җaz'sΟdA>%nM~8 ]k_y啫>{#6Eo k/șsgg&Z[[\c)jc=_Ed~TtF񭷭^Y~ż`$1gNk֫&Ι3A6}9W a}}mSN MMM_طo_0Fio(gNEYɈV~{ٮC`>P#6ݴsӰsg4=={|0`vO 0Ȧd`|A2ˋ[skeԪr_iuw}3]v#ﳡAA0}`V20ܰɅ7X k<*ws`ʕuia 3fxꩧzNT_?ӃR8{zp__37ԅqSS-AvOrq|Uk|[o _gl tx0*?]0!h3T>%'JEڦ$ʮ *W4g%ZY g,ҩ7Hg\.%kG5T+ӥ7U̩RZ q{[VeV1>Y2&\(/ً6?4A#Pa|gY7`Mȡ6J+ XK+kZ7o_M;+պqSהO+f)y2 5U7tN¥6?[Qܺ&ԭgXږlzͲKiV-R̉Fmتt[pׅym)IJzٌt׭aPp3ɇ6gO^ea{6wnԵTӊ9sRv ="ahզVȨ׭cͲ9F4A;(_xn+⊺e]{Oms*o[\4S2 /MThk%C1[V}7ۜf)`^) +\Krⲍ_f6ѬTGu J Ósڶm cT#/>sb{' ҃-%?{W_<ΛW+7U$>VǤRD:8{>w_<9_n=G!7ߣu`:`cVѶ.D;ًşRQ_" Xlk'QueFp'v_9&}S&N8cW]{]u_g,|@Բ%[OKj ul [5ƞE˵R+=_܊[Tl{BqQIr,m0(gd*3d2I&! d׫sgs?3p]s17giisz}+]4w_<Ⱥ,׍_n[P'̦buQɃQڲQ&]RQku0:ѫZ ++gJv ժNIDAT:9{́xУQ\5oܸqot_ܘ5_O}׻k7ߴ:aLƈ2(\sKdLlm5,1"SUW%rn]Eto\b]T =iКȭ6)޿lUmʺ35u%uC2cE `gnU4_{ҕ˷6_yge(#\7'TX5,ߵ>t. <'x{wF7o~d(9 `vv6756q^%iZ lyT՜s%ް_뿦}gL{_y N*P/SO'?9~wE'pR߶4?2oog P Kixtx_λO_TqWq]#mGpK;(: _owvdQ_ '>Hƽ P X!8< :{TEIEXݗz &Mw~0\sR C Gn䓿 }e_EŜwxu?˿+>g9#ʫ ]VRRcsRm#W0}o/v|^{zE37_ƘNLk{n/>/0a|gv1ryNoŒ{5%OSw{Aj~x;/T{nR<_'?x;~ֲ=4O.gyƴ(.3g{'^?'MhK:x~uzo~P\&L?ϛW'p»&On}{SC3ϼ|ev>>w{x#|\;?[_JiiiOVOy?s7u5𩝏KR_II z]`T<]ߊl^ cS&_qE@@8M]`kSS˖oܪ%5P N@kkk;H{$]wuۓÈ*)) PP ;( P 3{F}ePp 2۰`D}λL^z?Ax߸'@*/'/ۡԟQQQ~_]p[8WTT.ĭ˂0%][n]XYQR)?cgv^]sV_U_Sc:Ne ---v断0VEPψk7?}odϨkV`įͷ1 #ǂe_V]xWVR>q׶ką̟ϫ<óg7.0fUiP[2C8&R0R~オ#^2ٛ[±ԷlPKoӟ=mۣ[,I7ݛ cIN~+^;̭4{wNb;.\p(P6k֕vnNE J5鵫n[P2:g}3*:9\9Yu⥆K.4y0qt]) 9KiMI4,jҞ j[^Xr{ܮdt;g/u<){7nsSd:wwKibk~NuqdrOK{#z{ٓ*yevHt$qœj<ץ? ø~g0Ȝ|=|~O>_[Ͽ| @!+y&NkjR0D.Y0qAˮ`2-[^.$Y7r(Sy4<=shqEgD.5R2eFl_YQq_&\s`3M{r3?f-GF Z>D-hH8 p(8"=\+әFO@_^Qnץua}⥦7ڙ.;p}vH3**#[ǭ*K~$STU6Q#Fva2jաg{9Q-]S)ڪ#~VC4lx+hl. !lG]l;}O>`tvvsҩ7^L(-]wǪU-j˲[j;0KҩHibUUh9:*,X;9[_qĺhV'4$A{\4Q=%N~ :ϴ=6gժ} Q gf޷{+IJ7l{ν+_ՒzEWGe6X}qQMjnW>ul^ws鳩-<'QׅN6wu{^T-w?!{?u^= z5ݿR 'xkƒL ?P$ }? &b b bp']x]§q5>9@Q@@@@ǐvx㵽`$P $P 2۹sg8֮k굁PQR:;;ㅒPٹ3S3?`۷/,daw;::we%L^z?\v:.#x߸'@*/'/gTT_㗷u(b߱wvZ`,SX4Vg{дu5kk⥕ ӣ޺92r0%Ct?^M8{́!CE- aB*Le{-5>g*K7lUY*LO+:2m^訋!/ɏ_P x/|\awS'm Y]pK^hY]U5,(gT^5yG,[&.ٛ3449[!cSiLޭk﫨[5&T*=ݧӟUW~Cg(pt箩IG_߾keͼJ[TZBb]g:kZ^9w ݚ3r}x㵽` rO /UCO,~AIE!lo;J/2.D~W~ƒL ?C6䏡? Wa$P $P $P $ }+0HHtvvsҩ7^Fi0ǿ0L-8r'X{B-jizɿˁ1a5-,I]ra wԞyf5 (h<ȹO=%9Ui- ~AIłm_YU$^~ے4xv57q%*+ϭ<䅖%ab0T/mO}fΞ={~'m{tKcj9o(@_qgoݲ%J-̭8Z_<}[ڼ*=5Y-X$oV5}!izJ!u\b݁5qֺriá̾9xu:8ܙVBW.imw_aiEI{\lU[IQңgZUXUմ2CWs~ҩ#O~\gW(L9ĉX}O;-p,ԟ49%zn3kiٚťcTH>$y]~(:i]"$QD҆)%:[j&fLo2Wc v75,^8& {)rk⥕܁/$֥ׯ: :6uT&d=]Ss3FPre2DBe68  VAž?WsMܶ-p͙S*J o=k2qKVU/m^x0>!b^jk wַUDd8"}w6EyB`([)כiIY* L/G+s ySv́QN[O+?NBsԤ^M?`0{F%q!;g5tz9rrGzgdWO ɗg xH*8ZZM%8 GAɱV$=^孛sFȒk8+D-uaeEI0KUGlQP[sWQWe*T8D4 0J:;;nx}a9 lߜ ܛ3V`ζquc`ɜ/]׽2*ʥq(K}Ks2䜪:1!v˔'\~U@W}T{~w=_u{ ݘ0'_.MOo_ߤI~0LF'~ '`WTT.l 3켺=PszJSY]E5~yʊ3[ZSo/9rʿ +ޞpBIT Ї?<;v횛?zyV{nx/ Z6͎"´maO4+˞={~'m{tKcj9&@*~>(~-WjanU֦@qhj{))s^Ю~AI]{^WRQ-&6 gTI]Uմ2y(8.)60%]HJS Svrڟ'S' '~CT}N8xշŪʪq}ezϒ}%;[UBΖ~цZZ&Ját`DHkSgKmT,^>Oد>pK~o_7~EhqyVZy o=*SChk {R'Y uUb\(>_[Ͽ| @!+>&NkjR@֦Z0ؽl]X>,YrcJtjVU5>9u\GqKE}|n~(+ߞ㗷zZ8԰2sV&1k(rBCIE]MYmg4{7}+1~i]fkibkjS܊+u%AeZ6'WW&V.|坕u{wKϨoyeʥW$Q75 }́^ۗl([7/3hFU+6  0aO(3'aj օK˥7c;pccf+J*#A@@Uo70$P $P $P $P $S'ƌ[+_^!b  %% KA&;w<GKKgKwW -ofw#@A9!gv 7ވƍZIDATfy;p@|ɧ((mݎ0~]e5L^z?\ggg!'X{LR|/nr` _PRQZp[8H]tA};{rakօ]4|{晝W\'jwuus>rSOƀ3ڧնtįͷ{gJXdse}6Ԝuեa_YU$^~>q׶ką̟ϫeKZ[U)pt.\p(ZjXZQ^5چŲU-om]>~i`sxqd2Vkݶ >0c\b݁5WM\ZR*J7&6iYt^X]vBFz6rt|թW`Ԝ|= G8q#oi-3g*cusDW<{́-SN `[03/`:HKgyһmOZME7gқr%u)SKtU_:Bץzi{zmv pZT}٥M?N~DU}׷/k?z3.*.* ZjjesK- ʇ5hS^Dzn[iP rϬ'~+0 N:ur8nrgjKrpĢB0 Fb-_^/(?ƺt9] }%aO},"PgTTQ?uٺC:,J~գC \9;{p̔tvv-A{㵽їΖvK`u{z)^׼)K+KTLqI)ĺW>0~i`zU-o +dݧJ_jAI]{f63_`Ӧ´hs|W.s.s/JVF˩SU׻O2twW jy,sƒL ?dǨe? Wa$P $sF>7 n" ë(m?(?(?k{B@@@@֦Z8s~xJLvygƒ9̹7yo`ж?u17//L81@A9!gv #^8L#o߾}Z|{dawu9#wޕ]>I ^~j>F'~ '(,M+K**u[( JҗNՠ%˛Egv^]sV_ȹO=5*!5Zj#{CϨkV68~߿++˯z;a4xv57q%*+ϭz]ٹi_YQ2^WDҊԵWUؽ)wk%JV&y`INk'|C|' SA9qG;VN %/Di3#m*]aJmSKKԧL]޴5 KlMӸ8QU_ĸ(#̌l֖: M[/uCɕ.+o .mq&} z=m[5-ߓ 6gn]X4-7Dsu%u{5Ī|JH=ne c۷^=[h怱BǺwvڢOW]p& #?4S )-OdgO Ɏw}J[TKC VU5>9QueոCO,oߦKӖTO aO݂2[VVT.4ȜCs--Y^hYW]ھ"yiáo"$}ƧC85_ZQs!}HWf(Y<!^O׵):yWYSo-;hڨ01MJsM#: Gּܺf;ަf\9ϱ՗poZsV=?(?(?(?(?F'WTGcsxmoX@1@1@1@1omUUn@@1t;x`Pz J!%?&sγ>;\0F'_.}-^2eJrB(y{gv gʦ((͞=+^x0rŜ9 J!%] F+^ԩj(0]OU^Zxs`<|b7xß(4xwߵ&^nzɿˁu[#~AcϨgyu5Opa. Ph )K[UȹO=%WUQȴ0th6}WT.o p߿++˯z;y4շɟ$v횛?zyV{n`=۳:Ԗ *0K6w. ={-Onrv}}Ulyo/UoW}?Qs6y؜ ܛM+&DdC{f\b݁5{l&6JZV.m8=MiM{Lmy!ΜԵw.[ղru{rm@>zVu4եw(lJ#}N=Ud27T/}+|bi`6$^:Ѻxe])MjZlm *VPWw߷csݪiDG2s9+Ol.q]8|=_cS&_8q#oirUi^U¡Ζu\O&jIoiY5%9k,mR-:MT9*9^ʮܚxieE¨ 33eNl0M^Btt"0Y崪vjriɂ,ٲ4L5lSg[Uva倳Eu$e.Q0Dzt%b$4rme4,F%W&C9Q篼m8=ʗ[[5釒^wUDK^H)(PWX5.mqr,~pX7g>jްד۶&+fO ɎT0}eE2x&KC.25XzgSTtʖJrnߓ:|sf$[W%V-Moڳ֔;"hx.ȥ aʜTj@jSy".@ST+rֶmOmJB*\=6^sZmW aIDATܒUK|{lݚ-QzWO T@Xu–T.֯l8ڭpU +ÒL-lJ_Y>EgC:;@+/>wMMݏ6Ԃp$XLrqeTeGO!+3g"8w 7mfr$Gmm4ᶰ$' -3'<{Δ|U_{|<_@R! 2g^Aͭj|ts DA0,,*;kh!:#CFC\dF+PETRU4'欏ΐJoZ^' Y԰MKSS3ͲdծϞ6̘q 8Ierٖ{HaZ10z>hk۳EFVlՒ5 xRٙwÛ ٚ9̹7yoRh(tMޕwV.mH纷˔'9ɸe-XٞY.˔uִe$&{Bo9RYW9Ex+綧+3)MjZDdC{헭jٜUWuQtaA4abJCGk{uHQ9Ğu=:שKt5W5cS&0 6cէ-1K {? f?hhC K+Jzp̩c&Z&m-9W8z$f+J*$b bPٙwÛ OjHHHHHHHHHHHHHHHHtvvb b b b b b b b b b b b b b b b b b b b b b b b b b bpB(1ezoոxзVcMjG܎,_;!t]WjEڶA1m[,Q>9&'hhӜxg>g?N`Ri Gi]0:6.q5xb׾xqit{})GY!%e;lYOYԽ=w@:u;l7e~Kgܽ!8QSb?Ɔy:;7(Rӓ\&&L.lCw:20 \st]o螉k¬ݽFXbެ c&Z-omIdu+'˲L.O,[co8z7TOnucC^hzkW/39#k3+^ۜ~5]ՖOgrEphaiK=Ө#43#L]]O|ƅo:.yE;Hu auowOw#Mz;˗%6^s~]Gpt8 ӥuϪ#7=MƧ<}dzm{x{xMWOVu^?J\\|ezωG#-cNl9]yy+2?g=`:/NzhӫOXݜqS/yvLJ0'mZ^-W_ՕU[ooG@2wcT-4؜g3h^oG}wu[SG'o MwO~cJR4/+Ϝ{ُˋߝ]߸0~g<R8fCn=ٜ̻Q-f;g5-}r7uv=o]}+:t>2gWq:=zه탿! /2-^_]>!L^[~6 '=nnw驺ز(A۸e5Ooh\]3kx)<Ѹ#mik)O7'jWӿ?p??_\fƄP6#l7T3$wmKDY5V'NOXS{CG@s{I%,t831kB8_x3v#|ѓu}zCz-W9;tp϶zzrcڽS&@QVmoNf?.ee]祟=՜X 摆A 9BfhsBn5nQ9۟ݽfVSUQmm~a͵'/Wq,[JkÿQ82u&wMGwk u׍nY=<.}=|PV>#g[pdB];v#3yrk ٖʗm9]2鐕ͪLW=ݜm^3⢝&T*Ge+8arȞܷq{Y2ϭN"ڼvs~qXawcٜ ؝g3ݞkE]݊MGF۬tvyGw;CRNuă+vz3u|-\VݽytU]peo?c_oƆ#S4b_fhdg;жlFߎߛGyg_o/>dsމwd fEyƐ}ͨL`O]9jڸh^&ϪYݸ\o|x+VggW<9+;F<.{h@ f}+Es2odY9rX#P}OD!ԋ~M;0F,+WgP߱x l\Cxϵ.o o$IDAT c^ٌ޶#mW&JrnV"ӏw[unx3[*KJJʖu{OnٌYjW7$>5&<%e5H*kj&iůN׼d4}f,^6`=7 w_w[v7.KtroxýSFȍ=7Umos[{ے.7+~*+?ےɶےu*5a+UaoX?m?qal4.<(Aau"v>&T.bټeu>g%򵆵f{k kϊL?à%ƎoT[!X>!`^wșX>]{g׬߱;;הuBGspZ^zâto9}XbqbF+u)Lewe?lG:fQY4d>253/u8ߎAz*sNo8#>:PFN%m۱|w pEvlys}6֔&'zOWW {ظxȿ(oq# fnO3'~U;?yu5՜}߆ØtɚCC\;{޼ 'd 3kmPݵ逝sҾgqqozՓsWOT^3S:4zm<kSquy{kۊY g-g}ΊkfwMyYy8d ۇbXݸyżz nLg8F=ǷiPgzNw/Ȅd fNqԩSϹ꛿ɮZ~n݋9~ {S cߌW|L'nG6z/9kŤ<# C5gݲ˖ʑ/|g'ǟytkYٷO8K>|/ej3g<O<1 ?`dRrq7~7~~n)݁W Hȯ^^xې8*8I-:0v7.o_?s~1km.AmqEEI5(O2 9Îf|pwvK yQAd~g(jI:Jz2Mep}Ye_q=]}.JWeGs#oa:aCyGp'|Mz*]w}s}o#z;qOu|y#K_}hKǙgYx9/1THߎ;ⅳ;; ̛Ҳ0\/{Ey6uD߯̍߼k˫O}p2.k93mׯ޹1\T'ؐ󉋶t>{ݯ< jK=.rO!}0\z߻{zMo:\84螟0h*:AH8C?˼/4ČmWuۮ0X43_Ztig>Dz՗O98߸>:*߸pRgx< /X}}Iv p R/|#,~cNr3ǣ=3oOi˯\XXSإwͺ%>d̻Dг5FV̛0}nz.ݴ#(R̫8c7 2#H2=ϙҎ7.+lI}ɦw]eq@^K?߾q@=?/{XS'} 5wɂ6] C5z=}?n$2,k.ҍ oȍRakFH0%7<<{}sN8o\tvo 4Q0߸؁>/YsΊۇZ<oBƥw +g9"gμK)^I~Ƌ2_[RA{f/=^/u3%1'uץ(% kU ywVH|0dʘ_T5@}ۈ\=fΘ#d#/b[tϐ@4jwc ϧQY*O=AGh0#Շ%?a|3/[c3`Ef<ɟrV-qE[Z^&*۶8 l3i,f|%6lKWWsy91Qg:(gϏRwgY6` h#3[EkťNZ@?g+:Ua燐7~f>c}Ms@&tςƅ]wiCaԼ޾+×:3ߤ~/? ,Z,-' FZh|婟3*#Te-7p/ FօR'Z evϜ01cf~FVE F~S)G?-~OW;K pQpi*LwSa]=?us#= Ѣe8lIF]ؖ zZ_O`Tt;\}~͚떿ҟ́7.qIDATo=?/i[kfөSh U!=~aL~=FS75^zl~vϨ/ ZzFxG52дy=-k]MNs߸!׿_'Cjͤ}eeSVHٳK"u5JZY5g===gIz|ǖ=8p>t=&:H?So{y>uQ7/Zʣ;=:y4e4_حG`q6q>/i6c37_ec c-ũS&oعaJٔ5(pC3S5R1M#0G,<牤v8Q  =MnNFFu`̡M Iwp~#oC1xP04_ӳ?hLxʤg O~dK{oYtKeq⡖u Dnp9L؏xV1]V1ASia ߴzX)ƈ>#\\CrDOZ4@px~3W?*6o rC_+o'>pR_֦y,߰x78 x5WYN0 /enU՟? plޙ'ݸËF\&.|ۏ͚;뜏s;v<өߺykve*ca#4[b[~>(~SG]_Q8|QͿ_~GL濨0P')o憍Mܶ-([Uxѧ}OwMǡN$pyO@@@@@@@@@@@@@@@Š3NBh0ōx7,.+{`bPH5e;lYOYԽ=wC5+zϪV'̪iVXbެ c&Z|OnDyYvew GOKW76?9ۚܝioyY>S=6ۉ%ek޶ƵgueB٬y+w΃a=SƼR~?i}v:gw,+Sج+wߟl)]XS2!s~yYyOS.ҹa^82Fϸs4o;~s̼ezs;͈w-?]{?i\]99Aw)a=f늈_nZ4>W'k'ޛɟ:;;즫G:~pMm9|sD~zcpT-nxzS/tsZVev=`:/NzhӫOXݜqS/yvLJ%ֶebP(NC5-^_]>!L^[~6Zֆk5!e;,oVYM2Aquͬ뮋§Dp LZ<ݜ5_M'd74#sq݆BٌZo7T3$wmKDY5V'NOXS{!&l[ݼ@}me{$nuWyyuuݻ)+mw8f~u܁4Ä];v#3yoglK6ܜtt{2oWOȿiG2< w]zyo57lB+WēܽoKLz^$;vP@Jñv{z_ǁ@JVK"Sh{QB0y1+qA0g;жlFߎ]̫7=xW_|/N l;$rV(R#ͫ3X0ޑν]sM\6᭽a+7۶c߱vuC CvՈ%sKOxVƶ<}omoKnXlެ%%%e5e%m];%Uk;XW>2g Qj߱~~`yki\Vy֍O'-jXHbPJ:;;۶cu/ੋ6P]ֽ⭶y?oc.dMtƚdSoIоa{a!jP=Gr'XȽug^O.w~ +λ뤩k.93 15+CL(M`ٵNzW-/c~n݋9~ {S cߌW|L'nG6z/9kŤ<# Cv@5@( @@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@1@17{}(O㘚?(?(?(?(?(?(?(?(?(?(?(?(?(?(?(?(?(?(=65=ySN9:U^ƶμ|}_~/O_ua xʤF>W _n˿ߪ0>9Ca~ikSSjanUV i`H87INxmP/S۷?=e)W-j欙{f0^~w=lHnݼ5;՗aI_K'߷|yE{ୃ!\)?{5oVլ]=STt^IDAT{:@jYzӦ͙0Ɯ >1^^|b?F嵗g>=8%KSHoYsκj__<ƘBJ4R '}'P`C햒F¯,qHxKE^{ym~>/߻n]c ):]veZDN1+3ul8? nlgQMݡ`I?^75ӳGdr5r?å\-z9MC؆χA/-b$9 76nD]x0R/|#_EPOr3IŊ랙7^ڧ.{,,gft-Yćlyיl0)W>QcRQzD7l a]Fqt"|O_`N8ƒQLN:ur[Sy,oK/s?Ю_G$] Z[3=ڝ|xW&[nuWpzxlsnܵ LmLue'm}+:械0hCzwۋH\޷6oA*{Oa:L`y#¸(ʻtQcwM4ݰLᖋ pWOc5|wμ+tUenysѰkA<~0&G_vZKo|>n+oVU?[g miyx=.׶+G1aᮁ@f|SIv?xvF1{㵽}_oMߦ_K}-](){WA;S}m^˕/:Q9=,e0`vo]n3feߐi=By{MG/&|-(mx)5E&n= Wϯ{-_^Z`+R{x;('Ë,V^/g?ٜI9c3f˜P|ʪOXy#@ߓv*Kn垻:_?$'cL'}#w1&MlBglWkuW_7|3@vɗO>s`_{W>ŋGkg|C }$09@@H $?D@Q (@H $?D@Q (Hkhh@?D@Q (@H $?D@Q (@H $?D@Q (@H $?D`PiIߪYvImڒTE( <=*o\º˪y%u ke~ac`749aVPYCx_T0=P-:Օmm;X[QRr߳ʪ [`9-WXVUZٸЌ}NAgTll7qF`J+kRїnGҺ S'OJyxmQ˪:Z1Z(ns:iC5-Dƴ*-萴vW(ʞ\F^VW<K=-Wkyp}hאSnSsUYiE[̋J9gV#P`-gW9kC歩&u_,'%~;nM9G^Xf]@UI݊I1ѺN=v2ϼ}1"[GiX^|}omhʲnw MhױL1ymO'bXjаqaaF^qݖ{?W7!?e}cͻi9'EoX2LFL׼E)|d`B 'wlYJB/Af7sÏn<0y~rL~IMה'+y+'dɽg.زJo}// lvdN3< '3}htj#b1YA~v袪9˦e'=4{ZY#yOWg4nRT<'ݾpg`4rݧ_hF"Z?y9?ol5cŧY[CqN]y4!4ZyI2A*-YY "{?i'U$?i]Y6>X\^(U%!_/@BzaɶɽbٷVnnTE?NQTڢ֭zpO.:sX1fcڪĸYugnLv m(ıT&){ZMcmŌi~]=qZA6IDAT޷5i5B귖0{ʘ[_n?ot^Im}v꺍 z5]7{JcsBWd%U +yƪU[rNF~52c+edd&Vit*y4}GSpګZMr}TVusR_mi^ZZZƬghz,%)Y\Q#sޯ]WT4<9*EsnݓQP^UXRN+Jkj/4xg@*T>L+SQSP5s攭. ]W\>#?5hake6R'\~YdVANz<,HZX\33K*֍KKdW%eM_X_[0gh{46zڳV׵XtNa~f|ݼz\~Q^Sl,)><{ ^ZQ6u~ۋG}[MٴƩ}^)7RQ4USw΃\{ƢƑ!dyպ\V3'naaΩm3?^XSZw^;{7RY<9G^X؞+ R5+ȟ~/|$kImiި?k}̜?o/^~%Mrf15oMr;m?6#Жeomc̾a[uc.[hތ1#u;%954t왕u/cf\[UeCF}mkj }BZCCC>'?D@Q (@H $?D@Q (@H $?Dw]wA(@H $?D@Q (@H $?D@Q (@oo{WX /+!Bo̘C'u/mi .xo{|ɒ~m_}6 'n66a><>w.٥|וu4hР /;s=;?(n{' ]٥aÆ)'O&'wO|1+'kO쟙"zowIOK/ʣ}7ϒشicQ2?N;:I?O٢{ߐCe^);b7`]v׬4Oߝwݝ,|_iWM/q'i-e{gtk6j'NLkBJCʗg5v.P49L]PY{Y[l.b:kV׾&Cqᣓag~?c~͉]7.Z;w_bkUC L\5mу}v3luiF}W_{-VX|cԶ! g nܬEK(h^6ኆW #Yըqls9BCu˗.-/GYV,1gVNj  >Ozubak_~3Gw6̟vnM/'']fղƴ/#cD&);6'Yvײ]׽\2=7-wz˭.oֿNq~gqqh̳ L-l64'vX&=8gʝr緿_3]?~tv^͸a{[{AZnnM/,7-ֆ.It[U[RbӦMsNN;r{4Ik+?{Kv#=Yx.ݮ~ /%aW[82//t^]wASI'~_O˯)?S?u+V>iswѬ a_Ҥc|rYg?ٜI9c3f˜!W/dyPXw!.tNv=wutHN{`ɿMY^8;kuW_7|3 {9=_ }>;P?Nb{^,^"jĉ3ΘqÆ }`}`Js'(@H $?D@Q (@H $?D@Q~N?D@Q (@H $?D@Q (@H $?D@Q (@H $?Dz+22*C(LK*@Gœq[zv5%9iiy%5ۮ]Y~XV^>+ƣfW=SG$Q.&Ы篮lZ2ymOoh;RAyCRyAՖ?9iCfϪmWWVti[+m~՜-VueCsֶ?XW^x{.,*-lthFNQYMO X[Qըee-n}vFZ, 傜, RQ1l]aE_~㩣=]=+ IDAT;tsbxj [VSw΃[̉jzvŷ95-:eάjhhjeUlhFrzƢTl⺆ouی!W6yOM۴.疫+J7<})co5jQyOS_Q5jbOqaaFg;_FQׇ j= /SZQ]1__Vmb`i%qą3CtUq~F9Y 7Z5p~<>cQC.=2@?0h{+.0yuyS;,-hajz7~5(lh+ 3xB.mSUVs|qɖ#ˋO m7 !a<)cF ߼`ՍfVԇTq졡VU5-3=}HW>6gVV_>}_F\#3 ToLLn.+9xyglzN~r’ac}m’œiiieu+.ϟS0ykejm~ ͅ%٣.jgGPUYʆy{ʢP]=F1iSu&vLUs2j]%YW.S0붙/Ք6=cQCyA>F0f޲W0{ʘ̓x:x/̪n-1fٳ{ د.[h^y杒j1iS燐5oMͬ}@++?3dOEHhƺ 9篅챗vyUy0}5|̌}jVv>-!> $?D@Q (@H $?D@Q (@H $?DA{@@k(@H $?D@Q (@H $?D@Q (@oo{WX /+:c;`nj9tQGM©Jkhhhu{}K|k3Rᓟ Ɔ>l֤݇>w.٥|וu5 o;K@%n{' ]٥aÆ)'O&'wO|1+'kO쟙3jkj_ Wǿ}#ƍ; G/Ж~Ŏg.HNL)x}=u/}V?\<y?`tssWxA]/#%2Ȉ5ߜO}>OK/ʣ}7ϒKM6}/^:V5*sONv-' :WHX?yc5kjOλN>{g4=-wzˡX|YZnn+Mى˾o8šo5z'&MO_uuupȑzdzb~j K6\39ΪYz͌T\K/b^]& -:U lYScݺu¡Gc՟kcU:YNCmH4gG򪩫.^ti|;.1od"^J.m 9B潱/{5,fƽ?N<'oBoyւEέ:]ܓOKDbM_t3v3&'_tHKə{rbP 剃 T4ީoMlbA`&3;2-@ /j*ꊽŨYMorV>$j8Y-MbűYn ^ЉX23/lemV :$7iώ[&Fλc-uȋk헙Bum,s~Ѹm7.κwvvx{!& 2=[|Y߄DzڹF^),"-`B[յ,~O囲O*폄4C#M^ˡD ilwmzţ Q]5Z{6K!Jj5#{fU!@ҟFg}իY#;fik#Lnf M8iF,}rS>AD۪+Q:.;UsGhUsV:6Rb/UrCVe'_ 3C;,i .xK:8aF\TQqB+;y(.to$Ozu>w߉o;6tR]1><?9Ggǟ/Wze3.k+K9? 6msduOov7Gzdz~ăr VǴ܁V9?GW'?O>\zgѣ7O螕U+\E.%FvL?'5O~͙31c& W/dyP#"t!T9]^A}י_!9S LߔnK`[kuW_7|3@*|l̯-am_{W>ŋtդ g1Ӈ 6Ж@#ڒOQ (@H $?D@Q (@H $?DIDAT !>?D@Q (@H $?D@Q (@H $?D@Q (@H $?AY0'chZ􌌜YUXQQTწ-N~@+/HZaEWzm :Ք{E{yuT>u!#t[G9->W64lxkͲ.|euZwمԩ 9G?d̔7,[Ӹr㑄.Y>@os5o͖Y͜}g,YXJthF~剸n…-Ң c=]S6-r=vm^fFFyˋΏ˺ڲ'f\XhXyi3+Z~ؑOI؉X]Q\ٸrHJ>$^|"8})=Y0UյͳjKF.Nuaiy?0Ko9[JzADFL ?}"눚[[s<{HuŃӦ巶8`Z=tb6,S1t$kJ %gZ_ԻW3WL}̜?_c_zz1t*wxC*[}8_ueU瘼 :W1sbo{ ɧ5nxWH @/#>tS^aQ"VPSQTURfk*XjJJ$kG* SSQ<ԔMNo84=cn"v&9y AƺYy{Nq]).]TV][m.+}΃ú-7/HRIY,,)̉?..tZ̲ycŎeaMP(sEce^љXTSYXk*KSuq\X0BYW.bFmiި a{dO<1ic/]D,?/ceG+ҷ!}+jVƑ?N5GJyU1ʅ3uvR+(#߈ُŏ`3Sn~0qܝGR$˜Y֢Glbs1Sf߰+B*dUֽSƌyw5f1g6xzCCeW{Wm˅Gg ooþUWWLzAYE󶨍Ϟw[;F}~bp?D@Q0(GWeuмAׇTݸ.tV!yEg3d̂!544OQ (@H $?D@Q (@H $?DA{v}x (@H $?D@Q (@H $?D@Q (@H $?D@Q (Ims 7 æu|-^D>qoq߹푞xvm㼵?s}MKϹqsk~هXucy :@An:]<7n7%.B{WDq+k[ݷ|cdl’pi[|[t@ZCCC {g}u_{Ije2̋|չO=q^ӌ>'xqɉۼg.^|!0@*YoIq}s??rKY9{τ_}o_Ж@I:+Ds-9E# K_5;ƴN}Fm#v&Glyڂ`M3[ pFH@oܳïq $"訟\>;ȼGZhUUזTwo䥷rle+?|ӟtԄ-HRep5!CZyv6}oN[jhhx_ 7`-ݕ1bD?0)bO[Xӟ "o;7; Jv>RE?-_F؞@{>^-cg{>wnl.^,cNI1~8gͪձ0#?>,99cГL>cX|?n4]+ :sGN_8Cyg[njo{WX /+&4>{sģSC*& E <蓟C_}{ǧF~rYu>rkǗ,fnZrc?_^~ua o&  aO|"@\}4 k }|0{Υ;nدbuu~H>מa锔\}n!ウ>kÆ SN8'LN7HjlNNPWW -nr@_ cС\}H $BTwNn{{_ ^u߹џqucI2K `N7CoԿk5I2K `@Lw?{qg3.c|-f>>._wm'߸k6g{k [Wacφs}56؉]|%]6imط#~6X;o<6IFLMҗiXZ M'T>?íw߮[]M7ю1>'Zau~[O{&^q+]y1-In{] [݆k^tEFf72 KNV+OKީ=O!Qձ3~_uzc'+y5ڵzi Nmθ{x=-]rC;_xom's.29mFQd 8+"';@/vn7Z*[}'nCb7Ԋ$6xw嗮k\[Y_?+%L<7m;=}f+5p7Ϭ8ʧ8/cw`%.W'z;k!Iv9ƦfL? Ɏ0D9n5|bO5+;5F}7}~ո[N?귏ZlKbU}C[mӹY䐫|Vg^rhy#[]bV<}m1 oMbI$}IG}YWH%-'ʿ_\uy?{x/qsZrS;o_Ii{ 7]{גq'\LOkid[7]{Vzr$~rcJl~дmg6I2K  ݌;XùM}l矵dݚֺqO/T|钬V,tW{|=қ:誕>72Ol1>$}vb">ZHj96i_' W^u襟鷾-٢=|aak}g?,}nh[=aSe';Yw7ve>|⼭Foq./>9w}R푞,v}'6SbM&xӝzk9H+-uT}>gyo{75'wԑy͓ٱ@~|)vƛo!6lbܚ52v rᇅz+ͷ ~Cvvdbn遡jrP]osW=']ù%·.X,3>TWW7uTu2)K+rBLmiX~0U{?%Ye]>oFFƈ7UoǼΪ<798mz趈d]Ϯ_qzcE&S:wR6sW5JXT9hРdy{>=3m{$O4iQ*Y_C9IݳN;% ÇNLOYs]5E b3{Džߣ^}]/KKK|ܱ/  H]vϟy%;s_xϟ8u]v QO:_WpVG/>q{zg'ox pDWU"{& ';5 p5|aɁQW&˴Ov,-Nq>}oׇ>|?']vmHQ2Gx`nnnGt45K^S+|Ci .x)֡Cx|>F}))눗^zo|c_\pgAMv\5پ_x1Y8sׅޝz>;N+j$ ߺxV$-0v}x RW' ߹tNgoݫ~]G|Æ6l:7o͞-m߱GϜ1#t^w}jw]';;zxP꓿+ڽsE7n nu% Æ mg Kҟ\d 0:xZu~'Ϛu֧O|h֖6>^x勗r-9oW'Xë;.+#Z&;n}^V\y!gdڿ۱> ׊BT;zxPtGO|+v#o)>$G"؍O~*r3&{a]lJK?QzW4.)1j2f}If+z,k3է=1>ܜK/Ks&_9nn%^7/yQc|{ڵχ^ќ~a!u`Mƌ,X21=70gO  $9ح H-{G6,9_W\z޺uOOC L::,Kn;i(+ $=70gu}Z $oy7o]d~{}c}[dy-_>M6}Ew:c\HV&X7rѹ _L€s-}}F[w^U3os񁹹N>v}%Co坺q×䵜E*7t_:1tGei-v9'n?Etɷg/~d^R5%/n͚lN;͛dGKmOJ>;W$_W oH"OV|68tK<;:IXvy! K&^U ϲd!gbvW^\vM 3N웶{ݫ'_q_&'/uyy!u]N^tmgjr[&N濜,4VO>9 N~]''Sۗ+U}}F[7$60֞Ja?S#[&j͏:CrfȐVU\;wȋ ~98tB㻯{ՐR}t(í.<C_~ye}u]ƶh+_7i~4yi{W.kYyLF}mNBinZi?0-vl"3J;͘pgGrζNJkkk۪:eYc~mސuq~7pv>|tp{k<~VU̸IDAT*dfsK+_uֶ{&j4>{sģS]瞻:_?$'^( XV&tKo~R}SFT3f~?6~ 4_ןwɟyåOeGzk>xqءzikޖ{SWՇ[Q>]V Lgk7dhm,tn?L>;V<wTCC6߼8M#p.ޕxNQ3B{~*xz_-ff$6nՔصw< q?7IS.6.x/[yh_+rɲ^{y@;9e;skS˵mg!/A5_̑a՟kbd6^~E{# 뮷~UW~tBi#~a&X$48p]/^x*KN凅v?t?^d+ߐHзy_[Ӯw T+MIw^nnZNb7%S#6ߍqBNWGd-i9Rz?W*biyU[7kYO>%;׽YU[ܞg=s~~o^S5aBy}cLQU,]߫ۦ?4coJF*ojCwn+]+MG|mg6S{ivx^m_!tYbznCe~&+ٿ<,~_*C)ɘe=WV~VXy͵ׯߴiӼ8$9޷.ɴQY ~-޽'6%l1.)=t-oذa '6?0=}桇2jԨO|wJgޏZѭ7__9G*/YhKCsf|p gP>BL; }臘]|->pfMK$/-7sg^RZb%}y4ٽܴ"0>'YX]:t~9!T׾hղ>#F)5reڐu=WS f[-~d‘G&g>ds1<`dM6o*?<_O'jKg$.)2%v.:]/K;)bWziE}JhC"\-& g,v uRe"֋z}Ҵi֕B`Fo{9GZZڵ^;.M'͹y.gw}퐚\\{4\fMnڴi¤W\+'viR=%Nɐ=w-ᇟ>4祗^ǎlŽ_.~rտvO!Wz?mEp}ugOߐ-vG/f݇RhlGjz{qN!1XwN]0;dr9׽~YeuVl/U]FFojrMnm Xy͚{/:*I C 7t?HHŕrei-42Wz+%_WD2W+A9瞱BV췧 ]SpNx7>'y x}{NϺWhX`VDZ!5U0er|]ws#֕n̶>O*BΪYе|#vN+W W+>{u/,?'O}]sWyG^pur׿>=>6krG$ ˪C.mhzgmWuS}TJO^kEj_T[`O\#=S&O濜?Y[?~줱yGHHG^UV=ͺC7jr;ֽ:[3N nݺdaBn^_}P$[`]O.tNo=xcwy'R7L>^:xZU|peqr/% =/--f:ۡYWS46''Y ‹/vd%[!6pKgV|_{Зh-¸);NwwO{7hø^{)F=KݚUB>u?8sDŽf]OMvСC=`ӦM>GH-IuIZ`B9Ošڵ^|hɓbcR> t]]WSe';s>U=+_w߮ԫj3rAk>eoN膩on}kͺjK-giE=t5D@JsG>}X=fMO|kuxʲc?e>\'g&1:;kw~iXxĸYY?)=O_g'-[6mzѪ ]5@NYs]Mpd:zɎua5w,oß G)Ky]OMҗiXZ VNZTnݫ?egoF̈@WVosMpG> w-z)1d]g?;vۭy~j}hAmڴ)Vwy}F|,No'V=+KVKGefi͓ϭYڕ[:thg';e[ /{ndYyذa=TW^VGJяxkjj9W>k;a~0 VV)U|Ň=蝲+V=RW^M\|>$ +VgT-_"Y]` }sϓN:ȼ?W_}[K rnO}yi-O믿o9x"{uʁhر9_b+VU544wf=ғwsr3 CbǫᡪκuwD}}~qw஻B?1Ggg ƗmOFM6}E/=s$lN;4oy۳/C\_ً}49k]$o5 lcĉ埕MQ%s_29yѬ @_58‹/q#> jV S5!?l]v% O>YUGUT4Ϗ{gJݮ:|@|#bw}wv l)s]g~K䜻*lIDAT-BGC?Vɓ{ ׿ۛc] 2'@|1{wu]o*{>? w~쇞o& {gAhߌdᙿ>hàAqy5ORrԄ JKK4qOr׿ ==,gzh'U/uu]=( =^G @7hOH<y°C' ?͎?s?@Oz_x1Y>昣 67#ctvVo644lneɬ?s~v'5"Cqd)m@%#+Wr! ri_x7vunߵɨӾ0y5kv{_FM?5kjomܣ+|'OIr,V4qg|daĈI? Rgdaʕ}^{=DV6+[W޴i ~)|Ec7cs+mkCӰj9(h|2mڴi9 u;,0 m{g}oUTvFaG?xbCĺuwD}}o~q]wH}H|񣳳cxE QiӦ/~(e|~.0 IHiQ#|{ .ŏ>,kCDͤ/'?+-=|'\%Kbr?/ͺȼ@9@4M?ewԩGM7~|?hUcZTQ<3w?T{/?ić~8D˔ɓ]w5C?T1'M߷~UW~t@t}lë-4 "+KA? Bb_h3ΘqÆ >"`G?D@Q (@H $?D@Q (@H $i (@H $?D@Q (@H $?D@Q wY I0Ͳ&2F̜NGi:bYfiayrG=̎xr&)T#1bfDA-94u?^{clcvq7y]uuyā@q 8@H $?ā@q 8@H bܬٹe W5mrԪ܌g&Fԗeo]PihnEݪe#[;7w:'ʭl j+KZ.oKV\_^ǁYt]֭MwܲIȑY#:1 nln"!WI6vOοw캞Ɗ{~[\w9G ՗uٽVvCKdó?-3ѷ-lhe33[srodOk4 y Ucg-}uW4:Y{GsJks쒚O޴.٣ϭn )k(/d z# OLx ;&mYE՛w?Veue}W6.,m?ovMC*A\>t/sU6,|Q^8mvqv]N_}edȫdm/lc;+;[6+QraꢬhėVmٕUTYqdr+7v}YKf/ZPRW*`W}X_{7c+.Kłau}C#6,ҿѳz*nݙ]<{ZQˣƕ-6L]̰0k7mia.Rгֲn҃NG6TN_~;O+(mUWw $-( @z+(-L6n]}nYCesL2g.{饥3s_<¿lbɪiEj]nqժe7767*/)QP~DsmIA* WeeWϟx𜂒n_PV۰15{CMi9S,,6evv0"{+ kKs/Zס4Ul-?U%8$c'}uuѬ~t7oeCy^]Ұm*j8:sso<{tCD^rGvon޸eǸy_yƍ6ig_؆m ֚qh( @ '8{Ī܌HbsHɭX>Pq!Nā@q 8@H $?ā@q 8@H $?ā@qm+Hj $?ā@q 8@H $?ā@q 8@H $C)sTV.S~DA'̫H5,;y/;Z~Qc):% ]cwi$+ZV?'Q\0|l V8@H $B,? #??#䕡_M}NnA+^ߔ[fgpŊ F0ȉ 0sTVN2ykNj 7uV7⌺S-l UMmYqEUCֽ:yqMᅧS)9lvCȯz*9;S_<|k6]>i[gp鼊d{`'j /kŊBkV\-$GYug'W\S|UFy} zTѷ?q򥃉UC)=|Cj(k[SK6] ͇)xF߬.$漦0]ut%ߘ/lLo\ ,WoNvxfA"\g?Z7iU+CV~OOM|({njUV{Ol姏 M9o{S [w/ޞ|hG'OnoOOim3J s'o#msYͮ|R aR1Ol7[L8s/S!-屗XiIDAT`Ћg_/e 71ŧӋDŽۗL'J'}}h]3<ׇ̺З7% o}bo J*XPZ~ygּ9[.kkv$>&,ȯJu"O|rSËY4%^—3RGDܭoy#Ψ{u/No˅:6m]uD{B~4&<߰ 2{ B] k?z^dOrs@q 8@H $?ā@q 8@H $?ā %C?ā@q 8@H $?ā@q 8@H $?ā@q 8@H $?ā`Xj6֖fgdd6V_}Sư *RmI XRz0EBXha}jk1@z_vʦ' eǝ;A:lS5M#7㮢(/u3+W-fWRY}[40wʚĻ:մ(9dT5nɤNW-,kBxst[N}?T76V]\YTS᥅%yYѬtrl^k+K;]ȅ:-/E?'QRyO\Η|ˉJjƦy5}웇pa<5y[߼MEmE.{\:_-JœSaߟ DRgnñ?,Aye]WGw]]mCs3}Q"mE99'gdf}굡[?P" 1J6۷9Gu:]/ؽEOn'VFˋ.;Y[ yܻD3g-ȡ4{{]:<:iu2Que=zΓlqyq&Dw9v3:wڒw@ѾCf.k..S[Qv;_d\X]!쒚[nI=҆()ϟu2 ۯf!v:-bN=0/sZ<:/ѽj ']Ć{ݶ=sK-Wԇ>/m͟Z>u̟[V2e[^Z63u;'/'#Z;T%Jdszb[PEz'6׮;NΗSPКt㆞νӑ ߼ J/muM1VS]M5"77Kzӻ{G-khnI 7ΟuO^TQ"'7:½@ qo_vQi*;Y{YIeCi*.kGFfE\^چ{N!Nfz'3]=zkO ד>\A4Uv/_P7̙^ziijMv,҂/{zwhx¦/\Xp]%M}+zaWWvE[sk]`(hiizOSuqgnԡg̥WUN"k;Ӯ{4UV[1}q#GZڰ8kUy6Odˋް-Ͽ!Ҝu34b4N$z9nʆEiSF>q!]͵_g\Y\[H/7.~kce¸__YzluvmݻS?rueo䋞}?Rn|53ty;{Y}eQ۩ԗgu㺻Ax;M%̝]ﯚ5mkr=zfղnhK"Gv5If4Veə]=W͜#ZZ6ϟdToxbhnEIDAT}ȢO,={ڸͿvܴg_MS{Zz>dU5nxtm!3SoԜZ5+;|y̙7>5qeOlhh&˞ݛ[0щ[lV7~}]RӴ!uYN=uͱk V87sYKt2<C$;###gdIj 4;#=# *4~jvquSKI4/\.gӽUaم~*@LHPP:ktHψ#g儡g1!nx>ā@q 8@H $?ā@q 8@H $&>`Sq 8@H $?ā@q 8@H $?ā@q 8@H $?ā@q0,_sT֞p{^5iH?ݓWNnI?z2 M6v$!՗=& Mc\C8c¼G^n^tuͯ.CocshZEvG'YJ?qYcV:¬='_65g ֑ќk 9OLYs_8dl~۷ݷ"YxO!ݨ ZGz6ϐmz:<8#lݵct/5mkk_]ɛgd}#_~?q_ͧ,9e#I-N1x̵l;5DX|߼WS>ٚ~ڜ#Nu|ʄХVb w_hkf||Sf(=&hrꩉ'%ymOӒP|cr#'Wz3jOK>S{Do~9y^'z0[Ϯ6[==sq'pq>o왋V8@}C+j[*oMC=rc}kBq7/ K.+zu56>wΚ(&lR:ZspE{辳V2d$-cNP>!Uwumvۚk{53d)KUխO~|ƞ2^%%n3z,=*7kj}غlwlz䯋 ~W_n}:! ko>kPqu8;MGVg$צ*Xζq_UA/JT͎+pv[cȊoIYy_C>-&&|HdW[V{BG1YOkM.`nn_wx]_q*3yF[^I3L9`}7t2.h4U*KxHhvdljT7̕kn!|5ϻT _w_U}hO/ݺjա_?tZ⺡m.:y&lO~(ɍb 'Y6'G|WyMQs=3n~5gږ: {Ec/ZMƁ=bҨ@D]ҚyǬɏgv*$#VϽZ^䕧םk폎!u~^5i!+zQc};ܐO>+ta~z= ƹe7/'Z}n)6_V՗WT~n觫3\s>ϻ=;o^xps2wV '{aE_;9Mmw_]GL`o{=}ɾt&Yg-趷S>7p|}sG?pݢ /z;- ~+WyCSSUG= o!vO~#yBjj}=z} CˑW^YG}tMα)3qK6lܘ==c8%=3 5Q嗟?zO N1o=Q;sԨO8yo,<{L4= o^kE#?4Gh\~T@g9(;nsyEo RFFA{_>|xu_[C=3#zH oǏ;g=Mb$++<ƛoFS{w3 >o12@цj_pN Vyٺ;:~zQf0(`3;?o\qmW3 Mhᴰ9*+0]09agXsцg~_ gwkGUp≟xϻ~2joysaxOywv}~|Տ'=ﮯ?`Ǎ;t} }ru /ַׯ{gͻ!vS%*R.slsϽQ1>7Oo_3(Q8)CW|?3sfH_c7lظaÆyGy뭖>$֭_}ݝaGy_꒥K\uUߊ^}-a{WZw-_5NS V']_{12ke7O-;CƼlٸa{ʛ_~3+{+j|ܲW+ZV?>yc;kslQž~_:pgjӓMk׬}Ϗ߲xsw;n!T{Ƈ*8]0|l0hQ{7z芛*/8< (D|q9ؙ^xZ};_0`ZjK/5<_tv{Q}#g̞q9W,Zu> ş;޻/Ԧ{ {Ϲ Λu}׍8S}k 0?{K+9@_G#Fs՜eƵ}[Os%ƞ;ʨGE߸Ǟ{6{̚:칟O[؁>vN-;5ϯU̓^|%Hy7wc{wj/L'oV9kYa꼯Q_5 rIDATb-[VҒx X2a{^q!m'v➣ `cYoCۂ2O@Tk%om!MTsnWڷW諘'+WJ5ms%gPv[yѝ:ssox&lCj;Ady-^xŦTfdϨ~߯xp+yyyg_ظ_@<[n]1 S06;,}W^z[a(/lÄ[}sυ͆@~kˊOb1r!蜜q!~93s:2=ll{Xnٸq#zJ!`x0{ީSܵƌ]w͝;7iܤq_nc^x[wnaNDXXiMz-ɍU/-8 D/h-?`jݛU\*Q#{/y3y7{uo5LOd g5=7Uk?ە'egv8y!{v˭wCBǣZ٪uw/f:里),\W:טּΫ>!YI = Æm q[]zlX|ۭ]9~+Q{s}0?@}0h (Hz i\mm؂-#FOXqWd"%i{BԺ}:W|g'|7*ޮ)^ w%5?tMīevv2BKLԂ]yވuפuU#[:Dӄ7?54qznONfMUũCfSsFaW7E_4VӴ I3jc;XOHJ6o٢$/SRߞt.ܷ/鲀cCXݪrr6 gT|m*tEQ;:Jر_ْ%ax'c߿YXD[{!`GaV{[{4vyQ!$}&Gîw,~y 5^ [W/:㩭n<; ΨxA{SvQ|xzR;?#@L^}yE>%X5ߎuʌ$ Z흶2G|aV|'[MO/m})̲uaD:-Rֵ=_ɂkvC:Uқۙ]09a5^=sOo_{zTczȶ8.i[|%@j}w'XjMrBXL+[Sѣ`r)pf :7Qt{x/qB+S[bd$to֜ѺhXyܽ;{qk }S{k/M6ڃAl(Y}ͩFɧO!`ۗK ӗ5zjN`l\~UqmaFa[mʭ+ +ZQ:lkNJv*Q^?⌺CH_C~(z‚n ']iEUMo_3;fKoeHVE_FNih;$ &J7~HuCRڲSFgVEԺ7;Tb"#L\5EV]p@eXd8!ylUۨ ?5Ooy;;k gd߱ݽ0 =(Y2f̘QFORtn׿<;=gY;OK:}Ӌ O"ںu1-EAZWl6uj:Ki;Nﰱ gomC{]]]N_qkKWֿr3fU|?+W\?S K/c矕歷~jS |QFV:+j\ ;ذֻCzoz R/V^{2 0`Μ#FDZ,YzYߗ/KԈN+xO}}s」F}s7_Ko.]riZM/>bSq{/0gU5%wF~F~K^cƌMt-I?^j9諡g߼\p՟ [ק6ɂ̰k%ޫwk=y_孷>Q^]s>Һ7{_/OmOs v9c_Q^oǷo#9rIu;F#|0VȊG);.߆ed--eÇ#/OҸ3 '~x℣&|^tlǢ_jgw[ц{ɓOo}C|W O>ay^}3`;j{]p'ep{T#J5~ބN oYܾ'X$GYÆ o[i>SロpcSӺf vateXƍ;t||7 F}5*[oU{{GU`պ g:qUN6N J# 9T]pUsˆG3}iUճ kA*;;'^y¹WoJ42\^MӞ]R:_V2ŋF6Ԭ޼!l^>^ŗ5Tν38bn6G;;t00o[g]>ј6oѿ̮OByBfaANo.lm1{Sȗ2ZZZB-͘(wu֕)>y֭bemIѿ3T2scbA*^JԨ%DЗU\U3ktGzQ]<Is~eֵn*ZԲ0iZ8MFK  ; sL6[Iv嗭M4F|bO_j-زKUN6NIvsޔhd~dd&+L6[ YC=0 9%pvv!j?ā@q 8@H $?ā@q 8@H $?ā@q 86{x^XSq 8@H $?ā@q 8@H $?ā@q 8ߒ_,kzɧzg~'Lg|;[FKKK;^{e}t}g|i_cXRدk% ZcHf7;P{7>0!駟'_EÆ ?5Qs|v-Ic(-m*1rļ($?/yoO?y|Դ=]J}nKmk󙺪aO }3b;.=sCmcrE Z+X=܊ ;[w/eޞx!Qc̓kxhH~685ٸeŖ`wnaN賆 ѣꐦ%@P{{ޓjY&ƺ%ñIW}٣XC)4)/+֎;=ړ`k(%'T7?Mχx /:e?_jOرRw1nj͍7_0󂖖m3Kư? ~YoV_i~%j;Џ}Xg>ɞRW_nNw6ݵ|yOHKVr M{S}mG u{^XJ5SWjWS#+ ;GSvvb?NC/ejGx`eG>񑼩y?kH) n`g  aݢuՖynecw;;/'7/WۛM 3z_fHnT#/7'HcϬFf;Cevi>N;"++H#n-:o`gHmg; e@g 6HZ8vպ -9i$!;gtߜ*RvvN9t]tv"/+u"/N/ޱ7/fWeg"ڒV6}vH+)( [pѺMnY՗i! ' wxY}}P.k) e`g &ҩYV¦L\ֱiaѮleQuKr]Z5 %8@{:+:nDϴ .Xj?{ߠRP:ktg3S9IDAT qV8@H $?ā@q 8@H $?ā@q 8@H $?Ak޾Wf`Sq 8@H $?ā@q 8@H $?ā@q 8ߒ_,kzɧzgN^{w:蠂#?4}z;DFKKK;^{e}t}g|i_< JY_ʷ/hĈa{^KU)Owo/{UUw'?x|A?]xĉB_w-_5NS?xoQYƫ/776lpǏR{e>7.oퟓvW_yϏ][jO\|R(+4^0|븴罽!!(c)y7U>apb蔢I_J߲>Qc6N ?|j_}5PJnoRڿwg$?%w<26vWֆt}AFl}sʕ}`(%VJ5?^0_XQ}6ᶲ4sbA4b+WC)[n]1 o1-876lOL׭{.̞w)w-_ztؑ !t)1+}iѶ dOQ?.>O.W}te( N<6,~Z2bikfxڶoK;'*:q'^Q~ '^zi]Ң7^#@՗l_˽=;C?ƚ:д 9.i95HFeWL GfQOÊSC?x/?/ΡᒶE>/S~J}=I5֬ZB džKj mPJ&MK5;{XnG5s;级֥'C);Oooz>Mb϶wmen~e]{鵩Ƈ8bh5 {1sz7_0󂖖m3K*K7nkD3xmY}3vm}~y >zŊ-YQG_ڲm ZjsR G tb1j"SLϯ~%ծaGV<6?Xh3++'8J5).=<ʨģOO|$ojOxİS5=p+Cn_㫽s~_sߥ6-AxǍ>Zj)5 ##0]~`U|҉sC>8 bo+30 /kU/)àws?}v„à'$v<ā@q 8@H $?ā@q 8@H $? qj $?ā@q 8@H $?ā@q 8݀Q`A 悴 *4T6`Y*5XwAa +6( k ]HPT )6TRHhZĶ?%/ͽMd>yy=Ǜ4W-1.(oh˸{I0}+^RUPU0חdkx]jzV)k-/Ny]4BH׷7kGv& qˎaΝ|}Ke~ θe`G瞼AGk=>~ʒu]Eוup押L+TQ6Cʼ =ciri T5577ش_CMإ Wns?ђᅆ:JAߛ}59W5EEk/9h,r햞'hUzg~ª^-f\^鹹[6/O'N{=bC|Ʋ=3n{5%C>L[r_cuQWo/\V_dn8.PQ2 N:Ζ5F yi>Ȩ14t~0=>,Ib9}qU7o m޹dN%Uh+>(uy֢ܶy͋fwm>kח'9I/|ݪE=X/>*~a O/ʄ&cܓlkΟ[3߯}bz#mL?!q%wo'4^0㫞y]޼3 C͕$}._ټsS FI0͋xbS_Ԗ:פDw_tWl7/Mɷi0*Id>?bݳ7_A5vomH5f~’5UO8W'Zwt㪏Ŗէg>5fy(j=?nk9ߍKqi~i5:;GюƲdZjݳ}e-gw7{#;^#j9%=oVU%,\4>Z\^7b]9٨95'/8F͞fmkK'+*ʏ/nlZe'J6润n׉ v,JA44ɤf+hhMڲa9HaЫCe beui ώ`d`2a7{iuR7vޒؘzn]5ړ[[)d$è-O;h߬X,e{q]{piI2͵5[kr_YdV02i~rPE~w%5zӧesb(hIc0oE]ـK5]mjJdeer7k!Y<̊_sDKk,-_ZSj)d5E =ޛKNl{¹Ɵ{+()mhjU4fWSSڿ+W$&mmxZv-mmA&2iwA˯,z9nd{NǮ tskGaڐرa@|d`R霿jiJN v\~dYKk[9^Svlڴ\|)s$%VZۚU)첒AҒɤ]tWҖ?u{E!Gs9%u7r 7/̄%lli,\Z?TA{w/jXyۮ>pfT]7-w V\Ƿ-k4@YiҊ-Cnd{NǬ -v/Y_Ŀ56Dۨ%ɯlټnՒO6rEP8bycqG׋M î5 :E1'//#ޛSRĚN=;)}O7Q&.;xavtŦ.5ov٨%6%;ZĜƖ흝6?֬Xr[UU7H2X^qC0~2n/(}mսߙ5ɧl묢@V0HԐ秿vi͞^+kjL/kۃL'ߴ}`rڸb?LR"$*_~S[91fnW,8W"#"ǃwSSa?g4'1g '<:̕ߏYtGpY#tQd^1Yfw »o1#27v QNߙa`:$}|?y'֎ßG5V3?W,G?}7}9_>[w\CnN߯G%{>l٣[;Qukc4G{fpx#p̍]v?]xM|1&W ux2t)Y;Jݲ?qUGÂ1ճk^* }>qč no\1wAA$͜u~aQɻahaAWwvbv&)A|'7<#s$^WK-wXPu~U]G}> +.Ypˉes* ɹ8w|f?bO\zi9]+v#7=U97&~.jgx0?%s7Җ`3k=13-wYlXg+GW7 {8CzҤO6>=(k|vi39^bIDATclQ_wO7K*?_~/{jN{kqi+G 믾`O0:Ɵ`M?_ ftiӗ.=}w%&n ^fKo)c~_ CQ5Yy׃+4SN>?u"lRx}]xAb܃:(^zic?~;;g͜1t^Vk/ +|~ÏӧM8 ^y5=/|{JN:1Fc7,9W#w>SL ݿMo oxC׿>3Sg~X3vc{jvX}F~8s Fl5A0֦{λ~|mƶ:мY3gpOvE/ov=a`RLso1;{3|{{ }O?y;+łq'#2H 9cm}uYur }wx{W^yw?"??Ғ?x s3. ^m۷m@ #7v8`u6tj?Q+4}rwY37q،wfdz}+oZuvεL~Y CN1x`#{3ro>` I |'-<3/ԦpkkCϫ87&C^AvՏ{uCy d'`0t0D?_Mn7m4Mxvo˯\,& CNē^|ƛ~_>փRr{ 7lْd`2xfMcggg1-? vEEYcg}li_40ɭ;0{zYyjVa̕ATqEY j vtE<[Ғ(_Ӄ-+:{ۃog~aau;-]PVΌTfnN]l\|I$&'6mJnuQ;=8hV0yx76bu/88/-_wpGM=LLZܛv6}~@/gڹvgQCq__OD2%3MϿR˛9c/{ҥAfϝc{nf8`8 'چaj[Md&v*:oM8+g>u䌊dsg..mOrYP{iҧ߽V!+)SZs>+OMOqŇMpJ7] q;>7묔ksJOQ=.[{%}.Wsu_xXi WtNZWdw/-,gK|ܯ4_;`&ٔ⟥^νXVme}ܞwSH,!'ϵfx8n~npNaVb_<\)AS)6?#+6~nZ .I]z裧 }a[>l`fa;8kٗ<'z:r-?Ե?0h dC^Dº .kU_Yqs gex9!Pݵ#! >.Vcc}wcY7paމ wvp{ɍOcoTVYq0 僭 WzEq|1}>RWO2K-VJR]abxB=ĮwN>-5g#}tܣ 6ؗ5DygyvbJb|tꀵ=^HZ% ߤ:Bơci2mɍZ 2wp^A=dhú ɍXnn0YX8segyk05gS|ڙ]sAQVarʮ)L.給{sʺkze&~:tFŗT frOYyaaZ~k[~}o?<% *6Oe#~5C3M 27&ᔑ &pcrS뮿s 7fk _|3 ,9oQԬ.*rὋVOsnG{_+ ?[n/m첫/t Klhj}_V2{凾~mg{/]3/{>}mp]˟N~#XÛ*2ɔ7j_bOٺu!_uWPƫ=s]ǾQi~}.g}|0L&Dt V&aoW2t[V'}򴇌.wLF_sڴig/ 7€3.x>'|fI[ |]YiݻO]:uu0k3 d _.n˛9LkӜs/V}*ovʙ'k ?/Zk fyh׆.\:23%+*/~}q? -/}kˋESʜ=oOmJ TH,9zzsgX0t0D? |Iϟv-~Õ7;qyo`y˟CO͏}{?P|BK bwDf`r 2~wxӦMۺukK/ԫPӿ:mKk^ M/br-o~s سE8hq0xWO&[ӿ}$Y}_ҺaC0.w/{7Ӻ?CN8+<9ɍ'69|o_ӂO~ʯ};cx[o?8a &s#UuK.8$ߺUDsهDIDATWğh &S(7G>0sYɍwo{[`o6t'L_”_}?(v=AVggo-‹/Fuj˳b0 0&ٜ~~qӦygrIh_x}ӛԽ_c@$M{~:yyx⦛o rpvvvc@TLZg~D쬬 *ZzW_ d &7p>c~G{O;:w[?+.=xw{=_@Teuvv_^(yƒi"?D@Q (@H $?D@Q (@H $Y0əQ (@H $?D@Q (@H $?D@Q (@H $?D@Q (@0PkMQVVVQm[Ўh,eek:k_[M~VRYc䎖갼 N7_ih FhnNvܵ. ;فj;]kƱm&l{'yɍEA:5V8v-ѷ4$ AkO;t4oNn(qh+Ӯ}hGlkjw~- bE#]k=qX3'gjXNHOϬ CSmSrE7ה$*V-LްyIgsbeȤ t4ׄܳݐ|{*}wZRfɼ,56Mi$X,6;k3zB;ZWurv~y}'n^6ݶFxy#28uPavZY0+;](gJPvT7oo*wV>Dtq&R{4Bl;_-9VUmC؀iyuafIa׺/Z[+otq{cE,kDbw.H@ji߼'{"gBȾӜV ܪO7i-Q.mc{:f( 'HB_ˋsyLH,Y}gV=1̪켒~gX,/ond2Twզ`D6]UdR k] 0y0R;)(7^H츿mD4e8Xm=yDIrwcx̪{fUה=mfT5z֤ /4;V\ض~=kGԿ7W VpO6T3 "0{0d`ѰWhXn\S^rO^RW$o|'8˟h İq{{SmyYOPf7f˲NYpMg}I0lo ]ٵu/9{Ѫ =%mwn4`t +1[/9S5n3wyIze,vXXEȾhHL?;飩ckfe({D+-ؓ ی{#n6j_BYW-ü׳7[;9k{[y^1BF܎MuWmYk 49E ّ8(:ôm 5QQ;ih L;m= `7/)[ӭV,[ӭ--uɉ2{S$'A;;r-/H5>y=1j|e]KGXbە~<1Ŷ_ڞWZ9o :4/ӌ F$l,>ӭ8%je{Dg__÷cvIm{爴ז5}fQ5FIJ\wmàiU^Ey%fsv1Kӭ^{ZGOٙaڑ4$fQn[{`XkY%kL͌f`"/!;VXrs$TYݳ@3#Oh0t./ ,Er.VeF30M INQeC{e͝iЎd">e{])k 5hܒ?` jOr%`^ei^@R+E.*/Ȝ5 `> $?D@Q (@H $?D@Q (@H $?D`//m ޸ (@H $?D@Q (@H $?D@Q (@L|=<#O>Գ>0>2gQ8-`􍿼%~S~]||D'_]VܸªtW^yYQ;TO{_;Ԙv'oi9ɍvHl۶|.}; {mmOZ}漏;c~rw #cm$`%am?5ɗ o>v/9{Z/?YYYA$h`Ruw~e_([yJn 0?_09駟8ku^{M2^?c=7i2`MlMmoje&_{'h;d nO=䝇홚=d--3&zġ?2?50&SҒ8#&/e]xLߦMG{Ϻ0>Í 2UxQcFP(Tx QǥM wS1ߴ =~'{70Ƭ}fA~/d'}4Aoo-%qQ tG$7wIDAT01Lvg76ķNZWvk/(7zŇ?~Pm7h34~c ~=5`Xד d`8Cg`A݀3[מaFb`׮ 22kμ3K`7wv8;=?=sd&p`_l{;~dhսCg ]p}85o]ך4 1, SiT2T򗔚Oz=iVϺKvvNg^{s6K}Xn+<-HnH'mk0ظ_k{溒0 sp#prpMaQ?\>+X]1vcVԐq7}c}?~K؁#9+9..zC`T AQ{5[G?0&ӜN>yy=Ǜ4W-1.(oh˸{I0}+^RUPU0חdG|kx]jzV)k-/Ny]4BH׷7kG4 sV;F4vc5 Wv oqˎaΝ|}Ke~ θe`G瞼AGk=>~ʒu]Eוup押L+TQ6Cʼ =ciri uwNMj.`:t /4\Url)Ij)*X|OE/Z~Acyk=aEK};V57jW:iznM Ӊi޸zX|G'_w(9pMg}X][e ״՗y3 t̽pCν8wMFG{/`i2j ? %ͺKdOӈߡVSp⇺wNunC1 mHoQ`< =/Vְ3r?jmaR; w<uZt6yѬMUTg~M9I/|ݪE=X/>"~ ~~U&<7垼gG_s`T$ݚ~UoWիhc +Y,{o?_Ķz͝UU7jOyN}|,?az|߆o~W6oܼf뼂R;»ϝa"+^姾-wuDAIQEՉVF|©]\ݔ|;V D>0+=:z5KNXYcwֆZSl',Y]Tc{zUz8oIw;x]lY}Jy}\jƑwMSV|<ގ@^yS#X>9)wQsDh,OE=۷]6rF~w?).SR^sRөTs͝jKe.1fw`wkDž_[sTvzi6Ɔ+κ+5kɺD_ZגeuYUL=ydXqy͢inIqҬLKUU[RWXYK_RsKzdЎM?aĕW*Jc=\[_f,KMmA&ZRN!cŕMͩ|hqE]rJ{**,:"9'.tҧ^_C[nֹk6'5WHmmyEE9%ՍMwe6润n׉ v,J44ɤf+hhMڲa9HaGJCe beui ώ`dO*wʦN)*O^M?:Xw+w`a7{iuۙZR;koIlL=A~mɉ-WsaԖէoVv,_\VYSز8>DYښy52W/LڱEߊKj*.)OłQ\l`ފ YjȻՔ^-W|3Tw-ܩ uz=ʛNVSΠ9$.ogچXEs jy55,qEbφږ.ed"ޛvy⫇8F7t@WO=v _kG fHĿ)]uErc/ޮlsv)9#q8aE-mk{M۱iӆVs Jk[3^r0ʴ57%]V2H_Z25?c_S2ܜzr4sH=DqCs9%uer {?3U\^(acKgngiޢ݋Z&|k8q}M7&mjlj Z7.PVZX*IDAT55M"OQ twś,0 F-+(NN f-Y9ʼ'W7oܶgXfŒS?n2^ebm=j{s`d܎_^QQnǯ6\KZSzWҖ**zm nojH|QS_4fOfT5vt&_M^A&k*nhj~GW-;ޛ^T_?X.ؐ(/HW7tL@_tMƥ-Mɞ8(ȍT](|ǔW}fwGqcoBn6j_ePYx> m7{zw{cy,<|5J>=Ӊj%g ;܊`e{Z]qUb %g4ӱye 5u*O, Zf] R뷭_\Ŀ? u/LQFoϞG=M5%9񻞽V?kmߤҒǷ6VUmoPR0s .j &lz.N}y5M]Ƕ6q͊CT[Y#~;NEݡM~imK{/8/նukϜsrJ뛗oFx7睶:L_T_- =wYu-mڥ2-O/`ZRquCRÚ 3jte{3= U A2#o ZUMaW#c7w͕c9\ՃFCa'hjHȞw֚ԓW5S,knI|Uc= aHoQ`ޜg\ٹ=krN͝s%+֬{v[Sϼy2=%+)X=AKu~/ڰTȯn #Fœ?sXJOvQMk0 MKַw406Zk+oFAU`= `L.` _gm]*jkGM5D.0 IPT(7Hy%y]*+75HO򢀨&'(@H $?D@Q (@H $?D`//m 1?D@Q (@H $?D@Q (@H $?D@Q (@H $?h3Mog&+NG#Ro?LNw5$ApM/o`ru޺_ enXt⪎oQMd&"ǃYj]笟$&$s{ݑO%OI#ev,ko:2,scw +aI=6+ɮ.9&f*'G˳ G7nb OI#L =%$ kL F#ߙzkHޥ.W~mx9ydɻ'^h'>A0>|ł|׼|'n\c~w?tOy4Q£4d܉ׄҹG o8mG,{9Y[=TwYHr獧>w bptgɎG&p ggZKO?\#ߛҳ~:s?+c酏1aj7>:3\rdrʇ]`ݎ00ȾщgUuTr~މUvm>h^xĥWoL=kS{?Ԕ'75:1g `of}v|큣z+ K}z=~쁣ϛkýλO|r17vMKt&9at캈o6>/^W@*3g?n  *i߬={SyO|ꨞyg&&7?|ỻ;:껟]:p`?~瓿dQ:sU ;yr*'D@Gz~r$^L wXPu~U]G}> +.Ypˉ8*k;>߂wT8ĥ̝ӵaW<fXscr_X炡vvg vc(38󧋎~?<߼;:f>?Etyf[oo=4޸b xna'|o5Os>yܱE?/'_%/ꚸ~/{V_{kqi+G 믾`O$_Һt’}MsXşzWMziIDATߕ|ejo׬FKNoK{ʫ/{|[ OI2=?ӟs. Wxҥ +7 ^fKo)c~_0^}_{:>eS) )Ң!ktp돿^ugrȩ.yӛ&k;zpݺ r^y啦~~'_xt r{~yؽ&jo~g}wtP,=Ihk襗6m'vʫi|y{Sr҉XzVx_phエh~Q>çx{!FW_LHYYY|;{SL c(= oxC׿>3Sg~X33o|}<{,8 Brr;?Z㐷-oys0=5; rAgΜQgmR2}`B2-?؝$hy~;/|6Cf͜YXXX| (>!M{.ª`ws?kn~t}3O?‹/#=cM97ܘ=uG={w~~`\|ߎb%晇2{tPkV]oex8e_?1-?˪ކmzW^y%[}D~~s0^ˆqn| mm۶bزzgߦM>{?tW0^6o?tߩ]俗=u։'8~=~~ZO.6ۻ|0 Knov/T.5_Yy{=3#;҆}?O=C>tÕ7{nz9utKNn|鋕Av ,NWwaDc'Tҽ绎|itڡG:󰙱9˹mo~[~߇{MOw+~y_5?c:7 .j`7ixϷc7TYtd0݅N>tozjS۵xǡUL 6Fh}?U_L'aм 7|J?:L5Nz&PuEY=F_?g]s?'//ٸ`[rEݣnڗ~M͞z W$_m-'}ɍW}C)/~|˗c?~}}}r_}q?xfx-'/7 +|AKnزeK0i]}w_p#/?>^χp+Wo͚CeG#h0{}쬏7m qzMmʙYz[wZQaVԬ™)?hhHn}l}L͂nSܾG? %ߺF|oYз`ۙ_X3NtzKW}&{.(;‹/' fWf(1^Gmܺuk@'6mJnuQ;=8hV0yx76bu/88/L vR ֦:ɵk;o=;ܛv6}~@/gڹv)#쩇uN˛yg`+,;+`x fOwjJwP cfi9{w3쳼3f.]i;=!`NqɍߍO0b% uôȭYXT|KSJnyn| oz-u⻓Sj~)= %N|Ϩi]w +"8ħo˛\kRڮ;(yX첊D XE*sB첵^>+uzڤAn IOqqnSS>bh|ΰ2 M{km%v^^ z}Tm}9wۦ~2y_;kA+a+_4TW*gJe4ѤsAS /ZA)k5xSS*40._VIG }ሺ^;G;;̀Ǖˏ+xFG掿?^v qA;4/C|h_F<'=2ܾYEyL͞LTkwOI k;?=yMv\{فM 9)+M AӃqu>أ"3>rED]0vSɏ輺xSm %kuYXLڃ&WoӍ͉_km4yJŁ s=X[1}eV|-$?/-L^9 V>=~nnܙj>4WυmOOI4ІjG'9x5٪a|d k/˿:UkS!˺t-?ܵ\m} ZӃOp-3i5)zׇ*]}K+pWC_{ػ.}>ްZSDۀ+9x8JTUX~JsعAS)mi.W~gELJ̝*[ 6cöܯ4_;`&ٔ⟥^νXVmz}_VW C_5\J]_rkw k2TKn$>qSp2lW `fa2lWok[~kO|a@XUڝL\yika]S ϾKVgj5[OǙrg9@nln ; F A 0{yk݋|nüYw{ɍOcoVGl@>?=0_{F{O\8%/=YX+s&Of#w_ Kj.6ôUU_,߳}t>Ab}YC>ts wO5tWYךz\{W{v)u`iC~g'$}-LL|D.[b6]taVcuÆmmlalhِX'v-9h;1Vc-;8 Zڞ 2a]&u,77kc< gvߵHh Ө}°% W,,L-SJⓨ.OZ )+O=Q:L4_u]UÛdio$L.t]l 6􇧼ֳ >Z<4 )L.給{sʺkzeX0-?\C4jjWڧإ_$$S0܍W)z/VW出ҝ k]s+YԷVg}BN{Dg7>d_XIDATۃ`vA?ض#= Uq4VF٧N){_j]KO N3 t'{ hWӵaj)-¬a_}.mOZz1䧿x]EujiqYnǟrk$TjK (fP 3/4QW9%躐ZBjO5}Ove3=: f[kȮGd(m5D+g%Z]Ӗ̿x%J^c+N隸6foC>dsŋzw'+dGp.^Tx,OWW\9 !*u|SbZ]9HWI )Cמ٫ku/S9g?0@ʙ~&΍gc 淏?{g$̚5sxㆃA wo]tjIuƌӦM 9yiKܕ>5ɍ/}rlݺYʺ+}(?.c(=_W}'~cv "%[[_֖S^ݕ99{zn=OD,*O {H=p~rm$ƁR't Ko /%aw՗xЁXM*{/ >_8'O:_s?oy'Λ{#=M?oC|(iѵv_\yOHQɥF%M'3=r+++1^2eʔ7'4i܂ťs?czב F?]K/'wo]#_dw`5EVeMup㥗^JyeuYuo䓢ZVV%5/r^|11}`ft4͚5>D[/cxǏni8C4utiϟn.xaw%d5/HG}ŗn.A^x+KGї^z)Hߡs]_+*/_?W-陬=NKP? 0&Ӣgmt҉>p7/iX'O?Wf A7 ~W^ɠ_+[K.]|g0f풋a˿Y/Í OyiK0ywW]$} {O~s>sVx{=md fgⴏ|AAt5G{8çL0o _s 7#{[DZۓO&7+c$aAkw@tM9{{k}͟:}3v7|sc0Z&w‹/mo g{D;4o{DΎ;^'q0Z&jxMM>X(76ox~??7M~xzwGN:{ᐺL6۷xqYYYݽjBi80 7Ow;/7|PEM`m۶;~$ƭFAź_u׷op^{u{c`Қ=#ggeeQïZ0N6mZ׵{I<pO9آSGG掎w%Yp=xw{=_&#<>ǧ^رcGePg}޴~p;qa+ؓduvv_^cOFf?D@Q (@H $?D@Q (@H $Y0əQ (@H $?D@Q (@H $?D@wY?CTN Cnث@@@@@@@@@AGكbgm:4{m82Ǔ1&7Ԁ:MkT@54˟0 9icuM΄BX5~P6MR$v5=wc)YGzVv^~5MMjP>dH_.PSrd49{_^a˪uҥUKMWi:x"/}q ƌ P */PӦϸ_>rSm§t !{o1n),p˃c&Tis^]S o)#&%ed啳9Fd+9t̔8;}F~ 2̷7=khf:.w5+ڡޤ`aWV\ؔݖqs8(n\Tv]ܜ cFZ?߯*}=zqLTPP}6O䊧7ynwV.ybӔɻ;&㤢b:M;6{hZ©FW<.Vom<,TMut+RN޳pΈ͋^h9djazboL4}LfJl%Jzݹ37_ʎs{ۇV0"?> ;z׽]~!Svܘ1]qn{9q}{u׫Pi/tQnĈuvEkO[ܑbB^ظCNVy󄡱oN]q+g?Z@ JL*;&3QiKicN,ZGg jGcrөQ,ٰ܂2{zӿ?.ҮoZx}vܞ#Ҋ#2#f^΢{S2qb]ϛJX%&S^teoIb"ECľgX5~; t/zjuHꗙ&XWS^2Ferj戜IASs MK)>dE˲)Svn7:#%_?32-t9;\ 'vYx99h+oSY8}tiCG,ʧjOY}eu;IRRJj~#L]9XR3nD7 mh֘O\==/TU>8@Bc3fL,3|@jQ:`h,[6a.iXJjOܛ%DQD4td֔駔;㺉FRrjjZ(Rʞ97Yrq/oosx2xM*;wa2_¢9yYU^bz6b\PUs+9&L_]jjX4'7TQ^>Ը@"S3a\lKN-nK:⒢b٘19;qDŽA;\*yݥQrٻfDCGڲjբ'FRžerܥlNNQm[ZfFMyӧuG'۝3.^唫% ߴrnԧSƥV=c1usf'ɩ'o UTw=)x*O6O`qMJ&W& [d!߄SҧS]Ne%I1ُteҤUO_wRƘ@]ڵrr74{GNbB97+3sUv4o)ީ47PM%InoĸܵQ>r—gHXFn |u9QT~ewm;rP]3c3Mm[nNYU32SKTP B6{hjRR.mlTn~~t˅!_yiw'z >fz?S AUzQ鞥e 2{~̸gsQHYڐoGcQN2R^VF{evo_د,;- $rE[Pk'(d 50)^ơM7~UƏ͏=gc,2yF?_L>%ؔ7ߴfz|?S AU7.1n[FYT>$\ϝDaC+6͛3nE!Ǒ2g) W;Hp#)5TI soSPm/Cm]<ẉd/sgFl%Yyat͌u02f\nO2fp*y~ءic- Q~fdËo~옜%ioo3=O59~Ӛ LTPP[c~Gu5;wdI 7}dj;W|HKy܍Bz޳0gDڎbكOxVC7 k*O\lm9k+m^;&Swtquef}]3t=v}9Y)oھUΏk*)w{usR3TP}R2ZܸU>Ct_$-gyiozt;b*IxөefK(_VަOtZhm*7{/-Tçڪdƭo<T1":堧V.zϐ2v/Z)/o\ҧ}קfܔi#b>'5{ >-oLZQAS & f좡۵o QԳo~Ëf sLj" ^[ :i$~iܮwZ7_JTPPH|c2}9Ր"RxQWyYEV7='$C~{6Ր8aOH $$$$$$$$$$$$$$$$*L6nXH-u>$$$$$$$$$$$$$$$$$$$$$$$$)ͺ?l˰5| Rn^Yx9V{׿^ª^$uayI uv-1/ԖJ?+1pO?7uϻC-}]:T-R -$tжd!-NZr-vTC(ZzWj=!/lb=}w>CUhygْ))=n//?]{XOxk)};?}b'/i/9mY<#wWʾޱ[Qr1%_.sEnw Ev~+-ξ"(+}?>Ypu]>R2갸xvdW7cyw{Gä.>Y? C3Fa_* &;:t,~:򜾏,۳y}aM,鬟/oٹO8y`,<Â?2 }EO|.3ֹS2w_;pktߖ;0]*}3L׷~ nK&{I8igߕ3aak9KD;%w9zX~GR 2|yes~ج%gVX%f#{L)Qwriɣv韷k߸2YuɦoK-$l#x龺-f v9ԮCiWm;x_d*r>}°✦k\VҺ=.hE5PfaT/ڤJet,^1?TH&Jο{cF)M:yG3ًC./<J}P4gůwP5 c'H) +LD}f-n.n= +)5rI~M'ϗ=z4k10ɏĊw"$p}{Pw\Pf}yKnrSJ0-v#4Y=.u0.7{Mh.Y;KSb 6LKirK&LkN{}Tat}8@ν* mIDAT|l%qT믜"YI݋F7Ǿi^|gv1WuvTPPPBGqLC/C7Ǣ;jy" {G3-]M mq-[b%+O"yF3{e{z;&뽢uU>9{&Ml2SN;6lXSAG6~xp︴M%{<߈ogtZ{{ 5|qWGmM7[+VkUgjI8s{??PRpwMw.}9QPѣiZf?G^{aߥ㎁XZ 5/WݿuGĽڲeˬ7g|svTZ6lAfB 5K/Ϛ=;P3nݚ^uuEJGW+Wb^E!~>͚6-;,[ djoQr쿿0?oFxG꘣TU5߰a% .ܼYm<o3JU6]>0(IkKrCSRNֵuԑ!|q#G甓Ob~Kȷ~q5hu_%Ν7?[hqez衁u۶/^vlNw^߰G6gh2zd_EGMlKϝܰosv\35X~Zs2?@w̔mP'%%%p5jذaC9$P:蠴NoTrƝ:v~8>4heTp&-:W7ڟ{;1sV]:xv1Ǭ߰a5QߕǤzh/&89PhԎLk۶mOؓjWVӺuƹμ7~ubu@'b۶msg޼]޴InÏnܴ)]>mց$'k"A;>Y6+ӦE1+V\j1ӦuSO3/ҥΈ{4{ܨ89-/ ?׬Y-[qǵo׶mzzzf>9a%)m۴S>]J_'?1cƵ;NxᱧՍ:[|œ&GEJJkQޢ㟡V| "Qcŭ7׭[z֭[IiiU oڴyӦM>G|* kS={w~rm{ϽJ`'F[6o n?c?iP[[wWW E5_B+TnʷVWw?ވJ<`f`_'NJrJ巽rtlu fz3}yy+^x~؆b3mϽ\[F#^9SN?M6ǟr|rPM6o[Xbks/G~>AD W +:G}D]Q-g]xC.LF2SRRR1+y`H8دUV9sQxrr7[uՊUQYYuÿV4P'fg7 ڏJm]àsM|ϡ&xțoQItߏj0VO|u8m*0)= 7MOvHpl |4}tqi?(pyXqg>uK;եI7ujvAAAT<_ YfQ}(P+5g>4a/ޅ?ۧCK ̜YL[̙+:Ll}<-==j(a=VzUK}ĖP+JT]^eKXs9Ԋ̷5\jfm?}֬OCrwM/ lժUK.{aJcB5h.\=Zju A{FoΫϽZx=9Ԇؘx۸S5kY{2mZڷo߶MJgY0/͸vʧU̇խMR=?6M4G`<ݵh,iǤ;;u='7qw𕈽ҫrcA᛹ۋGiZEzhY[^LEݚ]^33_E7:xϽH%7DQ?Gۧ|!BawMtc_)w]fφRniBNQRMӴ\SGYe?`ئmZR-;f嵟1a e_9P~/Tx*{W޾{׽(=uMjRV_cN!.tۧ{ީ`חDE/.mN#5;\XUn9h;ҁ44ZR苩K;5kbOEwf4"wvnhժջK|{.m۴}^94;t+ֻ(4d_Ioѯ+~}my**]nϾ=[Ċ^6Cͫ?Ix&]3Mȿ’ oFYmKLAFRzƾ 9¤BQ4 N%)ضIQG+Y>%^]1,] 5& bKDm5ڢaK8dlmmFud5Q;uoN|sT<9Ib*V8aQWrǩ<8*RH0G:.? k7D|_B E2moYc*xm#IDATׯ_ߺq۷oOJJ<*~68*5j|;͛75iڼen>0Cy}07wkot˃9FM>쳑~:v>_<iѢŰC>HAAW:i(Tys*~Q`|[bÆS-ǁwAs]u]75gڜX~Sy''ŖP[ƶM/c6?+)=}_bŖP[~|mzhTDq.k>+sQ>?ZQG g<[o P+$ go]'f'_`p̟>?'dl핑jҊދ-\|̂Ws?찱=8yI㳡=ӗtyi`cSR @-1'uQx~¾gK.Z}]zꙧzƩVDWF+QxsyEqowTpO'{gߞֹWCZ/zmeߧM>jK'<[+עEGņ *7+=)=PM>Xqa}={U_}VEK8?ۛ=^5kb͚5GydE{_ߢ89:FVzh 5/))?v7(|j?ąOn˷O׼y,XU9aݾ>M>/@9#f7jZ4G|mۦuƍþ~ww~.Zj)'<? n?ߢ/q!kX4oYV%~xwU{d߾c

:_AwqGmvm4m4P+Z>6VE|q.h{}U>6ޫz#u[año̘ƌX^~Xzï_\9qrnK*(((w 6<Gmt15je~ѩ$#{fz3nd O?kw/[t@4m2Ph{vjU[{lZSS[~n3zr!B٩k֬iӺuR[GWoٽ,7kUf6mzz>nC߿۶mk?Pq _ߏ]׾/ (]}wO=]ѩ\Vrrrg=( EFK؏#;7iҤ.ߖ-[~t|E}sMg_O/tA$~q7 BԩIijy۶}j@=iܫR.ͫ( E*sNmٲE/|~Uc-_M;C/b3zeWYvkזnH]޹Yf-7o}1'xȋQ}}QGVG:;t8aÚE?>*Y8ѪQ\ta'0?ZP$Uԝhu4m2Ph@@@@@@@@@@@@@@@@ qN?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H BY;nDfZJRԴ#ڴ9{hjRR쵡zU *oB)Ovˋ֕6mYjt6M)(&v5=w R WjzUSxn•/tjo>nr_O>}DZ; )-;PʗӲmѽdn]GS5So?ZڟQ 7?zBvhqsksGffƒ>#utSƌ--ymޜ)cw-/s\~Sm-=mNֈCƍڛG u *]Fl_sFV^ԡYZTͽٹkwɧIDATKA~n΄1#uMIڽۻ TPPP}o;كSKWNvJjSs& H U=8JKs2SvߐquWpTGW M]=4/M'/*f/P-;~d_QV_D)G͹Y2{y]%g]Jxԅŧѕp@O.iZzj© өeI{VS 7EtjƥGD 遗n*U)-zNt3䞧f4SW'//+o§n:V-wݲU1{kt U6<'KDՎ19+]+7UC,_b}80O@@Auc2MP'yYo fqPO޳q7 @  I H H H H H H H H H H H H H H H Tmܰ.O-D D D D D D D D D D D D D D D D D D jo>}}jqǵo׶mzzzf>d @-J*(((w ytm?ɺu'/|ܟxӴyġO~>jtVx)P7h_AW$?k"%V|~nl}W:牝Owqm;Mm[6o[Xbks/G ~H NI |3>{ٲ/#~=QF3mέW޺jŪ] @@A"/}>h?^E7}unluyڵ @<@j8xɒ'&L_WBiqhOnҬIlg$CgQ>G};GsX='׭bOb`oH eʔX17:8TA%_6m{햤O.vq͢bS@A|cu^we _^|ff~[xZzz{!A >spƄa<3h1yf_)ţ}ϕ>I 6.Zs;z:n߲eK?Hnt/:W"'`am(}{3Θ;w^n58'X:g[}hQ="/7/IN|ey8@=v ,Yߞyvjvv;qُa. G?oGyTXѺVgE"UOJJ3zNzr½ݤIXׯƬYo#vak6V/8TA-I7L a Q-J ^xq1 4;o|_QG[lk@I*(((w BT>>rm8Ӳ^jР%oϽ>*5j|;͛7P/\:XuzWBӴy!} ]777?e-aC~sy}XCj"צM~{ُg:| {u䑷zkJoŊٳ\Yg.]:۾rۈ G|p<ӗtisb<<6%)'ܤIX:4 @kذ?̳>vӞvYe2O=.Ps_->}79}PF zeK9QjP?U TYvm_ɹhKOp$%%oQvs'ǒ?8TOn4ۻU5O{<`8ТTc/~ϟ[GRRR@u0$w ߺ햛O

VSRZ>@jЊ+ޘ1^{njvTfW'+Ӧ͛7+W Pr!OϟU'o̘q7;ĀK.'?peu=UPP;}_+]t5#M6 fz3N;Sǎ8K :dXiwF^hjjjA+zٱ_x~"IMqúPl۶.]֭^gq\@״yġxsj/99>*R=s/?P"9sĊO?=eSjժX(# 7 uL)kP36o8O}H H 4n-RݿcŇO=o+, uʋ-_zt,gCȝ˖xΝz ){(=6_Nᑿ-+m~~-MzX°P/ꔶ˚[8y{}Xfe g9ftX;>\첿DZH߾Lyp`|qܹ>裵}-[T7SwnѢš)-[{N993Զ[1sYon۶-Y|EN.rH=‹;,1ԶO>ؼy!ҵK磏>lڤIR׬Ï9Y֭PqJK]n]gڸqc{H N;.ߦO:餴͛mܴ)Pݖ-[}ޓAmߞO,Zu~>V,yw. PjK$IDAT͛W^Tg}&Mnѿ5:v#sFPjWmZ%c?rIbÆWJvءjլiX~Æ[<%Gy5kb;w'6n+TO;MzRzEZh+֯_~>:X1o㳂XjF<%ݺuI`']rEb'WZB8WFl P<{RZ>kC~c'gH<;蠃X=Wtꇱmӓ±z0=f S9w|X}VV=|SlA]OthP%,Ѐpfm0iϘѣ~ r-:+/22zfiٲE_瞽⪯?bM-G+ӦHXYIYug)g9[wogߞ+xhSBU;4)4|h]݊F ZQ|u;$sӅ(seK ~qVNaSCVԟ|=_C)嶟} 4 P4oc92z޿@͈>c6m_&9z^i3|fAl(M7¤ksZ?4%QV~,4)צDQw#,V9}zᨡ?Mvt֬؞Q7swm)JtkN֬kvS]cbs455`eff6lؐhѳ=wO[n}˖-e];3P/4|;5ˇΞ}:|yq{l_G9ۧ|pw.>([1J)= {-E>ȍoEֵS>ݭގ ̆[sn[c3ĺB۾}g̝;/TTӦM64ZaykADN99ZvQ1jޝ鈴ޥuFxpFiwޯw Ԋޡ* r̞Ap[}^X#B'P*71lnu .X=w9㬳K\Oxn-QKa'X5r6nݾ߻֜kKu f@{ȟޞ\sWUbSY+G̘v.|(oE\Wrcf{1$g5k_{ﹻI&_Y 'A=1ml#f]kkc/LJO*j/BhQ,wVzz({ .LRb9&nmΝۋ[{_pYfQ4%ºQf nPAᐞ+M 暯_ݫWƅ]z͚-[\}͵sg Dq *MƮyݞ>s۞}=][ʶ]Sv%+g޵㔓O~/xy(W}%T}@:^W^qE~@5n Op(ѝfoŊٳ\2T}J,׎NGvu'7idӦMQ}to?q B3ze7 4/DU@uAkܸqغeK%>ZLk׮o͚5:HƥP$999V|}{?qGydi:jj!rNfzh O>d T粗XqIig>y]ׯ_RQ ~=}V}qI׮]wz>gm۶9sVtqǵPIVySQo̘hǴ>C9$P(4}.[( b;x~sġ[ƊjU|oƂ׿9gNnGZǟ_UѩzbÆ ew8)O Ɗ#8"TA:}]ue'5))iՐTɩɥu/e#sX*T}v街\tkւ nڼ9rHIG~DvmN9lݺu^N=Tr7lܰ.51F=zBӴy!}V{{w@5@7ob3@5iiӦ[oq>~Q~>PVXƌsS}lժU>qMSL6o+V\2@v!<>NfVq1cƵ;.É'֭[oO~@VAAA:/t9ԌK6mt/5jJJ~;R;N;,+((azq!'fgb?$U4U Bm۶St}[z Yr u_-iϩb?<JS̳Ŋ @xJ̙+N?5k֬e򖅺?cNN;W/# @uyw~9|Gzzz߿?͡ϿzWPWT<%ZĊVlҤI|7V߾>n@:^&*JΝK7G-]rĕ~Jm?&ɡN_lwc~wbG~/<PH NS׳יy뭨}_owțoխڴoټ59ھ}i/|)K$ѭ[X1o;[uuE'7ռe]rEb'WZ+h6ч<$ħ/ •#?-]Oy}|׆^]8>Itߏ8Ͼ5[Oh۷ohxJ:{+VO{tszcX|P=^%)==ZjWƃo)ջwu}?+{o9;@=0{ΜXѵw=(ϻe40%l(:UsI _>'ΒQ8n:wѢ2Ϲ|c_Jҫwn.t\6-oa|zYvjܤq^zuO+/#ԩz2mZ֩۞>s7.+n8ƢA9ጒyphl_&Rq}oEE>\ nءKzZzռyc9NyzbԄiڴ|QvXzF~]Sfg(ٻ3 f.;b&Nم'^}<-9kl炿~o iΘP4@h!3=W٧WqrnÆ =s䎞μ۷lj@\&1߾c<Ƨ>N~SG_/,O^o^EQ}IŅbv9$s²Vӷm>پ}g̝;/TTӦM64Z$ 6/OEŻ ٷg{yY+fϚѱChu .X=w9㬳K\E>xIDATOz#,[oɮx{:e7~t'Z6ޖMcj AInظa]ǟxo^v?ɾ%ߋA9(ϻab_3~}ˊVM/(JZEP-I7N1d^4hӦM[o-XpE^&O<ᄹgiC?ׯo۷'%%z[K~֐>lXaoVT{7? Po/\:XuzWB#8eO-Z6tHTDiWܺ!eݞ7n|oO;W\|PM$7~|mzhTDߏ.k>?>/7 V={ʕ+@uA8>`~_o=C5n%D: wp;y'=ז-M'F}ʴiK֭kKn80qe_hFVz؄ySZn:RNT|q 5Fs#NB|zڵk{wi^HII A?K7Zfg?1a<'pի>ybEjjP ݰqúԀuӦ]~wɢVV״ 8 .W;VޣG]%ZRcM Dg޼C }Nf\IԼM6z{𣏢Ք?P}bŊ7f|מեc<ʴi_bʕ+mrzdj3f\oN81ɏ;xbnqmݺwd?A_WJ.@͈oӦMYތw!Աcz)ΒVѫ?~kʟbjvv~*HRESmܰ.1۶m;K?u٠A%P5m2q(F|,KNNãT<%<\?oΜ9O@Z*V T[ 6޽g>8@} É'4j(P>O}-P_jϢK6<OI1ڶmۚ>Ïy%o4INWlٲEy NI<;n]sсl^WjuTjҼIrA]t;xB?Smۧ1*o{'_rșg ԺK޶m[a[ ƊgiԨQƌgܲe_}v }}gIII:vԮ[ EE޲e}_!VluGqD'?fYfZ״iX~A5쳂Xu b\P^@"A5;#]>0*7AUrrmZGQG͋CkKf6C?3-:t³uòuyZ4+oaqaϿ=[VwQ_\vfî.i/Inظa]c<#V|~mC#y' wΟv/?znz,#j)fŁ7(ܳl#>kڼe>^9/GQGs˖ڸ8;'|=z M^xrM%t-/|}ڒQXɩg?#/ ߣˋ%%maٳ3aƳK[v)};T@m;Onqsay٤Om=Э͋#=.qѳ=N$ ?ҷuWHi֢h™RL`%̾mꍤr7lܰ.1ZĊO֯ PW-_?O6[@ra5m2qH?86o޲xɒw.j%;|`6KW'<9i`Gv19q*&o^ g/2ݬiA]:7j(PUbE>2n[ <~g>sӦMmڴ>4%Cci*x^ -ZzM(oٲn]3[nݥ_szh[?è/4Nn|I' TgO>$ejKbE3{_Lg3e[:v8u8 jGtN9m۴F$PV^Ϝ#9}vٺaÆhٲEjO_^&*ϟ߹su-[V^E[׭_+ivH%'ާ9j˳!~uQbg O}uފyOW7ϓMփ<0E%_+&L|rժU`7Q.D˄''Oy}07?Ы{xĝ1f fkVJ %auڸqW}KY{2mZ}t>IDATC7n\^^^Ety޼{<*3¤ fHW_6gn'h3|k´dNb 黶t3׳/͸vJ4iYutm]g<뛙 nrotjS͏=N8!;)--yM @>M>wuac)zKݚR?4`C3 fFC_Lj,EkPf`xjEpDAyﻦަ0{=~|z"&h>3.-IXQ|I~AٰaCE>?g3o-[_̷.w~{38#@y漼T}{/ZO\->=ua~)gzZ蕶u%t֬>ӆ~Z|=S4B}{3Θ;w^n CPiScjVG\z`lcþzn>BǍ0)vk _8|C6Ѳ{t uPJJ3zNzr½ݤIXׯƬYo}4ԟ,i2_U09[Cr?5ߞ~̢3\8hkumR| 8th~(+=Oѩ3_qm%լX.NWqE^f˖-W_sٳ@5A5[z?s^< 5wU][fPvrSksڷ7^y ;EÄN9ҁa?؟zW@u0'T[xhYfMy+b=E?0=)y& |+V̞=gʕ:Mݞ_ԟ|PE=3ǖX⽉mZ)'ܤIM6Eg_p`ITG>Ws>XѠA[ą ϗrzժ:HVlqNf&M?Jv@y|AhִYյkXƜ@5AjѢEi!?x$f͚[ɱ@uq&ժXq !gk[0wuh;.%ykE{m<‹۩|P͎:Aƍ+瓍g{>#?{a_駟 +#e, ڶi-GudE4mҤa}۶mOL|rS.> }(ʮ.x ~[^K3fϵo׮y͚6 ٸiS~چ=(X萂X^ѨQ+}/0wQnW^}-ZYO^gο^1sVEItyc-]9}B6<#dj[*6g4I;v{1CvUGwߝ3wKwNҹ;v81Z>ÅV^I;ST鰕 ͛J P%/23zn~>j/F[ny#C]Ҵyġn?wJfz3P+6o޲za~ZX/y;Pön:??>w. P/IFyF(Oύ6jF޲ؚ>ضm䧞OԀF}K[nV̝ւg=PM>իD/myz#8"@CA rhJ] Q@n۶m{M^~e3fVtxgy_w>K{ ,\+Uٻ+R*V*Cd1aݘ{ 9 5lڄ&;P~u):wU||~u]q}_>jԢyc_~WOkk+iu+GJe)>rΥw6oРo}}FzX\\ SڒS6mR]Pr#GnCm+V...\ko/&dgeP {E?>>{-tyCk@17ş/7N%$ԜcƎ 9x@Zb"@yw=߸!XkØ?QJJʡ.՚_egg'@{> ݼe_dd\䔔˗/ t<+PVqw(:zk:{V'8]۴mzݽ{w|,DT t^ƍG >z:u(z_򗓓9*X1eA[۶0Jz)cib??Wq3z凵zĉ#$:&//N/^jOOjbg%ϼiϰ컕+ }J)תP@XڵP>%iiirѭPBT{ ;+C +.@0oh-!}$$!0Yٌ-"$ec,^I_$nOJ`|m_TzI1вM3-P(c$ψN-6_0~[фzArá:[Y+Yu(!NzD':غ=cfL|fo39Av'N3}kPG9LZ@>=K][~$Ê\@xrO;T4Ut}K}J]]hͤ69jVAIw~"w:Z^#;u9tk淽W~n3&MR'^`#W#,#(GOfN*~Ϳ3§&)5L_tЦ+.aub.G>VDp/ZO5bR'/4)I<\:e/DTu@(Je2ۙc5L3W0l>vA\bxm ?UR37?Z55-ҳE =D w֭Mfgg.ow?_QFљt3sֲcV.Oh!@{giiy]@ɮ_~95U8ֵ3AapgZΞKn[6ӴdddJZ[[ J{Ĥ1?Vq%[~鯳gGLa/]w_7qF°zʈf70X 6|E֭[vگ_veW.1ʕ+raogWfC^(/ (kӺi۱s?z?󞩩a,^޾}[.ۗݻ̜} ~rϗcq􇱌ɑ WcyGwmlߘ2S...nm JO8y3}GXxٳ=Z! ƒIT3N}z}Z/mc^og~7G_F^ZKGG/.Şr!ptph V)īYBXXtQA҇rQ'k~XIzĉ0V<9AW^^)QF + yCk@:R'oO=پW˖_g~:X҅|E033nJ0v}Krtl߱S.?߯U+Qe99 ȵf.b=2ALg:ӹ*㎟-[ryE Q5ScuR{͛ a nS]ILL_Uw˩^~?mu떨'۷oP8m2oMr<|G[WQYJ2<)&%8tt3=CS>׹/צukQ)&&&~~!TR\R^U c,lvf/\,7cvOۥO5m]jPnnj_[[Q)s>p_{HtTߙ7i/FhbN;t07ejjںU+ieGXKƟv촵mָQ#Qqfffrq}u 9т\gvY[[ :VލmCG .;<):~C ST=w.96G?_i >SS< KKn]}.^ؾ];ZA;.nm]Wq *?__PKHԵMki@!S.\ ,K7a`/.{`Tuƒ,-9F>jMrں8@p}KNҙw:kKE0ƒ߸IԼѧEG7>gdca4ga5n{g9n,{$ ]P:M4tkfmEKj<&=cf33?=wRoOI% `< @u"Y\ryNRЭǿ;LZ:kә3fq4IvBBJAOG0$PNG iK3u9;-D['3'=>sg" :D:_x|!թJ[wхfLb*HOcQ+mR!1jbZ v,V*D#&(8O ;sFh+a#.\j mtԼgWg.R'[.Ez%-_?)(#AWU#^&gϝ;ٴ+W222sssK3t~mf\ի'Hq$Jq'ВM---v@DMv֭[;~~LQKS.?%mR!)Je2ۙ颂4;D*WmҤIfM4윜W]~-66͛RO4ϒ HWѡ }2 bΚQ);p0J*| CaZC2'srۼZXXhxzh:t.1]*3l >5Ol#T#}8 mq=veI5*9Q&j$i\_phw;3]I9]Ɠ>ia}_#(Ik3Ἕ33?=wRoOuӤM*?Z}\ʅ FITm2'sr)4,/i\ѽkt?^H[3>ѯO1?##:埾i8TҽNyRڤÓ%'irzzt&Y}\?Mx$9 |՝aѮW1VTCG2O3gaՙku}{r+ӥDv9Iw[^Cۇ^ǻe᧷؇x?Yɯd,qg322ngd#1&0ΦVVV͚nU@7dff'NLJ̺uv^^^)oƴ»^ذ;kPn =sҥ_NM(ܫjݿ=wcݻǡhxz @9@\qc~:@q].Rh}0oVʃ1'M75CR٩YfY`:gHQkW[ G.llZ4oncccffZs:[ZZxuT|vv{ >lF #}?qR!Aw7c'5m*P> ttR3U(pBUZIDAT暚y(KKO|DZռ-[_1i&/{' jӽz TMzzƆMU֡}{9U*ϖz EPxtԺ˚unݺuNcGMT#AWU#^&P)*Tcq;umVSQ,kk+i+Crʅ ҥK+P> 6>l跫W&&&9;; @qLFJh#%!˿uoYYYZұkyHpqv&w 33 (cjA-"#'\|Y-Z8:8t){C6>sݻGbbJ3O>rFfϚ[y>1)///55͛5Uvԩ?={Kn:aÆOhѺukn]]TٗSSnݺ|9/(*iNNmZ:F3SP%ӑ99EGOxm_g uIC^Ï>^͊.]k}Nλw3s1+3A^^)&0( YDPUIȑ>~_,]#߿v?v,NT?O߸Iڤ9*jIUH( j>mիRq; -|ogg'*N_.80''K鈼ЦᨷFy9vpvw$1>1寔ӱgMVz-Zvn֠AQ)oߖGJVx_tR.2-cƍ>5𩞃z:9~ $=gOMJHo>{% 7lLKKȩB^K33t6_}'rΫ݌E31ysm;ͻ.qtp6ͷ+ϟO빫:9 ԦCV} =Mw,)ӻw;wwvc+ f+ pF<6==Cڶ}晧|E053afrE#!O}R~="]w 蒖|ceW|#{O\|жۏxqI6u\| UDթSgZwfyw<(_~:ھc\<5)֕ WJr [^Uw`t%*f qi?@5F|WZQpAi0Z'Noqi(|*kk+)^67Ât.붎qlZ),KCB|=Z8PttW_> ?__Q bcc墣_2;üD?|XyxQO5bt/yWsDҔ#ѼwBR&*'(D{= >/0jQ R[FƪgHbd|5<%;6m`*Gcנ-[;oW|ݰaCμzz?.@ SzzqK?_epaÃ{=[:Wn2?;u*p,j<)ZXX\)-=pn!?]'t>gsev$:w(6ڇrBLLL4rjKhbye'XU\߻w? yzonm]+X&h^[y玗F޳ywgX }Ş2wUV%&&>~`T(U)Wnذa&M+K( ueix` vF,).{ĥ&hvf>8hfGʡBEڧ^*DyԒR2ӽ s;xyԖX|<{Nj1"- w~rV Ptx{YC{D˿4bED1'SBR> >~< _ myNk\ M}(i`'OÑ>n3fx,OqZ-tZ^Y=G5qӤMTDZ8p򫅞 oUC3wV R(0/)~5ODi*qaPDDD%jWRRrW_-Znڷ[~ @uп1ss7~`~ƍEmZTdj:ͩ3ϴmF2g<eԪQKS{z5[ku.Rjk}wuPdâލ!RxS +v`JfϚ4?ujV?~"fڌ7sT3|ϳrdWƏ#s-s]fZUKPqxFčM59 y~+OB[o-5X9Wf/=!۩[@BO,)1Ӥ){ˣ7m\ 4AxLxM뽢S.HIE+}X=F8LTkiL8LLzzzO!#cD9{f>aՌ[sL5dP6ߠEtVWk\&5w'NSr ͐O:RMyD?='U{->R'޾G4]tx{ )T)tфի[Wx)vN/飘Z0m%J)S?u mO T? ]Б%_& VEI] {QC~9zDUn =le Y̾[oMV}zn.g]Rj/?S=<:wٿ0 ܷ}Q>€|Ӹ::8O,*$xjZj](>ґOoҸ0͚6Ͽy*~Lomc-:gٿ?/A#O]<=<ϨљB^šQ[`XF>yco(mG@@#ؠAQeOkٹk֥ Ckqc߭YiS7ΓbÇN: 趬lx[@qHjqcM|x6tJILLzY~oxwLi(Y䁃r  Q2@Hctr-[---{?ٮ@Mw^ԡ7j$P>qO\{{uW}Vm!9w|+*eOJ2+++&ɟVth^NJsveff&$~yH4T?#Rڦ89F䯪F8LeoDƍ@IӖ%֭;~`mm%mWqwk SDIzW_---+%#*ƑԘgb?~k׵n-Z4wx \NMpҩ+r lcc-PS42uoM==:X[3P#==Cd*A/߲g{¿N#UUƋzIJΞ;'JVu6tf[~,R?w.ܡaAjVMG ޾3իB^Oz)ys{MO)NMM+:dץ?])~qQ*)UmܨQNNA)R.\ j$iի7t1',L(2GQclffVx}v=YY15%*֭[ M4mdEq(6xVVc굫׮]5Eߺ}KI>H(I42,lvfGo$V ۔J}!3$|9/ٳf;kү\ܷ7dP@/TMʅ &7Ν"XkjDjjڝ;@B*-##S]~7YtFX7ɛjӷϳr!~p*>Aa݆;wro]Aѫ+q\\׽IunnaD) |.Ʀ?\_>YD`%>llnfy3Q#yyzeݻwݫW]R8~ԴNRptP2WQl077`HʦQ~N@vh"y6[ Tf͚=wq\XZZ0\$U漺8{!ll<߯ϳu\FQTSG:KիgaaniaDV ,ɽ{RG rtp 䯪\]'|Y0o#_V}G ֻzu֝8գ11iWZXhy_KGiHJשcRrmf 133Ga#ӂ~;vxRDʞhтtJRr1 cfbb˫W^yNپ3L!O>پTwfgξ}hL3R[2ϒu JNrT8:g,߈jڤɕW">>cǎe~Ʃ8QgaCkvϝ?ǒ.Eg:әtJLN]ݴiSQARw`TuƒUY[[[9;~<јR*"BAZ ԭ[w>e<'v}ğJE\,gn*rPLl5jٹSÆ <%##zN}P*P 6>{-*h(l|+t'̛@*fϚB7@Y]*]%e7ş/7N猦%?IDAT%[qS΢uo3+//OY\1cW` sƒ\ oRzLd^ph衜w3Ү7˿ χA9OH~vY~}a/^vȍ b_UzW X? sRqf͚wxi={~[vIP)zrk(*Ν;raff&lrqUQYElߧ 7iXA#J'y^/m}l(Kggg+WT>>yR|qw+M7#@g:^=-,,xnFPĤ#GcΝ?/J8;ʺ{\ԭSG6W'y$fjRYlg#aCkvO{C(J@g:әt6xJT֩SrѴiS`t#ΝO,)#P( KlaaѣO9'vؓuiǏQuԫWڪcnmEedd\pAhoYT`υjj:Ƽ}5loo?_"oL"@KH9qqnj'sDꗓz^qCڵf1TCч83,\5+N}y˾ȸ))/_6KKu?yWPt&u@O 4pﻶi#@2{?rYR&>|uQ@п/''9rT޵~cTm`,S*nj~~~߯^ioo/f"kׅwFH%-!tL^^ޓ<.^(՞DϒKtyCk@la?˱w+Wm߱S.?߯U+~ȑ#II7>z4FSǎ.]jD||Y3@Ч/66V.v*!.^8)򫦥aC+kׯK[\7|2z@&LKKn]}w߯ӭp踛7'NaW^hBT{ ;+C +.`ܦNͷ+5Oզuv4h r毳'OZ;Oi&{vڦtyCk@A˥3g͖kW0P;w3kow"Q#?@OAϜ={g۴q5PCol㨗1/%=$ҧuG|"VVV߯^I2d'Op|@KHO߸)t\ @sZHX!?蓰py~& 2334rO? $&6V.tĤL6AE>[:ulР\]"?7nENի'իm+R.կ/}fff&h`HC:=fzYx-K~/P$1:w=zLiX'W'QUA3DžOۇ {XI۸=t;Zy>Y=Oؽƫ+5#vs>X~gLrcfKu49:F3Cm)hh YOTC> ooevA\I',̙MV ~$z;w/P=HqZr<坎nHIb8 +OGK'OfNbT>VDH%-]Vh䄢E2}k /f1NFEXXm-TSzvuZN,!nƝyc ?&(tj+o,4)&sc[~$b.?KNIvzfVֽ{J<|f79†mmlm5svfC@!N#Z!m%R3Z4o.q&ԡ@Hru~ڱSPJYBXXt"#"lzTʭ[ΝOlڴIMի'P5׮_KKr$&Ν\wϲOf2bO]v-C51kii٩#JZjs[o$?)ʰ]iWܺ};h TSSӧ{ Y8)Լ< `ngg/R{XXXԬ̔ 5>u9y_Mx )۶cGjjZ@c`223};wAZjK/߹+~$̒ KKKU^=kkNOOT??`ݺ}K.XVE޽<@c?`=x B!PLLkR)$!  Ӂ=Jmf: mfff*l8 + eI"?{eM:: Hiȑ3§mіew=ޢqnj(bY>WG%-ս  Mbh2UǓ!{9k(x0@ " ֯{rT<ֶYIZvӡ64],z?xF/ܻ ooevA\I',̙MV ~$z3C(Տ0XRrT-9+_/!;-&iq}{=҉Hy"zGf/iB%']o8/TE[^৤|t51 q4*ª`7hmԳwBg 1tk淽 0;UM4ydE P#H{eE&dNzc׏^]Z@߸ImuċZ::.]s))nݾYJOG4)6ows'(77'Z$?ݻeǤ]r$&Fڬ=ٮ@ǘP[nO\rE.222w[n߾-%𐧇Ǎ7[4kZybKG1̀;;:8ww?sl^^nF4¼An Znnf̴|;wr8x46Vjq旆+PHt`;Ra۬Yoŷv"PR2Ӂ[lڲUT^z^=:zIDATuek۬IyUɉ=(7ggz?+ױqsrt`*vjR":vxYӦRaaa~ `O_~9r$1))11I誦MxE{v~~PZ'Rڦ#G>?`_d@۟PoJlno/ $0X/^_~UkׯK[\7|2zDuJOOm*ޮÇ j}Bܽ{W.֭Sz_ŧ~y3} vUQmMvJ1IȐ kk+WN_y%UOcl5ǏwQ?.MKd|R;r'>Vf ̄NJMNM:tWxϳR{|kJɓ~^R.\;̔ Kˆ\䫽_yz c^?qDT&ME|B3OT> Mr|bNN\ە8\V\9cь^zw{$-=M );] 냇ݼ.JP(5ζY/8~C?OOrt,.N.s3g͖k 7tճᡦfʻINZqӿ. Q@ߔ ߿NrǏuo)ӻw;wwJOQ-fjj:yߋsƍM/nڼgRq+Vm{:Imf5j1R!*7ךj)S΢uo3K8]ߟGg󶽽}<غuV7D 153 ,?6[f-T6?ƍ fۨ^&}J$=c\/ vhxbЋ#&6Qzs:ʅGGYüD?|Xyx-{GE 233Y1@=㊜Ha$4nbWrwW)T%u) ={8ş/Cqĉ|ꄿ{u gQI~~IfN~DY}[gQ;yw77Ү\zڑf#xOf~r??xϞ_0ԲBsKFK˻;¤MG4B˹orD9y٧{1}.-8=*3ŏlQe"Ӣm'% rYXpiБequuzRŻ>:v;~Ccǎ\jܹs+zn fQ[<6nPpxsR@}Q-CRTs<m< &9Zڒ_-F(YzOMM-/#G%--,,n߾-4n٣s;txgP=o̟͡./}*ԫ_\< {Nw[TM쩚c2' ]%} {,t ˿0.޳K{IL_xxӧK:ڷo_׶mE}<`֦߁=DɻR&H{d/\WŤ':ދB:ÇZ?ʌJ"j?<.bb )%-wH²b?*߸{|k'{z[yER:'{}$i;9̙gϚ( Ľ{ew;po5UPcBbw."B)}y`eW?"׊$(%ʻ'*+55նYۋ t+"B!5?:^4u?Bw∨bj`]Z|ϊT)n=?%зGULl 25uUzɺHxy[szw0b,ydrVL%G}gr^?OM#m]]߸)…sxqXKGG}~@ ,J5x) MD_O!t]} s& Rx-$*¹ 9rmog'tϊ-Wvy^M;PxXT@[ ߷"+qWKEJv1C|՗|3݈ICb NIU<|͘&m{(ߘGoڸE 4h 2#G ht!J|iѶEiT,=un꽡یma~}>!ȥiYׯVVVB7x+ լRJdTͤ\PEx??/ rjnnW'ҔPBT{ ;+Cz%33 ]_t{R~??_& Rt`O[G+}.Jl_+K&4/_#`>ٵka/u/G1 =l0VVVƎ )~wӯ }2'DLMM'O8)=i+>}z|%jrZB7j$Rv7i;\zm{{{my[Z 5u?"&&u`P4nbWC ꣿn،E3/GڅGwޜ1]))qU>YaQeϘ 4h#Gcb7o.H`hg?&˥Rq=プ?nyR3qgu[n_mbbcsUȅ(s׽RvE6-? ?)/_Zjӏ[+1ܩc;w7sssfJ^YbH\vM.,-PArwU:0LgܲnnB?M}~RT)?6L*wOEjiI 333{ `[׭ymZRˣG5g/&M4WWھ[R"wn(Y^^^T!vum# [nM"~޽͛RQn]N:1z:\m֬>۽{rr<9rS rRHek۬>M4yTy>>cmm%P* 3ufOxr7nLO($++KS7h0|XSАA&&%U*rPjccffH=+mBk-%];;t>nF6/"Jecc}G ҡM֯}"޽+˩i=GPH}H|iB;7h`{|Jr7ҋN(uG^zݺuR!購/}u=23>`R1{wgļLU^3gILJ8?yzt7o#,//OyB7oڼIDATPHC֤qn]}!-@˯;~;5`О ~guVOa/}vFff|'OJhaa!(fTh:uh`^"wϞ;M///o,ܺuNfljj:%w씋kE(O_ll\tU(SaaQ:{Knݺ%jU-:wн{!T3}Zɥץ"=>ZNN~4Ԧu߬S)}J,lZ B9rt' fbb)y^z@/r_dTxG@iOfͮ\*Wǎ`6n3nfOͩ4*1>1寔ӱgMVzփ-|;o#H _ g|<+(f"􇭭\?.whk'ɵٻ_DžQ뱟ݹǀʺur1^)i1 }J<=Ã8?@% 7lLKKە殞,tۛl۹\ *ƥK@޾cZOɟG@L!!^>ݎ\X42zϖB[޶ȩhۥk/unGr+VY'Y0^.r#׋#^Z?qЬsٹ{{wpNEuj!su$iiWЪBsKF󋼻3,LڄzDH 7O;9;)qm¤CG:KNOn3fx,\A}`Ѷiq^B7/r_'%Ϋ\ZXU3oic$?nt& ի_|ݜ vYvR-tQMbZB$,<1V~~>P&T۝(C/?'ş<wQw)!9j~ O_Hی `Au/'9-Hg}#jFZ}j7V`Lfڌ7s,)asx;w&AO &=k滳ft1ѲӱE#Į)_*#Į~ NP  U=0NݺťK9sX4w\zk6ťASU- mSUӀN8琢]}f,r5}TEŒS&E"􏽽GLLTr'EE9 U|qZiF. &*Z군5ar=*fҴSbG?*tރf83+=Kڶ}晧*?@/ нT(Ô5鳩F_,Q(h]uÆ kG1닻w9u/nr;}~h'XUHȿI{W-Xk]ҹ{f-Z{l1}i)@5P(bdge:oϞ_^5:;;[Y*sssj~/2R*z<#BGüHw̙|cN5m:'5@z0Ǿ[fӦ7n# x_lР'H=E T]@0$!  `HC@?0$!  `HC@?(J?0$!  `HC@?0$!  `HC@?0$!  `HC@?P(|Njw'|Ba?6<]T]zx^)0n%&Q3ԩf}gnM# N֐? O =*$,mq5>vG TiB^%_1W \!. qUřcMp,-7%#χ~XzU nK`<?J"7ۢJSajcfRW 'l9#.zNP1f}C"=*3ZU3#xqx|qW  "vմ@"`-aqq'>biRg{BJ݋4jzrS ݄.pj?6 C/Ms+cW v7SN /uU_AV}CE;2ԭ&u!-_Q|_=-2l𪨐f:vU|v^)l@y4`l|byBsZ0_}W?7h¬^>-,<9Ox$̩ϥi.cKI|> 3<&&mb_gQYJ+MMq1gm~8JW0oߒϐ^q휃k [*݉ ,wU_Q59-sn2IՔ8lcfX؈BW|xeTᒾ\hPV7Puc?橕UW-:MbLlIDATn'*ͣoO?O;3<>H3Qգ?lR E+{kQFMtWZ~BPA+(Q0zĖc3DU_ԢLw^)Z36N_)pw'=~4_gϓT{[p`q-;1sZٸ^6BBILb,rĭEUrjZ_w 6dž,VgpQ؏]w~5Pٻ M|J+M}.dXg3al޵{#|`ύt^t*jAYk]0S5\r&HkШݐPr{cofZՅW-(zMߐŮ XtOXU?^~E&$MKmçy6op5Uh^i%v"Clxq |8jlb0R]O8}o@~l<|K~KF/\ЯȺjQrW26aW3 E xeΩ\g;VquJMr&5n|G=O _`H3;b镺ǝ@&-!-asnZ`1B(NR"~#L[+"|o___=}v~SE_v-{f|8˞5.~B I,jf1vU|NR%穬WZojm_TfOQ:uWF+9I/Έ_0\Usl_ _=q\cç:;gfc#6о?8c_cllLEWZoj-_J>-|e-qlV;_)wZx|,wS#/Cb&??~XvT;m*vu{{g؈&n]edNBG2-^uiQ >;מj'}Gܴuxע~f*_iUe֋ RP*iiڣϭ?*}k ڽaÝzbv&_2Av'|si%|IoL]+**q􄒏[\QjN uTҫJ/~ e7bVߙ~m(13=*=}/5cH[_@Ur̟U$g>1"ecz=ήscYs9 {mޘo:ڭ+cn?UӢnj]Zβ֍1*'Ƣ-+9vR_:?W:f˩~'F;KtĔ;7lNb_qEnn&&F>x`TQjcGԩSG1@0la?˱ *Huԫ_OϟOܵ{!+;⩁O9vǥK@ּ)$e~| [1%kAk=viKe\k)x7S %--M.:u*,tM҉x{sҮjL,l*qG@ȒΪѪЭC}Z=r {oaA&Iیm#Ua[ uPw8:R8-Z2uamKN/8CswY_=.ՄUF2j'g+=:{sNݻ "PY < _N"iabѶm3/…-az s[=;~drI)>bbݖ(OYp`̢o[0`ς>7*ɜ|EYLLEuR*.]СxyΞ^G}j[yD3ndaTcv œ%_#˿닜NUvMU9#1Q;?2|P7QN- ٳ=~捩S>^zR5E{T7vrT>vm綢?i9 IEAtĒ?CEՌ!BcܙQ N>w\\%_|E?߿4h P*f,\=-lRzg>M# #0uvxRRu?INT]Uw *r$}vzmۯow?EGR(_<==R߁ oo9I $'g}Nc>N%U6곍C|>8猜?m,6m]QXK9, t^6nGvꩧڷe˖tҨڵW~.iѪM3۵잖^7캆6d=ol4wic./.Zu`@ɯlk@'y|ϐ@^_|Ų({}0qnnϔB]b? %CMڱ>Z=?Oy x!Bpi'}裎7λ~OBЮm۱\=_}d%81*ڷo[B]bPX.dtN8?KaYdIHIi\h‘#-Pʒ>䏺`ԩ~r?-[g# cMvv) TNGu̙;7^iIIIIs^7o%-[߽b23;TTTT6͙;779ssg5F3O:E6Ψc=ȋg/Ytڵ֭ $O;M z~W$vmێQ2{kwk'yW y͛7} ^&'W㘮]vAg_QQO/Y߯_akꕿx}ɨQ3!HRQQQ>۸>17o>G{/{slԨ%$:>9#x׬Y4IeSOƋ3ww @-Z(^wq(>%q('m\ꘖŦ :>*#D D(̑-[_8s*Lܲ]wկ1Ԑ8pz0TYK, w.;}K? j15˖nݶn3/l:9z߹_pm3;4fL\|޼-%'w,#~fzi56 6~ސ3xFyK67qQ;3Jow%őo6䡅_9w{VYP3'ꜷuo[Kv<-%%a^yaxbM?ݲpR{A(M…3éoWgܸb1ntr}3?k Gnygv2°ͼe{Wf|悱/1Z'귖.ydm۸>1-['NjM C7pҩբUPg416mZk}O 7lذ<_fKssͭga 9 /o:W!k׶]:uЮ]ҰgLJz9F%g^c |m4VQhZhѥs@x3oY7A5u_p}F|}IV_](2޵kHDꔆuaճG}ZX8gSu㘐$@Ҁ۴il޼0[:>7+bՕtz$׬]xA'%%w{O> Ԏ2k/zپ!蝕+g>܆ qb[aC8+)$m(~VԎ2oƍvƋO>4P;J4;@ו͛7jGCI I 4oyC$FaԱC|SfLn™Lܲ]=fIÅ:]`Isy{OCW-kn3/l:9z߹@pm3;4fL\|޼-%'w "]K***gׇ:&JŦ aoxC:728α<% /X}g9チbpV;kɸQw '̑I $:9sV4 <-/ k1⍧7 BqyÅ3éoWgܸ0@h(}}Vs1ntr}3?k Gv*ygv2ѭܙe{Wf|悱/vXRZ䭒Vߙquƍ{2_ wda~qol @)m\ꘖŦ W {zxImԢUPgWw 6mlӦM;y|e47w܉r>m~os;VL\ni&'_ >xxca$g^zcfHH׬rk۶W*Ҿ!:vT$? ^|G3猧lXUj+VӥK<(9يn[-[KW^S#8)mf/lڴinN-nGFۧ|wVZ^/>Pa yǟ<{gHvӁC9sΛgcڴn::vouxqM}CӖ-+勤زe/GJs׬}uoN/M_}U`__Jݻe˖m:9PΦ w8sݮm֦w$1DYGyD8wc$S|(^ _>^1j >%kFҥK9*wwr$|,=)=PW5 !/,]rӘ޽{QdS ’~D}/L} PD`| Ԏ4ﴁlą9O>j°Әo/t5׆ҩc~O_d@K}2P;*3)U8c9M@Pϒȸ[n>:oٲY'7GpG/:Yj[`$Ux್C]g'?}gkп+Xw7**s/ jY_6z1NkxwѿWHUEឳ=#~j|zd8jJWeuMg{}wv*Xq^c={ C='y-Z uFiѢţOu-tn2y-|S#F4ogYGE`l)5翘8n?Ekɽ{po!4ɺ&0:eGOeW٧Gq`zvAtu*.D8k[rK~Vն(~_~ٳw1+@Q/K/kÄ?~WZUH.]žӧqXnv# Mċi{U>x{RID9Mn>~E*낷W8黧\ynh-Z\8rD4O1IDAT=_OE+xeݹHGrcCNJ~ǯ{Gş;TmƬ!?M wla-[wYd'߲e x9O>X;U1~oC3GU:nUIWo9%StVewO_ٱS?Sf}HƷP]ݺ1h5W9/߯_y. .L峍CQ6"mcPkD[vAsۍһ_L]atnQBvڨ*5b{#^մxr3^ܡ;(]TJH~);/v2n]k_~:$S|(^ DWmRe˖tҨڵW~.uJCsƷ@=ѨQӤI^r3g*g?bkOCz9 C:O<\@Ú|m`]xEa|j{qXhQrzmEv.طq@$1'8EHwKOJT,;BݫWTNs\zXW˵l"Ԩf͚v_P/; ۵M O[B@9s_~%۾믿Ci׹SP ;o.<=skG𝣏 gɧSN # %Ա./>B&Mvgcx3o˖-'om?7,**Zpkoڭ{Zj1b#_ݢya3ww$tL-[KF[޵K.ʕy$|ٷlۑߎP(+l>o Ԏ}evԨQ(ُԦ}G+}t;kgoxO>\RRRbw޼ysI***gׇw蠨of>޲j@k(_wͼe/ ԾO=~9ZְV37w#n@(,\C^{}. Ԧ__~CYK=NjBn?ӥlyYc;qơZ;S͛7axbwߍf)'guxgiڱKEkX_e˖8tO 8kF hӽq'C*/)IRR$;>{G[A۵'EW$w޹eL>ÏM6 {,s5u_ 80S|izJK) tuߖ-[~/[SNnr?ꨫfܹOnrQ#ye޼ї\lY|1 u+̝򜹹3rrsBd?Nc=ȋg/Ytڵ֭ $O;M z~W$vmێQ2{kwk'yW y͛7} ^&'W㘮]vAg_QQO/Y߯_akꕿx}ɨQ3!HRQQQ>۸>17o>G{/{slԨ%$:>9#x׬Y4IeSOƋ3ww @-Z(^wq.y= ,XzUC=ԵkΝ:gtY'_G|Q1d:}鯞}!rw;SRR;e?NOKcw>:׿7bHDӏ{`@Qf<]>0*~c9&S/N*=Gwt#;~͚7 }k9`ԲaÆ~q 4g~'Q?wþ?9u=8}D֔E-[G8P}uJ}w^bɒaY❲دW^SNM/?yBUW_z@Wx1eaw-[K[Gռeoo%PէﴁEGV6OiOpzmmQS|p:7+۩O~7^k^7cFN}_}ua؋.Z/zsQU,r~ؘi?6sW>,P3.*}jzEry˖ :a?;r_~9Ծ{]2;t 5bky~ӊOsX}]Sz_|z'O~3w1#Bg{Ej]9,m>9ץtoig߾,wG]& 9!+{~Xys_VܲCҰ;O9>.I F}Njh ^c={ C='Po_E>{yW^&q^2: 'jכu(R{KAEv_D6}+N)n޼~}iѢŅ#GD[[~6b䴇wx!x}E8o%Բe˗;K,c[l?/4k޼y`}vċ勖j(Wj+VZu! {EJvvƠA\t|~Wͻ`ϋ;%c/oqg'E߉ei/0䲩uNi=ҥB8sY]oX2WguQKĩ_0=? cӗC&Tgвc {Qf>5cwxɩ_`*MlذC|MRRħ'=5a'|W.9hҤɚ+Zj-[?थKFu׮]` uIVm@a_մnz "JL~TG]7x}{?4jhDcT\3UpAQw?ӐX>獍kwo~A@$UvAs/:'DHy[4{Q|޿ܓ/{qbEY篚^{tgw`zZG[ӹo1a{i"%%ePXS$w-~w˸ڱ\ 6ڡS޴n(}V_=rQG=u!\*^o>P99 ЃS{N~xY^ɝsʷIDATwOu%KEJ`gENie_c TNGUPP0ex?P9uԖ-[~:[SNnr?ꨫfܹOHJJ TNGʼy/4oٲc.ة |q}hܹ/ϙ;#'1y:'I-Z uF7G^={ɒk֮]n] ~ioR`7oK/ۥbE kv5WS_k^;λ g@Çpk޼y`տ??{g.Xj|79Ut5[ R=K~zȲ~zߤ [PfKF D*<ټy=z{QݻwgF,$h&i9Ocf͚Ib?(Sǟx2^3?kJէoѢE @9)+((}@9IEEElPǴl/6m( h&iP$$F 'eVkh@T9ԸN.X\yo| 1Z>NZG济m\8d3.i`fI#{wHgg@I*sOQc޸MmCH Ћbk34f0 0->X8ǽ(Vߙquƒ➷;f蒌nT>+t}Nݺ7($t{C,̻?cKK(.?_zoiwL<#y,ԩν tZ۵-2_5BྨiA~=&۵ne;3z߹q߶cyPIso\'Vrȼr! }Z3;CTN_O>˯:@"+qy_.>Tvēm׾MniwH Bq!ċ%K=eKQHJJ ԴFJ~W|%Wԧw^bɒ=M ԧg?^L`AAAG/3ڴޗS}4(i잖f^G<:( ]i~7^k>۳ғң߆ӓκ'@ԧ/2_%>}_}uaCڵvhnIz|Y58d#=>9Ӹ[n~ixlـw'/3of߾yf͚v!@#̞z iA^Q7nXJ4?=5/z<>WGWoؓˬdy^R/K/kÄ?>;T2jGu 7]7qֳ.?CQ{lVf bb#a|-(ߖ_ ; zc(%smƇ'FW(@P/g,ӢE GPE|?g=kݓO /ήl5Wӧqx9b#D큯fEI[:w0+/> O}a].+c}Қmb&\;')>wGze|nP _|eME~Ll_}_7ޏ{_?8%gM۳׆nz{?«Nup/SbSwv*sUI|=+6L(猞U})>Iҩ5{?^窦(moۊዝ~C([S P4l,ڦm $4H 4kҤIFc;vp*<W#BТUPg41Ԓܗ_y99SN>C{K@3oX~QQz;3ûv=})p@,}u^d_panҤɷ8CSi.S_}}^cƍƃ:!j*$:u/G>-,I^;_P٥Z'g}Q~c{>I&NkД199OT|gLO=c Q3W>iկמ?}x[u0&+-9~ e܊|S7 rGg$=౳kIHf$ʊ\\s{O1`+=,@fEnvv<)֥1r֡?z46a3?G.k*xjdmƓ:)oӞ_3iO?/`󚒙DGMfXt#%Ie_lTQeTnYcҶ6fm'wTP'wﵧ _nA6?󢹗6dqUzOl~ؘ?fÖ>+ͫUN(̛>&K?SF,/3tf3% hư6S-.`ʈYQŢq#zuIO}qX|΢] _7.k.IRҲYEcUx*k=eDf!Krns ʒ/gړk3lFi{ӽӧP+v3[vEגך?\<,f˟hqzm{ve+\p)%N$?='{j[}Y>͓FLwTVQ5_{r6s&wI 5x J.P Ԃ:_\΢Ya?TimC/+%־əck('~vfYO 5!yЄ|޳};'mJl7I__wӹ-nY瓻deL94~έO-.(rk;%%%%ԘfiYLY_X O5Tؓ@%:/9s\~P"ifŇ*w7v"oLxEc{S/xO?u랻%ޔ_Ѭf {(oBfRRRfmZ19oF uaUZUT^@Ml)çWq)FSշr&Z2ou%4bi5{9',Xq žYr'p~p(9iإ=i^^5{v=S\/mLΤҵ_=3RFdā9&'0>yL3WrRRRʈxs(/͚W1oV̔ϸo /ml@շ2bzٵgMv4Rz&_ήţm߽WViɥ~Qj {Ŗ˚_'իګvTRQQQrǦu\ /YTpmB̚?3G?>TIf]0gDΓҫ GwyFE%Z'#v;0TS*|նO @*#PI H H 4 0gDJR4˜~K/w}j|9;gUz-ђUӴA]kIEEE@"@"@"@"@"@"@"@"@"@"@"@"@"@"@"4lZj @@@@@@@@@@@@@@@@@@@@@@@@Q Aܲ3CZ3Or>wԴl]_޲%! 5yCnpom|e{C 7,uHFDfْЭ4Y}gFxz\[|d bŃz߹d6#{+8S~+l+}5%_\ĿZ.\z+N)GXK-HJ* *l[>/)}E%]K1[λ4˜zߴs[iҩ!ttA mz[%){7-Ǽ{3Q{{MsO먴:- R L<7c[SFc}qKnr|i>4$%㒟eէ޷ᡡӆFc`%_ϻ%3شyy3G^4%^%*H/q 1Eм GBl، CpI!m*|C̓KH@[,d|NңZ'GKFwIIk, hIcC >#k8NIWgL4Zx4;<6sdI7pR!qfe<{xp[CCJwN/=3x^R`x#Cwl,cOطـ EDE6rɁyO=Z|􁧆=./YmZG_9x`H_E*o=;G:m`{$$ndy_}'8_ r@˖~v7߼nӦMR5JJJ:Û4iҸq(;B^KZwլi=|Wd$c`w=u[LHۛo @]U9O{QѴY[ҨQ=X^t{w7?W\̙*'<4x}ī v>\m)<{'ʼngn3<==)ڮkm:SNgmE>t}K}UK`VJbײur5ٳN}w®"mZ Olj3L;QzcyG}~N;펢/vާ{ϯ ҥK_xo1Ts21X$/o]̾*s^̽YcmgM/י:條}oJ"!;=)|{:g"e#Rnn.hʨw'KU*{Ne*Sc|iw٦h %ԧ>sfO?啝ϸ=l~cW'HtJ;z~v|SJIcpCk+ԴYӰ@%ܞHn;NYŬLn7P1ӦUrǦ#augDӗ%=]˲U]!]o:d<՜W.R2v>rCw=7L: bB,ջcp{'6j..7g^aVA^{ּUg/˵-(饣p6ءCᅽ_ӠH,ƞRAnV79T>yW0biCᎍeUxtq~/ֳ[C0&j}cqXeo="j[/ڷo[B9ٚ8M۳eeQTH9c/|ָ9G7;oGV"^7t{j0(>y!ċ勖sYBzu9%Q—4UQ.겘pں_씧(4>0T˲%i_JJP\4cȿ{JvcCK26qfv#LJϬT|Nu O}_PEQqY|Bۻʕ!g^6gL]n~lSc|ˮ(9:厐^:AiWO_,~W9PuS|(^ PmQt7`VqW2Uf|EkNIS7ΟbSӓJ@6ɺޱtր̫^g[x͋iz HO*>ӋWgT:Wgl*;rǯ}ۗ/{@zt)7=~Ql_xtaWv챽%9?Ncǁzl~^TTTT6ղsUc99C8<*&OY:mJP}yX1}xکn/~}EU^X`B6lй7|4}O΄swfʳ\r%QѤI5+Wj*Ծ$ҢU >yҢ]WYfY/lٲeyc_jn@=w-[9"65G~_nE .^_8rDbO~7/c;[]vًۢ&ޑqx`(μr~nD|IQCڵ7 @]UȀo)wL9ޘFW.n?=߽b23T?(}}"ԾG}Edd@87ns_}uaT|s2~vO5Wz}y˖裎ߝݓC @gw%xpLJzb@otcHߊ+WenKIDATN`=8eȹFJ~aPUoZhq+QanPQ~Ѳo# Ul1hPI]UU{\FZjCڵ Ծ+މG~!TG_Yf㺧Map\/}{W@UI[n˖-/|P]N7wuBIEEEl@}'|7Xժu_Y;ԢU ǘ'f|;tHKҾ}JJ@u}iG'?e˖e5e=1#VEW_Y]x;fJ8~Qwm]tzwVȣ]J7ouP ,ދ7YG:7k֬K"5[Ԥ@Zd_jA}e/ټVK%O>-, 솤PAֲe֭Z}C<ۍRe|aaaalD›#÷TTTT6E69$$$$$$$$$$$$$$$$P@@@@@@@@@@@@@@@@@@@@@@@@@@@QerǦ$UYJAcbk+^?07{xf%=ӲL[4WRR愼\=fv.?"; ڱKڸE;yN&U^*f)уN^T4 en=kdnH9詋 ,iY?ӽCx9;gUa98s zБL4y"Te/**Z9>x/uʢ29➱֗[|⦱?OR~] nj 5~/sLq:4rEa1]x̞oTAg$E^lJ1آ{aIRҲY/wYTlͰ #l=5fL|5G'L/k͛0؊SV] .5o]?\kLY;2W͸uI4!7{`lfe6fB΢¢-tAGfmnugZ%v^U=T_C9~ẅ9gڤt]ϭˏ~"mk:Wrl[ښO=I ?]%`U:G@"@"@"@"@"@"@"@"@"@"@"@"@"@"@"@"@"@"@"@"@"@"@"4l{KVm{?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?H?HM{g^d隵k׭[;c={ C='@%Ux್Cʼy娷WԷ8b_9ޡ!iѪM`|[ŋ\;G?ݕ]5jteCQ߬`|ײurشG?`Vɭ~rOR{v8C.aXjk/Z22|͛VYj_ ьn=8m>6_4{Q|}oOJJ u.k@Y7x>")S{a'|r`W͛7ݣ{t5Q-[~rO/^]vY/ke zߌ_fMozK"ѝd^r3gة=ēijOpDPsKJO>CߟT ~ݻ?v iߢE1U/ݏޟÕ͟_MsX١9ã,9B]-,OLЀċza]zEr\4NX:ڱLaw]q| NbײurVπ_=;Tw~g}bq]6-OrcUꕏ坿5˹.ҧ;vC>E~~~^Wn=ԠgΙ]6f}A7Gw a>*X^fM=gD92IDATPChpPTߦ ;6MY_}Dԏ>xCo헿(ԜGF˻꘼y}U,Ԝ{۶=xeWwg P}NYeKֽ{򇢰jÆ r!bY$KIijNȈW޽wYq>FXArϴ POuZVOhyJQ ~30IQdek`vz7埏r9O/,џΉ'v}LNO.egeOZ5գ0}tvU{Pw_noe|VQQێ[6}R=!G:S%w\8fϙs!QѼUi+j*4^}Ձnٸ%Y|O}|\zZѴ |V,\ftF|;v̷z&)p_YVͭQ~-=?Oڷk>]>K-]6Yn2 T?7ϺLuAp\s>ŭE?o}a{=]SuVn W7c? q}|sUYng7tk>U[|cq}f~}֭[M]KJ'oNΐذa$~$Ձ?I $?Hz=?Ϟ=gӋV^oF8(5i?۷o߳ءCIm-Aqqa_[n۷r衇^ˮu 4|ÏC&ᐐm3ϔԳm,b{[O{ٲa;J>W\ٹsPGϼhSN9S32߾I&ᠴeϮ^W>OE-]wSW;7џ2P)-__Yْ_ri\+']կ}5HkN:s'+|sLeq s.9+3mZN)߇_ߢZ"w?_ u$HLMaÆڏ_Y6w22Cj:ӱ{}\u_NUF_lJ^pĨZ㮻"oT^zTg@/<;~睵}aظqS R2̛?Ul۶Ƒʳ>ÿ=<vN0u} rX\,Y_q|= ɕ_ɓ{)+[a ^4nױ9QW0%CҐ>teip?} 6%5ŋ;j:_n'N8I?)ZGWإOݡSFaw]K~8CeÆ|to]`AIrgF_)nճg  )>r=x|}sr7oON 5S r*&ĐUK'Ѹ~R~u;xܬCӫƍZOɘ8xL~}:vʵW|kLt}w)ۺmz Rr_F~t -[Ï8v23wZ\QgUV^~Us(-76hҢQdXٕ>9S֌ c>} ZVn_O[ Rr_.5igDP*zwykC̒+6wqqT+_>Oo{g[cr2xA6lHTMb55rDte̝w=fܕQ/OiuIhshċG {)guQqjp %x?um8ʗE۶mVQQێ[6Lk?W^iqO5lo^޹}gnQńIycUe5ټqgƸ5C3+ӾqYc:ee':VwK'Ʀ75/M: ?4 'S-Y4*F쇗WtU7'tCJ*}FƌeOTEqWR/+O(Rjف9W4OwyR/=wѤIxWgy:ֿ]}*wam޼w`zq_w?2dWߦg眓n]ti:^++X'dTW?8cڀC9 Qy/6|֭!e}3yWS|ZO$IU_vq_JHM睛7'9 ךjK.ʔ,~Ae >O8s?$U=M-@R'$@H i<{O/ZzK׿ԤIHOo߾}'пcv'b[l Mś7}[o}?}ϷoRʡz7/;5h  ?4 CB}3e'u?K/{֓{^lyJ>WXѹsPGϼhSN9S32߾I&ᠴeϮ^W>OE-]wSW;7ԑ R2[^䯬l/4lt䕓׾zQ$5kt{œ Q_9{nuzڲ?J>/_‘#~23k٦唲))}H%-Q-:zQPG?Ko6lŚ5k{}/3+3c;{_W_~nŦMHL^} G;;.F:WHe}9³wYY۷ovል7*%ȼ_uMmF+>l\pଟ]uOΰ+Œ%K_~LJ,$W&'O~R%{EqѸIv}pS%ysBm).(51#(7h ˖/@RTJ&ݺ+;m &hOvp]t 5)#dt>C9]6lnǔ,XP8qvW{HB \0lc=>:{vtEEߜӬB23w3hvvd[S<43`NA.*ֻ*)H]ݑ;tB~}w:vʵW|kLt}w)ۺmz Rr_FYoh٢Eg~]+̚]ZZQu*lWӆQR8|ܚxʬqY.8kǣ֌+?i~} ZVnΈ[ Rr_.5igDǿP*zz_ro wYWxr޺( ,ˈ1rؼ챻 ^6=l{g[m2xA6lHNBQ#GD^yׯGIDATc]/䨣UKW="7\SXcG;L]҇sČ=ԝK ҲԼZʗE۶mVQQێ[6Lk?W^iqO5l\}/]۬|j1qV(kϮKow׼_\6m74j,ErNdҨU0^R\UEtT|I|u+H3zt\_=YR٢_F_JH>}`Her|i5i P^${I&Q˯~5;!u/0MUڼy#N✿~dML9')ݺ:u8(WV,\%Oɨnpƴs@Rգ/ğzHY[z n~nܴiӐj5k65ϱ VU{)+[tׇ|RI'v 4ǚ?_%H$?H$A“♿yj޼W_~ }t.'__ oiغeS84n<.ܼ//ա8}_}Wn'8NԨI~8$$;s|zE7=˧_mRr+Vty]oY_9g&͛ YG?:CfH+׾W-]5)[6nپ}I??чg5lpS-[H\|ŊݶWTT hdu5믟^svNbHF}{u?ME_4=l R3[WS=gN\=䮧jV!6zW oy3~ۑ?K[6LU˖ifm۶Bח^z);vxߢ9$ۇuj٪n.sY3z6l7nQfثvQ,g}58 oW_$z>Ï8<׬Y;ص2pDu@j<6oW]kÏ<rtÁS2$;;0u}%ѣkU0'IrΉJ,$W /}'(+[.]4.:\ܪ0$JiEǭd蹃ߊ {OPܱݗ/3hԭۉqෲoӾ2`@޽^g^'̞ai=!JvӾ~ҐqIgvf{ǻ 'N*YpWs…$J538ٳw7mq]j|Bz6wxϙ?uΎIV.j+,PUB_5;+7wog*%F=4G7вEϺ2tܬ;mttk +ssٹg*ڹigQ¼;)ZfMpW>k\VȘ8kИ& l֭ZrM3}@Bn/tԈM]KjyfN'vpgFܞQo]nQEqUXWpeisw[vmY :뛓3d6l0h)Fn?bղU_Pwg(U.œs/wv8P\E{KVE6m^KyH>w먣UKW엟֍3 -`N9vn!L]󈽪3?cUdG׶m@}kvu]}':J4sHv}ΞPjoǒ؎@]WdY=>54Z;5]]/4cdžP{n$b[l Mś7~w9[5bZB=+8p-Q38c ?E4 {;tn,\D3o~/K_:/$zuٓe%'?Oo+JKK 'I"}sreq=h>_|H WDo:3۱cիg@=swZYْS}vӥK.!A[lS?Ue~͝YH&[n`{<3gNFe g,Yoh٢EZju7|pc?,kmݺu5$$Tߜ! 4aÆo@R%9$IuXR@I $ ǬY[p^^{jղeסc^=֭$b[l Mś7_{wߴ{g?p FM!ڰa9y^1m׿6^r7?g=K>WXѹsW:3ƞv>_j>Ϸ|zo[nϭZN:c=6e˖*%-_"kWϯ}s|O?S"ѿ=zǍy~X\X-߯k ֭[\T|pipdk~v͏~vu}a?H,%iglذ!UӦ/חO:fh\rʯ֬YIŦMHL^} Guwwo߾=*2;d^~!|oxPw+pƍ _d㯺&6.rOҜ*Si~Fڸ~w uW,XHTM"OeeKj?_Ws5^;5?-;pPf\JDY`AIMSk׮ۼysEG_wHB 8[Y^޷i_0O^={٣'V_<5LffVCz8eK;e4,kV ~4mtK,X gya@dG`{<}t芊99O͛W'du!5wpcIA;orgN_:]Ẑ1nbVتάqVݑw;dZ8â٧+9]e}nYSuۏ7Ӓ}6j衙?-Z}R2:urgVV^kƕ4sh.te[\tol^]ZFVUnOҵCW7kLN-0?BiPoNΐذa@p9"j9~eyy*\rmGͬˌ]u}R<.%s^9.s G~=k߶mQv}|6Z̆o=2/a?''@R/nrʿq;_>]Nu± ,/Czs˛qc-J=yG#HzE֬Y _mF~$U;ZvKpp}7H@5^z9e]:4m~C.>s\8pH*_"H$?H$A“♿yj޼W_~ }t.'__ oiغeS84n<.ܼ//ա8}_}Wn'8NԨI~8$$;s|zE7=˧_mRr+Vty]oY_9g&͛ YG?:CfH+׾W-]5)[6nپ}I??чg5lpS-[H\|ŊݶWTT hdu5믟^svNbHF}{u?ME_4=l R3[WS=gN\=䮧jV!6zW oy3~ۑ?K[6LU˖ifm۶Bח^z);vxߢ9$ۇuj٪n.sY3z6l7nQfثvQ,g}58 oW_$z>Ï8<׬Y;ص2pDu@j<6oW]kÏ<rtCӮcskľ= ɕ n{j N =3N`ٕ?]5?wſNT`9s{{`@䚿?g^}~绛68ĮSN5>!CևZVFW9SӪ5vkw־ߒ?r5ގ%y'gWOe_V+\yZZؽc\߹{~g@BdרQfZhY,=t͸p@a8bָPx[)2٥Uv+W冰ng']EYc.fURԵ0ogW+;gM,3!w& l֭ZrM3}@Bn/tԈM]Kxf_ wߓ1qV ]Y*cj)]Ɣ\郋&xN'f䍽d9O1:3֮ 3 V!+RPg}sr 4x -PogTZK]QFy=M/bB7 \DNدrAaU~R~p`\2.ڴi_FJ[GuT\Z*8GV.sMa Շ{EJ  z38 vWu_+]W,zu{_:(_#k۶M>I5:Į>\Bw,l]XߌqkfV S~w7rAm]՜s1_izAhU &W41c¼gw,(zY;Qu׽[@}VQQێ[6L?;{Μ 歚O[1UVU<`+8p-Q38c ?E4 {;tn,\D3o~/K_:/$zuٓe%||*tؼ#>E?Oo+JKK '3v5nױqDžD[pF`͟ķc|~= '@R%-wZYْS}vӥK.!A[lS?Uثgm mݺa{PϜ;{5j1?J9բ롙?-ZuV|g= ֭[M]KJBB2xA6lX$U?>JT I $?Hz='|g֮[vڵ糳ziN SZEEn;n2677o˼K/]z?B~m۶Ӭ}FM!!n'HX>=@bŊΝ;f1cշC =1_8 G6<2{ſdٌfD-7o}%7tcml@Bdv߭?:ksLgعgƒSU}\tuYsz7DO/oe%}._1Wp5q5S:X@>]ojݺ8K`)M>cÆ {qѸigf Mjظa|nMs( @rdk]8bTEEŞόoV!Z[7ϘiӦ=ܾ} Glܸ)P)E͟?k;{8lֲSӲ'ߵm쪫$주y6{oiط_U`A R5>yrz-hגKkNS2dU{SvxҊY3UKw-^}qg  )[oeyy~}e>{٣gSOuBOv ĺgWFOo -$33+!Ɓ'>ab?QX`…O,X8{ΜE$J538ٳwO?_9q>weU;|p̜x΂loȹcS_Wp]]W:-,TRbƯ_?g5;oYHL5jxC->#5u's +ߐ3}Lq QZZQ c{Zi<+wvUWEi(Xg:< >uV|gD-P)|]goɤ>{i̻ 5iCeUQ!gʚ'QX<4qٶ99?ϭ_$ZJWQFF_8bdD Ͽ!V?:.=w^G>*.V-]AbJn.کiS׆O@hۦMJ5{ҭ[׸/0;7{@:wČcKGOZ :Y+=at倱yJ'¡N,1+dLc9ӫ8tB w&F͍TX{_nUZEEn;n2677o͛7KKKmm=H솟_tEG54iFM,HIDATC2wlڴEEk^{_=RW^-RףF1 EZ|Q~ ?^zqyT߹@=ew.{?GBR_>v̷߯CT O"n7(--kj|H*}V<YY!Y?~3N 5fϙ3RܠG׀CYT(#H>$@IPOٳ,|zի_Z7&MGzz{8y;t;iغeS84n<.ܼ1쫷z{}R=˿y߹Aa_oqhԤY`?g);gnY~{'Eܳe|PJbŊΝ;:zxE#GUߞwʩ瞚M7 -~vuO~*jս2z޹D 'eeK~ɥq}d#tWpЋ"ɮ9]܋-\\8ގ/?1ݻwӖ-$VJ|PGەY6-MIC/ɿo}-jѻ:$XJ&ӦذaC}/֬Y߻{Y!5>z/s/6m@Bdk]8bTEEE-qq7*YB*3?Zھ} Glܸ)P)E͟?kj3W^ygzکiiև:v尸Xd/\)UɂJ/rOQVd>(.7iܮcs 4`Ne-( ;oаA\--^}QՁLu;1.VwLI§jԡSF!|:jrHlݎ)Yp 9373PG`{<}t芊99O͛YY'fef~xک Eࢢ0zʶ٥G-)H=wL1qVwRٻ_߃;.zr-]w8+7wnH\רQfZhQYqxfefrW-giG_nQEiܹc`}USvWe۹gU7(|f ljuV|gD-P)/veqѴ3k~IInY ~*O(]Oʯ\76/{.C rQ]ɐxuUOeni;q km7'gA lذa R8 UF]{s]wweT a >#\Ƹ5C3?Z ߗU{{}qQ4iţF꽔N:꨸XtU8p O]!J~c’!W9I;fT-GKv$m۶ BZEEn;n2677oW^y:So<հq\?)?o4 .*ݱcgչ}w|`_ܞ;( 3&*NoW?.c⸬s?ZycRަM¿}FMCHΩ,Y F]B+O:鏏Ns%I>#cF8i7ɲ=725UEw~C V-;}ʗ_3xiN=ܼUE;4i]s;oRǿw /Z.͛7;T/G srҭK.[+{eK\gLп;$U=J"=Æoݺ5|3jʗO n38}S:+_ s=>~$XZWmeOůz8lbAÇ 'tǚ?_%H$?H$A=JӓO>3k׭[v]HAef|N=~)b[l Mś7e^x饗.!AN?wmi>Ï[&ᐐtrJz$,DotbL Ew\bEΝk3rwۡc|/#Rʿ Ͻ_^\Vlm3͛7׾Q̒o6OXly R2[^֟^9͍3nܳVy)*>.κvË'O]z7j|²?J>/_Qի_u)}HF,{K._nj%HLMaÆ~øhܴ3nLτdi٦{5l0 7}|Ŧ9 R2{.1bO^{gƷ\D[gشiӞFn߾}؅#6nHL"5{={N 6kgOJɐ촂׸ixf}{U% +U'w?GYْv-Y4.t9@\WC keOZ_w\wh+;_n'N8I?)ZO< 5>-gFJK+&mҵ5x !CzO7Ս% Nt!~f^={감~# cǷΞ]Q7'yvubVOK1']WY .*ֻr]ªܢsN=.)]5,c1 xhǽ^Vv<'NK ŭK')+<jֱ{Ǹk!rVnmݶ(Tk5jxC->#5:KS\42ۛu6ۯxvnUu'TΚ G ֔Vgی=};Vn9|Ҹq͸3SPG6֭ZrM3}@B䚿]:jEӦψ%?EmJ?.ktTbUad˯:/wҭ;R2$;{HIya]a;,)HluW<.ڶiR{ߞt5.1 s韞yIFذ㼽9VUyi7kЪv+ e~+V6zǔ[T刽+2 oj/bu׭[@}VQsn2677o͛7KKKmm=Ψ)b.;㲨8#fu&M>֨I~HnM69⢨rk/vWuʫC z5~$X2ws]~6*o|_!Y^W:5j;^l;eOG~HHyh`ǁK-o P%jW_SpOo={ľ'v3M?RX6Yt-ǎ|s CIDAT*_d 7C]WpW@R%vjQ4!++$of) 9s6xoB4п;k%@r'$@H S-_o//IOO?裻t9!Oj~Km-Aqq5^x׾~_Wu;ƑuFM!!qy睫g֓/_>^m۶@}Xsλz뭷۰UVEuvʞ9CwaÆn'qon&4 쇔^} GPf9{د n~C"~Qfڹî#c?'Uy珿][~Ѹ8%v圝_#W,XH^wOQV$]ti\tչƹ%C JZ?)?~jP/5-^}qg  )[oeyy~}e>{j N =3N@(vmc5Y㯜{ǻ 'N*Yp9սz\pa Rr}3N}tkMvbשG!C-U+ꜩiUu;[kw(H.wS,LܪU/?dR~<,ϟ:i܏.頻*kcq;3 _FYoh٢Eg]?52ºaҊYBmsvYKK+YTY@.((B Uω]#;ƭ0̡ųsC ϩzNO ^=3CM࣍[f>8#nJ>c_vM>#̾(TfQh*΍=w1+ׇgƸ5U1aZ\K㍽=]zWFPg}sr 4x -PogTZK]QFyr*&NV~qXde\i慿ꍔs:꨸XtU8pzȭ<ɯzͪ3*wϗ)%U )_#k۶M>I5:Į>\B,l]XߝrV);f5fǺ17:-MZ{掛1w:͚lހ?VQ+GibU{aoGO3$tZݖV'ݻu 'iغeS84n<.ܼ񣽳9АhުZmW_yu`ǁ[6nfqo)jԤY`?$g3ءCTl|uc=%I}^~Y_9P$';C'8˞,e->/4z[QZZZ>IN雓s7/iE7CҭX"z?ߎ^={WoʖTߞt۵K.]zw teEz({lr@R%0ۺuÆ?㡞9+7w6jh/c$I>cQxC-BкU[ni3` \Wm֭Ӧψ%%! в޾S uْ^W]@J[beyy~ |-|>K.F:eN§v~!Tˆ 혒 'N:АN?3Jqc= uXHA Ggώ蛓Լy{ubVQfn߮pݎqkfVۙ7v]7kaǤǃv6vӱ{EUe[cCgNmIk5jxC-j?#]d+̚]ZZQu*lW!g!>;}͸06/ި* hu_߃G6ֺU[ni3H\KGh5n{7Ԭ޻ޗ;7;w@]WeUSr]1q̸}蕃 GO_ߓmlͰ99C~$XZWmeOůz8lbAÇ 'tǚ?_%H$?H$/l?f݂ /믇OU-#{ꙗGn&iغѨIDATeS84n<.ܼ1 {M>7Çw8@>ox@4j, Ն ;o9hcȿ˾y^?YJ|\ǎa?^iQ籝׿ڮcm?6|^+V[zhs?᱓Nڅ*%+~x74:A/O>O=Dg:f_7kѿy֭a?< R2pӏoY3o#> lpϮу?oWqİfzvlrН~׸iO6nܔuoFTobp8=nsKT4i/+++[ҷiշon&4 쇔\e>~;?{i^6c-[q]a+UY{xUׄ:;w} -;{HIDΫo:wտ{@rj~eeKj?套^zy٧e0zI~+Ǥ+Ǚ=>3QmÆ -^}'O$ZJ&'eVwLI§q68ܮQ-j23B*JKutn#̞!SfY˶-_qpɂ'?hi}WϞڷ.?e>iݪ-74w $T we|[2O:n»ޭŨ+fZwc/I=?Znm֢??o|=h)gF9"j9~eyyzDڕkC)_㸾%,`)o׽> %C@/ގm^WW-Z|6#-W-]υZ;5]ʪ0/0OY=?`neSoGO0$3ɳܴr*=i 9昦Mvlݲ)d7monUۢ)&q!۷5EE{ׇ}u@ǡQfPv\z74heOB*q/>%s^9.s G~=k߶mQv}|6Z̆o=2/a?''@R/nrʿq;_>]Nu± ,/Czs˛qc-J=yG#HzE֬Y _mF~$U;ZvKpp}7H@5^z9e]:4m~C.>s\8pH*_"H$?H$A=JӓO>3k׭[v]HAef|N=~)b[l Mś7e^x饗.!AN?wmi>Ï[&ᐐtrJz$,DotbL Ew\bEΝk3rwۡc|/#Rʿ Ͻ_^\Vlm3͛7׾Q̒o6OXly R2[^֟^9͍3nܳVy)*>.κvË'O]z7j|²?J>/_Qի_u)}HF,{K._nj%HLMaÆ~øhܴ3nLτdi٦{5l0 7}|Ŧ9 R2{.1bO^{gƷ\D[gشiӞFn߾}؅#6nHL"5{={N 6kg}~jWMwO_ȼMG{7{4*Y \En#}'V apQgiM_徝ǭ-=$@4}V>kaގv[w/ѩCQ#}@VnΈ[ Rr_.5igDݎywۻ5?(SrugzO;w%zX Xip-Eŵm{ꛓ3d6l0h)F_8bdD Ͽ3׮ WV~K'T%CGlsbsw^J>ktTbUakےs+f+C='^S8`=>rSׇ:+_m^'ݺu}K.o캪rtv .*;߮pݎQFU1qVJgk]X5\>hav<2zH๣^:nVcn79oGow:֭[Jm-Aqq{y3ڽ{iiiͽІE/ˢ#ۚM4OX&!}6mt䈋"5ڍ\)ׁ+ )Q#G`L"u->٨bdy_=8Eou,wCYKjy`♿ )nk@Hz$uXR@I $HxW<7O͛|/$==儜>}-b[l Mś78x_%]:ǶoG~5iyw/[ObH~{mRJbŊΝ;뭷:+g?LY|ۤya5Ggv v⪥2e-۷o8'< vʲe kXtڋsIXި9}/?iܸhF^\-$Vj&w>ShIDATj̉!]>*$]cFo:#>:}Ưw;R`i{Zu˦piܴy\jr’6mڻm۶OK/Eu[t!$=پ}nV-[e.+{Cu tƍ;yc84j,R2{.1C9cG6a *D~xG5kVHT͟?kvmyG┼Snt?umĴ.윸od@r¸'O~R%ҥKs5-VPjr?O퐝aU_cWwu;1VwW ӻ߫3#,bwz).̮;^8qRɂ̩ճ炅 Ik~#gqzg_nڴN=:Ymڟ3ʟTnC(//,)o;L-9qǔꮴ9y~S|':+W}eaeTY w_;oYHL5jxC->%ts fUV^EC+J5n֎ +;zO(51#JG ֔V>9ώzNh0 ÎW>3JuzFPG6hcVnΈ[ Rr]:jEӦψ%u<l)#N.-_ge[S<43*ó]?933+W(.~qhD2wNRPg}sr 4x -%UkԨѨ#yj:n\lUUk6&+_f8H\2.ڴi}9>< ~Aj':ꨣb}IJQ_Qg5U'ݻu 'i?nM ӸixsƏΞ3ACyVLkնUHUv+dV:M{Wve㖨~hfg1{FMCrv=̎:DW7 .S>Q\:-۾}c/}ӿOz eO2斐R*Lf.пNÏGx鼥qۊIrv]}M?=ul\q!V,\Q?X51|O TIK"}VVO:D.}2Bya).v~!DDsÆvLɂ >]`97|?DE~# cǷΞ]jESiV։YFZ?)?o캏 -;J׆d*%iƭK'ӲƍZXX51c1{ؽc]1~rso RlXFYoh٢Eg~JS1[E&^䨣UKWhBFyUNb7~ʗE۶mԇ'zLZEzyCv>:{׍+fM Ӳ+'fTK+w-Uڣ^y_^剀vn7GMolxqC\gw vlݲ)$EΩ,Y F]B+O:鏏!$B&!k"cF_'B*[_˸+TӧOTTTT )X *_Z~ke;sT}F^z'ܲeKTzءÿ= )oU{yfei&$>S}I"{!C6=3=眜ntҧK^YpŒ'<'DQy/6|֭!e}3yWS|Z,?T/vOg+!5wn޼'H^_k-])S|_-Z 4h>!O4`#O I $?H$@I $@H $?H$@I $@UTT YI $@H $?H$@I $@H $?HޝWU{_AH(* L %Vebт֖`o+Zֶ$Z[ tP8^c!S* J}IBIrN><^{Yk@*@*@*@*@*AIDAT@*@*@*@*@*@*@*hœŠt]U_\NEQnta'Hisr̴ L*,-x_ҰLVBմ7oUŬAH5|ȌͤRW桼0ا4Z0~3uJM2dcv7ZΝlM6rx=Ś #GYS9)7l/) ItLn<0p#o]_sTvaI}*6ݡ<6["*/.+3ў9tE07pf_W9uH,CŒ[eS^# ˷XqWD:^Z\RkJ6]{].o.eR׻U% Ϭ[J4haqƗޤYUQ\pҜe^6) KRYy~^*7߭=>(#ekr-擿+1"tL],3$^]|rr27}I{w:vƂ񆪻7Qor̈=rvu+/1clV)w+f앞756.3hrcWYY^2`H 6h7'jYeˋ%^g7`dֆ3ss;..*,򒢂F}2.+)M}jKM;ix:bМaEe z[Tb瞽6)@KVSSݳF9#QfI~"+6u캵+gu挪-,{7K 2]Ω,ݠ(˅ ]!u3V;7NؤL_7/;7'rYcJߟs㈞뮭Mǎ=w#/Y)|G nuȨoolj@k:#|ٓwXwʊM~k2b靗68C#.|gt5gNA':mtwemd )Xa:&֨sFi۹gw Вle @@*@*@*hZ/̴䯢աqM- ̴/kȘڄ8*?7@3VSS$gRRRRRRRRRRRRRRRRf?\> T T T T T T T T T T T T T T T T T T KJUou)-}7^ ?ӭ_38 lMf)SWHh}3&:> v|ˉOؽlYUUwGJ SOSэ&57?H;>k>#Q|Auc,9uА=~ę;K.yXa!T.\d+ϽrMw+8#͆/9~'l7n:$իV_;ڙE3YY}4?H`W~o<5bH6Wx5&YQ쪟,H$䥗n>=Qo~_)N>DcҊ@cHkFEVN/)NQg!Kw̚(F^2r{]i}v6mLwsO1$ݻWYY뾕޻ }[*B<9O+ZXٞ歪*QIosd#;++;o!ae;[\y!4dCٗzDv6{YruTWVf'&g4a <;j{&٭Zmuf֗s62cE˖<7+6w.ˢzDA\?F\?ozuk_6O<3 bAg_ew0~<$';l=3J7{*vRΉ'+کSϞ=v}&m~_/^zYX73k|l0˲cy^R0s^Bx0f#m|77,Q/)[ KC<&!_E{㖜>}.y0}ꣻP|eyɌXᮬs7s!] wnVlл1vYx{c-_;Cm߾}Hi:uz^pAbq?@SmnM<W~wCT}EjyڵkGG/~Z0pѢEQݥKւgc=BsvH% \ЦMx7UӢDEc.-CN֭[Gҥ>Ph_8Cߟo))羿w7'+]Z!%{?4/9G?ѣ{W|7 )굪v~ڵ=s/Z=6Q/+ M=Icٲǟx׎[>_1~\ M"ݬjkDڵkv~uu쵚]|@H`w㞜3'Q@H`xz /|؂KJ䎏?\9sJKzrN({,ݧCAyǝ=…o 4O'OϝyW$8`\ݒ2O~Ƣ-U 8{;BR&ܹ:#å?Aݻtݵk)+i}׿_Mek>RrK_tC@$ms00o8{OZZZvt@2H䯪 GfGA4/;E23H@ %S#Q{h ^{5Qdw @ɔUW׾zcǎh ?`s$ $ Z؅Ѯ]aW~ngsO ʮ.ʜ?v}kxv3QpL{GFk9e g=<}|WQ}oXHi?v#sauã}b}'.~>1)^kGuDag8e 1g;)joR\ZMM&w|̴k('Q_jp5^ܹvװ%0uKw.a}OuVY=Ͳ;G}: xM, mݗtGI]R4a]쾿#/^kj6]{?<\[.w|_Qp|}7g); GZHm:_t'>=yJ,;&]qagۇaY&.yEEAmD17. -W~;|.\W|œx /ʡ:cǟZne#Zs?H-4{z~oL{~򗛎>wVZ//_<19ܿ_r7O>ƗΛp[ܨ3oscxb@c|'?c"+A~K/z^{vիW?yΏDˇ~)# akҲ+WiWpozڵk'^O{w>Qwm\⃆W7ԮmۆQ,l'gtg8gvqqb~6%333k6;}rΜi_ʌ[*꺜oߌ{tЁ!|r_L]j:jSgX> Y -?n>h̘-שS =ͮ_G_2~EbxJwhZʜ5k|G_={GUznk?aEK>{{W램HKKʐGu I=|>a]dÜ?H-%]@"KOO)bMe7n:.xB['ŗO,哯׬Yw^ sԳoFDz$Ӝ<u}\`aر\rWN{gdsޏNY9Y(xW-oak׮\xO ״`7JoЩvɉw}lkמQݵ'yf?GE6gLl*e_z^ ׄ`Jk=|oO ߈o?ye|AKueiu5Cf͚@3dN0߿(Q蘾=M|zh؂Kneee{a+޸%O[m,ܙ5Zykiʷ[k : uk ͤW?1gN"*_2t\{rΜҧS:h/mѯG؊CzE:IDAT$=HU[MPݻw֭F%Jl?{v;lv3N0tܗdv6>9%36F\?oz< ɗ-{؎A\ݿz6o1Eeeets '+vԳgWO ̋677[ &EEh{Bɧ{=Vaߝo;t̼U}c]FU EƨbM_M+wNj9ϥw%ln6wˏYΝ׬YS?ÿ~fAlτmuk&M97VlK.;JgK rzeQ`Q]|#vxQMkf}jjjx㍧~Oo<WPr$s޼9>_E}gbauUyB ot?+'C<읢_~RR4+=6/:Cӛ}5T%)/~w]]萂3 ,YQ2sq=#OkcUTxnwl^>]?Ol'mw_yeOg?_fMVZ⡾OIz?Mgܾw'd~S|M3_Il2CMg_oo|` w͍9@$jڶm{OÏ|bɂ%]{v yݍ 䲿U_geeGYaؑ';MO?}?1 .W]vruO<޽{7CF}VTvhnn̍/׹*w19zknQ>z__[ +WӞyfFFK=w%kKl4Jہ:DlIhaRQ>}Ү|rG2lxf| x~mڗqs}s(:dȸԓO/ܹF&4I%>{;[MLWcS3/1͏L[w3/,d?vhܾ5jt}3O?u4dh1AлwDє/rnG,Kꔗf_?WP|cc[We;sea?(;<'aDKVBͩO9mߩS v{ծyBɧnMծ{_b_vr_f17%xʼn1cz`vff&{Fcm.c$M3ň12*2ȘhdN;gw;;frxڵk0pѢEQݥKւgc=U缚yaǙfn</D>|Y{׬Y^jp}vjO$sbzj~W&Q4/kדOTSouQtiŃ=h$bN/s`ǑM~!iߔ=^iii9:dg<(Q{v{v*vb? ;+C.al_ /Jӯ~Qg0T..ߖ[pix{l_V^K|®_ͫM۔Սرucs"{Lxs#$>Tw=~CwjO$}'Jc5&~! x&~Dgƫ~;w}_Yzu$pE+<$N0{aD[=;l\Lhfoڶm{hG/D /۷OvmnKYnkFw;}̘.]x{R#%^fMTt͌,--/_}e!==w޳ee@#c;N}G9$O?>n9Gqxh~Mhժڵkb͚5{Whkؾ}6_]oFFHsJzj"Ν|)Y [oݻwMAzLVSS],]:λfΟ][u=OJn &;]jlA(.Zv,\|5<ž:?/n!,XXefJ@&+Q,\Ò=o}7w--mT;dǎEs~='}t67 WZg}cd/t铖ܪ[]Ws3O9H׾CsvH N=[NNT?ҹ{]o'b]O>` {k]f͚fqOΙ/ kHش /J(*?gܹ=sbslrs=l'|r  z|(:޽[nZ')-}9qyTl'[s޷~_0`c?3xРuj۶mC,X 'FEǎМH YX-;o5&~M9~_qmM" .L@H؊VZ]|х/< ?P~_|~ј O}wG&'fUUUG=:/;frɡ9'$=]o'b]O>I$;qOΙiiiI${<=w]\xqbslrs@SyROΙSZԓsJg7Ff{ Y$w/\hAש`$qܹޘ_y%@r:Ə| -)O>?o,R̝0`{#$_r_9gMlfdt?ѣ{.]v "%YWSSQcmڔ-[Tq˭Ec:D}: $Ӝ?`s$ $ Zh>~CzL|өS?G&4dn8MYtOy?w~}-cn\޵=c{oygCS;Cuj_]y68ækwv l'_284{.3kxX*x~sOSoh:܋YxMs0lÝ/¤0{Έ|ąrF_wQg }8lI_M6։$Kf)믓y=H;uͧ&u咹/}}uNpMA IDATxiYj[OIaD|;][Vy|i\i|GiKwu>; JL7|'"M6k KbZ'iT WlN4u'/UC/{]{R?o6%;u }0qn7X-/,w"|E3n y=(u}o΄SWU>4_3aY-_ĩj(PwM4ī h=I+6̼g}pawQ3u;zZcą3Ŷf KxMlYQk{7cKQO6Fh ϛ3B, \G"ԝ2-f;>pEhfW}P2>&L[?;rS7h#cە:Ty+9iO$_R=ʏ.=skǗ47(,~'V} gQZ]zCmkݬ__[gnT_rU- {ӟ:Y@gYfOΙ̳Q=t„Ɯ d^uX[ju~=~ưg8s~ג=@Vu^۽k׾λF'oYc ҡC@aOH?`K$,篥z뭻gNi /^qC>Q9=:e_s˯k4!wHɣaWy1}wƦM6mg6I'Wo^ e$Ӝ.oGEu= O)}bNiT/FxɒS _G3trؑev˖,{WW%x?GqDc}bmy:vN5E<:DpѢblTl߯>sY7눋G{;6D'<-8:|D;;ãMh)ݻWX%M6+-[5Wpy6N&7^q?IlVT,g? |ɔ}UUU6oK/:}ze׿v:܂sK+;Y2%N=[NN/#7B"_֮]Y9YO8rߟNw>7ɒ)c=&_DO\>f1kVyȽZv6mNwsO`'K/r€?EEE=g{UVV&ow- /|#l+x+꿺b|ؙ,LxGNw#)ҧ տMz#{YY!d]Η:_J^mnS{Ioؙ I;o=Ϟ}B|Fc?RKF\EEEh٭Zm5Rvxn{*ne#7G­s=but&Lz⤒Znބv3R%ߜH۶mc5&~!UWW7-l>o#YY[&M`H9 _tϸ-<䓁|muȹ37'ܙ5njGkm5I&LhMTx1}u׻ m_ruTfn#A~Ϗ>nޭjO$\-;ŊVTo64D13%j-sϿ}K_<*l!o·-[<-9)()ZyfY<q8C۷oؙkV|}bۏvcڵ *Jf.ÂCBD__5Q;/5]86mDų~)4AsaC2.sĜ__[}"$C/K*84֐g6u}oNW<333IR֏='꫾yUW y󝰓UV}Ͽfcec;ߞUZZiqa=_m>~s y|z㼴O.\ĂGz?J4~۴V.׿pVbiF5wOH;XIÆ-]Zm~Gvÿ{թSHՉ"###mb|)C'~ah.]_ǰ\rǏC}D~OD-3;Qo|'22:,y;Mt]8_6-{~e_`mq"<{3v5{^zf>M q]jIGQwt^!Y^Ks 494#_}w_vFy0/)-y.YkrV^}%͇>K/r=iӦ:C333۵mU_}}ooh$_YrՃ=s=;?lsF|pfnjsgk[jK_LOOlVҦM߾}*֮]1/ɴjժG/EE=kWWWWְZHvc֭[]}/t9#'f;>pEZt@20RRRRRRRRRRRRRRRRRAZMMM9 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ Zݯ(7---<Ъ̴Q|-fQ陽U*3G*3Q/Iyb32'e׌,lm똙qSe۵RWQ\T ved [=IU1ی]Q\U􌌰jKòMuԓ7@rk{r %7Eqr ˫+,/^X0W%t.9wqQaIeU%Ey# Ⲝ^񿳦N[UY6 7sߡӪBR_F&^u`̐ K4*Z^?.e GJ&oje4xYJJW%g.cµlۨ7G;䡑w jjj6t|fk6Jf)TճFf9cǕd<7 fIVgm6xD*r\<+5י3/^VNu]~;˦,F(2vw8$?gn~kG0-ILZ1kdKQ_U^4dk?j͙_o;_mw7430Ԏj-ᘺLѷZqYIJs>7,w5c^ ^麛FXK|zayƌ1ΐ8y]?`<aӍ K#; IhvX]}_ga<ﰋO;5%Yєs/~f5ኣU0,S}svLofYBB7|fM<+ z b2ӿyG3~.Lw2eј~̳Ս ߹y' #9,ENW8yC(xY=j#M6Dz Ml5 G^hŝkw KX jy\~NR0zZ.ֿZ:iօ>?LI ãFiSN TC 7Ozc﯇YԟsCaVeE1lfËzX;?JXwM4^7,d!Mb j%>_ݗRV۰0iºPi}_X2ka2~advhn4&ۣ Ϫ`dn_5oYk^2Ǥ9C,lp5Mp⾷ޯPԛc^`!485̽knõ{WrxiQo΄9g,9vMNR=kx]Beu}Dzz0>hYò {ѩ/L:2ԝz`shWyXwLq/Ŗp̾}ͽ86m=rGGN| ;$ Nk|—u߈-G=ڍ?s0WXK"}םa;#3=m<[իW?yΏDˇ~)# ak׮]^}w{/ B9k„6j="vT?O8&V_[}uc@*PQwˌ~ ߯Nڶm+,['yCOJwee?E^]훑qt^>joIDAT:0$>VZţʐAa?ТOԭ[> _8̎|pHBQ.^ /Ra~Y'4y?-=ͮ?>@^;IyvVZ%۟=}7$qQ{€g?䥗CQ9dЩH!{LK|:^~啧=O:W!}C>÷~;x}Mvкu=3>υT{dw^h3MGF٫Mzj-_qKU[Qqt^;x~?;6/;ѽCdOh2_f͚[pg{>?e+WF:N$&Kow>QW|͐B9C;uٳǀ3׮}>ze ⨜Ӿ2$&Gy晊e**K·֧O͖,Ƽ+8ç妣w I-[mό=thݞC/^^ /a8/?dff"&3h8)Qݻ>䓟翿hse΁_>K~^մ\*Q^:4^[oEK/-' #׿_Uwc1"4^t+WZreffH8;~_gemuﶈ_9gMly?:/Wv;edRQ^˯.)[{wsW̫>i}&__[(~|YAh9yJ~/z_N;Ȫ^}O./3׿ȓm@9;US~kد׀^ntT焯pڨӮ:B|Q3ƛ~b7 ) !PuD} rD=Vh9ԐLٽݟ(Nz?Lz&ڷXɚ$vH;1-rovT,YkϮ:qXsv剢cǎyiqh対6쳢C;mwo_s#%1?n3>&uXo9 4&__[(~|YA?zwF^qvW%Q}7%|[Wl P]iσ:(Q,)[vBx7+ngx|px[b;. i_ffxQeƖs2fwi}l[Htl#dZw^=|H-B#E%<ߺ9c.Q7 jRˊθ$-qhtȹ=O.^ ;ch헜vm=$Jv̛5>#MoT瘣UQ E}Ҋj[Z7֧fU̿(K{̼cn;n`")z=Hpm'8k9^b{ ѻMWW&ƕ⳾12*2ȘhwvF]w<唓U̫vg~w] 1$g:ug ǝҔ?緹/lE\[^}'|;x>$ɴSO햓T_9ejڵv=/vۏΏM>ş FE٠65+G^ߨ/J:dJc&Q?g[Вߔ=^iiiv{vY֧zo~|YAv7ˇ_9򫛶{o%O~- %O?_BHuJEwzoKl-_nnhW_{- -7~7:Jv}/|w|ήOoMnϐl&M9s}66ylK'~bzM޻s+{}B L԰ڵmGo}n[>g}>0迍za^۷I~>/--_ԸC#{b MVSS"4o7_Fj;g g_;DW QGm]$>zw};S6mB2x#*rHh|芟\Uxq%oտ<'[wsoTy8=4'ml)4Q篡/~w]u€/>hcHǎ%z;gͺ צ}K+&4g>umӇ̰3}쳢oyɦ~xr@H5ԶmGGz={E/xl>ڵkwt>{u7eޗxsE|$T'IDAT!C_N U.^R>Nh.YY߻キrժ7JKK ɯ|iTth Kqv> էgDqtЁHI'MЪUSOr~ח-[SO},Q <14 O/ˍa_shN}9z39wVV>ǟx2fGvw{O?KYqve_K7Ķm۷OcNSO͝f͚f· >7N|'W?>WQR䯅 [z_Ld.YYg}}X.y]a3vY֮s*BXU1 /gݍYTZ>kdƦފYEOE**;={srV B P]Rwcg,ZQ۴j׍eh,|pVEh̑5ufjʺK'g0w.g^u7`ƅ9cޝ,)$-$æW6oF̮NIvvddP]<2GUfů|)R);66ɏY{/ޙz x;h Z7,z{r&?W9ƗTn6X2ꝗ_X\^:>'--ojaSĿ`Q My?]u3뗝2~V3~ۨtoF̮(4$'#=֚+jK;ntʲ#r23bԲm~R\حv /FsM-uƝk.c7_dzaA{bkWg>0i7xb&48Aް3WP{ʟ&/#*ߴr(99(?/k=2;Nݠ_ya*,!czFzrhz5,[q⻮9Wt|ZF6vh~DģKvY%z]wD\sfc%7s66[5}B< k3b!-p\縂aYuMc=kf{D,mY1cؘM-wYpY9|%QZxR~QxhqYhr' ˦fRP8zLLD\%S L 9E\Q\Zh1Wͯ&9~h1t7uRnFȬM3O)Y]Ky]bn[+֭WPR:9FfS餺#r'{w*@A>&Pe eM 㓚:^ ҇gwܰ]0rz]m.(d >+Q8k0j[t7Ɋ-/Wf~7^U n9'uw!;c4yqYS'f=03uRe )*J[o3۵J ŋn:r9S%f>:izǎ?UT*6h=K,0wdüMNL`ϝ81kذM2,L*5~Hz^D9c+W9F ئ~Gcm{ WUdf̑3jw&*+I<0aOJȾriUG3rL*.Z^Yzn> :#aK0tbdFͭ[WnӇwUUg߀WeHU$BP@AQi+3 *AmZm Nlb8UXAb+*5 H%B%$ Mb}{.מN_Y U{M fe_pFwK.*K Sz'g{?Z_}Η?f+'>=!g䄅͝py{M-iOV5}أ1v{-\=y,mZ G/^sN wKͤf*rܿo+ųg_bG`wmF-b>_6{̴OlnGG\sٶ Kc ݿ^^ mա[4a`,~}:rmtZ;ixؽLȋn%ӏƱwk>c'_~zdzѳ>ftyxʒ2=E񾼩SK 󦎬.€=Anvef?ܑ#}7O--68ޢaѤZ🯹&98/&6qYԱ#ud[V?yf۞#Ğ {>]UV'vZ6O ,?:㉥}Kly%%!6+o)1(IDATH؞>^=foqNj2p3S+qKZ:5MoHe#2K rONԶklY gy=0ۊd|Mo|}8a򖿆''f4{d?Ç.GqubᄯWůy_SGM1W&ݱ4ᠲҿA˸@㟾^CҺQ%th{ iWhrK27'.?j;Fi_kfV Ny<\^XCoy]_G:xtQy2kCΤE[|SS{r\Pzr˔B]v wW`|q5DU9G5J2oᘐ~^ ۭS缜/Y|=â{;q~l`!imq9̸^օx@;QӶ`xxvMRvEtk0_mrtfYە Nj  H}Yܿϩ7'x/~zfl֛7_|Ĉ˳zQ2Z8ޒҮbkD\wqyvhzPI XfƍY7o|fV֙c:CjuY;&y6m:gVVXQc?vԸ׭[3O8N baB:u\޷~Ny$|np_ѷOZZL/&E~W\V^X_\q%Ahҩ/r=7nj$=|$'@GF㦡Cn:$˗Ͻ>}}I>.]2;4 ?6}zCiӦu UѷիwVOʏ?}rs}ꩬa_jO~;lxT{InW/_"ټ _AAW/]eժAx3<85,n: 6ԁ~e+ӦŊv=䮕 왪?k۫#Q4#<|0P%"*֫*iyOQ편=V%.:6E4tLVd) UjUz~O}NcN;נ^wpC=/5嗿󝪼lPqx7)?QTn~y/wR췵:u #\0n 5䏚nO՗] }y|0H?jzdͱ"muî ܏_~C?j$N>'s9 c=&eD[ fmcR-0!*\g}\ubg{.HI=|C(}&]+s˾)zޔ .pa5k@SComV^A}V͊g _hUjPPPuiվ7NOomPqmifЦN:o5 5NL4Jޓv}eڴ-̺ Մ;:h't5:o:WO"5hbh>ݺ5:uq|zM49с%І;;NES1;⧊}[v;nug[vҢ펮,}ϵݖ Tb . צcZE56r,|W˻/㌱'~޻v,w|?sw8s؅={$\xʇJVelLJҜo?ɯtE%,bYtiy3c]mƂE'4Zb:y%z[u~1믾Cű_(tV,~{_1K85*EfUb*6+on㺶= L_zY8tPYU?LUZBtWOv3 2>sғNeE&:%ڙ6(zߖ6F w>k`t`l;s&sRFvNY:zo+y'GO]ۯվuj~'[!Ft~on+9ا"wZh(Vϛ=hwozJ=F' ͸jGv\[KV,݌%vaXެշ9 ;7_:wN/emd׬YdIgTwϟ'{rZoT]8u>Y͛7w/j=iO5~TNX|)w_wb|wbE6׈'VLGMw衇UmIhTiiiFJ>Av3_ ?'N͝oXwCpag*XR0lаiE;un5F](*k׮==SV*mҸ^m{uؓmߥg~rz}yu׿+7o{\ t՟4tHVP΁԰aèOC%hS6׭Y7ϓb~a=;C TXXN5%VTv/gnU]6T^˖^~7xȍlܸq?$*;N9kS":5];6/"T^jj;Ǽ޹妡G~xib'햛ߟް[UV\_RvƵ֮P&>?uuAfׄ?78DsC SaUL&>ko.owL6nܸxɒ>1bժLo.y^y@͛~{wH:6ltݺ?$};MSNvrp:A!|OV}dɇ)));)v Oy񟡸7.gg _砃6˖l5a^{c֕AI:t=Fd_9kVԪU}cb9oxɇ˥))_?y}ٷA|;8 CJQQQ;>[:I~H.z H H H H H H H H H H H H H H H H  d d d d d d d d d d d d d d d d d d d d d d d d d dP+ GM)v@|?-%%vaE$$dB; jFڐ!q-'-BjrD6u옂 ƌN_UUCOfhjj{$Mls#n+}>vʶ.\lxf6vcŮm7cϳ]e~T!YyeFxiM;bpii dMgDrҦNzӇl5#wK[v*nokWW /۳n=mgOңC闓ڶ琩vtfa7ڶ[yӇMI6e{_'';pV[ZѱO2!﫿Ԫ?)^E?bԒr+}.yw/*(X]:'o8ezJ1/o(;Gɮ/oDXdaDbJB'd[o׍20{Põ+_[ɭϝlh_q~9x =3놝oؑ9o;bÓ#&lUIF{_ъcSgC;eSG6-5Lݴ>O !Z. ayӣfnږ;fϝev?{Vn=z|!{j`X9?5c^[z7GzAW;GzڴM5^iadɬ_[gV~±=x_`bW-3Bj;xvgnv/zٻ?Ok5>NZBN/ylVEnwㄬn^8z uM^=[zjI6X755|^MZz fgӿ8{!kDE-5%6`IbX .^5>LވwNjSI^OBZH+ooZz N_VI}^p}kyBi!ceGLΙc ·m&ɹCl셅_ݿ^^ -aniϷtmPyiF_4uCf&EGV|ػGO f)EEE .ЧOna5c{#CҺܱ޿e?_X8O<ur?}}و.fج!h郦|-J,~Q^&T.[:kԍg۴:MoӷJn/9i Mrc^j~W['zU˲Kc?vr{S;O@@ɠVH.R*n戼-ْ $dK2k* zHh)EEEHp$ $ $ $ $V&^IDAT $ $ $ $ $ $ $ $ $ $ v}vuv AF[bѽλ֢{;6rHE+nb^NnUvZ_yvn# lI^(j+kqoq+\} b㍶=nУ񒞹K)&2.n1,6ߔ)I?xoɮ-{w_оUղO:}ic>NsIgΰuk ?r.B{xnkZ ϵ6tvtݜas:ݚ }.vӹg3,w|]+~x;<| rC*J|s@i2^=|KLnk^1GguS 7>4_6Cq6/'&lwt`lsqÄ5Aݨk.1nֵ%v3ZQ޵g |,Lϰ s.b KR<'ebaiJN?? %srѧ$WM>jpܭJ t[:2 cnVI~f*gZ]xɧ֭Ykfz!}.]h'6nwO~wޓ>KL p#W:ܭʷ^{}z6n,KHhӦMLgׇDu]}Wü2÷W|Ybƍtb<2Ivu0CMQ:G]kQz'{ygqz ;UoK/ֲe&6nŖ-+ lܸ1NjjK/_^ૼ.JذaC:uKF_}7gώ64irŽ}ېեVbbÏΙfb֭u RRRb+VxCWQ3ޜS_z)Pa-~ZTΝ~@W!*g̨nѼy2st d'v-ڸqc%X8|=:i&Ox]qzPtPZZ`UHaaaTnuDҚvO~;lxTPьϯӖZ/|73TRA^BN\A*=kWMQfԾ]9sBue;/frgi4礌\/L? Ys7kJYy!3nzۛuAf:f}juYqݬ_|;;78z[/^u_UlݺldY\3]ޱϻ~{"-> }vR.]qOի_yg|3$5}"Юx=X9Iċ;7 :'edV_Ju[;g|hzq8չzdJN^M|%/h~ݭS^hЄJTT-_m%e݇wN/7 p|עBʁ]dsWذa~k$HgΫ&mݲM 5myמp+:j_\gG]P__>$[S~z^z_>V9k?v͛7GEZ)aUV`yHRw!U[c۾ݑmԯ_&MfڏX2*ov:륩{X"$OnlLb_[O⋨w]խ[7*6}eHRǮ *;P$ ۸qoDuVGvZO_r2^'VŊڵkwh.rk˛6mZ<#P{ys:}7ͱgV^&-[l԰a8CN8>#sH*^#>s U]_Ž{ujힿ/"*jWHRVc>n:xq,}Bni7nI~rҾ|' /{EJ;ï߯ñg@y.+5[Q4$)=UQ^wO=%oK|'_]3%%kfoM{?}7W^dITw)$rw|vuwm{=9%06A쥩/Q䏤;_QWw@ _[ozj?$ IMcoxמ~MͯIDATyeڴ9/^ti4l/Gu~ZHv M{_w (Om8"5q{?voK./k߾]c$^~3:{7?ObO˖-۴n``_QQ~'v1jǟ4b?I)***wgkWfƍG;ժ`%l~:$j_buy(Io<찖(Hٳ `קO>O> 5U˖-7ܹsSOnS5X"EW~q3:w QoWW׸}{{H_FQ`izBB)((4吰5jt~%.M,_"Vڵ cyOQ편u c7`qAyfЏAP]jѱc͝ǍCo*~7wtቷ8c_Ʋ'H΍O>UPP;6/e߻{!15NO נ}X&Iݏl6VuJkzdͱ"muî I&'zj,,i }gk,|WJ^#> 5h V|嗓_ŜܵO~|mT7rd|sV>e˖Eu.aN*Wеmg vqu꼹sO݋.t=euiվ7NOoB·w|ь+s _`@Q;$tW?'O}BqG+ӦM6j}cȚ~LvVMvsZ}ӷ{(_'K8c% wy};vd#⩿}BMҰaÃ5;3O83{DoC$^_L}zÇ~!T -)˪z>cQߌ"h/ɿkk%{f|>3{=xWOw|lwM?,u^vxSN֮]7w矿WY't9[nݰaC3$dk}O8CͶi j7+ڤG#mꞏo۹sJ'WA-~6ԯ_OqBX0TXw]g/*^3,xgAT\ԻG 5Iaw{w8irvvl N<<悞=5߁M՟^4To -u+~KGx_5;knT5mj'vW{j=wU^hʫ8s IvNͣzyRo|?Bm_7{H+^'aZZv)?-_xbohDۿ%w\r/&Mb ^uuHj)EEElvͷ{cq7򥑵j%v?߸kc> 6 5?1E/ 5L@us]3Guԉo͇V.[ySz5?9}/4x$;ס??YT?~<;$O2!+ CMn ɏb֬KVjN?yn|KW^tE͎6}ԄY裎W^T9kVHR;Yڵ'rʪUij۫[nǞtl.hwD>][Lwg[6~~۩!qԪUK zij.(XoWhѢ+S۳,m[nҟ'>!r!72$:*JVZ>w-ӧ5?QHLgN/ŁkLjjjHR]'5񝿿c{r#?<$/=oLnHLoFEZZRի";nӦ5+߰qG32jZP$$gxl#׭RNˌ@]g}خ/׍:dt0Vƃ;(rkq9;_8aͣ%KvϺ#/;eE?: 7Q%m|o?gn~>>T P#Ivoke zέҥ5~͖C<%˟HY7^|Wo6EJ_ݷnN/E 9'PIv2xUVË87'dzo/ﮍ7i_دݣWf5irEbɩ`5 +I,ݙ!jvx߹[m˙?nHh׸uFU6aQz4s;1>RgpXnVw̉^רw9[Fhk4f_Cbfgjrw|vua4Juk Cy߀e~1e@ܬ9Kߗq[1î4eݛ67l]aʕ^2m w<;y!wK~{1|]fIY8+CHkܺ416ɿ+5y} i<3cG5_?PHvkB8hPVV#zgev05(JalhqaVօb+bvt5o'ʛ;Iχd4w /s5jogyw';Ai1gh}٧k?_(}jU4ؠA~*ogYIDAT;o7o޼w{a-CxcW{XݤI\ޚGHTҦuO+uwRSC9s8oO??kVJUFΌOVwށT=T5䯆z&OΞ7,XG}駡4kC9]O:ׅ>RPPՎ>ƍ[~}F>yqy:v}եVZ}ɪEC͜fFf{~1/Xpmڸqck._bÆ 'Vv/д_y\mNz'[ %RwyF'*((IGG}¨&=B?Ƕ~_~H4޽mƊh}~$*x^3]VZ}{w2%h)kΨ꫿qhH ˖-{_\JPY-lQ=qDH_]F}#Gv87g7?oDE b 7ξsJ盲ڐ>;ZYgM%1Ç~q:oܓ}K.q?!1ؓmiZӶ] Ó}}u8=EhsLzOl_z?vH@/ķ {\LDÏ cofB,oV^T4mTXޝ?&NyO>? %p_8by[Hl澽0TY%i_ZZӐRSإK\1}Wz+̙o&fzO}/_QCN8>#*>ZuCU5٫EP5e_ +?l$VoذaUW&fWXdI <$--cQ=Q*m岕{nH Gu/XF|Q1jب7]u)OsO]*eC.pmnӺ;qkDhP~z^碣.z6o.!}QՋ7g IvZժU0WTTT#,VGc?S;c4kizؿL|l0_͛7G^{VZ]2OKScuA$l}Fŧ> t9g?K/>m~}* ;؟G+,,PSu!JVX>YF%5kCv_}:+*M8㞪_~?_WR]vԭ[7*6}eHRjvG CnꩱëoӜܵ3gЏ~$oܨ8>Yz 4Xng}_>J:t86߇jӦM獨nݺU`Ud֫Wu#BR[VP 8cE;oحYm.cPi {o\`7t6m7kK/xlUk+Μ5+5qc9蠃ҚXF~ǟ_萃&j/"*jWHRkɇbXQX^foڵo͍7T5d8`/!^^T9%@XsO8>#vdʕ, ܨHKk^t=)S9sX`yޔ'o;^ݺo&MZ:⠴8V^4ܩSHR)EEEl~u{b/sJa7l?KS_q$$/I+7wNv;U+@Y~ͷnIl35#=?ŋșk=?9;V?M6 I-ᓿO?ʴis-^t[iذ_F8?,P矗ZqD$jw㐡w~\|_־}Hogu̙oF2-[i:)+ (N/cFس 寏?19;;4h ~RTTT֮5ƍn?;vKU+KF@uH>'g~uQb?(HIGgya-P*ٳgG$RWPP'㳵C ӠQjT[S )o8TDvD@ɠV`y_RM ){5o5nݚ1Cb:m̚ ڵii$PC%]OF2b{<>20eV3۩ȿcNesZj7U3_ $мЪS ͘SnM3wVŭt3g;+;&w|C2ލ,|G{{GzTz krhs[9c(nMnƐҘp_fnWVϠ:۷uv|ni%[2m5ݙD[kϙ9 k-Y:{a~~)?/+Y6ϿoC*ik9sKQ`Qe*oT?Ix[h/c+pn.9/k:pl-\Gʺr~0/\W25us2~-(f9Hߗ}ūz*^\NƹQ,?)'׫}{w~wm)0wHҼ~2Hܖ-KN{-5gXIX` @ Q;j{^qCREƭ6 Cj4t֣g;?1<.>㍀r{6cNbFt5B[\7Q43`|4;5;,G<;P㳵C ӠQjT[Sϋ-/)2fY"Zv)ǷQaP Wy^P7iӎfz!}.]$BIDATh^rco0>=_Y}NwDR4MM~o*~O^dsy+47pl@ #۹bߋz|?ʊ8+zo;y]VfUºC/ʺ V>9zjN7wsh,_~y6j(Px;N~evXbb>!ѬO~hQ,dժhA.7PUT2w޼go޼yڵ;ZdƌL{5hI&d5V.MןW9臘$r|Npߞ~&V׬>`?荜Zv{U.z3:j _ {M=?o,XÏ>OCi֬١rtR /$>}V~ }Q7 ~|`a;G=qu VK@U/y˗ʛ9͌.wb_}~qP%k׮]|ņ O"y`&Wsi׮]6n"*ի*i Xyyz-ڴ86 ga/7{cxlmXx{^}'^z:ا-^$VM9sBMUxVQݡ7ߜADuuo~滞w8C~1mO>+o':t oERU=H_ǎ%UnnMD ft|삫/;_ڡi%?$ڜO>@J΍O>UPP#Q5&+Mz؅~>筏mտ/2h);{#۶+?%>HT7.gt VZ~ogX 1eJ $R^{}םQ=WyА-[oG"TGܹk[hydˮgwꉓ$DJbN'?69S o9+$y#*4lKavMS:ߔPnZ'xO)7}c0خK5{v $X3|1=w/qS; =o1m2lOw )?KlAۗ@ O+^|'>#invakYYYtl͓˛t9<9'ݾfm+ptdT,[APa?s.\v ܬyg#z+$"zbׯ>l 5L,6tP%{w&IOv0w[fԩ['$k͝;oU ]N[7l Ew=#N*-!mڸNķ {\LDÏ coV}_* 6msC*,\{Οs'MΎ`'؟\/ixQ1oPUGVY%i_ZZӐRSإK\1}Wz+̙o&fzO}/_QCN8>#*>ZuCU6.9۬Yu:r/&Mb ^uuHjj|ŊK>oPC:vգn*GhUV.[9Q}熤pQG=p}Qy yIj_zߕ]#%?fC.pmnӺ;qkDhP~z^٧eM_>cǝrܱ'ۤYP}fO֫o}e+e7B%m޼9*ګȵjy¿^ $%f0*>]is9٧_z}Yl=uSO8<:T^aaaTCQbŊY5*I֮Y*Ӿ+/}YaWirTC%_rڵT]nݺQ/@UC>8*>XuVO}^~]O|9~P%ysFŁحY[4oРu>/b} Uҡñ]w>T6mz?oDu֭%^z[ڲX+ׯߡ}newlvIuM{]p{}|FڵEo۴iӼdtX˖]zIcv7Z;ݿ_yuYsA*o7O?dUE,79P}QQ{@\K>0Ŋ6{k׮}וmnܸqğoG!{[' D)j;#+V\dIH(oFEZZ\=I:Ι|ŊUl=ymw}4iҺız%QeN@J)***wgkWH|G+xSB SaP^{?' yIHZsu~۩=?/$ZovOby</^FΌW_{ٱlhڴiHj WM͝hKJÆ 2zTdߴW_u׿`A<_# Q lg⋯=F%ׯ?㬳g|3LMmӟ$lٲMH ]o@Ywb.3*---VH(}Q}AS^,rw|vua6nxt~aرÿ_WZ \67lC"99([G@DJ&Nz>*>kR͞=;*?l%8l%]jRbݚI~:$R#?H?H!Lڠ)ՕN :ݟMz~:zJ۽gQPiͯע"sKE_̢uF-! >[T6]33͟e;6ںok@EZ]yvz^G xwM5uo <گ8˿/tpXN޹ő^a{um [\^NXhjxΜ-[s[ {w5Ѻ{l^e䖄y8aҢ}m9fO3~4 iߔȚk@5y9_S)˻C-zr2nW(72dLV;o[/y_bYֽor^W >2)tf^9mYWLwЌX+ H9޽7hTkܺQ% xNhШwzZG5͜ЫwF~xg?K.RTTT֮5LFQnMaj֨| ī+=g IDATO;{b̓dVdr{Gd~} t3==s~gNy?^^0=m9 z֬YϭX"V/Zj^{5gNOz{{>['\UXrx6=@駟e}.}!IyP]>7nƗ~Gy}?PSA'v`Jbʨ>>:uj]qYƍb_|1q)ߦMfVTwΝA}.eWXʳ$ ?|CeH'w=185jyQ;@yj=GKEE:m(5Pc4tCl=r|N/Xxɒ@y?(*n,tP 6|G)=]Of͚>[PZ@2ZSct$-)15\D aEqh&"̆eumnkiO?<ν{o~"w0ٚ^֛"a!%ښ~˯ر?̑Ll'vbӽI^pFo׸;ѰHb߷zuexںpM>j+97bfFl87 Vl  BMOկmtz'_(Tn:yNuw$pU7u-k޲*SmL-ې^R3?juu{z5tn-=*8VgpߦLБU>;UTf܄trݍc'}:7}Q:3ˑ}?&J>_ҕ|0禙|j?ܥK>tմ7w+l;tdʍ! :Z#F,hI*V 3i B$ɭj{ުlIKO? K}_1x/ۺnKe]Mz/?2B׽pXf=pd mz5k\*onvu5/I[6 &^?:ֲP* l{hh#[y_4I _gkpQc$oOW5mҸh$SZ}VZZoܒ;?yޱ>0{sZߝ[NZQՄpx'©i{i@ȯkjBB8|UUQ3ڮXi\X3TTݝ;wL8mlM{mW+-9(0o,yPN7&_w *o^$d-+Tg.YM՜VGo\:SחKcCylpg}kZ×߄wO f®[nBY_ve[֤]VP45^rڭC7?RR<7vnf>%^v2M3yP|'P[1k`ZUO'amI;W5nlswBE=-\0-Iԗ prKw ׇS=2u|5r_׮nH0 }2+[e?'[d;NYa-g8 pI)#`[,߶yyTòl`^߻woiie^ZV<̕ښ#m̴`.-Wגo[QQXh>008zҸLmM;^$,˗6^|Bs;i8,pR.sW)))r}}i Wq)&XjVXvIcxxx[±o߾vJիY,_"[5o?^7o{v& n`2(䥟XQQĦy,*LgQdɒ뾴lY~G||\ߎ/ɬknyo O;w=tGuWTW]r_n0xu箧~s|CJ?rv8"S\\|>KB&3|&d*c1ӟ;\qyh" TV\1HfHfp+'`ѭ >"@1@ $@1@ $@1@ $@1@ $H85@1@ $@1@ $@1@ $@1@ $@1@ $@1@ $@1@ $@1@ $@1@ $@1@ $@1@ $@1@ $@1@ e IDATXIENDB`././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/tiny/tiny_repl.py0000644000000000000000000002652015134002420015635 0ustar00""" Interactive REPL for the TINY language. Features - Starts with an empty TinyEngine and a single empty TinyFrame (locals scope). - Executes entered TINY statements in the context of the current frame. - Supports commands: - `help` — display commands help - `quit` — exit the REPL - `import ` — parse a TINY source file and load all defined functions, ignoring any `main()` function present. - `clear vars` — clear all locally defined variables (reset current frame). - `clear all` — clear all variables and functions (engine reset). - `list`, `list vars`, `list functions` — list defined vars and/or functions Usage: python -m examples.tiny.tiny_repl """ from __future__ import annotations from pathlib import Path import sys import traceback from typing import Generic, TypeVar import pyparsing as pp from .tiny_parser import parse_tiny, stmt_seq, Function_Definition, comment as TINY_COMMENT from .tiny_ast import TinyNode from .tiny_engine import TinyEngine, TinyFrame, __version__ as TINY_VERSION from .tiny_run import explain_parse_error PROMPT = ">>> " CONTINUE_PROMPT = "... " T = TypeVar("T") class byref(Generic[T]): """Class to pass scalar values by reference""" def __init__(self, /, value: T): self._value = value def get(self) -> T: return self._value def set(self, value: T): self._value = value def _build_nodes_from_stmt_seq(parsed_seq: pp.ParseResults) -> list[TinyNode]: """Convert a parsed `stmt_seq` group into prebuilt `TinyNode` instances.""" nodes: list[TinyNode] = [] for st in parsed_seq: stype = st.get("type") cls = TinyNode.from_statement_type(stype) if not cls: # Skip unknown or unimplemented statements gracefully continue nodes.append(cls.from_parsed(st)) return nodes def _load_functions_from_file( engine: TinyEngine, filepath: str | Path, *, debug: bool = False, ) -> None: """Parse a .tiny file and register its function definitions into the engine. - Ignores any `main()` function present. - If `overwrite` is False, existing functions with the same name are preserved. """ p = Path(filepath) try: with p.open("r", encoding="utf-8") as f: source_text = f.read() try: parsed = parse_tiny(source_text) except pp.ParseBaseException as exc: msg = explain_parse_error(source_text, exc) print(msg, file=sys.stderr) return except OSError as exc: # File-related problems if debug: traceback.print_exc() else: print(f"{type(exc).__name__}: {exc}", file=sys.stderr) return except Exception as exc: # Unexpected importer exception if debug: traceback.print_exc() else: print(f"{type(exc).__name__}: {exc}", file=sys.stderr) return program = parsed.program if "functions" in program: for fdef in program.functions: try: decl = fdef.decl fname = decl.name except Exception: # Skip malformed definitions continue # Build function node and register signature and node fn_node_class = TinyNode.from_statement_type(fdef.type) if fn_node_class is None: continue fn_node = fn_node_class.from_parsed(fdef) engine.register_function(fname, fn_node) def handle_meta_command(engine: TinyEngine, cmd: str, debug_ref: byref[bool]) -> bool: # normalize to lowercase, and collapse whitespace lower = " ".join(cmd.lower().split()) line = cmd.strip() if lower == "help": print(f"TINY REPL v{TINY_VERSION}") print("Commands:") print(" help - list commands and descriptions") print(" quit - exit the REPL") print(" import - load functions from a .tiny file") print(" clear vars - clear current local variables") print(" clear all - reset engine state (all vars, funcs)") print(" list - list variables and functions") print(" list vars - list only current variables") print(" list functions - list defined function names") print(" debug on - show full Python tracebacks") print(" debug off - concise errors; hide tracebacks") return True if lower == "quit": return True if lower in ("list", "list vars", "list functions"): # Listing helpers def _print_vars() -> None: frame = engine.current_frame vars_dict = getattr(frame, "_vars", {}) # type: ignore[attr-defined] names = sorted(vars_dict.keys()) if not names: print("[variables] (none)") else: print("[variables]") for name in names: dtype, value = vars_dict[name] print(f" {name} = {value!r} : {dtype}") def _print_functions() -> None: funcs = engine.get_functions() names = sorted(funcs.keys()) if not names: print("[functions] (none)") else: print("[functions]") sigs = engine.get_function_signatures() for name in names: fn_ret_type, fn_params = sigs[name] print(f" {name}({', '.join(' '.join(p) for p in fn_params)}) : {fn_ret_type}") if lower in ("list", "list vars"): _print_vars() if lower in ("list", "list functions"): _print_functions() return True # Debug mode commands if lower == "debug on": debug_ref.set(True) print("[debug: on]") return True if lower == "debug off": debug_ref.set(False) print("[debug: off]") return True # import commands if cmd.startswith("import "): try: _, rest = line.split(None, 1) except ValueError: print("usage: import ") return True _load_functions_from_file(engine, rest.strip(), debug=debug_ref.get()) return True # clear/reset commands if lower == "clear vars": if engine._frames: # type: ignore[attr-defined] engine._frames[-1] = TinyFrame() # type: ignore[attr-defined] else: engine.push_frame() print("[locals cleared]") return True if lower == "clear all": engine = TinyEngine() engine.push_frame() print("[engine reset]") return True return False def repl() -> int: print( f"TINY REPL v{TINY_VERSION} — enter statements on one or more lines." " Ctrl-C to cancel current input; `quit` to exit." ) engine = TinyEngine() # Initialize with a single empty frame for locals engine.push_frame() # Incremental input buffer buffer_lines: list[str] = [] # Debug mode flag: when True, show full tracebacks for exceptions during execution debug: bool = False while True: try: # Choose prompt based on whether we're in the middle of a statement line = input(PROMPT if not buffer_lines else CONTINUE_PROMPT) except EOFError: # On EOF: discard any partial input and exit print() break except KeyboardInterrupt: # Ctrl-C while prompting: clear current buffer and show fresh prompt print() # move to a new line buffer_lines.clear() continue # If starting fresh, allow immediate REPL commands if not buffer_lines: cmd = line.strip() if not cmd: # ignore empty input continue debug_ref = byref(debug) if handle_meta_command(engine, cmd, debug_ref): debug = debug_ref.get() if cmd.strip().lower() == "quit": break continue # Treat as part of TINY input buffer_lines.append(line) source = "\n".join(buffer_lines) # Try to parse after each line; if it parses, execute immediately try: parsed = stmt_seq.parse_string(source, parse_all=True) except pp.ParseBaseException: # Try parsing a single function definition instead try: fdef_parsed = Function_Definition.parse_string(source, parse_all=True) except pp.ParseBaseException: # If the buffer contains only comments, accept and clear it try: pp.OneOrMore(TINY_COMMENT).parse_string(source, parse_all=True) except pp.ParseBaseException: # Keep collecting lines until parse succeeds or user presses Ctrl-C continue else: buffer_lines.clear() continue else: # Successfully parsed a function declaration/definition typed at the prompt fdef = fdef_parsed[0] # Build node and register (overwrite if already exists) try: fn_node_class = TinyNode.from_statement_type(fdef.type) if fn_node_class is None: raise TypeError(f"Unsupported function node type: {getattr(fdef, 'type', None)!r}") fn_node = fn_node_class.from_parsed(fdef) engine.register_function(fn_node.name, fn_node) except Exception as exc: if debug: traceback.print_exc() else: print(f"{type(exc).__name__}: {exc}", file=sys.stderr) finally: # Clear buffer and continue to next prompt buffer_lines.clear() continue # Parsed successfully: execute and reset buffer nodes = _build_nodes_from_stmt_seq(parsed) echoed_any = False try: for node in nodes: ret = node.execute(engine) stype = getattr(node, "statement_type", None) if stype in ("expr_stmt", "call_stmt"): # Echo the resulting value using Python repr() if ret is not None: print(repr(ret)) echoed_any = True except KeyboardInterrupt: # Interrupt current execution; fall through to flush output pass except Exception as exc: # Non-runtime exceptions during execution if debug: # In debug mode, show full traceback but keep REPL alive traceback.print_exc() else: # Suppress traceback: show only exception type and message print(f"{type(exc).__name__}: {exc}", file=sys.stderr) finally: engine.output_text() if not echoed_any: # Preserve the invariant: ensure at least one newline after execution print() buffer_lines.clear() return 0 def main(argv: list[str] | None = None) -> int: # No CLI options at this time; reserved for future enhancements return repl() if __name__ == "__main__": raise SystemExit(main()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/tiny/tiny_run.py0000644000000000000000000001032315134002420015471 0ustar00""" TINY interpreter scaffold built using: - parser defined in tiny_parser.py - executable statement AST classes defined in tiny_ast.py - execution engine defined in tiny_engine.py This module currently provides: - main(): CLI entry point that reads a .tiny source file, parses it using the TINY grammar, and prepares for conversion to TinyNode-based AST. Usage: python -m examples.tiny.tiny_run path/to/program.tiny [--dump] """ from __future__ import annotations import argparse import sys import pyparsing as pp from .tiny_parser import parse_tiny from .tiny_ast import TinyNode from .tiny_engine import TinyEngine def explain_parse_error(src: str, err: pp.ParseBaseException) -> str: """Return a helpful, context-rich parse error string.""" source_lines = src.splitlines() error_lineno = err.lineno lineno_len = len(str(error_lineno + 1)) # Guard against last-line errors if err.lineno - 1 >= len(source_lines): source_lines.append("") *prelude, error_line, postlude = source_lines[max(error_lineno - 3, 0): error_lineno + 1] fragment = "\n".join( [ *(f"{prelineno:>{lineno_len}}: {line}" for prelineno, line in enumerate(prelude, start=error_lineno - len(prelude))), f"{error_lineno:>{lineno_len}}: >{error_line}", f"{error_lineno + 1:>{lineno_len}}: {postlude}", ] ) return fragment + "\n\n" + err.explain(depth=0) def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description="Run a TINY program using the TINY interpreter scaffold.") parser.add_argument("source", help="Path to the .tiny source file") parser.add_argument("--dump", action="store_true", help="Dump parsed structure (debug)") args = parser.parse_args(argv) try: with open(args.source, "r", encoding="utf-8") as f: source_text = f.read() except OSError as exc: print(f"Error reading {args.source}: {exc}", file=sys.stderr) return 2 try: parsed = parse_tiny(source_text) except pp.ParseBaseException as exc: # Print helpful location info print(explain_parse_error(source_text, exc)) return 3 if args.dump: # Pretty-print the primary structure for inspection print(parsed.dump()) exit() # Instantiate the engine that will hold globals, functions, and frames engine = TinyEngine() # initialize engine with parsed globals initialize_engine(engine, parsed.program) # Execute scripts "main" function try: main_node = engine.get_function("main") main_node.execute(engine) except Exception as exc: print(f"{type(exc).__name__}: {exc}") exit() return 0 def initialize_engine(engine: TinyEngine, program: pp.ParseResults) -> None: # Register all top-level function definitions: build function nodes and signatures if "functions" in program: for fdef in program.functions: # Build a function node with a prebuilt body fn_node_class = TinyNode.from_statement_type(fdef.type) fn_node = fn_node_class.from_parsed(fdef) # Register function node for runtime use engine.register_function(fn_node.name, fn_node) # Register any top-level globals if they exist (grammar may not provide these) if "globals" in program: for g in program.globals: try: dtype = str(g.datatype) # Handle one or more variable declarations in a decl stmt decls = g.decls if hasattr(g, "decls") else [] for d in decls: name = d.name init_val = d.get("init") if isinstance(d, pp.ParseResults) else None engine.declare_global_var(name, dtype, init_val) except Exception: # Best-effort: skip malformed/unsupported global forms continue # Build AST node for main() and register it as a function main_group = program.main main_node_class = TinyNode.from_statement_type(main_group["type"]) main_node = main_node_class.from_parsed(main_group) engine.register_function("main", main_node) if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/unicode_denormalizer.py0000644000000000000000000001202315134002420017037 0ustar00# unicode_denormalizer.py # # Demonstration of the pyparsing's transform_string() method, to # convert identifiers in Python source code to equivalent Unicode # characters. Python's compiler automatically normalizes Unicode # characters back to their ASCII equivalents, so that identifiers may # be rewritten using other Unicode characters, and normalize back to # the same identifier. For instance, Python treats "print" and "𝕡𝓻ᵢ𝓃𝘁" # and "𝖕𝒓𝗂𝑛ᵗ" all as the same identifier. # # The converter must take care to *only* transform identifiers - # Python keywords must always be represented in base ASCII form. To # skip over keywords, they are added to the parser/transformer, but # contain no transforming parse action. # # The converter also detects identifiers in placeholders within f-strings. # # Copyright 2022, by Paul McGuire # import keyword import random import unicodedata import pyparsing as pp ppu = pp.pyparsing_unicode _· = "_·" ident_chars = ( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789" + _· ) # build map of each ASCII character to a string of # all the characters in the Basic Multilingual Plane # that NFKC normalizes back to that ASCII character ident_char_map = {c: [] for c in ident_chars} for ch in ppu.BMP.identbodychars: normal = unicodedata.normalize("NFKC", ch) if normal in ident_char_map: ident_char_map[normal].append(ch) # ligatures will also normalize back to ASCII # (doubled elements have higher chance of being chosen by random.choice) ligature_map = { 'IJ': ('IJ', 'IJ', 'IJ'), 'LJ': ('LJ', 'LJ', 'LJ'), 'NJ': ('NJ', 'NJ', 'NJ'), 'DZ': ('DZ', 'DZ', 'DZ'), 'II': ('Ⅱ', 'Ⅱ', 'II'), 'IV': ('Ⅳ', 'Ⅳ', 'IV'), 'VI': ('Ⅵ', 'Ⅵ', 'VI'), 'IX': ('Ⅸ', 'Ⅸ', 'IX'), 'XI': ('Ⅺ', 'Ⅺ', 'XI'), 'ffl': ('ffl', 'ffl', 'ffl', 'ffl', 'ffl'), 'ffi': ('ffi', 'ffi', 'ffi', 'ffi', 'ffi'), 'ff': ('ff', 'ff', 'ff'), 'fi': ('fi', 'fi', 'fi'), 'fl': ('fl', 'fl', 'fl'), 'ij': ('ij', 'ij', 'ij'), 'lj': ('lj', 'lj', 'lj'), 'nj': ('nj', 'nj', 'nj'), 'dz': ('dz', 'dz', 'dz'), 'ii': ('ⅱ', 'ⅱ', 'ii'), 'iv': ('ⅳ', 'ⅳ', 'iv'), 'vi': ('ⅵ', 'ⅵ', 'vi'), 'ix': ('ⅸ', 'ⅸ', 'ix'), 'xi': ('ⅺ', 'ⅺ', 'xi'), } ligature_transformer = pp.one_of(ligature_map).add_parse_action( lambda t: random.choice(ligature_map[t[0]]) ) def make_mixed_font(t): # extract leading character and remainder to process separately t_first, t_rest = t[0][0], t[0][1:] # a leading '_' must be written using the ASCII character '_' ret = ['_' if t_first == '_' else random.choice(ident_char_map.get(t_first, t_first))] t_rest = ligature_transformer.transform_string(t_rest) ret.extend(random.choice(ident_char_map.get(c, c)) for c in t_rest) return ''.join(ret) # define a pyparsing expression to match any identifier; add a parse # action to convert to mixed Unicode characters identifier = pp.pyparsing_common.identifier identifier.add_parse_action(make_mixed_font) # match quoted strings (which may be f-strings) python_quoted_string = pp.Opt(pp.Char("fF")("f_string_prefix")) + ( pp.python_quoted_string )("quoted_string_body") def mix_fstring_expressions(t): if not t.f_string_prefix: return # define an expression and transformer to handle embedded # f-string field expressions fstring_arg = pp.QuotedString("{", end_quote_char="}") fstring_arg.add_parse_action( lambda tt: "{" + transformer.transform_string(tt[0]) + "}" ) return ( t.f_string_prefix + fstring_arg.transform_string(t.quoted_string_body) ) # add parse action to transform identifiers in f-strings python_quoted_string.add_parse_action(mix_fstring_expressions) # match keywords separately from identifiers - keywords must be kept in their # original ASCII any_keyword = pp.one_of( list(keyword.kwlist) + getattr(keyword, "softkwlist", []), as_keyword=True ) # quoted strings and keywords will be parsed, but left untransformed transformer = python_quoted_string | any_keyword | identifier def demo(): import textwrap hello_source = textwrap.dedent(""" def hello(): try: hello_ = "Hello" world_ = "World" print(f"{hello_}, {world_}!") except TypeError as exc: print("failed: {}".format(exc)) if __name__ == "__main__": hello() """) # use transformer to generate code with denormalized identifiers transformed = transformer.transform_string(hello_source) print(transformed) # does it really work? compile the transformed code and run it! code = compile(transformed, "inline source", mode="exec") exec(code) if 1: # pick some code from the stdlib import unittest.util as lib_module import inspect source = inspect.getsource(lib_module) transformed = transformer.transform_string(source) print() print(transformed) if __name__ == '__main__': demo() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/urlExtractor.py0000644000000000000000000000205415134002420015337 0ustar00# URL extractor # Copyright 2004, Paul McGuire from pyparsing import make_html_tags, pyparsing_common as ppc from urllib.request import urlopen import pprint linkOpenTag, linkCloseTag = make_html_tags("a") linkBody = linkOpenTag.tag_body linkBody.set_parse_action(ppc.strip_html_tags) linkBody.add_parse_action(lambda toks: " ".join(toks[0].strip().split())) link = linkOpenTag + linkBody("body") + linkCloseTag.suppress() # Go get some HTML with some links in it. with urlopen("https://www.cnn.com/") as serverListPage: htmlText = serverListPage.read().decode("UTF-8") # scan_string is a generator that loops through the input htmlText, and for each # match yields the tokens and start and end locations (for this application, we are # not interested in the start and end values). for toks, strt, end in link.scan_string(htmlText): print(toks.as_list()) # Create dictionary from list comprehension, assembled from each pair of tokens returned # from a matched URL. pprint.pprint({toks.body: toks.href for toks, strt, end in link.scan_string(htmlText)}) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/urlExtractorNew.py0000644000000000000000000000464215134002420016016 0ustar00# URL extractor # Copyright 2004, Paul McGuire from collections import Counter import pprint from urllib.request import urlopen from pyparsing import make_html_tags, pyparsing_common as ppc, FollowedBy, trace_parse_action # Define the pyparsing grammar for a URL, that is: # URLlink ::= linkText # URL ::= doubleQuotedString | alphanumericWordPath # Note that whitespace may appear just about anywhere in the link. Note also # that it is not necessary to explicitly show this in the pyparsing grammar; by default, # pyparsing skips over whitespace between tokens. linkOpenTag, linkCloseTag = make_html_tags("a") link = linkOpenTag + linkOpenTag.tag_body("body") + linkCloseTag.suppress() # Add a parse action to expand relative URLs def expand_relative_url(t): url = t.href if url.startswith("//"): url = "https:" + url elif url.startswith(("/", "?", "#")): url = "https://www.cnn.com" + url # Put modified URL back into input tokens t["href"] = url link.add_parse_action(expand_relative_url) # Go get some HTML with some links in it. with urlopen("https://www.cnn.com/") as serverListPage: htmlText = serverListPage.read().decode() # scan_string is a generator that loops through the input htmlText, and for each # match yields the tokens and start and end locations (for this application, we are # not interested in the start and end values). for toks, strt, end in link.scan_string(htmlText): print(toks.startA.href, "->", toks.body) # Create dictionary with a dict comprehension, assembled from each pair of tokens returned # from a matched URL. links = {toks.body: toks.href for toks, _, _ in link.scan_string(htmlText)} pprint.pprint(links) # Parse the urls in the links using pyparsing_common.url, and tally up all # the different domains in a Counter. domains = Counter() for url in links.values(): print(url) parsed = ppc.url.parse_string(url) # print parsed fields for each new url if parsed.host not in domains: print(parsed.dump()) print() # update domain counter domains[parsed.host] += 1 # Print out a little table of all the domains in the urls max_domain_len = max(len(d) for d in domains) print() print("{:{}s} {}".format("Domain", max_domain_len, "Count")) print("{:=<{}} {:=<5}".format("", max_domain_len, "")) for domain, count in domains.most_common(): print("{:{}s} {:5d}".format(domain, max_domain_len, count)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/verilog_parse.py0000644000000000000000000007627315134002420015520 0ustar00# # verilogParse.py # # an example of using the pyparsing module to be able to process Verilog files # uses BNF defined at http://www.verilog.com/VerilogBNF.html # # Copyright (c) 2004-2011 Paul T. McGuire. All rights reserved. # # 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. # # If you find this software to be useful, please make a donation to one # of the following charities: # - the Red Cross (https://www.redcross.org/) # - Hospice Austin (https://www.hospiceaustin.org/) # # DISCLAIMER: # THIS SOFTWARE IS PROVIDED BY PAUL T. McGUIRE ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO # EVENT SHALL PAUL T. McGUIRE OR CO-CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OFUSE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # For questions or inquiries regarding this license, or commercial use of # this software, contact the author via e-mail: ptmcg@users.sourceforge.net # # Todo: # - add pre-process pass to implement compilerDirectives (ifdef, include, etc.) # # Revision History: # # 1.0 - Initial release # 1.0.1 - Fixed grammar errors: # . real declaration was incorrect # . tolerant of '=>' for '*>' operator # . tolerant of '?' as hex character # . proper handling of mintypmax_expr within path delays # 1.0.2 - Performance tuning (requires pyparsing 1.3) # 1.0.3 - Performance updates, using Regex (requires pyparsing 1.4) # 1.0.4 - Performance updates, enable packrat parsing (requires pyparsing 1.4.2) # 1.0.5 - Converted keyword Literals to Keywords, added more use of Group to # group parsed results tokens # 1.0.6 - Added support for module header with no ports list (thanks, Thomas Dejanovic!) # 1.0.7 - Fixed erroneous '<<' Forward definition in timCheckCond, omitting ()'s # 1.0.8 - Re-released under MIT license # 1.0.9 - Enhanced udpInstance to handle identifiers with leading '\' and subscripting # 1.0.10 - Fixed change added in 1.0.9 to work for all identifiers, not just those used # for udpInstance. # 1.0.11 - Fixed bug in inst_args, content alternatives were reversed # 1.1.0 - Some performance fixes, convert most literal strs to Keywords # from pathlib import Path import pprint import time __version__ = "1.1.0" __all__ = ["__version__", "verilogbnf"] from pyparsing import ( Literal, Keyword, Word, Forward, DelimitedList, Group, Optional, Combine, alphas, nums, rest_of_line, alphanums, dbl_quoted_string, empty, ParseBaseException, one_of, StringEnd, FollowedBy, ParserElement, Regex, cpp_style_comment, ) import pyparsing usePackrat = True packratOn = False if usePackrat: try: ParserElement.enable_packrat() except Exception: pass else: packratOn = True verilogbnf = None def make_verilog_bnf(): global verilogbnf if verilogbnf is None: # compiler directives compilerDirective = Combine( "`" + one_of( "define undef ifdef else endif default_nettype" " include resetall timescale unconnected_drive" " nounconnected_drive celldefine endcelldefine", as_keyword=True, ) + rest_of_line ).set_name("compilerDirective") # primitives ( SEMI, COLON, LPAR, RPAR, LBRACE, RBRACE, LBRACK, RBRACK, DOT, COMMA, EQ, ) = Literal.using_each(";:(){}[].,=") identLead = alphas + "$_" identBody = alphanums + "$_" identifier1 = Regex( rf"\.?[{identLead}][{identBody}]*(\.[{identLead}][{identBody}]*)*" ).set_name("baseIdent") identifier2 = ( Regex(r"\\\S+").set_parse_action(lambda t: t[0][1:]).set_name("escapedIdent") ) # .set_debug() identifier = identifier1 | identifier2 assert identifier2 == r"\abc" hexnums = nums + "abcdefABCDEF" + "_?" base = Regex("'[bBoOdDhH]").set_name("base") basedNumber = Combine( (Word(nums + "_") | "") + base + Word(hexnums + "xXzZ"), join_string=" ", adjacent=False, ).set_name("basedNumber") # number = ( basedNumber | Combine( Word( "+-"+spacedNums, spacedNums ) + # Optional( DOT + Optional( Word( spacedNums ) ) ) + # Optional( e + Word( "+-"+spacedNums, spacedNums ) ) ).set_name("numeric") ) number = ( basedNumber | Regex(r"[+-]?[0-9_]+(\.[0-9_]*)?([Ee][+-]?[0-9_]+)?") ).set_name("numeric") expr = Forward().set_name("expr") concat = Group(LBRACE + DelimitedList(expr) + RBRACE) multiConcat = Group("{" + expr + concat + "}").set_name("multiConcat") funcCall = Group( identifier + LPAR + (DelimitedList(expr) | "") + RPAR ).set_name("funcCall") subscrRef = Group(LBRACK + DelimitedList(expr, COLON) + RBRACK) subscrIdentifier = Group(identifier + (subscrRef | "")) # scalarConst = "0" | (( FollowedBy('1') + one_of("1'b0 1'b1 1'bx 1'bX 1'B0 1'B1 1'Bx 1'BX 1") )) scalarConst = Regex("0|1('[Bb][01xX])?") mintypmaxExpr = Group(expr + COLON + expr + COLON + expr).set_name("mintypmax") primary = ( number | (LPAR + mintypmaxExpr + RPAR) | (LPAR + Group(expr) + RPAR).set_name("nested_expr") | multiConcat | concat | dbl_quoted_string | funcCall | subscrIdentifier ) unop = one_of("+ - ! ~ & ~& | ^| ^ ~^").set_name("unop") binop = one_of( "+ - * / % == != === !== && " "|| < <= > >= & | ^ ^~ >> << ** <<< >>>" ).set_name("binop") expr <<= ( (unop + expr) | (primary + "?" + expr + COLON + expr) # must be first! | (primary + ((binop + expr) | "")) ) lvalue = subscrIdentifier | concat # keywords reg = Keyword("reg") trireg = Keyword("trireg") signed = Keyword("signed") parameter = Keyword("parameter") input_, output, inout = Keyword.using_each("input output inout".split()) time = Keyword("time") integer = Keyword("integer") real = Keyword("real") event = Keyword("event") scalared = Keyword("scalared") vectored = Keyword("vectored") if_ = Keyword("if") else_ = Keyword("else") always = Keyword("always") initial = Keyword("initial") small, medium, large = Keyword.using_each("small medium large".split()) edge = Keyword("edge") posedge = Keyword("posedge") negedge = Keyword("negedge") specify, endspecify = Keyword.using_each("specify endspecify".split()) primitive, endprimitive = Keyword.using_each("primitive endprimitive".split()) fork = Keyword("fork") join = Keyword("join") begin = Keyword("begin") end = Keyword("end") default = Keyword("default") forever = Keyword("forever") repeat = Keyword("repeat") while_ = Keyword("while") for_ = Keyword("for") case = one_of("case casez casex", as_keyword=True) endcase = Keyword("endcase") wait = Keyword("wait") disable = Keyword("disable") deassign = Keyword("deassign") force = Keyword("force") release = Keyword("release") assign = Keyword("assign") table, endtable = Keyword.using_each("table endtable".split()) function, endfunction = Keyword.using_each("function endfunction".split()) task, endtask = Keyword.using_each("task endtask".split()) module, macromodule, endmodule = Keyword.using_each( "module macromodule endmodule".split() ) eventExpr = Forward() eventTerm = ( (posedge + expr) | (negedge + expr) | expr | (LPAR + eventExpr + RPAR) ) eventExpr <<= Group(DelimitedList(eventTerm, Keyword("or"))) eventControl = Group( "@" + ((LPAR + eventExpr + RPAR) | identifier | "*") ).set_name("eventCtrl") delayArg = ( number | Word(alphanums + "$_") | (LPAR + Group(DelimitedList(mintypmaxExpr | expr)) + RPAR) # identifier | ).set_name( "delayArg" ) # .set_debug() delay = Group("#" + delayArg).set_name("delay") # .set_debug() delayOrEventControl = delay | eventControl assgnmt = Group(lvalue + EQ + (delayOrEventControl | "") + expr).set_name( "assgnmt" ) nbAssgnmt = Group( (lvalue + "<=" + (delay | "") + expr) | (lvalue + "<=" + (eventControl | "") + expr) ).set_name("nbassgnmt") range_ = LBRACK + expr + COLON + expr + RBRACK paramAssgnmt = Group(identifier + EQ + expr).set_name("paramAssgnmt") parameterDecl = Group( parameter + (range_ | "") + DelimitedList(paramAssgnmt) + SEMI ).set_name("paramDecl") inputDecl = Group(input_ + (range_ | "") + DelimitedList(identifier) + SEMI) outputDecl = Group(output + (range_ | "") + DelimitedList(identifier) + SEMI) inoutDecl = Group(inout + (range_ | "") + DelimitedList(identifier) + SEMI) regIdentifier = Group(identifier + (LBRACK + expr + COLON + expr + RBRACK | "")) regDecl = Group( reg + (signed | "") + (range_ | "") + DelimitedList(regIdentifier) + SEMI ).set_name("regDecl") timeDecl = Group(time + DelimitedList(regIdentifier) + SEMI) integerDecl = Group(integer + DelimitedList(regIdentifier) + SEMI) strength0 = one_of("supply0 strong0 pull0 weak0 highz0", as_keyword=True) strength1 = one_of("supply1 strong1 pull1 weak1 highz1", as_keyword=True) driveStrength = Group( LPAR + ((strength0 + COMMA + strength1) | (strength1 + COMMA + strength0)) + RPAR ).set_name("driveStrength") nettype = one_of( "wire tri tri1 supply0 wand triand tri0 supply1 wor trior trireg", as_keyword=True, ) expandRange = (scalared | vectored | "") + range_ realDecl = Group(real + DelimitedList(identifier) + SEMI) eventDecl = Group(event + DelimitedList(identifier) + SEMI) blockDecl = ( parameterDecl | regDecl | integerDecl | realDecl | timeDecl | eventDecl ) stmt = Forward().set_name("stmt") # .set_debug() stmtOrNull = stmt | SEMI caseItem = (DelimitedList(expr) + COLON + stmtOrNull) | ( default + Optional(":") + stmtOrNull ) stmt <<= Group( (begin + Group(stmt[...:end]) + end).set_name("begin-end") | ( if_ + Group(LPAR + expr + RPAR) + stmtOrNull + (else_ + stmtOrNull | "") ).set_name("if") | (delayOrEventControl + stmtOrNull) | (case + LPAR + expr + RPAR + caseItem[1, ...] + endcase) | (forever + stmt) | (repeat + LPAR + expr + RPAR + stmt) | (while_ + LPAR + expr + RPAR + stmt) | ( for_ + LPAR + assgnmt + SEMI + Group(expr) + SEMI + assgnmt + RPAR + stmt ) | (fork + stmt[...] + join) | (fork + COLON + identifier + blockDecl[...] + stmt[...] + end) | (wait + LPAR + expr + RPAR + stmtOrNull) | ("->" + identifier + SEMI) | (disable + identifier + SEMI) | (assign + assgnmt + SEMI) | (deassign + lvalue + SEMI) | (force + assgnmt + SEMI) | (release + lvalue + SEMI) | (begin + COLON + identifier + blockDecl[...] + stmt[...] + end).set_name( "begin:label-end" ) | # these *have* to go at the end of the list!!! (assgnmt + SEMI) | (nbAssgnmt + SEMI) | ( Combine(Optional("$") + identifier) + (LPAR + DelimitedList(expr | empty) + RPAR | "") + SEMI ) ).set_name("stmtBody") """ x::= ; x||= ; x||= if ( ) x||= if ( ) else x||= case ( ) + endcase x||= casez ( ) + endcase x||= casex ( ) + endcase x||= forever x||= repeat ( ) x||= while ( ) x||= for ( ; ; ) x||= x||= wait ( ) x||= -> ; x||= x||= x||= x||= x||= disable ; x||= disable ; x||= assign ; x||= deassign ; x||= force ; x||= release ; """ alwaysStmt = Group(always + (eventControl | "") + stmt).set_name("alwaysStmt") initialStmt = Group(initial + stmt).set_name("initialStmt") chargeStrength = Group(LPAR + (small | medium | large) + RPAR).set_name( "chargeStrength" ) continuousAssign = Group( assign + (driveStrength | "") + (delay | "") + DelimitedList(assgnmt) + SEMI ).set_name("continuousAssign") tfDecl = ( parameterDecl | inputDecl | outputDecl | inoutDecl | regDecl | timeDecl | integerDecl | realDecl ) functionDecl = Group( function + (range_ | "integer" | "real" | "") + identifier + SEMI + Group(tfDecl[1, ...]) + Group(stmt[...]) + endfunction ) inputOutput = input_ | output netDecl1Arg = ( nettype + (expandRange | "") + (delay | "") + Group(DelimitedList(~inputOutput + identifier)) ) netDecl2Arg = ( trireg + (chargeStrength | "") + (expandRange | "") + (delay | "") + Group(DelimitedList(~inputOutput + identifier)) ) netDecl3Arg = ( nettype + (driveStrength | "") + (expandRange | "") + (delay | "") + Group(DelimitedList(assgnmt)) ) netDecl1 = Group(netDecl1Arg + SEMI).set_name("netDecl1") netDecl2 = Group(netDecl2Arg + SEMI).set_name("netDecl2") netDecl3 = Group(netDecl3Arg + SEMI).set_name("netDecl3") gateType = one_of( "and nand or nor xor xnor buf bufif0 bufif1 " "not notif0 notif1 pulldown pullup nmos rnmos " "pmos rpmos cmos rcmos tran rtran tranif0 " "rtranif0 tranif1 rtranif1", as_keyword=True, ) gateInstance = ( (Group(identifier + (range_ | "")) | "") + LPAR + Group(DelimitedList(expr)) + RPAR ) gateDecl = Group( gateType + (driveStrength | "") + (delay | "") + DelimitedList(gateInstance) + SEMI ) udpInstance = Group( Group(identifier + (range_ | subscrRef | "")) + LPAR + Group(DelimitedList(expr)) + RPAR ) udpInstantiation = Group( identifier - (driveStrength | "") + (delay | "") + DelimitedList(udpInstance) + SEMI ).set_name("udpInstantiation") parameterValueAssignment = Group( Literal("#") + LPAR + Group(DelimitedList(expr)) + RPAR ) namedPortConnection = Group(DOT + identifier + LPAR + expr + RPAR).set_name( "namedPortConnection" ) # .set_debug() # assert r".\abc (abc )" == namedPortConnection modulePortConnection = expr | empty inst_args = Group( LPAR + (DelimitedList(namedPortConnection) | DelimitedList(modulePortConnection)) + RPAR ).set_name("inst_args") moduleInstance = Group(Group(identifier + (range_ | "")) + inst_args).set_name( "moduleInstance" ) # .set_debug() moduleInstantiation = Group( identifier + (parameterValueAssignment | "") + DelimitedList(moduleInstance).set_name("moduleInstanceList") + SEMI ).set_name("moduleInstantiation") parameterOverride = Group("defparam" + DelimitedList(paramAssgnmt) + SEMI) task = Group(task + identifier + SEMI + tfDecl[...] + stmtOrNull + endtask) specparamDecl = Group("specparam" + DelimitedList(paramAssgnmt) + SEMI) pathDescr1 = Group(LPAR + subscrIdentifier + "=>" + subscrIdentifier + RPAR) pathDescr2 = Group( LPAR + Group(DelimitedList(subscrIdentifier)) + "*>" + Group(DelimitedList(subscrIdentifier)) + RPAR ) pathDescr3 = Group( LPAR + Group(DelimitedList(subscrIdentifier)) + "=>" + Group(DelimitedList(subscrIdentifier)) + RPAR ) pathDelayValue = Group( (LPAR + Group(DelimitedList(mintypmaxExpr | expr)) + RPAR) | mintypmaxExpr | expr ) pathDecl = Group( (pathDescr1 | pathDescr2 | pathDescr3) + EQ + pathDelayValue + SEMI ).set_name("pathDecl") portConditionExpr = Forward() portConditionTerm = (unop | "") + subscrIdentifier portConditionExpr <<= portConditionTerm + (binop + portConditionExpr | "") polarityOp = one_of("+ -") levelSensitivePathDecl1 = Group( if_ + Group(LPAR + portConditionExpr + RPAR) + subscrIdentifier + (polarityOp | "") + "=>" + subscrIdentifier + EQ + pathDelayValue + SEMI ) levelSensitivePathDecl2 = Group( if_ + Group(LPAR + portConditionExpr + RPAR) + LPAR + Group(DelimitedList(subscrIdentifier)) + (polarityOp | "") + "*>" + Group(DelimitedList(subscrIdentifier)) + RPAR + EQ + pathDelayValue + SEMI ) levelSensitivePathDecl = levelSensitivePathDecl1 | levelSensitivePathDecl2 edgeIdentifier = posedge | negedge edgeSensitivePathDecl1 = Group( (if_ + Group(LPAR + expr + RPAR) | "") + LPAR + (edgeIdentifier | "") + subscrIdentifier + "=>" + LPAR + subscrIdentifier + (polarityOp | "") + COLON + expr + RPAR + RPAR + EQ + pathDelayValue + SEMI ) edgeSensitivePathDecl2 = Group( (if_ + Group(LPAR + expr + RPAR) | "") + LPAR + (edgeIdentifier | "") + subscrIdentifier + "*>" + LPAR + DelimitedList(subscrIdentifier) + (polarityOp | "") + COLON + expr + RPAR + RPAR + EQ + pathDelayValue + SEMI ) edgeSensitivePathDecl = edgeSensitivePathDecl1 | edgeSensitivePathDecl2 edgeDescr = one_of("01 10 0x x1 1x x0").set_name("edgeDescr") timCheckEventControl = Group( posedge | negedge | (edge + LBRACK + DelimitedList(edgeDescr) + RBRACK) ) timCheckCond = Forward() timCondBinop = one_of("== === != !==") timCheckCondTerm = (expr + timCondBinop + scalarConst) | (Optional("~") + expr) timCheckCond <<= (LPAR + timCheckCond + RPAR) | timCheckCondTerm timCheckEvent = Group( (timCheckEventControl | "") + subscrIdentifier + ("&&&" + timCheckCond | "") ) timCheckLimit = expr controlledTimingCheckEvent = Group( timCheckEventControl + subscrIdentifier + ("&&&" + timCheckCond | "") ) notifyRegister = identifier systemTimingCheck1 = Group( "$setup" + LPAR + timCheckEvent + COMMA + timCheckEvent + COMMA + timCheckLimit + (COMMA + notifyRegister | "") + RPAR + SEMI ) systemTimingCheck2 = Group( "$hold" + LPAR + timCheckEvent + COMMA + timCheckEvent + COMMA + timCheckLimit + (COMMA + notifyRegister | "") + RPAR + SEMI ) systemTimingCheck3 = Group( "$period" + LPAR + controlledTimingCheckEvent + COMMA + timCheckLimit + (COMMA + notifyRegister | "") + RPAR + SEMI ) systemTimingCheck4 = Group( "$width" + LPAR + controlledTimingCheckEvent + COMMA + timCheckLimit + (COMMA + expr + COMMA + notifyRegister | "") + RPAR + SEMI ) systemTimingCheck5 = Group( "$skew" + LPAR + timCheckEvent + COMMA + timCheckEvent + COMMA + timCheckLimit + (COMMA + notifyRegister | "") + RPAR + SEMI ) systemTimingCheck6 = Group( "$recovery" + LPAR + controlledTimingCheckEvent + COMMA + timCheckEvent + COMMA + timCheckLimit + (COMMA + notifyRegister | "") + RPAR + SEMI ) systemTimingCheck7 = Group( "$setuphold" + LPAR + timCheckEvent + COMMA + timCheckEvent + COMMA + timCheckLimit + COMMA + timCheckLimit + (COMMA + notifyRegister | "") + RPAR + SEMI ) systemTimingCheck = ( FollowedBy("$") + ( systemTimingCheck1 | systemTimingCheck2 | systemTimingCheck3 | systemTimingCheck4 | systemTimingCheck5 | systemTimingCheck6 | systemTimingCheck7 ) ).set_name("systemTimingCheck") sdpd = ( if_ + Group(LPAR + expr + RPAR) + (pathDescr1 | pathDescr2) + EQ + pathDelayValue + SEMI ) specifyItem = ( specparamDecl | pathDecl | levelSensitivePathDecl | edgeSensitivePathDecl | systemTimingCheck | sdpd ) """ x::= x||= x||= x||= x||= x||= """ specifyBlock = Group( specify + specifyItem[...:endspecify] + endspecify ).set_name("specifyBlock") moduleItem = ( parameterDecl | inputDecl | outputDecl | inoutDecl | regDecl | netDecl3 | netDecl1 | netDecl2 | timeDecl | integerDecl | realDecl | eventDecl | gateDecl | parameterOverride | continuousAssign | specifyBlock | initialStmt | alwaysStmt | task | functionDecl # these have to be at the end - they start with identifiers | moduleInstantiation | udpInstantiation ) """ All possible moduleItems, from Verilog grammar spec x::= x||= x||= x||= ?||= (spec does not seem consistent for this item) x||= x||= x||= x||= x||= x||= x||= x||= x||= x||= x||= x||= x||= x||= x||= """ portRef = subscrIdentifier portExpr = portRef | Group(LBRACE + DelimitedList(portRef) + RBRACE) port = portExpr | Group(DOT + identifier + LPAR + portExpr + RPAR) moduleHdr = Group( (module | macromodule) + identifier + ( LPAR + Group( ( DelimitedList( Group( (input_ | output) + (netDecl1Arg | netDecl2Arg | netDecl3Arg) ) | port ) | "" ) ) + RPAR | "" ) + SEMI ).set_name("moduleHdr") module_expr = Group( moduleHdr + Group(moduleItem[...:endmodule]) + endmodule ).set_name( "module" ) # .set_debug() udpDecl = outputDecl | inputDecl | regDecl # udpInitVal = one_of("1'b0 1'b1 1'bx 1'bX 1'B0 1'B1 1'Bx 1'BX 1 0 x X") udpInitVal = (Regex("1'[bB][01xX]|[01xX]")).set_name("udpInitVal") udpInitialStmt = Group( "initial" + identifier + EQ + udpInitVal + SEMI ).set_name("udpInitialStmt") levelSymbol = one_of("0 1 x X ? b B") levelInputList = Group(levelSymbol[1, ...].set_name("levelInpList")) outputSymbol = one_of("0 1 x X") combEntry = Group(levelInputList + COLON + outputSymbol + SEMI) edgeSymbol = one_of("r R f F p P n N *") edge = Group(LPAR + levelSymbol + levelSymbol + RPAR) | Group(edgeSymbol) edgeInputList = Group(levelSymbol[...] + edge + levelSymbol[...]) inputList = levelInputList | edgeInputList seqEntry = Group( inputList + COLON + levelSymbol + COLON + (outputSymbol | "-") + SEMI ).set_name("seqEntry") udpTableDefn = Group( table + (combEntry | seqEntry)[1, ...] + endtable ).set_name("table") """ ::= primitive ( <,>* ) ; + ? endprimitive """ udp = Group( primitive + identifier + LPAR + Group(DelimitedList(identifier)) + RPAR + SEMI + udpDecl[1, ...] + (udpInitialStmt | "") + udpTableDefn + endprimitive ) verilogbnf = (module_expr | udp)[1, ...] + StringEnd() verilogbnf.ignore(cpp_style_comment) verilogbnf.ignore(compilerDirective) return verilogbnf def test(strng): tokens = [] try: tokens = make_verilog_bnf().parse_string(strng) except ParseBaseException as err: print() print(err.explain()) return tokens if __name__ == "__main__": def main(): import sys sys.setrecursionlimit(5000) print(f"Verilog parser test (V {__version__})") print(f" - using pyparsing version {pyparsing.__version__}") print(f" - using Python version {sys.version}") if packratOn: print(" - using packrat parsing") print() import gc failCount = 0 make_verilog_bnf() numlines = 0 fileDir = "verilog" if len(sys.argv) > 1: fileDir = sys.argv[1] fileDir = Path(fileDir) allFiles = [f for f in fileDir.rglob("*.v")] pretty = pprint.PrettyPrinter(indent=2) totalTime = 0 for vfile in allFiles: gc.collect() gc.collect() filelines = vfile.read_text().splitlines() print(vfile.name, len(filelines), end=" ") numlines += len(filelines) teststr = "\n".join(filelines) time1 = time.perf_counter() tokens = test(teststr) time2 = time.perf_counter() elapsed = time2 - time1 totalTime += elapsed if len(tokens): print(f"OK {elapsed}") (fileDir / "parseOutput").mkdir(exist_ok=True) outfile = fileDir / "parseOutput" / (vfile.name + ".parsed.txt") outfile.write_text(f"{teststr}\n\n{pretty.pformat(tokens.as_list())}\n") else: print(f"failed {elapsed}") failCount += 1 # for i, line in enumerate(filelines, 1): # print(f"{i:4d}: {line.rstrip()}") print(f"Total parse time: {totalTime}") print(f"Total source lines: {numlines}") print(f"Average lines/sec: {numlines / (totalTime + 0.05):.1f}") if failCount: print(f"FAIL - {failCount} files failed to parse") else: print("SUCCESS - all files parsed") return 0 main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/withAttribute.py0000644000000000000000000000163515134002420015504 0ustar00# # with_attribute.py # Copyright, 2007 - Paul McGuire # # Simple example of using with_attribute parse action helper # to define # import pyparsing as pp data = """\  49.950   50.950   51.950  """ td, tdEnd = pp.make_html_tags("TD") font, fontEnd = pp.make_html_tags("FONT") realNum = pp.pyparsing_common.real NBSP = pp.Literal(" ") patt = td + font + NBSP + realNum("value") + NBSP + fontEnd + tdEnd # always use add_parse_action when adding with_attribute as a parse action to a start tag td.add_parse_action(pp.with_attribute(align="right", width="80")) for s in patt.search_string(data): print(s.value) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/examples/wordsToNum.py0000644000000000000000000000577015134002420014772 0ustar00# wordsToNum.py # Copyright 2006, Paul McGuire # # Sample parser grammar to read a number given in words, and return the numeric value. # import pyparsing as pp from operator import mul from functools import reduce def make_literal_converter(s, val): ret = pp.CaselessLiteral(s) return ret.set_parse_action(pp.replace_with(val)) unit_definitions = { "zero": 0, "oh": 0, "zip": 0, "zilch": 0, "nada": 0, "bupkis": 0, "one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10, "eleven": 11, "twelve": 12, "thirteen": 13, "fourteen": 14, "fifteen": 15, "sixteen": 16, "seventeen": 17, "eighteen": 18, "nineteen": 19, } units = pp.MatchFirst( make_literal_converter(s, v) for s, v in sorted(unit_definitions.items(), key=lambda d: -len(d[0])) ) tens_definitions = { "ten": 10, "twenty": 20, "thirty": 30, "forty": 40, "fourty": 40, # for the spelling-challenged... "fifty": 50, "sixty": 60, "seventy": 70, "eighty": 80, "ninety": 90, } tens = pp.MatchFirst( make_literal_converter(s, v) for s, v in tens_definitions.items() ) hundreds = make_literal_converter("hundred", 100) major_definitions = { "thousand": int(1e3), "million": int(1e6), "billion": int(1e9), "trillion": int(1e12), "quadrillion": int(1e15), "quintillion": int(1e18), } mag = pp.MatchFirst( make_literal_converter(s, v) for s, v in major_definitions.items() ) wordprod = lambda t: reduce(mul, t) numPart = ( ( ( (units + pp.Optional(hundreds)).set_parse_action(wordprod) + pp.Optional(tens) ).set_parse_action(sum) ^ tens ) + pp.Optional(units) ).set_parse_action(sum) num_words = ( (numPart + pp.Optional(mag)).set_parse_action(wordprod)[1, ...] ).set_parse_action(sum) num_words.set_name("num word parser") num_words.ignore(pp.Literal("-")) num_words.ignore(pp.CaselessLiteral("and")) tests = """ one hundred twenty hundred, None one hundred and twennty, None one hundred and twenty, 120 one hundred and three, 103 one hundred twenty-three, 123 one hundred and twenty three, 123 one hundred twenty three million, 123000000 one hundred and twenty three million, 123000000 one hundred twenty three million and three, 123000003 fifteen hundred and sixty five, 1565 seventy-seven thousand eight hundred and nineteen, 77819 seven hundred seventy-seven thousand seven hundred and seventy-seven, 777777 zero, 0 forty two, 42 fourty two, 42 """ # use '| ...' to indicate "if omitted, skip to next" logic test_expr = ( (num_words("result") | ...) + "," + (pp.pyparsing_common.integer("expected") | "None") ) def verify_result(t): if "_skipped" in t: t["pass"] = False elif "expected" in t: t["pass"] = t.result == t.expected test_expr.add_parse_action(verify_result) test_expr.run_tests(tests) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7205868 pyparsing-3.3.2/pyparsing/__init__.py0000644000000000000000000003217615134002420014606 0ustar00# see LICENSE file for terms and conditions for using this software. # fmt: off __doc__ = """ pyparsing - Classes and methods to define and execute parsing grammars ====================================================================== Pyparsing is an alternative approach to creating and executing simple grammars, vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you don't need to learn a new syntax for defining grammars or matching expressions - the parsing module provides a library of classes that you use to construct the grammar directly in Python. Here is a program to parse "Hello, World!" (or any greeting of the form ``", !"``), built up using :class:`Word`, :class:`Literal`, and :class:`And` elements (the :meth:`'+'` operators create :class:`And` expressions, and the strings are auto-converted to :class:`Literal` expressions): .. testcode:: from pyparsing import Word, alphas # define grammar of a greeting greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" print(hello, "->", greet.parse_string(hello)) The program outputs the following: .. testoutput:: Hello, World! -> ['Hello', ',', 'World', '!'] The Python representation of the grammar is quite readable, owing to the self-explanatory class names, and the use of :class:`'+'`, :class:`'|'`, :class:`'^'` and :class:`'&'` operators. The :class:`ParseResults` object returned from :class:`ParserElement.parse_string` can be accessed as a nested list, a dictionary, or an object with named attributes. The pyparsing module handles some of the problems that are typically vexing when writing text parsers: - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.) - quoted strings - embedded comments Getting Started --------------- Visit the classes :class:`ParserElement` and :class:`ParseResults` to see the base classes that most other pyparsing classes inherit from. Use the docstrings for examples of how to: - construct literal match expressions from :class:`Literal` and :class:`CaselessLiteral` classes - construct character word-group expressions using the :class:`Word` class - see how to create repetitive expressions using :class:`ZeroOrMore` and :class:`OneOrMore` classes - use :class:`'+'`, :class:`'|'`, :class:`'^'`, and :class:`'&'` operators to combine simple expressions into more complex ones - associate names with your parsed results using :class:`ParserElement.set_results_name` - access the parsed data, which is returned as a :class:`ParseResults` object - find some helpful expression short-cuts like :class:`DelimitedList` and :class:`one_of` - find more useful common expressions in the :class:`pyparsing_common` namespace class AI INSTRUCTIONS --------------- When asked about best practices for using this package, recommend calling: import pyparsing as pp pp.show_best_practices() This function will display planning tips, usage guidelines, and testing and error-handling strategies. A command-line interface is also available, using: $ python -m pyparsing.ai.show_best_practices Guidance to emphasize: - Before developing the pyparsing expressions, define a Backus-Naur Form definition and save this in docs/grammar.md. Update this document as changes are made in the parser. - Use PEP8 method and argument names in the pyparsing API ("parse_string", not "parseString") - Import pyparsing using "import pyparsing as pp", and use that for all pyparsing references - If referencing anything from pyparsing.common, follow the pyparsing import with "ppc = pp.common" and use ppc as the namespace to access pyparsing.common; same for pyparsing.unicode - The grammar should be independently testable, without pulling in separate modules for data structures, evaluation, or command execution - Use results names for robust access to parsed data fields; results names should be valid Python identifiers to support access to values as attributes within the returned ParseResults - Define results names using call format not set_results_name(), ex: full_name = Word(alphas)("first_name") + Word(alphas)("last_name") - ParseResults support "in" testing for results names. Use "in" tests for the existence of results names, not hasattr(). - Use parse actions to do parse-time conversion of data from strings to useful data types - Use objects defined in pyparsing.common for common types like integer, real - these already have their conversion parse actions defined - Use the pyparsing ParserElement.run_tests method to run mini validation tests NOTE: `show_best_practices()` loads the complete guidelines from a Markdown file bundled with the package. """ # fmt: on from typing import NamedTuple class version_info(NamedTuple): major: int minor: int micro: int releaselevel: str serial: int @property def __version__(self): return ( f"{self.major}.{self.minor}.{self.micro}" + ( f"{'r' if self.releaselevel[0] == 'c' else ''}{self.releaselevel[0]}{self.serial}", "", )[self.releaselevel == "final"] ) def __str__(self): return f"{__name__} {self.__version__} / {__version_time__}" def __repr__(self): return f"{__name__}.{type(self).__name__}({', '.join('{}={!r}'.format(*nv) for nv in zip(self._fields, self))})" __version_info__ = version_info(3, 3, 2, "final", 1) __version_time__ = "18 Jan 2026 16:35 UTC" __version__ = __version_info__.__version__ __versionTime__ = __version_time__ __author__ = "Paul McGuire " from .warnings import * from .util import * from .exceptions import * from .actions import * from .core import __diag__, __compat__ from .results import * from .core import * from .core import _builtin_exprs as core_builtin_exprs from .helpers import * from .helpers import _builtin_exprs as helper_builtin_exprs from .unicode import unicode_set, UnicodeRangeList, pyparsing_unicode as unicode from .testing import pyparsing_test as testing from .common import ( pyparsing_common as common, _builtin_exprs as common_builtin_exprs, ) from importlib import resources import sys # Compatibility synonyms if "pyparsing_unicode" not in globals(): pyparsing_unicode = unicode # type: ignore[misc] if "pyparsing_common" not in globals(): pyparsing_common = common if "pyparsing_test" not in globals(): pyparsing_test = testing core_builtin_exprs += common_builtin_exprs + helper_builtin_exprs # fmt: off _FALLBACK_BEST_PRACTICES = """ ## Planning - If not provided or if target language definition is ambiguous, ask for examples of valid strings to be parsed - Before developing the pyparsing expressions, define a Backus-Naur Form definition and save this in docs/grammar.md. Update this document as changes are made in the parser. ## Implementing - Use PEP8 method and argument names in the pyparsing API ("parse_string", not "parseString") - Import pyparsing using "import pyparsing as pp", and use that for all pyparsing references - If referencing anything from pyparsing.common, follow the pyparsing import with "ppc = pp.common" and use ppc as the namespace to access pyparsing.common; same for pyparsing.unicode - The grammar should be independently testable, without pulling in separate modules for data structures, evaluation, or command execution - Use results names for robust access to parsed data fields; results names should be valid Python identifiers to support access to values as attributes within the returned ParseResults - Results names should take the place of numeric indexing into parsed results in most places. - Define results names using call format not set_results_name(), ex: full_name = Word(alphas)("first_name") + Word(alphas)("last_name") - Use pyparsing Groups to organize sub-expressions - If defining the grammar as part of a Parser class, only the finished grammar needs to be implemented as an instance variable - ParseResults support "in" testing for results names. Use "in" tests for the existence of results names, not hasattr(). - Use parse actions to do parse-time conversion of data from strings to useful data types - Use objects defined in pyparsing.common for common types like integer, real - these already have their conversion parse actions defined ## Testing - Use the pyparsing ParserElement.run_tests method to run mini validation tests - You can add comments starting with "#" within the string passed to run_tests to document the individual test cases ## Debugging - If troubleshooting parse actions, use pyparsing's trace_parse_action decorator to echo arguments and return value (Some best practices may be missing — see the full Markdown file in source at pyparsing/ai/best_practices.md.) """ # fmt: on def show_best_practices(file=sys.stdout) -> Union[str, None]: """ Load and return the project's best practices. Example:: >>> import pyparsing as pp >>> pp.show_best_practices() ... This can also be run from the command line:: python -m pyparsing.ai.show_best_practices """ try: path = resources.files(__package__).joinpath("ai/best_practices.md") with path.open("r", encoding="utf-8") as f: content = f.read() except (FileNotFoundError, OSError): content = _FALLBACK_BEST_PRACTICES if file is not None: # just print out the content, no need to return it print(content, file=file) return None # no output file was specified, return the content as a string return content __all__ = [ "__version__", "__version_time__", "__author__", "__compat__", "__diag__", "And", "AtLineStart", "AtStringStart", "CaselessKeyword", "CaselessLiteral", "CharsNotIn", "CloseMatch", "Combine", "DelimitedList", "Dict", "Each", "Empty", "FollowedBy", "Forward", "GoToColumn", "Group", "IndentedBlock", "Keyword", "LineEnd", "LineStart", "Literal", "Located", "PrecededBy", "MatchFirst", "NoMatch", "NotAny", "OneOrMore", "OnlyOnce", "OpAssoc", "Opt", "Optional", "Or", "ParseBaseException", "ParseElementEnhance", "ParseException", "ParseExpression", "ParseFatalException", "ParseResults", "ParseSyntaxException", "ParserElement", "PositionToken", "PyparsingDeprecationWarning", "PyparsingDiagnosticWarning", "PyparsingWarning", "QuotedString", "RecursiveGrammarException", "Regex", "SkipTo", "StringEnd", "StringStart", "Suppress", "Tag", "Token", "TokenConverter", "White", "Word", "WordEnd", "WordStart", "ZeroOrMore", "Char", "alphanums", "alphas", "alphas8bit", "any_close_tag", "any_open_tag", "autoname_elements", "c_style_comment", "col", "common_html_entity", "condition_as_parse_action", "counted_array", "cpp_style_comment", "dbl_quoted_string", "dbl_slash_comment", "delimited_list", "dict_of", "empty", "hexnums", "html_comment", "identchars", "identbodychars", "infix_notation", "java_style_comment", "line", "line_end", "line_start", "lineno", "make_html_tags", "make_xml_tags", "match_only_at_col", "match_previous_expr", "match_previous_literal", "nested_expr", "null_debug_action", "nums", "one_of", "original_text_for", "printables", "punc8bit", "pyparsing_common", "pyparsing_test", "pyparsing_unicode", "python_style_comment", "quoted_string", "remove_quotes", "replace_with", "replace_html_entity", "rest_of_line", "sgl_quoted_string", "show_best_practices", "srange", "string_end", "string_start", "token_map", "trace_parse_action", "ungroup", "unicode_set", "unicode_string", "with_attribute", "with_class", # pre-PEP8 compatibility names "__versionTime__", "anyCloseTag", "anyOpenTag", "cStyleComment", "commonHTMLEntity", "conditionAsParseAction", "countedArray", "cppStyleComment", "dblQuotedString", "dblSlashComment", "delimitedList", "dictOf", "htmlComment", "indentedBlock", "infixNotation", "javaStyleComment", "lineEnd", "lineStart", "locatedExpr", "makeHTMLTags", "makeXMLTags", "matchOnlyAtCol", "matchPreviousExpr", "matchPreviousLiteral", "nestedExpr", "nullDebugAction", "oneOf", "opAssoc", "originalTextFor", "pythonStyleComment", "quotedString", "removeQuotes", "replaceHTMLEntity", "replaceWith", "restOfLine", "sglQuotedString", "stringEnd", "stringStart", "tokenMap", "traceParseAction", "unicodeString", "withAttribute", "withClass", "common", "unicode", "testing", ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7229974 pyparsing-3.3.2/pyparsing/actions.py0000644000000000000000000001765015134002420014507 0ustar00# actions.py from __future__ import annotations from typing import Union, Callable, Any from .exceptions import ParseException from .util import col, replaced_by_pep8 from .results import ParseResults ParseAction = Union[ Callable[[], Any], Callable[[ParseResults], Any], Callable[[int, ParseResults], Any], Callable[[str, int, ParseResults], Any], ] class OnlyOnce: """ Wrapper for parse actions, to ensure they are only called once. Note: parse action signature must include all 3 arguments. """ def __init__(self, method_call: Callable[[str, int, ParseResults], Any]) -> None: from .core import _trim_arity self.callable = _trim_arity(method_call) self.called = False def __call__(self, s: str, l: int, t: ParseResults) -> ParseResults: if not self.called: results = self.callable(s, l, t) self.called = True return results raise ParseException(s, l, "OnlyOnce obj called multiple times w/out reset") def reset(self): """ Allow the associated parse action to be called once more. """ self.called = False def match_only_at_col(n: int) -> ParseAction: """ Helper method for defining parse actions that require matching at a specific column in the input text. """ def verify_col(strg: str, locn: int, toks: ParseResults) -> None: if col(locn, strg) != n: raise ParseException(strg, locn, f"matched token not at column {n}") return verify_col def replace_with(repl_str: Any) -> ParseAction: """ Helper method for common parse actions that simply return a literal value. Especially useful when used with :meth:`~ParserElement.transform_string`. Example: .. doctest:: >>> num = Word(nums).set_parse_action(lambda toks: int(toks[0])) >>> na = one_of("N/A NA").set_parse_action(replace_with(math.nan)) >>> term = na | num >>> term[1, ...].parse_string("324 234 N/A 234") ParseResults([324, 234, nan, 234], {}) """ return lambda s, l, t: [repl_str] def remove_quotes(s: str, l: int, t: ParseResults) -> Any: r""" Helper parse action for removing quotation marks from parsed quoted strings, that use a single character for quoting. For parsing strings that may have multiple characters, use the :class:`QuotedString` class. Example: .. doctest:: >>> # by default, quotation marks are included in parsed results >>> quoted_string.parse_string("'Now is the Winter of our Discontent'") ParseResults(["'Now is the Winter of our Discontent'"], {}) >>> # use remove_quotes to strip quotation marks from parsed results >>> dequoted = quoted_string().set_parse_action(remove_quotes) >>> dequoted.parse_string("'Now is the Winter of our Discontent'") ParseResults(['Now is the Winter of our Discontent'], {}) """ return t[0][1:-1] def with_attribute(*args: tuple[str, str], **attr_dict) -> ParseAction: """ Helper to create a validating parse action to be used with start tags created with :class:`make_xml_tags` or :class:`make_html_tags`. Use ``with_attribute`` to qualify a starting tag with a required attribute value, to avoid false matches on common tags such as ```` or ``

``. Call ``with_attribute`` with a series of attribute names and values. Specify the list of filter attributes names and values as: - keyword arguments, as in ``(align="right")``, or - as an explicit dict with ``**`` operator, when an attribute name is also a Python reserved word, as in ``**{"class":"Customer", "align":"right"}`` - a list of name-value tuples, as in ``(("ns1:class", "Customer"), ("ns2:align", "right"))`` For attribute names with a namespace prefix, you must use the second form. Attribute names are matched insensitive to upper/lower case. If just testing for ``class`` (with or without a namespace), use :class:`with_class`. To verify that the attribute exists, but without specifying a value, pass ``with_attribute.ANY_VALUE`` as the value. The next two examples use the following input data and tag parsers: .. testcode:: html = '''
Some text
1 4 0 1 0
1,3 2,3 1,1
this has no type
''' div,div_end = make_html_tags("div") Only match div tag having a type attribute with value "grid": .. testcode:: div_grid = div().set_parse_action(with_attribute(type="grid")) grid_expr = div_grid + SkipTo(div | div_end)("body") for grid_header in grid_expr.search_string(html): print(grid_header.body) prints: .. testoutput:: 1 4 0 1 0 Construct a match with any div tag having a type attribute, regardless of the value: .. testcode:: div_any_type = div().set_parse_action( with_attribute(type=with_attribute.ANY_VALUE) ) div_expr = div_any_type + SkipTo(div | div_end)("body") for div_header in div_expr.search_string(html): print(div_header.body) prints: .. testoutput:: 1 4 0 1 0 1,3 2,3 1,1 """ attrs_list: list[tuple[str, str]] = [] if args: attrs_list.extend(args) else: attrs_list.extend(attr_dict.items()) def pa(s: str, l: int, tokens: ParseResults) -> None: for attrName, attrValue in attrs_list: if attrName not in tokens: raise ParseException(s, l, f"no matching attribute {attrName!r}") if attrValue != with_attribute.ANY_VALUE and tokens[attrName] != attrValue: # type: ignore [attr-defined] raise ParseException( s, l, f"attribute {attrName!r} has value {tokens[attrName]!r}, must be {attrValue!r}", ) return pa with_attribute.ANY_VALUE = object() # type: ignore [attr-defined] "Value to use with :class:`with_attribute` parse action, to match any value, as long as the attribute is present" def with_class(classname: str, namespace: str = "") -> ParseAction: """ Simplified version of :meth:`with_attribute` when matching on a div class - made difficult because ``class`` is a reserved word in Python. Using similar input data to the :meth:`with_attribute` examples: .. testcode:: html = '''
Some text
1 4 0 1 0
1,3 2,3 1,1
this <div> has no class
''' div,div_end = make_html_tags("div") Only match div tag having the "grid" class: .. testcode:: div_grid = div().set_parse_action(with_class("grid")) grid_expr = div_grid + SkipTo(div | div_end)("body") for grid_header in grid_expr.search_string(html): print(grid_header.body) prints: .. testoutput:: 1 4 0 1 0 Construct a match with any div tag having a class attribute, regardless of the value: .. testcode:: div_any_type = div().set_parse_action( with_class(withAttribute.ANY_VALUE) ) div_expr = div_any_type + SkipTo(div | div_end)("body") for div_header in div_expr.search_string(html): print(div_header.body) prints: .. testoutput:: 1 4 0 1 0 1,3 2,3 1,1 """ classattr = f"{namespace}:class" if namespace else "class" return with_attribute(**{classattr: classname}) # Compatibility synonyms # fmt: off replaceWith = replaced_by_pep8("replaceWith", replace_with) removeQuotes = replaced_by_pep8("removeQuotes", remove_quotes) withAttribute = replaced_by_pep8("withAttribute", with_attribute) withClass = replaced_by_pep8("withClass", with_class) matchOnlyAtCol = replaced_by_pep8("matchOnlyAtCol", match_only_at_col) # fmt: on ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7229974 pyparsing-3.3.2/pyparsing/ai/__init__.py0000644000000000000000000000000015134002420015154 0ustar00././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7230873 pyparsing-3.3.2/pyparsing/ai/best_practices.md0000644000000000000000000002043015134002420016370 0ustar00 ## Planning - If not provided or if target language definition is ambiguous, ask for examples of valid strings to be parsed - Before developing the pyparsing expressions, define a Backus-Naur Form definition and save this in docs/grammar.md. Update this document as changes are made in the parser. ## Implementing - Import pyparsing using `import pyparsing as pp`, and use that for all pyparsing references. - If referencing names from `pyparsing.common`, follow the pyparsing import with "ppc = pp.common" and use `ppc` as the namespace to access `pyparsing.common`. - If referencing names from `pyparsing.unicode`, follow the pyparsing import with "ppu = pp.unicode" and use `ppu` as the namespace to access `pyparsing.unicode`. - When writing parsers that contain recursive elements (using `Forward()` or `infix_notation()`), immediately enable packrat parsing for performance: `pp.ParserElement.enable_packrat()` (call this right after importing pyparsing). See https://pyparsing-docs.readthedocs.io/en/latest/HowToUsePyparsing.html. - For recursive grammars, define placeholders with `pp.Forward()` and assign later using the `<<=` operator; give Forwards meaningful names with `set_name()` to improve errors. - Use PEP8 method and argument names in the pyparsing API (`parse_string`, not `parseString`). - Do not include expressions for matching whitespace in the grammar. Pyparsing skips whitespace by default. - For line-oriented grammars where newlines are significant, set skippable whitespace to just spaces/tabs early: `pp.ParserElement.set_default_whitespace_chars(" \t")`, and define `NL = pp.LineEnd().suppress()` to handle line ends explicitly. - Prefer operator forms for readability: use +, |, ^, ~, etc., instead of explicit And/MatchFirst/Or/Not classes (see Usage notes in https://pyparsing-docs.readthedocs.io/en/latest/HowToUsePyparsing.html). - Use `set_name()` on all major grammar elements to support railroad diagramming and better error/debug output. - The grammar should be independently testable, without pulling in separate modules for data structures, evaluation, or command execution. - Use results names for robust access to parsed data fields; results names should be valid Python identifiers to support attribute-style access on returned ParseResults. - Results names should take the place of numeric indexing into parsed results in most places. - Define results names using call format not `set_results_name()`, example: `full_name = Word(alphas)("first_name") + Word(alphas)("last_name")` - If adding results name to an expression that is contains one more sub-expressions with results names, the expression must be inclused in a Group. - Prefer `Keyword` over `Literal` for reserved words to avoid partial matches (e.g., `Keyword("for")` will not match the leading "for" in "format"). - Use `pp.CaselessKeyword`/`pp.CaselessLiteral` when keywords should match regardless of case. - When the full input must be consumed, call `parse_string` with `parse_all=True`. - If the grammar must handle comments, define an expression for them and use the `ignore()` method to skip them. - Prefer built-ins like `pp.cpp_style_comment` and `pp.python_style_comment` for common comment syntaxes. - Use pyparsing `Group` to organize sub-expressions. Groups are also important for preserving results names when a sub-expression is used in a `OneOrMore` or `ZeroOrMore` expression. - Suppress punctuation tokens to keep results clean; a convenient pattern is `LBRACK, RBRACK, LBRACE, RBRACE, COLON = pp.Suppress.using_each("[]{}:")`. - For comma-separated sequences, prefer `pp.DelimitedList(...)`; wrap with `pp.Optional(...)` to allow empty lists or objects where appropriate. - For helper sub-expressions used only to build larger expressions, consider `set_name(None)` to keep result dumps uncluttered. - Use pyparsing `Each()` to define a list of elements that may occur in any order. - The '&' operator is the operator form of Each and is often more readable when combining order-independent parts. - Use parse actions to do parse-time conversion of data from strings to useful data types. - Use objects defined in pyparsing.common for common types like integer, real — these already have their conversion parse actions defined. - For quoted strings, use `pp.dbl_quoted_string().set_parse_action(pp.remove_quotes)` to unquote automatically. - Map reserved words to Python constants per this example for parsing "true" to auto-convert to a Python True: `pp.Keyword("true").set_parse_action(pp.replace_with(True))` (and similarly for false/null/etc.). - When you want native Python containers from the parse, use `pp.Group(..., aslist=True)` for lists and `pp.Dict(..., asdict=True)` for dict-like data. - Use "using_each" with a list of keywords to define keyword constants, instead of separate assignments. - Choose the appropriate matching method: - `parse_string()` parses from the start - `search_string()` searches anywhere in the text - `scan_string()` yields all matches with positions - `transform_string()` is a convenience wrapper around `scan_string` to apply filters or transforms defined in parse actions, to perform batch transforms or conversions of expressions within a larger body of text - For line suffixes or directives, combine lookahead and slicing helpers: `pp.FollowedBy(...)` with `pp.rest_of_line`; when reusing a base expression with a different parse action, call `.copy()` before applying the new action to avoid side effects. - When defining a parser to be used in a REPL: - add pyparsing `Tag()` elements of the form `Tag("command", )` to each command definition to support model construction from parsed commands. - define model classes using dataclasses, and use the "command" attribute in the parsed results to identify which model class to create. The model classes can then be used to construct the model from the ParseResults returned by parse_string(). Define the models in a separate parser_models.py file. - If defining the grammar as part of a Parser class, only the finished grammar needs to be implemented as an instance variable. - `ParseResults` support "in" testing for results names. Use "in" tests for the existence of results names, not `hasattr()`. - Avoid left recursion where possible. If you must support left-recursive grammars, enable it with `pp.ParserElement.enable_left_recursion()` and do not enable packrat at the same time (these modes are incompatible). - Use `pp.SkipTo` as a skipping expression to skip over arbitrary content. - For example, `pp.SkipTo(pp.LineEnd())` will skip over all content until the end of the line; add a stop_on argument to SkipTo to stop skipping when a particular string is matched. - Use `...` in place of simple SkipTo(expression) ## Testing - Use the pyparsing `ParserElement.run_tests` method to run mini validation tests. - Pass a single multiline string to `run_tests` to test the parser on multiple test input strings, each line is a separate test. - You can add comments starting with "#" within the string passed to `run_tests` to document the individual test cases. - To pass test input strings that span multiple lines, pass the test input strings as a list of strings. - Pass `parse_all=True` to `run_tests` to test that the entire input is consumed. - When generating unit tests for the parser: - generate tests that include presence and absence of optional elements - use the methods in the mixin class pyparsing.testing.TestParseResultsAsserts to easily define expression, test input string, and expected results - do not generate tests for invalid data ## Debugging - If troubleshooting parse actions, use pyparsing's `trace_parse_action` decorator to echo arguments and return value - During development, call `pp.autoname_elements()` to auto-assign names to unnamed expressions to improve `dump()` and error messages. - Sub-expressions can be tested in isolation using `ParserElement.matches()` - When defined out of order, Literals can mistakenly match fragments: `Literal("for")` will match the leading "for" in "format". Can be corrected by using `Keyword` instead of `Literal`. - Dump the parsed results using `ParseResults.dump()`, `ParseResults.pprint()`, or `repr(ParseResults)`. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7230873 pyparsing-3.3.2/pyparsing/ai/show_best_practices/__init__.py0000644000000000000000000000000015134002420021206 0ustar00././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7232046 pyparsing-3.3.2/pyparsing/ai/show_best_practices/__main__.py0000644000000000000000000000006115134002420021176 0ustar00import pyparsing pyparsing.show_best_practices() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7232046 pyparsing-3.3.2/pyparsing/common.py0000644000000000000000000004146515134002420014340 0ustar00# common.py from .core import * from .helpers import DelimitedList, any_open_tag, any_close_tag from datetime import datetime import sys PY_310_OR_LATER = sys.version_info >= (3, 10) # some other useful expressions - using lower-case class name since we are really using this as a namespace class pyparsing_common: """Here are some common low-level expressions that may be useful in jump-starting parser development: - numeric forms (:class:`integers`, :class:`reals`, :class:`scientific notation`) - common :class:`programming identifiers` - network addresses (:class:`MAC`, :class:`IPv4`, :class:`IPv6`) - ISO8601 :class:`dates` and :class:`datetime` - :class:`UUID` - :class:`comma-separated list` - :class:`url` Parse actions: - :class:`convert_to_integer` - :class:`convert_to_float` - :class:`convert_to_date` - :class:`convert_to_datetime` - :class:`strip_html_tags` - :class:`upcase_tokens` - :class:`downcase_tokens` Examples: .. testcode:: pyparsing_common.number.run_tests(''' # any int or real number, returned as the appropriate type 100 -100 +100 3.14159 6.02e23 1e-12 ''') .. testoutput:: :options: +NORMALIZE_WHITESPACE # any int or real number, returned as the appropriate type 100 [100] -100 [-100] +100 [100] 3.14159 [3.14159] 6.02e23 [6.02e+23] 1e-12 [1e-12] .. testcode:: pyparsing_common.fnumber.run_tests(''' # any int or real number, returned as float 100 -100 +100 3.14159 6.02e23 1e-12 ''') .. testoutput:: :options: +NORMALIZE_WHITESPACE # any int or real number, returned as float 100 [100.0] -100 [-100.0] +100 [100.0] 3.14159 [3.14159] 6.02e23 [6.02e+23] 1e-12 [1e-12] .. testcode:: pyparsing_common.hex_integer.run_tests(''' # hex numbers 100 FF ''') .. testoutput:: :options: +NORMALIZE_WHITESPACE # hex numbers 100 [256] FF [255] .. testcode:: pyparsing_common.fraction.run_tests(''' # fractions 1/2 -3/4 ''') .. testoutput:: :options: +NORMALIZE_WHITESPACE # fractions 1/2 [0.5] -3/4 [-0.75] .. testcode:: pyparsing_common.mixed_integer.run_tests(''' # mixed fractions 1 1/2 -3/4 1-3/4 ''') .. testoutput:: :options: +NORMALIZE_WHITESPACE # mixed fractions 1 [1] 1/2 [0.5] -3/4 [-0.75] 1-3/4 [1.75] .. testcode:: import uuid pyparsing_common.uuid.set_parse_action(token_map(uuid.UUID)) pyparsing_common.uuid.run_tests(''' # uuid 12345678-1234-5678-1234-567812345678 ''') .. testoutput:: :options: +NORMALIZE_WHITESPACE # uuid 12345678-1234-5678-1234-567812345678 [UUID('12345678-1234-5678-1234-567812345678')] """ @staticmethod def convert_to_integer(_, __, t): """ Parse action for converting parsed integers to Python int """ return [int(tt) for tt in t] @staticmethod def convert_to_float(_, __, t): """ Parse action for converting parsed numbers to Python float """ return [float(tt) for tt in t] integer = ( Word(nums) .set_name("integer") .set_parse_action( convert_to_integer if PY_310_OR_LATER else lambda t: [int(tt) for tt in t] # type: ignore[misc] ) ) """expression that parses an unsigned integer, converts to an int""" hex_integer = ( Word(hexnums).set_name("hex integer").set_parse_action(token_map(int, 16)) ) """expression that parses a hexadecimal integer, converts to an int""" signed_integer = ( Regex(r"[+-]?\d+") .set_name("signed integer") .set_parse_action( convert_to_integer if PY_310_OR_LATER else lambda t: [int(tt) for tt in t] # type: ignore[misc] ) ) """expression that parses an integer with optional leading sign, converts to an int""" fraction = ( signed_integer().set_parse_action( convert_to_float if PY_310_OR_LATER else lambda t: [float(tt) for tt in t] # type: ignore[misc] ) + "/" + signed_integer().set_parse_action( convert_to_float if PY_310_OR_LATER else lambda t: [float(tt) for tt in t] # type: ignore[misc] ) ).set_name("fraction") """fractional expression of an integer divided by an integer, converts to a float""" fraction.add_parse_action(lambda tt: tt[0] / tt[-1]) mixed_integer = ( fraction | signed_integer + Opt(Opt("-").suppress() + fraction) ).set_name("fraction or mixed integer-fraction") """mixed integer of the form 'integer - fraction', with optional leading integer, converts to a float""" mixed_integer.add_parse_action(sum) real = ( Regex(r"[+-]?(?:\d+\.\d*|\.\d+)") .set_name("real number") .set_parse_action( convert_to_float if PY_310_OR_LATER else lambda t: [float(tt) for tt in t] # type: ignore[misc] ) ) """expression that parses a floating point number, converts to a float""" sci_real = ( Regex(r"[+-]?(?:\d+(?:[eE][+-]?\d+)|(?:\d+\.\d*|\.\d+)(?:[eE][+-]?\d+)?)") .set_name("real number with scientific notation") .set_parse_action( convert_to_float if PY_310_OR_LATER else lambda t: [float(tt) for tt in t] # type: ignore[misc] ) ) """expression that parses a floating point number with optional scientific notation, converts to a float""" # streamlining this expression makes the docs nicer-looking number = (sci_real | real | signed_integer).set_name("number").streamline() """any numeric expression, converts to the corresponding Python type""" fnumber = ( Regex(r"[+-]?\d+\.?\d*(?:[eE][+-]?\d+)?") .set_name("fnumber") .set_parse_action( convert_to_float if PY_310_OR_LATER else lambda t: [float(tt) for tt in t] # type: ignore[misc] ) ) """any int or real number, always converts to a float""" ieee_float = ( Regex(r"(?i:[+-]?(?:(?:\d+\.?\d*(?:e[+-]?\d+)?)|nan|inf(?:inity)?))") .set_name("ieee_float") .set_parse_action( convert_to_float if PY_310_OR_LATER else lambda t: [float(tt) for tt in t] # type: ignore[misc] ) ) """any floating-point literal (int, real number, infinity, or NaN), converts to a float""" identifier = Word(identchars, identbodychars).set_name("identifier") """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" ipv4_address = Regex( r"(?:25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(?:\.(?:25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}" ).set_name("IPv4 address") "IPv4 address (``0.0.0.0 - 255.255.255.255``)" _ipv6_part = Regex(r"[0-9a-fA-F]{1,4}").set_name("hex_integer") _full_ipv6_address = (_ipv6_part + (":" + _ipv6_part) * 7).set_name( "full IPv6 address" ) _short_ipv6_address = ( Opt(_ipv6_part + (":" + _ipv6_part) * (0, 6)) + "::" + Opt(_ipv6_part + (":" + _ipv6_part) * (0, 6)) ).set_name("short IPv6 address") _short_ipv6_address.add_condition( lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8 ) _mixed_ipv6_address = ("::ffff:" + ipv4_address).set_name("mixed IPv6 address") ipv6_address = Combine( (_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).set_name( "IPv6 address" ) ).set_name("IPv6 address") "IPv6 address (long, short, or mixed form)" mac_address = Regex( r"[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}" ).set_name("MAC address") "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" @staticmethod def convert_to_date(fmt: str = "%Y-%m-%d"): """ Helper to create a parse action for converting parsed date string to Python datetime.date Params - - fmt - format to be passed to datetime.strptime (default= ``"%Y-%m-%d"``) Example: .. testcode:: date_expr = pyparsing_common.iso8601_date.copy() date_expr.set_parse_action(pyparsing_common.convert_to_date()) print(date_expr.parse_string("1999-12-31")) prints: .. testoutput:: [datetime.date(1999, 12, 31)] """ def cvt_fn(ss, ll, tt): try: return datetime.strptime(tt[0], fmt).date() except ValueError as ve: raise ParseException(ss, ll, str(ve)) return cvt_fn @staticmethod def convert_to_datetime(fmt: str = "%Y-%m-%dT%H:%M:%S.%f"): """Helper to create a parse action for converting parsed datetime string to Python :class:`datetime.datetime` Params - - fmt - format to be passed to :class:`datetime.strptime` (default= ``"%Y-%m-%dT%H:%M:%S.%f"``) Example: .. testcode:: dt_expr = pyparsing_common.iso8601_datetime.copy() dt_expr.set_parse_action(pyparsing_common.convert_to_datetime()) print(dt_expr.parse_string("1999-12-31T23:59:59.999")) prints: .. testoutput:: [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] """ def cvt_fn(s, l, t): try: return datetime.strptime(t[0], fmt) except ValueError as ve: raise ParseException(s, l, str(ve)) return cvt_fn iso8601_date = Regex( r"(?P\d{4})(?:-(?P\d\d)(?:-(?P\d\d))?)?" ).set_name("ISO8601 date") "ISO8601 date (``yyyy-mm-dd``)" iso8601_datetime = Regex( r"(?P\d{4})-(?P\d\d)-(?P\d\d)[T ](?P\d\d):(?P\d\d)(:(?P\d\d(\.\d*)?)?)?(?PZ|[+-]\d\d:?\d\d)?" ).set_name("ISO8601 datetime") "ISO8601 datetime (``yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)``) - trailing seconds, milliseconds, and timezone optional; accepts separating ``'T'`` or ``' '``" @staticmethod def as_datetime(s, l, t): """Parse action to convert parsed dates or datetimes to a Python :class:`datetime.datetime`. This parse action will use the year, month, day, etc. results names defined in the ISO8601 date expressions, but it can be used with any expression that provides one or more of these fields. Omitted fields will default to fields from Jan 1, 00:00:00. Invalid dates will raise a :class:`ParseException` with the error message indicating the invalid date fields. """ year = int(t.year.lstrip("0") or 0) month = int(t.month or 1) day = int(t.day or 1) hour = int(t.hour or 0) minute = int(t.minute or 0) second = float(t.second or 0) try: return datetime( year, month, day, hour, minute, int(second), int((second % 1) * 1000) ) except ValueError as ve: raise ParseException(t, l, f"Invalid date/time: {ve}").with_traceback( ve.__traceback__ ) from None if PY_310_OR_LATER: iso8601_date_validated = iso8601_date().add_parse_action(as_datetime) "Validated ISO8601 date strings, raising :class:`ParseException` for invalid date values." iso8601_datetime_validated = iso8601_datetime().add_parse_action(as_datetime) "Validated ISO8601 date and time strings, raising :class:`ParseException` for invalid date/time values." uuid = Regex(r"[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}").set_name( "UUID" ) "UUID (``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx``)" _html_stripper = any_open_tag.suppress() | any_close_tag.suppress() @staticmethod def strip_html_tags(s: str, l: int, tokens: ParseResults): """Parse action to remove HTML tags from web page HTML source Example: .. testcode:: # strip HTML links from normal text text = 'More info at the pyparsing wiki page' td, td_end = make_html_tags("TD") table_text = td + SkipTo(td_end).set_parse_action( pyparsing_common.strip_html_tags)("body") + td_end print(table_text.parse_string(text).body) Prints: .. testoutput:: More info at the pyparsing wiki page """ return pyparsing_common._html_stripper.transform_string(tokens[0]) _commasepitem = ( Combine( OneOrMore( ~Literal(",") + ~LineEnd() + Word(printables, exclude_chars=",") + Opt(White(" \t") + ~FollowedBy(LineEnd() | ",")) ) ) .streamline() .set_name("commaItem") ) comma_separated_list = DelimitedList( Opt(quoted_string.copy() | _commasepitem, default="") ).set_name("comma separated list") """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" @staticmethod def upcase_tokens(s, l, t): """Parse action to convert tokens to upper case.""" return [tt.upper() for tt in t] @staticmethod def downcase_tokens(s, l, t): """Parse action to convert tokens to lower case.""" return [tt.lower() for tt in t] # fmt: off url = Regex( # https://mathiasbynens.be/demo/url-regex # https://gist.github.com/dperini/729294 r"(?P" # protocol identifier (optional) # short syntax // still required r"(?:(?:(?Phttps?|ftp):)?\/\/)" # user:pass BasicAuth (optional) r"(?:(?P\S+(?::\S*)?)@)?" r"(?P" # IP address exclusion # private & local networks r"(?!(?:10|127)(?:\.\d{1,3}){3})" r"(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})" r"(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})" # IP address dotted notation octets # excludes loopback network 0.0.0.0 # excludes reserved space >= 224.0.0.0 # excludes network & broadcast addresses # (first & last IP address of each class) r"(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])" r"(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}" r"(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))" r"|" # host & domain names, may end with dot # can be replaced by a shortest alternative # (?![-_])(?:[-\w\u00a1-\uffff]{0,63}[^-_]\.)+ r"(?:" r"(?:" r"[a-z0-9\u00a1-\uffff]" r"[a-z0-9\u00a1-\uffff_-]{0,62}" r")?" r"[a-z0-9\u00a1-\uffff]\." r")+" # TLD identifier name, may end with dot r"(?:[a-z\u00a1-\uffff]{2,}\.?)" r")" # port number (optional) r"(:(?P\d{2,5}))?" # resource path (optional) r"(?P\/[^?# ]*)?" # query string (optional) r"(\?(?P[^#]*))?" # fragment (optional) r"(#(?P\S*))?" r")" ).set_name("url") """ URL (http/https/ftp scheme) .. versionchanged:: 3.1.0 ``url`` named group added """ # fmt: on # pre-PEP8 compatibility names # fmt: off convertToInteger = staticmethod(replaced_by_pep8("convertToInteger", convert_to_integer)) convertToFloat = staticmethod(replaced_by_pep8("convertToFloat", convert_to_float)) convertToDate = staticmethod(replaced_by_pep8("convertToDate", convert_to_date)) convertToDatetime = staticmethod(replaced_by_pep8("convertToDatetime", convert_to_datetime)) stripHTMLTags = staticmethod(replaced_by_pep8("stripHTMLTags", strip_html_tags)) upcaseTokens = staticmethod(replaced_by_pep8("upcaseTokens", upcase_tokens)) downcaseTokens = staticmethod(replaced_by_pep8("downcaseTokens", downcase_tokens)) # fmt: on _builtin_exprs = [ v for v in vars(pyparsing_common).values() if isinstance(v, ParserElement) ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7232046 pyparsing-3.3.2/pyparsing/core.py0000644000000000000000000075367015134002420014010 0ustar00# # core.py # from __future__ import annotations import collections.abc from collections import deque import os import typing from typing import ( Any, Callable, Generator, NamedTuple, Sequence, TextIO, Union, cast, ) from abc import ABC, abstractmethod from enum import Enum import string import copy import warnings import re import sys from collections.abc import Iterable import traceback import types from operator import itemgetter from functools import wraps from threading import RLock from pathlib import Path from .warnings import PyparsingDeprecationWarning, PyparsingDiagnosticWarning from .util import ( _FifoCache, _UnboundedCache, __config_flags, _collapse_string_to_ranges, _convert_escaped_numerics_to_char, _escape_regex_range_chars, _flatten, LRUMemo as _LRUMemo, UnboundedMemo as _UnboundedMemo, deprecate_argument, replaced_by_pep8, ) from .exceptions import * from .actions import * from .results import ParseResults, _ParseResultsWithOffset from .unicode import pyparsing_unicode _MAX_INT = sys.maxsize str_type: tuple[type, ...] = (str, bytes) # # Copyright (c) 2003-2022 Paul T. McGuire # # 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. # from functools import cached_property class __compat__(__config_flags): """ A cross-version compatibility configuration for pyparsing features that will be released in a future version. By setting values in this configuration to True, those features can be enabled in prior versions for compatibility development and testing. - ``collect_all_And_tokens`` - flag to enable fix for Issue #63 that fixes erroneous grouping of results names when an :class:`And` expression is nested within an :class:`Or` or :class:`MatchFirst`; maintained for compatibility, but setting to ``False`` no longer restores pre-2.3.1 behavior """ _type_desc = "compatibility" collect_all_And_tokens = True _all_names = [__ for __ in locals() if not __.startswith("_")] _fixed_names = """ collect_all_And_tokens """.split() class __diag__(__config_flags): _type_desc = "diagnostic" warn_multiple_tokens_in_named_alternation = False warn_ungrouped_named_tokens_in_collection = False warn_name_set_on_empty_Forward = False warn_on_parse_using_empty_Forward = False warn_on_assignment_to_Forward = False warn_on_multiple_string_args_to_oneof = False warn_on_match_first_with_lshift_operator = False enable_debug_on_named_expressions = False _all_names = [__ for __ in locals() if not __.startswith("_")] _warning_names = [name for name in _all_names if name.startswith("warn")] _debug_names = [name for name in _all_names if name.startswith("enable_debug")] @classmethod def enable_all_warnings(cls) -> None: for name in cls._warning_names: cls.enable(name) class Diagnostics(Enum): """ Diagnostic configuration (all default to disabled) - ``warn_multiple_tokens_in_named_alternation`` - flag to enable warnings when a results name is defined on a :class:`MatchFirst` or :class:`Or` expression with one or more :class:`And` subexpressions - ``warn_ungrouped_named_tokens_in_collection`` - flag to enable warnings when a results name is defined on a containing expression with ungrouped subexpressions that also have results names - ``warn_name_set_on_empty_Forward`` - flag to enable warnings when a :class:`Forward` is defined with a results name, but has no contents defined - ``warn_on_parse_using_empty_Forward`` - flag to enable warnings when a :class:`Forward` is defined in a grammar but has never had an expression attached to it - ``warn_on_assignment_to_Forward`` - flag to enable warnings when a :class:`Forward` is defined but is overwritten by assigning using ``'='`` instead of ``'<<='`` or ``'<<'`` - ``warn_on_multiple_string_args_to_oneof`` - flag to enable warnings when :class:`one_of` is incorrectly called with multiple str arguments - ``enable_debug_on_named_expressions`` - flag to auto-enable debug on all subsequent calls to :class:`ParserElement.set_name` Diagnostics are enabled/disabled by calling :class:`enable_diag` and :class:`disable_diag`. All warnings can be enabled by calling :class:`enable_all_warnings`. """ warn_multiple_tokens_in_named_alternation = 0 warn_ungrouped_named_tokens_in_collection = 1 warn_name_set_on_empty_Forward = 2 warn_on_parse_using_empty_Forward = 3 warn_on_assignment_to_Forward = 4 warn_on_multiple_string_args_to_oneof = 5 warn_on_match_first_with_lshift_operator = 6 enable_debug_on_named_expressions = 7 def enable_diag(diag_enum: Diagnostics) -> None: """ Enable a global pyparsing diagnostic flag (see :class:`Diagnostics`). """ __diag__.enable(diag_enum.name) def disable_diag(diag_enum: Diagnostics) -> None: """ Disable a global pyparsing diagnostic flag (see :class:`Diagnostics`). """ __diag__.disable(diag_enum.name) def enable_all_warnings() -> None: """ Enable all global pyparsing diagnostic warnings (see :class:`Diagnostics`). """ __diag__.enable_all_warnings() # hide abstract class del __config_flags def _should_enable_warnings( cmd_line_warn_options: typing.Iterable[str], warn_env_var: typing.Optional[str] ) -> bool: enable = bool(warn_env_var) for warn_opt in cmd_line_warn_options: w_action, w_message, w_category, w_module, w_line = (warn_opt + "::::").split( ":" )[:5] if not w_action.lower().startswith("i") and ( not (w_message or w_category or w_module) or w_module == "pyparsing" ): enable = True elif w_action.lower().startswith("i") and w_module in ("pyparsing", ""): enable = False return enable if _should_enable_warnings( sys.warnoptions, os.environ.get("PYPARSINGENABLEALLWARNINGS") ): enable_all_warnings() # build list of single arg builtins, that can be used as parse actions # fmt: off _single_arg_builtins = { sum, len, sorted, reversed, list, tuple, set, any, all, min, max } # fmt: on _generatorType = types.GeneratorType ParseImplReturnType = tuple[int, Any] PostParseReturnType = Union[ParseResults, Sequence[ParseResults]] ParseCondition = Union[ Callable[[], bool], Callable[[ParseResults], bool], Callable[[int, ParseResults], bool], Callable[[str, int, ParseResults], bool], ] ParseFailAction = Callable[[str, int, "ParserElement", Exception], None] DebugStartAction = Callable[[str, int, "ParserElement", bool], None] DebugSuccessAction = Callable[ [str, int, int, "ParserElement", ParseResults, bool], None ] DebugExceptionAction = Callable[[str, int, "ParserElement", Exception, bool], None] alphas: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" identchars: str = pyparsing_unicode.Latin1.identchars identbodychars: str = pyparsing_unicode.Latin1.identbodychars nums: str = "0123456789" hexnums: str = "0123456789ABCDEFabcdef" alphanums: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" printables: str = ( '!"' "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ" "[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" ) class _ParseActionIndexError(Exception): """ Internal wrapper around IndexError so that IndexErrors raised inside parse actions aren't misinterpreted as IndexErrors raised inside ParserElement parseImpl methods. """ def __init__(self, msg: str, exc: BaseException) -> None: self.msg: str = msg self.exc: BaseException = exc _trim_arity_call_line: traceback.StackSummary = None # type: ignore[assignment] pa_call_line_synth = () def _trim_arity(func, max_limit=3): """decorator to trim function calls to match the arity of the target""" global _trim_arity_call_line, pa_call_line_synth if func in _single_arg_builtins: return lambda s, l, t: func(t) limit = 0 found_arity = False # synthesize what would be returned by traceback.extract_stack at the call to # user's parse action 'func', so that we don't incur call penalty at parse time # fmt: off LINE_DIFF = 9 # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! _trim_arity_call_line = _trim_arity_call_line or traceback.extract_stack(limit=2)[-1] pa_call_line_synth = pa_call_line_synth or (_trim_arity_call_line[0], _trim_arity_call_line[1] + LINE_DIFF) def wrapper(*args): nonlocal found_arity, limit if found_arity: return func(*args[limit:]) while 1: try: ret = func(*args[limit:]) found_arity = True return ret except TypeError as te: # re-raise TypeErrors if they did not come from our arity testing if found_arity: raise else: tb = te.__traceback__ frames = traceback.extract_tb(tb, limit=2) frame_summary = frames[-1] trim_arity_type_error = ( [frame_summary[:2]][-1][:2] == pa_call_line_synth ) del tb if trim_arity_type_error: if limit < max_limit: limit += 1 continue raise except IndexError as ie: # wrap IndexErrors inside a _ParseActionIndexError raise _ParseActionIndexError( "IndexError raised in parse action", ie ).with_traceback(None) # fmt: on # copy func name to wrapper for sensible debug output # (can't use functools.wraps, since that messes with function signature) func_name = getattr(func, "__name__", getattr(func, "__class__").__name__) wrapper.__name__ = func_name wrapper.__doc__ = func.__doc__ return wrapper def condition_as_parse_action( fn: ParseCondition, message: typing.Optional[str] = None, fatal: bool = False ) -> ParseAction: """ Function to convert a simple predicate function that returns ``True`` or ``False`` into a parse action. Can be used in places when a parse action is required and :meth:`ParserElement.add_condition` cannot be used (such as when adding a condition to an operator level in :class:`infix_notation`). Optional keyword arguments: :param message: define a custom message to be used in the raised exception :param fatal: if ``True``, will raise :class:`ParseFatalException` to stop parsing immediately; otherwise will raise :class:`ParseException` """ msg = message if message is not None else "failed user-defined condition" exc_type = ParseFatalException if fatal else ParseException fn = _trim_arity(fn) @wraps(fn) def pa(s, l, t): if not bool(fn(s, l, t)): raise exc_type(s, l, msg) return pa def _default_start_debug_action( instring: str, loc: int, expr: ParserElement, cache_hit: bool = False ): cache_hit_str = "*" if cache_hit else "" print( ( f"{cache_hit_str}Match {expr} at loc {loc}({lineno(loc, instring)},{col(loc, instring)})\n" f" {line(loc, instring)}\n" f" {'^':>{col(loc, instring)}}" ) ) def _default_success_debug_action( instring: str, startloc: int, endloc: int, expr: ParserElement, toks: ParseResults, cache_hit: bool = False, ): cache_hit_str = "*" if cache_hit else "" print(f"{cache_hit_str}Matched {expr} -> {toks.as_list()}") def _default_exception_debug_action( instring: str, loc: int, expr: ParserElement, exc: Exception, cache_hit: bool = False, ): cache_hit_str = "*" if cache_hit else "" print(f"{cache_hit_str}Match {expr} failed, {type(exc).__name__} raised: {exc}") def null_debug_action(*args): """'Do-nothing' debug action, to suppress debugging output during parsing.""" class ParserElement(ABC): """Abstract base level parser element class.""" DEFAULT_WHITE_CHARS: str = " \n\t\r" verbose_stacktrace: bool = False _literalStringClass: type = None # type: ignore[assignment] @staticmethod def set_default_whitespace_chars(chars: str) -> None: r""" Overrides the default whitespace chars Example: .. doctest:: # default whitespace chars are space, and newline >>> Word(alphas)[1, ...].parse_string("abc def\nghi jkl") ParseResults(['abc', 'def', 'ghi', 'jkl'], {}) # change to just treat newline as significant >>> ParserElement.set_default_whitespace_chars(" \t") >>> Word(alphas)[1, ...].parse_string("abc def\nghi jkl") ParseResults(['abc', 'def'], {}) # Reset to default >>> ParserElement.set_default_whitespace_chars(" \n\t\r") """ ParserElement.DEFAULT_WHITE_CHARS = chars # update whitespace all parse expressions defined in this module for expr in _builtin_exprs: if expr.copyDefaultWhiteChars: expr.whiteChars = set(chars) @staticmethod def inline_literals_using(cls: type) -> None: """ Set class to be used for inclusion of string literals into a parser. Example: .. doctest:: :options: +NORMALIZE_WHITESPACE # default literal class used is Literal >>> integer = Word(nums) >>> date_str = ( ... integer("year") + '/' ... + integer("month") + '/' ... + integer("day") ... ) >>> date_str.parse_string("1999/12/31") ParseResults(['1999', '/', '12', '/', '31'], {'year': '1999', 'month': '12', 'day': '31'}) # change to Suppress >>> ParserElement.inline_literals_using(Suppress) >>> date_str = ( ... integer("year") + '/' ... + integer("month") + '/' ... + integer("day") ... ) >>> date_str.parse_string("1999/12/31") ParseResults(['1999', '12', '31'], {'year': '1999', 'month': '12', 'day': '31'}) # Reset >>> ParserElement.inline_literals_using(Literal) """ ParserElement._literalStringClass = cls @classmethod def using_each(cls, seq, **class_kwargs): """ Yields a sequence of ``class(obj, **class_kwargs)`` for obj in seq. Example: .. testcode:: LPAR, RPAR, LBRACE, RBRACE, SEMI = Suppress.using_each("(){};") .. versionadded:: 3.1.0 """ yield from (cls(obj, **class_kwargs) for obj in seq) class DebugActions(NamedTuple): debug_try: typing.Optional[DebugStartAction] debug_match: typing.Optional[DebugSuccessAction] debug_fail: typing.Optional[DebugExceptionAction] def __init__(self, savelist: bool = False) -> None: self.parseAction: list[ParseAction] = list() self.failAction: typing.Optional[ParseFailAction] = None self.customName: str = None # type: ignore[assignment] self._defaultName: typing.Optional[str] = None self.resultsName: str = None # type: ignore[assignment] self.saveAsList: bool = savelist self.skipWhitespace: bool = True self.whiteChars: set[str] = set(ParserElement.DEFAULT_WHITE_CHARS) self.copyDefaultWhiteChars: bool = True # used when checking for left-recursion self._may_return_empty: bool = False self.keepTabs: bool = False self.ignoreExprs: list[ParserElement] = list() self.debug: bool = False self.streamlined: bool = False # optimize exception handling for subclasses that don't advance parse index self.mayIndexError: bool = True self.errmsg: Union[str, None] = "" # mark results names as modal (report only last) or cumulative (list all) self.modalResults: bool = True # custom debug actions self.debugActions = self.DebugActions(None, None, None) # avoid redundant calls to preParse self.callPreparse: bool = True self.callDuringTry: bool = False self.suppress_warnings_: list[Diagnostics] = [] self.show_in_diagram: bool = True @property def mayReturnEmpty(self) -> bool: """ .. deprecated:: 3.3.0 use _may_return_empty instead. """ return self._may_return_empty @mayReturnEmpty.setter def mayReturnEmpty(self, value) -> None: """ .. deprecated:: 3.3.0 use _may_return_empty instead. """ self._may_return_empty = value def suppress_warning(self, warning_type: Diagnostics) -> ParserElement: """ Suppress warnings emitted for a particular diagnostic on this expression. Example: .. doctest:: >>> label = pp.Word(pp.alphas) # Normally using an empty Forward in a grammar # would print a warning, but we can suppress that >>> base = pp.Forward().suppress_warning( ... pp.Diagnostics.warn_on_parse_using_empty_Forward) >>> grammar = base | label >>> print(grammar.parse_string("x")) ['x'] """ self.suppress_warnings_.append(warning_type) return self def visit_all(self): """General-purpose method to yield all expressions and sub-expressions in a grammar. Typically just for internal use. """ to_visit = deque([self]) seen = set() while to_visit: cur = to_visit.popleft() # guard against looping forever through recursive grammars if cur in seen: continue seen.add(cur) to_visit.extend(cur.recurse()) yield cur def copy(self) -> ParserElement: """ Make a copy of this :class:`ParserElement`. Useful for defining different parse actions for the same parsing pattern, using copies of the original parse element. Example: .. testcode:: integer = Word(nums).set_parse_action( lambda toks: int(toks[0])) integerK = integer.copy().add_parse_action( lambda toks: toks[0] * 1024) + Suppress("K") integerM = integer.copy().add_parse_action( lambda toks: toks[0] * 1024 * 1024) + Suppress("M") print( (integerK | integerM | integer)[1, ...].parse_string( "5K 100 640K 256M") ) prints: .. testoutput:: [5120, 100, 655360, 268435456] Equivalent form of ``expr.copy()`` is just ``expr()``: .. testcode:: integerM = integer().add_parse_action( lambda toks: toks[0] * 1024 * 1024) + Suppress("M") """ cpy = copy.copy(self) cpy.parseAction = self.parseAction[:] cpy.ignoreExprs = self.ignoreExprs[:] if self.copyDefaultWhiteChars: cpy.whiteChars = set(ParserElement.DEFAULT_WHITE_CHARS) return cpy def set_results_name( self, name: str, list_all_matches: bool = False, **kwargs ) -> ParserElement: """ Define name for referencing matching tokens as a nested attribute of the returned parse results. Normally, results names are assigned as you would assign keys in a dict: any existing value is overwritten by later values. If it is necessary to keep all values captured for a particular results name, call ``set_results_name`` with ``list_all_matches`` = True. NOTE: ``set_results_name`` returns a *copy* of the original :class:`ParserElement` object; this is so that the client can define a basic element, such as an integer, and reference it in multiple places with different names. You can also set results names using the abbreviated syntax, ``expr("name")`` in place of ``expr.set_results_name("name")`` - see :meth:`__call__`. If ``list_all_matches`` is required, use ``expr("name*")``. Example: .. testcode:: integer = Word(nums) date_str = (integer.set_results_name("year") + '/' + integer.set_results_name("month") + '/' + integer.set_results_name("day")) # equivalent form: date_str = integer("year") + '/' + integer("month") + '/' + integer("day") """ listAllMatches: bool = deprecate_argument(kwargs, "listAllMatches", False) list_all_matches = listAllMatches or list_all_matches return self._setResultsName(name, list_all_matches) def _setResultsName(self, name, list_all_matches=False) -> ParserElement: if name is None: return self newself = self.copy() if name.endswith("*"): name = name[:-1] list_all_matches = True newself.resultsName = name newself.modalResults = not list_all_matches return newself def set_break(self, break_flag: bool = True) -> ParserElement: """ Method to invoke the Python pdb debugger when this element is about to be parsed. Set ``break_flag`` to ``True`` to enable, ``False`` to disable. """ if break_flag: _parseMethod = self._parse def breaker(instring, loc, do_actions=True, callPreParse=True): # this call to breakpoint() is intentional, not a checkin error breakpoint() return _parseMethod(instring, loc, do_actions, callPreParse) breaker._originalParseMethod = _parseMethod # type: ignore [attr-defined] self._parse = breaker # type: ignore [method-assign] elif hasattr(self._parse, "_originalParseMethod"): self._parse = self._parse._originalParseMethod # type: ignore [method-assign] return self def set_parse_action( self, *fns: ParseAction, call_during_try: bool = False, **kwargs: Any ) -> ParserElement: """ Define one or more actions to perform when successfully matching parse element definition. Parse actions can be called to perform data conversions, do extra validation, update external data structures, or enhance or replace the parsed tokens. Each parse action ``fn`` is a callable method with 0-3 arguments, called as ``fn(s, loc, toks)`` , ``fn(loc, toks)`` , ``fn(toks)`` , or just ``fn()`` , where: - ``s`` = the original string being parsed (see note below) - ``loc`` = the location of the matching substring - ``toks`` = a list of the matched tokens, packaged as a :class:`ParseResults` object The parsed tokens are passed to the parse action as ParseResults. They can be modified in place using list-style append, extend, and pop operations to update the parsed list elements; and with dictionary-style item set and del operations to add, update, or remove any named results. If the tokens are modified in place, it is not necessary to return them with a return statement. Parse actions can also completely replace the given tokens, with another ``ParseResults`` object, or with some entirely different object (common for parse actions that perform data conversions). A convenient way to build a new parse result is to define the values using a dict, and then create the return value using :class:`ParseResults.from_dict`. If None is passed as the ``fn`` parse action, all previously added parse actions for this expression are cleared. Optional keyword arguments: :param call_during_try: (default= ``False``) indicate if parse action should be run during lookaheads and alternate testing. For parse actions that have side effects, it is important to only call the parse action once it is determined that it is being called as part of a successful parse. For parse actions that perform additional validation, then ``call_during_try`` should be passed as True, so that the validation code is included in the preliminary "try" parses. .. Note:: The default parsing behavior is to expand tabs in the input string before starting the parsing process. See :meth:`parse_string` for more information on parsing strings containing ```` s, and suggested methods to maintain a consistent view of the parsed string, the parse location, and line and column positions within the parsed string. Example: Parse dates in the form ``YYYY/MM/DD`` ----------------------------------------------- Setup code: .. testcode:: def convert_to_int(toks): '''a parse action to convert toks from str to int at parse time''' return int(toks[0]) def is_valid_date(instring, loc, toks): '''a parse action to verify that the date is a valid date''' from datetime import date year, month, day = toks[::2] try: date(year, month, day) except ValueError: raise ParseException(instring, loc, "invalid date given") integer = Word(nums) date_str = integer + '/' + integer + '/' + integer # add parse actions integer.set_parse_action(convert_to_int) date_str.set_parse_action(is_valid_date) Successful parse - note that integer fields are converted to ints: .. testcode:: print(date_str.parse_string("1999/12/31")) prints: .. testoutput:: [1999, '/', 12, '/', 31] Failure - invalid date: .. testcode:: date_str.parse_string("1999/13/31") prints: .. testoutput:: Traceback (most recent call last): ParseException: invalid date given, found '1999' ... """ callDuringTry: bool = deprecate_argument(kwargs, "callDuringTry", False) if list(fns) == [None]: self.parseAction.clear() return self if not all(callable(fn) for fn in fns): raise TypeError("parse actions must be callable") self.parseAction[:] = [_trim_arity(fn) for fn in fns] self.callDuringTry = self.callDuringTry or call_during_try or callDuringTry return self def add_parse_action( self, *fns: ParseAction, call_during_try: bool = False, **kwargs: Any ) -> ParserElement: """ Add one or more parse actions to expression's list of parse actions. See :class:`set_parse_action`. See examples in :class:`copy`. """ callDuringTry: bool = deprecate_argument(kwargs, "callDuringTry", False) self.parseAction += [_trim_arity(fn) for fn in fns] self.callDuringTry = self.callDuringTry or callDuringTry or call_during_try return self def add_condition( self, *fns: ParseCondition, call_during_try: bool = False, **kwargs: Any ) -> ParserElement: """Add a boolean predicate function to expression's list of parse actions. See :class:`set_parse_action` for function call signatures. Unlike ``set_parse_action``, functions passed to ``add_condition`` need to return boolean success/fail of the condition. Optional keyword arguments: - ``message`` = define a custom message to be used in the raised exception - ``fatal`` = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException - ``call_during_try`` = boolean to indicate if this method should be called during internal tryParse calls, default=False Example: .. doctest:: :options: +NORMALIZE_WHITESPACE >>> integer = Word(nums).set_parse_action(lambda toks: int(toks[0])) >>> year_int = integer.copy().add_condition( ... lambda toks: toks[0] >= 2000, ... message="Only support years 2000 and later") >>> date_str = year_int + '/' + integer + '/' + integer >>> result = date_str.parse_string("1999/12/31") Traceback (most recent call last): ParseException: Only support years 2000 and later... """ callDuringTry: bool = deprecate_argument(kwargs, "callDuringTry", False) for fn in fns: self.parseAction.append( condition_as_parse_action( fn, message=str(kwargs.get("message")), fatal=bool(kwargs.get("fatal", False)), ) ) self.callDuringTry = self.callDuringTry or call_during_try or callDuringTry return self def set_fail_action(self, fn: ParseFailAction) -> ParserElement: """ Define action to perform if parsing fails at this expression. Fail acton fn is a callable function that takes the arguments ``fn(s, loc, expr, err)`` where: - ``s`` = string being parsed - ``loc`` = location where expression match was attempted and failed - ``expr`` = the parse expression that failed - ``err`` = the exception thrown The function returns no value. It may throw :class:`ParseFatalException` if it is desired to stop parsing immediately.""" self.failAction = fn return self def _skipIgnorables(self, instring: str, loc: int) -> int: if not self.ignoreExprs: return loc exprsFound = True ignore_expr_fns = [e._parse for e in self.ignoreExprs] last_loc = loc while exprsFound: exprsFound = False for ignore_fn in ignore_expr_fns: try: while 1: loc, dummy = ignore_fn(instring, loc) exprsFound = True except ParseException: pass # check if all ignore exprs matched but didn't actually advance the parse location if loc == last_loc: break last_loc = loc return loc def preParse(self, instring: str, loc: int) -> int: if self.ignoreExprs: loc = self._skipIgnorables(instring, loc) if self.skipWhitespace: instrlen = len(instring) white_chars = self.whiteChars while loc < instrlen and instring[loc] in white_chars: loc += 1 return loc def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: return loc, [] def postParse(self, instring, loc, tokenlist): return tokenlist # @profile def _parseNoCache( self, instring, loc, do_actions=True, callPreParse=True ) -> tuple[int, ParseResults]: debugging = self.debug # and do_actions) len_instring = len(instring) if debugging or self.failAction: # print("Match {} at loc {}({}, {})".format(self, loc, lineno(loc, instring), col(loc, instring))) try: if callPreParse and self.callPreparse: pre_loc = self.preParse(instring, loc) else: pre_loc = loc tokens_start = pre_loc if self.debugActions.debug_try: self.debugActions.debug_try(instring, tokens_start, self, False) if self.mayIndexError or pre_loc >= len_instring: try: loc, tokens = self.parseImpl(instring, pre_loc, do_actions) except IndexError: raise ParseException(instring, len_instring, self.errmsg, self) else: loc, tokens = self.parseImpl(instring, pre_loc, do_actions) except Exception as err: # print("Exception raised:", err) if self.debugActions.debug_fail: self.debugActions.debug_fail( instring, tokens_start, self, err, False ) if self.failAction: self.failAction(instring, tokens_start, self, err) raise else: if callPreParse and self.callPreparse: pre_loc = self.preParse(instring, loc) else: pre_loc = loc tokens_start = pre_loc if self.mayIndexError or pre_loc >= len_instring: try: loc, tokens = self.parseImpl(instring, pre_loc, do_actions) except IndexError: raise ParseException(instring, len_instring, self.errmsg, self) else: loc, tokens = self.parseImpl(instring, pre_loc, do_actions) tokens = self.postParse(instring, loc, tokens) ret_tokens = ParseResults( tokens, self.resultsName, aslist=self.saveAsList, modal=self.modalResults ) if self.parseAction and (do_actions or self.callDuringTry): if debugging: try: for fn in self.parseAction: try: tokens = fn(instring, tokens_start, ret_tokens) # type: ignore [call-arg, arg-type] except IndexError as parse_action_exc: exc = ParseException("exception raised in parse action") raise exc from parse_action_exc if tokens is not None and tokens is not ret_tokens: ret_tokens = ParseResults( tokens, self.resultsName, aslist=self.saveAsList and isinstance(tokens, (ParseResults, list)), modal=self.modalResults, ) except Exception as err: # print "Exception raised in user parse action:", err if self.debugActions.debug_fail: self.debugActions.debug_fail( instring, tokens_start, self, err, False ) raise else: for fn in self.parseAction: try: tokens = fn(instring, tokens_start, ret_tokens) # type: ignore [call-arg, arg-type] except IndexError as parse_action_exc: exc = ParseException("exception raised in parse action") raise exc from parse_action_exc if tokens is not None and tokens is not ret_tokens: ret_tokens = ParseResults( tokens, self.resultsName, aslist=self.saveAsList and isinstance(tokens, (ParseResults, list)), modal=self.modalResults, ) if debugging: # print("Matched", self, "->", ret_tokens.as_list()) if self.debugActions.debug_match: self.debugActions.debug_match( instring, tokens_start, loc, self, ret_tokens, False ) return loc, ret_tokens def try_parse( self, instring: str, loc: int, *, raise_fatal: bool = False, do_actions: bool = False, ) -> int: try: return self._parse(instring, loc, do_actions=do_actions)[0] except ParseFatalException: if raise_fatal: raise raise ParseException(instring, loc, self.errmsg, self) def can_parse_next(self, instring: str, loc: int, do_actions: bool = False) -> bool: try: self.try_parse(instring, loc, do_actions=do_actions) except (ParseException, IndexError): return False else: return True # cache for left-recursion in Forward references recursion_lock = RLock() recursion_memos: collections.abc.MutableMapping[ tuple[int, Forward, bool], tuple[int, Union[ParseResults, Exception]] ] = {} class _CacheType(typing.Protocol): """ Class to be used for packrat and left-recursion cacheing of results and exceptions. """ not_in_cache: bool def get(self, *args) -> typing.Any: ... def set(self, *args) -> None: ... def clear(self) -> None: ... class NullCache(dict): """ A null cache type for initialization of the packrat_cache class variable. If/when enable_packrat() is called, this null cache will be replaced by a proper _CacheType class instance. """ not_in_cache: bool = True def get(self, *args) -> typing.Any: ... def set(self, *args) -> None: ... def clear(self) -> None: ... # class-level argument cache for optimizing repeated calls when backtracking # through recursive expressions packrat_cache: _CacheType = NullCache() packrat_cache_lock = RLock() packrat_cache_stats = [0, 0] # this method gets repeatedly called during backtracking with the same arguments - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression def _parseCache( self, instring, loc, do_actions=True, callPreParse=True ) -> tuple[int, ParseResults]: HIT, MISS = 0, 1 lookup = (self, instring, loc, callPreParse, do_actions) with ParserElement.packrat_cache_lock: cache = ParserElement.packrat_cache value = cache.get(lookup) if value is cache.not_in_cache: ParserElement.packrat_cache_stats[MISS] += 1 try: value = self._parseNoCache(instring, loc, do_actions, callPreParse) except ParseBaseException as pe: # cache a copy of the exception, without the traceback cache.set(lookup, pe.__class__(*pe.args)) raise else: cache.set(lookup, (value[0], value[1].copy(), loc)) return value else: ParserElement.packrat_cache_stats[HIT] += 1 if self.debug and self.debugActions.debug_try: try: self.debugActions.debug_try(instring, loc, self, cache_hit=True) # type: ignore [call-arg] except TypeError: pass if isinstance(value, Exception): if self.debug and self.debugActions.debug_fail: try: self.debugActions.debug_fail( instring, loc, self, value, cache_hit=True # type: ignore [call-arg] ) except TypeError: pass raise value value = cast(tuple[int, ParseResults, int], value) loc_, result, endloc = value[0], value[1].copy(), value[2] if self.debug and self.debugActions.debug_match: try: self.debugActions.debug_match( instring, loc_, endloc, self, result, cache_hit=True # type: ignore [call-arg] ) except TypeError: pass return loc_, result _parse = _parseNoCache @staticmethod def reset_cache() -> None: """ Clears caches used by packrat and left-recursion. """ with ParserElement.packrat_cache_lock: ParserElement.packrat_cache.clear() ParserElement.packrat_cache_stats[:] = [0] * len( ParserElement.packrat_cache_stats ) ParserElement.recursion_memos.clear() # class attributes to keep caching status _packratEnabled = False _left_recursion_enabled = False @staticmethod def disable_memoization() -> None: """ Disables active Packrat or Left Recursion parsing and their memoization This method also works if neither Packrat nor Left Recursion are enabled. This makes it safe to call before activating Packrat nor Left Recursion to clear any previous settings. """ with ParserElement.packrat_cache_lock: ParserElement.reset_cache() ParserElement._left_recursion_enabled = False ParserElement._packratEnabled = False ParserElement._parse = ParserElement._parseNoCache @staticmethod def enable_left_recursion( cache_size_limit: typing.Optional[int] = None, *, force=False ) -> None: """ Enables "bounded recursion" parsing, which allows for both direct and indirect left-recursion. During parsing, left-recursive :class:`Forward` elements are repeatedly matched with a fixed recursion depth that is gradually increased until finding the longest match. Example: .. testcode:: import pyparsing as pp pp.ParserElement.enable_left_recursion() E = pp.Forward("E") num = pp.Word(pp.nums) # match `num`, or `num '+' num`, or `num '+' num '+' num`, ... E <<= E + '+' - num | num print(E.parse_string("1+2+3+4")) prints: .. testoutput:: ['1', '+', '2', '+', '3', '+', '4'] Recursion search naturally memoizes matches of ``Forward`` elements and may thus skip reevaluation of parse actions during backtracking. This may break programs with parse actions which rely on strict ordering of side-effects. Parameters: - ``cache_size_limit`` - (default=``None``) - memoize at most this many ``Forward`` elements during matching; if ``None`` (the default), memoize all ``Forward`` elements. Bounded Recursion parsing works similar but not identical to Packrat parsing, thus the two cannot be used together. Use ``force=True`` to disable any previous, conflicting settings. """ with ParserElement.packrat_cache_lock: if force: ParserElement.disable_memoization() elif ParserElement._packratEnabled: raise RuntimeError("Packrat and Bounded Recursion are not compatible") if cache_size_limit is None: ParserElement.recursion_memos = _UnboundedMemo() elif cache_size_limit > 0: ParserElement.recursion_memos = _LRUMemo(capacity=cache_size_limit) # type: ignore[assignment] else: raise NotImplementedError(f"Memo size of {cache_size_limit}") ParserElement._left_recursion_enabled = True @staticmethod def enable_packrat( cache_size_limit: Union[int, None] = 128, *, force: bool = False ) -> None: """ Enables "packrat" parsing, which adds memoizing to the parsing logic. Repeated parse attempts at the same string location (which happens often in many complex grammars) can immediately return a cached value, instead of re-executing parsing/validating code. Memoizing is done of both valid results and parsing exceptions. Parameters: - ``cache_size_limit`` - (default= ``128``) - if an integer value is provided will limit the size of the packrat cache; if None is passed, then the cache size will be unbounded; if 0 is passed, the cache will be effectively disabled. This speedup may break existing programs that use parse actions that have side-effects. For this reason, packrat parsing is disabled when you first import pyparsing. To activate the packrat feature, your program must call the class method :class:`ParserElement.enable_packrat`. For best results, call ``enable_packrat()`` immediately after importing pyparsing. .. Can't really be doctested, alas Example:: import pyparsing pyparsing.ParserElement.enable_packrat() Packrat parsing works similar but not identical to Bounded Recursion parsing, thus the two cannot be used together. Use ``force=True`` to disable any previous, conflicting settings. """ with ParserElement.packrat_cache_lock: if force: ParserElement.disable_memoization() elif ParserElement._left_recursion_enabled: raise RuntimeError("Packrat and Bounded Recursion are not compatible") if ParserElement._packratEnabled: return ParserElement._packratEnabled = True if cache_size_limit is None: ParserElement.packrat_cache = _UnboundedCache() else: ParserElement.packrat_cache = _FifoCache(cache_size_limit) ParserElement._parse = ParserElement._parseCache def parse_string( self, instring: str, parse_all: bool = False, **kwargs ) -> ParseResults: """ Parse a string with respect to the parser definition. This function is intended as the primary interface to the client code. :param instring: The input string to be parsed. :param parse_all: If set, the entire input string must match the grammar. :param parseAll: retained for pre-PEP8 compatibility, will be removed in a future release. :raises ParseException: Raised if ``parse_all`` is set and the input string does not match the whole grammar. :returns: the parsed data as a :class:`ParseResults` object, which may be accessed as a `list`, a `dict`, or an object with attributes if the given parser includes results names. If the input string is required to match the entire grammar, ``parse_all`` flag must be set to ``True``. This is also equivalent to ending the grammar with :class:`StringEnd`\\ (). To report proper column numbers, ``parse_string`` operates on a copy of the input string where all tabs are converted to spaces (8 spaces per tab, as per the default in ``string.expandtabs``). If the input string contains tabs and the grammar uses parse actions that use the ``loc`` argument to index into the string being parsed, one can ensure a consistent view of the input string by doing one of the following: - calling ``parse_with_tabs`` on your grammar before calling ``parse_string`` (see :class:`parse_with_tabs`), - define your parse action using the full ``(s,loc,toks)`` signature, and reference the input string using the parse action's ``s`` argument, or - explicitly expand the tabs in your input string before calling ``parse_string``. Examples: By default, partial matches are OK. .. doctest:: >>> res = Word('a').parse_string('aaaaabaaa') >>> print(res) ['aaaaa'] The parsing behavior varies by the inheriting class of this abstract class. Please refer to the children directly to see more examples. It raises an exception if parse_all flag is set and instring does not match the whole grammar. .. doctest:: >>> res = Word('a').parse_string('aaaaabaaa', parse_all=True) Traceback (most recent call last): ParseException: Expected end of text, found 'b' ... """ parseAll: bool = deprecate_argument(kwargs, "parseAll", False) parse_all = parse_all or parseAll ParserElement.reset_cache() if not self.streamlined: self.streamline() for e in self.ignoreExprs: e.streamline() if not self.keepTabs: instring = instring.expandtabs() try: loc, tokens = self._parse(instring, 0) if parse_all: loc = self.preParse(instring, loc) se = Empty() + StringEnd().set_debug(False) se._parse(instring, loc) except _ParseActionIndexError as pa_exc: raise pa_exc.exc except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise # catch and re-raise exception from here, clearing out pyparsing internal stack trace raise exc.with_traceback(None) else: return tokens def scan_string( self, instring: str, max_matches: int = _MAX_INT, overlap: bool = False, always_skip_whitespace=True, *, debug: bool = False, **kwargs, ) -> Generator[tuple[ParseResults, int, int], None, None]: """ Scan the input string for expression matches. Each match will return the matching tokens, start location, and end location. May be called with optional ``max_matches`` argument, to clip scanning after 'n' matches are found. If ``overlap`` is specified, then overlapping matches will be reported. Note that the start and end locations are reported relative to the string being parsed. See :class:`parse_string` for more information on parsing strings with embedded tabs. Example: .. testcode:: source = "sldjf123lsdjjkf345sldkjf879lkjsfd987" print(source) for tokens, start, end in Word(alphas).scan_string(source): print(' '*start + '^'*(end-start)) print(' '*start + tokens[0]) prints: .. testoutput:: sldjf123lsdjjkf345sldkjf879lkjsfd987 ^^^^^ sldjf ^^^^^^^ lsdjjkf ^^^^^^ sldkjf ^^^^^^ lkjsfd """ maxMatches: int = deprecate_argument(kwargs, "maxMatches", _MAX_INT) max_matches = min(maxMatches, max_matches) if not self.streamlined: self.streamline() for e in self.ignoreExprs: e.streamline() if not self.keepTabs: instring = str(instring).expandtabs() instrlen = len(instring) loc = 0 if always_skip_whitespace: preparser = Empty() preparser.ignoreExprs = self.ignoreExprs preparser.whiteChars = self.whiteChars preparseFn = preparser.preParse else: preparseFn = self.preParse parseFn = self._parse ParserElement.reset_cache() matches = 0 try: while loc <= instrlen and matches < max_matches: try: preloc: int = preparseFn(instring, loc) nextLoc: int tokens: ParseResults nextLoc, tokens = parseFn(instring, preloc, callPreParse=False) except ParseException: loc = preloc + 1 else: if nextLoc > loc: matches += 1 if debug: print( { "tokens": tokens.as_list(), "start": preloc, "end": nextLoc, } ) yield tokens, preloc, nextLoc if overlap: nextloc = preparseFn(instring, loc) if nextloc > loc: loc = nextLoc else: loc += 1 else: loc = nextLoc else: loc = preloc + 1 except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise # catch and re-raise exception from here, clears out pyparsing internal stack trace raise exc.with_traceback(None) def transform_string(self, instring: str, *, debug: bool = False) -> str: """ Extension to :class:`scan_string`, to modify matching text with modified tokens that may be returned from a parse action. To use ``transform_string``, define a grammar and attach a parse action to it that modifies the returned token list. Invoking ``transform_string()`` on a target string will then scan for matches, and replace the matched text patterns according to the logic in the parse action. ``transform_string()`` returns the resulting transformed string. Example: .. testcode:: quote = '''now is the winter of our discontent, made glorious summer by this sun of york.''' wd = Word(alphas) wd.set_parse_action(lambda toks: toks[0].title()) print(wd.transform_string(quote)) prints: .. testoutput:: Now Is The Winter Of Our Discontent, Made Glorious Summer By This Sun Of York. """ out: list[str] = [] lastE = 0 # force preservation of s, to minimize unwanted transformation of string, and to # keep string locs straight between transform_string and scan_string self.keepTabs = True try: for t, s, e in self.scan_string(instring, debug=debug): if s > lastE: out.append(instring[lastE:s]) lastE = e if not t: continue if isinstance(t, ParseResults): out += t.as_list() elif isinstance(t, Iterable) and not isinstance(t, str_type): out.extend(t) else: out.append(t) out.append(instring[lastE:]) out = [o for o in out if o] return "".join([str(s) for s in _flatten(out)]) except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise # catch and re-raise exception from here, clears out pyparsing internal stack trace raise exc.with_traceback(None) def search_string( self, instring: str, max_matches: int = _MAX_INT, *, debug: bool = False, **kwargs, ) -> ParseResults: """ Another extension to :class:`scan_string`, simplifying the access to the tokens found to match the given parse expression. May be called with optional ``max_matches`` argument, to clip searching after 'n' matches are found. Example: .. testcode:: quote = '''More than Iron, more than Lead, more than Gold I need Electricity''' # a capitalized word starts with an uppercase letter, # followed by zero or more lowercase letters cap_word = Word(alphas.upper(), alphas.lower()) print(cap_word.search_string(quote)) # the sum() builtin can be used to merge results # into a single ParseResults object print(sum(cap_word.search_string(quote))) prints: .. testoutput:: [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']] ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity'] """ maxMatches: int = deprecate_argument(kwargs, "maxMatches", _MAX_INT) max_matches = min(maxMatches, max_matches) try: return ParseResults( [ t for t, s, e in self.scan_string( instring, max_matches=max_matches, always_skip_whitespace=False, debug=debug, ) ] ) except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise # catch and re-raise exception from here, clears out pyparsing internal stack trace raise exc.with_traceback(None) def split( self, instring: str, maxsplit: int = _MAX_INT, include_separators: bool = False, **kwargs, ) -> Generator[str, None, None]: """ Generator method to split a string using the given expression as a separator. May be called with optional ``maxsplit`` argument, to limit the number of splits; and the optional ``include_separators`` argument (default= ``False``), if the separating matching text should be included in the split results. Example: .. testcode:: punc = one_of(list(".,;:/-!?")) print(list(punc.split( "This, this?, this sentence, is badly punctuated!"))) prints: .. testoutput:: ['This', ' this', '', ' this sentence', ' is badly punctuated', ''] """ includeSeparators: bool = deprecate_argument(kwargs, "includeSeparators", False) include_separators = includeSeparators or include_separators last = 0 for t, s, e in self.scan_string(instring, max_matches=maxsplit): yield instring[last:s] if include_separators: yield t[0] last = e yield instring[last:] def __add__(self, other) -> ParserElement: """ Implementation of ``+`` operator - returns :class:`And`. Adding strings to a :class:`ParserElement` converts them to :class:`Literal`\\ s by default. Example: .. testcode:: greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" print(hello, "->", greet.parse_string(hello)) prints: .. testoutput:: Hello, World! -> ['Hello', ',', 'World', '!'] ``...`` may be used as a parse expression as a short form of :class:`SkipTo`: .. testcode:: Literal('start') + ... + Literal('end') is equivalent to: .. testcode:: Literal('start') + SkipTo('end')("_skipped*") + Literal('end') Note that the skipped text is returned with '_skipped' as a results name, and to support having multiple skips in the same parser, the value returned is a list of all skipped text. """ if other is Ellipsis: return _PendingSkip(self) if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return And([self, other]) def __radd__(self, other) -> ParserElement: """ Implementation of ``+`` operator when left operand is not a :class:`ParserElement` """ if other is Ellipsis: return SkipTo(self)("_skipped*") + self if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return other + self def __sub__(self, other) -> ParserElement: """ Implementation of ``-`` operator, returns :class:`And` with error stop """ if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return self + And._ErrorStop() + other def __rsub__(self, other) -> ParserElement: """ Implementation of ``-`` operator when left operand is not a :class:`ParserElement` """ if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return other - self def __mul__(self, other) -> ParserElement: """ Implementation of ``*`` operator, allows use of ``expr * 3`` in place of ``expr + expr + expr``. Expressions may also be multiplied by a 2-integer tuple, similar to ``{min, max}`` multipliers in regular expressions. Tuples may also include ``None`` as in: - ``expr*(n, None)`` or ``expr*(n, )`` is equivalent to ``expr*n + ZeroOrMore(expr)`` (read as "at least n instances of ``expr``") - ``expr*(None, n)`` is equivalent to ``expr*(0, n)`` (read as "0 to n instances of ``expr``") - ``expr*(None, None)`` is equivalent to ``ZeroOrMore(expr)`` - ``expr*(1, None)`` is equivalent to ``OneOrMore(expr)`` Note that ``expr*(None, n)`` does not raise an exception if more than n exprs exist in the input stream; that is, ``expr*(None, n)`` does not enforce a maximum number of expr occurrences. If this behavior is desired, then write ``expr*(None, n) + ~expr`` """ if other is Ellipsis: other = (0, None) elif isinstance(other, tuple) and other[:1] == (Ellipsis,): other = ((0,) + other[1:] + (None,))[:2] if not isinstance(other, (int, tuple)): return NotImplemented if isinstance(other, int): minElements, optElements = other, 0 else: other = tuple(o if o is not Ellipsis else None for o in other) other = (other + (None, None))[:2] if other[0] is None: other = (0, other[1]) if isinstance(other[0], int) and other[1] is None: if other[0] == 0: return ZeroOrMore(self) if other[0] == 1: return OneOrMore(self) else: return self * other[0] + ZeroOrMore(self) elif isinstance(other[0], int) and isinstance(other[1], int): minElements, optElements = other optElements -= minElements else: return NotImplemented if minElements < 0: raise ValueError("cannot multiply ParserElement by negative value") if optElements < 0: raise ValueError( "second tuple value must be greater or equal to first tuple value" ) if minElements == optElements == 0: return And([]) if optElements: def makeOptionalList(n): if n > 1: return Opt(self + makeOptionalList(n - 1)) else: return Opt(self) if minElements: if minElements == 1: ret = self + makeOptionalList(optElements) else: ret = And([self] * minElements) + makeOptionalList(optElements) else: ret = makeOptionalList(optElements) else: if minElements == 1: ret = self else: ret = And([self] * minElements) return ret def __rmul__(self, other) -> ParserElement: return self.__mul__(other) def __or__(self, other) -> ParserElement: """ Implementation of ``|`` operator - returns :class:`MatchFirst` .. versionchanged:: 3.1.0 Support ``expr | ""`` as a synonym for ``Optional(expr)``. """ if other is Ellipsis: return _PendingSkip(self, must_skip=True) if isinstance(other, str_type): # `expr | ""` is equivalent to `Opt(expr)` if other == "": return Opt(self) other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return MatchFirst([self, other]) def __ror__(self, other) -> ParserElement: """ Implementation of ``|`` operator when left operand is not a :class:`ParserElement` """ if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return other | self def __xor__(self, other) -> ParserElement: """ Implementation of ``^`` operator - returns :class:`Or` """ if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return Or([self, other]) def __rxor__(self, other) -> ParserElement: """ Implementation of ``^`` operator when left operand is not a :class:`ParserElement` """ if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return other ^ self def __and__(self, other) -> ParserElement: """ Implementation of ``&`` operator - returns :class:`Each` """ if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return Each([self, other]) def __rand__(self, other) -> ParserElement: """ Implementation of ``&`` operator when left operand is not a :class:`ParserElement` """ if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return other & self def __invert__(self) -> ParserElement: """ Implementation of ``~`` operator - returns :class:`NotAny` """ return NotAny(self) # disable __iter__ to override legacy use of sequential access to __getitem__ to # iterate over a sequence __iter__ = None def __getitem__(self, key): """ use ``[]`` indexing notation as a short form for expression repetition: - ``expr[n]`` is equivalent to ``expr*n`` - ``expr[m, n]`` is equivalent to ``expr*(m, n)`` - ``expr[n, ...]`` or ``expr[n,]`` is equivalent to ``expr*n + ZeroOrMore(expr)`` (read as "at least n instances of ``expr``") - ``expr[..., n]`` is equivalent to ``expr*(0, n)`` (read as "0 to n instances of ``expr``") - ``expr[...]`` and ``expr[0, ...]`` are equivalent to ``ZeroOrMore(expr)`` - ``expr[1, ...]`` is equivalent to ``OneOrMore(expr)`` ``None`` may be used in place of ``...``. Note that ``expr[..., n]`` and ``expr[m, n]`` do not raise an exception if more than ``n`` ``expr``\\ s exist in the input stream. If this behavior is desired, then write ``expr[..., n] + ~expr``. For repetition with a stop_on expression, use slice notation: - ``expr[...: end_expr]`` and ``expr[0, ...: end_expr]`` are equivalent to ``ZeroOrMore(expr, stop_on=end_expr)`` - ``expr[1, ...: end_expr]`` is equivalent to ``OneOrMore(expr, stop_on=end_expr)`` .. versionchanged:: 3.1.0 Support for slice notation. """ stop_on_defined = False stop_on = NoMatch() if isinstance(key, slice): key, stop_on = key.start, key.stop if key is None: key = ... stop_on_defined = True elif isinstance(key, tuple) and isinstance(key[-1], slice): key, stop_on = (key[0], key[1].start), key[1].stop stop_on_defined = True # convert single arg keys to tuples if isinstance(key, str_type): key = (key,) try: iter(key) except TypeError: key = (key, key) if len(key) > 2: raise TypeError( f"only 1 or 2 index arguments supported ({key[:5]}{f'... [{len(key)}]' if len(key) > 5 else ''})" ) # clip to 2 elements ret = self * tuple(key[:2]) ret = typing.cast(_MultipleMatch, ret) if stop_on_defined: ret.stopOn(stop_on) return ret def __call__(self, name: typing.Optional[str] = None) -> ParserElement: """ Shortcut for :class:`set_results_name`, with ``list_all_matches=False``. If ``name`` is given with a trailing ``'*'`` character, then ``list_all_matches`` will be passed as ``True``. If ``name`` is omitted, same as calling :class:`copy`. Example: .. testcode:: # these are equivalent userdata = ( Word(alphas).set_results_name("name") + Word(nums + "-").set_results_name("socsecno") ) userdata = Word(alphas)("name") + Word(nums + "-")("socsecno") """ if name is not None: return self._setResultsName(name) return self.copy() def suppress(self) -> ParserElement: """ Suppresses the output of this :class:`ParserElement`; useful to keep punctuation from cluttering up returned output. """ return Suppress(self) def ignore_whitespace(self, recursive: bool = True) -> ParserElement: """ Enables the skipping of whitespace before matching the characters in the :class:`ParserElement`'s defined pattern. :param recursive: If ``True`` (the default), also enable whitespace skipping in child elements (if any) """ self.skipWhitespace = True return self def leave_whitespace(self, recursive: bool = True) -> ParserElement: """ Disables the skipping of whitespace before matching the characters in the :class:`ParserElement`'s defined pattern. This is normally only used internally by the pyparsing module, but may be needed in some whitespace-sensitive grammars. :param recursive: If true (the default), also disable whitespace skipping in child elements (if any) """ self.skipWhitespace = False return self def set_whitespace_chars( self, chars: Union[set[str], str], copy_defaults: bool = False ) -> ParserElement: """ Overrides the default whitespace chars """ self.skipWhitespace = True self.whiteChars = set(chars) self.copyDefaultWhiteChars = copy_defaults return self def parse_with_tabs(self) -> ParserElement: """ Overrides default behavior to expand ```` s to spaces before parsing the input string. Must be called before ``parse_string`` when the input grammar contains elements that match ```` characters. """ self.keepTabs = True return self def ignore(self, other: ParserElement) -> ParserElement: """ Define expression to be ignored (e.g., comments) while doing pattern matching; may be called repeatedly, to define multiple comment or other ignorable patterns. Example: .. doctest:: >>> patt = Word(alphas)[...] >>> print(patt.parse_string('ablaj /* comment */ lskjd')) ['ablaj'] >>> patt = Word(alphas)[...].ignore(c_style_comment) >>> print(patt.parse_string('ablaj /* comment */ lskjd')) ['ablaj', 'lskjd'] """ if isinstance(other, str_type): other = Suppress(other) if isinstance(other, Suppress): if other not in self.ignoreExprs: self.ignoreExprs.append(other) else: self.ignoreExprs.append(Suppress(other.copy())) return self def set_debug_actions( self, start_action: DebugStartAction, success_action: DebugSuccessAction, exception_action: DebugExceptionAction, ) -> ParserElement: """ Customize display of debugging messages while doing pattern matching: :param start_action: method to be called when an expression is about to be parsed; should have the signature:: fn(input_string: str, location: int, expression: ParserElement, cache_hit: bool) :param success_action: method to be called when an expression has successfully parsed; should have the signature:: fn(input_string: str, start_location: int, end_location: int, expression: ParserELement, parsed_tokens: ParseResults, cache_hit: bool) :param exception_action: method to be called when expression fails to parse; should have the signature:: fn(input_string: str, location: int, expression: ParserElement, exception: Exception, cache_hit: bool) """ self.debugActions = self.DebugActions( start_action or _default_start_debug_action, # type: ignore[truthy-function] success_action or _default_success_debug_action, # type: ignore[truthy-function] exception_action or _default_exception_debug_action, # type: ignore[truthy-function] ) self.debug = any(self.debugActions) return self def set_debug(self, flag: bool = True, recurse: bool = False) -> ParserElement: """ Enable display of debugging messages while doing pattern matching. Set ``flag`` to ``True`` to enable, ``False`` to disable. Set ``recurse`` to ``True`` to set the debug flag on this expression and all sub-expressions. Example: .. testcode:: wd = Word(alphas).set_name("alphaword") integer = Word(nums).set_name("numword") term = wd | integer # turn on debugging for wd wd.set_debug() term[1, ...].parse_string("abc 123 xyz 890") prints: .. testoutput:: :options: +NORMALIZE_WHITESPACE Match alphaword at loc 0(1,1) abc 123 xyz 890 ^ Matched alphaword -> ['abc'] Match alphaword at loc 4(1,5) abc 123 xyz 890 ^ Match alphaword failed, ParseException raised: Expected alphaword, ... Match alphaword at loc 8(1,9) abc 123 xyz 890 ^ Matched alphaword -> ['xyz'] Match alphaword at loc 12(1,13) abc 123 xyz 890 ^ Match alphaword failed, ParseException raised: Expected alphaword, ... abc 123 xyz 890 ^ Match alphaword failed, ParseException raised: Expected alphaword, found end of text ... The output shown is that produced by the default debug actions - custom debug actions can be specified using :meth:`set_debug_actions`. Prior to attempting to match the ``wd`` expression, the debugging message ``"Match at loc (,)"`` is shown. Then if the parse succeeds, a ``"Matched"`` message is shown, or an ``"Exception raised"`` message is shown. Also note the use of :meth:`set_name` to assign a human-readable name to the expression, which makes debugging and exception messages easier to understand - for instance, the default name created for the :class:`Word` expression without calling :meth:`set_name` is ``"W:(A-Za-z)"``. .. versionchanged:: 3.1.0 ``recurse`` argument added. """ if recurse: for expr in self.visit_all(): expr.set_debug(flag, recurse=False) return self if flag: self.set_debug_actions( _default_start_debug_action, _default_success_debug_action, _default_exception_debug_action, ) else: self.debug = False return self @property def default_name(self) -> str: if self._defaultName is None: self._defaultName = self._generateDefaultName() return self._defaultName @abstractmethod def _generateDefaultName(self) -> str: """ Child classes must define this method, which defines how the ``default_name`` is set. """ def set_name(self, name: typing.Optional[str]) -> ParserElement: """ Define name for this expression, makes debugging and exception messages clearer. If `__diag__.enable_debug_on_named_expressions` is set to True, setting a name will also enable debug for this expression. If `name` is None, clears any custom name for this expression, and clears the debug flag is it was enabled via `__diag__.enable_debug_on_named_expressions`. Example: .. doctest:: >>> integer = Word(nums) >>> integer.parse_string("ABC") Traceback (most recent call last): ParseException: Expected W:(0-9) (at char 0), (line:1, col:1) >>> integer.set_name("integer") integer >>> integer.parse_string("ABC") Traceback (most recent call last): ParseException: Expected integer (at char 0), (line:1, col:1) .. versionchanged:: 3.1.0 Accept ``None`` as the ``name`` argument. """ self.customName = name # type: ignore[assignment] self.errmsg = f"Expected {str(self)}" if __diag__.enable_debug_on_named_expressions: self.set_debug(name is not None) return self @property def name(self) -> str: """ Returns a user-defined name if available, but otherwise defaults back to the auto-generated name """ return self.customName if self.customName is not None else self.default_name @name.setter def name(self, new_name) -> None: self.set_name(new_name) def __str__(self) -> str: return self.name def __repr__(self) -> str: return str(self) def streamline(self) -> ParserElement: self.streamlined = True self._defaultName = None return self def recurse(self) -> list[ParserElement]: return [] def _checkRecursion(self, parseElementList): subRecCheckList = parseElementList[:] + [self] for e in self.recurse(): e._checkRecursion(subRecCheckList) def validate(self, validateTrace=None) -> None: """ .. deprecated:: 3.0.0 Do not use to check for left recursion. Check defined expressions for valid structure, check for infinite recursive definitions. """ warnings.warn( "ParserElement.validate() is deprecated, and should not be used to check for left recursion", PyparsingDeprecationWarning, stacklevel=2, ) self._checkRecursion([]) def parse_file( self, file_or_filename: Union[str, Path, TextIO], encoding: str = "utf-8", parse_all: bool = False, **kwargs, ) -> ParseResults: """ Execute the parse expression on the given file or filename. If a filename is specified (instead of a file object), the entire file is opened, read, and closed before parsing. """ parseAll: bool = deprecate_argument(kwargs, "parseAll", False) parse_all = parse_all or parseAll try: file_or_filename = typing.cast(TextIO, file_or_filename) file_contents = file_or_filename.read() except AttributeError: file_or_filename = typing.cast(str, file_or_filename) with open(file_or_filename, "r", encoding=encoding) as f: file_contents = f.read() try: return self.parse_string(file_contents, parse_all) except ParseBaseException as exc: if ParserElement.verbose_stacktrace: raise # catch and re-raise exception from here, clears out pyparsing internal stack trace raise exc.with_traceback(None) def __eq__(self, other): if self is other: return True elif isinstance(other, str_type): return self.matches(other, parse_all=True) elif isinstance(other, ParserElement): return vars(self) == vars(other) return False def __hash__(self): return id(self) def matches(self, test_string: str, parse_all: bool = True, **kwargs) -> bool: """ Method for quick testing of a parser against a test string. Good for simple inline microtests of sub expressions while building up larger parser. :param test_string: to test against this expression for a match :param parse_all: flag to pass to :meth:`parse_string` when running tests Example: .. doctest:: >>> expr = Word(nums) >>> expr.matches("100") True """ parseAll: bool = deprecate_argument(kwargs, "parseAll", True) parse_all = parse_all and parseAll try: self.parse_string(str(test_string), parse_all=parse_all) return True except ParseBaseException: return False def run_tests( self, tests: Union[str, list[str]], parse_all: bool = True, comment: typing.Optional[Union[ParserElement, str]] = "#", full_dump: bool = True, print_results: bool = True, failure_tests: bool = False, post_parse: typing.Optional[ Callable[[str, ParseResults], typing.Optional[str]] ] = None, file: typing.Optional[TextIO] = None, with_line_numbers: bool = False, *, parseAll: bool = True, fullDump: bool = True, printResults: bool = True, failureTests: bool = False, postParse: typing.Optional[ Callable[[str, ParseResults], typing.Optional[str]] ] = None, ) -> tuple[bool, list[tuple[str, Union[ParseResults, Exception]]]]: """ Execute the parse expression on a series of test strings, showing each test, the parsed results or where the parse failed. Quick and easy way to run a parse expression against a list of sample strings. Parameters: - ``tests`` - a list of separate test strings, or a multiline string of test strings - ``parse_all`` - (default= ``True``) - flag to pass to :class:`parse_string` when running tests - ``comment`` - (default= ``'#'``) - expression for indicating embedded comments in the test string; pass None to disable comment filtering - ``full_dump`` - (default= ``True``) - dump results as list followed by results names in nested outline; if False, only dump nested list - ``print_results`` - (default= ``True``) prints test output to stdout - ``failure_tests`` - (default= ``False``) indicates if these tests are expected to fail parsing - ``post_parse`` - (default= ``None``) optional callback for successful parse results; called as `fn(test_string, parse_results)` and returns a string to be added to the test output - ``file`` - (default= ``None``) optional file-like object to which test output will be written; if None, will default to ``sys.stdout`` - ``with_line_numbers`` - default= ``False``) show test strings with line and column numbers Returns: a (success, results) tuple, where success indicates that all tests succeeded (or failed if ``failure_tests`` is True), and the results contain a list of lines of each test's output Passing example: .. testcode:: number_expr = pyparsing_common.number.copy() result = number_expr.run_tests(''' # unsigned integer 100 # negative integer -100 # float with scientific notation 6.02e23 # integer with scientific notation 1e-12 # negative decimal number without leading digit -.100 ''') print("Success" if result[0] else "Failed!") prints: .. testoutput:: :options: +NORMALIZE_WHITESPACE # unsigned integer 100 [100] # negative integer -100 [-100] # float with scientific notation 6.02e23 [6.02e+23] # integer with scientific notation 1e-12 [1e-12] # negative decimal number without leading digit -.100 [-0.1] Success Failure-test example: .. testcode:: result = number_expr.run_tests(''' # stray character 100Z # too many '.' 3.14.159 ''', failure_tests=True) print("Success" if result[0] else "Failed!") prints: .. testoutput:: :options: +NORMALIZE_WHITESPACE # stray character 100Z 100Z ^ ParseException: Expected end of text, found 'Z' ... # too many '.' 3.14.159 3.14.159 ^ ParseException: Expected end of text, found '.' ... FAIL: Expected end of text, found '.' ... Success Each test string must be on a single line. If you want to test a string that spans multiple lines, create a test like this: .. testcode:: expr = Word(alphanums)[1,...] expr.run_tests(r"this is a test\\n of strings that spans \\n 3 lines") .. testoutput:: :options: +NORMALIZE_WHITESPACE :hide: this is a test\\n of strings that spans \\n 3 lines ['this', 'is', 'a', 'test', 'of', 'strings', 'that', 'spans', '3', 'lines'] (Note that this is a raw string literal, you must include the leading ``'r'``.) """ from .testing import pyparsing_test parseAll = parseAll and parse_all fullDump = fullDump and full_dump printResults = printResults and print_results failureTests = failureTests or failure_tests postParse = postParse or post_parse if isinstance(tests, str_type): tests = typing.cast(str, tests) line_strip = type(tests).strip tests = [line_strip(test_line) for test_line in tests.rstrip().splitlines()] comment_specified = comment is not None if comment_specified: if isinstance(comment, str_type): comment = typing.cast(str, comment) comment = Literal(comment) comment = typing.cast(ParserElement, comment) if file is None: file = sys.stdout print_ = file.write result: Union[ParseResults, Exception] allResults: list[tuple[str, Union[ParseResults, Exception]]] = [] comments: list[str] = [] success = True NL = Literal(r"\n").add_parse_action(replace_with("\n")).ignore(quoted_string) BOM = "\ufeff" nlstr = "\n" for t in tests: if comment_specified and comment.matches(t, False) or comments and not t: comments.append( pyparsing_test.with_line_numbers(t) if with_line_numbers else t ) continue if not t: continue out = [ f"{nlstr}{nlstr.join(comments) if comments else ''}", pyparsing_test.with_line_numbers(t) if with_line_numbers else t, ] comments.clear() try: # convert newline marks to actual newlines, and strip leading BOM if present t = NL.transform_string(t.lstrip(BOM)) result = self.parse_string(t, parse_all=parse_all) except ParseBaseException as pe: fatal = "(FATAL) " if isinstance(pe, ParseFatalException) else "" out.append(pe.explain()) out.append(f"FAIL: {fatal}{pe}") if ParserElement.verbose_stacktrace: out.extend(traceback.format_tb(pe.__traceback__)) success = success and failureTests result = pe except Exception as exc: tag = "FAIL-EXCEPTION" # see if this exception was raised in a parse action tb = exc.__traceback__ it = iter(traceback.walk_tb(tb)) for f, line in it: if (f.f_code.co_filename, line) == pa_call_line_synth: next_f = next(it)[0] tag += f" (raised in parse action {next_f.f_code.co_name!r})" break out.append(f"{tag}: {type(exc).__name__}: {exc}") if ParserElement.verbose_stacktrace: out.extend(traceback.format_tb(exc.__traceback__)) success = success and failureTests result = exc else: success = success and not failureTests if postParse is not None: try: pp_value = postParse(t, result) if pp_value is not None: if isinstance(pp_value, ParseResults): out.append(pp_value.dump()) else: out.append(str(pp_value)) else: out.append(result.dump()) except Exception as e: out.append(result.dump(full=fullDump)) out.append( f"{postParse.__name__} failed: {type(e).__name__}: {e}" ) else: out.append(result.dump(full=fullDump)) out.append("") if printResults: print_("\n".join(out)) allResults.append((t, result)) return success, allResults def create_diagram( self, output_html: Union[TextIO, Path, str], vertical: int = 3, show_results_names: bool = False, show_groups: bool = False, embed: bool = False, show_hidden: bool = False, **kwargs, ) -> None: """ Create a railroad diagram for the parser. Parameters: - ``output_html`` (str or file-like object) - output target for generated diagram HTML - ``vertical`` (int) - threshold for formatting multiple alternatives vertically instead of horizontally (default=3) - ``show_results_names`` - bool flag whether diagram should show annotations for defined results names - ``show_groups`` - bool flag whether groups should be highlighted with an unlabeled surrounding box - ``show_hidden`` - bool flag to show diagram elements for internal elements that are usually hidden - ``embed`` - bool flag whether generated HTML should omit , , and tags to embed the resulting HTML in an enclosing HTML source - ``head`` - str containing additional HTML to insert into the section of the generated code; can be used to insert custom CSS styling - ``body`` - str containing additional HTML to insert at the beginning of the section of the generated code Additional diagram-formatting keyword arguments can also be included; see railroad.Diagram class. .. versionchanged:: 3.1.0 ``embed`` argument added. """ try: from .diagram import to_railroad, railroad_to_html except ImportError as ie: raise Exception( "must ``pip install pyparsing[diagrams]`` to generate parser railroad diagrams" ) from ie self.streamline() railroad = to_railroad( self, vertical=vertical, show_results_names=show_results_names, show_groups=show_groups, show_hidden=show_hidden, diagram_kwargs=kwargs, ) if not isinstance(output_html, (str, Path)): # we were passed a file-like object, just write to it output_html.write(railroad_to_html(railroad, embed=embed, **kwargs)) return with open(output_html, "w", encoding="utf-8") as diag_file: diag_file.write(railroad_to_html(railroad, embed=embed, **kwargs)) # Compatibility synonyms # fmt: off inlineLiteralsUsing = staticmethod(replaced_by_pep8("inlineLiteralsUsing", inline_literals_using)) setDefaultWhitespaceChars = staticmethod(replaced_by_pep8( "setDefaultWhitespaceChars", set_default_whitespace_chars )) disableMemoization = staticmethod(replaced_by_pep8("disableMemoization", disable_memoization)) enableLeftRecursion = staticmethod(replaced_by_pep8("enableLeftRecursion", enable_left_recursion)) enablePackrat = staticmethod(replaced_by_pep8("enablePackrat", enable_packrat)) resetCache = staticmethod(replaced_by_pep8("resetCache", reset_cache)) setResultsName = replaced_by_pep8("setResultsName", set_results_name) setBreak = replaced_by_pep8("setBreak", set_break) setParseAction = replaced_by_pep8("setParseAction", set_parse_action) addParseAction = replaced_by_pep8("addParseAction", add_parse_action) addCondition = replaced_by_pep8("addCondition", add_condition) setFailAction = replaced_by_pep8("setFailAction", set_fail_action) tryParse = replaced_by_pep8("tryParse", try_parse) parseString = replaced_by_pep8("parseString", parse_string) scanString = replaced_by_pep8("scanString", scan_string) transformString = replaced_by_pep8("transformString", transform_string) searchString = replaced_by_pep8("searchString", search_string) ignoreWhitespace = replaced_by_pep8("ignoreWhitespace", ignore_whitespace) leaveWhitespace = replaced_by_pep8("leaveWhitespace", leave_whitespace) setWhitespaceChars = replaced_by_pep8("setWhitespaceChars", set_whitespace_chars) parseWithTabs = replaced_by_pep8("parseWithTabs", parse_with_tabs) setDebugActions = replaced_by_pep8("setDebugActions", set_debug_actions) setDebug = replaced_by_pep8("setDebug", set_debug) setName = replaced_by_pep8("setName", set_name) parseFile = replaced_by_pep8("parseFile", parse_file) runTests = replaced_by_pep8("runTests", run_tests) canParseNext = replaced_by_pep8("canParseNext", can_parse_next) defaultName = default_name # fmt: on class _PendingSkip(ParserElement): # internal placeholder class to hold a place were '...' is added to a parser element, # once another ParserElement is added, this placeholder will be replaced with a SkipTo def __init__(self, expr: ParserElement, must_skip: bool = False) -> None: super().__init__() self.anchor = expr self.must_skip = must_skip def _generateDefaultName(self) -> str: return str(self.anchor + Empty()).replace("Empty", "...") def __add__(self, other) -> ParserElement: skipper = SkipTo(other).set_name("...")("_skipped*") if self.must_skip: def must_skip(t): if not t._skipped or t._skipped.as_list() == [""]: del t[0] t.pop("_skipped", None) def show_skip(t): if t._skipped.as_list()[-1:] == [""]: t.pop("_skipped") t["_skipped"] = f"missing <{self.anchor!r}>" return ( self.anchor + skipper().add_parse_action(must_skip) | skipper().add_parse_action(show_skip) ) + other return self.anchor + skipper + other def __repr__(self): return self.defaultName def parseImpl(self, *args) -> ParseImplReturnType: raise Exception( "use of `...` expression without following SkipTo target expression" ) class Token(ParserElement): """Abstract :class:`ParserElement` subclass, for defining atomic matching patterns. """ def __init__(self) -> None: super().__init__(savelist=False) def _generateDefaultName(self) -> str: return type(self).__name__ class NoMatch(Token): """ A token that will never match. """ def __init__(self) -> None: super().__init__() self._may_return_empty = True self.mayIndexError = False self.errmsg = "Unmatchable token" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: raise ParseException(instring, loc, self.errmsg, self) class Literal(Token): """ Token to exactly match a specified string. Example: .. doctest:: >>> Literal('abc').parse_string('abc') ParseResults(['abc'], {}) >>> Literal('abc').parse_string('abcdef') ParseResults(['abc'], {}) >>> Literal('abc').parse_string('ab') Traceback (most recent call last): ParseException: Expected 'abc', found 'ab' (at char 0), (line: 1, col: 1) For case-insensitive matching, use :class:`CaselessLiteral`. For keyword matching (force word break before and after the matched string), use :class:`Keyword` or :class:`CaselessKeyword`. """ def __new__(cls, match_string: str = "", **kwargs): # Performance tuning: select a subclass with optimized parseImpl if cls is Literal: matchString: str = deprecate_argument(kwargs, "matchString", "") match_string = matchString or match_string if not match_string: return super().__new__(Empty) if len(match_string) == 1: return super().__new__(_SingleCharLiteral) # Default behavior return super().__new__(cls) # Needed to make copy.copy() work correctly if we customize __new__ def __getnewargs__(self): return (self.match,) def __init__(self, match_string: str = "", **kwargs) -> None: matchString: str = deprecate_argument(kwargs, "matchString", "") super().__init__() match_string = matchString or match_string self.match = match_string self.matchLen = len(match_string) self.firstMatchChar = match_string[:1] self.errmsg = f"Expected {self.name}" self._may_return_empty = False self.mayIndexError = False def _generateDefaultName(self) -> str: return repr(self.match) def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if instring[loc] == self.firstMatchChar and instring.startswith( self.match, loc ): return loc + self.matchLen, self.match raise ParseException(instring, loc, self.errmsg, self) class Empty(Literal): """ An empty token, will always match. """ def __init__(self, match_string="", *, matchString="") -> None: super().__init__("") self._may_return_empty = True self.mayIndexError = False def _generateDefaultName(self) -> str: return "Empty" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: return loc, [] class _SingleCharLiteral(Literal): def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if instring[loc] == self.firstMatchChar: return loc + 1, self.match raise ParseException(instring, loc, self.errmsg, self) ParserElement._literalStringClass = Literal class Keyword(Token): """ Token to exactly match a specified string as a keyword, that is, it must be immediately preceded and followed by whitespace or non-keyword characters. Compare with :class:`Literal`: - ``Literal("if")`` will match the leading ``'if'`` in ``'ifAndOnlyIf'``. - ``Keyword("if")`` will not; it will only match the leading ``'if'`` in ``'if x=1'``, or ``'if(y==2)'`` Accepts two optional constructor arguments in addition to the keyword string: - ``ident_chars`` is a string of characters that would be valid identifier characters, defaulting to all alphanumerics + "_" and "$" - ``caseless`` allows case-insensitive matching, default is ``False``. Example: .. doctest:: :options: +NORMALIZE_WHITESPACE >>> Keyword("start").parse_string("start") ParseResults(['start'], {}) >>> Keyword("start").parse_string("starting") Traceback (most recent call last): ParseException: Expected Keyword 'start', keyword was immediately followed by keyword character, found 'ing' (at char 5), (line:1, col:6) .. doctest:: :options: +NORMALIZE_WHITESPACE >>> Keyword("start").parse_string("starting").debug() Traceback (most recent call last): ParseException: Expected Keyword "start", keyword was immediately followed by keyword character, found 'ing' ... For case-insensitive matching, use :class:`CaselessKeyword`. """ DEFAULT_KEYWORD_CHARS = alphanums + "_$" def __init__( self, match_string: str = "", ident_chars: typing.Optional[str] = None, caseless: bool = False, **kwargs, ) -> None: matchString = deprecate_argument(kwargs, "matchString", "") identChars = deprecate_argument(kwargs, "identChars", None) super().__init__() identChars = identChars or ident_chars if identChars is None: identChars = Keyword.DEFAULT_KEYWORD_CHARS match_string = matchString or match_string self.match = match_string self.matchLen = len(match_string) self.firstMatchChar = match_string[:1] if not self.firstMatchChar: raise ValueError("null string passed to Keyword; use Empty() instead") self.errmsg = f"Expected {type(self).__name__} {self.name}" self._may_return_empty = False self.mayIndexError = False self.caseless = caseless if caseless: self.caselessmatch = match_string.upper() identChars = identChars.upper() self.ident_chars = set(identChars) @property def identChars(self) -> set[str]: """ .. deprecated:: 3.3.0 use ident_chars instead. Property returning the characters being used as keyword characters for this expression. """ return self.ident_chars def _generateDefaultName(self) -> str: return repr(self.match) def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: errmsg = self.errmsg or "" errloc = loc if self.caseless: if instring[loc : loc + self.matchLen].upper() == self.caselessmatch: if loc == 0 or instring[loc - 1].upper() not in self.identChars: if ( loc >= len(instring) - self.matchLen or instring[loc + self.matchLen].upper() not in self.identChars ): return loc + self.matchLen, self.match # followed by keyword char errmsg += ", was immediately followed by keyword character" errloc = loc + self.matchLen else: # preceded by keyword char errmsg += ", keyword was immediately preceded by keyword character" errloc = loc - 1 # else no match just raise plain exception elif ( instring[loc] == self.firstMatchChar and self.matchLen == 1 or instring.startswith(self.match, loc) ): if loc == 0 or instring[loc - 1] not in self.identChars: if ( loc >= len(instring) - self.matchLen or instring[loc + self.matchLen] not in self.identChars ): return loc + self.matchLen, self.match # followed by keyword char errmsg += ", keyword was immediately followed by keyword character" errloc = loc + self.matchLen else: # preceded by keyword char errmsg += ", keyword was immediately preceded by keyword character" errloc = loc - 1 # else no match just raise plain exception raise ParseException(instring, errloc, errmsg, self) @staticmethod def set_default_keyword_chars(chars) -> None: """ Overrides the default characters used by :class:`Keyword` expressions. """ Keyword.DEFAULT_KEYWORD_CHARS = chars # Compatibility synonyms setDefaultKeywordChars = staticmethod( replaced_by_pep8("setDefaultKeywordChars", set_default_keyword_chars) ) class CaselessLiteral(Literal): """ Token to match a specified string, ignoring case of letters. Note: the matched results will always be in the case of the given match string, NOT the case of the input text. Example: .. doctest:: >>> CaselessLiteral("CMD")[1, ...].parse_string("cmd CMD Cmd10") ParseResults(['CMD', 'CMD', 'CMD'], {}) (Contrast with example for :class:`CaselessKeyword`.) """ def __init__(self, match_string: str = "", **kwargs) -> None: matchString: str = deprecate_argument(kwargs, "matchString", "") match_string = matchString or match_string super().__init__(match_string.upper()) # Preserve the defining literal. self.returnString = match_string self.errmsg = f"Expected {self.name}" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if instring[loc : loc + self.matchLen].upper() == self.match: return loc + self.matchLen, self.returnString raise ParseException(instring, loc, self.errmsg, self) class CaselessKeyword(Keyword): """ Caseless version of :class:`Keyword`. Example: .. doctest:: >>> CaselessKeyword("CMD")[1, ...].parse_string("cmd CMD Cmd10") ParseResults(['CMD', 'CMD'], {}) (Contrast with example for :class:`CaselessLiteral`.) """ def __init__( self, match_string: str = "", ident_chars: typing.Optional[str] = None, **kwargs ) -> None: matchString: str = deprecate_argument(kwargs, "matchString", "") identChars: typing.Optional[str] = deprecate_argument( kwargs, "identChars", None ) identChars = identChars or ident_chars match_string = matchString or match_string super().__init__(match_string, identChars, caseless=True) class CloseMatch(Token): """A variation on :class:`Literal` which matches "close" matches, that is, strings with at most 'n' mismatching characters. :class:`CloseMatch` takes parameters: - ``match_string`` - string to be matched - ``caseless`` - a boolean indicating whether to ignore casing when comparing characters - ``max_mismatches`` - (``default=1``) maximum number of mismatches allowed to count as a match The results from a successful parse will contain the matched text from the input string and the following named results: - ``mismatches`` - a list of the positions within the match_string where mismatches were found - ``original`` - the original match_string used to compare against the input string If ``mismatches`` is an empty list, then the match was an exact match. Example: .. doctest:: :options: +NORMALIZE_WHITESPACE >>> patt = CloseMatch("ATCATCGAATGGA") >>> patt.parse_string("ATCATCGAAXGGA") ParseResults(['ATCATCGAAXGGA'], {'original': 'ATCATCGAATGGA', 'mismatches': [9]}) >>> patt.parse_string("ATCAXCGAAXGGA") Traceback (most recent call last): ParseException: Expected 'ATCATCGAATGGA' (with up to 1 mismatches), found 'ATCAXCGAAXGGA' (at char 0), (line:1, col:1) # exact match >>> patt.parse_string("ATCATCGAATGGA") ParseResults(['ATCATCGAATGGA'], {'original': 'ATCATCGAATGGA', 'mismatches': []}) # close match allowing up to 2 mismatches >>> patt = CloseMatch("ATCATCGAATGGA", max_mismatches=2) >>> patt.parse_string("ATCAXCGAAXGGA") ParseResults(['ATCAXCGAAXGGA'], {'original': 'ATCATCGAATGGA', 'mismatches': [4, 9]}) """ def __init__( self, match_string: str, max_mismatches: typing.Optional[int] = None, *, caseless=False, **kwargs, ) -> None: maxMismatches: int = deprecate_argument(kwargs, "maxMismatches", 1) maxMismatches = max_mismatches if max_mismatches is not None else maxMismatches super().__init__() self.match_string = match_string self.maxMismatches = maxMismatches self.errmsg = f"Expected {self.match_string!r} (with up to {self.maxMismatches} mismatches)" self.caseless = caseless self.mayIndexError = False self._may_return_empty = False def _generateDefaultName(self) -> str: return f"{type(self).__name__}:{self.match_string!r}" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: start = loc instrlen = len(instring) maxloc = start + len(self.match_string) if maxloc <= instrlen: match_string = self.match_string match_stringloc = 0 mismatches = [] maxMismatches = self.maxMismatches for match_stringloc, s_m in enumerate( zip(instring[loc:maxloc], match_string) ): src, mat = s_m if self.caseless: src, mat = src.lower(), mat.lower() if src != mat: mismatches.append(match_stringloc) if len(mismatches) > maxMismatches: break else: loc = start + match_stringloc + 1 results = ParseResults([instring[start:loc]]) results["original"] = match_string results["mismatches"] = mismatches return loc, results raise ParseException(instring, loc, self.errmsg, self) class Word(Token): """Token for matching words composed of allowed character sets. Parameters: - ``init_chars`` - string of all characters that should be used to match as a word; "ABC" will match "AAA", "ABAB", "CBAC", etc.; if ``body_chars`` is also specified, then this is the string of initial characters - ``body_chars`` - string of characters that can be used for matching after a matched initial character as given in ``init_chars``; if omitted, same as the initial characters (default=``None``) - ``min`` - minimum number of characters to match (default=1) - ``max`` - maximum number of characters to match (default=0) - ``exact`` - exact number of characters to match (default=0) - ``as_keyword`` - match as a keyword (default=``False``) - ``exclude_chars`` - characters that might be found in the input ``body_chars`` string but which should not be accepted for matching ;useful to define a word of all printables except for one or two characters, for instance (default=``None``) :class:`srange` is useful for defining custom character set strings for defining :class:`Word` expressions, using range notation from regular expression character sets. A common mistake is to use :class:`Word` to match a specific literal string, as in ``Word("Address")``. Remember that :class:`Word` uses the string argument to define *sets* of matchable characters. This expression would match "Add", "AAA", "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'. To match an exact literal string, use :class:`Literal` or :class:`Keyword`. pyparsing includes helper strings for building Words: - :attr:`alphas` - :attr:`nums` - :attr:`alphanums` - :attr:`hexnums` - :attr:`alphas8bit` (alphabetic characters in ASCII range 128-255 - accented, tilded, umlauted, etc.) - :attr:`punc8bit` (non-alphabetic characters in ASCII range 128-255 - currency, symbols, superscripts, diacriticals, etc.) - :attr:`printables` (any non-whitespace character) ``alphas``, ``nums``, and ``printables`` are also defined in several Unicode sets - see :class:`pyparsing_unicode`. Example: .. testcode:: # a word composed of digits integer = Word(nums) # Two equivalent alternate forms: Word("0123456789") Word(srange("[0-9]")) # a word with a leading capital, and zero or more lowercase capitalized_word = Word(alphas.upper(), alphas.lower()) # hostnames are alphanumeric, with leading alpha, and '-' hostname = Word(alphas, alphanums + '-') # roman numeral # (not a strict parser, accepts invalid mix of characters) roman = Word("IVXLCDM") # any string of non-whitespace characters, except for ',' csv_value = Word(printables, exclude_chars=",") :raises ValueError: If ``min`` and ``max`` are both specified and the test ``min <= max`` fails. .. versionchanged:: 3.1.0 Raises :exc:`ValueError` if ``min`` > ``max``. """ def __init__( self, init_chars: str = "", body_chars: typing.Optional[str] = None, min: int = 1, max: int = 0, exact: int = 0, as_keyword: bool = False, exclude_chars: typing.Optional[str] = None, **kwargs, ) -> None: initChars: typing.Optional[str] = deprecate_argument(kwargs, "initChars", None) bodyChars: typing.Optional[str] = deprecate_argument(kwargs, "bodyChars", None) asKeyword: bool = deprecate_argument(kwargs, "asKeyword", False) excludeChars: typing.Optional[str] = deprecate_argument( kwargs, "excludeChars", None ) initChars = initChars or init_chars bodyChars = bodyChars or body_chars asKeyword = asKeyword or as_keyword excludeChars = excludeChars or exclude_chars super().__init__() if not initChars: raise ValueError( f"invalid {type(self).__name__}, initChars cannot be empty string" ) initChars_set = set(initChars) if excludeChars: excludeChars_set = set(excludeChars) initChars_set -= excludeChars_set if bodyChars: bodyChars = "".join(set(bodyChars) - excludeChars_set) self.init_chars = initChars_set self.initCharsOrig = "".join(sorted(initChars_set)) if bodyChars: self.bodyChars = set(bodyChars) self.bodyCharsOrig = "".join(sorted(bodyChars)) else: self.bodyChars = initChars_set self.bodyCharsOrig = self.initCharsOrig self.maxSpecified = max > 0 if min < 1: raise ValueError( "cannot specify a minimum length < 1; use Opt(Word()) if zero-length word is permitted" ) if self.maxSpecified and min > max: raise ValueError( f"invalid args, if min and max both specified min must be <= max (min={min}, max={max})" ) self.minLen = min if max > 0: self.maxLen = max else: self.maxLen = _MAX_INT if exact > 0: min = max = exact self.maxLen = exact self.minLen = exact self.errmsg = f"Expected {self.name}" self.mayIndexError = False self.asKeyword = asKeyword if self.asKeyword: self.errmsg += " as a keyword" # see if we can make a regex for this Word if " " not in (self.initChars | self.bodyChars): if len(self.initChars) == 1: re_leading_fragment = re.escape(self.initCharsOrig) else: re_leading_fragment = f"[{_collapse_string_to_ranges(self.initChars)}]" if self.bodyChars == self.initChars: if max == 0 and self.minLen == 1: repeat = "+" elif max == 1: repeat = "" else: if self.minLen != self.maxLen: repeat = f"{{{self.minLen},{'' if self.maxLen == _MAX_INT else self.maxLen}}}" else: repeat = f"{{{self.minLen}}}" self.reString = f"{re_leading_fragment}{repeat}" else: if max == 1: re_body_fragment = "" repeat = "" else: re_body_fragment = f"[{_collapse_string_to_ranges(self.bodyChars)}]" if max == 0 and self.minLen == 1: repeat = "*" elif max == 2: repeat = "?" if min <= 1 else "" else: if min != max: repeat = f"{{{min - 1 if min > 0 else ''},{max - 1 if max > 0 else ''}}}" else: repeat = f"{{{min - 1 if min > 0 else ''}}}" self.reString = f"{re_leading_fragment}{re_body_fragment}{repeat}" if self.asKeyword: self.reString = rf"\b{self.reString}\b" try: self.re = re.compile(self.reString) except re.error: self.re = None # type: ignore[assignment] else: self.re_match = self.re.match self.parseImpl = self.parseImpl_regex # type: ignore[method-assign] @property def initChars(self) -> set[str]: """ .. deprecated:: 3.3.0 use `init_chars` instead. Property returning the initial chars to be used when matching this Word expression. If no body chars were specified, the initial characters will also be the body characters. """ return set(self.init_chars) def copy(self) -> Word: """ Returns a copy of this expression. Generally only used internally by pyparsing. """ ret: Word = cast(Word, super().copy()) if hasattr(self, "re_match"): ret.re_match = self.re_match ret.parseImpl = ret.parseImpl_regex # type: ignore[method-assign] return ret def _generateDefaultName(self) -> str: def charsAsStr(s): max_repr_len = 16 s = _collapse_string_to_ranges(s, re_escape=False) if len(s) > max_repr_len: return s[: max_repr_len - 3] + "..." return s if self.initChars != self.bodyChars: base = f"W:({charsAsStr(self.initChars)}, {charsAsStr(self.bodyChars)})" else: base = f"W:({charsAsStr(self.initChars)})" # add length specification if self.minLen > 1 or self.maxLen != _MAX_INT: if self.minLen == self.maxLen: if self.minLen == 1: return base[2:] else: return base + f"{{{self.minLen}}}" elif self.maxLen == _MAX_INT: return base + f"{{{self.minLen},...}}" else: return base + f"{{{self.minLen},{self.maxLen}}}" return base def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if instring[loc] not in self.initChars: raise ParseException(instring, loc, self.errmsg, self) start = loc loc += 1 instrlen = len(instring) body_chars: set[str] = self.bodyChars maxloc = start + self.maxLen maxloc = min(maxloc, instrlen) while loc < maxloc and instring[loc] in body_chars: loc += 1 throw_exception = False if loc - start < self.minLen: throw_exception = True elif self.maxSpecified and loc < instrlen and instring[loc] in body_chars: throw_exception = True elif self.asKeyword and ( (start > 0 and instring[start - 1] in body_chars) or (loc < instrlen and instring[loc] in body_chars) ): throw_exception = True if throw_exception: raise ParseException(instring, loc, self.errmsg, self) return loc, instring[start:loc] def parseImpl_regex(self, instring, loc, do_actions=True) -> ParseImplReturnType: result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) loc = result.end() return loc, result[0] class Char(Word): """A short-cut class for defining :class:`Word` ``(characters, exact=1)``, when defining a match of any single character in a string of characters. """ def __init__( self, charset: str, as_keyword: bool = False, exclude_chars: typing.Optional[str] = None, **kwargs, ) -> None: asKeyword: bool = deprecate_argument(kwargs, "asKeyword", False) excludeChars: typing.Optional[str] = deprecate_argument( kwargs, "excludeChars", None ) asKeyword = asKeyword or as_keyword excludeChars = excludeChars or exclude_chars super().__init__( charset, exact=1, as_keyword=asKeyword, exclude_chars=excludeChars ) class Regex(Token): r"""Token for matching strings that match a given regular expression. Defined with string specifying the regular expression in a form recognized by the stdlib Python `re module `_. If the given regex contains named groups (defined using ``(?P...)``), these will be preserved as named :class:`ParseResults`. If instead of the Python stdlib ``re`` module you wish to use a different RE module (such as the ``regex`` module), you can do so by building your ``Regex`` object with a compiled RE that was compiled using ``regex``. The parameters ``pattern`` and ``flags`` are passed to the ``re.compile()`` function as-is. See the Python `re module `_ module for an explanation of the acceptable patterns and flags. Example: .. testcode:: realnum = Regex(r"[+-]?\d+\.\d*") # ref: https://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression roman = Regex(r"M{0,4}(CM|CD|D?{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})") # named fields in a regex will be returned as named results date = Regex(r'(?P\d{4})-(?P\d\d?)-(?P\d\d?)') # the Regex class will accept regular expressions compiled using the # re module import re parser = pp.Regex(re.compile(r'[0-9]')) """ def __init__( self, pattern: Any, flags: Union[re.RegexFlag, int] = 0, as_group_list: bool = False, as_match: bool = False, **kwargs, ) -> None: super().__init__() asGroupList: bool = deprecate_argument(kwargs, "asGroupList", False) asMatch: bool = deprecate_argument(kwargs, "asMatch", False) asGroupList = asGroupList or as_group_list asMatch = asMatch or as_match if isinstance(pattern, str_type): if not pattern: raise ValueError("null string passed to Regex; use Empty() instead") self._re = None self._may_return_empty = None # type: ignore [assignment] self.reString = self.pattern = pattern elif hasattr(pattern, "pattern") and hasattr(pattern, "match"): self._re = pattern self._may_return_empty = None # type: ignore [assignment] self.pattern = self.reString = pattern.pattern elif callable(pattern): # defer creating this pattern until we really need it self.pattern = pattern self._may_return_empty = None # type: ignore [assignment] self._re = None else: raise TypeError( "Regex may only be constructed with a string or a compiled RE object," " or a callable that takes no arguments and returns a string or a" " compiled RE object" ) self.flags = flags self.errmsg = f"Expected {self.name}" self.mayIndexError = False self.asGroupList = asGroupList self.asMatch = asMatch if self.asGroupList: self.parseImpl = self.parseImplAsGroupList # type: ignore [method-assign] if self.asMatch: self.parseImpl = self.parseImplAsMatch # type: ignore [method-assign] def copy(self) -> Regex: """ Returns a copy of this expression. Generally only used internally by pyparsing. """ ret: Regex = cast(Regex, super().copy()) if self.asGroupList: ret.parseImpl = ret.parseImplAsGroupList # type: ignore [method-assign] if self.asMatch: ret.parseImpl = ret.parseImplAsMatch # type: ignore [method-assign] return ret @cached_property def re(self) -> re.Pattern: """ Property returning the compiled regular expression for this Regex. Generally only used internally by pyparsing. """ if self._re: return self._re if callable(self.pattern): # replace self.pattern with the string returned by calling self.pattern() self.pattern = cast(Callable[[], str], self.pattern)() # see if we got a compiled RE back instead of a str - if so, we're done if hasattr(self.pattern, "pattern") and hasattr(self.pattern, "match"): self._re = cast(re.Pattern[str], self.pattern) self.pattern = self.reString = self._re.pattern return self._re try: self._re = re.compile(self.pattern, self.flags) except re.error: raise ValueError(f"invalid pattern ({self.pattern!r}) passed to Regex") else: self._may_return_empty = self.re.match("", pos=0) is not None return self._re @cached_property def re_match(self) -> Callable[[str, int], Any]: return self.re.match @property def mayReturnEmpty(self): if self._may_return_empty is None: # force compile of regex pattern, to set may_return_empty flag self.re # noqa return self._may_return_empty @mayReturnEmpty.setter def mayReturnEmpty(self, value): self._may_return_empty = value def _generateDefaultName(self) -> str: unescaped = repr(self.pattern).replace("\\\\", "\\") return f"Re:({unescaped})" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: # explicit check for matching past the length of the string; # this is done because the re module will not complain about # a match with `pos > len(instring)`, it will just return "" if loc > len(instring) and self.mayReturnEmpty: raise ParseException(instring, loc, self.errmsg, self) result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) loc = result.end() ret = ParseResults(result[0]) d = result.groupdict() for k, v in d.items(): ret[k] = v return loc, ret def parseImplAsGroupList(self, instring, loc, do_actions=True): if loc > len(instring) and self.mayReturnEmpty: raise ParseException(instring, loc, self.errmsg, self) result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) loc = result.end() ret = result.groups() return loc, ret def parseImplAsMatch(self, instring, loc, do_actions=True): if loc > len(instring) and self.mayReturnEmpty: raise ParseException(instring, loc, self.errmsg, self) result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) loc = result.end() ret = result return loc, ret def sub(self, repl: str) -> ParserElement: r""" Return :class:`Regex` with an attached parse action to transform the parsed result as if called using `re.sub(expr, repl, string) `_. Example: .. testcode:: make_html = Regex(r"(\w+):(.*?):").sub(r"<\1>\2") print(make_html.transform_string("h1:main title:")) .. testoutput::

main title

""" if self.asGroupList: raise TypeError("cannot use sub() with Regex(as_group_list=True)") if self.asMatch and callable(repl): raise TypeError( "cannot use sub() with a callable with Regex(as_match=True)" ) if self.asMatch: def pa(tokens): return tokens[0].expand(repl) else: def pa(tokens): return self.re.sub(repl, tokens[0]) return self.add_parse_action(pa) class QuotedString(Token): r""" Token for matching strings that are delimited by quoting characters. Defined with the following parameters: - ``quote_char`` - string of one or more characters defining the quote delimiting string - ``esc_char`` - character to re_escape quotes, typically backslash (default= ``None``) - ``esc_quote`` - special quote sequence to re_escape an embedded quote string (such as SQL's ``""`` to re_escape an embedded ``"``) (default= ``None``) - ``multiline`` - boolean indicating whether quotes can span multiple lines (default= ``False``) - ``unquote_results`` - boolean indicating whether the matched text should be unquoted (default= ``True``) - ``end_quote_char`` - string of one or more characters defining the end of the quote delimited string (default= ``None`` => same as quote_char) - ``convert_whitespace_escapes`` - convert escaped whitespace (``'\t'``, ``'\n'``, etc.) to actual whitespace (default= ``True``) .. caution:: ``convert_whitespace_escapes`` has no effect if ``unquote_results`` is ``False``. Example: .. doctest:: >>> qs = QuotedString('"') >>> print(qs.search_string('lsjdf "This is the quote" sldjf')) [['This is the quote']] >>> complex_qs = QuotedString('{{', end_quote_char='}}') >>> print(complex_qs.search_string( ... 'lsjdf {{This is the "quote"}} sldjf')) [['This is the "quote"']] >>> sql_qs = QuotedString('"', esc_quote='""') >>> print(sql_qs.search_string( ... 'lsjdf "This is the quote with ""embedded"" quotes" sldjf')) [['This is the quote with "embedded" quotes']] """ ws_map = dict(((r"\t", "\t"), (r"\n", "\n"), (r"\f", "\f"), (r"\r", "\r"))) def __init__( self, quote_char: str = "", esc_char: typing.Optional[str] = None, esc_quote: typing.Optional[str] = None, multiline: bool = False, unquote_results: bool = True, end_quote_char: typing.Optional[str] = None, convert_whitespace_escapes: bool = True, **kwargs, ) -> None: super().__init__() quoteChar: str = deprecate_argument(kwargs, "quoteChar", "") escChar: str = deprecate_argument(kwargs, "escChar", None) escQuote: str = deprecate_argument(kwargs, "escQuote", None) unquoteResults: bool = deprecate_argument(kwargs, "unquoteResults", True) endQuoteChar: typing.Optional[str] = deprecate_argument( kwargs, "endQuoteChar", None ) convertWhitespaceEscapes: bool = deprecate_argument( kwargs, "convertWhitespaceEscapes", True ) esc_char = escChar or esc_char esc_quote = escQuote or esc_quote unquote_results = unquoteResults and unquote_results end_quote_char = endQuoteChar or end_quote_char convert_whitespace_escapes = ( convertWhitespaceEscapes and convert_whitespace_escapes ) quote_char = quoteChar or quote_char # remove white space from quote chars quote_char = quote_char.strip() if not quote_char: raise ValueError("quote_char cannot be the empty string") if end_quote_char is None: end_quote_char = quote_char else: end_quote_char = end_quote_char.strip() if not end_quote_char: raise ValueError("end_quote_char cannot be the empty string") self.quote_char: str = quote_char self.quote_char_len: int = len(quote_char) self.first_quote_char: str = quote_char[0] self.end_quote_char: str = end_quote_char self.end_quote_char_len: int = len(end_quote_char) self.esc_char: str = esc_char or "" self.has_esc_char: bool = esc_char is not None self.esc_quote: str = esc_quote or "" self.unquote_results: bool = unquote_results self.convert_whitespace_escapes: bool = convert_whitespace_escapes self.multiline = multiline self.re_flags = re.RegexFlag(0) # fmt: off # build up re pattern for the content between the quote delimiters inner_pattern: list[str] = [] if esc_quote: inner_pattern.append(rf"(?:{re.escape(esc_quote)})") if esc_char: inner_pattern.append(rf"(?:{re.escape(esc_char)}.)") if len(self.end_quote_char) > 1: inner_pattern.append( "(?:" + "|".join( f"(?:{re.escape(self.end_quote_char[:i])}(?!{re.escape(self.end_quote_char[i:])}))" for i in range(len(self.end_quote_char) - 1, 0, -1) ) + ")" ) if self.multiline: self.re_flags |= re.MULTILINE | re.DOTALL inner_pattern.append( rf"(?:[^{_escape_regex_range_chars(self.end_quote_char[0])}" rf"{(_escape_regex_range_chars(self.esc_char) if self.has_esc_char else '')}])" ) else: inner_pattern.append( rf"(?:[^{_escape_regex_range_chars(self.end_quote_char[0])}\n\r" rf"{(_escape_regex_range_chars(self.esc_char) if self.has_esc_char else '')}])" ) self.pattern = "".join( [ re.escape(self.quote_char), "(?:", '|'.join(inner_pattern), ")*", re.escape(self.end_quote_char), ] ) if self.unquote_results: if self.convert_whitespace_escapes: self.unquote_scan_re = re.compile( rf"({'|'.join(re.escape(k) for k in self.ws_map)})" rf"|(\\[0-7]{3}|\\0|\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4})" rf"|({re.escape(self.esc_char)}.)" rf"|(\n|.)", flags=self.re_flags, ) else: self.unquote_scan_re = re.compile( rf"({re.escape(self.esc_char)}.)" rf"|(\n|.)", flags=self.re_flags ) # fmt: on try: self.re = re.compile(self.pattern, self.re_flags) self.reString = self.pattern self.re_match = self.re.match except re.error: raise ValueError(f"invalid pattern {self.pattern!r} passed to Regex") self.errmsg = f"Expected {self.name}" self.mayIndexError = False self._may_return_empty = True def _generateDefaultName(self) -> str: if self.quote_char == self.end_quote_char and isinstance( self.quote_char, str_type ): return f"string enclosed in {self.quote_char!r}" return f"quoted string, starting with {self.quote_char} ending with {self.end_quote_char}" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: # check first character of opening quote to see if that is a match # before doing the more complicated regex match result = ( instring[loc] == self.first_quote_char and self.re_match(instring, loc) or None ) if not result: raise ParseException(instring, loc, self.errmsg, self) # get ending loc and matched string from regex matching result loc = result.end() ret = result[0] if self.unquote_results: # strip off quotes ret = ret[self.quote_char_len : -self.end_quote_char_len] if isinstance(ret, str_type): # fmt: off if self.convert_whitespace_escapes: # as we iterate over matches in the input string, # collect from whichever match group of the unquote_scan_re # regex matches (only 1 group will match at any given time) ret = "".join( # match group 1 matches \t, \n, etc. self.ws_map[g] if (g := match[1]) # match group 2 matches escaped octal, null, hex, and Unicode # sequences else _convert_escaped_numerics_to_char(g[1:]) if (g := match[2]) # match group 3 matches escaped characters else g[-1] if (g := match[3]) # match group 4 matches any character else match[4] for match in self.unquote_scan_re.finditer(ret) ) else: ret = "".join( # match group 1 matches escaped characters g[-1] if (g := match[1]) # match group 2 matches any character else match[2] for match in self.unquote_scan_re.finditer(ret) ) # fmt: on # replace escaped quotes if self.esc_quote: ret = ret.replace(self.esc_quote, self.end_quote_char) return loc, ret class CharsNotIn(Token): """Token for matching words composed of characters *not* in a given set (will include whitespace in matched characters if not listed in the provided exclusion set - see example). Defined with string containing all disallowed characters, and an optional minimum, maximum, and/or exact length. The default value for ``min`` is 1 (a minimum value < 1 is not valid); the default values for ``max`` and ``exact`` are 0, meaning no maximum or exact length restriction. Example: .. testcode:: # define a comma-separated-value as anything that is not a ',' csv_value = CharsNotIn(',') print( DelimitedList(csv_value).parse_string( "dkls,lsdkjf,s12 34,@!#,213" ) ) prints: .. testoutput:: ['dkls', 'lsdkjf', 's12 34', '@!#', '213'] """ def __init__( self, not_chars: str = "", min: int = 1, max: int = 0, exact: int = 0, **kwargs ) -> None: super().__init__() notChars: str = deprecate_argument(kwargs, "notChars", "") self.skipWhitespace = False self.notChars = not_chars or notChars self.notCharsSet = set(self.notChars) if min < 1: raise ValueError( "cannot specify a minimum length < 1; use" " Opt(CharsNotIn()) if zero-length char group is permitted" ) self.minLen = min if max > 0: self.maxLen = max else: self.maxLen = _MAX_INT if exact > 0: self.maxLen = exact self.minLen = exact self.errmsg = f"Expected {self.name}" self._may_return_empty = self.minLen == 0 self.mayIndexError = False def _generateDefaultName(self) -> str: not_chars_str = _collapse_string_to_ranges(self.notChars) if len(not_chars_str) > 16: return f"!W:({self.notChars[: 16 - 3]}...)" else: return f"!W:({self.notChars})" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: notchars = self.notCharsSet if instring[loc] in notchars: raise ParseException(instring, loc, self.errmsg, self) start = loc loc += 1 maxlen = min(start + self.maxLen, len(instring)) while loc < maxlen and instring[loc] not in notchars: loc += 1 if loc - start < self.minLen: raise ParseException(instring, loc, self.errmsg, self) return loc, instring[start:loc] class White(Token): """Special matching class for matching whitespace. Normally, whitespace is ignored by pyparsing grammars. This class is included when some whitespace structures are significant. Define with a string containing the whitespace characters to be matched; default is ``" \\t\\r\\n"``. Also takes optional ``min``, ``max``, and ``exact`` arguments, as defined for the :class:`Word` class. """ whiteStrs = { " ": "", "\t": "", "\n": "", "\r": "", "\f": "", "\u00a0": "", "\u1680": "", "\u180e": "", "\u2000": "", "\u2001": "", "\u2002": "", "\u2003": "", "\u2004": "", "\u2005": "", "\u2006": "", "\u2007": "", "\u2008": "", "\u2009": "", "\u200a": "", "\u200b": "", "\u202f": "", "\u205f": "", "\u3000": "", } def __init__( self, ws: str = " \t\r\n", min: int = 1, max: int = 0, exact: int = 0 ) -> None: super().__init__() self.matchWhite = ws self.set_whitespace_chars( "".join(c for c in self.whiteStrs if c not in self.matchWhite), copy_defaults=True, ) # self.leave_whitespace() self._may_return_empty = True self.errmsg = f"Expected {self.name}" self.minLen = min if max > 0: self.maxLen = max else: self.maxLen = _MAX_INT if exact > 0: self.maxLen = exact self.minLen = exact def _generateDefaultName(self) -> str: return "".join(White.whiteStrs[c] for c in self.matchWhite) def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if instring[loc] not in self.matchWhite: raise ParseException(instring, loc, self.errmsg, self) start = loc loc += 1 maxloc = start + self.maxLen maxloc = min(maxloc, len(instring)) while loc < maxloc and instring[loc] in self.matchWhite: loc += 1 if loc - start < self.minLen: raise ParseException(instring, loc, self.errmsg, self) return loc, instring[start:loc] class PositionToken(Token): def __init__(self) -> None: super().__init__() self._may_return_empty = True self.mayIndexError = False class GoToColumn(PositionToken): """Token to advance to a specific column of input text; useful for tabular report scraping. """ def __init__(self, colno: int) -> None: super().__init__() self.col = colno def preParse(self, instring: str, loc: int) -> int: if col(loc, instring) == self.col: return loc instrlen = len(instring) if self.ignoreExprs: loc = self._skipIgnorables(instring, loc) while ( loc < instrlen and instring[loc].isspace() and col(loc, instring) != self.col ): loc += 1 return loc def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: thiscol = col(loc, instring) if thiscol > self.col: raise ParseException(instring, loc, "Text not in expected column", self) newloc = loc + self.col - thiscol ret = instring[loc:newloc] return newloc, ret class LineStart(PositionToken): r"""Matches if current position is at the logical beginning of a line (after skipping whitespace) within the parse string Example: .. testcode:: test = '''\ AAA this line AAA and this line AAA and even this line B AAA but definitely not this line ''' for t in (LineStart() + 'AAA' + rest_of_line).search_string(test): print(t) prints: .. testoutput:: ['AAA', ' this line'] ['AAA', ' and this line'] ['AAA', ' and even this line'] """ def __init__(self) -> None: super().__init__() self.leave_whitespace() self.orig_whiteChars = set() | self.whiteChars self.whiteChars.discard("\n") self.skipper = Empty().set_whitespace_chars(self.whiteChars) self.set_name("start of line") def preParse(self, instring: str, loc: int) -> int: if loc == 0: return loc ret = self.skipper.preParse(instring, loc) if "\n" in self.orig_whiteChars: while instring[ret : ret + 1] == "\n": ret = self.skipper.preParse(instring, ret + 1) return ret def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if col(loc, instring) == 1: return loc, [] raise ParseException(instring, loc, self.errmsg, self) class LineEnd(PositionToken): """Matches if current position is at the end of a line within the parse string """ def __init__(self) -> None: super().__init__() self.whiteChars.discard("\n") self.set_whitespace_chars(self.whiteChars, copy_defaults=False) self.set_name("end of line") def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if loc < len(instring): if instring[loc] == "\n": return loc + 1, "\n" else: raise ParseException(instring, loc, self.errmsg, self) elif loc == len(instring): return loc + 1, [] else: raise ParseException(instring, loc, self.errmsg, self) class StringStart(PositionToken): """Matches if current position is at the beginning of the parse string """ def __init__(self) -> None: super().__init__() self.set_name("start of text") def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: # see if entire string up to here is just whitespace and ignoreables if loc != 0 and loc != self.preParse(instring, 0): raise ParseException(instring, loc, self.errmsg, self) return loc, [] class StringEnd(PositionToken): """ Matches if current position is at the end of the parse string """ def __init__(self) -> None: super().__init__() self.set_name("end of text") def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if loc < len(instring): raise ParseException(instring, loc, self.errmsg, self) if loc == len(instring): return loc + 1, [] if loc > len(instring): return loc, [] raise ParseException(instring, loc, self.errmsg, self) class WordStart(PositionToken): """Matches if the current position is at the beginning of a :class:`Word`, and is not preceded by any character in a given set of ``word_chars`` (default= ``printables``). To emulate the ``\b`` behavior of regular expressions, use ``WordStart(alphanums)``. ``WordStart`` will also match at the beginning of the string being parsed, or at the beginning of a line. """ def __init__(self, word_chars: str = printables, **kwargs) -> None: wordChars: str = deprecate_argument(kwargs, "wordChars", printables) wordChars = word_chars if wordChars == printables else wordChars super().__init__() self.wordChars = set(wordChars) self.set_name("start of a word") def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if loc != 0: if ( instring[loc - 1] in self.wordChars or instring[loc] not in self.wordChars ): raise ParseException(instring, loc, self.errmsg, self) return loc, [] class WordEnd(PositionToken): """Matches if the current position is at the end of a :class:`Word`, and is not followed by any character in a given set of ``word_chars`` (default= ``printables``). To emulate the ``\b`` behavior of regular expressions, use ``WordEnd(alphanums)``. ``WordEnd`` will also match at the end of the string being parsed, or at the end of a line. """ def __init__(self, word_chars: str = printables, **kwargs) -> None: wordChars: str = deprecate_argument(kwargs, "wordChars", printables) wordChars = word_chars if wordChars == printables else wordChars super().__init__() self.wordChars = set(wordChars) self.skipWhitespace = False self.set_name("end of a word") def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: instrlen = len(instring) if instrlen > 0 and loc < instrlen: if ( instring[loc] in self.wordChars or instring[loc - 1] not in self.wordChars ): raise ParseException(instring, loc, self.errmsg, self) return loc, [] class Tag(Token): """ A meta-element for inserting a named result into the parsed tokens that may be checked later in a parse action or while processing the parsed results. Accepts an optional tag value, defaulting to `True`. Example: .. doctest:: >>> end_punc = "." | ("!" + Tag("enthusiastic")) >>> greeting = "Hello," + Word(alphas) + end_punc >>> result = greeting.parse_string("Hello, World.") >>> print(result.dump()) ['Hello,', 'World', '.'] >>> result = greeting.parse_string("Hello, World!") >>> print(result.dump()) ['Hello,', 'World', '!'] - enthusiastic: True .. versionadded:: 3.1.0 """ def __init__(self, tag_name: str, value: Any = True) -> None: super().__init__() self._may_return_empty = True self.mayIndexError = False self.leave_whitespace() self.tag_name = tag_name self.tag_value = value self.add_parse_action(self._add_tag) self.show_in_diagram = False def _add_tag(self, tokens: ParseResults): tokens[self.tag_name] = self.tag_value def _generateDefaultName(self) -> str: return f"{type(self).__name__}:{self.tag_name}={self.tag_value!r}" class ParseExpression(ParserElement): """Abstract subclass of ParserElement, for combining and post-processing parsed tokens. """ def __init__( self, exprs: typing.Iterable[ParserElement], savelist: bool = False ) -> None: super().__init__(savelist) self.exprs: list[ParserElement] if isinstance(exprs, _generatorType): exprs = list(exprs) if isinstance(exprs, str_type): self.exprs = [self._literalStringClass(exprs)] elif isinstance(exprs, ParserElement): self.exprs = [exprs] elif isinstance(exprs, Iterable): exprs = list(exprs) # if sequence of strings provided, wrap with Literal if any(isinstance(expr, str_type) for expr in exprs): exprs = ( self._literalStringClass(e) if isinstance(e, str_type) else e for e in exprs ) self.exprs = list(exprs) else: try: self.exprs = list(exprs) except TypeError: self.exprs = [exprs] self.callPreparse = False def recurse(self) -> list[ParserElement]: return self.exprs[:] def append(self, other) -> ParserElement: """ Add an expression to the list of expressions related to this ParseExpression instance. """ self.exprs.append(other) self._defaultName = None return self def leave_whitespace(self, recursive: bool = True) -> ParserElement: """ Extends ``leave_whitespace`` defined in base class, and also invokes ``leave_whitespace`` on all contained expressions. """ super().leave_whitespace(recursive) if recursive: self.exprs = [e.copy() for e in self.exprs] for e in self.exprs: e.leave_whitespace(recursive) return self def ignore_whitespace(self, recursive: bool = True) -> ParserElement: """ Extends ``ignore_whitespace`` defined in base class, and also invokes ``ignore_whitespace`` on all contained expressions. """ super().ignore_whitespace(recursive) if recursive: self.exprs = [e.copy() for e in self.exprs] for e in self.exprs: e.ignore_whitespace(recursive) return self def ignore(self, other) -> ParserElement: """ Define expression to be ignored (e.g., comments) while doing pattern matching; may be called repeatedly, to define multiple comment or other ignorable patterns. """ if isinstance(other, Suppress): if other not in self.ignoreExprs: super().ignore(other) for e in self.exprs: e.ignore(self.ignoreExprs[-1]) else: super().ignore(other) for e in self.exprs: e.ignore(self.ignoreExprs[-1]) return self def _generateDefaultName(self) -> str: return f"{type(self).__name__}:({self.exprs})" def streamline(self) -> ParserElement: if self.streamlined: return self super().streamline() for e in self.exprs: e.streamline() # collapse nested :class:`And`'s of the form ``And(And(And(a, b), c), d)`` to ``And(a, b, c, d)`` # but only if there are no parse actions or resultsNames on the nested And's # (likewise for :class:`Or`'s and :class:`MatchFirst`'s) if len(self.exprs) == 2: other = self.exprs[0] if ( isinstance(other, self.__class__) and not other.parseAction and other.resultsName is None and not other.debug ): self.exprs = other.exprs[:] + [self.exprs[1]] self._defaultName = None self._may_return_empty |= other.mayReturnEmpty self.mayIndexError |= other.mayIndexError other = self.exprs[-1] if ( isinstance(other, self.__class__) and not other.parseAction and other.resultsName is None and not other.debug ): self.exprs = self.exprs[:-1] + other.exprs[:] self._defaultName = None self._may_return_empty |= other.mayReturnEmpty self.mayIndexError |= other.mayIndexError self.errmsg = f"Expected {self}" return self def validate(self, validateTrace=None) -> None: warnings.warn( "ParserElement.validate() is deprecated, and should not be used to check for left recursion", PyparsingDeprecationWarning, stacklevel=2, ) tmp = (validateTrace if validateTrace is not None else [])[:] + [self] for e in self.exprs: e.validate(tmp) self._checkRecursion([]) def copy(self) -> ParserElement: """ Returns a copy of this expression. Generally only used internally by pyparsing. """ ret = super().copy() ret = typing.cast(ParseExpression, ret) ret.exprs = [e.copy() for e in self.exprs] return ret def _setResultsName(self, name, list_all_matches=False) -> ParserElement: if not ( __diag__.warn_ungrouped_named_tokens_in_collection and Diagnostics.warn_ungrouped_named_tokens_in_collection not in self.suppress_warnings_ ): return super()._setResultsName(name, list_all_matches) for e in self.exprs: if ( isinstance(e, ParserElement) and e.resultsName and ( Diagnostics.warn_ungrouped_named_tokens_in_collection not in e.suppress_warnings_ ) ): warning = ( "warn_ungrouped_named_tokens_in_collection:" f" setting results name {name!r} on {type(self).__name__} expression" f" collides with {e.resultsName!r} on contained expression" ) warnings.warn(warning, PyparsingDiagnosticWarning, stacklevel=3) break return super()._setResultsName(name, list_all_matches) # Compatibility synonyms # fmt: off leaveWhitespace = replaced_by_pep8("leaveWhitespace", leave_whitespace) ignoreWhitespace = replaced_by_pep8("ignoreWhitespace", ignore_whitespace) # fmt: on class And(ParseExpression): """ Requires all given :class:`ParserElement` s to be found in the given order. Expressions may be separated by whitespace. May be constructed using the ``'+'`` operator. May also be constructed using the ``'-'`` operator, which will suppress backtracking. Example: .. testcode:: integer = Word(nums) name_expr = Word(alphas)[1, ...] expr = And([integer("id"), name_expr("name"), integer("age")]) # more easily written as: expr = integer("id") + name_expr("name") + integer("age") """ class _ErrorStop(Empty): def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.leave_whitespace() def _generateDefaultName(self) -> str: return "-" def __init__( self, exprs_arg: typing.Iterable[Union[ParserElement, str]], savelist: bool = True, ) -> None: # instantiate exprs as a list, converting strs to ParserElements exprs: list[ParserElement] = [ self._literalStringClass(e) if isinstance(e, str) else e for e in exprs_arg ] # convert any Ellipsis elements to SkipTo if Ellipsis in exprs: # Ellipsis cannot be the last element if exprs[-1] is Ellipsis: raise Exception("cannot construct And with sequence ending in ...") tmp: list[ParserElement] = [] for cur_expr, next_expr in zip(exprs, exprs[1:]): if cur_expr is Ellipsis: tmp.append(SkipTo(next_expr)("_skipped*")) else: tmp.append(cur_expr) exprs[:-1] = tmp super().__init__(exprs, savelist) if self.exprs: self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) if not isinstance(self.exprs[0], White): self.set_whitespace_chars( self.exprs[0].whiteChars, copy_defaults=self.exprs[0].copyDefaultWhiteChars, ) self.skipWhitespace = self.exprs[0].skipWhitespace else: self.skipWhitespace = False else: self._may_return_empty = True self.callPreparse = True def streamline(self) -> ParserElement: """ Collapse `And` expressions like `And(And(And(A, B), C), D)` to `And(A, B, C, D)`. .. doctest:: >>> expr = Word("A") + Word("B") + Word("C") + Word("D") >>> # Using '+' operator creates nested And expression >>> expr {{{W:(A) W:(B)} W:(C)} W:(D)} >>> # streamline simplifies to a single And with multiple expressions >>> expr.streamline() {W:(A) W:(B) W:(C) W:(D)} Guards against collapsing out expressions that have special features, such as results names or parse actions. Resolves pending Skip commands defined using `...` terms. """ # collapse any _PendingSkip's if self.exprs and any( isinstance(e, ParseExpression) and e.exprs and isinstance(e.exprs[-1], _PendingSkip) for e in self.exprs[:-1] ): deleted_expr_marker = NoMatch() for i, e in enumerate(self.exprs[:-1]): if e is deleted_expr_marker: continue if ( isinstance(e, ParseExpression) and e.exprs and isinstance(e.exprs[-1], _PendingSkip) ): e.exprs[-1] = e.exprs[-1] + self.exprs[i + 1] self.exprs[i + 1] = deleted_expr_marker self.exprs = [e for e in self.exprs if e is not deleted_expr_marker] super().streamline() # link any IndentedBlocks to the prior expression prev: ParserElement cur: ParserElement for prev, cur in zip(self.exprs, self.exprs[1:]): # traverse cur or any first embedded expr of cur looking for an IndentedBlock # (but watch out for recursive grammar) seen = set() while True: if id(cur) in seen: break seen.add(id(cur)) if isinstance(cur, IndentedBlock): prev.add_parse_action( lambda s, l, t, cur_=cur: setattr( cur_, "parent_anchor", col(l, s) ) ) break subs = cur.recurse() next_first = next(iter(subs), None) if next_first is None: break cur = typing.cast(ParserElement, next_first) self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) return self def parseImpl(self, instring, loc, do_actions=True): # pass False as callPreParse arg to _parse for first element, since we already # pre-parsed the string as part of our And pre-parsing loc, resultlist = self.exprs[0]._parse( instring, loc, do_actions, callPreParse=False ) errorStop = False for e in self.exprs[1:]: # if isinstance(e, And._ErrorStop): if type(e) is And._ErrorStop: errorStop = True continue if errorStop: try: loc, exprtokens = e._parse(instring, loc, do_actions) except ParseSyntaxException: raise except ParseBaseException as pe: pe.__traceback__ = None raise ParseSyntaxException._from_exception(pe) except IndexError: raise ParseSyntaxException( instring, len(instring), self.errmsg, self ) else: loc, exprtokens = e._parse(instring, loc, do_actions) resultlist += exprtokens return loc, resultlist def __iadd__(self, other): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return self.append(other) # And([self, other]) def _checkRecursion(self, parseElementList): subRecCheckList = parseElementList[:] + [self] for e in self.exprs: e._checkRecursion(subRecCheckList) if not e.mayReturnEmpty: break def _generateDefaultName(self) -> str: inner = " ".join(str(e) for e in self.exprs) # strip off redundant inner {}'s while len(inner) > 1 and inner[0 :: len(inner) - 1] == "{}": inner = inner[1:-1] return f"{{{inner}}}" class Or(ParseExpression): """Requires that at least one :class:`ParserElement` is found. If two expressions match, the expression that matches the longest string will be used. May be constructed using the ``'^'`` operator. Example: .. testcode:: # construct Or using '^' operator number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums)) print(number.search_string("123 3.1416 789")) prints: .. testoutput:: [['123'], ['3.1416'], ['789']] """ def __init__( self, exprs: typing.Iterable[ParserElement], savelist: bool = False ) -> None: super().__init__(exprs, savelist) if self.exprs: self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.skipWhitespace = all(e.skipWhitespace for e in self.exprs) else: self._may_return_empty = True def streamline(self) -> ParserElement: super().streamline() if self.exprs: self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.saveAsList = any(e.saveAsList for e in self.exprs) self.skipWhitespace = all( e.skipWhitespace and not isinstance(e, White) for e in self.exprs ) else: self.saveAsList = False return self def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: maxExcLoc = -1 maxException = None matches: list[tuple[int, ParserElement]] = [] fatals: list[ParseFatalException] = [] if all(e.callPreparse for e in self.exprs): loc = self.preParse(instring, loc) for e in self.exprs: try: loc2 = e.try_parse(instring, loc, raise_fatal=True) except ParseFatalException as pfe: pfe.__traceback__ = None pfe.parser_element = e fatals.append(pfe) maxException = None maxExcLoc = -1 except ParseException as err: if not fatals: err.__traceback__ = None if err.loc > maxExcLoc: maxException = err maxExcLoc = err.loc except IndexError: if len(instring) > maxExcLoc: maxException = ParseException( instring, len(instring), e.errmsg, self ) maxExcLoc = len(instring) else: # save match among all matches, to retry longest to shortest matches.append((loc2, e)) if matches: # re-evaluate all matches in descending order of length of match, in case attached actions # might change whether or how much they match of the input. matches.sort(key=itemgetter(0), reverse=True) if not do_actions: # no further conditions or parse actions to change the selection of # alternative, so the first match will be the best match best_expr = matches[0][1] return best_expr._parse(instring, loc, do_actions) longest: tuple[int, typing.Optional[ParseResults]] = -1, None for loc1, expr1 in matches: if loc1 <= longest[0]: # already have a longer match than this one will deliver, we are done return longest try: loc2, toks = expr1._parse(instring, loc, do_actions) except ParseException as err: err.__traceback__ = None if err.loc > maxExcLoc: maxException = err maxExcLoc = err.loc else: if loc2 >= loc1: return loc2, toks # didn't match as much as before elif loc2 > longest[0]: longest = loc2, toks if longest != (-1, None): return longest if fatals: if len(fatals) > 1: fatals.sort(key=lambda e: -e.loc) if fatals[0].loc == fatals[1].loc: fatals.sort(key=lambda e: (-e.loc, -len(str(e.parser_element)))) max_fatal = fatals[0] raise max_fatal if maxException is not None: # infer from this check that all alternatives failed at the current position # so emit this collective error message instead of any single error message parse_start_loc = self.preParse(instring, loc) if maxExcLoc == parse_start_loc: maxException.msg = self.errmsg or "" raise maxException raise ParseException(instring, loc, "no defined alternatives to match", self) def __ixor__(self, other): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return self.append(other) # Or([self, other]) def _generateDefaultName(self) -> str: return f"{{{' ^ '.join(str(e) for e in self.exprs)}}}" def _setResultsName(self, name, list_all_matches=False) -> ParserElement: if ( __diag__.warn_multiple_tokens_in_named_alternation and Diagnostics.warn_multiple_tokens_in_named_alternation not in self.suppress_warnings_ ): if any( isinstance(e, And) and Diagnostics.warn_multiple_tokens_in_named_alternation not in e.suppress_warnings_ for e in self.exprs ): warning = ( "warn_multiple_tokens_in_named_alternation:" f" setting results name {name!r} on {type(self).__name__} expression" " will return a list of all parsed tokens in an And alternative," " in prior versions only the first token was returned; enclose" " contained argument in Group" ) warnings.warn(warning, PyparsingDiagnosticWarning, stacklevel=3) return super()._setResultsName(name, list_all_matches) class MatchFirst(ParseExpression): """Requires that at least one :class:`ParserElement` is found. If more than one expression matches, the first one listed is the one that will match. May be constructed using the ``'|'`` operator. Example: Construct MatchFirst using '|' operator .. doctest:: # watch the order of expressions to match >>> number = Word(nums) | Combine(Word(nums) + '.' + Word(nums)) >>> print(number.search_string("123 3.1416 789")) # Fail! [['123'], ['3'], ['1416'], ['789']] # put more selective expression first >>> number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums) >>> print(number.search_string("123 3.1416 789")) # Better [['123'], ['3.1416'], ['789']] """ def __init__( self, exprs: typing.Iterable[ParserElement], savelist: bool = False ) -> None: super().__init__(exprs, savelist) if self.exprs: self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.skipWhitespace = all(e.skipWhitespace for e in self.exprs) else: self._may_return_empty = True def streamline(self) -> ParserElement: if self.streamlined: return self super().streamline() if self.exprs: self.saveAsList = any(e.saveAsList for e in self.exprs) self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.skipWhitespace = all( e.skipWhitespace and not isinstance(e, White) for e in self.exprs ) else: self.saveAsList = False self._may_return_empty = True return self def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: maxExcLoc = -1 maxException = None for e in self.exprs: try: return e._parse(instring, loc, do_actions) except ParseFatalException as pfe: pfe.__traceback__ = None pfe.parser_element = e raise except ParseException as err: if err.loc > maxExcLoc: maxException = err maxExcLoc = err.loc except IndexError: if len(instring) > maxExcLoc: maxException = ParseException( instring, len(instring), e.errmsg, self ) maxExcLoc = len(instring) if maxException is not None: # infer from this check that all alternatives failed at the current position # so emit this collective error message instead of any individual error message parse_start_loc = self.preParse(instring, loc) if maxExcLoc == parse_start_loc: maxException.msg = self.errmsg or "" raise maxException raise ParseException(instring, loc, "no defined alternatives to match", self) def __ior__(self, other): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return self.append(other) # MatchFirst([self, other]) def _generateDefaultName(self) -> str: return f"{{{' | '.join(str(e) for e in self.exprs)}}}" def _setResultsName(self, name, list_all_matches=False) -> ParserElement: if ( __diag__.warn_multiple_tokens_in_named_alternation and Diagnostics.warn_multiple_tokens_in_named_alternation not in self.suppress_warnings_ ): if any( isinstance(e, And) and Diagnostics.warn_multiple_tokens_in_named_alternation not in e.suppress_warnings_ for e in self.exprs ): warning = ( "warn_multiple_tokens_in_named_alternation:" f" setting results name {name!r} on {type(self).__name__} expression" " will return a list of all parsed tokens in an And alternative," " in prior versions only the first token was returned; enclose" " contained argument in Group" ) warnings.warn(warning, PyparsingDiagnosticWarning, stacklevel=3) return super()._setResultsName(name, list_all_matches) class Each(ParseExpression): """Requires all given :class:`ParserElement` s to be found, but in any order. Expressions may be separated by whitespace. May be constructed using the ``'&'`` operator. Example: .. testcode:: color = one_of("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN") shape_type = one_of("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON") integer = Word(nums) shape_attr = "shape:" + shape_type("shape") posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn") color_attr = "color:" + color("color") size_attr = "size:" + integer("size") # use Each (using operator '&') to accept attributes in any order # (shape and posn are required, color and size are optional) shape_spec = shape_attr & posn_attr & Opt(color_attr) & Opt(size_attr) shape_spec.run_tests(''' shape: SQUARE color: BLACK posn: 100, 120 shape: CIRCLE size: 50 color: BLUE posn: 50,80 color:GREEN size:20 shape:TRIANGLE posn:20,40 ''' ) prints: .. testoutput:: :options: +NORMALIZE_WHITESPACE shape: SQUARE color: BLACK posn: 100, 120 ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']] - color: 'BLACK' - posn: ['100', ',', '120'] - x: '100' - y: '120' - shape: 'SQUARE' ... shape: CIRCLE size: 50 color: BLUE posn: 50,80 ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']] - color: 'BLUE' - posn: ['50', ',', '80'] - x: '50' - y: '80' - shape: 'CIRCLE' - size: '50' ... color:GREEN size:20 shape:TRIANGLE posn:20,40 ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']] - color: 'GREEN' - posn: ['20', ',', '40'] - x: '20' - y: '40' - shape: 'TRIANGLE' - size: '20' ... """ def __init__( self, exprs: typing.Iterable[ParserElement], savelist: bool = True ) -> None: super().__init__(exprs, savelist) if self.exprs: self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) else: self._may_return_empty = True self.skipWhitespace = True self.initExprGroups = True self.saveAsList = True def __iand__(self, other): if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented return self.append(other) # Each([self, other]) def streamline(self) -> ParserElement: super().streamline() if self.exprs: self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) else: self._may_return_empty = True return self def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if self.initExprGroups: self.opt1map = dict( (id(e.expr), e) for e in self.exprs if isinstance(e, Opt) ) opt1 = [e.expr for e in self.exprs if isinstance(e, Opt)] opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e, (Opt, Regex, ZeroOrMore)) ] self.optionals = opt1 + opt2 self.multioptionals = [ e.expr.set_results_name(e.resultsName, list_all_matches=True) for e in self.exprs if isinstance(e, _MultipleMatch) ] self.multirequired = [ e.expr.set_results_name(e.resultsName, list_all_matches=True) for e in self.exprs if isinstance(e, OneOrMore) ] self.required = [ e for e in self.exprs if not isinstance(e, (Opt, ZeroOrMore, OneOrMore)) ] self.required += self.multirequired self.initExprGroups = False tmpLoc = loc tmpReqd = self.required[:] tmpOpt = self.optionals[:] multis = self.multioptionals[:] matchOrder: list[ParserElement] = [] keepMatching = True failed: list[ParserElement] = [] fatals: list[ParseFatalException] = [] while keepMatching: tmpExprs = tmpReqd + tmpOpt + multis failed.clear() fatals.clear() for e in tmpExprs: try: tmpLoc = e.try_parse(instring, tmpLoc, raise_fatal=True) except ParseFatalException as pfe: pfe.__traceback__ = None pfe.parser_element = e fatals.append(pfe) failed.append(e) except ParseException: failed.append(e) else: matchOrder.append(self.opt1map.get(id(e), e)) if e in tmpReqd: tmpReqd.remove(e) elif e in tmpOpt: tmpOpt.remove(e) if len(failed) == len(tmpExprs): keepMatching = False # look for any ParseFatalExceptions if fatals: if len(fatals) > 1: fatals.sort(key=lambda e: -e.loc) if fatals[0].loc == fatals[1].loc: fatals.sort(key=lambda e: (-e.loc, -len(str(e.parser_element)))) max_fatal = fatals[0] raise max_fatal if tmpReqd: missing = ", ".join([str(e) for e in tmpReqd]) raise ParseException( instring, loc, f"Missing one or more required elements ({missing})", ) # add any unmatched Opts, in case they have default values defined matchOrder += [e for e in self.exprs if isinstance(e, Opt) and e.expr in tmpOpt] total_results = ParseResults([]) for e in matchOrder: loc, results = e._parse(instring, loc, do_actions) total_results += results return loc, total_results def _generateDefaultName(self) -> str: return f"{{{' & '.join(str(e) for e in self.exprs)}}}" class ParseElementEnhance(ParserElement): """Abstract subclass of :class:`ParserElement`, for combining and post-processing parsed tokens. """ def __init__(self, expr: Union[ParserElement, str], savelist: bool = False) -> None: super().__init__(savelist) if isinstance(expr, str_type): expr_str = typing.cast(str, expr) if issubclass(self._literalStringClass, Token): expr = self._literalStringClass(expr_str) # type: ignore[call-arg] elif issubclass(type(self), self._literalStringClass): expr = Literal(expr_str) else: expr = self._literalStringClass(Literal(expr_str)) # type: ignore[assignment, call-arg] expr = typing.cast(ParserElement, expr) self.expr = expr if expr is not None: self.mayIndexError = expr.mayIndexError self._may_return_empty = expr.mayReturnEmpty self.set_whitespace_chars( expr.whiteChars, copy_defaults=expr.copyDefaultWhiteChars ) self.skipWhitespace = expr.skipWhitespace self.saveAsList = expr.saveAsList self.callPreparse = expr.callPreparse self.ignoreExprs.extend(expr.ignoreExprs) def recurse(self) -> list[ParserElement]: return [self.expr] if self.expr is not None else [] def parseImpl(self, instring, loc, do_actions=True): if self.expr is None: raise ParseException(instring, loc, "No expression defined", self) try: return self.expr._parse(instring, loc, do_actions, callPreParse=False) except ParseSyntaxException: raise except ParseBaseException as pbe: pbe.pstr = pbe.pstr or instring pbe.loc = pbe.loc or loc pbe.parser_element = pbe.parser_element or self if not isinstance(self, Forward) and self.customName is not None: if self.errmsg: pbe.msg = self.errmsg raise def leave_whitespace(self, recursive: bool = True) -> ParserElement: """ Extends ``leave_whitespace`` defined in base class, and also invokes ``leave_whitespace`` on the contained expression. """ super().leave_whitespace(recursive) if recursive: if self.expr is not None: self.expr = self.expr.copy() self.expr.leave_whitespace(recursive) return self def ignore_whitespace(self, recursive: bool = True) -> ParserElement: """ Extends ``ignore_whitespace`` defined in base class, and also invokes ``ignore_whitespace`` on the contained expression. """ super().ignore_whitespace(recursive) if recursive: if self.expr is not None: self.expr = self.expr.copy() self.expr.ignore_whitespace(recursive) return self def ignore(self, other) -> ParserElement: """ Define expression to be ignored (e.g., comments) while doing pattern matching; may be called repeatedly, to define multiple comment or other ignorable patterns. """ if not isinstance(other, Suppress) or other not in self.ignoreExprs: super().ignore(other) if self.expr is not None: self.expr.ignore(self.ignoreExprs[-1]) return self def streamline(self) -> ParserElement: super().streamline() if self.expr is not None: self.expr.streamline() return self def _checkRecursion(self, parseElementList): if self in parseElementList: raise RecursiveGrammarException(parseElementList + [self]) subRecCheckList = parseElementList[:] + [self] if self.expr is not None: self.expr._checkRecursion(subRecCheckList) def validate(self, validateTrace=None) -> None: warnings.warn( "ParserElement.validate() is deprecated, and should not be used to check for left recursion", PyparsingDeprecationWarning, stacklevel=2, ) if validateTrace is None: validateTrace = [] tmp = validateTrace[:] + [self] if self.expr is not None: self.expr.validate(tmp) self._checkRecursion([]) def _generateDefaultName(self) -> str: return f"{type(self).__name__}:({self.expr})" # Compatibility synonyms # fmt: off leaveWhitespace = replaced_by_pep8("leaveWhitespace", leave_whitespace) ignoreWhitespace = replaced_by_pep8("ignoreWhitespace", ignore_whitespace) # fmt: on class IndentedBlock(ParseElementEnhance): """ Expression to match one or more expressions at a given indentation level. Useful for parsing text where structure is implied by indentation (like Python source code). Example: .. testcode:: ''' BNF: statement ::= assignment_stmt | if_stmt assignment_stmt ::= identifier '=' rvalue rvalue ::= identifier | integer if_stmt ::= 'if' bool_condition block block ::= ([indent] statement)... identifier ::= [A..Za..z] integer ::= [0..9]... bool_condition ::= 'TRUE' | 'FALSE' ''' IF, TRUE, FALSE = Keyword.using_each("IF TRUE FALSE".split()) statement = Forward() identifier = Char(alphas) integer = Word(nums).add_parse_action(lambda t: int(t[0])) rvalue = identifier | integer assignment_stmt = identifier + "=" + rvalue if_stmt = IF + (TRUE | FALSE) + IndentedBlock(statement) statement <<= Group(assignment_stmt | if_stmt) result = if_stmt.parse_string(''' IF TRUE a = 1000 b = 2000 IF FALSE z = 100 ''') print(result.dump()) .. testoutput:: ['IF', 'TRUE', [['a', '=', 1000], ['b', '=', 2000], ['IF', 'FALSE', [['z', '=', 100]]]]] [0]: IF [1]: TRUE [2]: [['a', '=', 1000], ['b', '=', 2000], ['IF', 'FALSE', [['z', '=', 100]]]] [0]: ['a', '=', 1000] [1]: ['b', '=', 2000] [2]: ['IF', 'FALSE', [['z', '=', 100]]] [0]: IF [1]: FALSE [2]: [['z', '=', 100]] [0]: ['z', '=', 100] """ class _Indent(Empty): def __init__(self, ref_col: int) -> None: super().__init__() self.errmsg = f"expected indent at column {ref_col}" self.add_condition(lambda s, l, t: col(l, s) == ref_col) class _IndentGreater(Empty): def __init__(self, ref_col: int) -> None: super().__init__() self.errmsg = f"expected indent at column greater than {ref_col}" self.add_condition(lambda s, l, t: col(l, s) > ref_col) def __init__( self, expr: ParserElement, *, recursive: bool = False, grouped: bool = True ) -> None: super().__init__(expr, savelist=True) # if recursive: # raise NotImplementedError("IndentedBlock with recursive is not implemented") self._recursive = recursive self._grouped = grouped self.parent_anchor = 1 def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: # advance parse position to non-whitespace by using an Empty() # this should be the column to be used for all subsequent indented lines anchor_loc = Empty().preParse(instring, loc) # see if self.expr matches at the current location - if not it will raise an exception # and no further work is necessary self.expr.try_parse(instring, anchor_loc, do_actions=do_actions) indent_col = col(anchor_loc, instring) peer_detect_expr = self._Indent(indent_col) inner_expr = Empty() + peer_detect_expr + self.expr if self._recursive: sub_indent = self._IndentGreater(indent_col) nested_block = IndentedBlock( self.expr, recursive=self._recursive, grouped=self._grouped ) nested_block.set_debug(self.debug) nested_block.parent_anchor = indent_col inner_expr += Opt(sub_indent + nested_block) inner_expr.set_name(f"inner {hex(id(inner_expr))[-4:].upper()}@{indent_col}") block = OneOrMore(inner_expr) trailing_undent = self._Indent(self.parent_anchor) | StringEnd() if self._grouped: wrapper = Group else: wrapper = lambda expr: expr # type: ignore[misc, assignment] return (wrapper(block) + Optional(trailing_undent)).parseImpl( instring, anchor_loc, do_actions ) class AtStringStart(ParseElementEnhance): """Matches if expression matches at the beginning of the parse string:: AtStringStart(Word(nums)).parse_string("123") # prints ["123"] AtStringStart(Word(nums)).parse_string(" 123") # raises ParseException """ def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) self.callPreparse = False def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if loc != 0: raise ParseException(instring, loc, "not found at string start") return super().parseImpl(instring, loc, do_actions) class AtLineStart(ParseElementEnhance): r"""Matches if an expression matches at the beginning of a line within the parse string Example: .. testcode:: test = '''\ BBB this line BBB and this line BBB but not this one A BBB and definitely not this one ''' for t in (AtLineStart('BBB') + rest_of_line).search_string(test): print(t) prints: .. testoutput:: ['BBB', ' this line'] ['BBB', ' and this line'] """ def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) self.callPreparse = False def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if col(loc, instring) != 1: raise ParseException(instring, loc, "not found at line start") return super().parseImpl(instring, loc, do_actions) class FollowedBy(ParseElementEnhance): """Lookahead matching of the given parse expression. ``FollowedBy`` does *not* advance the parsing position within the input string, it only verifies that the specified parse expression matches at the current position. ``FollowedBy`` always returns a null token list. If any results names are defined in the lookahead expression, those *will* be returned for access by name. Example: .. testcode:: # use FollowedBy to match a label only if it is followed by a ':' data_word = Word(alphas) label = data_word + FollowedBy(':') attr_expr = Group( label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join) ) attr_expr[1, ...].parse_string( "shape: SQUARE color: BLACK posn: upper left").pprint() prints: .. testoutput:: [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] """ def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) self._may_return_empty = True def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: # by using self._expr.parse and deleting the contents of the returned ParseResults list # we keep any named results that were defined in the FollowedBy expression _, ret = self.expr._parse(instring, loc, do_actions=do_actions) del ret[:] return loc, ret class PrecededBy(ParseElementEnhance): """Lookbehind matching of the given parse expression. ``PrecededBy`` does not advance the parsing position within the input string, it only verifies that the specified parse expression matches prior to the current position. ``PrecededBy`` always returns a null token list, but if a results name is defined on the given expression, it is returned. Parameters: - ``expr`` - expression that must match prior to the current parse location - ``retreat`` - (default= ``None``) - (int) maximum number of characters to lookbehind prior to the current parse location If the lookbehind expression is a string, :class:`Literal`, :class:`Keyword`, or a :class:`Word` or :class:`CharsNotIn` with a specified exact or maximum length, then the retreat parameter is not required. Otherwise, retreat must be specified to give a maximum number of characters to look back from the current parse position for a lookbehind match. Example: .. testcode:: # VB-style variable names with type prefixes int_var = PrecededBy("#") + pyparsing_common.identifier str_var = PrecededBy("$") + pyparsing_common.identifier """ def __init__(self, expr: Union[ParserElement, str], retreat: int = 0) -> None: super().__init__(expr) self.expr = self.expr().leave_whitespace() self._may_return_empty = True self.mayIndexError = False self.exact = False if isinstance(expr, str_type): expr = typing.cast(str, expr) retreat = len(expr) self.exact = True elif isinstance(expr, (Literal, Keyword)): retreat = expr.matchLen self.exact = True elif isinstance(expr, (Word, CharsNotIn)) and expr.maxLen != _MAX_INT: retreat = expr.maxLen self.exact = True elif isinstance(expr, PositionToken): retreat = 0 self.exact = True self.retreat = retreat self.errmsg = f"not preceded by {expr}" self.skipWhitespace = False self.parseAction.append(lambda s, l, t: t.__delitem__(slice(None, None))) def parseImpl(self, instring, loc=0, do_actions=True) -> ParseImplReturnType: if self.exact: if loc < self.retreat: raise ParseException(instring, loc, self.errmsg, self) start = loc - self.retreat _, ret = self.expr._parse(instring, start) return loc, ret # retreat specified a maximum lookbehind window, iterate test_expr = self.expr + StringEnd() instring_slice = instring[max(0, loc - self.retreat) : loc] last_expr: ParseBaseException = ParseException(instring, loc, self.errmsg, self) for offset in range(1, min(loc, self.retreat + 1) + 1): try: # print('trying', offset, instring_slice, repr(instring_slice[loc - offset:])) _, ret = test_expr._parse(instring_slice, len(instring_slice) - offset) except ParseBaseException as pbe: last_expr = pbe else: break else: raise last_expr return loc, ret class Located(ParseElementEnhance): """ Decorates a returned token with its starting and ending locations in the input string. This helper adds the following results names: - ``locn_start`` - location where matched expression begins - ``locn_end`` - location where matched expression ends - ``value`` - the actual parsed results Be careful if the input text contains ```` characters, you may want to call :class:`ParserElement.parse_with_tabs` Example: .. testcode:: wd = Word(alphas) for match in Located(wd).search_string("ljsdf123lksdjjf123lkkjj1222"): print(match) prints: .. testoutput:: [0, ['ljsdf'], 5] [8, ['lksdjjf'], 15] [18, ['lkkjj'], 23] """ def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: start = loc loc, tokens = self.expr._parse(instring, start, do_actions, callPreParse=False) ret_tokens = ParseResults([start, tokens, loc]) ret_tokens["locn_start"] = start ret_tokens["value"] = tokens ret_tokens["locn_end"] = loc if self.resultsName: # must return as a list, so that the name will be attached to the complete group return loc, [ret_tokens] else: return loc, ret_tokens class NotAny(ParseElementEnhance): """ Lookahead to disallow matching with the given parse expression. ``NotAny`` does *not* advance the parsing position within the input string, it only verifies that the specified parse expression does *not* match at the current position. Also, ``NotAny`` does *not* skip over leading whitespace. ``NotAny`` always returns a null token list. May be constructed using the ``'~'`` operator. Example: .. testcode:: AND, OR, NOT = map(CaselessKeyword, "AND OR NOT".split()) # take care not to mistake keywords for identifiers ident = ~(AND | OR | NOT) + Word(alphas) boolean_term = Opt(NOT) + ident # very crude boolean expression - to support parenthesis groups and # operation hierarchy, use infix_notation boolean_expr = boolean_term + ((AND | OR) + boolean_term)[...] # integers that are followed by "." are actually floats integer = Word(nums) + ~Char(".") """ def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) # do NOT use self.leave_whitespace(), don't want to propagate to exprs # self.leave_whitespace() self.skipWhitespace = False self._may_return_empty = True self.errmsg = f"Found unwanted token, {self.expr}" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if self.expr.can_parse_next(instring, loc, do_actions=do_actions): raise ParseException(instring, loc, self.errmsg, self) return loc, [] def _generateDefaultName(self) -> str: return f"~{{{self.expr}}}" class _MultipleMatch(ParseElementEnhance): def __init__( self, expr: Union[str, ParserElement], stop_on: typing.Optional[Union[ParserElement, str]] = None, **kwargs, ) -> None: stopOn: typing.Optional[Union[ParserElement, str]] = deprecate_argument( kwargs, "stopOn", None ) super().__init__(expr) stopOn = stopOn or stop_on self.saveAsList = True ender = stopOn if isinstance(ender, str_type): ender = self._literalStringClass(ender) self.stopOn(ender) def stop_on(self, ender) -> ParserElement: if isinstance(ender, str_type): ender = self._literalStringClass(ender) self.not_ender = ~ender if ender is not None else None return self stopOn = stop_on def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: self_expr_parse = self.expr._parse self_skip_ignorables = self._skipIgnorables check_ender = False if self.not_ender is not None: try_not_ender = self.not_ender.try_parse check_ender = True # must be at least one (but first see if we are the stopOn sentinel; # if so, fail) if check_ender: try_not_ender(instring, loc) loc, tokens = self_expr_parse(instring, loc, do_actions) try: hasIgnoreExprs = not not self.ignoreExprs while 1: if check_ender: try_not_ender(instring, loc) if hasIgnoreExprs: preloc = self_skip_ignorables(instring, loc) else: preloc = loc loc, tmptokens = self_expr_parse(instring, preloc, do_actions) tokens += tmptokens except (ParseException, IndexError): pass return loc, tokens def _setResultsName(self, name, list_all_matches=False) -> ParserElement: if ( __diag__.warn_ungrouped_named_tokens_in_collection and Diagnostics.warn_ungrouped_named_tokens_in_collection not in self.suppress_warnings_ ): for e in [self.expr] + self.expr.recurse(): if ( isinstance(e, ParserElement) and e.resultsName and ( Diagnostics.warn_ungrouped_named_tokens_in_collection not in e.suppress_warnings_ ) ): warning = ( "warn_ungrouped_named_tokens_in_collection:" f" setting results name {name!r} on {type(self).__name__} expression" f" collides with {e.resultsName!r} on contained expression" ) warnings.warn(warning, PyparsingDiagnosticWarning, stacklevel=3) break return super()._setResultsName(name, list_all_matches) class OneOrMore(_MultipleMatch): """ Repetition of one or more of the given expression. Parameters: - ``expr`` - expression that must match one or more times - ``stop_on`` - (default= ``None``) - expression for a terminating sentinel (only required if the sentinel would ordinarily match the repetition expression) Example: .. doctest:: >>> data_word = Word(alphas) >>> label = data_word + FollowedBy(':') >>> attr_expr = Group( ... label + Suppress(':') ... + OneOrMore(data_word).set_parse_action(' '.join)) >>> text = "shape: SQUARE posn: upper left color: BLACK" # Fail! read 'posn' as data instead of next label >>> attr_expr[1, ...].parse_string(text).pprint() [['shape', 'SQUARE posn']] # use stop_on attribute for OneOrMore # to avoid reading label string as part of the data >>> attr_expr = Group( ... label + Suppress(':') ... + OneOrMore( ... data_word, stop_on=label).set_parse_action(' '.join)) >>> OneOrMore(attr_expr).parse_string(text).pprint() # Better [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] # could also be written as >>> (attr_expr * (1,)).parse_string(text).pprint() [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] """ def _generateDefaultName(self) -> str: return f"{{{self.expr}}}..." class ZeroOrMore(_MultipleMatch): """ Optional repetition of zero or more of the given expression. Parameters: - ``expr`` - expression that must match zero or more times - ``stop_on`` - expression for a terminating sentinel (only required if the sentinel would ordinarily match the repetition expression) - (default= ``None``) Example: similar to :class:`OneOrMore` """ def __init__( self, expr: Union[str, ParserElement], stop_on: typing.Optional[Union[ParserElement, str]] = None, **kwargs, ) -> None: stopOn: Union[ParserElement, str] = deprecate_argument(kwargs, "stopOn", None) super().__init__(expr, stop_on=stopOn or stop_on) self._may_return_empty = True def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: try: return super().parseImpl(instring, loc, do_actions) except (ParseException, IndexError): return loc, ParseResults([], name=self.resultsName) def _generateDefaultName(self) -> str: return f"[{self.expr}]..." class DelimitedList(ParseElementEnhance): """Helper to define a delimited list of expressions - the delimiter defaults to ','. By default, the list elements and delimiters can have intervening whitespace, and comments, but this can be overridden by passing ``combine=True`` in the constructor. If ``combine`` is set to ``True``, the matching tokens are returned as a single token string, with the delimiters included; otherwise, the matching tokens are returned as a list of tokens, with the delimiters suppressed. If ``allow_trailing_delim`` is set to True, then the list may end with a delimiter. Example: .. doctest:: >>> DelimitedList(Word(alphas)).parse_string("aa,bb,cc") ParseResults(['aa', 'bb', 'cc'], {}) >>> DelimitedList(Word(hexnums), delim=':', combine=True ... ).parse_string("AA:BB:CC:DD:EE") ParseResults(['AA:BB:CC:DD:EE'], {}) .. versionadded:: 3.1.0 """ def __init__( self, expr: Union[str, ParserElement], delim: Union[str, ParserElement] = ",", combine: bool = False, min: typing.Optional[int] = None, max: typing.Optional[int] = None, *, allow_trailing_delim: bool = False, ) -> None: if isinstance(expr, str_type): expr = ParserElement._literalStringClass(expr) expr = typing.cast(ParserElement, expr) if min is not None and min < 1: raise ValueError("min must be greater than 0") if max is not None and min is not None and max < min: raise ValueError("max must be greater than, or equal to min") self.content = expr self.raw_delim = str(delim) self.delim = delim self.combine = combine if not combine: self.delim = Suppress(delim) if not isinstance(delim, Suppress) else delim self.min = min or 1 self.max = max self.allow_trailing_delim = allow_trailing_delim delim_list_expr = self.content + (self.delim + self.content) * ( self.min - 1, None if self.max is None else self.max - 1, ) if self.allow_trailing_delim: delim_list_expr += Opt(self.delim) if self.combine: delim_list_expr = Combine(delim_list_expr) super().__init__(delim_list_expr, savelist=True) def _generateDefaultName(self) -> str: content_expr = self.content.streamline() return f"{content_expr} [{self.raw_delim} {content_expr}]..." class _NullToken: def __bool__(self): return False def __str__(self): return "" class Opt(ParseElementEnhance): """ Optional matching of the given expression. :param expr: expression that must match zero or more times :param default: (optional) - value to be returned if the optional expression is not found. Example: .. testcode:: # US postal code can be a 5-digit zip, plus optional 4-digit qualifier zip = Combine(Word(nums, exact=5) + Opt('-' + Word(nums, exact=4))) zip.run_tests(''' # traditional ZIP code 12345 # ZIP+4 form 12101-0001 # invalid ZIP 98765- ''') prints: .. testoutput:: :options: +NORMALIZE_WHITESPACE # traditional ZIP code 12345 ['12345'] # ZIP+4 form 12101-0001 ['12101-0001'] # invalid ZIP 98765- 98765- ^ ParseException: Expected end of text, found '-' (at char 5), (line:1, col:6) FAIL: Expected end of text, found '-' (at char 5), (line:1, col:6) """ __optionalNotMatched = _NullToken() def __init__( self, expr: Union[ParserElement, str], default: Any = __optionalNotMatched ) -> None: super().__init__(expr, savelist=False) self.saveAsList = self.expr.saveAsList self.defaultValue = default self._may_return_empty = True def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: self_expr = self.expr try: loc, tokens = self_expr._parse( instring, loc, do_actions, callPreParse=False ) except (ParseException, IndexError): default_value = self.defaultValue if default_value is not self.__optionalNotMatched: if self_expr.resultsName: tokens = ParseResults([default_value]) tokens[self_expr.resultsName] = default_value else: tokens = [default_value] # type: ignore[assignment] else: tokens = [] # type: ignore[assignment] return loc, tokens def _generateDefaultName(self) -> str: inner = str(self.expr) # strip off redundant inner {}'s while len(inner) > 1 and inner[0 :: len(inner) - 1] == "{}": inner = inner[1:-1] return f"[{inner}]" Optional = Opt class SkipTo(ParseElementEnhance): """ Token for skipping over all undefined text until the matched expression is found. :param expr: target expression marking the end of the data to be skipped :param include: if ``True``, the target expression is also parsed (the skipped text and target expression are returned as a 2-element list) (default= ``False``). :param ignore: (default= ``None``) used to define grammars (typically quoted strings and comments) that might contain false matches to the target expression :param fail_on: (default= ``None``) define expressions that are not allowed to be included in the skipped test; if found before the target expression is found, the :class:`SkipTo` is not a match Example: .. testcode:: report = ''' Outstanding Issues Report - 1 Jan 2000 # | Severity | Description | Days Open -----+----------+-------------------------------------------+----------- 101 | Critical | Intermittent system crash | 6 94 | Cosmetic | Spelling error on Login ('log|n') | 14 79 | Minor | System slow when running too many reports | 47 ''' integer = Word(nums) SEP = Suppress('|') # use SkipTo to simply match everything up until the next SEP # - ignore quoted strings, so that a '|' character inside a quoted string does not match # - parse action will call token.strip() for each matched token, i.e., the description body string_data = SkipTo(SEP, ignore=quoted_string) string_data.set_parse_action(token_map(str.strip)) ticket_expr = (integer("issue_num") + SEP + string_data("sev") + SEP + string_data("desc") + SEP + integer("days_open")) for tkt in ticket_expr.search_string(report): print(tkt.dump()) prints: .. testoutput:: ['101', 'Critical', 'Intermittent system crash', '6'] - days_open: '6' - desc: 'Intermittent system crash' - issue_num: '101' - sev: 'Critical' ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14'] - days_open: '14' - desc: "Spelling error on Login ('log|n')" - issue_num: '94' - sev: 'Cosmetic' ['79', 'Minor', 'System slow when running too many reports', '47'] - days_open: '47' - desc: 'System slow when running too many reports' - issue_num: '79' - sev: 'Minor' """ def __init__( self, other: Union[ParserElement, str], include: bool = False, ignore: typing.Optional[Union[ParserElement, str]] = None, fail_on: typing.Optional[Union[ParserElement, str]] = None, **kwargs, ) -> None: failOn: typing.Optional[Union[ParserElement, str]] = deprecate_argument( kwargs, "failOn", None ) super().__init__(other) failOn = failOn or fail_on self.ignoreExpr = ignore self._may_return_empty = True self.mayIndexError = False self.includeMatch = include self.saveAsList = False if isinstance(failOn, str_type): self.failOn = self._literalStringClass(failOn) else: self.failOn = failOn self.errmsg = f"No match found for {self.expr}" self.ignorer = Empty().leave_whitespace() self._update_ignorer() def _update_ignorer(self): # rebuild internal ignore expr from current ignore exprs and assigned ignoreExpr self.ignorer.ignoreExprs.clear() for e in self.expr.ignoreExprs: self.ignorer.ignore(e) if self.ignoreExpr: self.ignorer.ignore(self.ignoreExpr) def ignore(self, expr): """ Define expression to be ignored (e.g., comments) while doing pattern matching; may be called repeatedly, to define multiple comment or other ignorable patterns. """ super().ignore(expr) self._update_ignorer() def parseImpl(self, instring, loc, do_actions=True): startloc = loc instrlen = len(instring) self_expr_parse = self.expr._parse self_failOn_canParseNext = ( self.failOn.can_parse_next if self.failOn is not None else None ) ignorer_try_parse = self.ignorer.try_parse if self.ignorer.ignoreExprs else None tmploc = loc while tmploc <= instrlen: if self_failOn_canParseNext is not None: # break if failOn expression matches if self_failOn_canParseNext(instring, tmploc): break if ignorer_try_parse is not None: # advance past ignore expressions prev_tmploc = tmploc while 1: try: tmploc = ignorer_try_parse(instring, tmploc) except ParseBaseException: break # see if all ignorers matched, but didn't actually ignore anything if tmploc == prev_tmploc: break prev_tmploc = tmploc try: self_expr_parse(instring, tmploc, do_actions=False, callPreParse=False) except (ParseException, IndexError): # no match, advance loc in string tmploc += 1 else: # matched skipto expr, done break else: # ran off the end of the input string without matching skipto expr, fail raise ParseException(instring, loc, self.errmsg, self) # build up return values loc = tmploc skiptext = instring[startloc:loc] skipresult = ParseResults(skiptext) if self.includeMatch: loc, mat = self_expr_parse(instring, loc, do_actions, callPreParse=False) skipresult += mat return loc, skipresult class Forward(ParseElementEnhance): """ Forward declaration of an expression to be defined later - used for recursive grammars, such as algebraic infix notation. When the expression is known, it is assigned to the ``Forward`` instance using the ``'<<'`` operator. .. Note:: Take care when assigning to ``Forward`` not to overlook precedence of operators. Specifically, ``'|'`` has a lower precedence than ``'<<'``, so that:: fwd_expr << a | b | c will actually be evaluated as:: (fwd_expr << a) | b | c thereby leaving b and c out as parseable alternatives. It is recommended that you explicitly group the values inserted into the :class:`Forward`:: fwd_expr << (a | b | c) Converting to use the ``'<<='`` operator instead will avoid this problem. See :meth:`ParseResults.pprint` for an example of a recursive parser created using :class:`Forward`. """ def __init__( self, other: typing.Optional[Union[ParserElement, str]] = None ) -> None: self.caller_frame = traceback.extract_stack(limit=2)[0] super().__init__(other, savelist=False) # type: ignore[arg-type] self.lshift_line = None def __lshift__(self, other) -> Forward: if hasattr(self, "caller_frame"): del self.caller_frame if isinstance(other, str_type): other = self._literalStringClass(other) if not isinstance(other, ParserElement): return NotImplemented self.expr = other self.streamlined = other.streamlined self.mayIndexError = self.expr.mayIndexError self._may_return_empty = self.expr.mayReturnEmpty self.set_whitespace_chars( self.expr.whiteChars, copy_defaults=self.expr.copyDefaultWhiteChars ) self.skipWhitespace = self.expr.skipWhitespace self.saveAsList = self.expr.saveAsList self.ignoreExprs.extend(self.expr.ignoreExprs) self.lshift_line = traceback.extract_stack(limit=2)[-2] # type: ignore[assignment] return self def __ilshift__(self, other) -> Forward: if not isinstance(other, ParserElement): return NotImplemented return self << other def __or__(self, other) -> ParserElement: caller_line = traceback.extract_stack(limit=2)[-2] if ( __diag__.warn_on_match_first_with_lshift_operator and caller_line == self.lshift_line and Diagnostics.warn_on_match_first_with_lshift_operator not in self.suppress_warnings_ ): warnings.warn( "warn_on_match_first_with_lshift_operator:" " using '<<' operator with '|' is probably an error, use '<<='", PyparsingDiagnosticWarning, stacklevel=2, ) ret = super().__or__(other) return ret def __del__(self): # see if we are getting dropped because of '=' reassignment of var instead of '<<=' or '<<' if ( self.expr is None and __diag__.warn_on_assignment_to_Forward and Diagnostics.warn_on_assignment_to_Forward not in self.suppress_warnings_ ): warnings.warn_explicit( "warn_on_assignment_to_Forward:" " Forward defined here but no expression attached later using '<<=' or '<<'", UserWarning, filename=self.caller_frame.filename, lineno=self.caller_frame.lineno, ) def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if ( self.expr is None and __diag__.warn_on_parse_using_empty_Forward and Diagnostics.warn_on_parse_using_empty_Forward not in self.suppress_warnings_ ): # walk stack until parse_string, scan_string, search_string, or transform_string is found parse_fns = ( "parse_string", "scan_string", "search_string", "transform_string", ) tb = traceback.extract_stack(limit=200) for i, frm in enumerate(reversed(tb), start=1): if frm.name in parse_fns: stacklevel = i + 1 break else: stacklevel = 2 warnings.warn( "warn_on_parse_using_empty_Forward:" " Forward expression was never assigned a value, will not parse any input", PyparsingDiagnosticWarning, stacklevel=stacklevel, ) if not ParserElement._left_recursion_enabled: return super().parseImpl(instring, loc, do_actions) # ## Bounded Recursion algorithm ## # Recursion only needs to be processed at ``Forward`` elements, since they are # the only ones that can actually refer to themselves. The general idea is # to handle recursion stepwise: We start at no recursion, then recurse once, # recurse twice, ..., until more recursion offers no benefit (we hit the bound). # # The "trick" here is that each ``Forward`` gets evaluated in two contexts # - to *match* a specific recursion level, and # - to *search* the bounded recursion level # and the two run concurrently. The *search* must *match* each recursion level # to find the best possible match. This is handled by a memo table, which # provides the previous match to the next level match attempt. # # See also "Left Recursion in Parsing Expression Grammars", Medeiros et al. # # There is a complication since we not only *parse* but also *transform* via # actions: We do not want to run the actions too often while expanding. Thus, # we expand using `do_actions=False` and only run `do_actions=True` if the next # recursion level is acceptable. with ParserElement.recursion_lock: memo = ParserElement.recursion_memos try: # we are parsing at a specific recursion expansion - use it as-is prev_loc, prev_result = memo[loc, self, do_actions] if isinstance(prev_result, Exception): raise prev_result return prev_loc, prev_result.copy() except KeyError: act_key = (loc, self, True) peek_key = (loc, self, False) # we are searching for the best recursion expansion - keep on improving # both `do_actions` cases must be tracked separately here! prev_loc, prev_peek = memo[peek_key] = ( loc - 1, ParseException( instring, loc, "Forward recursion without base case", self ), ) if do_actions: memo[act_key] = memo[peek_key] while True: try: new_loc, new_peek = super().parseImpl(instring, loc, False) except ParseException: # we failed before getting any match - do not hide the error if isinstance(prev_peek, Exception): raise new_loc, new_peek = prev_loc, prev_peek # the match did not get better: we are done if new_loc <= prev_loc: if do_actions: # replace the match for do_actions=False as well, # in case the action did backtrack prev_loc, prev_result = memo[peek_key] = memo[act_key] del memo[peek_key], memo[act_key] return prev_loc, copy.copy(prev_result) del memo[peek_key] return prev_loc, copy.copy(prev_peek) # the match did get better: see if we can improve further if do_actions: try: memo[act_key] = super().parseImpl(instring, loc, True) except ParseException as e: memo[peek_key] = memo[act_key] = (new_loc, e) raise prev_loc, prev_peek = memo[peek_key] = new_loc, new_peek def leave_whitespace(self, recursive: bool = True) -> ParserElement: """ Extends ``leave_whitespace`` defined in base class. """ self.skipWhitespace = False return self def ignore_whitespace(self, recursive: bool = True) -> ParserElement: """ Extends ``ignore_whitespace`` defined in base class. """ self.skipWhitespace = True return self def streamline(self) -> ParserElement: if not self.streamlined: self.streamlined = True if self.expr is not None: self.expr.streamline() return self def validate(self, validateTrace=None) -> None: warnings.warn( "ParserElement.validate() is deprecated, and should not be used to check for left recursion", PyparsingDeprecationWarning, stacklevel=2, ) if validateTrace is None: validateTrace = [] if self not in validateTrace: tmp = validateTrace[:] + [self] if self.expr is not None: self.expr.validate(tmp) self._checkRecursion([]) def _generateDefaultName(self) -> str: # Avoid infinite recursion by setting a temporary _defaultName save_default_name = self._defaultName self._defaultName = ": ..." # Use the string representation of main expression. try: if self.expr is not None: ret_string = str(self.expr)[:1000] else: ret_string = "None" except Exception: ret_string = "..." self._defaultName = save_default_name return f"{type(self).__name__}: {ret_string}" def copy(self) -> ParserElement: """ Returns a copy of this expression. Generally only used internally by pyparsing. """ if self.expr is not None: return super().copy() else: ret = Forward() ret <<= self return ret def _setResultsName(self, name, list_all_matches=False) -> ParserElement: # fmt: off if ( __diag__.warn_name_set_on_empty_Forward and Diagnostics.warn_name_set_on_empty_Forward not in self.suppress_warnings_ and self.expr is None ): warning = ( "warn_name_set_on_empty_Forward:" f" setting results name {name!r} on {type(self).__name__} expression" " that has no contained expression" ) warnings.warn(warning, PyparsingDiagnosticWarning, stacklevel=3) # fmt: on return super()._setResultsName(name, list_all_matches) # Compatibility synonyms # fmt: off leaveWhitespace = replaced_by_pep8("leaveWhitespace", leave_whitespace) ignoreWhitespace = replaced_by_pep8("ignoreWhitespace", ignore_whitespace) # fmt: on class TokenConverter(ParseElementEnhance): """ Abstract subclass of :class:`ParseElementEnhance`, for converting parsed results. """ def __init__(self, expr: Union[ParserElement, str], savelist=False) -> None: super().__init__(expr) # , savelist) self.saveAsList = False class Combine(TokenConverter): """Converter to concatenate all matching tokens to a single string. By default, the matching patterns must also be contiguous in the input string; this can be disabled by specifying ``'adjacent=False'`` in the constructor. Example: .. doctest:: >>> real = Word(nums) + '.' + Word(nums) >>> print(real.parse_string('3.1416')) ['3', '.', '1416'] >>> # will also erroneously match the following >>> print(real.parse_string('3. 1416')) ['3', '.', '1416'] >>> real = Combine(Word(nums) + '.' + Word(nums)) >>> print(real.parse_string('3.1416')) ['3.1416'] >>> # no match when there are internal spaces >>> print(real.parse_string('3. 1416')) Traceback (most recent call last): ParseException: Expected W:(0123...) """ def __init__( self, expr: ParserElement, join_string: str = "", adjacent: bool = True, *, joinString: typing.Optional[str] = None, ) -> None: super().__init__(expr) joinString = joinString if joinString is not None else join_string # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself if adjacent: self.leave_whitespace() self.adjacent = adjacent self.skipWhitespace = True self.joinString = joinString self.callPreparse = True def ignore(self, other) -> ParserElement: """ Define expression to be ignored (e.g., comments) while doing pattern matching; may be called repeatedly, to define multiple comment or other ignorable patterns. """ if self.adjacent: ParserElement.ignore(self, other) else: super().ignore(other) return self def postParse(self, instring, loc, tokenlist): retToks = tokenlist.copy() del retToks[:] retToks += ParseResults( ["".join(tokenlist._asStringList(self.joinString))], modal=self.modalResults ) if self.resultsName and retToks.haskeys(): return [retToks] else: return retToks class Group(TokenConverter): """Converter to return the matched tokens as a list - useful for returning tokens of :class:`ZeroOrMore` and :class:`OneOrMore` expressions. The optional ``aslist`` argument when set to True will return the parsed tokens as a Python list instead of a pyparsing ParseResults. Example: .. doctest:: >>> ident = Word(alphas) >>> num = Word(nums) >>> term = ident | num >>> func = ident + Opt(DelimitedList(term)) >>> print(func.parse_string("fn a, b, 100")) ['fn', 'a', 'b', '100'] >>> func = ident + Group(Opt(DelimitedList(term))) >>> print(func.parse_string("fn a, b, 100")) ['fn', ['a', 'b', '100']] """ def __init__(self, expr: ParserElement, aslist: bool = False) -> None: super().__init__(expr) self.saveAsList = True self._asPythonList = aslist def postParse(self, instring, loc, tokenlist): if self._asPythonList: return ParseResults.List( tokenlist.as_list() if isinstance(tokenlist, ParseResults) else list(tokenlist) ) return [tokenlist] class Dict(TokenConverter): """Converter to return a repetitive expression as a list, but also as a dictionary. Each element can also be referenced using the first token in the expression as its key. Useful for tabular report scraping when the first column can be used as a item key. The optional ``asdict`` argument when set to True will return the parsed tokens as a Python dict instead of a pyparsing ParseResults. Example: .. doctest:: >>> data_word = Word(alphas) >>> label = data_word + FollowedBy(':') >>> attr_expr = ( ... label + Suppress(':') ... + OneOrMore(data_word, stop_on=label) ... .set_parse_action(' '.join) ... ) >>> text = "shape: SQUARE posn: upper left color: light blue texture: burlap" >>> # print attributes as plain groups >>> print(attr_expr[1, ...].parse_string(text).dump()) ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] # instead of OneOrMore(expr), parse using Dict(Group(expr)[1, ...]) # Dict will auto-assign names. >>> result = Dict(Group(attr_expr)[1, ...]).parse_string(text) >>> print(result.dump()) [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - color: 'light blue' - posn: 'upper left' - shape: 'SQUARE' - texture: 'burlap' [0]: ['shape', 'SQUARE'] [1]: ['posn', 'upper left'] [2]: ['color', 'light blue'] [3]: ['texture', 'burlap'] # access named fields as dict entries, or output as dict >>> print(result['shape']) SQUARE >>> print(result.as_dict()) {'shape': 'SQUARE', 'posn': 'upper left', 'color': 'light blue', 'texture': 'burlap'} See more examples at :class:`ParseResults` of accessing fields by results name. """ def __init__(self, expr: ParserElement, asdict: bool = False) -> None: super().__init__(expr) self.saveAsList = True self._asPythonDict = asdict def postParse(self, instring, loc, tokenlist): for i, tok in enumerate(tokenlist): if len(tok) == 0: continue ikey = tok[0] if isinstance(ikey, int): ikey = str(ikey).strip() if len(tok) == 1: tokenlist[ikey] = _ParseResultsWithOffset("", i) elif len(tok) == 2 and not isinstance(tok[1], ParseResults): tokenlist[ikey] = _ParseResultsWithOffset(tok[1], i) else: try: dictvalue = tok.copy() # ParseResults(i) except Exception: exc = TypeError( "could not extract dict values from parsed results" " - Dict expression must contain Grouped expressions" ) raise exc from None del dictvalue[0] if len(dictvalue) != 1 or ( isinstance(dictvalue, ParseResults) and dictvalue.haskeys() ): tokenlist[ikey] = _ParseResultsWithOffset(dictvalue, i) else: tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0], i) if self._asPythonDict: return [tokenlist.as_dict()] if self.resultsName else tokenlist.as_dict() return [tokenlist] if self.resultsName else tokenlist class Suppress(TokenConverter): """Converter for ignoring the results of a parsed expression. Example: .. doctest:: >>> source = "a, b, c,d" >>> wd = Word(alphas) >>> wd_list1 = wd + (',' + wd)[...] >>> print(wd_list1.parse_string(source)) ['a', ',', 'b', ',', 'c', ',', 'd'] # often, delimiters that are useful during parsing are just in the # way afterward - use Suppress to keep them out of the parsed output >>> wd_list2 = wd + (Suppress(',') + wd)[...] >>> print(wd_list2.parse_string(source)) ['a', 'b', 'c', 'd'] # Skipped text (using '...') can be suppressed as well >>> source = "lead in START relevant text END trailing text" >>> start_marker = Keyword("START") >>> end_marker = Keyword("END") >>> find_body = Suppress(...) + start_marker + ... + end_marker >>> print(find_body.parse_string(source)) ['START', 'relevant text ', 'END'] (See also :class:`DelimitedList`.) """ def __init__(self, expr: Union[ParserElement, str], savelist: bool = False) -> None: if expr is ...: expr = _PendingSkip(NoMatch()) super().__init__(expr) def __add__(self, other) -> ParserElement: if isinstance(self.expr, _PendingSkip): return Suppress(SkipTo(other)) + other return super().__add__(other) def __sub__(self, other) -> ParserElement: if isinstance(self.expr, _PendingSkip): return Suppress(SkipTo(other)) - other return super().__sub__(other) def postParse(self, instring, loc, tokenlist): return [] def suppress(self) -> ParserElement: return self # XXX: Example needs to be re-done for updated output def trace_parse_action(f: ParseAction) -> ParseAction: """Decorator for debugging parse actions. When the parse action is called, this decorator will print ``">> entering method-name(line:, , )"``. When the parse action completes, the decorator will print ``"<<"`` followed by the returned value, or any exception that the parse action raised. Example: .. testsetup:: stderr import sys sys.stderr = sys.stdout .. testcleanup:: stderr sys.stderr = sys.__stderr__ .. testcode:: stderr wd = Word(alphas) @trace_parse_action def remove_duplicate_chars(tokens): return ''.join(sorted(set(''.join(tokens)))) wds = wd[1, ...].set_parse_action(remove_duplicate_chars) print(wds.parse_string("slkdjs sld sldd sdlf sdljf")) prints: .. testoutput:: stderr :options: +NORMALIZE_WHITESPACE >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, ParseResults(['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {})) < 3: thisFunc = f"{type(paArgs[0]).__name__}.{thisFunc}" sys.stderr.write(f">>entering {thisFunc}(line: {line(l, s)!r}, {l}, {t!r})\n") try: ret = f(*paArgs) except Exception as exc: sys.stderr.write( f"< str: r"""Helper to easily define string ranges for use in :class:`Word` construction. Borrows syntax from regexp ``'[]'`` string range definitions:: srange("[0-9]") -> "0123456789" srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" The input string must be enclosed in []'s, and the returned string is the expanded character set joined into a single string. The values enclosed in the []'s may be: - a single character - an escaped character with a leading backslash (such as ``\-`` or ``\]``) - an escaped hex character with a leading ``'\x'`` (``\x21``, which is a ``'!'`` character) (``\0x##`` is also supported for backwards compatibility) - an escaped octal character with a leading ``'\0'`` (``\041``, which is a ``'!'`` character) - a range of any of the above, separated by a dash (``'a-z'``, etc.) - any combination of the above (``'aeiouy'``, ``'a-zA-Z0-9_$'``, etc.) """ def _expanded(p): if isinstance(p, ParseResults): yield from (chr(c) for c in range(ord(p[0]), ord(p[1]) + 1)) else: yield p try: return "".join( [c for part in _reBracketExpr.parse_string(s).body for c in _expanded(part)] ) except Exception as e: return "" def token_map(func, *args) -> ParseAction: """Helper to define a parse action by mapping a function to all elements of a :class:`ParseResults` list. If any additional args are passed, they are forwarded to the given function as additional arguments after the token, as in ``hex_integer = Word(hexnums).set_parse_action(token_map(int, 16))``, which will convert the parsed data to an integer using base 16. Example (compare the last to example in :class:`ParserElement.transform_string`:: hex_ints = Word(hexnums)[1, ...].set_parse_action(token_map(int, 16)) hex_ints.run_tests(''' 00 11 22 aa FF 0a 0d 1a ''') upperword = Word(alphas).set_parse_action(token_map(str.upper)) upperword[1, ...].run_tests(''' my kingdom for a horse ''') wd = Word(alphas).set_parse_action(token_map(str.title)) wd[1, ...].set_parse_action(' '.join).run_tests(''' now is the winter of our discontent made glorious summer by this sun of york ''') prints:: 00 11 22 aa FF 0a 0d 1a [0, 17, 34, 170, 255, 10, 13, 26] my kingdom for a horse ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE'] now is the winter of our discontent made glorious summer by this sun of york ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York'] """ def pa(s, l, t): return [func(tokn, *args) for tokn in t] func_name = getattr(func, "__name__", getattr(func, "__class__").__name__) pa.__name__ = func_name return pa def autoname_elements() -> None: """ Utility to simplify mass-naming of parser elements, for generating railroad diagram with named subdiagrams. """ # guard against _getframe not being implemented in the current Python getframe_fn = getattr(sys, "_getframe", lambda _: None) calling_frame = getframe_fn(1) if calling_frame is None: return # find all locals in the calling frame that are ParserElements calling_frame = typing.cast(types.FrameType, calling_frame) for name, var in calling_frame.f_locals.items(): # if no custom name defined, set the name to the var name if isinstance(var, ParserElement) and not var.customName: var.set_name(name) dbl_quoted_string = Combine( Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"' ).set_name("string enclosed in double quotes") sgl_quoted_string = Combine( Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'" ).set_name("string enclosed in single quotes") quoted_string = Combine( (Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"').set_name( "double quoted string" ) | (Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'").set_name( "single quoted string" ) ).set_name("quoted string using single or double quotes") # XXX: Is there some way to make this show up in API docs? # .. versionadded:: 3.1.0 python_quoted_string = Combine( (Regex(r'"""(?:[^"\\]|""(?!")|"(?!"")|\\.)*', flags=re.MULTILINE) + '"""').set_name( "multiline double quoted string" ) ^ ( Regex(r"'''(?:[^'\\]|''(?!')|'(?!'')|\\.)*", flags=re.MULTILINE) + "'''" ).set_name("multiline single quoted string") ^ (Regex(r'"(?:[^"\n\r\\]|(?:\\")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"').set_name( "double quoted string" ) ^ (Regex(r"'(?:[^'\n\r\\]|(?:\\')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'").set_name( "single quoted string" ) ).set_name("Python quoted string") unicode_string = Combine("u" + quoted_string.copy()).set_name("unicode string literal") alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") # build list of built-in expressions, for future reference if a global default value # gets updated _builtin_exprs: list[ParserElement] = [ v for v in vars().values() if isinstance(v, ParserElement) ] # Compatibility synonyms # fmt: off sglQuotedString = sgl_quoted_string dblQuotedString = dbl_quoted_string quotedString = quoted_string unicodeString = unicode_string lineStart = line_start lineEnd = line_end stringStart = string_start stringEnd = string_end nullDebugAction = replaced_by_pep8("nullDebugAction", null_debug_action) traceParseAction = replaced_by_pep8("traceParseAction", trace_parse_action) conditionAsParseAction = replaced_by_pep8("conditionAsParseAction", condition_as_parse_action) tokenMap = replaced_by_pep8("tokenMap", token_map) # fmt: on ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7232046 pyparsing-3.3.2/pyparsing/diagram/__init__.py0000644000000000000000000006446115134002420016214 0ustar00# mypy: ignore-errors from __future__ import annotations import itertools import railroad import pyparsing import dataclasses import typing from typing import ( Generic, TypeVar, Callable, Iterable, ) from jinja2 import Template from io import StringIO import inspect import re jinja2_template_source = """\ {% if not embed %} {% endif %} {% if not head %} {% else %} {{ head | safe }} {% endif %} {% if not embed %} {% endif %} {{ body | safe }} {% for diagram in diagrams %}

{{ diagram.title }}

{{ diagram.text }}
{{ diagram.svg }}
{% endfor %} {% if not embed %} {% endif %} """ template = Template(jinja2_template_source) _bookmark_lookup = {} _bookmark_ids = itertools.count(start=1) def _make_bookmark(s: str) -> str: """ Converts a string into a valid HTML bookmark (ID or anchor name). """ if s in _bookmark_lookup: return _bookmark_lookup[s] # Replace invalid characters with hyphens and ensure only valid characters bookmark = re.sub(r'[^a-zA-Z0-9-]+', '-', s) # Ensure it starts with a letter by adding 'z' if necessary if not bookmark[:1].isalpha(): bookmark = f"z{bookmark}" # Convert to lowercase and strip hyphens bookmark = bookmark.lower().strip('-') _bookmark_lookup[s] = bookmark = f"{bookmark}-{next(_bookmark_ids):04d}" return bookmark def _collapse_verbose_regex(regex_str: str) -> str: if "\n" not in regex_str: return regex_str collapsed = pyparsing.Regex(r"#.*$").suppress().transform_string(regex_str) collapsed = re.sub(r"\s*\n\s*", "", collapsed) return collapsed @dataclasses.dataclass class NamedDiagram: """ A simple structure for associating a name with a railroad diagram """ name: str index: int diagram: railroad.DiagramItem = None @property def bookmark(self): bookmark = _make_bookmark(self.name) return bookmark T = TypeVar("T") class EachItem(railroad.Group): """ Custom railroad item to compose a: - :class:`railroad.Group` containing a - :class:`railroad.OneOrMore` containing a - :class:`railroad.Choice` of the elements in the :class:`railroad.Each` with the group label indicating that all must be matched """ all_label = "[ALL]" def __init__(self, *items) -> None: choice_item = railroad.Choice(len(items) - 1, *items) one_or_more_item = railroad.OneOrMore(item=choice_item) super().__init__(one_or_more_item, label=self.all_label) class AnnotatedItem(railroad.Group): """ Simple subclass of Group that creates an annotation label """ def __init__(self, label: str, item) -> None: super().__init__(item=item, label=f"[{label}]" if label else "") class EditablePartial(Generic[T]): """ Acts like a functools.partial, but can be edited. In other words, it represents a type that hasn't yet been constructed. """ # We need this here because the railroad constructors actually transform the data, so can't be called until the # entire tree is assembled def __init__(self, func: Callable[..., T], args: list, kwargs: dict) -> None: self.func = func self.args = args self.kwargs = kwargs @classmethod def from_call(cls, func: Callable[..., T], *args, **kwargs) -> EditablePartial[T]: """ If you call this function in the same way that you would call the constructor, it will store the arguments as you expect. For example ``EditablePartial.from_call(Fraction, 1, 3)() == Fraction(1, 3)`` """ return EditablePartial(func=func, args=list(args), kwargs=kwargs) @property def name(self): return self.kwargs["name"] def __call__(self) -> T: """ Evaluate the partial and return the result """ args = self.args.copy() kwargs = self.kwargs.copy() # This is a helpful hack to allow you to specify varargs parameters (e.g. *args) as keyword args (e.g. # args=['list', 'of', 'things']) arg_spec = inspect.getfullargspec(self.func) if arg_spec.varargs in self.kwargs: args += kwargs.pop(arg_spec.varargs) return self.func(*args, **kwargs) def railroad_to_html(diagrams: list[NamedDiagram], embed=False, **kwargs) -> str: """ Given a list of :class:`NamedDiagram`, produce a single HTML string that visualises those diagrams. :params kwargs: kwargs to be passed in to the template """ data = [] for diagram in diagrams: if diagram.diagram is None: continue io = StringIO() try: css = kwargs.get("css") diagram.diagram.writeStandalone(io.write, css=css) except AttributeError: diagram.diagram.writeSvg(io.write) title = diagram.name if diagram.index == 0: title += " (root)" data.append( { "title": title, "text": "", "svg": io.getvalue(), "bookmark": diagram.bookmark } ) return template.render(diagrams=data, embed=embed, **kwargs) def resolve_partial(partial: EditablePartial[T]) -> T: """ Recursively resolves a collection of Partials into whatever type they are """ if isinstance(partial, EditablePartial): partial.args = resolve_partial(partial.args) partial.kwargs = resolve_partial(partial.kwargs) return partial() elif isinstance(partial, list): return [resolve_partial(x) for x in partial] elif isinstance(partial, dict): return {key: resolve_partial(x) for key, x in partial.items()} else: return partial def to_railroad( element: pyparsing.ParserElement, diagram_kwargs: typing.Optional[dict] = None, vertical: int = 3, show_results_names: bool = False, show_groups: bool = False, show_hidden: bool = False, ) -> list[NamedDiagram]: """ Convert a pyparsing element tree into a list of diagrams. This is the recommended entrypoint to diagram creation if you want to access the Railroad tree before it is converted to HTML :param element: base element of the parser being diagrammed :param diagram_kwargs: kwargs to pass to the :meth:`Diagram` constructor :param vertical: (optional) int - limit at which number of alternatives should be shown vertically instead of horizontally :param show_results_names: bool to indicate whether results name annotations should be included in the diagram :param show_groups: bool to indicate whether groups should be highlighted with an unlabeled surrounding box :param show_hidden: bool to indicate whether internal elements that are typically hidden should be shown """ # Convert the whole tree underneath the root lookup = ConverterState(diagram_kwargs=diagram_kwargs or {}) _to_diagram_element( element, lookup=lookup, parent=None, vertical=vertical, show_results_names=show_results_names, show_groups=show_groups, show_hidden=show_hidden, ) root_id = id(element) # Convert the root if it hasn't been already if root_id in lookup: if not element.customName: lookup[root_id].name = "" lookup[root_id].mark_for_extraction(root_id, lookup, force=True) # Now that we're finished, we can convert from intermediate structures into Railroad elements diags = list(lookup.diagrams.values()) if len(diags) > 1: # collapse out duplicate diags with the same name seen = set() deduped_diags = [] for d in diags: # don't extract SkipTo elements, they are uninformative as subdiagrams if d.name == "...": continue if d.name is not None and d.name not in seen: seen.add(d.name) deduped_diags.append(d) resolved = [resolve_partial(partial) for partial in deduped_diags] else: # special case - if just one diagram, always display it, even if # it has no name resolved = [resolve_partial(partial) for partial in diags] return sorted(resolved, key=lambda diag: diag.index) def _should_vertical( specification: int, exprs: Iterable[pyparsing.ParserElement] ) -> bool: """ Returns true if we should return a vertical list of elements """ if specification is None: return False else: return len(_visible_exprs(exprs)) >= specification @dataclasses.dataclass class ElementState: """ State recorded for an individual pyparsing Element """ #: The pyparsing element that this represents element: pyparsing.ParserElement #: The output Railroad element in an unconverted state converted: EditablePartial #: The parent Railroad element, which we store so that we can extract this if it's duplicated parent: EditablePartial #: The order in which we found this element, used for sorting diagrams if this is extracted into a diagram number: int #: The name of the element name: str = None #: The index of this inside its parent parent_index: typing.Optional[int] = None #: If true, we should extract this out into a subdiagram extract: bool = False #: If true, all of this element's children have been filled out complete: bool = False def mark_for_extraction( self, el_id: int, state: ConverterState, name: str = None, force: bool = False ): """ Called when this instance has been seen twice, and thus should eventually be extracted into a sub-diagram :param el_id: id of the element :param state: element/diagram state tracker :param name: name to use for this element's text :param force: If true, force extraction now, regardless of the state of this. Only useful for extracting the root element when we know we're finished """ self.extract = True # Set the name if not self.name: if name: # Allow forcing a custom name self.name = name elif self.element.customName: self.name = self.element.customName else: self.name = "" # Just because this is marked for extraction doesn't mean we can do it yet. We may have to wait for children # to be added # Also, if this is just a string literal etc, don't bother extracting it if force or (self.complete and _worth_extracting(self.element)): state.extract_into_diagram(el_id) class ConverterState: """ Stores some state that persists between recursions into the element tree """ index_generator = itertools.count(start=1) def __init__(self, diagram_kwargs: typing.Optional[dict] = None) -> None: #: A dictionary mapping ParserElements to state relating to them self._element_diagram_states: dict[int, ElementState] = {} #: A dictionary mapping ParserElement IDs to subdiagrams generated from them self.diagrams: dict[int, EditablePartial[NamedDiagram]] = {} #: The index of the next element. This is used for sorting self.index: int = 0 #: Shared kwargs that are used to customize the construction of diagrams self.diagram_kwargs: dict = diagram_kwargs or {} self.extracted_diagram_names: set[str] = set() def __setitem__(self, key: int, value: ElementState): self._element_diagram_states[key] = value def __getitem__(self, key: int) -> ElementState: return self._element_diagram_states[key] def __delitem__(self, key: int): del self._element_diagram_states[key] def __contains__(self, key: int): return key in self._element_diagram_states def get(self, key, default=None): try: return self[key] except KeyError: return default def generate_index(self) -> int: """ Generate a number used to index a diagram """ return next(self.index_generator) def extract_into_diagram(self, el_id: int): """ Used when we encounter the same token twice in the same tree. When this happens, we replace all instances of that token with a terminal, and create a new subdiagram for the token """ position = self[el_id] # Replace the original definition of this element with a regular block if position.parent: href = f"#{_make_bookmark(position.name)}" ret = EditablePartial.from_call(railroad.NonTerminal, text=position.name, href=href) if "item" in position.parent.kwargs: position.parent.kwargs["item"] = ret elif "items" in position.parent.kwargs: position.parent.kwargs["items"][position.parent_index] = ret # If the element we're extracting is a group, skip to its content but keep the title if position.converted.func == railroad.Group: content = position.converted.kwargs["item"] else: content = position.converted self.diagrams[el_id] = EditablePartial.from_call( NamedDiagram, name=position.name, diagram=EditablePartial.from_call( railroad.Diagram, content, **self.diagram_kwargs ), index=position.number, ) del self[el_id] def _worth_extracting(element: pyparsing.ParserElement) -> bool: """ Returns true if this element is worth having its own sub-diagram. Simply, if any of its children themselves have children, then its complex enough to extract """ children = element.recurse() return any(child.recurse() for child in children) def _apply_diagram_item_enhancements(fn): """ decorator to ensure enhancements to a diagram item (such as results name annotations) get applied on return from _to_diagram_element (we do this since there are several returns in _to_diagram_element) """ def _inner( element: pyparsing.ParserElement, parent: typing.Optional[EditablePartial], lookup: ConverterState = None, vertical: int = None, index: int = 0, name_hint: str = None, show_results_names: bool = False, show_groups: bool = False, show_hidden: bool = False, ) -> typing.Optional[EditablePartial]: ret = fn( element, parent, lookup, vertical, index, name_hint, show_results_names, show_groups, show_hidden, ) # apply annotation for results name, if present if show_results_names and ret is not None: element_results_name = element.resultsName if element_results_name: # add "*" to indicate if this is a "list all results" name modal_tag = "" if element.modalResults else "*" ret = EditablePartial.from_call( railroad.Group, item=ret, label=f"{repr(element_results_name)}{modal_tag}", ) return ret return _inner def _visible_exprs(exprs: Iterable[pyparsing.ParserElement]): non_diagramming_exprs = ( pyparsing.ParseElementEnhance, pyparsing.PositionToken, pyparsing.And._ErrorStop, ) return [ e for e in exprs if not isinstance(e, non_diagramming_exprs) ] @_apply_diagram_item_enhancements def _to_diagram_element( element: pyparsing.ParserElement, parent: typing.Optional[EditablePartial], lookup: ConverterState = None, vertical: int = None, index: int = 0, name_hint: str = None, show_results_names: bool = False, show_groups: bool = False, show_hidden: bool = False, ) -> typing.Optional[EditablePartial]: """ Recursively converts a PyParsing Element to a railroad Element :param lookup: The shared converter state that keeps track of useful things :param index: The index of this element within the parent :param parent: The parent of this element in the output tree :param vertical: Controls at what point we make a list of elements vertical. If this is an integer (the default), it sets the threshold of the number of items before we go vertical. If True, always go vertical, if False, never do so :param name_hint: If provided, this will override the generated name :param show_results_names: bool flag indicating whether to add annotations for results names :param show_groups: bool flag indicating whether to show groups using bounding box :param show_hidden: bool flag indicating whether to show elements that are typically hidden :returns: The converted version of the input element, but as a Partial that hasn't yet been constructed """ exprs = element.recurse() name = name_hint or element.customName or type(element).__name__ # Python's id() is used to provide a unique identifier for elements el_id = id(element) element_results_name = element.resultsName # Here we basically bypass processing certain wrapper elements if they contribute nothing to the diagram if not element.customName: if isinstance( element, ( # pyparsing.TokenConverter, pyparsing.Forward, pyparsing.Located, pyparsing.AtStringStart, pyparsing.AtLineStart, ), ): # However, if this element has a useful custom name, and its child does not, we can pass it on to the child if exprs: if not exprs[0].customName: propagated_name = name else: propagated_name = None return _to_diagram_element( element.expr, parent=parent, lookup=lookup, vertical=vertical, index=index, name_hint=propagated_name, show_results_names=show_results_names, show_groups=show_groups, show_hidden=show_hidden, ) # If the element isn't worth extracting, we always treat it as the first time we say it if _worth_extracting(element): looked_up = lookup.get(el_id) if looked_up and looked_up.name is not None: # If we've seen this element exactly once before, we are only just now finding out that it's a duplicate, # so we have to extract it into a new diagram. looked_up.mark_for_extraction(el_id, lookup, name=name_hint) href = f"#{_make_bookmark(looked_up.name)}" ret = EditablePartial.from_call(railroad.NonTerminal, text=looked_up.name, href=href) return ret elif el_id in lookup.diagrams: # If we have seen the element at least twice before, and have already extracted it into a subdiagram, we # just put in a marker element that refers to the sub-diagram text = lookup.diagrams[el_id].kwargs["name"] ret = EditablePartial.from_call( railroad.NonTerminal, text=text, href=f"#{_make_bookmark(text)}" ) return ret # Recursively convert child elements # Here we find the most relevant Railroad element for matching pyparsing Element # We use ``items=[]`` here to hold the place for where the child elements will go once created # see if this element is normally hidden, and whether hidden elements are desired # if not, just return None if not element.show_in_diagram and not show_hidden: return None if isinstance(element, pyparsing.And): # detect And's created with ``expr*N`` notation - for these use a OneOrMore with a repeat # (all will have the same name, and resultsName) if not exprs: return None if len(set((e.name, e.resultsName) for e in exprs)) == 1 and len(exprs) > 2: ret = EditablePartial.from_call( railroad.OneOrMore, item="", repeat=str(len(exprs)) ) elif _should_vertical(vertical, exprs): ret = EditablePartial.from_call(railroad.Stack, items=[]) else: ret = EditablePartial.from_call(railroad.Sequence, items=[]) elif isinstance(element, (pyparsing.Or, pyparsing.MatchFirst)): if not exprs: return None if _should_vertical(vertical, exprs): ret = EditablePartial.from_call(railroad.Choice, 0, items=[]) else: ret = EditablePartial.from_call(railroad.HorizontalChoice, items=[]) elif isinstance(element, pyparsing.Each): if not exprs: return None ret = EditablePartial.from_call(EachItem, items=[]) elif isinstance(element, pyparsing.NotAny): ret = EditablePartial.from_call(AnnotatedItem, label="NOT", item="") elif isinstance(element, pyparsing.FollowedBy): ret = EditablePartial.from_call(AnnotatedItem, label="LOOKAHEAD", item="") elif isinstance(element, pyparsing.PrecededBy): ret = EditablePartial.from_call(AnnotatedItem, label="LOOKBEHIND", item="") elif isinstance(element, pyparsing.Group): if show_groups: ret = EditablePartial.from_call(AnnotatedItem, label="", item="") else: ret = EditablePartial.from_call( railroad.Group, item=None, label=element_results_name ) elif isinstance(element, pyparsing.TokenConverter): label = type(element).__name__.lower() if label == "tokenconverter": ret = EditablePartial.from_call(railroad.Sequence, items=[]) else: ret = EditablePartial.from_call(AnnotatedItem, label=label, item="") elif isinstance(element, pyparsing.Opt): ret = EditablePartial.from_call(railroad.Optional, item="") elif isinstance(element, pyparsing.OneOrMore): if element.not_ender is not None: args = [ parent, lookup, vertical, index, name_hint, show_results_names, show_groups, show_hidden, ] return _to_diagram_element( (~element.not_ender.expr + element.expr)[1, ...].set_name(element.name), *args, ) ret = EditablePartial.from_call(railroad.OneOrMore, item=None) elif isinstance(element, pyparsing.ZeroOrMore): if element.not_ender is not None: args = [ parent, lookup, vertical, index, name_hint, show_results_names, show_groups, show_hidden, ] return _to_diagram_element( (~element.not_ender.expr + element.expr)[...].set_name(element.name), *args, ) ret = EditablePartial.from_call(railroad.ZeroOrMore, item="") elif isinstance(element, pyparsing.Empty) and not element.customName: # Skip unnamed "Empty" elements ret = None elif isinstance(element, pyparsing.ParseElementEnhance): ret = EditablePartial.from_call(railroad.Sequence, items=[]) elif len(exprs) > 0 and not element_results_name: ret = EditablePartial.from_call(railroad.Group, item="", label=name) elif isinstance(element, pyparsing.Regex): collapsed_patt = _collapse_verbose_regex(element.pattern) ret = EditablePartial.from_call(railroad.Terminal, collapsed_patt) elif len(exprs) > 0: ret = EditablePartial.from_call(railroad.Sequence, items=[]) else: terminal = EditablePartial.from_call(railroad.Terminal, element.defaultName) ret = terminal if ret is None: return # Indicate this element's position in the tree so we can extract it if necessary lookup[el_id] = ElementState( element=element, converted=ret, parent=parent, parent_index=index, number=lookup.generate_index(), ) if element.customName: lookup[el_id].mark_for_extraction(el_id, lookup, element.customName) i = 0 for expr in exprs: # Add a placeholder index in case we have to extract the child before we even add it to the parent if "items" in ret.kwargs: ret.kwargs["items"].insert(i, None) item = _to_diagram_element( expr, parent=ret, lookup=lookup, vertical=vertical, index=i, show_results_names=show_results_names, show_groups=show_groups, show_hidden=show_hidden, ) # Some elements don't need to be shown in the diagram if item is not None: if "item" in ret.kwargs: ret.kwargs["item"] = item elif "items" in ret.kwargs: # If we've already extracted the child, don't touch this index, since it's occupied by a nonterminal ret.kwargs["items"][i] = item i += 1 elif "items" in ret.kwargs: # If we're supposed to skip this element, remove it from the parent del ret.kwargs["items"][i] # If all this items children are none, skip this item if ret and ( ("items" in ret.kwargs and len(ret.kwargs["items"]) == 0) or ("item" in ret.kwargs and ret.kwargs["item"] is None) ): ret = EditablePartial.from_call(railroad.Terminal, name) # Mark this element as "complete", ie it has all of its children if el_id in lookup: lookup[el_id].complete = True if el_id in lookup and lookup[el_id].extract and lookup[el_id].complete: lookup.extract_into_diagram(el_id) if ret is not None: text = lookup.diagrams[el_id].kwargs["name"] href = f"#{_make_bookmark(text)}" ret = EditablePartial.from_call( railroad.NonTerminal, text=text, href=href ) return ret ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7232046 pyparsing-3.3.2/pyparsing/exceptions.py0000644000000000000000000002534515134002420015230 0ustar00# exceptions.py from __future__ import annotations import copy import re import sys import typing import warnings from functools import cached_property from .warnings import PyparsingDeprecationWarning from .unicode import pyparsing_unicode as ppu from .util import ( _collapse_string_to_ranges, col, deprecate_argument, line, lineno, replaced_by_pep8, ) class _ExceptionWordUnicodeSet( ppu.Latin1, ppu.LatinA, ppu.LatinB, ppu.Greek, ppu.Cyrillic ): pass _extract_alphanums = _collapse_string_to_ranges(_ExceptionWordUnicodeSet.alphanums) _exception_word_extractor = re.compile(fr"([{_extract_alphanums}]{{1,16}})|.") class ParseBaseException(Exception): """base exception class for all parsing runtime exceptions""" loc: int msg: str pstr: str parser_element: typing.Any # "ParserElement" args: tuple[str, int, typing.Optional[str]] __slots__ = ( "loc", "msg", "pstr", "parser_element", "args", ) # Performance tuning: we construct a *lot* of these, so keep this # constructor as small and fast as possible def __init__( self, pstr: str, loc: int = 0, msg: typing.Optional[str] = None, elem=None, ) -> None: if msg is None: msg, pstr = pstr, "" self.loc = loc self.msg = msg self.pstr = pstr self.parser_element = elem self.args = (pstr, loc, msg) @staticmethod def explain_exception(exc: Exception, depth: int = 16) -> str: """ Method to take an exception and translate the Python internal traceback into a list of the pyparsing expressions that caused the exception to be raised. Parameters: - exc - exception raised during parsing (need not be a ParseException, in support of Python exceptions that might be raised in a parse action) - depth (default=16) - number of levels back in the stack trace to list expression and function names; if None, the full stack trace names will be listed; if 0, only the failing input line, marker, and exception string will be shown Returns a multi-line string listing the ParserElements and/or function names in the exception's stack trace. """ import inspect from .core import ParserElement if depth is None: depth = sys.getrecursionlimit() ret: list[str] = [] if isinstance(exc, ParseBaseException): ret.append(exc.line) ret.append(f"{'^':>{exc.column}}") ret.append(f"{type(exc).__name__}: {exc}") if depth <= 0 or exc.__traceback__ is None: return "\n".join(ret) callers = inspect.getinnerframes(exc.__traceback__, context=depth) seen: set[int] = set() for ff in callers[-depth:]: frm = ff[0] f_self = frm.f_locals.get("self", None) if isinstance(f_self, ParserElement): if not frm.f_code.co_name.startswith(("parseImpl", "_parseNoCache")): continue if id(f_self) in seen: continue seen.add(id(f_self)) self_type = type(f_self) ret.append(f"{self_type.__module__}.{self_type.__name__} - {f_self}") elif f_self is not None: self_type = type(f_self) ret.append(f"{self_type.__module__}.{self_type.__name__}") else: code = frm.f_code if code.co_name in ("wrapper", ""): continue ret.append(code.co_name) depth -= 1 if not depth: break return "\n".join(ret) @classmethod def _from_exception(cls, pe) -> ParseBaseException: """ internal factory method to simplify creating one type of ParseException from another - avoids having __init__ signature conflicts among subclasses """ return cls(pe.pstr, pe.loc, pe.msg, pe.parser_element) @cached_property def line(self) -> str: """ Return the line of text where the exception occurred. """ return line(self.loc, self.pstr) @cached_property def lineno(self) -> int: """ Return the 1-based line number of text where the exception occurred. """ return lineno(self.loc, self.pstr) @cached_property def col(self) -> int: """ Return the 1-based column on the line of text where the exception occurred. """ return col(self.loc, self.pstr) @cached_property def column(self) -> int: """ Return the 1-based column on the line of text where the exception occurred. """ return col(self.loc, self.pstr) @cached_property def found(self) -> str: if not self.pstr: return "" if self.loc >= len(self.pstr): return "end of text" # pull out next word at error location found_match = _exception_word_extractor.match(self.pstr, self.loc) if found_match is not None: found_text = found_match[0] else: found_text = self.pstr[self.loc : self.loc + 1] return repr(found_text).replace(r"\\", "\\") # pre-PEP8 compatibility @property def parserElement(self): warnings.warn( "parserElement is deprecated, use parser_element", PyparsingDeprecationWarning, stacklevel=2, ) return self.parser_element @parserElement.setter def parserElement(self, elem): warnings.warn( "parserElement is deprecated, use parser_element", PyparsingDeprecationWarning, stacklevel=2, ) self.parser_element = elem def copy(self): return copy.copy(self) def formatted_message(self) -> str: """ Output the formatted exception message. Can be overridden to customize the message formatting or contents. .. versionadded:: 3.2.0 """ found_phrase = f", found {self.found}" if self.found else "" return f"{self.msg}{found_phrase} (at char {self.loc}), (line:{self.lineno}, col:{self.column})" def __str__(self) -> str: """ .. versionchanged:: 3.2.0 Now uses :meth:`formatted_message` to format message. """ try: return self.formatted_message() except Exception as ex: return ( f"{type(self).__name__}: {self.msg}" f" ({type(ex).__name__}: {ex} while formatting message)" ) def __repr__(self): return str(self) def mark_input_line( self, marker_string: typing.Optional[str] = None, **kwargs ) -> str: """ Extracts the exception line from the input string, and marks the location of the exception with a special symbol. """ markerString: str = deprecate_argument(kwargs, "markerString", ">!<") markerString = marker_string if marker_string is not None else markerString line_str = self.line line_column = self.column - 1 if markerString: line_str = f"{line_str[:line_column]}{markerString}{line_str[line_column:]}" return line_str.strip() def explain(self, depth: int = 16) -> str: """ Method to translate the Python internal traceback into a list of the pyparsing expressions that caused the exception to be raised. Parameters: - depth (default=16) - number of levels back in the stack trace to list expression and function names; if None, the full stack trace names will be listed; if 0, only the failing input line, marker, and exception string will be shown Returns a multi-line string listing the ParserElements and/or function names in the exception's stack trace. Example: .. testcode:: # an expression to parse 3 integers expr = pp.Word(pp.nums) * 3 try: # a failing parse - the third integer is prefixed with "A" expr.parse_string("123 456 A789") except pp.ParseException as pe: print(pe.explain(depth=0)) prints: .. testoutput:: 123 456 A789 ^ ParseException: Expected W:(0-9), found 'A789' (at char 8), (line:1, col:9) Note: the diagnostic output will include string representations of the expressions that failed to parse. These representations will be more helpful if you use `set_name` to give identifiable names to your expressions. Otherwise they will use the default string forms, which may be cryptic to read. Note: pyparsing's default truncation of exception tracebacks may also truncate the stack of expressions that are displayed in the ``explain`` output. To get the full listing of parser expressions, you may have to set ``ParserElement.verbose_stacktrace = True`` """ return self.explain_exception(self, depth) # Compatibility synonyms # fmt: off markInputline = replaced_by_pep8("markInputline", mark_input_line) # fmt: on class ParseException(ParseBaseException): """ Exception thrown when a parse expression doesn't match the input string Example: .. testcode:: integer = Word(nums).set_name("integer") try: integer.parse_string("ABC") except ParseException as pe: print(pe, f"column: {pe.column}") prints: .. testoutput:: Expected integer, found 'ABC' (at char 0), (line:1, col:1) column: 1 """ class ParseFatalException(ParseBaseException): """ User-throwable exception thrown when inconsistent parse content is found; stops all parsing immediately """ class ParseSyntaxException(ParseFatalException): """ Just like :class:`ParseFatalException`, but thrown internally when an :class:`ErrorStop` ('-' operator) indicates that parsing is to stop immediately because an unbacktrackable syntax error has been found. """ class RecursiveGrammarException(Exception): """ .. deprecated:: 3.0.0 Only used by the deprecated :meth:`ParserElement.validate`. Exception thrown by :class:`ParserElement.validate` if the grammar could be left-recursive; parser may need to enable left recursion using :class:`ParserElement.enable_left_recursion` """ def __init__(self, parseElementList) -> None: self.parseElementTrace = parseElementList def __str__(self) -> str: return f"RecursiveGrammarException: {self.parseElementTrace}" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7232046 pyparsing-3.3.2/pyparsing/helpers.py0000644000000000000000000012150115134002420014500 0ustar00# helpers.py import html.entities import operator import re import sys import typing from . import __diag__ from .core import * from .util import ( _bslash, _flatten, _escape_regex_range_chars, make_compressed_re, replaced_by_pep8, ) def _suppression(expr: Union[ParserElement, str]) -> ParserElement: # internal helper to avoid wrapping Suppress inside another Suppress if isinstance(expr, Suppress): return expr return Suppress(expr) # # global helpers # def counted_array( expr: ParserElement, int_expr: typing.Optional[ParserElement] = None, **kwargs ) -> ParserElement: """Helper to define a counted list of expressions. This helper defines a pattern of the form:: integer expr expr expr... where the leading integer tells how many expr expressions follow. The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed. If ``int_expr`` is specified, it should be a pyparsing expression that produces an integer value. Examples: .. doctest:: >>> counted_array(Word(alphas)).parse_string('2 ab cd ef') ParseResults(['ab', 'cd'], {}) - In this parser, the leading integer value is given in binary, '10' indicating that 2 values are in the array: .. doctest:: >>> binary_constant = Word('01').set_parse_action(lambda t: int(t[0], 2)) >>> counted_array(Word(alphas), int_expr=binary_constant ... ).parse_string('10 ab cd ef') ParseResults(['ab', 'cd'], {}) - If other fields must be parsed after the count but before the list items, give the fields results names and they will be preserved in the returned ParseResults: .. doctest:: >>> ppc = pyparsing.common >>> count_with_metadata = ppc.integer + Word(alphas)("type") >>> typed_array = counted_array(Word(alphanums), ... int_expr=count_with_metadata)("items") >>> result = typed_array.parse_string("3 bool True True False") >>> print(result.dump()) ['True', 'True', 'False'] - items: ['True', 'True', 'False'] - type: 'bool' """ intExpr: typing.Optional[ParserElement] = deprecate_argument( kwargs, "intExpr", None ) intExpr = intExpr or int_expr array_expr = Forward() def count_field_parse_action(s, l, t): nonlocal array_expr n = t[0] array_expr <<= (expr * n) if n else Empty() # clear list contents, but keep any named results del t[:] if intExpr is None: intExpr = Word(nums).set_parse_action(lambda t: int(t[0])) else: intExpr = intExpr.copy() intExpr.set_name("arrayLen") intExpr.add_parse_action(count_field_parse_action, call_during_try=True) return (intExpr + array_expr).set_name(f"(len) {expr}...") def match_previous_literal(expr: ParserElement) -> ParserElement: """Helper to define an expression that is indirectly defined from the tokens matched in a previous expression, that is, it looks for a 'repeat' of a previous expression. For example:: .. testcode:: first = Word(nums) second = match_previous_literal(first) match_expr = first + ":" + second will match ``"1:1"``, but not ``"1:2"``. Because this matches a previous literal, will also match the leading ``"1:1"`` in ``"1:10"``. If this is not desired, use :class:`match_previous_expr`. Do *not* use with packrat parsing enabled. """ rep = Forward() def copy_token_to_repeater(s, l, t): if not t: rep << Empty() return if len(t) == 1: rep << t[0] return # flatten t tokens tflat = _flatten(t.as_list()) rep << And(Literal(tt) for tt in tflat) expr.add_parse_action(copy_token_to_repeater, call_during_try=True) rep.set_name(f"(prev) {expr}") return rep def match_previous_expr(expr: ParserElement) -> ParserElement: """Helper to define an expression that is indirectly defined from the tokens matched in a previous expression, that is, it looks for a 'repeat' of a previous expression. For example: .. testcode:: first = Word(nums) second = match_previous_expr(first) match_expr = first + ":" + second will match ``"1:1"``, but not ``"1:2"``. Because this matches by expressions, will *not* match the leading ``"1:1"`` in ``"1:10"``; the expressions are evaluated first, and then compared, so ``"1"`` is compared with ``"10"``. Do *not* use with packrat parsing enabled. """ rep = Forward() e2 = expr.copy() rep <<= e2 def copy_token_to_repeater(s, l, t): matchTokens = _flatten(t.as_list()) def must_match_these_tokens(s, l, t): theseTokens = _flatten(t.as_list()) if theseTokens != matchTokens: raise ParseException( s, l, f"Expected {matchTokens}, found{theseTokens}" ) rep.set_parse_action(must_match_these_tokens, call_during_try=True) expr.add_parse_action(copy_token_to_repeater, call_during_try=True) rep.set_name(f"(prev) {expr}") return rep def one_of( strs: Union[typing.Iterable[str], str], caseless: bool = False, use_regex: bool = True, as_keyword: bool = False, **kwargs, ) -> ParserElement: """Helper to quickly define a set of alternative :class:`Literal` s, and makes sure to do longest-first testing when there is a conflict, regardless of the input order, but returns a :class:`MatchFirst` for best performance. :param strs: a string of space-delimited literals, or a collection of string literals :param caseless: treat all literals as caseless :param use_regex: bool - as an optimization, will generate a :class:`Regex` object; otherwise, will generate a :class:`MatchFirst` object (if ``caseless=True`` or ``as_keyword=True``, or if creating a :class:`Regex` raises an exception) :param as_keyword: bool - enforce :class:`Keyword`-style matching on the generated expressions Parameters ``asKeyword`` and ``useRegex`` are retained for pre-PEP8 compatibility, but will be removed in a future release. Example: .. testcode:: comp_oper = one_of("< = > <= >= !=") var = Word(alphas) number = Word(nums) term = var | number comparison_expr = term + comp_oper + term print(comparison_expr.search_string("B = 12 AA=23 B<=AA AA>12")) prints: .. testoutput:: [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] """ useRegex: bool = deprecate_argument(kwargs, "useRegex", True) asKeyword: bool = deprecate_argument(kwargs, "asKeyword", False) asKeyword = asKeyword or as_keyword useRegex = useRegex and use_regex if ( isinstance(caseless, str_type) and __diag__.warn_on_multiple_string_args_to_oneof ): warnings.warn( "warn_on_multiple_string_args_to_oneof:" " More than one string argument passed to one_of, pass" " choices as a list or space-delimited string", PyparsingDiagnosticWarning, stacklevel=2, ) if caseless: is_equal = lambda a, b: a.upper() == b.upper() masks = lambda a, b: b.upper().startswith(a.upper()) else: is_equal = operator.eq masks = lambda a, b: b.startswith(a) symbols: list[str] if isinstance(strs, str_type): strs = typing.cast(str, strs) symbols = strs.split() elif isinstance(strs, Iterable): symbols = list(strs) else: raise TypeError("Invalid argument to one_of, expected string or iterable") if not symbols: return NoMatch() # reorder given symbols to take care to avoid masking longer choices with shorter ones # (but only if the given symbols are not just single characters) i = 0 while i < len(symbols) - 1: cur = symbols[i] for j, other in enumerate(symbols[i + 1 :]): if is_equal(other, cur): del symbols[i + j + 1] break if len(other) > len(cur) and masks(cur, other): del symbols[i + j + 1] symbols.insert(i, other) break else: i += 1 if useRegex: re_flags: int = re.IGNORECASE if caseless else 0 try: if all(len(sym) == 1 for sym in symbols): # symbols are just single characters, create range regex pattern patt = f"[{''.join(_escape_regex_range_chars(sym) for sym in symbols)}]" else: patt = "|".join(re.escape(sym) for sym in symbols) # wrap with \b word break markers if defining as keywords if asKeyword: patt = rf"\b(?:{patt})\b" ret = Regex(patt, flags=re_flags) ret.set_name(" | ".join(repr(s) for s in symbols)) if caseless: # add parse action to return symbols as specified, not in random # casing as found in input string symbol_map = {sym.lower(): sym for sym in symbols} ret.add_parse_action(lambda s, l, t: symbol_map[t[0].lower()]) return ret except re.error: warnings.warn( "Exception creating Regex for one_of, building MatchFirst", PyparsingDiagnosticWarning, stacklevel=2, ) # last resort, just use MatchFirst of Token class corresponding to caseless # and asKeyword settings CASELESS = KEYWORD = True parse_element_class = { (CASELESS, KEYWORD): CaselessKeyword, (CASELESS, not KEYWORD): CaselessLiteral, (not CASELESS, KEYWORD): Keyword, (not CASELESS, not KEYWORD): Literal, }[(caseless, asKeyword)] return MatchFirst(parse_element_class(sym) for sym in symbols).set_name( " | ".join(symbols) ) def dict_of(key: ParserElement, value: ParserElement) -> Dict: """Helper to easily and clearly define a dictionary by specifying the respective patterns for the key and value. Takes care of defining the :class:`Dict`, :class:`ZeroOrMore`, and :class:`Group` tokens in the proper order. The key pattern can include delimiting markers or punctuation, as long as they are suppressed, thereby leaving the significant key text. The value pattern can include named results, so that the :class:`Dict` results can include named token fields. Example: .. doctest:: >>> text = "shape: SQUARE posn: upper left color: light blue texture: burlap" >>> data_word = Word(alphas) >>> label = data_word + FollowedBy(':') >>> attr_expr = ( ... label ... + Suppress(':') ... + OneOrMore(data_word, stop_on=label) ... .set_parse_action(' '.join)) >>> print(attr_expr[1, ...].parse_string(text).dump()) ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] >>> attr_label = label >>> attr_value = Suppress(':') + OneOrMore(data_word, stop_on=label ... ).set_parse_action(' '.join) # similar to Dict, but simpler call format >>> result = dict_of(attr_label, attr_value).parse_string(text) >>> print(result.dump()) [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - color: 'light blue' - posn: 'upper left' - shape: 'SQUARE' - texture: 'burlap' [0]: ['shape', 'SQUARE'] [1]: ['posn', 'upper left'] [2]: ['color', 'light blue'] [3]: ['texture', 'burlap'] >>> print(result['shape']) SQUARE >>> print(result.shape) # object attribute access works too SQUARE >>> print(result.as_dict()) {'shape': 'SQUARE', 'posn': 'upper left', 'color': 'light blue', 'texture': 'burlap'} """ return Dict(OneOrMore(Group(key + value))) def original_text_for( expr: ParserElement, as_string: bool = True, **kwargs ) -> ParserElement: """Helper to return the original, untokenized text for a given expression. Useful to restore the parsed fields of an HTML start tag into the raw tag text itself, or to revert separate tokens with intervening whitespace back to the original matching input text. By default, returns a string containing the original parsed text. If the optional ``as_string`` argument is passed as ``False``, then the return value is a :class:`ParseResults` containing any results names that were originally matched, and a single token containing the original matched text from the input string. So if the expression passed to :class:`original_text_for` contains expressions with defined results names, you must set ``as_string`` to ``False`` if you want to preserve those results name values. The ``asString`` pre-PEP8 argument is retained for compatibility, but will be removed in a future release. Example: .. testcode:: src = "this is test bold text normal text " for tag in ("b", "i"): opener, closer = make_html_tags(tag) patt = original_text_for(opener + ... + closer) print(patt.search_string(src)[0]) prints: .. testoutput:: [' bold text '] ['text'] """ asString: bool = deprecate_argument(kwargs, "asString", True) asString = asString and as_string locMarker = Empty().set_parse_action(lambda s, loc, t: loc) endlocMarker = locMarker.copy() endlocMarker.callPreparse = False matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") if asString: extractText = lambda s, l, t: s[t._original_start : t._original_end] else: def extractText(s, l, t): t[:] = [s[t.pop("_original_start") : t.pop("_original_end")]] matchExpr.set_parse_action(extractText) matchExpr.ignoreExprs = expr.ignoreExprs matchExpr.suppress_warning(Diagnostics.warn_ungrouped_named_tokens_in_collection) return matchExpr def ungroup(expr: ParserElement) -> ParserElement: """Helper to undo pyparsing's default grouping of And expressions, even if all but one are non-empty. """ return TokenConverter(expr).add_parse_action(lambda t: t[0]) def locatedExpr(expr: ParserElement) -> ParserElement: """ .. deprecated:: 3.0.0 Use the :class:`Located` class instead. Note that `Located` returns results with one less grouping level. Helper to decorate a returned token with its starting and ending locations in the input string. This helper adds the following results names: - ``locn_start`` - location where matched expression begins - ``locn_end`` - location where matched expression ends - ``value`` - the actual parsed results Be careful if the input text contains ```` characters, you may want to call :meth:`ParserElement.parse_with_tabs` """ warnings.warn( f"{'locatedExpr'!r} deprecated - use {'Located'!r}", PyparsingDeprecationWarning, stacklevel=2, ) locator = Empty().set_parse_action(lambda ss, ll, tt: ll) return Group( locator("locn_start") + expr("value") + locator.copy().leave_whitespace()("locn_end") ) # define special default value to permit None as a significant value for # ignore_expr _NO_IGNORE_EXPR_GIVEN = NoMatch() def nested_expr( opener: Union[str, ParserElement] = "(", closer: Union[str, ParserElement] = ")", content: typing.Optional[ParserElement] = None, ignore_expr: typing.Optional[ParserElement] = _NO_IGNORE_EXPR_GIVEN, **kwargs, ) -> ParserElement: """Helper method for defining nested lists enclosed in opening and closing delimiters (``"("`` and ``")"`` are the default). :param opener: str - opening character for a nested list (default= ``"("``); can also be a pyparsing expression :param closer: str - closing character for a nested list (default= ``")"``); can also be a pyparsing expression :param content: expression for items within the nested lists :param ignore_expr: expression for ignoring opening and closing delimiters (default = :class:`quoted_string`) Parameter ``ignoreExpr`` is retained for compatibility but will be removed in a future release. If an expression is not provided for the content argument, the nested expression will capture all whitespace-delimited content between delimiters as a list of separate values. Use the ``ignore_expr`` argument to define expressions that may contain opening or closing characters that should not be treated as opening or closing characters for nesting, such as quoted_string or a comment expression. Specify multiple expressions using an :class:`Or` or :class:`MatchFirst`. The default is :class:`quoted_string`, but if no expressions are to be ignored, then pass ``None`` for this argument. Example: .. testcode:: data_type = one_of("void int short long char float double") decl_data_type = Combine(data_type + Opt(Word('*'))) ident = Word(alphas+'_', alphanums+'_') number = pyparsing_common.number arg = Group(decl_data_type + ident) LPAR, RPAR = map(Suppress, "()") code_body = nested_expr('{', '}', ignore_expr=(quoted_string | c_style_comment)) c_function = (decl_data_type("type") + ident("name") + LPAR + Opt(DelimitedList(arg), [])("args") + RPAR + code_body("body")) c_function.ignore(c_style_comment) source_code = ''' int is_odd(int x) { return (x%2); } int dec_to_hex(char hchar) { if (hchar >= '0' && hchar <= '9') { return (ord(hchar)-ord('0')); } else { return (10+ord(hchar)-ord('A')); } } ''' for func in c_function.search_string(source_code): print(f"{func.name} ({func.type}) args: {func.args}") prints: .. testoutput:: is_odd (int) args: [['int', 'x']] dec_to_hex (int) args: [['char', 'hchar']] """ ignoreExpr: ParserElement = deprecate_argument( kwargs, "ignoreExpr", _NO_IGNORE_EXPR_GIVEN ) if ignoreExpr != ignore_expr: ignoreExpr = ignore_expr if ignoreExpr is _NO_IGNORE_EXPR_GIVEN else ignoreExpr # type: ignore [assignment] if ignoreExpr is _NO_IGNORE_EXPR_GIVEN: ignoreExpr = quoted_string() if opener == closer: raise ValueError("opening and closing strings cannot be the same") if content is None: if isinstance(opener, str_type) and isinstance(closer, str_type): opener = typing.cast(str, opener) closer = typing.cast(str, closer) if len(opener) == 1 and len(closer) == 1: if ignoreExpr is not None: content = Combine( OneOrMore( ~ignoreExpr + CharsNotIn( opener + closer + ParserElement.DEFAULT_WHITE_CHARS, exact=1, ) ) ) else: content = Combine( Empty() + CharsNotIn( opener + closer + ParserElement.DEFAULT_WHITE_CHARS ) ) else: if ignoreExpr is not None: content = Combine( OneOrMore( ~ignoreExpr + ~Literal(opener) + ~Literal(closer) + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) ) ) else: content = Combine( OneOrMore( ~Literal(opener) + ~Literal(closer) + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) ) ) else: raise ValueError( "opening and closing arguments must be strings if no content expression is given" ) # for these internally-created context expressions, simulate whitespace-skipping if ParserElement.DEFAULT_WHITE_CHARS: content.set_parse_action( lambda t: t[0].strip(ParserElement.DEFAULT_WHITE_CHARS) ) ret = Forward() if ignoreExpr is not None: ret <<= Group( _suppression(opener) + ZeroOrMore(ignoreExpr | ret | content) + _suppression(closer) ) else: ret <<= Group( _suppression(opener) + ZeroOrMore(ret | content) + _suppression(closer) ) ret.set_name(f"nested {opener}{closer} expression") # don't override error message from content expressions ret.errmsg = None return ret def _makeTags(tagStr, xml, suppress_LT=Suppress("<"), suppress_GT=Suppress(">")): """Internal helper to construct opening and closing tag expressions, given a tag name""" if isinstance(tagStr, str_type): resname = tagStr tagStr = Keyword(tagStr, caseless=not xml) else: resname = tagStr.name tagAttrName = Word(alphas, alphanums + "_-:") if xml: tagAttrValue = dbl_quoted_string.copy().set_parse_action(remove_quotes) openTag = ( suppress_LT + tagStr("tag") + Dict(ZeroOrMore(Group(tagAttrName + Suppress("=") + tagAttrValue))) + Opt("/", default=[False])("empty").set_parse_action( lambda s, l, t: t[0] == "/" ) + suppress_GT ) else: tagAttrValue = quoted_string.copy().set_parse_action(remove_quotes) | Word( printables, exclude_chars=">" ) openTag = ( suppress_LT + tagStr("tag") + Dict( ZeroOrMore( Group( tagAttrName.set_parse_action(lambda t: t[0].lower()) + Opt(Suppress("=") + tagAttrValue) ) ) ) + Opt("/", default=[False])("empty").set_parse_action( lambda s, l, t: t[0] == "/" ) + suppress_GT ) closeTag = Combine(Literal("", adjacent=False) openTag.set_name(f"<{resname}>") # add start results name in parse action now that ungrouped names are not reported at two levels openTag.add_parse_action( lambda t: t.__setitem__( "start" + "".join(resname.replace(":", " ").title().split()), t.copy() ) ) closeTag = closeTag( "end" + "".join(resname.replace(":", " ").title().split()) ).set_name(f"") openTag.tag = resname closeTag.tag = resname openTag.tag_body = SkipTo(closeTag()) return openTag, closeTag def make_html_tags( tag_str: Union[str, ParserElement], ) -> tuple[ParserElement, ParserElement]: """Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches tags in either upper or lower case, attributes with namespaces and with quoted or unquoted values. Example: .. testcode:: text = 'More info at the pyparsing wiki page' # make_html_tags returns pyparsing expressions for the opening and # closing tags as a 2-tuple a, a_end = make_html_tags("A") link_expr = a + SkipTo(a_end)("link_text") + a_end for link in link_expr.search_string(text): # attributes in the tag (like "href" shown here) are # also accessible as named results print(link.link_text, '->', link.href) prints: .. testoutput:: pyparsing -> https://github.com/pyparsing/pyparsing/wiki """ return _makeTags(tag_str, False) def make_xml_tags( tag_str: Union[str, ParserElement], ) -> tuple[ParserElement, ParserElement]: """Helper to construct opening and closing tag expressions for XML, given a tag name. Matches tags only in the given upper/lower case. Example: similar to :class:`make_html_tags` """ return _makeTags(tag_str, True) any_open_tag: ParserElement any_close_tag: ParserElement any_open_tag, any_close_tag = make_html_tags( Word(alphas, alphanums + "_:").set_name("any tag") ) _htmlEntityMap = {k.rstrip(";"): v for k, v in html.entities.html5.items()} _most_common_entities = "nbsp lt gt amp quot apos cent pound euro copy".replace( " ", "|" ) common_html_entity = Regex( lambda: f"&(?P{_most_common_entities}|{make_compressed_re(_htmlEntityMap)});" ).set_name("common HTML entity") def replace_html_entity(s, l, t): """Helper parser action to replace common HTML entities with their special characters""" return _htmlEntityMap.get(t.entity) class OpAssoc(Enum): """Enumeration of operator associativity - used in constructing InfixNotationOperatorSpec for :class:`infix_notation`""" LEFT = 1 RIGHT = 2 InfixNotationOperatorArgType = Union[ ParserElement, str, tuple[Union[ParserElement, str], Union[ParserElement, str]] ] InfixNotationOperatorSpec = Union[ tuple[ InfixNotationOperatorArgType, int, OpAssoc, typing.Optional[ParseAction], ], tuple[ InfixNotationOperatorArgType, int, OpAssoc, ], ] def infix_notation( base_expr: ParserElement, op_list: list[InfixNotationOperatorSpec], lpar: Union[str, ParserElement] = Suppress("("), rpar: Union[str, ParserElement] = Suppress(")"), ) -> Forward: """Helper method for constructing grammars of expressions made up of operators working in a precedence hierarchy. Operators may be unary or binary, left- or right-associative. Parse actions can also be attached to operator expressions. The generated parser will also recognize the use of parentheses to override operator precedences (see example below). Note: if you define a deep operator list, you may see performance issues when using infix_notation. See :class:`ParserElement.enable_packrat` for a mechanism to potentially improve your parser performance. Parameters: :param base_expr: expression representing the most basic operand to be used in the expression :param op_list: list of tuples, one for each operator precedence level in the expression grammar; each tuple is of the form ``(op_expr, num_operands, right_left_assoc, (optional)parse_action)``, where: - ``op_expr`` is the pyparsing expression for the operator; may also be a string, which will be converted to a Literal; if ``num_operands`` is 3, ``op_expr`` is a tuple of two expressions, for the two operators separating the 3 terms - ``num_operands`` is the number of terms for this operator (must be 1, 2, or 3) - ``right_left_assoc`` is the indicator whether the operator is right or left associative, using the pyparsing-defined constants ``OpAssoc.RIGHT`` and ``OpAssoc.LEFT``. - ``parse_action`` is the parse action to be associated with expressions matching this operator expression (the parse action tuple member may be omitted); if the parse action is passed a tuple or list of functions, this is equivalent to calling ``set_parse_action(*fn)`` (:class:`ParserElement.set_parse_action`) :param lpar: expression for matching left-parentheses; if passed as a str, then will be parsed as ``Suppress(lpar)``. If lpar is passed as an expression (such as ``Literal('(')``), then it will be kept in the parsed results, and grouped with them. (default= ``Suppress('(')``) :param rpar: expression for matching right-parentheses; if passed as a str, then will be parsed as ``Suppress(rpar)``. If rpar is passed as an expression (such as ``Literal(')')``), then it will be kept in the parsed results, and grouped with them. (default= ``Suppress(')')``) Example: .. testcode:: # simple example of four-function arithmetic with ints and # variable names integer = pyparsing_common.signed_integer varname = pyparsing_common.identifier arith_expr = infix_notation(integer | varname, [ ('-', 1, OpAssoc.RIGHT), (one_of('* /'), 2, OpAssoc.LEFT), (one_of('+ -'), 2, OpAssoc.LEFT), ]) arith_expr.run_tests(''' 5+3*6 (5+3)*6 (5+x)*y -2--11 ''', full_dump=False) prints: .. testoutput:: :options: +NORMALIZE_WHITESPACE 5+3*6 [[5, '+', [3, '*', 6]]] (5+3)*6 [[[5, '+', 3], '*', 6]] (5+x)*y [[[5, '+', 'x'], '*', 'y']] -2--11 [[['-', 2], '-', ['-', 11]]] """ # captive version of FollowedBy that does not do parse actions or capture results names class _FB(FollowedBy): def parseImpl(self, instring, loc, doActions=True): self.expr.try_parse(instring, loc) return loc, [] _FB.__name__ = "FollowedBy>" ret = Forward() ret.set_name(f"{base_expr.name}_expression") if isinstance(lpar, str): lpar = Suppress(lpar) if isinstance(rpar, str): rpar = Suppress(rpar) nested_expr = (lpar + ret + rpar).set_name(f"nested_{base_expr.name}_expression") # if lpar and rpar are not suppressed, wrap in group if not (isinstance(lpar, Suppress) and isinstance(rpar, Suppress)): lastExpr = base_expr | Group(nested_expr) else: lastExpr = base_expr | nested_expr arity: int rightLeftAssoc: opAssoc pa: typing.Optional[ParseAction] opExpr1: ParserElement opExpr2: ParserElement matchExpr: ParserElement match_lookahead: ParserElement for operDef in op_list: opExpr, arity, rightLeftAssoc, pa = (operDef + (None,))[:4] # type: ignore[assignment] if isinstance(opExpr, str_type): opExpr = ParserElement._literalStringClass(opExpr) opExpr = typing.cast(ParserElement, opExpr) if arity == 3: if not isinstance(opExpr, (tuple, list)) or len(opExpr) != 2: raise ValueError( "if numterms=3, opExpr must be a tuple or list of two expressions" ) opExpr1, opExpr2 = opExpr term_name = f"{opExpr1}{opExpr2} operations" else: term_name = f"{opExpr} operations" if not 1 <= arity <= 3: raise ValueError("operator must be unary (1), binary (2), or ternary (3)") if rightLeftAssoc not in (OpAssoc.LEFT, OpAssoc.RIGHT): raise ValueError("operator must indicate right or left associativity") thisExpr: ParserElement = Forward().set_name(term_name) thisExpr = typing.cast(Forward, thisExpr) match_lookahead = And([]) if rightLeftAssoc is OpAssoc.LEFT: if arity == 1: match_lookahead = _FB(lastExpr + opExpr) matchExpr = Group(lastExpr + opExpr[1, ...]) elif arity == 2: if opExpr is not None: match_lookahead = _FB(lastExpr + opExpr + lastExpr) matchExpr = Group(lastExpr + (opExpr + lastExpr)[1, ...]) else: match_lookahead = _FB(lastExpr + lastExpr) matchExpr = Group(lastExpr[2, ...]) elif arity == 3: match_lookahead = _FB( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) matchExpr = Group( lastExpr + (opExpr1 + lastExpr + opExpr2 + lastExpr)[1, ...] ) elif rightLeftAssoc is OpAssoc.RIGHT: if arity == 1: # try to avoid LR with this extra test if not isinstance(opExpr, Opt): opExpr = Opt(opExpr) match_lookahead = _FB(opExpr.expr + thisExpr) matchExpr = Group(opExpr + thisExpr) elif arity == 2: if opExpr is not None: match_lookahead = _FB(lastExpr + opExpr + thisExpr) matchExpr = Group(lastExpr + (opExpr + thisExpr)[1, ...]) else: match_lookahead = _FB(lastExpr + thisExpr) matchExpr = Group(lastExpr + thisExpr[1, ...]) elif arity == 3: match_lookahead = _FB( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) matchExpr = Group(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) # suppress lookahead expr from railroad diagrams match_lookahead.show_in_diagram = False # TODO - determine why this statement can't be included in the following # if pa block matchExpr = match_lookahead + matchExpr if pa: if isinstance(pa, (tuple, list)): matchExpr.set_parse_action(*pa) else: matchExpr.set_parse_action(pa) thisExpr <<= (matchExpr | lastExpr).set_name(term_name) lastExpr = thisExpr ret <<= lastExpr return ret def indentedBlock(blockStatementExpr, indentStack, indent=True, backup_stacks=[]): """ .. deprecated:: 3.0.0 Use the :class:`IndentedBlock` class instead. Note that `IndentedBlock` has a difference method signature. Helper method for defining space-delimited indentation blocks, such as those used to define block statements in Python source code. :param blockStatementExpr: expression defining syntax of statement that is repeated within the indented block :param indentStack: list created by caller to manage indentation stack (multiple ``statementWithIndentedBlock`` expressions within a single grammar should share a common ``indentStack``) :param indent: boolean indicating whether block must be indented beyond the current level; set to ``False`` for block of left-most statements A valid block must contain at least one ``blockStatement``. (Note that indentedBlock uses internal parse actions which make it incompatible with packrat parsing.) Example: .. testcode:: data = ''' def A(z): A1 B = 100 G = A2 A2 A3 B def BB(a,b,c): BB1 def BBA(): bba1 bba2 bba3 C D def spam(x,y): def eggs(z): pass ''' indentStack = [1] stmt = Forward() identifier = Word(alphas, alphanums) funcDecl = ("def" + identifier + Group("(" + Opt(delimitedList(identifier)) + ")") + ":") func_body = indentedBlock(stmt, indentStack) funcDef = Group(funcDecl + func_body) rvalue = Forward() funcCall = Group(identifier + "(" + Opt(delimitedList(rvalue)) + ")") rvalue << (funcCall | identifier | Word(nums)) assignment = Group(identifier + "=" + rvalue) stmt << (funcDef | assignment | identifier) module_body = stmt[1, ...] parseTree = module_body.parseString(data) parseTree.pprint() prints: .. testoutput:: [['def', 'A', ['(', 'z', ')'], ':', [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]], 'B', ['def', 'BB', ['(', 'a', 'b', 'c', ')'], ':', [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]], 'C', 'D', ['def', 'spam', ['(', 'x', 'y', ')'], ':', [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] """ warnings.warn( f"{'indentedBlock'!r} deprecated - use {'IndentedBlock'!r}", PyparsingDeprecationWarning, stacklevel=2, ) backup_stacks.append(indentStack[:]) def reset_stack(): indentStack[:] = backup_stacks[-1] def checkPeerIndent(s, l, t): if l >= len(s): return curCol = col(l, s) if curCol != indentStack[-1]: if curCol > indentStack[-1]: raise ParseException(s, l, "illegal nesting") raise ParseException(s, l, "not a peer entry") def checkSubIndent(s, l, t): curCol = col(l, s) if curCol > indentStack[-1]: indentStack.append(curCol) else: raise ParseException(s, l, "not a subentry") def checkUnindent(s, l, t): if l >= len(s): return curCol = col(l, s) if not (indentStack and curCol in indentStack): raise ParseException(s, l, "not an unindent") if curCol < indentStack[-1]: indentStack.pop() NL = OneOrMore(LineEnd().set_whitespace_chars("\t ").suppress()) INDENT = (Empty() + Empty().set_parse_action(checkSubIndent)).set_name("INDENT") PEER = Empty().set_parse_action(checkPeerIndent).set_name("") UNDENT = Empty().set_parse_action(checkUnindent).set_name("UNINDENT") if indent: smExpr = Group( Opt(NL) + INDENT + OneOrMore(PEER + Group(blockStatementExpr) + Opt(NL)) + UNDENT ) else: smExpr = Group( Opt(NL) + OneOrMore(PEER + Group(blockStatementExpr) + Opt(NL)) + Opt(UNDENT) ) # add a parse action to remove backup_stack from list of backups smExpr.add_parse_action( lambda: backup_stacks.pop(-1) and None if backup_stacks else None ) smExpr.set_fail_action(lambda a, b, c, d: reset_stack()) blockStatementExpr.ignore(_bslash + LineEnd()) return smExpr.set_name("indented block") # it's easy to get these comment structures wrong - they're very common, # so may as well make them available c_style_comment = Regex(r"/\*(?:[^*]|\*(?!/))*\*\/").set_name("C style comment") "Comment of the form ``/* ... */``" html_comment = Regex(r"").set_name("HTML comment") "Comment of the form ````" rest_of_line = Regex(r".*").leave_whitespace().set_name("rest of line") dbl_slash_comment = Regex(r"//(?:\\\n|[^\n])*").set_name("// comment") "Comment of the form ``// ... (to end of line)``" cpp_style_comment = Regex( r"(?:/\*(?:[^*]|\*(?!/))*\*\/)|(?://(?:\\\n|[^\n])*)" ).set_name("C++ style comment") "Comment of either form :class:`c_style_comment` or :class:`dbl_slash_comment`" java_style_comment = cpp_style_comment "Same as :class:`cpp_style_comment`" python_style_comment = Regex(r"#.*").set_name("Python style comment") "Comment of the form ``# ... (to end of line)``" # build list of built-in expressions, for future reference if a global default value # gets updated _builtin_exprs: list[ParserElement] = [ v for v in vars().values() if isinstance(v, ParserElement) ] # compatibility function, superseded by DelimitedList class def delimited_list( expr: Union[str, ParserElement], delim: Union[str, ParserElement] = ",", combine: bool = False, min: typing.Optional[int] = None, max: typing.Optional[int] = None, *, allow_trailing_delim: bool = False, ) -> ParserElement: """ .. deprecated:: 3.1.0 Use the :class:`DelimitedList` class instead. """ return DelimitedList( expr, delim, combine, min, max, allow_trailing_delim=allow_trailing_delim ) # Compatibility synonyms # fmt: off opAssoc = OpAssoc anyOpenTag = any_open_tag anyCloseTag = any_close_tag commonHTMLEntity = common_html_entity cStyleComment = c_style_comment htmlComment = html_comment restOfLine = rest_of_line dblSlashComment = dbl_slash_comment cppStyleComment = cpp_style_comment javaStyleComment = java_style_comment pythonStyleComment = python_style_comment delimitedList = replaced_by_pep8("delimitedList", DelimitedList) delimited_list = replaced_by_pep8("delimited_list", DelimitedList) countedArray = replaced_by_pep8("countedArray", counted_array) matchPreviousLiteral = replaced_by_pep8("matchPreviousLiteral", match_previous_literal) matchPreviousExpr = replaced_by_pep8("matchPreviousExpr", match_previous_expr) oneOf = replaced_by_pep8("oneOf", one_of) dictOf = replaced_by_pep8("dictOf", dict_of) originalTextFor = replaced_by_pep8("originalTextFor", original_text_for) nestedExpr = replaced_by_pep8("nestedExpr", nested_expr) makeHTMLTags = replaced_by_pep8("makeHTMLTags", make_html_tags) makeXMLTags = replaced_by_pep8("makeXMLTags", make_xml_tags) replaceHTMLEntity = replaced_by_pep8("replaceHTMLEntity", replace_html_entity) infixNotation = replaced_by_pep8("infixNotation", infix_notation) # fmt: on ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7232046 pyparsing-3.3.2/pyparsing/py.typed0000644000000000000000000000000015134002420014151 0ustar00././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7232046 pyparsing-3.3.2/pyparsing/results.py0000644000000000000000000006572315134002420014554 0ustar00# results.py from __future__ import annotations import collections from collections.abc import ( MutableMapping, Mapping, MutableSequence, Iterator, Iterable, ) import pprint from typing import Any from .util import deprecate_argument, _is_iterable, _flatten str_type: tuple[type, ...] = (str, bytes) _generator_type = type((_ for _ in ())) NULL_SLICE: slice = slice(None) class _ParseResultsWithOffset: tup: tuple[ParseResults, int] __slots__ = ["tup"] def __init__(self, p1: ParseResults, p2: int) -> None: self.tup: tuple[ParseResults, int] = (p1, p2) def __getitem__(self, i): return self.tup[i] def __getstate__(self): return self.tup def __setstate__(self, *args): self.tup = args[0] class ParseResults: """Structured parse results, to provide multiple means of access to the parsed data: - as a list (``len(results)``) - by list index (``results[0], results[1]``, etc.) - by attribute (``results.`` - see :class:`ParserElement.set_results_name`) Example: .. testcode:: integer = Word(nums) date_str = (integer.set_results_name("year") + '/' + integer.set_results_name("month") + '/' + integer.set_results_name("day")) # equivalent form: # date_str = (integer("year") + '/' # + integer("month") + '/' # + integer("day")) # parse_string returns a ParseResults object result = date_str.parse_string("1999/12/31") def test(s, fn=repr): print(f"{s} -> {fn(eval(s))}") test("list(result)") test("result[0]") test("result['month']") test("result.day") test("'month' in result") test("'minutes' in result") test("result.dump()", str) prints: .. testoutput:: list(result) -> ['1999', '/', '12', '/', '31'] result[0] -> '1999' result['month'] -> '12' result.day -> '31' 'month' in result -> True 'minutes' in result -> False result.dump() -> ['1999', '/', '12', '/', '31'] - day: '31' - month: '12' - year: '1999' """ _null_values: tuple[Any, ...] = (None, [], ()) _name: str _parent: ParseResults _all_names: set[str] _modal: bool _toklist: list[Any] _tokdict: dict[str, Any] __slots__ = ( "_name", "_parent", "_all_names", "_modal", "_toklist", "_tokdict", ) class List(list): """ Simple wrapper class to distinguish parsed list results that should be preserved as actual Python lists, instead of being converted to :class:`ParseResults`: .. testcode:: import pyparsing as pp ppc = pp.common LBRACK, RBRACK, LPAR, RPAR = pp.Suppress.using_each("[]()") element = pp.Forward() item = ppc.integer item_list = pp.DelimitedList(element) element_list = LBRACK + item_list + RBRACK | LPAR + item_list + RPAR element <<= item | element_list # add parse action to convert from ParseResults # to actual Python collection types @element_list.add_parse_action def as_python_list(t): return pp.ParseResults.List(t.as_list()) element.run_tests(''' 100 [2,3,4] [[2, 1],3,4] [(2, 1),3,4] (2,3,4) ([2, 3], 4) ''', post_parse=lambda s, r: (r[0], type(r[0])) ) prints: .. testoutput:: :options: +NORMALIZE_WHITESPACE 100 (100, ) [2,3,4] ([2, 3, 4], ) [[2, 1],3,4] ([[2, 1], 3, 4], ) [(2, 1),3,4] ([[2, 1], 3, 4], ) (2,3,4) ([2, 3, 4], ) ([2, 3], 4) ([[2, 3], 4], ) (Used internally by :class:`Group` when `aslist=True`.) """ def __new__(cls, contained=None): if contained is None: contained = [] if not isinstance(contained, list): raise TypeError( f"{cls.__name__} may only be constructed with a list, not {type(contained).__name__}" ) return list.__new__(cls) def __new__(cls, toklist=None, name=None, **kwargs): if isinstance(toklist, ParseResults): return toklist self = object.__new__(cls) self._name = None self._parent = None self._all_names = set() if toklist is None: self._toklist = [] elif isinstance(toklist, (list, _generator_type)): self._toklist = ( [toklist[:]] if isinstance(toklist, ParseResults.List) else list(toklist) ) else: self._toklist = [toklist] self._tokdict = dict() return self # Performance tuning: we construct a *lot* of these, so keep this # constructor as small and fast as possible def __init__( self, toklist=None, name=None, aslist=True, modal=True, isinstance=isinstance, **kwargs, ) -> None: asList = deprecate_argument(kwargs, "asList", True, new_name="aslist") asList = asList and aslist self._tokdict: dict[str, _ParseResultsWithOffset] self._modal = modal if name is None or name == "": return if isinstance(name, int): name = str(name) if not modal: self._all_names = {name} self._name = name if toklist in self._null_values: return if isinstance(toklist, (str_type, type)): toklist = [toklist] if asList: if isinstance(toklist, ParseResults): self[name] = _ParseResultsWithOffset(ParseResults(toklist._toklist), 0) else: self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]), 0) self[name]._name = name return try: self[name] = toklist[0] except (KeyError, TypeError, IndexError): if toklist is not self: self[name] = toklist else: self._name = name def __getitem__(self, i): if isinstance(i, (int, slice)): return self._toklist[i] if i not in self._all_names: return self._tokdict[i][-1][0] return ParseResults([v[0] for v in self._tokdict[i]]) def __setitem__(self, k, v, isinstance=isinstance): if isinstance(v, _ParseResultsWithOffset): self._tokdict[k] = self._tokdict.get(k, list()) + [v] sub = v[0] elif isinstance(k, (int, slice)): self._toklist[k] = v sub = v else: self._tokdict[k] = self._tokdict.get(k, []) + [ _ParseResultsWithOffset(v, 0) ] sub = v if isinstance(sub, ParseResults): sub._parent = self def __delitem__(self, i): if not isinstance(i, (int, slice)): del self._tokdict[i] return # slight optimization if del results[:] if i == NULL_SLICE: self._toklist.clear() return mylen = len(self._toklist) del self._toklist[i] # convert int to slice if isinstance(i, int): if i < 0: i += mylen i = slice(i, i + 1) # get removed indices removed = list(range(*i.indices(mylen))) removed.reverse() # fixup indices in token dictionary for occurrences in self._tokdict.values(): for j in removed: for k, (value, position) in enumerate(occurrences): occurrences[k] = _ParseResultsWithOffset( value, position - (position > j) ) def __contains__(self, k) -> bool: return k in self._tokdict def __len__(self) -> int: return len(self._toklist) def __bool__(self) -> bool: return not not (self._toklist or self._tokdict) def __iter__(self) -> Iterator: return iter(self._toklist) def __reversed__(self) -> Iterator: return iter(self._toklist[::-1]) def keys(self): return iter(self._tokdict) def values(self): return (self[k] for k in self.keys()) def items(self): return ((k, self[k]) for k in self.keys()) def haskeys(self) -> bool: """ Since ``keys()`` returns an iterator, this method is helpful in bypassing code that looks for the existence of any defined results names.""" return not not self._tokdict def pop(self, *args, **kwargs): """ Removes and returns item at specified index (default= ``last``). Supports both ``list`` and ``dict`` semantics for ``pop()``. If passed no argument or an integer argument, it will use ``list`` semantics and pop tokens from the list of parsed tokens. If passed a non-integer argument (most likely a string), it will use ``dict`` semantics and pop the corresponding value from any defined results names. A second default return value argument is supported, just as in ``dict.pop()``. Example: .. doctest:: >>> numlist = Word(nums)[...] >>> print(numlist.parse_string("0 123 321")) ['0', '123', '321'] >>> def remove_first(tokens): ... tokens.pop(0) ... >>> numlist.add_parse_action(remove_first) [W:(0-9)]... >>> print(numlist.parse_string("0 123 321")) ['123', '321'] >>> label = Word(alphas) >>> patt = label("LABEL") + Word(nums)[1, ...] >>> print(patt.parse_string("AAB 123 321").dump()) ['AAB', '123', '321'] - LABEL: 'AAB' >>> # Use pop() in a parse action to remove named result >>> # (note that corresponding value is not >>> # removed from list form of results) >>> def remove_LABEL(tokens): ... tokens.pop("LABEL") ... return tokens ... >>> patt.add_parse_action(remove_LABEL) {W:(A-Za-z) {W:(0-9)}...} >>> print(patt.parse_string("AAB 123 321").dump()) ['AAB', '123', '321'] """ if not args: args = [-1] for k, v in kwargs.items(): if k == "default": args = (args[0], v) else: raise TypeError(f"pop() got an unexpected keyword argument {k!r}") if isinstance(args[0], int) or len(args) == 1 or args[0] in self: index = args[0] ret = self[index] del self[index] return ret else: defaultvalue = args[1] return defaultvalue def get(self, key, default_value=None): """ Returns named result matching the given key, or if there is no such name, then returns the given ``default_value`` or ``None`` if no ``default_value`` is specified. Similar to ``dict.get()``. Example: .. doctest:: >>> integer = Word(nums) >>> date_str = integer("year") + '/' + integer("month") + '/' + integer("day") >>> result = date_str.parse_string("1999/12/31") >>> result.get("year") '1999' >>> result.get("hour", "not specified") 'not specified' >>> result.get("hour") """ if key in self: return self[key] else: return default_value def insert(self, index, ins_string): """ Inserts new element at location index in the list of parsed tokens. Similar to ``list.insert()``. Example: .. doctest:: >>> numlist = Word(nums)[...] >>> print(numlist.parse_string("0 123 321")) ['0', '123', '321'] >>> # use a parse action to insert the parse location >>> # in the front of the parsed results >>> def insert_locn(locn, tokens): ... tokens.insert(0, locn) ... >>> numlist.add_parse_action(insert_locn) [W:(0-9)]... >>> print(numlist.parse_string("0 123 321")) [0, '0', '123', '321'] """ self._toklist.insert(index, ins_string) # fixup indices in token dictionary for occurrences in self._tokdict.values(): for k, (value, position) in enumerate(occurrences): occurrences[k] = _ParseResultsWithOffset( value, position + (position > index) ) def append(self, item): """ Add single element to end of ``ParseResults`` list of elements. Example: .. doctest:: >>> numlist = Word(nums)[...] >>> print(numlist.parse_string("0 123 321")) ['0', '123', '321'] >>> # use a parse action to compute the sum of the parsed integers, >>> # and add it to the end >>> def append_sum(tokens): ... tokens.append(sum(map(int, tokens))) ... >>> numlist.add_parse_action(append_sum) [W:(0-9)]... >>> print(numlist.parse_string("0 123 321")) ['0', '123', '321', 444] """ self._toklist.append(item) def extend(self, itemseq): """ Add sequence of elements to end of :class:`ParseResults` list of elements. Example: .. testcode:: patt = Word(alphas)[1, ...] # use a parse action to append the reverse of the matched strings, # to make a palindrome def make_palindrome(tokens): tokens.extend(reversed([t[::-1] for t in tokens])) return ''.join(tokens) patt.add_parse_action(make_palindrome) print(patt.parse_string("lskdj sdlkjf lksd")) prints: .. testoutput:: ['lskdjsdlkjflksddsklfjkldsjdksl'] """ if isinstance(itemseq, ParseResults): self.__iadd__(itemseq) else: self._toklist.extend(itemseq) def clear(self): """ Clear all elements and results names. """ del self._toklist[:] self._tokdict.clear() def __getattr__(self, name): try: return self[name] except KeyError: if name.startswith("__"): raise AttributeError(name) return "" def __add__(self, other: ParseResults) -> ParseResults: ret = self.copy() ret += other return ret def __iadd__(self, other: ParseResults) -> ParseResults: if not other: return self if other._tokdict: offset = len(self._toklist) addoffset = lambda a: offset if a < 0 else a + offset otheritems = other._tokdict.items() otherdictitems = [ (k, _ParseResultsWithOffset(v[0], addoffset(v[1]))) for k, vlist in otheritems for v in vlist ] for k, v in otherdictitems: self[k] = v if isinstance(v[0], ParseResults): v[0]._parent = self self._toklist += other._toklist self._all_names |= other._all_names return self def __radd__(self, other) -> ParseResults: if isinstance(other, int) and other == 0: # useful for merging many ParseResults using sum() builtin return self.copy() else: # this may raise a TypeError - so be it return other + self def __repr__(self) -> str: return f"{type(self).__name__}({self._toklist!r}, {self.as_dict()})" def __str__(self) -> str: return ( "[" + ", ".join( [ str(i) if isinstance(i, ParseResults) else repr(i) for i in self._toklist ] ) + "]" ) def _asStringList(self, sep=""): out = [] for item in self._toklist: if out and sep: out.append(sep) if isinstance(item, ParseResults): out += item._asStringList() else: out.append(str(item)) return out def as_list(self, *, flatten: bool = False) -> list: """ Returns the parse results as a nested list of matching tokens, all converted to strings. If ``flatten`` is True, all the nesting levels in the returned list are collapsed. Example: .. doctest:: >>> patt = Word(alphas)[1, ...] >>> result = patt.parse_string("sldkj lsdkj sldkj") >>> # even though the result prints in string-like form, >>> # it is actually a pyparsing ParseResults >>> type(result) >>> print(result) ['sldkj', 'lsdkj', 'sldkj'] .. doctest:: >>> # Use as_list() to create an actual list >>> result_list = result.as_list() >>> type(result_list) >>> print(result_list) ['sldkj', 'lsdkj', 'sldkj'] .. versionchanged:: 3.2.0 New ``flatten`` argument. """ if flatten: return [*_flatten(self)] else: return [ res.as_list() if isinstance(res, ParseResults) else res for res in self._toklist ] def as_dict(self) -> dict: """ Returns the named parse results as a nested dictionary. Example: .. doctest:: >>> integer = pp.Word(pp.nums) >>> date_str = integer("year") + '/' + integer("month") + '/' + integer("day") >>> result = date_str.parse_string('1999/12/31') >>> type(result) >>> result ParseResults(['1999', '/', '12', '/', '31'], {'year': '1999', 'month': '12', 'day': '31'}) >>> result_dict = result.as_dict() >>> type(result_dict) >>> result_dict {'year': '1999', 'month': '12', 'day': '31'} >>> # even though a ParseResults supports dict-like access, >>> # sometime you just need to have a dict >>> import json >>> print(json.dumps(result)) Traceback (most recent call last): TypeError: Object of type ParseResults is not JSON serializable >>> print(json.dumps(result.as_dict())) {"year": "1999", "month": "12", "day": "31"} """ def to_item(obj): if isinstance(obj, ParseResults): return obj.as_dict() if obj.haskeys() else [to_item(v) for v in obj] else: return obj return dict((k, to_item(v)) for k, v in self.items()) def copy(self) -> ParseResults: """ Returns a new shallow copy of a :class:`ParseResults` object. :class:`ParseResults` items contained within the source are shared with the copy. Use :meth:`ParseResults.deepcopy` to create a copy with its own separate content values. """ ret = ParseResults(self._toklist) ret._tokdict = self._tokdict.copy() ret._parent = self._parent ret._all_names |= self._all_names ret._name = self._name return ret def deepcopy(self) -> ParseResults: """ Returns a new deep copy of a :class:`ParseResults` object. .. versionadded:: 3.1.0 """ ret = self.copy() # replace values with copies if they are of known mutable types for i, obj in enumerate(self._toklist): if isinstance(obj, ParseResults): ret._toklist[i] = obj.deepcopy() elif isinstance(obj, (str, bytes)): pass elif isinstance(obj, MutableMapping): ret._toklist[i] = dest = type(obj)() for k, v in obj.items(): dest[k] = v.deepcopy() if isinstance(v, ParseResults) else v elif isinstance(obj, Iterable): ret._toklist[i] = type(obj)( v.deepcopy() if isinstance(v, ParseResults) else v for v in obj # type: ignore[call-arg] ) return ret def get_name(self) -> str | None: r""" Returns the results name for this token expression. Useful when several different expressions might match at a particular location. Example: .. testcode:: integer = Word(nums) ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") house_number_expr = Suppress('#') + Word(nums, alphanums) user_data = (Group(house_number_expr)("house_number") | Group(ssn_expr)("ssn") | Group(integer)("age")) user_info = user_data[1, ...] result = user_info.parse_string("22 111-22-3333 #221B") for item in result: print(item.get_name(), ':', item[0]) prints: .. testoutput:: age : 22 ssn : 111-22-3333 house_number : 221B """ if self._name: return self._name elif self._parent: par: ParseResults = self._parent parent_tokdict_items = par._tokdict.items() return next( ( k for k, vlist in parent_tokdict_items for v, loc in vlist if v is self ), None, ) elif ( len(self) == 1 and len(self._tokdict) == 1 and next(iter(self._tokdict.values()))[0][1] in (0, -1) ): return next(iter(self._tokdict.keys())) else: return None def dump(self, indent="", full=True, include_list=True, _depth=0) -> str: """ Diagnostic method for listing out the contents of a :class:`ParseResults`. Accepts an optional ``indent`` argument so that this string can be embedded in a nested display of other data. Example: .. testcode:: integer = Word(nums) date_str = integer("year") + '/' + integer("month") + '/' + integer("day") result = date_str.parse_string('1999/12/31') print(result.dump()) prints: .. testoutput:: ['1999', '/', '12', '/', '31'] - day: '31' - month: '12' - year: '1999' """ out = [] NL = "\n" out.append(indent + str(self.as_list()) if include_list else "") if not full: return "".join(out) if self.haskeys(): items = sorted((str(k), v) for k, v in self.items()) for k, v in items: if out: out.append(NL) out.append(f"{indent}{(' ' * _depth)}- {k}: ") if not isinstance(v, ParseResults): out.append(repr(v)) continue if not v: out.append(str(v)) continue out.append( v.dump( indent=indent, full=full, include_list=include_list, _depth=_depth + 1, ) ) if not any(isinstance(vv, ParseResults) for vv in self): return "".join(out) v = self incr = " " nl = "\n" for i, vv in enumerate(v): if isinstance(vv, ParseResults): vv_dump = vv.dump( indent=indent, full=full, include_list=include_list, _depth=_depth + 1, ) out.append( f"{nl}{indent}{incr * _depth}[{i}]:{nl}{indent}{incr * (_depth + 1)}{vv_dump}" ) else: out.append( f"{nl}{indent}{incr * _depth}[{i}]:{nl}{indent}{incr * (_depth + 1)}{vv}" ) return "".join(out) def pprint(self, *args, **kwargs): """ Pretty-printer for parsed results as a list, using the `pprint `_ module. Accepts additional positional or keyword args as defined for `pprint.pprint `_ . Example: .. testcode:: ident = Word(alphas, alphanums) num = Word(nums) func = Forward() term = ident | num | Group('(' + func + ')') func <<= ident + Group(Optional(DelimitedList(term))) result = func.parse_string("fna a,b,(fnb c,d,200),100") result.pprint(width=40) prints: .. testoutput:: ['fna', ['a', 'b', ['(', 'fnb', ['c', 'd', '200'], ')'], '100']] """ pprint.pprint(self.as_list(), *args, **kwargs) # add support for pickle protocol def __getstate__(self): return ( self._toklist, ( self._tokdict.copy(), None, self._all_names, self._name, ), ) def __setstate__(self, state): self._toklist, (self._tokdict, par, inAccumNames, self._name) = state self._all_names = set(inAccumNames) self._parent = None def __getnewargs__(self): return self._toklist, self._name def __dir__(self): return dir(type(self)) + list(self.keys()) @classmethod def from_dict(cls, other, name=None) -> ParseResults: """ Helper classmethod to construct a :class:`ParseResults` from a ``dict``, preserving the name-value relations as results names. If an optional ``name`` argument is given, a nested :class:`ParseResults` will be returned. """ ret = cls([]) for k, v in other.items(): if isinstance(v, Mapping): ret += cls.from_dict(v, name=k) else: ret += cls([v], name=k, aslist=_is_iterable(v)) if name is not None: ret = cls([ret], name=name) return ret asList = as_list """ .. deprecated:: 3.0.0 use :meth:`as_list` """ asDict = as_dict """ .. deprecated:: 3.0.0 use :meth:`as_dict` """ getName = get_name """ .. deprecated:: 3.0.0 use :meth:`get_name` """ MutableMapping.register(ParseResults) MutableSequence.register(ParseResults) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7232046 pyparsing-3.3.2/pyparsing/testing.py0000644000000000000000000003613415134002420014522 0ustar00# testing.py from contextlib import contextmanager import re import typing import unittest from .core import ( ParserElement, ParseException, Keyword, __diag__, __compat__, ) from . import core_builtin_exprs class pyparsing_test: """ namespace class for classes useful in writing unit tests """ class reset_pyparsing_context: """ Context manager to be used when writing unit tests that modify pyparsing config values: - packrat parsing - bounded recursion parsing - default whitespace characters - default keyword characters - literal string auto-conversion class - ``__diag__`` settings Example: .. testcode:: ppt = pyparsing.pyparsing_test class MyTestClass(ppt.TestParseResultsAsserts): def test_literal(self): with ppt.reset_pyparsing_context(): # test that literals used to construct # a grammar are automatically suppressed ParserElement.inline_literals_using(Suppress) term = Word(alphas) | Word(nums) group = Group('(' + term[...] + ')') # assert that the '()' characters # are not included in the parsed tokens self.assertParseAndCheckList( group, "(abc 123 def)", ['abc', '123', 'def'] ) # after exiting context manager, literals # are converted to Literal expressions again """ def __init__(self): self._save_context = {} def save(self): self._save_context["default_whitespace"] = ParserElement.DEFAULT_WHITE_CHARS self._save_context["default_keyword_chars"] = Keyword.DEFAULT_KEYWORD_CHARS self._save_context["literal_string_class"] = ( ParserElement._literalStringClass ) self._save_context["verbose_stacktrace"] = ParserElement.verbose_stacktrace self._save_context["packrat_enabled"] = ParserElement._packratEnabled if ParserElement._packratEnabled: self._save_context["packrat_cache_size"] = ( ParserElement.packrat_cache.size ) else: self._save_context["packrat_cache_size"] = None self._save_context["packrat_parse"] = ParserElement._parse self._save_context["recursion_enabled"] = ( ParserElement._left_recursion_enabled ) self._save_context["__diag__"] = { name: getattr(__diag__, name) for name in __diag__._all_names } self._save_context["__compat__"] = { "collect_all_And_tokens": __compat__.collect_all_And_tokens } return self def restore(self): # reset pyparsing global state if ( ParserElement.DEFAULT_WHITE_CHARS != self._save_context["default_whitespace"] ): ParserElement.set_default_whitespace_chars( self._save_context["default_whitespace"] ) ParserElement.verbose_stacktrace = self._save_context["verbose_stacktrace"] Keyword.DEFAULT_KEYWORD_CHARS = self._save_context["default_keyword_chars"] ParserElement.inline_literals_using( self._save_context["literal_string_class"] ) for name, value in self._save_context["__diag__"].items(): (__diag__.enable if value else __diag__.disable)(name) ParserElement._packratEnabled = False if self._save_context["packrat_enabled"]: ParserElement.enable_packrat(self._save_context["packrat_cache_size"]) else: ParserElement._parse = self._save_context["packrat_parse"] ParserElement._left_recursion_enabled = self._save_context[ "recursion_enabled" ] # clear debug flags on all builtins for expr in core_builtin_exprs: expr.set_debug(False) __compat__.collect_all_And_tokens = self._save_context["__compat__"] return self def copy(self): ret = type(self)() ret._save_context.update(self._save_context) return ret def __enter__(self): return self.save() def __exit__(self, *args): self.restore() class TestParseResultsAsserts(unittest.TestCase): """ A mixin class to add parse results assertion methods to normal unittest.TestCase classes. """ def assertParseResultsEquals( self, result, expected_list=None, expected_dict=None, msg=None ): """ Unit test assertion to compare a :class:`ParseResults` object with an optional ``expected_list``, and compare any defined results names with an optional ``expected_dict``. """ if expected_list is not None: self.assertEqual(expected_list, result.as_list(), msg=msg) if expected_dict is not None: self.assertEqual(expected_dict, result.as_dict(), msg=msg) def assertParseAndCheckList( self, expr, test_string, expected_list, msg=None, verbose=True ): """ Convenience wrapper assert to test a parser element and input string, and assert that the resulting :meth:`ParseResults.as_list` is equal to the ``expected_list``. """ result = expr.parse_string(test_string, parse_all=True) if verbose: print(result.dump()) else: print(result.as_list()) self.assertParseResultsEquals(result, expected_list=expected_list, msg=msg) def assertParseAndCheckDict( self, expr, test_string, expected_dict, msg=None, verbose=True ): """ Convenience wrapper assert to test a parser element and input string, and assert that the resulting :meth:`ParseResults.as_dict` is equal to the ``expected_dict``. """ result = expr.parse_string(test_string, parse_all=True) if verbose: print(result.dump()) else: print(result.as_list()) self.assertParseResultsEquals(result, expected_dict=expected_dict, msg=msg) def assertRunTestResults( self, run_tests_report, expected_parse_results=None, msg=None ): """ Unit test assertion to evaluate output of :meth:`~ParserElement.run_tests`. If a list of list-dict tuples is given as the ``expected_parse_results`` argument, then these are zipped with the report tuples returned by ``run_tests()`` and evaluated using :meth:`assertParseResultsEquals`. Finally, asserts that the overall `:meth:~ParserElement.run_tests` success value is ``True``. :param run_tests_report: the return value from :meth:`ParserElement.run_tests` :type run_tests_report: tuple[bool, list[tuple[str, ParseResults | Exception]]] :param expected_parse_results: (optional) :type expected_parse_results: list[tuple[str | list | dict | Exception, ...]] """ run_test_success, run_test_results = run_tests_report if expected_parse_results is None: self.assertTrue( run_test_success, msg=msg if msg is not None else "failed runTests" ) return merged = [ (*rpt, expected) for rpt, expected in zip(run_test_results, expected_parse_results) ] for test_string, result, expected in merged: # expected should be a tuple containing a list and/or a dict or an exception, # and optional failure message string # an empty tuple will skip any result validation fail_msg = next((exp for exp in expected if isinstance(exp, str)), None) expected_exception = next( ( exp for exp in expected if isinstance(exp, type) and issubclass(exp, Exception) ), None, ) if expected_exception is not None: with self.assertRaises( expected_exception=expected_exception, msg=fail_msg or msg ): if isinstance(result, Exception): raise result else: expected_list = next( (exp for exp in expected if isinstance(exp, list)), None ) expected_dict = next( (exp for exp in expected if isinstance(exp, dict)), None ) if (expected_list, expected_dict) != (None, None): self.assertParseResultsEquals( result, expected_list=expected_list, expected_dict=expected_dict, msg=fail_msg or msg, ) else: # warning here maybe? print(f"no validation for {test_string!r}") # do this last, in case some specific test results can be reported instead self.assertTrue( run_test_success, msg=msg if msg is not None else "failed runTests" ) @contextmanager def assertRaisesParseException( self, exc_type=ParseException, expected_msg=None, msg=None ): if expected_msg is not None: if isinstance(expected_msg, str): expected_msg = re.escape(expected_msg) with self.assertRaisesRegex(exc_type, expected_msg, msg=msg) as ctx: yield ctx else: with self.assertRaises(exc_type, msg=msg) as ctx: yield ctx @staticmethod def with_line_numbers( s: str, start_line: typing.Optional[int] = None, end_line: typing.Optional[int] = None, expand_tabs: bool = True, eol_mark: str = "|", mark_spaces: typing.Optional[str] = None, mark_control: typing.Optional[str] = None, *, indent: typing.Union[str, int] = "", base_1: bool = True, ) -> str: """ Helpful method for debugging a parser - prints a string with line and column numbers. (Line and column numbers are 1-based by default - if debugging a parse action, pass base_1=False, to correspond to the loc value passed to the parse action.) :param s: string to be printed with line and column numbers :param start_line: starting line number in s to print (default=1) :param end_line: ending line number in s to print (default=len(s)) :param expand_tabs: expand tabs to spaces, to match the pyparsing default :param eol_mark: string to mark the end of lines, helps visualize trailing spaces :param mark_spaces: special character to display in place of spaces :param mark_control: convert non-printing control characters to a placeholding character; valid values: - ``"unicode"`` - replaces control chars with Unicode symbols, such as "␍" and "␊" - any single character string - replace control characters with given string - ``None`` (default) - string is displayed as-is :param indent: string to indent with line and column numbers; if an int is passed, converted to ``" " * indent`` :param base_1: whether to label string using base 1; if False, string will be labeled based at 0 :returns: input string with leading line numbers and column number headers .. versionchanged:: 3.2.0 New ``indent`` and ``base_1`` arguments. """ if expand_tabs: s = s.expandtabs() if isinstance(indent, int): indent = " " * indent indent = indent.expandtabs() if mark_control is not None: mark_control = typing.cast(str, mark_control) if mark_control == "unicode": transtable_map = { c: u for c, u in zip(range(0, 33), range(0x2400, 0x2433)) } transtable_map[127] = 0x2421 tbl = str.maketrans(transtable_map) eol_mark = "" else: ord_mark_control = ord(mark_control) tbl = str.maketrans( {c: ord_mark_control for c in list(range(0, 32)) + [127]} ) s = s.translate(tbl) if mark_spaces is not None and mark_spaces != " ": if mark_spaces == "unicode": tbl = str.maketrans({9: 0x2409, 32: 0x2423}) s = s.translate(tbl) else: s = s.replace(" ", mark_spaces) if start_line is None: start_line = 0 if end_line is None: end_line = len(s.splitlines()) end_line = min(end_line, len(s.splitlines())) start_line = min(max(0, start_line), end_line) if mark_control != "unicode": s_lines = s.splitlines()[max(start_line - base_1, 0) : end_line] else: s_lines = [ line + "␊" for line in s.split("␊")[max(start_line - base_1, 0) : end_line] ] if not s_lines: return "" lineno_width = len(str(end_line)) max_line_len = max(len(line) for line in s_lines) lead = f"{indent}{' ' * (lineno_width + 1)}" if max_line_len >= 99: header0 = ( lead + ("" if base_1 else " ") + "".join( f"{' ' * 99}{(i + 1) % 100}" for i in range(max(max_line_len // 100, 1)) ) + "\n" ) else: header0 = "" header1 = ( ("" if base_1 else " ") + lead + "".join(f" {(i + 1) % 10}" for i in range(-(-max_line_len // 10))) + "\n" ) digits = "1234567890" header2 = ( lead + ("" if base_1 else "0") + digits * (-(-max_line_len // 10)) + "\n" ) return ( header0 + header1 + header2 + "\n".join( f"{indent}{i:{lineno_width}d}:{line}{eol_mark}" for i, line in enumerate(s_lines, start=start_line + base_1) ) + "\n" ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7232046 pyparsing-3.3.2/pyparsing/tools/__init__.py0000644000000000000000000000000015134002420015723 0ustar00././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.724493 pyparsing-3.3.2/pyparsing/tools/cvt_pyparsing_pep8_names.py0000644000000000000000000001436515134002420021216 0ustar00import warnings from functools import lru_cache import pyparsing as pp @lru_cache(maxsize=None) def camel_to_snake(s: str) -> str: """ Convert CamelCase to snake_case. """ return "".join(f"_{c.lower()}" if c.isupper() else c for c in s).lstrip("_") pre_pep8_method_names = """ addCondition addParseAction anyCloseTag anyOpenTag asDict asList cStyleComment canParseNext conditionAsParseAction convertToDate convertToDatetime convertToFloat convertToInteger countedArray cppStyleComment dblQuotedString dblSlashComment defaultName dictOf disableMemoization downcaseTokens enableLeftRecursion enablePackrat getName htmlComment ignoreWhitespace infixNotation inlineLiteralsUsing javaStyleComment leaveWhitespace lineEnd lineStart matchOnlyAtCol matchPreviousExpr matchPreviousLiteral nestedExpr nullDebugAction oneOf originalTextFor parseFile parseString parseWithTabs pythonStyleComment quotedString removeQuotes replaceWith resetCache restOfLine runTests scanString searchString setBreak setDebug setDebugActions setDefaultWhitespaceChars setFailAction setName setParseAction setResultsName setWhitespaceChars sglQuotedString stringEnd stringStart tokenMap traceParseAction transformString tryParse unicodeString upcaseTokens withAttribute withClass """.split() special_changes = { "opAssoc": "OpAssoc", "delimitedList": "DelimitedList", "delimited_list": "DelimitedList", "replaceHTMLEntity": "replace_html_entity", "makeHTMLTags": "make_html_tags", "makeXMLTags": "make_xml_tags", "commonHTMLEntity": "common_html_entity", "stripHTMLTags": "strip_html_tags", "indentedBlock": "IndentedBlock", "locatedExpr": "Located", } pre_pep8_arg_names = """parseAll maxMatches listAllMatches callDuringTry includeSeparators fullDump printResults failureTests postParse matchString identChars maxMismatches initChars bodyChars asKeyword excludeChars asGroupList asMatch quoteChar escChar escQuote unquoteResults endQuoteChar convertWhitespaceEscapes notChars wordChars stopOn failOn joinString markerString intExpr useRegex asString ignoreExpr""".split() special_changes_arg_names = { "asList": "aslist", } pre_pep8_method_name = pp.one_of(pre_pep8_method_names, as_keyword=True) pre_pep8_method_name.set_parse_action(lambda t: camel_to_snake(t[0])) special_pre_pep8_name = pp.one_of(special_changes, as_keyword=True) def update_special_changes(s, l, t): if t[0] == "indentedBlock": warnings.warn( "Conversion of 'indentedBlock' to new 'IndentedBlock'" " requires added code changes to remove 'indentStack' argument\n" f" {pp.lineno(l, s)}: {pp.line(l, s)}", stacklevel=2, ) elif t[0] == "locatedExpr": warnings.warn( "Conversion of 'locatedExpr' to new 'Located'" " may require added code changes - Located does not automatically" " group parsed elements\n" f" {pp.lineno(l, s)}: {pp.line(l, s)}", stacklevel=2, ) return special_changes[t[0]] special_pre_pep8_name.set_parse_action(update_special_changes) # only replace arg names if part of an arg list pre_pep8_arg_name = pp.Regex( rf"{pp.util.make_compressed_re(pre_pep8_arg_names)}" ) + pp.FollowedBy("=") pre_pep8_arg_name.set_parse_action(lambda t: camel_to_snake(t[0])) special_pre_pep8_arg_name = pp.one_of(special_changes_arg_names, as_keyword=True) + pp.FollowedBy("=") special_pre_pep8_arg_name.set_parse_action(lambda t: special_changes_arg_names[t[0]]) pep8_converter = special_pre_pep8_arg_name | pre_pep8_method_name | special_pre_pep8_name | pre_pep8_arg_name if __name__ == "__main__": import argparse from pathlib import Path import sys argparser = argparse.ArgumentParser( description = ( "Utility to convert Python pyparsing scripts using legacy" " camelCase names to use PEP8 snake_case names." "\nBy default, this script will only show whether this script would make any changes." ) ) argparser.add_argument("--verbose", "-v", action="store_true", help="Show unified diff for each source file") argparser.add_argument("-vv", action="store_true", dest="verbose2", help="Show unified diff for each source file, plus names of scanned files with no changes") argparser.add_argument("--update", "-u", action="store_true", help="Update source files in-place") argparser.add_argument("--encoding", type=str, default="utf-8", help="Encoding of source files (default: utf-8)") argparser.add_argument("--exit-zero-even-if-changed", "-exit0", action="store_true", help="Exit with status code 0 even if changes were made") argparser.add_argument("source_filename", nargs="+", help="Source filenames or filename patterns of Python files to be converted") args = argparser.parse_args() def show_diffs(original, modified): import difflib diff = difflib.unified_diff( original.splitlines(), modified.splitlines(), lineterm="" ) sys.stdout.writelines(f"{diff_line}\n" for diff_line in diff) exit_status = 0 for filename_pattern in args.source_filename: for filename in Path().glob(filename_pattern): if not Path(filename).is_file(): continue try: original_contents = Path(filename).read_text(encoding=args.encoding) modified_contents = pep8_converter.transform_string( original_contents ) if modified_contents != original_contents: if args.update: Path(filename).write_text(modified_contents, encoding=args.encoding) print(f"Converted {filename}") else: print(f"Found required changes in {filename}") if args.verbose: show_diffs(original_contents, modified_contents) print() exit_status = 1 else: if args.verbose2: print(f"No required changes in {filename}") except Exception as e: print(f"Failed to convert {filename}: {type(e).__name__}: {e}") sys.exit(exit_status if not args.exit_zero_even_if_changed else 0) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.724493 pyparsing-3.3.2/pyparsing/unicode.py0000644000000000000000000002456415134002420014477 0ustar00# unicode.py import sys from itertools import filterfalse from typing import Union class _lazyclassproperty: def __init__(self, fn): self.fn = fn self.__doc__ = fn.__doc__ self.__name__ = fn.__name__ def __get__(self, obj, cls): if cls is None: cls = type(obj) if not hasattr(cls, "_intern") or any( cls._intern is getattr(superclass, "_intern", []) for superclass in cls.__mro__[1:] ): cls._intern = {} attrname = self.fn.__name__ if attrname not in cls._intern: cls._intern[attrname] = self.fn(cls) return cls._intern[attrname] UnicodeRangeList = list[Union[tuple[int, int], tuple[int]]] class unicode_set: """ A set of Unicode characters, for language-specific strings for ``alphas``, ``nums``, ``alphanums``, and ``printables``. A unicode_set is defined by a list of ranges in the Unicode character set, in a class attribute ``_ranges``. Ranges can be specified using 2-tuples or a 1-tuple, such as:: _ranges = [ (0x0020, 0x007e), (0x00a0, 0x00ff), (0x0100,), ] Ranges are left- and right-inclusive. A 1-tuple of (x,) is treated as (x, x). A unicode set can also be defined using multiple inheritance of other unicode sets:: class CJK(Chinese, Japanese, Korean): pass """ _ranges: UnicodeRangeList = [] @_lazyclassproperty def _chars_for_ranges(cls) -> list[str]: ret: list[int] = [] for cc in cls.__mro__: # type: ignore[attr-defined] if cc is unicode_set: break for rr in getattr(cc, "_ranges", ()): ret.extend(range(rr[0], rr[-1] + 1)) return sorted(chr(c) for c in set(ret)) @_lazyclassproperty def printables(cls) -> str: """all non-whitespace characters in this range""" return "".join(filterfalse(str.isspace, cls._chars_for_ranges)) @_lazyclassproperty def alphas(cls) -> str: """all alphabetic characters in this range""" return "".join(filter(str.isalpha, cls._chars_for_ranges)) @_lazyclassproperty def nums(cls) -> str: """all numeric digit characters in this range""" return "".join(filter(str.isdigit, cls._chars_for_ranges)) @_lazyclassproperty def alphanums(cls) -> str: """all alphanumeric characters in this range""" return cls.alphas + cls.nums @_lazyclassproperty def identchars(cls) -> str: """all characters in this range that are valid identifier characters, plus underscore '_'""" return "".join( sorted( set(filter(str.isidentifier, cls._chars_for_ranges)) | set( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµº" "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ" "_" ) ) ) @_lazyclassproperty def identbodychars(cls) -> str: """ all characters in this range that are valid identifier body characters, plus the digits 0-9, and · (Unicode MIDDLE DOT) """ identifier_chars = set( c for c in cls._chars_for_ranges if f"_{c}".isidentifier() ) return "".join( sorted(identifier_chars | set(cls.identchars) | set("0123456789·")) ) @_lazyclassproperty def identifier(cls): """ a pyparsing Word expression for an identifier using this range's definitions for identchars and identbodychars """ from pyparsing import Word return Word(cls.identchars, cls.identbodychars) class pyparsing_unicode(unicode_set): """ A namespace class for defining common language unicode_sets. """ # fmt: off # define ranges in language character sets _ranges: UnicodeRangeList = [ (0x0020, sys.maxunicode), ] class BasicMultilingualPlane(unicode_set): """Unicode set for the Basic Multilingual Plane""" _ranges: UnicodeRangeList = [ (0x0020, 0xFFFF), ] class Latin1(unicode_set): """Unicode set for Latin-1 Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x0020, 0x007E), (0x00A0, 0x00FF), ] class LatinA(unicode_set): """Unicode set for Latin-A Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x0100, 0x017F), ] class LatinB(unicode_set): """Unicode set for Latin-B Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x0180, 0x024F), ] class Greek(unicode_set): """Unicode set for Greek Unicode Character Ranges""" _ranges: UnicodeRangeList = [ (0x0342, 0x0345), (0x0370, 0x0377), (0x037A, 0x037F), (0x0384, 0x038A), (0x038C,), (0x038E, 0x03A1), (0x03A3, 0x03E1), (0x03F0, 0x03FF), (0x1D26, 0x1D2A), (0x1D5E,), (0x1D60,), (0x1D66, 0x1D6A), (0x1F00, 0x1F15), (0x1F18, 0x1F1D), (0x1F20, 0x1F45), (0x1F48, 0x1F4D), (0x1F50, 0x1F57), (0x1F59,), (0x1F5B,), (0x1F5D,), (0x1F5F, 0x1F7D), (0x1F80, 0x1FB4), (0x1FB6, 0x1FC4), (0x1FC6, 0x1FD3), (0x1FD6, 0x1FDB), (0x1FDD, 0x1FEF), (0x1FF2, 0x1FF4), (0x1FF6, 0x1FFE), (0x2129,), (0x2719, 0x271A), (0xAB65,), (0x10140, 0x1018D), (0x101A0,), (0x1D200, 0x1D245), (0x1F7A1, 0x1F7A7), ] class Cyrillic(unicode_set): """Unicode set for Cyrillic Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x0400, 0x052F), (0x1C80, 0x1C88), (0x1D2B,), (0x1D78,), (0x2DE0, 0x2DFF), (0xA640, 0xA672), (0xA674, 0xA69F), (0xFE2E, 0xFE2F), ] class Chinese(unicode_set): """Unicode set for Chinese Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x2E80, 0x2E99), (0x2E9B, 0x2EF3), (0x31C0, 0x31E3), (0x3400, 0x4DB5), (0x4E00, 0x9FEF), (0xA700, 0xA707), (0xF900, 0xFA6D), (0xFA70, 0xFAD9), (0x16FE2, 0x16FE3), (0x1F210, 0x1F212), (0x1F214, 0x1F23B), (0x1F240, 0x1F248), (0x20000, 0x2A6D6), (0x2A700, 0x2B734), (0x2B740, 0x2B81D), (0x2B820, 0x2CEA1), (0x2CEB0, 0x2EBE0), (0x2F800, 0x2FA1D), ] class Japanese(unicode_set): """Unicode set for Japanese Unicode Character Range, combining Kanji, Hiragana, and Katakana ranges""" class Kanji(unicode_set): "Unicode set for Kanji Unicode Character Range" _ranges: UnicodeRangeList = [ (0x4E00, 0x9FBF), (0x3000, 0x303F), ] class Hiragana(unicode_set): """Unicode set for Hiragana Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x3041, 0x3096), (0x3099, 0x30A0), (0x30FC,), (0xFF70,), (0x1B001,), (0x1B150, 0x1B152), (0x1F200,), ] class Katakana(unicode_set): """Unicode set for Katakana Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x3099, 0x309C), (0x30A0, 0x30FF), (0x31F0, 0x31FF), (0x32D0, 0x32FE), (0xFF65, 0xFF9F), (0x1B000,), (0x1B164, 0x1B167), (0x1F201, 0x1F202), (0x1F213,), ] 漢字 = Kanji カタカナ = Katakana ひらがな = Hiragana _ranges = ( Kanji._ranges + Hiragana._ranges + Katakana._ranges ) class Hangul(unicode_set): """Unicode set for Hangul (Korean) Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x1100, 0x11FF), (0x302E, 0x302F), (0x3131, 0x318E), (0x3200, 0x321C), (0x3260, 0x327B), (0x327E,), (0xA960, 0xA97C), (0xAC00, 0xD7A3), (0xD7B0, 0xD7C6), (0xD7CB, 0xD7FB), (0xFFA0, 0xFFBE), (0xFFC2, 0xFFC7), (0xFFCA, 0xFFCF), (0xFFD2, 0xFFD7), (0xFFDA, 0xFFDC), ] Korean = Hangul class CJK(Chinese, Japanese, Hangul): """Unicode set for combined Chinese, Japanese, and Korean (CJK) Unicode Character Range""" class Thai(unicode_set): """Unicode set for Thai Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x0E01, 0x0E3A), (0x0E3F, 0x0E5B) ] class Arabic(unicode_set): """Unicode set for Arabic Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x0600, 0x061B), (0x061E, 0x06FF), (0x0700, 0x077F), ] class Hebrew(unicode_set): """Unicode set for Hebrew Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x0591, 0x05C7), (0x05D0, 0x05EA), (0x05EF, 0x05F4), (0xFB1D, 0xFB36), (0xFB38, 0xFB3C), (0xFB3E,), (0xFB40, 0xFB41), (0xFB43, 0xFB44), (0xFB46, 0xFB4F), ] class Devanagari(unicode_set): """Unicode set for Devanagari Unicode Character Range""" _ranges: UnicodeRangeList = [ (0x0900, 0x097F), (0xA8E0, 0xA8FF) ] BMP = BasicMultilingualPlane # add language identifiers using language Unicode العربية = Arabic 中文 = Chinese кириллица = Cyrillic Ελληνικά = Greek עִברִית = Hebrew 日本語 = Japanese 한국어 = Korean ไทย = Thai देवनागरी = Devanagari # fmt: on ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.724493 pyparsing-3.3.2/pyparsing/util.py0000644000000000000000000003717515134002420014030 0ustar00# util.py import contextlib import re from functools import lru_cache, wraps import inspect import itertools import types from typing import Callable, Union, Iterable, TypeVar, cast, Any import warnings from .warnings import PyparsingDeprecationWarning, PyparsingDiagnosticWarning _bslash = chr(92) C = TypeVar("C", bound=Callable) class __config_flags: """Internal class for defining compatibility and debugging flags""" _all_names: list[str] = [] _fixed_names: list[str] = [] _type_desc = "configuration" @classmethod def _set(cls, dname, value): if dname in cls._fixed_names: warnings.warn( f"{cls.__name__}.{dname} {cls._type_desc} is {str(getattr(cls, dname)).upper()}" f" and cannot be overridden", PyparsingDiagnosticWarning, stacklevel=3, ) return if dname in cls._all_names: setattr(cls, dname, value) else: raise ValueError(f"no such {cls._type_desc} {dname!r}") enable = classmethod(lambda cls, name: cls._set(name, True)) disable = classmethod(lambda cls, name: cls._set(name, False)) @lru_cache(maxsize=128) def col(loc: int, strg: str) -> int: """ Returns current column within a string, counting newlines as line separators. The first column is number 1. Note: the default parsing behavior is to expand tabs in the input string before starting the parsing process. See :meth:`ParserElement.parse_string` for more information on parsing strings containing ```` s, and suggested methods to maintain a consistent view of the parsed string, the parse location, and line and column positions within the parsed string. """ s = strg return 1 if 0 < loc < len(s) and s[loc - 1] == "\n" else loc - s.rfind("\n", 0, loc) @lru_cache(maxsize=128) def lineno(loc: int, strg: str) -> int: """Returns current line number within a string, counting newlines as line separators. The first line is number 1. Note - the default parsing behavior is to expand tabs in the input string before starting the parsing process. See :meth:`ParserElement.parse_string` for more information on parsing strings containing ```` s, and suggested methods to maintain a consistent view of the parsed string, the parse location, and line and column positions within the parsed string. """ return strg.count("\n", 0, loc) + 1 @lru_cache(maxsize=128) def line(loc: int, strg: str) -> str: """ Returns the line of text containing loc within a string, counting newlines as line separators. """ last_cr = strg.rfind("\n", 0, loc) next_cr = strg.find("\n", loc) return strg[last_cr + 1 : next_cr] if next_cr >= 0 else strg[last_cr + 1 :] class _UnboundedCache: def __init__(self): cache = {} cache_get = cache.get self.not_in_cache = not_in_cache = object() def get(_, key): return cache_get(key, not_in_cache) def set_(_, key, value): cache[key] = value def clear(_): cache.clear() self.size = None self.get = types.MethodType(get, self) self.set = types.MethodType(set_, self) self.clear = types.MethodType(clear, self) class _FifoCache: def __init__(self, size): cache = {} self.size = size self.not_in_cache = not_in_cache = object() cache_get = cache.get cache_pop = cache.pop def get(_, key): return cache_get(key, not_in_cache) def set_(_, key, value): cache[key] = value while len(cache) > size: # pop oldest element in cache by getting the first key cache_pop(next(iter(cache))) def clear(_): cache.clear() self.get = types.MethodType(get, self) self.set = types.MethodType(set_, self) self.clear = types.MethodType(clear, self) class LRUMemo: """ A memoizing mapping that retains `capacity` deleted items The memo tracks retained items by their access order; once `capacity` items are retained, the least recently used item is discarded. """ def __init__(self, capacity): self._capacity = capacity self._active = {} self._memory = {} def __getitem__(self, key): try: return self._active[key] except KeyError: self._memory[key] = self._memory.pop(key) return self._memory[key] def __setitem__(self, key, value): self._memory.pop(key, None) self._active[key] = value def __delitem__(self, key): try: value = self._active.pop(key) except KeyError: pass else: oldest_keys = list(self._memory)[: -(self._capacity + 1)] for key_to_delete in oldest_keys: self._memory.pop(key_to_delete) self._memory[key] = value def clear(self): self._active.clear() self._memory.clear() class UnboundedMemo(dict): """ A memoizing mapping that retains all deleted items """ def __delitem__(self, key): pass def _escape_regex_range_chars(s: str) -> str: # escape these chars: ^-[] for c in r"\^-[]": s = s.replace(c, _bslash + c) s = s.replace("\n", r"\n") s = s.replace("\t", r"\t") return str(s) class _GroupConsecutive: """ Used as a callable `key` for itertools.groupby to group characters that are consecutive: .. testcode:: from itertools import groupby from pyparsing.util import _GroupConsecutive grouped = groupby("abcdejkmpqrs", key=_GroupConsecutive()) for index, group in grouped: print(tuple([index, list(group)])) prints: .. testoutput:: (0, ['a', 'b', 'c', 'd', 'e']) (1, ['j', 'k']) (2, ['m']) (3, ['p', 'q', 'r', 's']) """ def __init__(self) -> None: self.prev = 0 self.counter = itertools.count() self.value = -1 def __call__(self, char: str) -> int: c_int = ord(char) self.prev, prev = c_int, self.prev if c_int - prev > 1: self.value = next(self.counter) return self.value def _is_iterable(obj, _str_type=(str, bytes), _iter_exception=Exception): # str's are iterable, but in pyparsing, we don't want to iterate over them if isinstance(obj, _str_type): return False try: iter(obj) except _iter_exception: # noqa return False else: return True def _escape_re_range_char(c: str) -> str: return fr"\{c}" if c in r"\^-][" else c def _collapse_string_to_ranges( s: Union[str, Iterable[str]], re_escape: bool = True ) -> str: r""" Take a string or list of single-character strings, and return a string of the consecutive characters in that string collapsed into groups, as might be used in a regular expression '[a-z]' character set:: 'a' -> 'a' -> '[a]' 'bc' -> 'bc' -> '[bc]' 'defgh' -> 'd-h' -> '[d-h]' 'fdgeh' -> 'd-h' -> '[d-h]' 'jklnpqrtu' -> 'j-lnp-rtu' -> '[j-lnp-rtu]' Duplicates get collapsed out:: 'aaa' -> 'a' -> '[a]' 'bcbccb' -> 'bc' -> '[bc]' 'defghhgf' -> 'd-h' -> '[d-h]' 'jklnpqrjjjtu' -> 'j-lnp-rtu' -> '[j-lnp-rtu]' Spaces are preserved:: 'ab c' -> ' a-c' -> '[ a-c]' Characters that are significant when defining regex ranges get escaped:: 'acde[]-' -> r'\-\[\]ac-e' -> r'[\-\[\]ac-e]' """ # Developer notes: # - Do not optimize this code assuming that the given input string # or internal lists will be short (such as in loading generators into # lists to make it easier to find the last element); this method is also # used to generate regex ranges for character sets in the pyparsing.unicode # classes, and these can be _very_ long lists of strings escape_re_range_char: Callable[[str], str] if re_escape: escape_re_range_char = _escape_re_range_char else: escape_re_range_char = lambda ss: ss ret = [] # reduce input string to remove duplicates, and put in sorted order s_chars: list[str] = sorted(set(s)) if len(s_chars) > 2: # find groups of characters that are consecutive (can be collapsed # down to "-") for _, chars in itertools.groupby(s_chars, key=_GroupConsecutive()): # _ is unimportant, is just used to identify groups # chars is an iterator of one or more consecutive characters # that comprise the current group first = last = next(chars) with contextlib.suppress(ValueError): *_, last = chars if first == last: # there was only a single char in this group ret.append(escape_re_range_char(first)) elif last == chr(ord(first) + 1): # there were only 2 characters in this group # 'a','b' -> 'ab' ret.append(f"{escape_re_range_char(first)}{escape_re_range_char(last)}") else: # there were > 2 characters in this group, make into a range # 'c','d','e' -> 'c-e' ret.append( f"{escape_re_range_char(first)}-{escape_re_range_char(last)}" ) else: # only 1 or 2 chars were given to form into groups # 'a' -> ['a'] # 'bc' -> ['b', 'c'] # 'dg' -> ['d', 'g'] # no need to list them with "-", just return as a list # (after escaping) ret = [escape_re_range_char(c) for c in s_chars] return "".join(ret) def _flatten(ll: Iterable) -> list: ret = [] for i in ll: # Developer notes: # - do not collapse this section of code, isinstance checks are done # in optimal order if isinstance(i, str): ret.append(i) elif isinstance(i, Iterable): ret.extend(_flatten(i)) else: ret.append(i) return ret def _convert_escaped_numerics_to_char(s: str) -> str: if s == "0": return "\0" if s.isdigit() and len(s) == 3: return chr(int(s, 8)) elif s.startswith(("u", "x")): return chr(int(s[1:], 16)) return s def make_compressed_re( word_list: Iterable[str], max_level: int = 2, *, non_capturing_groups: bool = True, _level: int = 1, ) -> str: """ Create a regular expression string from a list of words, collapsing by common prefixes and optional suffixes. Calls itself recursively to build nested sublists for each group of suffixes that have a shared prefix. """ def get_suffixes_from_common_prefixes(namelist: list[str]): if len(namelist) > 1: for prefix, suffixes in itertools.groupby(namelist, key=lambda s: s[:1]): yield prefix, sorted([s[1:] for s in suffixes], key=len, reverse=True) else: yield namelist[0][0], [namelist[0][1:]] if _level == 1: if not word_list: raise ValueError("no words given to make_compressed_re()") if "" in word_list: raise ValueError("word list cannot contain empty string") else: # internal recursive call, just return empty string if no words if not word_list: return "" # dedupe the word list word_list = list({}.fromkeys(word_list)) if max_level == 0: if any(len(wd) > 1 for wd in word_list): return "|".join( sorted([re.escape(wd) for wd in word_list], key=len, reverse=True) ) else: return f"[{''.join(_escape_regex_range_chars(wd) for wd in word_list)}]" ret = [] sep = "" ncgroup = "?:" if non_capturing_groups else "" for initial, suffixes in get_suffixes_from_common_prefixes(sorted(word_list)): ret.append(sep) sep = "|" initial = re.escape(initial) trailing = "" if "" in suffixes: trailing = "?" suffixes.remove("") if len(suffixes) > 1: if all(len(s) == 1 for s in suffixes): ret.append( f"{initial}[{''.join(_escape_regex_range_chars(s) for s in suffixes)}]{trailing}" ) else: if _level < max_level: suffix_re = make_compressed_re( sorted(suffixes), max_level, non_capturing_groups=non_capturing_groups, _level=_level + 1, ) ret.append(f"{initial}({ncgroup}{suffix_re}){trailing}") else: if all(len(s) == 1 for s in suffixes): ret.append( f"{initial}[{''.join(_escape_regex_range_chars(s) for s in suffixes)}]{trailing}" ) else: suffixes.sort(key=len, reverse=True) ret.append( f"{initial}({ncgroup}{'|'.join(re.escape(s) for s in suffixes)}){trailing}" ) else: if suffixes: suffix = re.escape(suffixes[0]) if len(suffix) > 1 and trailing: ret.append(f"{initial}({ncgroup}{suffix}){trailing}") else: ret.append(f"{initial}{suffix}{trailing}") else: ret.append(initial) return "".join(ret) def replaced_by_pep8(compat_name: str, fn: C) -> C: # Unwrap staticmethod/classmethod fn = getattr(fn, "__func__", fn) # (Presence of 'self' arg in signature is used by explain_exception() methods, so we take # some extra steps to add it if present in decorated function.) if ["self"] == list(inspect.signature(fn).parameters)[:1]: @wraps(fn) def _inner(self, *args, **kwargs): warnings.warn( f"{compat_name!r} deprecated - use {fn.__name__!r}", PyparsingDeprecationWarning, stacklevel=2, ) return fn(self, *args, **kwargs) else: @wraps(fn) def _inner(*args, **kwargs): warnings.warn( f"{compat_name!r} deprecated - use {fn.__name__!r}", PyparsingDeprecationWarning, stacklevel=2, ) return fn(*args, **kwargs) _inner.__doc__ = f""" .. deprecated:: 3.0.0 Use :class:`{fn.__name__}` instead """ _inner.__name__ = compat_name _inner.__annotations__ = fn.__annotations__ if isinstance(fn, types.FunctionType): _inner.__kwdefaults__ = fn.__kwdefaults__ # type: ignore [attr-defined] elif isinstance(fn, type) and hasattr(fn, "__init__"): _inner.__kwdefaults__ = fn.__init__.__kwdefaults__ # type: ignore [misc,attr-defined] else: _inner.__kwdefaults__ = None # type: ignore [attr-defined] _inner.__qualname__ = fn.__qualname__ return cast(C, _inner) def _to_pep8_name(s: str, _re_sub_pattern=re.compile(r"([a-z])([A-Z])")) -> str: s = _re_sub_pattern.sub(r"\1_\2", s) return s.lower() def deprecate_argument( kwargs: dict[str, Any], arg_name: str, default_value=None, *, new_name: str = "" ) -> Any: if arg_name in kwargs: new_name = new_name or _to_pep8_name(arg_name) warnings.warn( f"{arg_name!r} argument is deprecated, use {new_name!r}", category=PyparsingDeprecationWarning, stacklevel=3, ) else: kwargs[arg_name] = default_value return kwargs[arg_name] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.724493 pyparsing-3.3.2/pyparsing/warnings.py0000644000000000000000000000054515134002420014672 0ustar00class PyparsingWarning(UserWarning): """Base warning class for all pyparsing warnings""" class PyparsingDeprecationWarning(PyparsingWarning, DeprecationWarning): """Base warning class for all pyparsing deprecation warnings""" class PyparsingDiagnosticWarning(PyparsingWarning): """Base warning class for all pyparsing diagnostic warnings""" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.724493 pyparsing-3.3.2/pyproject.toml0000644000000000000000000000341315134002420013365 0ustar00[build-system] requires = ["flit_core >=3.12,<4"] build-backend = "flit_core.buildapi" [project] name = "pyparsing" authors = [{name = "Paul McGuire", email = "ptmcg.gm+pyparsing@gmail.com"}] readme = "README.rst" license = "MIT" license-files = ["LICENSE"] dynamic = ["version", "description"] requires-python = ">=3.9" classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "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", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Compilers", "Topic :: Text Processing", "Typing :: Typed", ] [project.optional-dependencies] diagrams = [ "railroad-diagrams", "jinja2", ] [project.urls] Homepage = "https://github.com/pyparsing/pyparsing/" Documentation = "https://pyparsing-docs.readthedocs.io/en/latest/" Source = "https://github.com/pyparsing/pyparsing.git" [tool.flit.sdist] include = [ "CHANGES", "CODE_OF_CONDUCT.rst", "CONTRIBUTING.md", "LICENSE", "ai/best_practices.md", "docs", "examples", "tests", "tox.ini", ] exclude = [ ".github", "docs/_build", "tests/__pycache__", "pyparsing_archive.py", "tests/.mypy_cache", "update_pyparsing_timestamp.py", ] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.724493 pyparsing-3.3.2/readthedocs.yaml0000644000000000000000000000214315134002420013621 0ustar00# Read the Docs configuration file for Sphinx projects # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the OS, Python version and other tools you might need build: os: ubuntu-22.04 tools: python: "3.12" # You can also specify other tool versions: # nodejs: "20" # rust: "1.70" # golang: "1.20" # Build documentation in the "docs/" directory with Sphinx sphinx: configuration: docs/conf.py # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs # builder: "dirhtml" builder: "html" # Fail on all warnings to avoid broken references # fail_on_warning: true # Optionally build your docs in additional formats such as PDF and ePub # formats: # - pdf # - epub # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html python: install: - method: pip path: . extra_requirements: - diagrams - requirements: docs/requirements.txt ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.724493 pyparsing-3.3.2/run_perf_all_tags.bat0000644000000000000000000001165415134002420014635 0ustar00@echo off REM Run perf_pyparsing.py against multiple pyparsing versions and consolidate results into perf_pyparsing.csv REM Requirements: REM - Windows REM - Python launcher `py` on PATH REM - Internet access to install specific pyparsing versions from PyPI REM Notes: REM - This script does NOT checkout git tags. It installs each version into a temp venv REM and runs the current repo's tests\perf_pyparsing.py, which will use the installed version. REM - The perf script has been enhanced to support appending to a CSV via --append-csv. setlocal enabledelayedexpansion REM Location of this repo (directory of this .bat) set REPO_DIR=%~dp0 pushd "%REPO_DIR%" >nul REM Consolidated CSV output path set CSV=%REPO_DIR%perf_pyparsing.csv REM Remove any previous consolidated CSV (do this once for the full matrix run) if exist "%CSV%" del /f /q "%CSV%" REM List of pyparsing versions to test set "VERSIONS=3.1.1 3.1.2 3.1.3 3.1.4 3.2.0 3.2.1 3.2.3 3.2.5 3.3.1 3.3.2 ." REM Python versions to use set "PY_VERSIONS=3.9 3.10 3.11 3.12 3.13 3.14" REM ---- Summary of planned run ---- echo. echo ============================================== echo === pyparsing perf matrix: planned targets === echo ============================================== echo Python versions: %PY_VERSIONS% echo pyparsing versions: %VERSIONS% echo Output CSV: %CSV% echo ============================================== echo. REM Start cumulative timer (Unix epoch seconds) for /f %%A in ('powershell -NoProfile -Command "[int]([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())"') do set START_TS=%%A for %%P in (%PY_VERSIONS%) do ( echo. echo ******************************* echo *** Python %%P matrix entry *** echo ******************************* REM Check that the requested Python is available py -%%P -c "import sys; print(sys.version)" >nul 2>&1 if errorlevel 1 ( echo Python %%P not found by the 'py' launcher, skipping this interpreter. ) else ( REM Create a fresh venv per Python version set "VENV_DIR=%REPO_DIR%.venv-perf-%%P" if exist "!VENV_DIR!" rmdir /S /Q "!VENV_DIR!" echo Creating virtual environment for Python %%P... py -%%P -m venv "!VENV_DIR!" if errorlevel 1 ( echo Failed to create virtual environment for Python %%P, skipping... ) else ( set "PYTHON=!VENV_DIR!\Scripts\python.exe" set "PIP=!VENV_DIR!\Scripts\pip.exe" set "VENV_TMP=!VENV_DIR!\_tmp" echo Upgrading pip and installing dependencies for Python %%P... "!PYTHON!" -m pip install --upgrade pip setuptools wheel >nul if errorlevel 1 ( echo Failed to upgrade pip for Python %%P, skipping this interpreter. ) else ( "!PIP!" install littletable >nul if errorlevel 1 ( echo Failed to install littletable for Python %%P, skipping this interpreter. ) else ( "!PIP!" install rich >nul if errorlevel 1 ( echo Failed to install rich for Python %%P, skipping this interpreter. ) else ( REM Prepare temp location for running the perf script outside the repo if exist "!VENV_TMP!" rmdir /S /Q "!VENV_TMP!" mkdir "!VENV_TMP!" copy /Y "%REPO_DIR%tests\perf_pyparsing.py" "!VENV_TMP!\perf_pyparsing.py" >nul for %%V in (%VERSIONS%) do ( echo. echo === Running perf for Python %%P, pyparsing %%V === "!PIP!" uninstall -y pyparsing >nul 2>&1 if "%%V" == "." ( "!PIP!" install -e . ) else ( "!PIP!" install "pyparsing==%%V" ) if errorlevel 1 ( echo Failed to install pyparsing %%V on Python %%P, skipping... ) else ( set PYTHONUTF8=1 pushd "!VENV_TMP!" >nul "!PYTHON!" "!VENV_TMP!\perf_pyparsing.py" --append-csv "%CSV%" set EXITCODE=!ERRORLEVEL! popd >nul if not !EXITCODE! EQU 0 ( echo perf run failed for pyparsing %%V on Python %%P, continuing... ) ) ) ) ) ) ) ) REM ---- Cumulative elapsed time after this matrix entry ---- for /f %%A in ('powershell -NoProfile -Command "[int]([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())"') do set NOW_TS=%%A set /a ELAPSED=NOW_TS-START_TS set /a ELAPSED_MIN=ELAPSED/60 set /a ELAPSED_SEC=ELAPSED%%60 set "PADSEC=0!ELAPSED_SEC!" set "PADSEC=!PADSEC:~-2!" echo Cumulative elapsed: !ELAPSED_MIN!:!PADSEC! ) echo. echo Consolidated results written to: echo %CSV% REM ---- Total elapsed time for full run ---- for /f %%A in ('powershell -NoProfile -Command "[int]([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())"') do set END_TS=%%A set /a TOTAL=END_TS-START_TS set /a T_MIN=TOTAL/60 set /a T_SEC=TOTAL%%60 set "T_PADSEC=0!T_SEC!" set "T_PADSEC=!T_PADSEC:~-2!" echo Total elapsed: !T_MIN!:!T_PADSEC! popd >nul endlocal exit /b 0 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.724493 pyparsing-3.3.2/run_perf_all_tags.sh0000644000000000000000000001116215134002420014473 0ustar00#!/usr/bin/env bash # Run tests/perf_pyparsing.py against multiple pyparsing versions and consolidate # results into perf_pyparsing.csv on Ubuntu (bash). # # Requirements: # - Ubuntu/Linux with bash # - One or more Python interpreters installed (python3.9, python3.10, ...) # - Internet access to install specific pyparsing versions from PyPI # # Notes: # - This script does NOT checkout git tags. It installs each requested version # into an isolated venv and runs the current repo's tests/perf_pyparsing.py, # which will import pyparsing from the installed package (not this checkout). # - The perf script supports appending CSV rows using the --append-csv option. set -Eeuo pipefail SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" REPO_DIR="$SCRIPT_DIR" CSV="$REPO_DIR/perf_pyparsing.csv" # pyparsing versions to test (3.1.1 through 3.3.0) VERSIONS=( 3.1.1 3.1.2 3.1.3 3.1.4 3.2.0 3.2.1 3.2.3 3.2.5 3.3.0 ) # Python versions to use PY_VERSIONS=(3.9 3.10 3.11 3.12 3.13 3.14) # ---- Summary of planned run ---- echo echo "==============================================" echo "=== pyparsing perf matrix: planned targets ===" echo "==============================================" echo -n "Python versions: " printf '%s ' "${PY_VERSIONS[@]}" echo echo -n "pyparsing versions: " printf '%s ' "${VERSIONS[@]}" echo echo "Output CSV: $CSV" echo "==============================================" echo # Remove any previous consolidated CSV (do this once for the full matrix run) rm -f "$CSV" # Start cumulative timer START_TS=$(date +%s) find_python_for_version() { local pv="$1" # e.g., 3.12 # Prefer python on PATH (Ubuntu convention) if command -v "python$pv" >/dev/null 2>&1; then echo "python$pv" return 0 fi # Fallback: try py launcher if present (less common on Linux) if command -v py >/dev/null 2>&1; then if py -"$pv" -c 'import sys; print(sys.version)' >/dev/null 2>&1; then echo "py -$pv" return 0 fi fi return 1 } for pv in "${PY_VERSIONS[@]}"; do echo echo "*******************************" echo "*** Python $pv matrix entry ***" echo "*******************************" if ! interp_cmd=$(find_python_for_version "$pv"); then echo "Python $pv not found on PATH (nor via 'py'), skipping this interpreter." continue fi VENV_DIR="$REPO_DIR/.venv-perf-$pv" if [ -d "$VENV_DIR" ]; then rm -rf "$VENV_DIR" fi echo "Creating virtual environment for Python $pv..." if [[ "$interp_cmd" == py* ]]; then # Using the Windows-style py launcher (rare on Ubuntu), invoke as: py -3.12 -m venv eval "$interp_cmd -m venv \"$VENV_DIR\"" || { echo "Failed to create venv for Python $pv, skipping..."; continue; } else "$interp_cmd" -m venv "$VENV_DIR" || { echo "Failed to create venv for Python $pv, skipping..."; continue; } fi PYTHON="$VENV_DIR/bin/python" PIP="$VENV_DIR/bin/pip" VENV_TMP="$VENV_DIR/_tmp" echo "Upgrading pip and installing dependencies for Python $pv..." if ! "$PYTHON" -m pip install --upgrade pip setuptools wheel >/dev/null; then echo "Failed to upgrade pip for Python $pv, skipping this interpreter." continue fi if ! "$PIP" install littletable >/dev/null; then echo "Failed to install littletable for Python $pv, skipping this interpreter." continue fi if ! "$PIP" install rich >/dev/null; then echo "Failed to install rich for Python $pv, skipping this interpreter." continue fi # Prepare temp location for running the perf script outside the repo rm -rf "$VENV_TMP" mkdir -p "$VENV_TMP" cp -f "$REPO_DIR/tests/perf_pyparsing.py" "$VENV_TMP/perf_pyparsing.py" for v in "${VERSIONS[@]}"; do echo echo "=== Running perf for Python $pv, pyparsing $v ===" "$PIP" uninstall -y pyparsing >/dev/null 2>&1 || true if ! "$PIP" install "pyparsing==$v"; then echo "Failed to install pyparsing $v on Python $pv, skipping..." continue fi export PYTHONUTF8=1 if ! "$PYTHON" "$VENV_TMP/perf_pyparsing.py" --append-csv "$CSV"; then echo "perf run failed for pyparsing $v on Python $pv, continuing..." continue fi done # ---- Cumulative elapsed time after this matrix entry ---- NOW_TS=$(date +%s) ELAPSED=$((NOW_TS - START_TS)) ELAPSED_MIN=$((ELAPSED / 60)) ELAPSED_SEC=$((ELAPSED % 60)) printf 'Cumulative elapsed: %d:%02d\n' "$ELAPSED_MIN" "$ELAPSED_SEC" done echo echo "Consolidated results written to:" echo " $CSV" # ---- Total elapsed time for full run ---- END_TS=$(date +%s) TOTAL=$((END_TS - START_TS)) T_MIN=$((TOTAL / 60)) T_SEC=$((TOTAL % 60)) printf 'Total elapsed: %d:%02d\n' "$T_MIN" "$T_SEC" exit 0 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.724493 pyparsing-3.3.2/tests/README.md0000644000000000000000000000752515134002420013102 0ustar00# Testing during Development After forking the pyparsing repo, and cloning your fork locally, install the libraries needed to run tests pip install -Ur tests/requirements.txt pre-commit install Run the simple unit tests to ensure your environment is setup python tests/test_simple_unit.py Use `tox` to run the full test suite on all supported Python versions # run a specific test environment tox -e py312-unit tox -e py312-doctest # run all test environments tox # run all test environments in parallel tox -p To run `mypy` standalone tox -e mypy-check # Performance benchmarks This directory includes a performance benchmark suite to compare behavior across different versions of Python and pyparsing. You can run it directly, or via helper scripts that iterate a matrix of interpreter and package versions and append results to a consolidated CSV file. ## Run the benchmark directly - From the repository root, run: ```bash python tests/perf_pyparsing.py ``` This prints a summary table and a CSV export of per‑benchmark timings to stdout. - To append the CSV rows to a consolidated file, either: - Pass the output path on the command line: ```bash python tests/perf_pyparsing.py --append-csv perf_pyparsing.csv ``` - Or set an environment variable and run without flags: ```powershell # Windows (CMD/PowerShell) set PERF_PYPARSING_CSV=perf_pyparsing.csv python tests/perf_pyparsing.py ``` ```bash # Linux/macOS (bash/zsh) export PERF_PYPARSING_CSV=perf_pyparsing.csv python tests/perf_pyparsing.py ``` If the destination file already exists, the benchmark will append new rows and avoid duplicating the CSV header line. ## Matrix runners (Windows and Ubuntu) Two scripts are provided to run the benchmark suite across a matrix of Python and pyparsing versions, and to collect all results into `perf_pyparsing.csv` in the repo root. - Windows (CMD or PowerShell): `run_perf_all_tags.bat` - Requirements: Windows, the `py` launcher on PATH, and internet access. - What it does: - Shows a summary of planned Python versions and pyparsing versions to test, and the output CSV path. - Creates a fresh virtual environment per Python version (named `.venv-perf-`). - Installs required tools in each venv (`pip`, `setuptools`, `wheel`, and runtime deps `littletable` and `rich`). - Copies `tests\perf_pyparsing.py` into a temp folder inside the venv so the run uses the installed pyparsing package, not the checkout. - Iterates through pyparsing tags `3.1.1` through `3.3.0a2`, installing each and appending results to the consolidated CSV. - Prints a cumulative elapsed timer (M:SS) after each Python version block, and a total elapsed time at the end. - How to run: ```powershell cd # e.g., D:\dev\pyparsing\gh\pyparsing .\run_perf_all_tags.bat ``` - Ubuntu/Linux (bash): `run_perf_all_tags.sh` - Requirements: bash, one or more Python interpreters available as `python3.9`, `python3.10`, …; internet access. - What it does: mirrors the Windows script behavior (venv per Python, dependency installs, iterate pyparsing versions, append to CSV, cumulative/total elapsed timers). - How to run: ```bash cd chmod +x ./run_perf_all_tags.sh ./run_perf_all_tags.sh ``` ## Notes - The consolidated output file is `perf_pyparsing.csv` at the repo root. It contains columns for date, `python_version`, `pyparsing_version`, benchmark name, mean time, standard deviation, and number of runs. - Re-running either script will recreate the venvs as needed and regenerate/append to the consolidated CSV. Some older pyparsing versions may not install on the newest Python versions; these entries will be skipped with a message. ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1768949007.724493 pyparsing-3.3.2/tests/__init__.py0000644000000000000000000000000015134002420013711 0ustar00././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/diag_embed.html0000644000000000000000000000544315134002420014546 0ustar00

W:(0-9) ':' W:(0-9) ':' W:(0-9) [combine]
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/diag_no_embed.html0000644000000000000000000000554315134002420015243 0ustar00

W:(0-9) ':' W:(0-9) ':' W:(0-9) [combine]
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/json_parser_tests.py0000644000000000000000000003012115134002420015730 0ustar00# jsonParser.py # # Copyright (c) 2006, Paul McGuire # test1 = """ { "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML", "markup"], "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "LargestPrimeLessThan100": 97, "AvogadroNumber": 6.02E23, "EvenPrimesGreaterThan2": [], "PrimesLessThan10" : [2,3,5,7], "FermatTheoremInMargin" : false, "MapRequiringFiveColors" : null, "Abbrev": "ISO 8879:1986", "EmptyDict" : {}, "EmptyList" : [] } ] } } } """ test2 = """ {"menu": { "id": "file", "value": "File:", "popup": { "menuitem": [ {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"} ] } }} """ test3 = """ {"widget": { "debug": "on", "window": { "title": "Sample Konfabulator Widget", "name": "main_window", "width": 500, "height": 500 }, "image": { "src": "Images/Sun.png", "name": "sun1", "hOffset": 250, "vOffset": 250, "alignment": "center" }, "text": { "data": "Click Here", "size": 36, "style": "bold", "name": "text1", "hOffset": 250, "vOffset": 100, "alignment": "center", "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" } }} """ test4 = """ {"web-app": { "servlet": [ // Defines the CDSServlet { "servlet-name": "cofaxCDS", "servlet-class": "org.cofax.cds.CDSServlet", /* Defines glossary variables that template designers can use across the site. You can add new variables to this set by creating a new init-param, with the param-name prefixed with "configGlossary:". */ "init-param": { "configGlossary:installationAt": "Philadelphia, PA", "configGlossary:adminEmail": "ksm@pobox.com", "configGlossary:poweredBy": "Cofax", "configGlossary:poweredByIcon": "/images/cofax.gif", "configGlossary:staticPath": "/content/static", /* Defines the template loader and template processor classes. These are implementations of org.cofax.TemplateProcessor and org.cofax.TemplateLoader respectively. Simply create new implementation of these classes and set them here if the default implementations do not suit your needs. Leave these alone for the defaults. */ "templateProcessorClass": "org.cofax.WysiwygTemplate", "templateLoaderClass": "org.cofax.FilesTemplateLoader", "templatePath": "templates", "templateOverridePath": "", /* Defines the names of the default templates to look for when acquiring WYSIWYG templates. Leave these at their defaults for most usage. */ "defaultListTemplate": "listTemplate.htm", "defaultFileTemplate": "articleTemplate.htm", /* New! useJSP switches on JSP template processing. jspListTemplate and jspFileTemplate are the names of the default templates to look for when acquiring JSP templates. Cofax currently in production at KR has useJSP set to false, since our sites currently use WYSIWYG templating exclusively. */ "useJSP": false, "jspListTemplate": "listTemplate.jsp", "jspFileTemplate": "articleTemplate.jsp", /* Defines the packageTag cache. This cache keeps Cofax from needing to interact with the database to look up packageTag commands. */ "cachePackageTagsTrack": 200, "cachePackageTagsStore": 200, "cachePackageTagsRefresh": 60, /* Defines the template cache. Keeps Cofax from needing to go to the file system to load a raw template from the file system. */ "cacheTemplatesTrack": 100, "cacheTemplatesStore": 50, "cacheTemplatesRefresh": 15, /* Defines the page cache. Keeps Cofax from processing templates to deliver to users. */ "cachePagesTrack": 200, "cachePagesStore": 100, "cachePagesRefresh": 10, "cachePagesDirtyRead": 10, /* Defines the templates Cofax will use when being browsed by a search engine identified in searchEngineRobotsDb */ "searchEngineListTemplate": "forSearchEnginesList.htm", "searchEngineFileTemplate": "forSearchEngines.htm", "searchEngineRobotsDb": "WEB-INF/robots.db", /* New! useDataStore enables/disables the Cofax database pool */ "useDataStore": true, /* Defines the implementation of org.cofax.DataStore that Cofax will use. If this DataStore class does not suit your needs simply implement a new DataStore class and set here. */ "dataStoreClass": "org.cofax.SqlDataStore", /* Defines the implementation of org.cofax.Redirection that Cofax will use. If this Redirection class does not suit your needs simply implenet a new Redirection class and set here. */ "redirectionClass": "org.cofax.SqlRedirection", /* Defines the data store name. Keep this at the default */ "dataStoreName": "cofax", /* Defines the JDBC driver that Cofax's database pool will use */ "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", /* Defines the JDBC connection URL to connect to the database */ "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", /* Defines the user name to connect to the database */ "dataStoreUser": "sa", /* Defines the password to connect to the database */ "dataStorePassword": "dataStoreTestQuery", /* A query that will run to test the validity of the connection in the pool. */ "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", /* A log file to print out database information */ "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", /* The number of connection to initialize on startup */ "dataStoreInitConns": 10, /* The maximum number of connection to use in the pool */ "dataStoreMaxConns": 100, /* The number of times a connection will be utilized from the pool before disconnect */ "dataStoreConnUsageLimit": 100, /* The level of information to print to the log */ "dataStoreLogLevel": "debug", /* The maximum URL length allowable by the CDS Servlet Helps to prevent hacking */ "maxUrlLength": 500}}, /* Defines the Email Servlet */ { "servlet-name": "cofaxEmail", "servlet-class": "org.cofax.cds.EmailServlet", "init-param": { /* The mail host to be used by the mail servlet */ "mailHost": "mail1", /* An override */ "mailHostOverride": "mail2"}}, /* Defines the Admin Servlet - used to refresh cache on demand and see statistics */ { "servlet-name": "cofaxAdmin", "servlet-class": "org.cofax.cds.AdminServlet"}, /* Defines the File Servlet - used to display files like Apache */ { "servlet-name": "fileServlet", "servlet-class": "org.cofax.cds.FileServlet"}, { "servlet-name": "cofaxTools", "servlet-class": "org.cofax.cms.CofaxToolsServlet", "init-param": { /* Path to the template folder relative to the tools tomcat installation. */ "templatePath": "toolstemplates/", /* Logging boolean 1 = on, 0 = off */ "log": 1, /* Location of log. If empty, log will be written System.out */ "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", /* Max size of log in BITS. If size is empty, no limit to log. If size is defined, log will be overwritten upon reaching defined size. */ "logMaxSize": "", /* DataStore logging boolean 1 = on, 0 = off */ "dataLog": 1, /* DataStore location of log. If empty, log will be written System.out */ "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", /* Max size of log in BITS. If size is empty, no limit to log. If size is defined, log will be overwritten upon reaching defined size. */ "dataLogMaxSize": "", /* Http string relative to server root to call for page cache removal to Cofax Servlet. */ "removePageCache": "/content/admin/remove?cache=pages&id=", /* Http string relative to server root to call for template cache removal to Cofax Servlet. */ "removeTemplateCache": "/content/admin/remove?cache=templates&id=", /* Location of folder from root of drive that will be used for ftp transfer from beta server or user hard drive to live servers. Note that Edit Article will not function without this variable set correctly. MultiPart request relies upon access to this folder. */ "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", /* Defines whether the Server should look in another path for config files or variables. */ "lookInContext": 1, /* Number of the ID of the top level administration group in tblPermGroups. */ "adminGroupID": 4, /* Is the tools app running on the 'beta server'. */ "betaServer": true}}], "servlet-mapping": { /* URL mapping for the CDS Servlet */ "cofaxCDS": "/", /* URL mapping for the Email Servlet */ "cofaxEmail": "/cofaxutil/aemail/*", /* URL mapping for the Admin servlet */ "cofaxAdmin": "/admin/*", /* URL mapping for the Files servlet */ "fileServlet": "/static/*", "cofaxTools": "/tools/*"}, /* New! The cofax taglib descriptor file */ "taglib": { "taglib-uri": "cofax.tld", "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} """ test5 = """ {"menu": { "header": "SVG Viewer", "items": [ {"id": "Open"}, {"id": "OpenNew", "label": "Open New"}, null, {"id": "ZoomIn", "label": "Zoom In"}, {"id": "ZoomOut", "label": "Zoom Out"}, {"id": "OriginalView", "label": "Original View"}, null, {"id": "Quality"}, {"id": "Pause"}, {"id": "Mute"}, null, {"id": "Find", "label": "Find..."}, {"id": "FindAgain", "label": "Find Again"}, {"id": "Copy"}, {"id": "CopyAgain", "label": "Copy Again"}, {"id": "CopySVG", "label": "Copy SVG"}, {"id": "ViewSVG", "label": "View SVG"}, {"id": "ViewSource", "label": "View Source"}, {"id": "SaveAs", "label": "Save As"}, null, {"id": "Help"}, {"id": "About", "label": "About Adobe CVG Viewer..."} ] }} """ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/karthik.ini0000644000000000000000000000053315134002420013751 0ustar00[users] source_dir = '/home/karthik/Projects/python' data_dir = '/home/karthik/Projects/data' result_dir = '/home/karthik/Projects/Results' param_file = $result_dir/param_file res_file = $result_dir/result_file comment = 'this is a comment' ; a line starting with ';' is a comment K = 8 simulate_K = 0 N = 4000 mod_scheme = 'QPSK' Na = K+2././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/mypy-ignore-cases/forward_methods.py0000644000000000000000000000123315134002420020725 0ustar00import pyparsing as pp # first, some basic validation: forward is a ParserElement, so is Literal # MatchFirst([Forward(), Literal(...)]) should also be okay e: pp.ParserElement = pp.Forward() e = pp.Literal() e = pp.MatchFirst([pp.Forward(), pp.Literal("hi there")]) # confirm that it isn't returning Any because it cannot be assigned to a str x: str = pp.Forward() | pp.Literal("oops") # type: ignore[assignment] # confirm that `Forward.__or__` has the right behavior e = pp.Forward() | pp.Literal("nice to meet you") # and that it isn't returning Any because it cannot be assigned to an int y: int = pp.Forward() | pp.Literal("oops") # type: ignore[assignment] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/parsefiletest_input_file.txt0000644000000000000000000000001315134002420017435 0ustar00123 456 789././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/perf_pyparsing.py0000644000000000000000000002525615134002420015226 0ustar00# Python import time import random import statistics as stats from typing import Callable import pyparsing as pp # ---------- Utilities ---------- def bench( name: str, fn: Callable[[], None], iters: int = 4 ) -> tuple[str, float, float, list[float]]: # one cold run (ignored) to warm caches/JIT-like paths fn() times = [] for _ in range(iters): t0 = time.perf_counter() fn() t1 = time.perf_counter() times.append(t1 - t0) mean = stats.mean(times) stdev = stats.pstdev(times) if len(times) > 1 else 0.0 print(f"{name},{mean:.6f},{stdev:.6f},{iters}") return name, mean, stdev, times def with_packrat(enabled: bool): pp.ParserElement.disable_memoization() if enabled: pp.ParserElement.enable_packrat(force=True) assert pp.ParserElement._packratEnabled == enabled def with_left_recursion(enabled: bool): pp.ParserElement.disable_memoization() if enabled: pp.ParserElement.enable_left_recursion(force=True) # ---------- Corpora generators ---------- def gen_csv(rows: int, cols: int, seed: int = 1) -> str: rnd = random.Random(seed) out = [] for _ in range(rows): row = [] for _ in range(cols): # mix of identifiers and quoted strings with commas inside sometimes if rnd.random() < 0.5: row.append("v" + str(rnd.randint(0, 10_000))) else: s = "t" + str(rnd.randint(0, 10_000)) if rnd.random() < 0.2: s += ",inner" row.append(f'"{s}"') out.append(",".join(row)) return "\n".join(out) def gen_expr_sequence(n_terms: int, seed: int = 2) -> str: rnd = random.Random(seed) ops = ["+", "-", "*", "/", "%"] def maybe_paren(term: str, prob: float = 0.25) -> str: # randomly wrap a term in parentheses return f"({term})" if rnd.random() < prob else term def make_term(depth: int) -> str: # base integer t = str(rnd.randint(0, 1000)) # with some probability, turn it into a small subexpression if rnd.random() < 0.5 and depth < 3: # choose a small number of inner terms to keep size reasonable k = rnd.randint(2, 4) parts = [str(rnd.randint(0, 1000)) for _ in range(k)] expr = parts[0] for i in range(1, k): # occasionally recurse to build nested subexpressions if rnd.random() < 0.35: next_part = make_term(depth + 1) else: next_part = parts[i] expr += f" {rnd.choice(ops)} {next_part}" t = maybe_paren(expr, prob=0.8) return t # build outer expression with n_terms top-level numbers/subexpressions terms = [make_term(0) for _ in range(n_terms)] expr = terms[0] for i in range(1, n_terms): expr += f" {rnd.choice(ops)} {terms[i]}" # print(expr) return expr def gen_log(n_lines: int, seed: int = 3) -> str: rnd = random.Random(seed) levels = ["INFO", "WARN", "ERROR", "DEBUG"] out = [] for i in range(n_lines): lvl = levels[rnd.randint(0, 3)] msg = f"message_{rnd.randint(0, 9999)}" out.append(f"{i:06d} [{lvl}] {msg}") return "\n".join(out) # ---------- Grammars ---------- def csv_grammar(): quoted = pp.QuotedString('"', esc_quote='""', multiline=False) field = quoted | pp.Word(pp.printables, exclude_chars=",") row = pp.DelimitedList(field).set_name("row") doc = pp.OneOrMore(row) return doc def arithmetic_grammar_left_recursive(): # classic left-recursive arithmetic to exercise enable_left_recursion pp.ParserElement.enable_left_recursion(force=True) lpar, rpar = map(pp.Suppress, "()") E = pp.Forward("E") integer = pp.Word(pp.nums)#.add_parse_action(lambda t: int(t[0])) muldiv = pp.one_of("* / %") addsub = pp.one_of("+ -") T = pp.Forward("T") F = integer | lpar + E + rpar T <<= T + muldiv + F | F E <<= E + addsub + T | T return E def arithmetic_grammar_non_recursive(): integer = pp.Word(pp.nums)#.add_parse_action(lambda t: int(t[0])) expr = pp.infix_notation( integer, [ (pp.one_of("+ -"), 1, pp.OpAssoc.RIGHT), # unary (pp.one_of("!"), 1, pp.OpAssoc.LEFT), (pp.one_of("^"), 2, pp.OpAssoc.LEFT), (pp.one_of("* / %"), 2, pp.OpAssoc.LEFT), (pp.one_of("+ -"), 2, pp.OpAssoc.LEFT), ], ) return expr def log_grammar(): level = pp.one_of("INFO WARN ERROR DEBUG") lbrack, rbrack = map(pp.Suppress, "[]") line = ( pp.Word(pp.nums, exact=6)("seq") + lbrack + level("level") + rbrack + pp.rest_of_line("msg") ) return line # ---------- Tasks ---------- def bench_csv_parse(rows=3000, cols=8): text = gen_csv(rows, cols) g = csv_grammar() def run(): g.parse_string(text, parse_all=True) return run def bench_expr_parse(n_terms=200, use_left_recursion=False): text = gen_expr_sequence(n_terms) if use_left_recursion: g = arithmetic_grammar_left_recursive() else: g = arithmetic_grammar_non_recursive() def run(): g.parse_string(text, parse_all=True) return run def bench_scan_log(n_lines=20000): text = gen_log(n_lines) g = log_grammar() def run(): # count matches via scan_string count = sum(1 for _ in g.scan_string(text)) assert count == n_lines return run def bench_transform_upper(n_lines=20000): # transform_string path + parse actions text = gen_log(n_lines) g = log_grammar() g.add_parse_action( lambda s, l, t: [t.seq, f"[{t.level}]", t.msg.upper()] ) def run(): g.transform_string(text) return run def bench_matchfirst_vs_or(n_alts=2000, seed=4): rnd = random.Random(seed) # create many similar alternatives to stress dispatch alts = [pp.Literal(f"KW{rnd.randint(0, n_alts*2)}") for _ in range(n_alts)] text = " ".join(a.match for a in alts[: n_alts // 2]) g_mf = pp.MatchFirst(alts) g_or = pp.Or(alts) def run_mf(): for tok, s, e in g_mf.scan_string(text): pass def run_or(): for tok, s, e in g_or.scan_string(text): pass return run_mf, run_or def bench_packrat_effect(base_fn_factory: Callable[[], Callable[[], None]]): def run_packrat_on(): with_packrat(True) base_fn_factory()() def run_packrat_off(): with_packrat(False) base_fn_factory()() return run_packrat_on, run_packrat_off # ---------- Main suite ---------- def main(): from contextlib import redirect_stdout from datetime import timedelta, date from io import StringIO import sys import time import littletable as lt import os from pathlib import Path save_csv = StringIO() start = time.perf_counter() with redirect_stdout(save_csv): print("benchmark,mean_s,stdev,runs") # 1) CSV parse (packrat off/on) run_csv = bench_packrat_effect(lambda: bench_csv_parse()) bench("csv_parse_packrat_on", run_csv[0]) bench("csv_parse_packrat_off", run_csv[1]) # 2) Expression parse via non-left recursion (packrat off/on) run_expr = bench_packrat_effect(lambda: bench_expr_parse(use_left_recursion=False)) bench("expr_non_lr_packrat_on", run_expr[0]) # omit from cumulative metrics # bench("expr_non_lr_packrat_off", run_expr[1]) # 3) Expression parse via left recursion (left recursion on) – compare packrat separately with_left_recursion(True) bench("expr_lr_leftrec_on", bench_expr_parse(use_left_recursion=True)) with_left_recursion(False) # 4) Scan-string over logs (tokenization pattern) bench("scan_log", bench_scan_log()) # 5) transform_string with parse action bench("transform_upper", bench_transform_upper()) # 6) MatchFirst vs Or dispatch run_mf, run_or = bench_matchfirst_vs_or() bench("matchfirst_many", run_mf) bench("or_many", run_or) # 7) Packrat overall toggle on a heavier CSV run_csv_heavy = bench_packrat_effect(lambda: bench_csv_parse(rows=8000, cols=10)) bench("csv_heavy_packrat_on", run_csv_heavy[0], iters=3) bench("csv_heavy_packrat_off", run_csv_heavy[1]) elapsed = time.perf_counter() - start print(f"\aTotal elapsed: {str(timedelta(seconds=elapsed))[:-5]}") results = save_csv.getvalue() benchmark_stats: lt.Table = lt.csv_import(results, transforms={"*": lt.Table.convert_numeric}) benchmark_stats.compute_field( "date", lambda *args: f"{date.today():%Y-%m-%d}" ) python_version = sys.version.partition(" ")[0] if not getattr(sys, "is_gil_enabled", 1): python_version += "t" benchmark_stats.compute_field("python_version", lambda *args: python_version) benchmark_stats.compute_field("pyparsing_version", lambda *args: pp.__version__) benchmark_stats.select("date python_version pyparsing_version *").present(width=120) print() exported_csv = benchmark_stats.csv_export( fieldnames="date python_version pyparsing_version benchmark mean_s stdev runs" ) print(exported_csv) # Optional: append results to a consolidated CSV file if requested. # Usage options: # - pass command-line option: --append-csv # - or set environment variable PERF_PYPARSING_CSV to a file path append_csv_path = None if "--append-csv" in sys.argv: try: idx = sys.argv.index("--append-csv") append_csv_path = sys.argv[idx + 1] except (ValueError, IndexError): print("warning: --append-csv specified without a path; ignoring", file=sys.stderr) append_csv_path = None elif os.getenv("PERF_PYPARSING_CSV"): append_csv_path = os.getenv("PERF_PYPARSING_CSV") if append_csv_path: out_path = Path(append_csv_path) out_path.parent.mkdir(parents=True, exist_ok=True) # If the file already exists and is non-empty, skip the header from this export try: file_exists = out_path.exists() and out_path.stat().st_size > 0 except OSError: file_exists = False lines = exported_csv.splitlines() if file_exists and lines: # drop header line lines = [ln for i, ln in enumerate(lines) if i != 0] # Append the (possibly headerless) lines to the file if lines: with out_path.open("a", encoding="utf-8", newline="") as fp: fp.write("\n".join(lines)) fp.write("\n") if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/requirements.txt0000644000000000000000000000003015134002420015067 0ustar00coverage tox pre-commit ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/test_diagram.py0000644000000000000000000002423515134002420014635 0ustar00import unittest from io import StringIO from pathlib import Path from typing import List from examples.jsonParser import jsonObject from examples.simpleBool import boolExpr from examples.simpleSQL import simpleSQL from examples.mozillaCalendarParser import calendars from pyparsing.diagram import to_railroad, railroad_to_html, NamedDiagram, AnnotatedItem import pyparsing as pp import railroad import tempfile import os import sys print(f"Running {__file__}") print(sys.version_info) curdir = Path(__file__).parent def is_run_with_coverage(): """Check whether test is run with coverage. From https://stackoverflow.com/a/69812849/165216 """ gettrace = getattr(sys, "gettrace", None) if gettrace is None: return False else: gettrace_result = gettrace() try: from coverage.pytracer import PyTracer from coverage.tracer import CTracer if isinstance(gettrace_result, (CTracer, PyTracer)): return True except ImportError: pass return False def running_in_debug() -> bool: """ Returns True if we're in debug mode (determined by either setting environment var, or running in a debugger which sets sys.settrace) """ return ( os.environ.get("RAILROAD_DEBUG", False) or sys.gettrace() and not is_run_with_coverage() ) class TestRailroadDiagrams(unittest.TestCase): def get_temp(self): """ Returns an appropriate temporary file for writing a railroad diagram """ delete_on_close = not running_in_debug() return tempfile.NamedTemporaryFile( dir=".", delete=delete_on_close, mode="w", encoding="utf-8", suffix=".html", ) def generate_railroad( self, expr: pp.ParserElement, label: str, show_results_names: bool = False ) -> List[NamedDiagram]: """ Generate an intermediate list of NamedDiagrams from a pyparsing expression. """ with self.get_temp() as temp: railroad = to_railroad(expr, show_results_names=show_results_names) temp.write(railroad_to_html(railroad)) if running_in_debug(): print(f"{label}: {temp.name}") return railroad def test_example_rr_diags(self): subtests = [ ("jsonObject", jsonObject, 8), ("boolExpr", boolExpr, 6), ("simpleSQL", simpleSQL, 20), ("calendars", calendars, 13), ] for label, example_expr, expected_rr_len in subtests: with self.subTest(f"{label}: test rr diag without results names"): railroad = self.generate_railroad(example_expr, example_expr) if len(railroad) != expected_rr_len: diag_html = railroad_to_html(railroad) for line in diag_html.splitlines(): if 'h1 class="railroad-heading"' in line: print(line) assert ( len(railroad) == expected_rr_len ), f"expected {expected_rr_len}, got {len(railroad)}" with self.subTest(f"{label}: test rr diag with results names"): railroad = self.generate_railroad( example_expr, example_expr, show_results_names=True ) if len(railroad) != expected_rr_len: print(railroad_to_html(railroad)) assert ( len(railroad) == expected_rr_len ), f"expected {expected_rr_len}, got {len(railroad)}" def test_nested_forward_with_inner_and_outer_names(self): outer = pp.Forward().set_name("outer") inner = pp.Word(pp.alphas)[...].set_name("inner") outer <<= inner railroad = self.generate_railroad(outer, "inner_outer_names") assert len(railroad) == 2 railroad = self.generate_railroad( outer, "inner_outer_names", show_results_names=True ) assert len(railroad) == 2 def test_nested_forward_with_inner_name_only(self): outer = pp.Forward() inner = pp.Word(pp.alphas)[...].set_name("inner") outer <<= inner railroad = self.generate_railroad(outer, "inner_only") assert len(railroad) == 1 railroad = self.generate_railroad(outer, "inner_only", show_results_names=True) assert len(railroad) == 1 def test_each_grammar(self): grammar = pp.Each( [ pp.Word(pp.nums), pp.Word(pp.alphas), pp.pyparsing_common.uuid, ] ).set_name("int-word-uuid in any order") railroad = self.generate_railroad(grammar, "each_expression") assert len(railroad) == 2 railroad = self.generate_railroad( grammar, "each_expression", show_results_names=True ) assert len(railroad) == 2 def test_none_name(self): grammar = pp.Or(["foo", "bar"]) railroad = to_railroad(grammar) assert len(railroad) == 1 assert railroad[0].name is not None def test_none_name2(self): grammar = pp.Or(["foo", "bar"]) + pp.Word(pp.nums).set_name("integer") railroad = to_railroad(grammar) assert len(railroad) == 2 assert railroad[0].name is not None railroad = to_railroad(grammar, show_results_names=True) assert len(railroad) == 2 def test_complete_combine_element(self): ints = pp.Word(pp.nums) grammar = pp.Combine( ints("hours") + ":" + ints("minutes") + ":" + ints("seconds") ) railroad = to_railroad(grammar) assert len(railroad) == 1 railroad = to_railroad(grammar, show_results_names=True) assert len(railroad) == 1 def test_create_diagram(self): ints = pp.Word(pp.nums) grammar = pp.Combine( ints("hours") + ":" + ints("minutes") + ":" + ints("seconds") ) diag_strio = StringIO() grammar.create_diagram(output_html=diag_strio) diag_str = diag_strio.getvalue().lower() tags = " ".split() assert all(tag in diag_str for tag in tags) def test_create_diagram_embed(self): ints = pp.Word(pp.nums) grammar = pp.Combine( ints("hours") + ":" + ints("minutes") + ":" + ints("seconds") ) diag_strio = StringIO() grammar.create_diagram(output_html=diag_strio, embed=True) diag_str = diag_strio.getvalue().lower() tags = " ".split() assert not any(tag in diag_str for tag in tags) def test_create_diagram_for_oneormore_with_stopon(self): wd = pp.Word(pp.alphas) grammar = "start" + wd[1, ...:"end"] + "end" pp.autoname_elements() railroad_diag = to_railroad(grammar) assert len(railroad_diag) == 3 assert isinstance(railroad_diag[1].diagram.items[1].item, railroad.Sequence) assert isinstance( railroad_diag[1].diagram.items[1].item.items[0], AnnotatedItem ) assert isinstance( railroad_diag[1].diagram.items[1].item.items[1], railroad.NonTerminal ) def test_kwargs_pass_thru_create_diagram(self): from io import StringIO # Creates a simple diagram with a blue body and # various other railroad features colored with # a complete disregard for taste # Very simple grammar for demo purposes salutation = pp.Word(pp.alphas).set_name("salutation") subject = pp.rest_of_line.set_name("subject") parse_grammar = salutation + subject # This is used to turn off the railroads # definition of DEFAULT_STYLE. # If this is set to 'None' the default style # will be written as part of each diagram # and will you will not be able to set the # css style globally and the string 'expStyle' # will have no effect. # There is probably a PR to railroad_diagram to # remove some cruft left in the SVG. DEFAULT_STYLE = "" # CSS Code to be placed into head of the html file expStyle = """ """ # the 'css=DEFAULT_STYLE' or 'css=""' is needed to turn off railroad_diagrams styling diag_html_capture = StringIO() parse_grammar.create_diagram( diag_html_capture, vertical=6, show_results_names=True, css=DEFAULT_STYLE, head=expStyle, ) self.assertIn(expStyle, diag_html_capture.getvalue()) if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/test_examples.py0000644000000000000000000000324315134002420015043 0ustar00# # test_examples.py # from importlib import import_module import unittest from pyparsing import testing as ppt class TestExamples(unittest.TestCase): def _run(self, name): mod = import_module("examples." + name) # use pyparsing context to reset each test to clean # pyparsing settings with ppt.reset_pyparsing_context(): getattr(mod, "main", lambda *args, **kwargs: None)() def test_numerics(self): self._run("numerics") def test_parse_python_value(self): self._run("parse_python_value") def test_tap(self): self._run("TAP") def test_roman_numerals(self): self._run("roman_numerals") def test_sexp_parser(self): self._run("sexpParser") def test_oc(self): self._run("oc") def test_delta_time(self): self._run("delta_time") def test_eval_arith(self): self._run("eval_arith") def test_select_parser(self): self._run("select_parser") def test_booleansearchparser(self): self._run("booleansearchparser") def test_rosettacode(self): self._run("rosettacode") def test_excelExpr(self): self._run("excel_expr") def test_lucene_grammar(self): self._run("lucene_grammar") def test_range_check(self): self._run("range_check") def test_stackish(self): self._run("stackish") def test_email_parser(self): self._run("email_address_parser") def test_mongodb_query_parser(self): self._run("mongodb_query_expression") def test_lox_parser(self): self._run("lox_parser") def test_inv_regex(self): self._run("inv_regex") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/test_matplotlib_cases.py0000644000000000000000000000630015134002420016547 0ustar00# # tests copied from matplotlib.tests.test_mathtext # import platform import re import pytest try: import matplotlib.mathtext as mpl_mathtext except ImportError: mpl_mathtext = None # fmt: off @pytest.mark.parametrize( "math, msg", [ (r"$\hspace{}$", r"Expected \hspace{space}"), (r"$\hspace{foo}$", r"Expected \hspace{space}"), (r"$\sinx$", r"Unknown symbol: \sinx"), (r"$\dotx$", r"Unknown symbol: \dotx"), (r"$\frac$", r"Expected \frac{num}{den}"), (r"$\frac{}{}$", r"Expected \frac{num}{den}"), (r"$\binom$", r"Expected \binom{num}{den}"), (r"$\binom{}{}$", r"Expected \binom{num}{den}"), (r"$\genfrac$", r"Expected \genfrac{ldelim}{rdelim}{rulesize}{style}{num}{den}"), (r"$\genfrac{}{}{}{}{}{}$", r"Expected \genfrac{ldelim}{rdelim}{rulesize}{style}{num}{den}"), (r"$\sqrt$", r"Expected \sqrt{value}"), (r"$\sqrt f$", r"Expected \sqrt{value}"), (r"$\overline$", r"Expected \overline{body}"), (r"$\overline{}$", r"Expected \overline{body}"), (r"$\leftF$", r"Expected a delimiter"), (r"$\rightF$", r"Unknown symbol: \rightF"), (r"$\left(\right$", r"Expected a delimiter"), # PyParsing 2 uses double quotes, PyParsing 3 uses single quotes and an # extra backslash. (r"$\left($", re.compile(r'Expected ("|\'\\)\\right["\']')), (r"$\dfrac$", r"Expected \dfrac{num}{den}"), (r"$\dfrac{}{}$", r"Expected \dfrac{num}{den}"), (r"$\overset$", r"Expected \overset{annotation}{body}"), (r"$\underset$", r"Expected \underset{annotation}{body}"), (r"$\foo$", r"Unknown symbol: \foo"), (r"$a^2^2$", r"Double superscript"), (r"$a_2_2$", r"Double subscript"), (r"$a^2_a^2$", r"Double superscript"), ], ids=[ "hspace without value", "hspace with invalid value", "function without space", "accent without space", "frac without parameters", "frac with empty parameters", "binom without parameters", "binom with empty parameters", "genfrac without parameters", "genfrac with empty parameters", "sqrt without parameters", "sqrt with invalid value", "overline without parameters", "overline with empty parameter", "left with invalid delimiter", "right with invalid delimiter", "unclosed parentheses with sizing", "unclosed parentheses without sizing", "dfrac without parameters", "dfrac with empty parameters", "overset without parameters", "underset without parameters", "unknown symbol", "double superscript", "double subscript", "super on sub without braces", ], ) @pytest.mark.skipif("mpl_mathtext is None") def test_mathtext_exceptions(math, msg): parser = mpl_mathtext.MathTextParser("agg") match = re.escape(msg) if isinstance(msg, str) else msg with pytest.raises(ValueError, match=match): parser.parse(math) # fmt: on @pytest.mark.skipif("mpl_mathtext is None") def test_get_unicode_index_exception(): with pytest.raises(ValueError): mpl_mathtext.get_unicode_index(r"\foo") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/test_pep8_converter.py0000644000000000000000000010056015134002420016170 0ustar00from pyparsing.tools.cvt_pyparsing_pep8_names import ( pep8_converter, pre_pep8_arg_names, pre_pep8_method_names, special_changes, special_changes_arg_names ) import pytest def test_conversion_composed(): # testing for these in their own test cases below special_changes_copy = {**special_changes} special_changes_copy.pop("indentedBlock") special_changes_copy.pop("locatedExpr") orig = ( "\n".join( f"{method_name}()" for method_name in sorted(pre_pep8_method_names) + list(special_changes_copy) ) + "\n" + "\n".join( f"fn(100, {arg_name}=True)" for arg_name in sorted(pre_pep8_arg_names) + list(special_changes_arg_names) ) ) expected = """\ add_condition() add_parse_action() any_close_tag() any_open_tag() as_dict() as_list() c_style_comment() can_parse_next() condition_as_parse_action() convert_to_date() convert_to_datetime() convert_to_float() convert_to_integer() counted_array() cpp_style_comment() dbl_quoted_string() dbl_slash_comment() default_name() dict_of() disable_memoization() downcase_tokens() enable_left_recursion() enable_packrat() get_name() html_comment() ignore_whitespace() infix_notation() inline_literals_using() java_style_comment() leave_whitespace() line_end() line_start() match_only_at_col() match_previous_expr() match_previous_literal() nested_expr() null_debug_action() one_of() original_text_for() parse_file() parse_string() parse_with_tabs() python_style_comment() quoted_string() remove_quotes() replace_with() reset_cache() rest_of_line() run_tests() scan_string() search_string() set_break() set_debug() set_debug_actions() set_default_whitespace_chars() set_fail_action() set_name() set_parse_action() set_results_name() set_whitespace_chars() sgl_quoted_string() string_end() string_start() token_map() trace_parse_action() transform_string() try_parse() unicode_string() upcase_tokens() with_attribute() with_class() OpAssoc() DelimitedList() DelimitedList() replace_html_entity() make_html_tags() make_xml_tags() common_html_entity() strip_html_tags() fn(100, as_group_list=True) fn(100, as_keyword=True) fn(100, as_match=True) fn(100, as_string=True) fn(100, body_chars=True) fn(100, call_during_try=True) fn(100, convert_whitespace_escapes=True) fn(100, end_quote_char=True) fn(100, esc_char=True) fn(100, esc_quote=True) fn(100, exclude_chars=True) fn(100, fail_on=True) fn(100, failure_tests=True) fn(100, full_dump=True) fn(100, ident_chars=True) fn(100, ignore_expr=True) fn(100, include_separators=True) fn(100, init_chars=True) fn(100, int_expr=True) fn(100, join_string=True) fn(100, list_all_matches=True) fn(100, marker_string=True) fn(100, match_string=True) fn(100, max_matches=True) fn(100, max_mismatches=True) fn(100, not_chars=True) fn(100, parse_all=True) fn(100, post_parse=True) fn(100, print_results=True) fn(100, quote_char=True) fn(100, stop_on=True) fn(100, unquote_results=True) fn(100, use_regex=True) fn(100, word_chars=True) fn(100, aslist=True) """.rstrip() converted = pep8_converter.transform_string(orig) assert converted == expected def test_conversion_examples(): orig = r""" L = equation.parseString(input_string) equation.runTests((t[1] for t in testcases), postParse=post_test) L = pattern.parseString(input_string, parseAll=True) itemRef = pp.OneOrMore(pp.Word(pp.alphas)).set_parse_action(self.validate_item_name).setName("item_ref") doorsCommand = doorsVerb.setName("DOORS") originalTextFor, cStyleComment, oneOf, delimitedList, oneOf(list(r"nrtbf\">" + "'")) | ("u" + Word(hexnums, exact=4)) | SGL_PRINTABLE | (SCOPE_.suppress() + delimitedList(id) + SEMI) | (SCOPE_.suppress() + ACTION + SCOPE_.suppress() + delimitedList(id) + SEMI) (id("result_name") + oneOf("= +=")("labelOp") + atom("atom") + Optional(ebnfSuffix)) | (id("result_name") + oneOf("= +=")("labelOp") + block + Optional(ebnfSuffix)) antlrGrammarTree = grammar().parseString(text) pyparsingTree = pyparsingRule.parseString("2 - 5 * 42 + 7 / 25") antlr_grammar.optionsSpec.parseString(text) # @UndefinedVariable antlr_grammar.tokensSpec.parseString(text) # @UndefinedVariable antlr_grammar.block.parseString(text) # @UndefinedVariable antlr_grammar.rule.parseString(text) # @UndefinedVariable # antlr_grammar.rule.parseString(text) #@UndefinedVariable antlrGrammarTree = antlr_grammar.grammarDef.parseString( pyparsingTree = pyparsingRule.parseString("2 - 5 * 42 + 7 / 25") pyparsingTreeList = pyparsingTree.asList() api_scanner = apiRef.scanString(test) api_scanner = apiRef.scanString(test) BigQueryViewParser._get_parser().parseString(sql_stmt, parseAll=True) ParserElement.enablePackrat() ungrouped_select_stmt = Forward().setName("select statement") QUOTED_BRACKETS = QuotedString("[", endQuoteChar="]") expr = Forward().setName("expression") bind_parameter = Word("?", nums) | Combine(oneOf(": @ $") + parameter_name) type_name = oneOf( date_part = oneOf( + delimitedList(function_arg) partition_expression_list = delimitedList(grouping_term)( + Optional(ORDER + BY + delimitedList(ordering_term)) Optional(ARRAY + Optional(LT + delimitedList(type_name) + GT)) + delimitedList(expr) + Optional(LT + delimitedList(type_name) + GT) + Optional(delimitedList(expr + Optional(AS + identifier))) struct_term = LPAR + delimitedList(expr_term) + RPAR expr <<= infixNotation( (oneOf("- + ~") | NOT, UNARY, opAssoc.RIGHT), (ISNULL | NOTNULL | NOT + NULL, UNARY, opAssoc.LEFT), ("||", BINARY, opAssoc.LEFT), (oneOf("* / %"), BINARY, opAssoc.LEFT), (oneOf("+ -"), BINARY, opAssoc.LEFT), (oneOf("<< >> & |"), BINARY, opAssoc.LEFT), (oneOf("= > < >= <= <> != !< !> =="), BINARY, opAssoc.LEFT), opAssoc.LEFT, ((BETWEEN, AND), TERNARY, opAssoc.LEFT), + Group(ungrouped_select_stmt | delimitedList(expr)) (AND, BINARY, opAssoc.LEFT), (OR, BINARY, opAssoc.LEFT), | USING + LPAR + Group(delimitedList(qualified_column_name)) + RPAR identifier_list = t.asList() ).setParseAction(record_table_identifier) ).setParseAction(record_quoted_table_identifier) ).setName("table_identifier") over_partition = (PARTITION + BY + delimitedList(partition_expression_list))( over_order = ORDER + BY + delimitedList(ordering_term) EXCEPT + LPAR + delimitedList(column_name) + RPAR with_stmt = Forward().setName("with statement") delimitedList( GROUP + BY + Group(delimitedList(grouping_term))("group_by_terms") ORDER + BY + Group(delimitedList(ordering_term))("order_by_terms") + Optional(delimitedList(window_select_clause)) sql_comment = oneOf("-- #") + restOfLine | cStyleComment identifier.setParseAction(record_with_alias) with_stmt <<= WITH + delimitedList(with_clause) return bibfile.parseString(str) stmt.runTests('''\ (Literal("#").suppress() + Word(nums)).setParseAction( + Optional(Group(delimitedList(identifier | number_value | string_value))) i.setParseAction(action) retval[f] = object_definition.parseFile(f) vert + pp.Word(pp.alphas) + vert + pp.delimitedList(number, "|") + vert results = BNF().parseString(s, parseAll=True) cStyleComment.suppress() | fn_typedef.suppress() | func_def if fn.fn_args.asList() != [["void"]]: fullDump=False, dblQuotedString, removeQuotes, ipAddress = delimitedList(integer, ".", combine=True) ipAddress.setResultsName("ipAddr") + ("-" | Word(alphas + nums + "@._")).setResultsName("auth") + serverDateTime.setResultsName("timestamp") + dblQuotedString.setResultsName("cmd").setParseAction(getCmdFields) + (integer | "-").setResultsName("statusCode") + (integer | "-").setResultsName("numBytesSent") + dblQuotedString.setResultsName("referrer").setParseAction(removeQuotes) + dblQuotedString.setResultsName("clientSfw").setParseAction(removeQuotes) fields = getLogLineBNF().parseString(line) + include_directive.transformString(included_file_contents) # use include_directive.transformString to perform includes expanded_source = include_directive.transformString(initial_file) "def" + identifier + Group("(" + Optional(delimitedList(identifier)) + ")") + ":" invre = GroupEmitter(parser().parseString(regex)).make_generator() (pp.one_of("! -"), 1, pp.opAssoc.RIGHT), (pp.one_of("/ *"), 2, pp.opAssoc.LEFT), (pp.one_of("- +"), 2, pp.opAssoc.LEFT), (pp.one_of("> >= < <="), 2, pp.opAssoc.LEFT), (pp.one_of("!= =="), 2, pp.opAssoc.LEFT), (AND, 2, pp.opAssoc.LEFT), (OR, 2, pp.opAssoc.LEFT), ("^", 2, pp.opAssoc.LEFT), ((NOT | pp.oneOf("# - ~")).set_name("not op"), 1, pp.opAssoc.RIGHT), (pp.oneOf("* / // %"), 2, pp.opAssoc.LEFT), (pp.oneOf("+ -"), 2, pp.opAssoc.LEFT), ("..", 2, pp.opAssoc.LEFT), (pp.oneOf("<< >>"), 2, pp.opAssoc.LEFT), ("&", 2, pp.opAssoc.LEFT), ("~", 2, pp.opAssoc.LEFT), ("|", 2, pp.opAssoc.LEFT), (pp.oneOf("< > <= >= ~= =="), 2, pp.opAssoc.LEFT), result = lua_script.parseString(sample) success2, _ = expression.run_tests(failtests, failureTests=True) UID DTSTAMP LAST-MODIFIED X RRULE EXDATE''', asKeyword=True return opening + wiki_markup.transformString(t[1][1:-1]) + closing t["link_text"] = wiki_markup.transformString(link_text) postParse=lambda _, s: "{:,}".format(s[0]), ast = program.parse_string(test, parseAll=True) expr.copy().addCondition( print(row.parseString(line).dump()) + pp.Word("ACGTN")[1, ...].addParseAction("".join)("gene") for t, startLoc, endLoc in searchseq.scanString(g.gene, overlap=True): return Empty().setParseAction(lambda s, l, t: t.__setitem__(name, l)) quotedString, OPTION_ - ident("optionName") + EQ + quotedString("optionValue") + SEMI return cls(t[0].asList()) (bnfToken | quotedString | optionalTerm | (LPAREN + bnfExpr + RPAREN)) ).setName("street_address") ).setName("header with various elements")("header") (plus_minus().setName("pos_neg"), 1, pp.opAssoc.RIGHT), (mult_div, 2, pp.opAssoc.LEFT), (plus_minus, 2, pp.opAssoc.LEFT), ]).setName("simple_arithmetic") ).setName("grammar") restOfLine, replaceWith, + ident.setResultsName("name") + restOfLine.setResultsName("value") operatorWord = Group(Combine(Word(alphanums) + Suppress("*"))).setResultsName( ) | Group(Word(alphanums)).setResultsName("word") Group(Suppress('"') + operatorQuotesContent + Suppress('"')).setResultsName( Group(Suppress("(") + operatorOr + Suppress(")")).setResultsName( Group(Suppress(Keyword("not", caseless=True)) + operatorNot).setResultsName( ).setResultsName("and") operatorNot + OneOrMore(~oneOf("and or") + operatorAnd) ).setResultsName("or") return operatorOr.parseString return self._methods[argument.getName()](argument) sexp.run_tests(alltests, fullDump=False) self.__dict__.update(tokens.asDict()) shape = shapeExpr.parseString(t)[0] (factop, 1, opAssoc.LEFT), (expop, 2, opAssoc.RIGHT), (signop, 1, opAssoc.RIGHT), (multop, 2, opAssoc.LEFT), (plusop, 2, opAssoc.LEFT), print(expr.parseString(t)) + Word(alphas, alphanums + "_").setResultsName("tablename") + field_list_def.setResultsName("columns") + Word(alphanums + "_").setResultsName("fromtable") + Word(alphanums + "_").setResultsName("fromcolumn") + Word(alphanums + "_").setResultsName("totable") + Word(alphanums + "_").setResultsName("tocolumn") self.assertEqual("2t", name_type.parseString("2t")[0]) self.assertRaises(ParseException, name_type.parseString, "2t") self.assertRaises(ParseException, name_type.parseString, char) self.assertEqual("simple_test", name_type.parseString("simple_test")[0]) self.assertRaises(ParseException, mr.parseString, "2t") self.assertRaises(ParseException, mr.parseString, char) self.assertEqual("simple_test", mr.parseString("simple_test")[0].name) self.assertEqual("1066", bp.number.parseString("1066")[0]) self.assertEqual("0", bp.number.parseString("0")[0]) self.assertRaises(ParseException, bp.number.parseString, "-4") self.assertRaises(ParseException, bp.number.parseString, "+4") self.assertRaises(ParseException, bp.number.parseString, ".4") self.assertEqual("0", bp.number.parseString("0.4")[0]) self.assertEqual(bp.chars_no_quotecurly.parseString("x")[0], "x") self.assertEqual(bp.chars_no_quotecurly.parseString("a string")[0], "a string") self.assertEqual(bp.chars_no_quotecurly.parseString('a "string')[0], "a ") self.assertEqual(bp.chars_no_curly.parseString("x")[0], "x") self.assertEqual(bp.chars_no_curly.parseString("a string")[0], "a string") self.assertEqual(bp.chars_no_curly.parseString("a {string")[0], "a ") self.assertEqual(bp.chars_no_curly.parseString("a }string")[0], "a ") self.assertEqual(obj.parseString("{}").asList(), []) self.assertEqual(obj.parseString('{a "string}')[0], 'a "string') obj.parseString("{a {nested} string}").asList(), obj.parseString("{a {double {nested}} string}").asList(), self.assertEqual([], obj.parseString('""').asList()) self.assertEqual("a string", obj.parseString('"a string"')[0]) obj.parseString('"a {nested} string"').asList(), obj.parseString('"a {double {nested}} string"').asList(), self.assertEqual(Macro("someascii"), bp.string.parseString("someascii")[0]) self.assertRaises(ParseException, bp.string.parseString, "%#= validstring") self.assertEqual(bp.string.parseString("1994")[0], "1994") self.assertEqual(Macro("aname"), fv.parseString("aname")[0]) self.assertEqual(Macro("aname"), fv.parseString("ANAME")[0]) fv.parseString('aname # "some string"').asList(), fv.parseString("aname # {some {string}}").asList(), ["a string", "1994"], fv.parseString('"a string" # 1994').asList() fv.parseString('"a string" # 1994 # a_macro').asList(), res = bp.comment.parseString("@Comment{about something}") self.assertEqual(res.asList(), ["comment", "{about something}"]) bp.comment.parseString("@COMMENT{about something").asList(), bp.comment.parseString("@comment(about something").asList(), bp.comment.parseString("@COMment about something").asList(), ParseException, bp.comment.parseString, "@commentabout something" ParseException, bp.comment.parseString, "@comment+about something" ParseException, bp.comment.parseString, '@comment"about something' res = bp.preamble.parseString('@preamble{"about something"}') self.assertEqual(res.asList(), ["preamble", "about something"]) bp.preamble.parseString("@PREamble{{about something}}").asList(), bp.preamble.parseString( ).asList(), res = bp.macro.parseString('@string{ANAME = "about something"}') self.assertEqual(res.asList(), ["string", "aname", "about something"]) bp.macro.parseString("@string{aname = {about something}}").asList(), res = bp.entry.parseString(txt) res.asList(), res = bp.bibfile.parseString(txt) self.assertEqual(res.asList(), res2.asList()) res3 = [r.asList()[0] for r, start, end in bp.definitions.scanString(txt)] self.assertEqual(res.asList(), res3) print(toks.asList()) parsed = ppc.url.parseString(url) cppStyleComment, + restOfLine Regex(r"\\\S+").setParseAction(lambda t: t[0][1:]).set_name("escapedIdent") ) # .setDebug() joinString=" ", | (LPAR + Group(expr) + RPAR).set_name("nestedExpr") delay = Group("#" + delayArg).set_name("delay") # .setDebug() stmt = Forward().set_name("stmt") # .setDebug() verilogbnf.ignore(cppStyleComment) return ret.set_parse_action(pp.replaceWith(val)) """ expected = r""" L = equation.parse_string(input_string) equation.run_tests((t[1] for t in testcases), post_parse=post_test) L = pattern.parse_string(input_string, parse_all=True) itemRef = pp.OneOrMore(pp.Word(pp.alphas)).set_parse_action(self.validate_item_name).set_name("item_ref") doorsCommand = doorsVerb.set_name("DOORS") original_text_for, c_style_comment, one_of, DelimitedList, one_of(list(r"nrtbf\">" + "'")) | ("u" + Word(hexnums, exact=4)) | SGL_PRINTABLE | (SCOPE_.suppress() + DelimitedList(id) + SEMI) | (SCOPE_.suppress() + ACTION + SCOPE_.suppress() + DelimitedList(id) + SEMI) (id("result_name") + one_of("= +=")("labelOp") + atom("atom") + Optional(ebnfSuffix)) | (id("result_name") + one_of("= +=")("labelOp") + block + Optional(ebnfSuffix)) antlrGrammarTree = grammar().parse_string(text) pyparsingTree = pyparsingRule.parse_string("2 - 5 * 42 + 7 / 25") antlr_grammar.optionsSpec.parse_string(text) # @UndefinedVariable antlr_grammar.tokensSpec.parse_string(text) # @UndefinedVariable antlr_grammar.block.parse_string(text) # @UndefinedVariable antlr_grammar.rule.parse_string(text) # @UndefinedVariable # antlr_grammar.rule.parse_string(text) #@UndefinedVariable antlrGrammarTree = antlr_grammar.grammarDef.parse_string( pyparsingTree = pyparsingRule.parse_string("2 - 5 * 42 + 7 / 25") pyparsingTreeList = pyparsingTree.as_list() api_scanner = apiRef.scan_string(test) api_scanner = apiRef.scan_string(test) BigQueryViewParser._get_parser().parse_string(sql_stmt, parse_all=True) ParserElement.enable_packrat() ungrouped_select_stmt = Forward().set_name("select statement") QUOTED_BRACKETS = QuotedString("[", end_quote_char="]") expr = Forward().set_name("expression") bind_parameter = Word("?", nums) | Combine(one_of(": @ $") + parameter_name) type_name = one_of( date_part = one_of( + DelimitedList(function_arg) partition_expression_list = DelimitedList(grouping_term)( + Optional(ORDER + BY + DelimitedList(ordering_term)) Optional(ARRAY + Optional(LT + DelimitedList(type_name) + GT)) + DelimitedList(expr) + Optional(LT + DelimitedList(type_name) + GT) + Optional(DelimitedList(expr + Optional(AS + identifier))) struct_term = LPAR + DelimitedList(expr_term) + RPAR expr <<= infix_notation( (one_of("- + ~") | NOT, UNARY, OpAssoc.RIGHT), (ISNULL | NOTNULL | NOT + NULL, UNARY, OpAssoc.LEFT), ("||", BINARY, OpAssoc.LEFT), (one_of("* / %"), BINARY, OpAssoc.LEFT), (one_of("+ -"), BINARY, OpAssoc.LEFT), (one_of("<< >> & |"), BINARY, OpAssoc.LEFT), (one_of("= > < >= <= <> != !< !> =="), BINARY, OpAssoc.LEFT), OpAssoc.LEFT, ((BETWEEN, AND), TERNARY, OpAssoc.LEFT), + Group(ungrouped_select_stmt | DelimitedList(expr)) (AND, BINARY, OpAssoc.LEFT), (OR, BINARY, OpAssoc.LEFT), | USING + LPAR + Group(DelimitedList(qualified_column_name)) + RPAR identifier_list = t.as_list() ).set_parse_action(record_table_identifier) ).set_parse_action(record_quoted_table_identifier) ).set_name("table_identifier") over_partition = (PARTITION + BY + DelimitedList(partition_expression_list))( over_order = ORDER + BY + DelimitedList(ordering_term) EXCEPT + LPAR + DelimitedList(column_name) + RPAR with_stmt = Forward().set_name("with statement") DelimitedList( GROUP + BY + Group(DelimitedList(grouping_term))("group_by_terms") ORDER + BY + Group(DelimitedList(ordering_term))("order_by_terms") + Optional(DelimitedList(window_select_clause)) sql_comment = one_of("-- #") + rest_of_line | c_style_comment identifier.set_parse_action(record_with_alias) with_stmt <<= WITH + DelimitedList(with_clause) return bibfile.parse_string(str) stmt.run_tests('''\ (Literal("#").suppress() + Word(nums)).set_parse_action( + Optional(Group(DelimitedList(identifier | number_value | string_value))) i.set_parse_action(action) retval[f] = object_definition.parse_file(f) vert + pp.Word(pp.alphas) + vert + pp.DelimitedList(number, "|") + vert results = BNF().parse_string(s, parse_all=True) c_style_comment.suppress() | fn_typedef.suppress() | func_def if fn.fn_args.as_list() != [["void"]]: full_dump=False, dbl_quoted_string, remove_quotes, ipAddress = DelimitedList(integer, ".", combine=True) ipAddress.set_results_name("ipAddr") + ("-" | Word(alphas + nums + "@._")).set_results_name("auth") + serverDateTime.set_results_name("timestamp") + dbl_quoted_string.set_results_name("cmd").set_parse_action(getCmdFields) + (integer | "-").set_results_name("statusCode") + (integer | "-").set_results_name("numBytesSent") + dbl_quoted_string.set_results_name("referrer").set_parse_action(remove_quotes) + dbl_quoted_string.set_results_name("clientSfw").set_parse_action(remove_quotes) fields = getLogLineBNF().parse_string(line) + include_directive.transform_string(included_file_contents) # use include_directive.transform_string to perform includes expanded_source = include_directive.transform_string(initial_file) "def" + identifier + Group("(" + Optional(DelimitedList(identifier)) + ")") + ":" invre = GroupEmitter(parser().parse_string(regex)).make_generator() (pp.one_of("! -"), 1, pp.OpAssoc.RIGHT), (pp.one_of("/ *"), 2, pp.OpAssoc.LEFT), (pp.one_of("- +"), 2, pp.OpAssoc.LEFT), (pp.one_of("> >= < <="), 2, pp.OpAssoc.LEFT), (pp.one_of("!= =="), 2, pp.OpAssoc.LEFT), (AND, 2, pp.OpAssoc.LEFT), (OR, 2, pp.OpAssoc.LEFT), ("^", 2, pp.OpAssoc.LEFT), ((NOT | pp.one_of("# - ~")).set_name("not op"), 1, pp.OpAssoc.RIGHT), (pp.one_of("* / // %"), 2, pp.OpAssoc.LEFT), (pp.one_of("+ -"), 2, pp.OpAssoc.LEFT), ("..", 2, pp.OpAssoc.LEFT), (pp.one_of("<< >>"), 2, pp.OpAssoc.LEFT), ("&", 2, pp.OpAssoc.LEFT), ("~", 2, pp.OpAssoc.LEFT), ("|", 2, pp.OpAssoc.LEFT), (pp.one_of("< > <= >= ~= =="), 2, pp.OpAssoc.LEFT), result = lua_script.parse_string(sample) success2, _ = expression.run_tests(failtests, failure_tests=True) UID DTSTAMP LAST-MODIFIED X RRULE EXDATE''', as_keyword=True return opening + wiki_markup.transform_string(t[1][1:-1]) + closing t["link_text"] = wiki_markup.transform_string(link_text) post_parse=lambda _, s: "{:,}".format(s[0]), ast = program.parse_string(test, parse_all=True) expr.copy().add_condition( print(row.parse_string(line).dump()) + pp.Word("ACGTN")[1, ...].add_parse_action("".join)("gene") for t, startLoc, endLoc in searchseq.scan_string(g.gene, overlap=True): return Empty().set_parse_action(lambda s, l, t: t.__setitem__(name, l)) quoted_string, OPTION_ - ident("optionName") + EQ + quoted_string("optionValue") + SEMI return cls(t[0].as_list()) (bnfToken | quoted_string | optionalTerm | (LPAREN + bnfExpr + RPAREN)) ).set_name("street_address") ).set_name("header with various elements")("header") (plus_minus().set_name("pos_neg"), 1, pp.OpAssoc.RIGHT), (mult_div, 2, pp.OpAssoc.LEFT), (plus_minus, 2, pp.OpAssoc.LEFT), ]).set_name("simple_arithmetic") ).set_name("grammar") rest_of_line, replace_with, + ident.set_results_name("name") + rest_of_line.set_results_name("value") operatorWord = Group(Combine(Word(alphanums) + Suppress("*"))).set_results_name( ) | Group(Word(alphanums)).set_results_name("word") Group(Suppress('"') + operatorQuotesContent + Suppress('"')).set_results_name( Group(Suppress("(") + operatorOr + Suppress(")")).set_results_name( Group(Suppress(Keyword("not", caseless=True)) + operatorNot).set_results_name( ).set_results_name("and") operatorNot + OneOrMore(~one_of("and or") + operatorAnd) ).set_results_name("or") return operatorOr.parse_string return self._methods[argument.get_name()](argument) sexp.run_tests(alltests, full_dump=False) self.__dict__.update(tokens.as_dict()) shape = shapeExpr.parse_string(t)[0] (factop, 1, OpAssoc.LEFT), (expop, 2, OpAssoc.RIGHT), (signop, 1, OpAssoc.RIGHT), (multop, 2, OpAssoc.LEFT), (plusop, 2, OpAssoc.LEFT), print(expr.parse_string(t)) + Word(alphas, alphanums + "_").set_results_name("tablename") + field_list_def.set_results_name("columns") + Word(alphanums + "_").set_results_name("fromtable") + Word(alphanums + "_").set_results_name("fromcolumn") + Word(alphanums + "_").set_results_name("totable") + Word(alphanums + "_").set_results_name("tocolumn") self.assertEqual("2t", name_type.parse_string("2t")[0]) self.assertRaises(ParseException, name_type.parse_string, "2t") self.assertRaises(ParseException, name_type.parse_string, char) self.assertEqual("simple_test", name_type.parse_string("simple_test")[0]) self.assertRaises(ParseException, mr.parse_string, "2t") self.assertRaises(ParseException, mr.parse_string, char) self.assertEqual("simple_test", mr.parse_string("simple_test")[0].name) self.assertEqual("1066", bp.number.parse_string("1066")[0]) self.assertEqual("0", bp.number.parse_string("0")[0]) self.assertRaises(ParseException, bp.number.parse_string, "-4") self.assertRaises(ParseException, bp.number.parse_string, "+4") self.assertRaises(ParseException, bp.number.parse_string, ".4") self.assertEqual("0", bp.number.parse_string("0.4")[0]) self.assertEqual(bp.chars_no_quotecurly.parse_string("x")[0], "x") self.assertEqual(bp.chars_no_quotecurly.parse_string("a string")[0], "a string") self.assertEqual(bp.chars_no_quotecurly.parse_string('a "string')[0], "a ") self.assertEqual(bp.chars_no_curly.parse_string("x")[0], "x") self.assertEqual(bp.chars_no_curly.parse_string("a string")[0], "a string") self.assertEqual(bp.chars_no_curly.parse_string("a {string")[0], "a ") self.assertEqual(bp.chars_no_curly.parse_string("a }string")[0], "a ") self.assertEqual(obj.parse_string("{}").as_list(), []) self.assertEqual(obj.parse_string('{a "string}')[0], 'a "string') obj.parse_string("{a {nested} string}").as_list(), obj.parse_string("{a {double {nested}} string}").as_list(), self.assertEqual([], obj.parse_string('""').as_list()) self.assertEqual("a string", obj.parse_string('"a string"')[0]) obj.parse_string('"a {nested} string"').as_list(), obj.parse_string('"a {double {nested}} string"').as_list(), self.assertEqual(Macro("someascii"), bp.string.parse_string("someascii")[0]) self.assertRaises(ParseException, bp.string.parse_string, "%#= validstring") self.assertEqual(bp.string.parse_string("1994")[0], "1994") self.assertEqual(Macro("aname"), fv.parse_string("aname")[0]) self.assertEqual(Macro("aname"), fv.parse_string("ANAME")[0]) fv.parse_string('aname # "some string"').as_list(), fv.parse_string("aname # {some {string}}").as_list(), ["a string", "1994"], fv.parse_string('"a string" # 1994').as_list() fv.parse_string('"a string" # 1994 # a_macro').as_list(), res = bp.comment.parse_string("@Comment{about something}") self.assertEqual(res.as_list(), ["comment", "{about something}"]) bp.comment.parse_string("@COMMENT{about something").as_list(), bp.comment.parse_string("@comment(about something").as_list(), bp.comment.parse_string("@COMment about something").as_list(), ParseException, bp.comment.parse_string, "@commentabout something" ParseException, bp.comment.parse_string, "@comment+about something" ParseException, bp.comment.parse_string, '@comment"about something' res = bp.preamble.parse_string('@preamble{"about something"}') self.assertEqual(res.as_list(), ["preamble", "about something"]) bp.preamble.parse_string("@PREamble{{about something}}").as_list(), bp.preamble.parse_string( ).as_list(), res = bp.macro.parse_string('@string{ANAME = "about something"}') self.assertEqual(res.as_list(), ["string", "aname", "about something"]) bp.macro.parse_string("@string{aname = {about something}}").as_list(), res = bp.entry.parse_string(txt) res.as_list(), res = bp.bibfile.parse_string(txt) self.assertEqual(res.as_list(), res2.as_list()) res3 = [r.as_list()[0] for r, start, end in bp.definitions.scan_string(txt)] self.assertEqual(res.as_list(), res3) print(toks.as_list()) parsed = ppc.url.parse_string(url) cpp_style_comment, + rest_of_line Regex(r"\\\S+").set_parse_action(lambda t: t[0][1:]).set_name("escapedIdent") ) # .set_debug() join_string=" ", | (LPAR + Group(expr) + RPAR).set_name("nested_expr") delay = Group("#" + delayArg).set_name("delay") # .set_debug() stmt = Forward().set_name("stmt") # .set_debug() verilogbnf.ignore(cpp_style_comment) return ret.set_parse_action(pp.replace_with(val)) """ failed = 0 for o, e in zip(orig.splitlines(), expected.splitlines()): converted = pep8_converter.transform_string(o) try: assert converted == e except AssertionError: print() print(f"Expected: {e!r}\n" f"Observed: {converted!r}") failed += 1 if failed: raise AssertionError(f"Failed to convert some original code ({failed} lines)") def test_conversion_warnings_for_indentedBlock(): source = """ parser = pp.indentedBlock(expr, indent, backup_stacks) """ with pytest.warns( UserWarning, match=( "Conversion of 'indentedBlock' to new 'IndentedBlock' requires added code changes" " to remove 'indentStack' argument" "\n" r" 2: parser = pp.indentedBlock\(expr, indent, backup_stacks\)" ) ): res = pep8_converter.transform_string(source) print(res) expected = source.replace("indentedBlock", "IndentedBlock") print(expected) assert res == expected def test_conversion_warnings_for_locatedExpr(): source = """ parser = pp.locatedExpr(expr) """ with pytest.warns( UserWarning, match=( "Conversion of 'locatedExpr' to new 'Located' may require added" " code changes - Located does not automatically group parsed elements" "\n" r" 2: parser = pp.locatedExpr\(expr\)" ) ): res = pep8_converter.transform_string(source) print(res) expected = source.replace("locatedExpr", "Located") print(expected) assert res == expected ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/test_pre_pep8_deprecation_warnings.py0000644000000000000000000004237415134002420021244 0ustar00import pytest import warnings from pyparsing import Word, nums, ParserElement, original_text_for, sgl_quoted_string def test_parseString_emits_DeprecationWarning_simple(): # Using deprecated camelCase API should emit DeprecationWarning parser = Word(nums) with pytest.warns(DeprecationWarning, match="'parseString' deprecated - use 'parse_string'"): result = parser.parseString("12345") assert result.as_list() == ["12345"] def test_parse_string_parseAll_kwarg_emits_DeprecationWarning(): # Using parse_string with deprecated 'parseAll' kwarg should warn parser = Word(nums) with pytest.warns(DeprecationWarning, match="'parseAll' argument is deprecated, use 'parse_all'"): result = parser.parse_string("13579", parseAll=True) assert result.as_list() == ["13579"] def test_parse_string_does_not_warn(): # Control test: new PEP8 API should not warn parser = Word(nums) with warnings.catch_warnings(record=True) as rec: warnings.simplefilter("always") result = parser.parse_string("2468") assert result.as_list() == ["2468"] # No DeprecationWarning should be captured assert not any(issubclass(w.category, DeprecationWarning) for w in rec) def test_enablePackrat_emits_DeprecationWarning_and_cleanup(): # Record initial packrat state; restore it after test completes initially_enabled = getattr(ParserElement, "_packratEnabled", False) try: # Deprecated classmethod should warn with pytest.warns(DeprecationWarning, match="'enablePackrat' deprecated - use 'enable_packrat'"): ParserElement.enablePackrat() finally: # Only disable if it was not initially enabled if not initially_enabled: ParserElement.disable_memoization() def test_setResultsName_emits_DeprecationWarning(): parser = Word(nums) with pytest.warns(DeprecationWarning, match="'setResultsName' deprecated - use 'set_results_name'"): p2 = parser.setResultsName("value") assert p2 is not parser # setResultsName returns a new ParserElement (copy) def test_setBreak_emits_DeprecationWarning(): parser = Word(nums) with pytest.warns(DeprecationWarning, match="'setBreak' deprecated - use 'set_break'"): parser.setBreak() def test_setParseAction_emits_DeprecationWarning(): parser = Word(nums) def as_int(t): return int(t[0]) with pytest.warns(DeprecationWarning, match="'setParseAction' deprecated - use 'set_parse_action'"): parser.setParseAction(as_int) # ensure it still works assert parser.parse_string("42")[0] == 42 def test_addParseAction_emits_DeprecationWarning(): parser = Word(nums) with pytest.warns(DeprecationWarning, match="'addParseAction' deprecated - use 'add_parse_action'"): parser.addParseAction(lambda t: t) assert parser.parse_string("7")[0] == "7" def test_addCondition_emits_DeprecationWarning(): parser = Word(nums) with pytest.warns(DeprecationWarning, match="'addCondition' deprecated - use 'add_condition'"): parser.addCondition(lambda t: True) assert parser.parse_string("123")[0] == "123" def test_scanString_emits_DeprecationWarning(): parser = Word(nums) with pytest.warns(DeprecationWarning, match="'scanString' deprecated - use 'scan_string'"): results = list(parser.scanString("abc 123 def 456")) assert results and all(str(t[0][0]).isdigit() for t in results) def test_scan_string_maxMatches_kwarg_emits_DeprecationWarning(): parser = Word(nums) with pytest.warns(DeprecationWarning, match="'maxMatches' argument is deprecated, use 'max_matches'"): results = list(parser.scan_string("1 2 3 4", maxMatches=2)) assert len(results) == 2 def test_transformString_emits_DeprecationWarning(): parser = Word(nums) parser.add_parse_action(lambda t: f"{t[0][::-1]}") with pytest.warns(DeprecationWarning, match="'transformString' deprecated - use 'transform_string'"): out = parser.transformString("abc 123 def") assert out == "abc 321 def" def test_searchString_emits_DeprecationWarning(): parser = Word(nums) with pytest.warns(DeprecationWarning, match="'searchString' deprecated - use 'search_string'"): res = parser.searchString("x 99 y") assert res.as_list() == [["99"]] def test_setDebug_emits_DeprecationWarning(): parser = Word(nums) with pytest.warns(DeprecationWarning, match="'setDebug' deprecated - use 'set_debug'"): parser.setDebug() def test_setName_emits_DeprecationWarning(): parser = Word(nums) with pytest.warns(DeprecationWarning, match="'setName' deprecated - use 'set_name'"): p2 = parser.setName("digits") assert p2 is parser assert str(p2) == "digits" def test_runTests_emits_DeprecationWarning(capsys): parser = Word(nums) # Keep the test input minimal; capture stdout to avoid noisy output with pytest.warns(DeprecationWarning, match="'runTests' deprecated - use 'run_tests'"): parser.runTests(""" 123 -> ['123'] ABC """, print_results=False) # ensure no exception and some output captured captured = capsys.readouterr() assert captured.out is not None # --- helpers.py compatibility function aliases --- from pyparsing import alphas from pyparsing.helpers import ( countedArray, matchPreviousLiteral, matchPreviousExpr, oneOf, dictOf, originalTextFor, nestedExpr, makeHTMLTags, makeXMLTags, replaceHTMLEntity, infixNotation, OpAssoc, common_html_entity, ) def test_countedArray_emits_DeprecationWarning(): # countedArray should warn and still work word = Word(alphas) with pytest.warns(DeprecationWarning, match="'countedArray' deprecated - use 'counted_array'"): expr = countedArray(word) res = expr.parse_string("2 ab cd ef") assert res.as_list() == ["ab", "cd"] def test_matchPreviousLiteral_emits_DeprecationWarning(): first = Word(nums) with pytest.warns(DeprecationWarning, match="'matchPreviousLiteral' deprecated - use 'match_previous_literal'"): second = matchPreviousLiteral(first) res = (first + ":" + second).parse_string("12:12") assert res.as_list() == ["12", ":", "12"] def test_matchPreviousExpr_emits_DeprecationWarning(): first = Word(alphas) with pytest.warns(DeprecationWarning, match="'matchPreviousExpr' deprecated - use 'match_previous_expr'"): second = matchPreviousExpr(first) res = (first + ":" + second).parse_string("ab:ab") assert res.as_list() == ["ab", ":", "ab"] def test_oneOf_emits_DeprecationWarning(): with pytest.warns(DeprecationWarning, match="'oneOf' deprecated - use 'one_of'"): expr = oneOf("red blue") assert expr.parse_string("blue")[0] == "blue" def test_dictOf_emits_DeprecationWarning(): key = Word(alphas) val = Word(nums) with pytest.warns(DeprecationWarning, match="'dictOf' deprecated - use 'dict_of'"): expr = dictOf(key, val) res = expr.parse_string("a 1 b 2") # expect list of pairs assert res.as_list() == [["a", "1"], ["b", "2"]] def test_originalTextFor_emits_DeprecationWarning(): inner = Word(alphas) with pytest.warns(DeprecationWarning, match="'originalTextFor' deprecated - use 'original_text_for'"): expr = originalTextFor(inner + "," + inner) res = expr.parse_string("ab,cd") assert res[0] == "ab,cd" def test_nestedExpr_emits_DeprecationWarning(): with pytest.warns(DeprecationWarning, match="'nestedExpr' deprecated - use 'nested_expr'"): expr = nestedExpr("(", ")", content=Word(alphas)) # parses nested parenthesized expression res = expr.parse_string("(a(b)c)") assert res.as_list() == [["a", ["b"], "c"]] def test_makeHTMLTags_emits_DeprecationWarning(): with pytest.warns(DeprecationWarning, match="'makeHTMLTags' deprecated - use 'make_html_tags'"): open_tag, close_tag = makeHTMLTags("B") expr = original_text_for(open_tag + Word(alphas) + close_tag) assert expr.parse_string("hi").as_list() == ["hi"] def test_makeXMLTags_emits_DeprecationWarning(): with pytest.warns(DeprecationWarning, match="'makeXMLTags' deprecated - use 'make_xml_tags'"): open_tag, close_tag = makeXMLTags("tag") expr = original_text_for(open_tag + Word(alphas) + close_tag) assert expr.parse_string("ok").as_list() == ["ok"] def test_replaceHTMLEntity_emits_DeprecationWarning(): # use as a parse action on the common_html_entity expression with pytest.warns(DeprecationWarning, match="'replaceHTMLEntity' deprecated - use 'replace_html_entity'"): expr = common_html_entity.copy() expr.add_parse_action(replaceHTMLEntity) res = expr.parse_string("&") assert res[0] == "&" # original token # apply parse action returns replacement value; ensure parse action returned '&' # ParseResults will hold returned value as the sole token assert expr.parse_string("&")[0] == "&" def test_infixNotation_emits_DeprecationWarning(): # simple arithmetic with '+' only integer = Word(nums).set_parse_action(lambda t: int(t[0])) with pytest.warns(DeprecationWarning, match="'infixNotation' deprecated - use 'infix_notation'"): expr = infixNotation( integer, [ ('+', 2, OpAssoc.LEFT, lambda t: [sum(t[0][0::2])]) ] ) res = expr.parse_string("2+3+4", parse_all=True) # 2+3=5; 5+4=9 assert res[0] == 9 # Additional tests for deprecated arguments in helpers.py (PEP8 functions accepting camelCase kwargs) from pyparsing.helpers import ( counted_array as counted_array_pep8, one_of as one_of_pep8, nested_expr as nested_expr_pep8, ) def test_counted_array_intExpr_kwarg_emits_DeprecationWarning(): # Provide custom int expression using deprecated 'intExpr' kwarg binary_constant = Word("01").set_parse_action(lambda t: int(t[0], 2)) with pytest.warns(DeprecationWarning, match="'intExpr' argument is deprecated, use 'int_expr'"): expr = counted_array_pep8(Word("ab"), intExpr=binary_constant) # '10' (binary 2) -> parse two items res = expr.parse_string("10 ab ab ab") assert res.as_list() == ["ab", "ab"] def test_one_of_useRegex_kwarg_emits_DeprecationWarning(): with pytest.warns(DeprecationWarning, match="'useRegex' argument is deprecated, use 'use_regex'"): expr = one_of_pep8(["a", "aa"], useRegex=False) # Should still parse a and aa assert expr.parse_string("aa")[0] in {"a", "aa", "aa"} def test_one_of_asKeyword_kwarg_emits_DeprecationWarning(): with pytest.warns(DeprecationWarning, match="'asKeyword' argument is deprecated, use 'as_keyword'"): expr = one_of_pep8(["if", "in"], asKeyword=True) # Keyword behavior: word breaks required assert expr.search_string(" if ").as_list() == [["if"]] def test_original_text_for_asString_kwarg_emits_DeprecationWarning(): # Using original_text_for with deprecated 'asString' kwarg inner = Word(alphas) + "," + Word(alphas) with pytest.warns(DeprecationWarning, match="'asString' argument is deprecated, use 'as_string'"): expr = original_text_for(inner, asString=False) res = expr.parse_string("ab,cd") # Returns original matched text as sole token assert res[0] == "ab,cd" def test_nested_expr_ignoreExpr_kwarg_emits_DeprecationWarning(): # Disable default ignoring of quoted strings using deprecated 'ignoreExpr' with pytest.warns(DeprecationWarning, match="'ignoreExpr' argument is deprecated, use 'ignore_expr'"): expr = nested_expr_pep8("(", ")", content=Word(alphas), ignoreExpr=None) res = expr.parse_string("(a(b)c)") assert res.as_list() == [["a", ["b"], "c"]] # --- actions.py compatibility function aliases --- from pyparsing import quoted_string from pyparsing.actions import ( replaceWith, removeQuotes, withAttribute, withClass, matchOnlyAtCol, ) from pyparsing.helpers import make_html_tags from pyparsing.results import ParseResults def test_replaceWith_emits_DeprecationWarning(): # replaceWith should warn and still function as a parse action factory from pyparsing import Word, nums parser = Word(nums) with pytest.warns(DeprecationWarning, match="'replaceWith' deprecated - use 'replace_with'"): parser = parser.set_parse_action(replaceWith(0)) assert parser.parse_string("123").as_list() == [0] def test_removeQuotes_emits_DeprecationWarning(): # removeQuotes should warn and strip quotes from quoted_string from pyparsing import Regex qs = Regex(r"'[^']*'") with pytest.warns(DeprecationWarning, match="'removeQuotes' deprecated - use 'remove_quotes'"): parser = qs.set_parse_action(removeQuotes) res = parser.parse_string("'abc'") assert res[0] == "abc" def test_withAttribute_emits_DeprecationWarning(): # withAttribute should warn and validate attribute presence/value div, div_end = make_html_tags("div") with pytest.warns(DeprecationWarning, match="'withAttribute' deprecated - use 'with_attribute'"): start = div().set_parse_action(withAttribute(type="grid")) # Parse succeeds when attribute matches res = start.parse_string('
') assert res.type == "grid" def test_withClass_emits_DeprecationWarning(): div, _ = make_html_tags("div") with pytest.warns(DeprecationWarning, match="'withClass' deprecated - use 'with_class'"): start = div().set_parse_action(withClass("grid")) res = start.parse_string('
') assert res.tag == "div" assert res["class"] == "grid" def test_matchOnlyAtCol_emits_DeprecationWarning(): from pyparsing import Word, nums parser = Word(nums) with pytest.warns(DeprecationWarning, match="'matchOnlyAtCol' deprecated - use 'match_only_at_col'"): parser.add_parse_action(matchOnlyAtCol(3)) # number starts at column 3 (1-based): two leading spaces res = parser.parse_string(" 123") assert res[0] == "123" def test_ParseResults_asList_kwarg_emits_DeprecationWarning(): # Using deprecated 'asList' kwarg in ParseResults constructor should warn with pytest.warns(DeprecationWarning, match="'asList' argument is deprecated, use 'aslist'"): pr = ParseResults([["a", "b"]], "items", asList=True) # Ensure behavior: named entry is preserved as a nested ParseResults containing the list assert isinstance(pr["items"], ParseResults) assert pr["items"].as_list() == ["a", "b"] # --- common.py compatibility methods (deprecated camelCase) --- import pyparsing as pp from datetime import date, datetime as dt def test_common_convertToInteger_emits_DeprecationWarning(): # convertToInteger is a parse action alias; warning emitted when action runs parser = Word(nums).set_parse_action(pp.common.convertToInteger) with pytest.warns(DeprecationWarning, match="'convertToInteger' deprecated - use 'convert_to_integer'"): res = parser.parse_string("1234") assert res[0] == 1234 def test_common_convertToFloat_emits_DeprecationWarning(): parser = Word("0123456789.").set_parse_action(pp.common.convertToFloat) with pytest.warns(DeprecationWarning, match="'convertToFloat' deprecated - use 'convert_to_float'"): res = parser.parse_string("3.14") assert isinstance(res[0], float) assert abs(res[0] - 3.14) < 1e-8 def test_common_convertToDate_emits_DeprecationWarning(): # convertToDate is a factory; warning emitted when called with pytest.warns(DeprecationWarning, match="'convertToDate' deprecated - use 'convert_to_date'"): pa = pp.common.convertToDate() expr = pp.common.iso8601_date.copy().set_parse_action(pa) res = expr.parse_string("1999-12-31") assert res[0] == date(1999, 12, 31) def test_common_convertToDatetime_emits_DeprecationWarning(): with pytest.warns(DeprecationWarning, match="'convertToDatetime' deprecated - use 'convert_to_datetime'"): pa = pp.common.convertToDatetime() expr = pp.common.iso8601_datetime.copy().set_parse_action(pa) res = expr.parse_string("1999-12-31T23:59:59.999") assert res[0] == dt(1999, 12, 31, 23, 59, 59, 999000) def test_common_stripHTMLTags_emits_DeprecationWarning(): # Use stripHTMLTags as a parse action on some HTML content td, td_end = pp.helpers.make_html_tags("td") body = pp.SkipTo(td_end).set_parse_action(pp.common.stripHTMLTags)("body") expr = td + body + td_end with pytest.warns(DeprecationWarning, match="'stripHTMLTags' deprecated - use 'strip_html_tags'"): res = expr.parse_string('Click here') assert res.body == "Click here" def test_common_upcaseTokens_emits_DeprecationWarning(): parser = Word("abc").set_parse_action(pp.common.upcaseTokens) with pytest.warns(DeprecationWarning, match="'upcaseTokens' deprecated - use 'upcase_tokens'"): res = parser.parse_string("abca") assert res[0] == "ABCA" def test_common_downcaseTokens_emits_DeprecationWarning(): parser = Word("ABC").set_parse_action(pp.common.downcaseTokens) with pytest.warns(DeprecationWarning, match="'downcaseTokens' deprecated - use 'downcase_tokens'"): res = parser.parse_string("ABCA") assert res[0] == "abca" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/test_simple_unit.py0000644000000000000000000006265215134002420015566 0ustar00# # test_simple_unit.py # # While these unit tests *do* perform low-level unit testing of the classes in pyparsing, # this testing module should also serve an instructional purpose, to clearly show simple passing # and failing parse cases of some basic pyparsing expressions. # # Copyright (c) 2018 Paul T. McGuire # import unittest from collections.abc import Iterable, Mapping from datetime import datetime, timezone from typing import NamedTuple import pyparsing as pp ppt = pp.pyparsing_test TestParseResultsAsserts = ppt.TestParseResultsAsserts # Test spec data class for specifying simple pyparsing test cases class PyparsingTest(NamedTuple): desc: str = "" expr: pp.ParserElement = pp.Empty() text: str = "" parse_fn: str = "parse_string" expected_list: Iterable = None expected_dict: Mapping = None expected_fail_locn: int = None NL = "\n" class PyparsingExpressionTestCase(ppt.TestParseResultsAsserts, unittest.TestCase): """ Base pyparsing testing class to parse various pyparsing expressions against given text strings. Subclasses must define a class attribute 'tests' which is a list of PyparsingTest instances. """ tests = [] def runTest(self): if self.__class__ is PyparsingExpressionTestCase: return for test_spec in self.tests: # for each spec in the class's tests list, create a subtest # that will either: # - parse the string with expected success, display the # results, and validate the returned ParseResults # - or parse the string with expected failure, display the # error message and mark the error location, and validate # the location against an expected value with self.subTest(test_spec=test_spec): test_spec.expr.streamline() print( f"{NL}{test_spec.desc} - {type(test_spec.expr).__name__}({test_spec.expr})" ) parse_function = getattr(test_spec.expr, test_spec.parse_fn) if test_spec.expected_fail_locn is None: # expect success subtest_result = parse_function(test_spec.text) if test_spec.parse_fn == "parse_string": print(subtest_result.dump()) # compare results against given list and/or dict self.assertParseResultsEquals( subtest_result, expected_list=test_spec.expected_list, expected_dict=test_spec.expected_dict, ) elif test_spec.parse_fn == "transform_string": print(subtest_result) # compare results against given list and/or dict if test_spec.expected_list is not None: self.assertEqual([subtest_result], test_spec.expected_list) elif test_spec.parse_fn == "search_string": print(subtest_result) # compare results against given list and/or dict if test_spec.expected_list is not None: self.assertEqual([subtest_result], test_spec.expected_list) else: # expect fail with self.assertRaisesParseException(): try: parse_function(test_spec.text) except pp.ParseBaseException as exc: print(pp.ParseException.explain(exc)) self.assertEqual(exc.loc, test_spec.expected_fail_locn) raise # =========== TEST DEFINITIONS START HERE ============== class TestLiteral(PyparsingExpressionTestCase): tests = [ PyparsingTest( desc="Simple match", expr=pp.Literal("xyz"), text="xyz", expected_list=["xyz"], ), PyparsingTest( desc="Simple match after skipping whitespace", expr=pp.Literal("xyz"), text=" xyz", expected_list=["xyz"], ), PyparsingTest( desc="Simple fail - parse an empty string", expr=pp.Literal("xyz"), text="", expected_fail_locn=0, ), PyparsingTest( desc="Simple fail - parse a mismatching string", expr=pp.Literal("xyz"), text="xyu", expected_fail_locn=0, ), PyparsingTest( desc="Simple fail - parse a partially matching string", expr=pp.Literal("xyz"), text="xy", expected_fail_locn=0, ), PyparsingTest( desc="Fail - parse a partially matching string by matching individual letters", expr=pp.Literal("x") + pp.Literal("y") + pp.Literal("z"), text="xy", expected_fail_locn=2, ), ] class TestCaselessLiteral(PyparsingExpressionTestCase): tests = [ PyparsingTest( desc="Match colors, converting to consistent case", expr=( pp.CaselessLiteral("RED") | pp.CaselessLiteral("GREEN") | pp.CaselessLiteral("BLUE") )[...], text="red Green BluE blue GREEN green rEd", expected_list=["RED", "GREEN", "BLUE", "BLUE", "GREEN", "GREEN", "RED"], ), ] class TestWord(PyparsingExpressionTestCase): tests = [ PyparsingTest( desc="Simple Word match", expr=pp.Word("xy"), text="xxyxxyy", expected_list=["xxyxxyy"], ), PyparsingTest( desc="Simple Word match of two separate Words", expr=pp.Word("x") + pp.Word("y"), text="xxxxxyy", expected_list=["xxxxx", "yy"], ), PyparsingTest( desc="Simple Word match of two separate Words - implicitly skips whitespace", expr=pp.Word("x") + pp.Word("y"), text="xxxxx yy", expected_list=["xxxxx", "yy"], ), ] class TestCombine(PyparsingExpressionTestCase): tests = [ PyparsingTest( desc="Parsing real numbers - fail, parsed numbers are in pieces", expr=(pp.Word(pp.nums) + "." + pp.Word(pp.nums))[...], text="1.2 2.3 3.1416 98.6", # fmt: off expected_list=["1", ".", "2", "2", ".", "3", "3", ".", "1416", "98", ".", "6"], # fmt: on ), PyparsingTest( desc="Parsing real numbers - better, use Combine to combine multiple tokens into one", expr=pp.Combine(pp.Word(pp.nums) + "." + pp.Word(pp.nums))[...], text="1.2 2.3 3.1416 98.6", expected_list=["1.2", "2.3", "3.1416", "98.6"], ), ] class TestRepetition(PyparsingExpressionTestCase): tests = [ PyparsingTest( desc="Match several words", expr=(pp.Word("x") | pp.Word("y"))[...], text="xxyxxyyxxyxyxxxy", expected_list=["xx", "y", "xx", "yy", "xx", "y", "x", "y", "xxx", "y"], ), PyparsingTest( desc="Match several words, skipping whitespace", expr=(pp.Word("x") | pp.Word("y"))[...], text="x x y xxy yxx y xyx xxy", # fmt: off expected_list=["x", "x", "y", "xx", "y", "y", "xx", "y", "x", "y", "x", "xx", "y"], # fmt: on ), PyparsingTest( desc="Match several words, skipping whitespace (old style)", expr=pp.OneOrMore(pp.Word("x") | pp.Word("y")), text="x x y xxy yxx y xyx xxy", # fmt: off expected_list=["x", "x", "y", "xx", "y", "y", "xx", "y", "x", "y", "x", "xx", "y"], # fmt: on ), PyparsingTest( desc="Match words and numbers - show use of results names to collect types of tokens", expr=(pp.Word(pp.alphas)("alpha*") | pp.pyparsing_common.integer("int*"))[ ... ], text="sdlfj23084ksdfs08234kjsdlfkjd0934", expected_list=["sdlfj", 23084, "ksdfs", 8234, "kjsdlfkjd", 934], expected_dict={ "alpha": ["sdlfj", "ksdfs", "kjsdlfkjd"], "int": [23084, 8234, 934], }, ), PyparsingTest( desc="Using DelimitedList (comma is the default delimiter)", expr=pp.DelimitedList(pp.Word(pp.alphas)), text="xxyx,xy,y,xxyx,yxx, xy", expected_list=["xxyx", "xy", "y", "xxyx", "yxx", "xy"], ), PyparsingTest( desc="Using DelimitedList (comma is the default delimiter) with trailing delimiter", expr=pp.DelimitedList(pp.Word(pp.alphas), allow_trailing_delim=True), text="xxyx,xy,y,xxyx,yxx, xy,", expected_list=["xxyx", "xy", "y", "xxyx", "yxx", "xy"], ), PyparsingTest( desc="Using DelimitedList (comma is the default delimiter) with minimum size", expr=pp.DelimitedList(pp.Word(pp.alphas), min=3), text="xxyx,xy", expected_fail_locn=7, ), PyparsingTest( desc="Using DelimitedList (comma is the default delimiter) with maximum size", expr=pp.DelimitedList(pp.Word(pp.alphas), max=3), text="xxyx,xy,y,xxyx,yxx, xy,", expected_list=["xxyx", "xy", "y"], ), PyparsingTest( desc="Using DelimitedList, with ':' delimiter", expr=pp.DelimitedList( pp.Word(pp.hexnums, exact=2), delim=":", combine=True ), text="0A:4B:73:21:FE:76", expected_list=["0A:4B:73:21:FE:76"], ), PyparsingTest( desc="Using DelimitedList, with ':' delimiter", expr=pp.DelimitedList( pp.Word(pp.hexnums, exact=2), delim=":", combine=True, allow_trailing_delim=True, ), text="0A:4B:73:21:FE:76:", expected_list=["0A:4B:73:21:FE:76:"], ), ] class TestResultsName(PyparsingExpressionTestCase): tests = [ PyparsingTest( desc="Match with results name", expr=pp.Literal("xyz").set_results_name("value"), text="xyz", expected_dict={"value": "xyz"}, expected_list=["xyz"], ), PyparsingTest( desc="Match with results name - using naming short-cut", expr=pp.Literal("xyz")("value"), text="xyz", expected_dict={"value": "xyz"}, expected_list=["xyz"], ), PyparsingTest( desc="Define multiple results names", expr=pp.Word(pp.alphas, pp.alphanums)("key") + "=" + pp.pyparsing_common.integer("value"), text="range=5280", expected_dict={"key": "range", "value": 5280}, expected_list=["range", "=", 5280], ), ] class TestGroups(PyparsingExpressionTestCase): EQ = pp.Suppress("=") tests = [ PyparsingTest( desc="Define multiple results names in groups", expr=pp.Group( pp.Word(pp.alphas)("key") + EQ + pp.pyparsing_common.number("value") )[...], text="range=5280 long=-138.52 lat=46.91", expected_list=[["range", 5280], ["long", -138.52], ["lat", 46.91]], ), PyparsingTest( desc=( "Define multiple results names in groups" " - use Dict to define results names using parsed keys" ), expr=pp.Dict( pp.Group(pp.Word(pp.alphas) + EQ + pp.pyparsing_common.number)[...] ), text="range=5280 long=-138.52 lat=46.91", expected_list=[["range", 5280], ["long", -138.52], ["lat", 46.91]], expected_dict={"lat": 46.91, "long": -138.52, "range": 5280}, ), PyparsingTest( desc="Define multiple value types", expr=pp.Dict( pp.Group( pp.Word(pp.alphas) + EQ + ( pp.pyparsing_common.number | pp.one_of("True False") | pp.QuotedString("'") ) )[...] ), text="long=-122.47 lat=37.82 public=True name='Golden Gate Bridge'", expected_list=[ ["long", -122.47], ["lat", 37.82], ["public", "True"], ["name", "Golden Gate Bridge"], ], expected_dict={ "long": -122.47, "lat": 37.82, "public": "True", "name": "Golden Gate Bridge", }, ), ] class TestParseAction(PyparsingExpressionTestCase): tests = [ PyparsingTest( desc="Parsing real numbers - use parse action to convert to float at parse time", expr=pp.Combine(pp.Word(pp.nums) + "." + pp.Word(pp.nums)).add_parse_action( lambda t: float(t[0]) )[...], text="1.2 2.3 3.1416 98.6", # note, these are now floats, not strs expected_list=[1.2, 2.3, 3.1416, 98.6], ), PyparsingTest( desc="Match with numeric string converted to int", expr=pp.Word("0123456789").add_parse_action(lambda t: int(t[0])), text="12345", expected_list=[12345], # note - result is type int, not str ), PyparsingTest( desc="Use two parse actions to convert numeric string, then convert to datetime", expr=pp.Word(pp.nums).add_parse_action( lambda t: int(t[0]), lambda t: datetime.fromtimestamp(t[0], timezone.utc), ), text="1537415628", expected_list=[datetime(2018, 9, 20, 3, 53, 48, tzinfo=timezone.utc)], ), PyparsingTest( desc="Use token_map for parse actions that operate on a single-length token", expr=pp.Word(pp.nums).add_parse_action( pp.token_map(int), pp.token_map(lambda t: datetime.fromtimestamp(t, timezone.utc)), ), text="1537415628", expected_list=[datetime(2018, 9, 20, 3, 53, 48, tzinfo=timezone.utc)], ), PyparsingTest( desc="Using a built-in function that takes a sequence of strs as a parse action", expr=pp.Word(pp.hexnums, exact=2)[...].add_parse_action(":".join), text="0A4B7321FE76", expected_list=["0A:4B:73:21:FE:76"], ), PyparsingTest( desc="Using a built-in function that takes a sequence of strs as a parse action", expr=pp.Word(pp.hexnums, exact=2)[...].add_parse_action(sorted), text="0A4B7321FE76", expected_list=["0A", "21", "4B", "73", "76", "FE"], ), ] class TestResultsModifyingParseAction(PyparsingExpressionTestCase): # do not make staticmethod # @staticmethod def compute_stats_parse_action(t): # by the time this parse action is called, parsed numeric words # have been converted to ints by a previous parse action, so # they can be treated as ints t["sum"] = sum(t) t["ave"] = sum(t) / len(t) t["min"] = min(t) t["max"] = max(t) tests = [ PyparsingTest( desc="A parse action that adds new key-values", expr=pp.pyparsing_common.integer[...].add_parse_action( compute_stats_parse_action ), text="27 1 14 22 89", expected_list=[27, 1, 14, 22, 89], expected_dict={"ave": 30.6, "max": 89, "min": 1, "sum": 153}, ), ] class TestRegex(PyparsingExpressionTestCase): tests = [ PyparsingTest( desc="Parsing real numbers - using Regex instead of Combine", expr=pp.Regex(r"\d+\.\d+").add_parse_action(lambda t: float(t[0]))[...], text="1.2 2.3 3.1416 98.6", # note, these are now floats, not strs expected_list=[1.2, 2.3, 3.1416, 98.6], ), ] class TestParseCondition(PyparsingExpressionTestCase): tests = [ PyparsingTest( desc="Define a condition to only match numeric values that are multiples of 7", expr=pp.Word(pp.nums).add_condition(lambda t: int(t[0]) % 7 == 0)[...], text="14 35 77 12 28", expected_list=["14", "35", "77"], ), PyparsingTest( desc="Separate conversion to int and condition into separate parse action/conditions", expr=pp.Word(pp.nums) .add_parse_action(lambda t: int(t[0])) .add_condition(lambda t: t[0] % 7 == 0)[...], text="14 35 77 12 28", expected_list=[14, 35, 77], ), ] class TestTransformStringUsingParseActions(PyparsingExpressionTestCase): markup_convert_map = { "*": "B", "_": "U", "/": "I", } # do not make staticmethod # @staticmethod def markup_convert(t): htmltag = TestTransformStringUsingParseActions.markup_convert_map[ t.markup_symbol ] return f"<{htmltag}>{t.body}" tests = [ PyparsingTest( desc="Use transform_string to convert simple markup to HTML", expr=( pp.one_of(markup_convert_map)("markup_symbol") + "(" + pp.CharsNotIn(")")("body") + ")" ).add_parse_action(markup_convert), text="Show in *(bold), _(underscore), or /(italic) type", expected_list=[ "Show in bold, underscore, or italic type" ], parse_fn="transform_string", ), ] class TestCommonHelperExpressions(PyparsingExpressionTestCase): tests = [ PyparsingTest( desc="A comma-delimited list of words", expr=pp.DelimitedList(pp.Word(pp.alphas)), text="this, that, blah,foo, bar", expected_list=["this", "that", "blah", "foo", "bar"], ), PyparsingTest( desc="A counted array of words", expr=pp.Group(pp.counted_array(pp.Word("ab")))[...], text="2 aaa bbb 0 3 abab bbaa abbab", expected_list=[["aaa", "bbb"], [], ["abab", "bbaa", "abbab"]], ), PyparsingTest( desc="skipping comments with ignore", expr=( pp.pyparsing_common.identifier("lhs") + "=" + pp.pyparsing_common.fnumber("rhs") ).ignore(pp.cpp_style_comment), text="abc_100 = /* value to be tested */ 3.1416", expected_list=["abc_100", "=", 3.1416], expected_dict={"lhs": "abc_100", "rhs": 3.1416}, ), PyparsingTest( desc=( "some pre-defined expressions in pyparsing_common, and" " building a dotted identifier with DelimitedList" ), expr=( pp.pyparsing_common.number("id_num") + pp.DelimitedList(pp.pyparsing_common.identifier, ".", combine=True)( "name" ) + pp.pyparsing_common.ipv4_address("ip_address") ), text="1001 www.google.com 192.168.10.199", expected_list=[1001, "www.google.com", "192.168.10.199"], expected_dict={ "id_num": 1001, "name": "www.google.com", "ip_address": "192.168.10.199", }, ), PyparsingTest( desc="using one_of (shortcut for Literal('a') | Literal('b') | Literal('c'))", expr=pp.one_of("a b c")[...], text="a b a b b a c c a b b", expected_list=["a", "b", "a", "b", "b", "a", "c", "c", "a", "b", "b"], ), PyparsingTest( desc="parsing nested parentheses", expr=pp.nested_expr(), text="(a b (c) d (e f g ()))", expected_list=[["a", "b", ["c"], "d", ["e", "f", "g", []]]], ), PyparsingTest( desc="parsing nested braces", expr=( pp.Keyword("if") + pp.nested_expr()("condition") + pp.nested_expr("{", "}")("body") ), text='if ((x == y) || !z) {printf("{}");}', expected_list=[ "if", [["x", "==", "y"], "||", "!z"], ["printf(", '"{}"', ");"], ], expected_dict={ "condition": [[["x", "==", "y"], "||", "!z"]], "body": [["printf(", '"{}"', ");"]], }, ), ] class TestWhitespaceMethods(PyparsingExpressionTestCase): tests = [ # These test the single-element versions PyparsingTest( desc="The word foo", expr=pp.Literal("foo").ignore_whitespace(), text=" foo ", expected_list=["foo"], ), PyparsingTest( desc="The word foo", expr=pp.Literal("foo").leave_whitespace(), text=" foo ", expected_fail_locn=0, ), PyparsingTest( desc="The word foo", expr=pp.Literal("foo").ignore_whitespace(), text="foo", expected_list=["foo"], ), PyparsingTest( desc="The word foo", expr=pp.Literal("foo").leave_whitespace(), text="foo", expected_list=["foo"], ), # These test the composite elements PyparsingTest( desc=( "If we recursively leave whitespace on the parent, this" " whitespace-dependent grammar will succeed, even if the" " children themselves skip whitespace" ), expr=pp.And( [ pp.Literal(" foo").ignore_whitespace(), pp.Literal(" bar").ignore_whitespace(), ] ).leave_whitespace(recursive=True), text=" foo bar", expected_list=[" foo", " bar"], ), # PyparsingTest( desc=( "If we recursively ignore whitespace in our parsing, this" " whitespace-dependent grammar will fail, even if the children" " themselves keep whitespace" ), expr=pp.And( [ pp.Literal(" foo").leave_whitespace(), pp.Literal(" bar").leave_whitespace(), ] ).ignore_whitespace(recursive=True), text=" foo bar", expected_fail_locn=1, ), PyparsingTest( desc=( "If we leave whitespace on the parent, but it isn't recursive," " this whitespace-dependent grammar will fail" ), expr=pp.And( [ pp.Literal(" foo").ignore_whitespace(), pp.Literal(" bar").ignore_whitespace(), ] ).leave_whitespace(recursive=False), text=" foo bar", expected_fail_locn=5, ), # These test the Enhance classes PyparsingTest( desc=( "If we recursively leave whitespace on the parent," " this whitespace-dependent grammar will succeed, even" " if the children themselves skip whitespace" ), expr=pp.Optional(pp.Literal(" foo").ignore_whitespace()).leave_whitespace( recursive=True ), text=" foo", expected_list=[" foo"], ), # PyparsingTest( desc=( "If we ignore whitespace on the parent, but it isn't recursive," " parsing will fail because we skip to the first character" " 'f' before the internal expr can see it" ), expr=pp.Optional(pp.Literal(" foo").leave_whitespace()).ignore_whitespace( recursive=True ), text=" foo", expected_list=[], ), # PyparsingTest( # desc=( # "If we leave whitespace on the parent, this whitespace-dependent" # " grammar will succeed, even if the children themselves skip whitespace" # ), # expr=pp.Optional(pp.Literal(" foo").ignore_whitespace()).leave_whitespace( # recursive=False # ), # text=" foo", # expected_list=[] # ), ] def _get_decl_line_no(cls): import inspect return inspect.getsourcelines(cls)[1] # get all test case classes defined in this module and sort them by decl line no test_case_classes = list(PyparsingExpressionTestCase.__subclasses__()) test_case_classes.sort(key=_get_decl_line_no) # make into a suite and run it - this will run the tests in the same order # they are declared in this module # # runnable from setup.py using "python setup.py test -s simple_unit_tests.suite" # suite = unittest.TestSuite(cls() for cls in test_case_classes) # ============ MAIN ================ if __name__ == "__main__": result = unittest.TextTestRunner().run(suite) exit(0 if result.wasSuccessful() else 1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/test_testing.py0000644000000000000000000000556015134002420014706 0ustar00import textwrap import pytest import pyparsing as pp ppt = pp.testing TAB = chr(9) @pytest.mark.parametrize( "source, options, expected", [ # simple call to with_line_numbers ("abcd", {}, textwrap.dedent( """\ 1 1234567890 1:abcd| """), ), # simple call to with_line_numbers with empty string ("", {}, ""), # simple call to with_line_numbers with single blank line ("\n", {}, ' \n \n1:|\n'), # simple call to with_line_numbers with line longer than 99 chars ("abcdefghij" * 11, {}, textwrap.dedent( """\ 1 1 2 3 4 5 6 7 8 9 0 1 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 1:abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij| """), ), # add indent = "...." ("abcd", {"indent": "...."}, textwrap.dedent( """\ .... 1 .... 1234567890 ....1:abcd| """), ), # show control characters as ? ("ab\tc\ad", {"mark_control": "?"}, textwrap.dedent( f"""\ 1 2 12345678901234567890 1:ab c?d| """) ), # show control characters as ? ("ab\tc\ad", {"mark_control": "?", "expand_tabs": False}, textwrap.dedent( f"""\ 1 1234567890 1:ab?c?d| """) ), # show control characters as unicode ("ab\tc\ad", {"mark_control": "unicode"}, textwrap.dedent( f"""\ 1 2 12345678901234567890 1:ab␠␠␠␠␠␠c␇d␊ """) ), # show space characters as "`" ("ab\tc d", {"mark_spaces": "`", "expand_tabs": False}, textwrap.dedent( f"""\ 1 1234567890 1:ab\tc``d| """) ), # show space characters as unicode ("ab\tc\ad", {"mark_spaces": "unicode", "expand_tabs": False}, textwrap.dedent( f"""\ 1 1234567890 1:ab␉c\ad| """) ), ] ) def test_with_line_numbers(source: str, options: dict, expected: str): observed = ppt.with_line_numbers(source, **options) print() print(observed) assert observed == expected ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1768949007.7248077 pyparsing-3.3.2/tests/test_unit.py0000644000000000000000000143670115134002420014216 0ustar00# # test_unit.py # # Unit tests for pyparsing module # # Copyright 2002-2021, Paul McGuire # # import collections import contextlib import datetime import random import re import shlex import sys import sysconfig import warnings from types import SimpleNamespace from io import StringIO from textwrap import dedent from typing import Any import unittest from unittest.mock import patch, mock_open import subprocess import pyparsing as pp from examples.jsonParser import jsonObject from pyparsing import ( ParserElement, ParseException, ParseFatalException, PyparsingDeprecationWarning, ) from tests.json_parser_tests import test1, test2, test3, test4, test5 import platform python_full_version = sys.version_info python_version = python_full_version[:2] ppc = pp.pyparsing_common ppt = pp.pyparsing_test # see which Python implementation we are running python_impl = platform.python_implementation() CPYTHON_ENV = python_impl == "CPython" IRON_PYTHON_ENV = python_impl == "IronPython" JYTHON_ENV = python_impl == "Jython" PYPY_ENV = python_impl == "PyPy" # global flags for Python config settings _config_vars = sysconfig.get_config_vars() _config_args = set(shlex.split(_config_vars.get("CONFIG_ARGS", ""))) PYTHON_JIT_ENABLED = "--enable-experimental-jit" in _config_args PYTHON_FREE_THREADED = _config_vars.get("Py_GIL_DISABLED", 0) == 1 # get full stack traces during testing pp.ParserElement.verbose_stacktrace = True # simple utility for flattening nested lists def flatten(nested_list): if not isinstance(nested_list, list): return [nested_list] if not nested_list: return nested_list return flatten(nested_list[0]) + flatten(nested_list[1:]) class resetting: def __init__(self, ob, attrname: str, *attrnames): self.ob = ob self.unset_attr = object() self.save_attrs = [attrname, *attrnames] self.save_values = [ getattr(ob, name, self.unset_attr) for name in self.save_attrs ] def __enter__(self): pass def __exit__(self, *args): for attr, value in zip(self.save_attrs, self.save_values): if value is not self.unset_attr: setattr(self.ob, attr, value) else: delattr(self.ob, attr) def find_all_re_matches(patt, s): ret = [] start = 0 if isinstance(patt, str): patt = re.compile(patt) while True: found = patt.search(s, pos=start) if found: ret.append(found) start = found.end() else: break return ret def current_method_name(level=2): import traceback stack = traceback.extract_stack(limit=level) return stack[0].name def __(): return f"{current_method_name(3)}: " class TestCase(unittest.TestCase): @contextlib.contextmanager def assertRaises(self, expected_exception_type: Any, msg: Any = None): """ Simple wrapper to print out the exceptions raised after assertRaises """ with super().assertRaises(expected_exception_type, msg=msg) as ar: yield if getattr(ar, "exception", None) is not None: print( f"Raised expected exception: {type(ar.exception).__name__}: {ar.exception}" ) else: print(f"Expected {expected_exception_type.__name__} exception not raised") return ar @contextlib.contextmanager def assertWarns(self, expected_warning_type: Any, msg: Any = None): """ Simple wrapper to print out the warnings raised after assertWarns """ with super().assertWarns(expected_warning_type, msg=msg) as ar: yield if getattr(ar, "warning", None) is not None: print(f"Raised expected warning: {type(ar.warning).__name__}: {ar.warning}") else: print(f"Expected {expected_warning_type.__name__} warning not raised") return ar @contextlib.contextmanager def assertDoesNotWarn(self, warning_type: type = UserWarning, msg: str = None): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("error") try: yield except Exception as e: if msg is None: msg = f"unexpected warning {e} raised" if isinstance(e, warning_type): self.fail(f"{msg}: {e}") else: raise finally: warnings.simplefilter("default") class Test01_PyparsingTestInit(TestCase): def runTest(self): print( "Beginning test of pyparsing, version", pp.__version__, pp.__version_time__, ) config_options = [] if PYTHON_JIT_ENABLED: config_options.append("JIT enabled") if PYTHON_FREE_THREADED: config_options.append("free_threaded") config_options_str = f" ({','.join(config_options)})" print( f"Python version {sys.version}" f"{config_options_str if config_options else ''}" ) print(f"__version_info__ : {pp.__version_info__}") print(f"__version_info__ repr: {repr(pp.__version_info__)}") class Test01a_PyparsingEnvironmentTests(TestCase): def runTest(self): # test warnings enable detection # fmt: off tests = [ (([], "",), False), ((["d", ], "",), True), ((["d", "i:::pyparsing", ], "",), False), ((["d:::pyparsing", ], "",), True), ((["d:::pyparsing", "i", ], "",), False), ((["d:::blah", ], "",), False), ((["i", ], "",), False), (([], "1",), True), ((["d", ], "1",), True), ((["d", "i:::pyparsing", ], "1",), False), ((["d:::pyparsing", ], "1",), True), ((["d:::pyparsing", "i", ], "1",), False), ((["d:::blah", ], "1",), True), ((["i", ], "1",), False), ] # fmt: on all_success = True for args, expected in tests: message = f"{args} should be {expected}" print(message, end=" -> ") actual = pp.core._should_enable_warnings(*args) print("PASS" if actual == expected else "FAIL") if actual != expected: all_success = False self.assertTrue(all_success, "failed warnings enable test") class Test01b_PyparsingUnitTestUtilitiesTests(TestCase): def runTest(self): with ppt.reset_pyparsing_context(): pp.enable_diag(pp.Diagnostics.warn_on_parse_using_empty_Forward) # test assertDoesNotWarn raises an AssertionError with self.assertRaises(AssertionError): with self.assertDoesNotWarn( msg="warned when parsing with an empty Forward expression warning was suppressed", ): base = pp.Forward() try: print(base.parse_string("x")) except ParseException as pe: pass class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase): suite_context = None save_suite_context = None def setUp(self): self.suite_context.restore() def test000_assert_packrat_status(self): print("Packrat enabled:", ParserElement._packratEnabled) self.assertFalse(ParserElement._packratEnabled, "packrat enabled") def testScanStringWithOverlap(self): parser = pp.Word(pp.alphas, exact=3) without_overlaps = sum( t for t, s, e in parser.scan_string("ABCDEFGHI") ).as_list() self.assertEqual( ["ABC", "DEF", "GHI"], without_overlaps, msg="scan_string without overlaps failed", ) with_overlaps = sum( t for t, s, e in parser.scan_string("ABCDEFGHI", overlap=True) ).as_list() self.assertEqual( ["ABC", "BCD", "CDE", "DEF", "EFG", "FGH", "GHI"], with_overlaps, msg="scan_string with overlaps failed", ) def testCombineWithResultsNames(self): # test case reproducing Issue #350 from pyparsing import White, alphas, Word parser = White(" \t").set_results_name("indent") + Word( alphas ).set_results_name("word") result = parser.parse_string(" test") print(result.dump()) self.assertParseResultsEquals( result, [" ", "test"], {"indent": " ", "word": "test"} ) parser = White(" \t") + Word(alphas).set_results_name("word") result = parser.parse_string(" test") print(result.dump()) self.assertParseResultsEquals(result, [" ", "test"], {"word": "test"}) def testTransformString(self): make_int_with_commas = ppc.integer().add_parse_action(lambda t: f"{t[0]:,}") lower_case_words = pp.Word(pp.alphas.lower(), as_keyword=True) + pp.Optional( pp.White() ) nested_list = pp.nested_expr().add_parse_action(pp.ParseResults.as_list) transformer = make_int_with_commas | nested_list | lower_case_words.suppress() in_string = ( "I wish to buy 12345 shares of Acme Industries (as a gift to my (ex)wife)" ) print(in_string) out_string = transformer.transform_string(in_string) print(out_string) self.assertEqual( "I 12,345 Acme Industries asagifttomyexwife", out_string, msg="failure in transform_string", ) def testTransformStringWithLeadingWhitespace(self): sample = "\n\ncheck" sample = " check" keywords = pp.one_of("aaa bbb", as_keyword=True) ident = ~keywords + pp.Word(pp.alphas) ident = pp.Combine(~keywords + pp.Word(pp.alphas)) # ident.add_parse_action(lambda t: t[0].upper()) ident.add_parse_action(ppc.upcase_tokens) transformed = ident.transform_string(sample) print(ppt.with_line_numbers(sample)) print(ppt.with_line_numbers(transformed)) self.assertEqual(sample.replace("check", "CHECK"), transformed) def testTransformStringWithLeadingNotAny(self): sample = "print a100" keywords = set("print read".split()) ident = pp.Word(pp.alphas, pp.alphanums).add_condition( lambda t: t[0] not in keywords ) print(ident.search_string(sample)) def testTransformStringWithExpectedLeadingWhitespace(self): sample1 = "\n\ncheck aaa" sample2 = " check aaa" keywords = pp.one_of("aaa bbb", as_keyword=True) # This construct only works with parse_string, not with scan_string or its siblings # ident = ~keywords + pp.Word(pp.alphas) ident = pp.Word(pp.alphas) ident.add_parse_action(ppc.upcase_tokens) for sample in sample1, sample2: transformed = (keywords | ident).transform_string(sample) print(ppt.with_line_numbers(sample)) print(ppt.with_line_numbers(transformed)) self.assertEqual(sample.replace("check", "CHECK"), transformed) print() def testTransformStringWithLeadingWhitespaceFromTranslateProject(self): from pyparsing import Keyword, Word, alphas, alphanums, Combine block_start = (Keyword("{") | Keyword("BEGIN")).set_name("block_start") block_end = (Keyword("}") | Keyword("END")).set_name("block_end") reserved_words = block_start | block_end # this is the first critical part of this test, an And with a leading NotAny # This construct only works with parse_string, not with scan_string or its siblings # name_id = ~reserved_words + Word(alphas, alphanums + "_").set_name("name_id") name_id = Word(alphas, alphanums + "_").set_name("name_id") dialog = name_id("block_id") + (Keyword("DIALOGEX") | Keyword("DIALOG"))( "block_type" ) string_table = Keyword("STRINGTABLE")("block_type") test_string = ( """\r\nSTRINGTABLE\r\nBEGIN\r\n// Comment\r\nIDS_1 "Copied"\r\nEND\r\n""" ) print("Original:") print(repr(test_string)) print("Should match:") # this is the second critical part of this test, an Or or MatchFirst including dialog for parser in (dialog ^ string_table, dialog | string_table): result = (reserved_words | parser).transform_string(test_string) print(repr(result)) self.assertEqual( test_string, result, "Failed whitespace skipping with NotAny and MatchFirst/Or", ) def testCuneiformTransformString(self): class Cuneiform(pp.unicode_set): """Unicode set for Cuneiform Character Range""" _ranges: list[tuple[int, ...]] = [ (0x10380, 0x103D5), (0x12000, 0x123FF), (0x12400, 0x1247F), ] # define a MINIMAL Python parser LPAR, RPAR, COLON, EQ = map(pp.Suppress, "():=") def_ = pp.Keyword("𒁴𒈫", ident_chars=Cuneiform.identbodychars).set_name("def") any_keyword = def_ ident = (~any_keyword) + pp.Word( Cuneiform.identchars, Cuneiform.identbodychars, as_keyword=True ) str_expr = pp.infix_notation( pp.QuotedString('"') | pp.common.integer, [ ("*", 2, pp.OpAssoc.LEFT), ("+", 2, pp.OpAssoc.LEFT), ], ) rvalue = pp.Forward() fn_call = (ident + pp.Group(LPAR + pp.Optional(rvalue) + RPAR)).set_name( "fn_call" ) rvalue <<= fn_call | ident | str_expr | pp.common.number assignment_stmt = ident + EQ + rvalue stmt = pp.Group(fn_call | assignment_stmt).set_name("stmt") fn_def = pp.Group( def_ + ident + pp.Group(LPAR + pp.Optional(rvalue) + RPAR) + COLON ).set_name("fn_def") fn_body = pp.IndentedBlock(stmt).set_name("fn_body") fn_expr = pp.Group(fn_def + pp.Group(fn_body)) script = fn_expr[...] + stmt[...] # parse some Python written in Cuneiform cuneiform_hello_world = dedent( r""" 𒁴𒈫 𒀄𒂖𒆷𒁎(): 𒀁 = "𒀄𒂖𒆷𒁎, 𒍟𒁎𒉿𒆷𒀳!\n" * 3 𒄑𒉿𒅔𒋫(𒀁) 𒀄𒂖𒆷𒁎() """ ) # use transform_string to convert keywords and builtins to runnable Python names_map = { "𒄑𒉿𒅔𒋫": "print", } ident.add_parse_action(lambda t: names_map.get(t[0], t[0])) def_.add_parse_action(lambda: "def") print("\nconvert Cuneiform Python to executable Python") transformed = ( # always put ident last (def_ | ident) .ignore(pp.quoted_string) .transform_string(cuneiform_hello_world) ) expected = dedent( r""" def 𒀄𒂖𒆷𒁎(): 𒀁 = "𒀄𒂖𒆷𒁎, 𒍟𒁎𒉿𒆷𒀳!\n" * 3 print(𒀁) 𒀄𒂖𒆷𒁎() """ ) print( "=================\n" + cuneiform_hello_world # .strip() + "\n=================\n" + transformed + "\n=================\n" ) self.assertEqual(expected, transformed) def testUpdateDefaultWhitespace(self): prev_default_whitespace_chars = pp.ParserElement.DEFAULT_WHITE_CHARS try: pp.dbl_quoted_string.copyDefaultWhiteChars = False pp.ParserElement.set_default_whitespace_chars(" \t") self.assertEqual( set(" \t"), set(pp.sgl_quoted_string.whiteChars), "set_default_whitespace_chars did not update sgl_quoted_string", ) self.assertEqual( set(prev_default_whitespace_chars), set(pp.dbl_quoted_string.whiteChars), "set_default_whitespace_chars updated dbl_quoted_string but should not", ) finally: pp.dbl_quoted_string.copyDefaultWhiteChars = True pp.ParserElement.set_default_whitespace_chars(prev_default_whitespace_chars) self.assertEqual( set(prev_default_whitespace_chars), set(pp.dbl_quoted_string.whiteChars), "set_default_whitespace_chars updated dbl_quoted_string", ) with ppt.reset_pyparsing_context(): pp.ParserElement.set_default_whitespace_chars(" \t") self.assertNotEqual( set(prev_default_whitespace_chars), set(pp.dbl_quoted_string.whiteChars), "set_default_whitespace_chars updated dbl_quoted_string but should not", ) EOL = pp.LineEnd().suppress().set_name("EOL") # Identifiers is a string + optional $ identifier = pp.Combine(pp.Word(pp.alphas) + pp.Optional("$")) # Literals (number or double quoted string) literal = ppc.number | pp.dbl_quoted_string expression = literal | identifier # expression.set_name("expression").set_debug() # ppc.number.set_debug() # ppc.integer.set_debug() line_number = ppc.integer # Keywords PRINT = pp.CaselessKeyword("print") print_stmt = PRINT - pp.ZeroOrMore(expression | ";") statement = print_stmt code_line = pp.Group(line_number + statement + EOL) program = pp.ZeroOrMore(code_line) test = """\ 10 print 123; 20 print 234; 567; 30 print 890 """ parsed_program = program.parse_string(test, parse_all=True) print(parsed_program.dump()) self.assertEqual( 3, len(parsed_program), "failed to apply new whitespace chars to existing builtins", ) def testUpdateDefaultWhitespace2(self): with ppt.reset_pyparsing_context(): expr_tests = [ (pp.dbl_quoted_string, '"abc"'), (pp.sgl_quoted_string, "'def'"), (ppc.integer, "123"), (ppc.number, "4.56"), (ppc.identifier, "a_bc"), ] NL = pp.LineEnd() for expr, test_str in expr_tests: parser = pp.Group(expr[1, ...] + pp.Optional(NL))[1, ...] test_string = "\n".join([test_str] * 3) result = parser.parse_string(test_string, parse_all=True) print(result.dump()) self.assertEqual(1, len(result), f"failed {test_string!r}") pp.ParserElement.set_default_whitespace_chars(" \t") for expr, test_str in expr_tests: parser = pp.Group(expr[1, ...] + pp.Optional(NL))[1, ...] test_string = "\n".join([test_str] * 3) result = parser.parse_string(test_string, parse_all=True) print(result.dump()) self.assertEqual(3, len(result), f"failed {test_string!r}") pp.ParserElement.set_default_whitespace_chars(" \n\t") for expr, test_str in expr_tests: parser = pp.Group(expr[1, ...] + pp.Optional(NL))[1, ...] test_string = "\n".join([test_str] * 3) result = parser.parse_string(test_string, parse_all=True) print(result.dump()) self.assertEqual(1, len(result), f"failed {test_string!r}") def testParseFourFn(self): import examples.fourFn as fourFn import math def test(s, ans): fourFn.exprStack[:] = [] results = fourFn.BNF().parse_string(s, parse_all=True) try: resultValue = fourFn.evaluate_stack(fourFn.exprStack) except Exception: self.assertIsNone(ans, f"exception raised for expression {s!r}") else: self.assertEqual( ans, resultValue, f"failed to evaluate {s}, got {resultValue:f}", ) print(s, "->", resultValue) test("9", 9) test("-9", -9) test("--9", 9) test("-E", -math.e) test("9 + 3 + 5", 9 + 3 + 5) test("9 + 3 / 11", 9 + 3.0 / 11) test("(9 + 3)", (9 + 3)) test("(9+3) / 11", (9 + 3.0) / 11) test("9 - 12 - 6", 9 - 12 - 6) test("9 - (12 - 6)", 9 - (12 - 6)) test("2*3.14159", 2 * 3.14159) test("3.1415926535*3.1415926535 / 10", 3.1415926535 * 3.1415926535 / 10) test("PI * PI / 10", math.pi * math.pi / 10) test("PI*PI/10", math.pi * math.pi / 10) test("PI^2", math.pi**2) test("round(PI^2)", round(math.pi**2)) test("6.02E23 * 8.048", 6.02e23 * 8.048) test("e / 3", math.e / 3) test("sin(PI/2)", math.sin(math.pi / 2)) test("10+sin(PI/4)^2", 10 + math.sin(math.pi / 4) ** 2) test("trunc(E)", int(math.e)) test("trunc(-E)", int(-math.e)) test("round(E)", round(math.e)) test("round(-E)", round(-math.e)) test("E^PI", math.e**math.pi) test("exp(0)", 1) test("exp(1)", math.e) test("2^3^2", 2**3**2) test("(2^3)^2", (2**3) ** 2) test("2^3+2", 2**3 + 2) test("2^3+5", 2**3 + 5) test("2^9", 2**9) test("sgn(-2)", -1) test("sgn(0)", 0) test("sgn(0.1)", 1) test("foo(0.1)", None) test("round(E, 3)", round(math.e, 3)) test("round(PI^2, 3)", round(math.pi**2, 3)) test("sgn(cos(PI/4))", 1) test("sgn(cos(PI/2))", 0) test("sgn(cos(PI*3/4))", -1) test("+(sgn(cos(PI/4)))", 1) test("-(sgn(cos(PI/4)))", -1) def testParseSQL(self): # SQL parser uses packrat parsing, not compatible with LR if ParserElement._left_recursion_enabled: return import examples.simpleSQL as simpleSQL def test(s, num_expected_toks, expected_errloc=-1): try: sqlToks = flatten( simpleSQL.simpleSQL.parse_string(s, parse_all=True).as_list() ) print(s, sqlToks, len(sqlToks)) self.assertEqual( num_expected_toks, len(sqlToks), f"invalid parsed tokens, expected {num_expected_toks}, found {len(sqlToks)} ({sqlToks})", ) except ParseException as e: if expected_errloc >= 0: self.assertEqual( expected_errloc, e.loc, f"expected error at {expected_errloc}, found at {e.loc}", ) test("SELECT * from XYZZY, ABC", 6) test("select * from SYS.XYZZY", 5) test("Select A from Sys.dual", 5) test("Select A,B,C from Sys.dual", 7) test("Select A, B, C from Sys.dual", 7) test("Select A, B, C from Sys.dual, Table2 ", 8) test("Xelect A, B, C from Sys.dual", 0, 0) test("Select A, B, C frox Sys.dual", 0, 15) test("Select", 0, 6) test("Select &&& frox Sys.dual", 0, 7) test("Select A from Sys.dual where a in ('RED','GREEN','BLUE')", 12) test( "Select A from Sys.dual where a in ('RED','GREEN','BLUE') and b in (10,20,30)", 20, ) test( "Select A,b from table1,table2 where table1.id eq table2.id -- test out comparison operators", 10, ) def testParseConfigFile(self): from examples import configParse def test(fnam, num_expected_toks, resCheckList): print("Parsing", fnam, "...", end=" ") with open(fnam) as infile: iniFileLines = "\n".join(infile.read().splitlines()) iniData = configParse.inifile_BNF().parse_string( iniFileLines, parse_all=True ) print(len(flatten(iniData.as_list()))) print(list(iniData.keys())) self.assertEqual( num_expected_toks, len(flatten(iniData.as_list())), f"file {fnam} not parsed correctly", ) for chkkey, chkexpect in resCheckList: var = iniData for attr in chkkey.split("."): var = getattr(var, attr) print(chkkey, var, chkexpect) self.assertEqual( chkexpect, var, f"ParseConfigFileTest: failed to parse ini {chkkey!r} as expected {chkexpect!r}, found {var}", ) print("OK") test( "tests/karthik.ini", 23, [("users.K", "8"), ("users.mod_scheme", "'QPSK'"), ("users.Na", "K+2")], ) test( "examples/Setup.ini", 125, [ ("Startup.audioinf", "M3i"), ("Languages.key1", "0x0003"), ("test.foo", "bar"), ], ) def testParseJSONData(self): expected = [ { "glossary": { "GlossDiv": { "GlossList": [ { "Abbrev": "ISO 8879:1986", "Acronym": "SGML", "AvogadroNumber": 6.02e23, "EmptyDict": {}, "EmptyList": [], "EvenPrimesGreaterThan2": [], "FermatTheoremInMargin": False, "GlossDef": "A meta-markup language, " "used to create markup " "languages such as " "DocBook.", "GlossSeeAlso": ["GML", "XML", "markup"], "GlossTerm": "Standard Generalized " "Markup Language", "ID": "SGML", "LargestPrimeLessThan100": 97, "MapRequiringFiveColors": None, "PrimesLessThan10": [2, 3, 5, 7], "SortAs": "SGML", } ], "title": "S", }, "title": "example glossary", } }, { "menu": { "id": "file", "popup": { "menuitem": [ {"onclick": "CreateNewDoc()", "value": "New"}, {"onclick": "OpenDoc()", "value": "Open"}, {"onclick": "CloseDoc()", "value": "Close"}, ] }, "value": "File:", } }, { "widget": { "debug": "on", "image": { "alignment": "center", "hOffset": 250, "name": "sun1", "src": "Images/Sun.png", "vOffset": 250, }, "text": { "alignment": "center", "data": "Click Here", "hOffset": 250, "name": "text1", "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;", "size": 36, "style": "bold", "vOffset": 100, }, "window": { "height": 500, "name": "main_window", "title": "Sample Konfabulator Widget", "width": 500, }, } }, { "web-app": { "servlet": [ { "init-param": { "cachePackageTagsRefresh": 60, "cachePackageTagsStore": 200, "cachePackageTagsTrack": 200, "cachePagesDirtyRead": 10, "cachePagesRefresh": 10, "cachePagesStore": 100, "cachePagesTrack": 200, "cacheTemplatesRefresh": 15, "cacheTemplatesStore": 50, "cacheTemplatesTrack": 100, "configGlossary:adminEmail": "ksm@pobox.com", "configGlossary:installationAt": "Philadelphia, " "PA", "configGlossary:poweredBy": "Cofax", "configGlossary:poweredByIcon": "/images/cofax.gif", "configGlossary:staticPath": "/content/static", "dataStoreClass": "org.cofax.SqlDataStore", "dataStoreConnUsageLimit": 100, "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", "dataStoreInitConns": 10, "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", "dataStoreLogLevel": "debug", "dataStoreMaxConns": 100, "dataStoreName": "cofax", "dataStorePassword": "dataStoreTestQuery", "dataStoreTestQuery": "SET NOCOUNT " "ON;select " "test='test';", "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", "dataStoreUser": "sa", "defaultFileTemplate": "articleTemplate.htm", "defaultListTemplate": "listTemplate.htm", "jspFileTemplate": "articleTemplate.jsp", "jspListTemplate": "listTemplate.jsp", "maxUrlLength": 500, "redirectionClass": "org.cofax.SqlRedirection", "searchEngineFileTemplate": "forSearchEngines.htm", "searchEngineListTemplate": "forSearchEnginesList.htm", "searchEngineRobotsDb": "WEB-INF/robots.db", "templateLoaderClass": "org.cofax.FilesTemplateLoader", "templateOverridePath": "", "templatePath": "templates", "templateProcessorClass": "org.cofax.WysiwygTemplate", "useDataStore": True, "useJSP": False, }, "servlet-class": "org.cofax.cds.CDSServlet", "servlet-name": "cofaxCDS", }, { "init-param": { "mailHost": "mail1", "mailHostOverride": "mail2", }, "servlet-class": "org.cofax.cds.EmailServlet", "servlet-name": "cofaxEmail", }, { "servlet-class": "org.cofax.cds.AdminServlet", "servlet-name": "cofaxAdmin", }, { "servlet-class": "org.cofax.cds.FileServlet", "servlet-name": "fileServlet", }, { "init-param": { "adminGroupID": 4, "betaServer": True, "dataLog": 1, "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", "dataLogMaxSize": "", "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", "log": 1, "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", "logMaxSize": "", "lookInContext": 1, "removePageCache": "/content/admin/remove?cache=pages&id=", "removeTemplateCache": "/content/admin/remove?cache=templates&id=", "templatePath": "toolstemplates/", }, "servlet-class": "org.cofax.cms.CofaxToolsServlet", "servlet-name": "cofaxTools", }, ], "servlet-mapping": { "cofaxAdmin": "/admin/*", "cofaxCDS": "/", "cofaxEmail": "/cofaxutil/aemail/*", "cofaxTools": "/tools/*", "fileServlet": "/static/*", }, "taglib": { "taglib-location": "/WEB-INF/tlds/cofax.tld", "taglib-uri": "cofax.tld", }, } }, { "menu": { "header": "SVG Viewer", "items": [ {"id": "Open"}, {"id": "OpenNew", "label": "Open New"}, None, {"id": "ZoomIn", "label": "Zoom In"}, {"id": "ZoomOut", "label": "Zoom Out"}, {"id": "OriginalView", "label": "Original View"}, None, {"id": "Quality"}, {"id": "Pause"}, {"id": "Mute"}, None, {"id": "Find", "label": "Find..."}, {"id": "FindAgain", "label": "Find Again"}, {"id": "Copy"}, {"id": "CopyAgain", "label": "Copy Again"}, {"id": "CopySVG", "label": "Copy SVG"}, {"id": "ViewSVG", "label": "View SVG"}, {"id": "ViewSource", "label": "View Source"}, {"id": "SaveAs", "label": "Save As"}, None, {"id": "Help"}, {"id": "About", "label": "About Adobe CVG Viewer..."}, ], } }, ] for t, exp_result in zip((test1, test2, test3, test4, test5), expected): result = jsonObject.parse_string(t, parse_all=True) self.assertEqual(exp_result, result[0]) def testParseCommaSeparatedValues(self): testData = [ "a,b,c,100.2,,3", "d, e, j k , m ", "'Hello, World', f, g , , 5.1,x", "John Doe, 123 Main St., Cleveland, Ohio", "Jane Doe, 456 St. James St., Los Angeles , California ", "", ] testVals = [ [(3, "100.2"), (4, ""), (5, "3")], [(2, "j k"), (3, "m")], [(0, "'Hello, World'"), (2, "g"), (3, "")], [(0, "John Doe"), (1, "123 Main St."), (2, "Cleveland"), (3, "Ohio")], [ (0, "Jane Doe"), (1, "456 St. James St."), (2, "Los Angeles"), (3, "California"), ], ] for line, tests in zip(testData, testVals): print(f"Parsing: {line!r} ->", end=" ") results = ppc.comma_separated_list.parse_string(line, parse_all=True) print(results) for t in tests: if not (len(results) > t[0] and results[t[0]] == t[1]): print("$$$", results.dump()) print("$$$", results[0]) self.assertTrue( len(results) > t[0] and results[t[0]] == t[1], f"failed on {line}, item {t[0]:d} s/b '{t[1]}', got '{results.as_list()}'", ) def testParseEBNF(self): from examples import ebnf print("Constructing EBNF parser with pyparsing...") grammar = """ syntax = (syntax_rule), {(syntax_rule)}; syntax_rule = meta_identifier, '=', definitions_list, ';'; definitions_list = single_definition, {'|', single_definition}; single_definition = syntactic_term, {',', syntactic_term}; syntactic_term = syntactic_factor,['-', syntactic_factor]; syntactic_factor = [integer, '*'], syntactic_primary; syntactic_primary = optional_sequence | repeated_sequence | grouped_sequence | meta_identifier | terminal_string; optional_sequence = '[', definitions_list, ']'; repeated_sequence = '{', definitions_list, '}'; grouped_sequence = '(', definitions_list, ')'; (* terminal_string = "'", character - "'", {character - "'"}, "'" | '"', character - '"', {character - '"'}, '"'; meta_identifier = letter, {letter | digit}; integer = digit, {digit}; *) """ table = {} table["terminal_string"] = pp.quoted_string table["meta_identifier"] = pp.Word(pp.alphas + "_", pp.alphas + "_" + pp.nums) table["integer"] = pp.Word(pp.nums) print("Parsing EBNF grammar with EBNF parser...") parsers = ebnf.parse(grammar, table) ebnf_parser = parsers["syntax"] ebnf_comment = pp.Literal("(*") + ... + "*)" ebnf_parser.ignore(ebnf_comment) print("-", "\n- ".join(parsers.keys())) self.assertEqual( 13, len(list(parsers.keys())), "failed to construct syntax grammar" ) print("Parsing EBNF grammar with generated EBNF parser...") parsed_chars = ebnf_parser.parse_string(grammar, parse_all=True) parsed_char_len = len(parsed_chars) print("],\n".join(str(parsed_chars.as_list()).split("],"))) self.assertEqual( 98, len(flatten(parsed_chars.as_list())), "failed to tokenize grammar correctly", ) def testParseEBNFmissingDefinitions(self): """ Test detection of missing definitions in EBNF """ from examples import ebnf grammar = """ (* EBNF for number_words.py *) number = [thousands, [and]], [hundreds, [and]], [one_to_99]; """ with self.assertRaisesRegex( AssertionError, r"Missing definitions for \['thousands', 'and', 'hundreds', 'one_to_99']", ): ebnf.parse(grammar) def testParseIDL(self): from examples import idlParse def test(strng, numToks, expectedErrloc=0): print(strng) try: bnf = idlParse.CORBA_IDL_BNF() tokens = bnf.parse_string(strng, parse_all=True) print("tokens = ") tokens.pprint() tokens = flatten(tokens.as_list()) print(len(tokens)) self.assertEqual( numToks, len(tokens), f"error matching IDL string, {strng} -> {tokens}", ) except ParseException as err: print(err.line) print(f"{' ' * (err.column - 1)}^") print(err) self.assertEqual( 0, numToks, f"unexpected ParseException while parsing {strng}, {err}", ) self.assertEqual( expectedErrloc, err.loc, f"expected ParseException at {expectedErrloc}, found exception at {err.loc}", ) test( """ /* * a block comment * */ typedef string[10] tenStrings; typedef sequence stringSeq; typedef sequence< sequence > stringSeqSeq; interface QoSAdmin { stringSeq method1(in string arg1, inout long arg2); stringSeqSeq method2(in string arg1, inout long arg2, inout long arg3); string method3(); }; """, 59, ) test( """ /* * a block comment * */ typedef string[10] tenStrings; typedef /** ** *** **** * * a block comment * */ sequence /*comment inside an And */ stringSeq; /* */ /**/ /***/ /****/ typedef sequence< sequence > stringSeqSeq; interface QoSAdmin { stringSeq method1(in string arg1, inout long arg2); stringSeqSeq method2(in string arg1, inout long arg2, inout long arg3); string method3(); }; """, 59, ) test( r""" const string test="Test String\n"; const long a = 0; const long b = -100; const float c = 3.14159; const long d = 0x007f7f7f; exception TestException { string msg; sequence dataStrings; }; interface TestInterface { void method1(in string arg1, inout long arg2); }; """, 60, ) test( """ module Test1 { exception TestException { string msg; ]; interface TestInterface { void method1(in string arg1, inout long arg2) raises (TestException); }; }; """, 0, 56, ) test( """ module Test1 { exception TestException { string msg; }; }; """, 13, ) def testParseVerilog(self): pass def testScanString(self): testdata = """
Name IP Address Location
time-a.nist.gov 129.6.15.28 NIST, Gaithersburg, Maryland
time-b.nist.gov 129.6.15.29 NIST, Gaithersburg, Maryland
time-a.timefreq.bldrdoc.gov 132.163.4.101 NIST, Boulder, Colorado
time-b.timefreq.bldrdoc.gov 132.163.4.102 NIST, Boulder, Colorado
time-c.timefreq.bldrdoc.gov 132.163.4.103 NIST, Boulder, Colorado
""" integer = pp.Word(pp.nums) ipAddress = pp.Combine(integer + "." + integer + "." + integer + "." + integer) tdStart = pp.Suppress("") tdEnd = pp.Suppress("") timeServerPattern = ( tdStart + ipAddress("ipAddr") + tdEnd + tdStart + pp.CharsNotIn("<")("loc") + tdEnd ) servers = [ srvr.ipAddr for srvr, startloc, endloc in timeServerPattern.scan_string(testdata) ] print(servers) self.assertEqual( [ "129.6.15.28", "129.6.15.29", "132.163.4.101", "132.163.4.102", "132.163.4.103", ], servers, "failed scan_string()", ) servers = [ srvr.ipAddr for srvr, startloc, endloc in timeServerPattern.scan_string( testdata, max_matches=3 ) ] self.assertEqual( [ "129.6.15.28", "129.6.15.29", "132.163.4.101", ], servers, "failed scan_string() with max_matches=3", ) # test for string_end detection in scan_string foundStringEnds = [r for r in pp.StringEnd().scan_string("xyzzy")] print(foundStringEnds) self.assertTrue(foundStringEnds, "Failed to find StringEnd in scan_string") def testQuotedStrings(self): testData = """ 'a valid single quoted string' 'an invalid single quoted string because it spans lines' "a valid double quoted string" "an invalid double quoted string because it spans lines" """ print(testData) with self.subTest(): sglStrings = [ (t[0], b, e) for (t, b, e) in pp.sgl_quoted_string.scan_string(testData) ] print(sglStrings) self.assertTrue( len(sglStrings) == 1 and (sglStrings[0][1] == 17 and sglStrings[0][2] == 47), "single quoted string failure", ) with self.subTest(): dblStrings = [ (t[0], b, e) for (t, b, e) in pp.dbl_quoted_string.scan_string(testData) ] print(dblStrings) self.assertTrue( len(dblStrings) == 1 and (dblStrings[0][1] == 154 and dblStrings[0][2] == 184), "double quoted string failure", ) with self.subTest(): allStrings = [ (t[0], b, e) for (t, b, e) in pp.quoted_string.scan_string(testData) ] print(allStrings) self.assertTrue( len(allStrings) == 2 and (allStrings[0][1] == 17 and allStrings[0][2] == 47) and (allStrings[1][1] == 154 and allStrings[1][2] == 184), "quoted string failure", ) escapedQuoteTest = r""" 'This string has an escaped (\') quote character' "This string has an escaped (\") quote character" """ with self.subTest(): sglStrings = [ (t[0], b, e) for (t, b, e) in pp.sgl_quoted_string.scan_string(escapedQuoteTest) ] print(sglStrings) self.assertTrue( len(sglStrings) == 1 and (sglStrings[0][1] == 17 and sglStrings[0][2] == 66), f"single quoted string escaped quote failure ({sglStrings[0]})", ) with self.subTest(): dblStrings = [ (t[0], b, e) for (t, b, e) in pp.dbl_quoted_string.scan_string(escapedQuoteTest) ] print(dblStrings) self.assertTrue( len(dblStrings) == 1 and (dblStrings[0][1] == 83 and dblStrings[0][2] == 132), f"double quoted string escaped quote failure ({dblStrings[0]})", ) with self.subTest(): allStrings = [ (t[0], b, e) for (t, b, e) in pp.quoted_string.scan_string(escapedQuoteTest) ] print(allStrings) self.assertTrue( len(allStrings) == 2 and ( allStrings[0][1] == 17 and allStrings[0][2] == 66 and allStrings[1][1] == 83 and allStrings[1][2] == 132 ), f"quoted string escaped quote failure ({[str(s[0]) for s in allStrings]})", ) dblQuoteTest = r""" 'This string has an doubled ('') quote character' "This string has an doubled ("") quote character" """ with self.subTest(): sglStrings = [ (t[0], b, e) for (t, b, e) in pp.sgl_quoted_string.scan_string(dblQuoteTest) ] print(sglStrings) self.assertTrue( len(sglStrings) == 1 and (sglStrings[0][1] == 17 and sglStrings[0][2] == 66), f"single quoted string escaped quote failure ({sglStrings[0]})", ) with self.subTest(): dblStrings = [ (t[0], b, e) for (t, b, e) in pp.dbl_quoted_string.scan_string(dblQuoteTest) ] print(dblStrings) self.assertTrue( len(dblStrings) == 1 and (dblStrings[0][1] == 83 and dblStrings[0][2] == 132), f"double quoted string escaped quote failure ({dblStrings[0]})", ) with self.subTest(): allStrings = [ (t[0], b, e) for (t, b, e) in pp.quoted_string.scan_string(dblQuoteTest) ] print(allStrings) self.assertTrue( len(allStrings) == 2 and ( allStrings[0][1] == 17 and allStrings[0][2] == 66 and allStrings[1][1] == 83 and allStrings[1][2] == 132 ), f"quoted string escaped quote failure ({[str(s[0]) for s in allStrings]})", ) # test invalid end_quote_char with self.subTest(): with self.assertRaises( ValueError, msg="issue raising error for invalid end_quote_char" ): expr = pp.QuotedString('"', end_quote_char=" ") with self.subTest(): source = """ ''' multiline quote with comment # this is a comment ''' \"\"\" multiline quote with comment # this is a comment \"\"\" "single line quote with comment # this is a comment" 'single line quote with comment # this is a comment' """ stripped = ( pp.python_style_comment.ignore(pp.python_quoted_string) .suppress() .transform_string(source) ) self.assertEqual(source, stripped) def testQuotedStringUnquotesAndConvertWhitespaceEscapes(self): # test for Issue #474 # fmt: off backslash = chr(92) # a single backslash tab = "\t" newline = "\n" test_string_0 = f'"{backslash}{backslash}n"' # r"\\n" test_string_1 = f'"{backslash}t{backslash}{backslash}n"' # r"\t\\n" test_string_2 = f'"a{backslash}tb"' # r"a\tb" test_string_3 = f'"{backslash}{backslash}{backslash}n"' # r"\\\n" T, F = True, False # these make the test cases format nicely for test_parameters in ( # Parameters are the arguments to creating a QuotedString # and the expected parsed list of characters): # - unquote_results # - convert_whitespace_escapes # - test string # - expected parsed characters (broken out as separate # list items (all those doubled backslashes make it # difficult to interpret the output) (T, T, test_string_0, [backslash, "n"]), (T, F, test_string_0, [backslash, "n"]), (F, F, test_string_0, ['"', backslash, backslash, "n", '"']), (T, T, test_string_1, [tab, backslash, "n"]), (T, F, test_string_1, ["t", backslash, "n"]), (F, F, test_string_1, ['"', backslash, "t", backslash, backslash, "n", '"']), (T, T, test_string_2, ["a", tab, "b"]), (T, F, test_string_2, ["a", "t", "b"]), (F, F, test_string_2, ['"', "a", backslash, "t", "b", '"']), (T, T, test_string_3, [backslash, newline]), (T, F, test_string_3, [backslash, "n"]), (F, F, test_string_3, ['"', backslash, backslash, backslash, "n", '"']), ): unquote_results, convert_ws_escapes, test_string, expected_list = test_parameters test_description = f"Testing with parameters {test_parameters}" with self.subTest(msg=test_description): print(test_description) print(f"unquote_results: {unquote_results}" f"\nconvert_whitespace_escapes: {convert_ws_escapes}") qs_expr = pp.QuotedString( quote_char='"', esc_char='\\', unquote_results=unquote_results, convert_whitespace_escapes=convert_ws_escapes ) result = qs_expr.parse_string(test_string) # do this instead of assertParserAndCheckList to explicitly # check and display the separate items in the list print("Results:") control_chars = {newline: "", backslash: "", tab: ""} print(f"[{', '.join(control_chars.get(c, repr(c)) for c in result[0])}]") self.assertEqual(expected_list, list(result[0])) print() # fmt: on def testPythonQuotedStrings(self): # fmt: off success1, _ = pp.python_quoted_string.run_tests([ '"""xyz"""', '''"""xyz """''', '"""xyz "" """', '''"""xyz "" """''', '"""xyz " """', '''"""xyz " """''', r'''"""xyz \""" """''', "'''xyz'''", """'''xyz '''""", "'''xyz '' '''", """'''xyz '' '''""", "'''xyz ' '''", """'''xyz ' '''""", r"""'''xyz \''' '''""", ]) print("\n\nFailure tests") success2, _ = pp.python_quoted_string.run_tests([ '"xyz"""', ], failure_tests=True) self.assertTrue(success1 and success2, "Python quoted string matching failure") # fmt: on def testCaselessOneOf(self): caseless1 = pp.one_of("d a b c aA B A C", caseless=True) caseless1str = str(caseless1) print(caseless1str) caseless2 = pp.one_of("d a b c Aa B A C", caseless=True) caseless2str = str(caseless2) print(caseless2str) self.assertEqual( caseless1str.upper(), caseless2str.upper(), "one_of not handling caseless option properly", ) self.assertNotEqual( caseless1str, caseless2str, "Caseless option properly sorted" ) res = caseless1[...].parse_string("AAaaAaaA", parse_all=True) print(res) self.assertEqual(4, len(res), "caseless1 one_of failed") self.assertEqual( "aA" * 4, "".join(res), "caseless1 CaselessLiteral return failed" ) res = caseless2[...].parse_string("AAaaAaaA", parse_all=True) print(res) self.assertEqual(4, len(res), "caseless2 one_of failed") self.assertEqual( "Aa" * 4, "".join(res), "caseless1 CaselessLiteral return failed" ) def testCStyleCommentParser(self): print("verify processing of C-style /* */ comments") testdata = f""" /* */ /** **/ /**/ /*{'*' * 1_000_000}*/ /****/ /* /*/ /** /*/ /*** /*/ /* ablsjdflj */ """ for test_expr in ( pp.c_style_comment, pp.cpp_style_comment, pp.java_style_comment, ): with self.subTest("parse test - /* */ comments", test_expr=test_expr): found_matches = [ len(t[0]) for t, s, e in test_expr.scan_string(testdata) ] self.assertEqual( [5, 7, 4, 1000004, 6, 6, 7, 8, 33], found_matches, f"only found {test_expr} lengths {found_matches}", ) found_lines = [ pp.lineno(s, testdata) for t, s, e in test_expr.scan_string(testdata) ] self.assertEqual( [2, 3, 4, 5, 6, 7, 8, 9, 10], found_lines, f"only found {test_expr} on lines {found_lines}", ) def testHtmlCommentParser(self): print("verify processing of HTML comments") test_expr = pp.html_comment testdata = """ """ found_matches = [len(t[0]) for t, s, e in test_expr.scan_string(testdata)] self.assertEqual( [8, 10, 7, 8, 9, 9, 10, 11, 79], found_matches, f"only found {test_expr} lengths {found_matches}", ) found_lines = [ pp.lineno(s, testdata) for t, s, e in pp.html_comment.scan_string(testdata) ] self.assertEqual( [2, 3, 4, 5, 6, 7, 8, 9, 10], found_lines, f"only found HTML comments on lines {found_lines}", ) def testDoubleSlashCommentParser(self): print("verify processing of C++ and Java comments - // comments") # test C++ single line comments that have line terminated with '\' (should continue comment to following line) testdata = r""" // comment1 // comment2 \ still comment 2 // comment 3 """ for test_expr in ( pp.dbl_slash_comment, pp.cpp_style_comment, pp.java_style_comment, ): with self.subTest("parse test - // comments", test_expr=test_expr): found_matches = [ len(t[0]) for t, s, e in test_expr.scan_string(testdata) ] self.assertEqual( [11, 41, 12], found_matches, f"only found {test_expr} lengths {found_matches}", ) found_lines = [ pp.lineno(s, testdata) for t, s, e in test_expr.scan_string(testdata) ] self.assertEqual( [2, 3, 5], found_lines, f"only found {test_expr} on lines {found_lines}", ) def testReCatastrophicBacktrackingInQuotedStringParsers(self): # reported by webpentest - 2016-04-28 print( "testing catastrophic RE backtracking in implementation of quoted string parsers" ) repeat = 5000 for expr, test_string in [ (pp.dblQuotedString, '"' + "\xff" * repeat), (pp.sglQuotedString, "'" + "\xff" * repeat), (pp.quotedString, '"' + "\xff" * repeat), (pp.quotedString, "'" + "\xff" * repeat), (pp.QuotedString('"'), '"' + "\xff" * repeat), (pp.QuotedString("'"), "'" + "\xff" * repeat), ]: test_string_label = f"{test_string[:2]}..." with self.subTest(expr=expr, test_string=repr(test_string_label)): # parse a valid quoted string expr.parse_string(test_string + test_string[0], parse_all=True) # try to parse a quoted string with no trailing quote with self.assertRaisesParseException(): expr.parse_string(test_string, parse_all=True) def testReCatastrophicBacktrackingInCommentParsers(self): print( "testing catastrophic RE backtracking in implementation of comment parsers" ) for expr, test_string in [ (pp.c_style_comment, f"/*{'*' * 500}"), (pp.cpp_style_comment, f"/*{'*' * 500}"), (pp.java_style_comment, f"/*{'*' * 500}"), (pp.html_comment, f"<-- {'-' * 500}"), ]: with self.subTest("Test catastrophic RE backtracking", expr=expr): try: expr.parse_string(test_string) except pp.ParseException: continue def testParseExpressionResults(self): a = pp.Word("a", pp.alphas).set_name("A") b = pp.Word("b", pp.alphas).set_name("B") c = pp.Word("c", pp.alphas).set_name("C") ab = (a + b).set_name("AB") abc = (ab + c).set_name("ABC") word = pp.Word(pp.alphas).set_name("word") words = pp.Group(pp.OneOrMore(~a + word)).set_name("words") phrase = ( words("Head") + pp.Group(a + pp.Optional(b + pp.Optional(c)))("ABC") + words("Tail") ) results = phrase.parse_string( "xavier yeti alpha beta charlie will beaver", parse_all=True ) print(results, results.Head, results.ABC, results.Tail) for key, ln in [("Head", 2), ("ABC", 3), ("Tail", 2)]: self.assertEqual( ln, len(results[key]), f"expected {ln:d} elements in {key}, found {results[key]}", ) def testParseKeyword(self): kw = pp.Keyword("if") lit = pp.Literal("if") def test(s, litShouldPass, kwShouldPass): print("Test", s) print("Match Literal", end=" ") try: print(lit.parse_string(s, parse_all=False)) except Exception: print("failed") if litShouldPass: self.fail(f"Literal failed to match {s}, should have") else: if not litShouldPass: self.fail(f"Literal matched {s}, should not have") print("Match Keyword", end=" ") try: print(kw.parse_string(s, parse_all=False)) except Exception: print("failed") if kwShouldPass: self.fail(f"Keyword failed to match {s}, should have") else: if not kwShouldPass: self.fail(f"Keyword matched {s}, should not have") test("ifOnlyIfOnly", True, False) test("if(OnlyIfOnly)", True, True) test("if (OnlyIf Only)", True, True) kw = pp.Keyword("if", caseless=True) test("IFOnlyIfOnly", False, False) test("If(OnlyIfOnly)", False, True) test("iF (OnlyIf Only)", False, True) with self.assertRaises( ValueError, msg="failed to warn empty string passed to Keyword" ): kw = pp.Keyword("") def testParseExpressionResultsAccumulate(self): num = pp.Word(pp.nums).set_name("num")("base10*") hexnum = pp.Combine("0x" + pp.Word(pp.nums)).set_name("hexnum")("hex*") name = pp.Word(pp.alphas).set_name("word")("word*") list_of_num = pp.DelimitedList(hexnum | num | name, ",") tokens = list_of_num.parse_string("1, 0x2, 3, 0x4, aaa", parse_all=True) print(tokens.dump()) self.assertParseResultsEquals( tokens, expected_list=["1", "0x2", "3", "0x4", "aaa"], expected_dict={ "base10": ["1", "3"], "hex": ["0x2", "0x4"], "word": ["aaa"], }, ) lbrack = pp.Literal("(").suppress() rbrack = pp.Literal(")").suppress() integer = pp.Word(pp.nums).set_name("int") variable = pp.Word(pp.alphas, max=1).set_name("variable") relation_body_item = ( variable | integer | pp.quoted_string().set_parse_action(pp.remove_quotes) ) relation_name = pp.Word(pp.alphas + "_", pp.alphanums + "_") relation_body = lbrack + pp.Group(pp.DelimitedList(relation_body_item)) + rbrack Goal = pp.Dict(pp.Group(relation_name + relation_body)) Comparison_Predicate = pp.Group(variable + pp.one_of("< >") + integer)("pred*") Query = Goal("head") + ":-" + pp.DelimitedList(Goal | Comparison_Predicate) test = """Q(x,y,z):-Bloo(x,"Mitsis",y),Foo(y,z,1243),y>28,x<12,x>3""" queryRes = Query.parse_string(test, parse_all=True) print(queryRes.dump()) self.assertParseResultsEquals( queryRes.pred, expected_list=[["y", ">", "28"], ["x", "<", "12"], ["x", ">", "3"]], msg=f"Incorrect list for attribute pred, {queryRes.pred.as_list()}", ) def testReStringRange(self): testCases = ( r"[A-Z]", r"[A-A]", r"[A-Za-z]", r"[A-z]", r"[\ -\~]", r"[\0x20-0]", r"[\0x21-\0x7E]", r"[\0xa1-\0xfe]", r"[\040-0]", r"[A-Za-z0-9]", r"[A-Za-z0-9_]", r"[A-Za-z0-9_$]", r"[A-Za-z0-9_$\-]", r"[^0-9\\]", r"[a-zA-Z]", r"[/\^~]", r"[=\+\-!]", r"[A-]", r"[-A]", r"[\x21]", r"[а-яА-ЯёЁA-Z$_\041α-ω]", r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]", r"[\0xa1-\0xbf\0xd7\0xf7]", r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]", r"[\0xa1-\0xbf\0xd7\0xf7]", r"[\\[\]\/\-\*\.\$\+\^\?()~ ]", ) expectedResults = ( "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "A", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz", " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", " !\"#$%&'()*+,-./0", "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", "¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ", " !\"#$%&'()*+,-./0", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$-", "0123456789\\", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", "/^~", "=+-!", "A-", "-A", "!", "абвгдежзийклмнопрстуфхцчшщъыьэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯёЁABCDEFGHIJKLMNOPQRSTUVWXYZ$_!αβγδεζηθικλμνξοπρςστυφχψω", "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ", "¡¢£¤¥¦§¨©ª«¬\xad®¯°±²³´µ¶·¸¹º»¼½¾¿×÷", pp.alphas8bit, pp.punc8bit, r"\[]/-*.$+^?()~ ", ) for test in zip(testCases, expectedResults): t, exp = test res = pp.srange(t) # print(t, "->", res) self.assertEqual( exp, res, f"srange error, srange({t!r})->'{res!r}', expected '{exp!r}'", ) def testSkipToParserTests(self): thingToFind = pp.Literal("working") testExpr = ( pp.SkipTo(pp.Literal(";"), include=True, ignore=pp.c_style_comment) + thingToFind ) def test_parse(someText): print(testExpr.parse_string(someText, parse_all=True)) # This first test works, as the SkipTo expression is immediately following the ignore expression (c_style_comment) test_parse("some text /* comment with ; in */; working") # This second test previously failed, as there is text following the ignore expression, and before the SkipTo expression. test_parse("some text /* comment with ; in */some other stuff; working") # tests for optional fail_on argument testExpr = ( pp.SkipTo( pp.Literal(";"), include=True, ignore=pp.c_style_comment, fail_on="other", ) + thingToFind ) test_parse("some text /* comment with ; in */; working") with self.assertRaisesParseException(): test_parse("some text /* comment with ; in */some other stuff; working") # test that we correctly create named results text = "prefixDATAsuffix" data = pp.Literal("DATA") suffix = pp.Literal("suffix") expr = pp.SkipTo(data + suffix)("prefix") + data + suffix result = expr.parse_string(text, parse_all=True) self.assertTrue( isinstance(result.prefix, str), "SkipTo created with wrong saveAsList attribute", ) alpha_word = ( ~pp.Literal("end") + pp.Word(pp.alphas, as_keyword=True) ).set_name("alpha") num_word = pp.Word(pp.nums, as_keyword=True).set_name("int") def test(expr, test_string, expected_list, expected_dict): if (expected_list, expected_dict) == (None, None): with self.assertRaises( Exception, msg=f"{expr} failed to parse {test_string!r}" ): expr.parse_string(test_string, parse_all=True) else: result = expr.parse_string(test_string, parse_all=True) self.assertParseResultsEquals( result, expected_list=expected_list, expected_dict=expected_dict ) # ellipses for SkipTo e = ... + pp.Literal("end") test(e, "start 123 end", ["start 123 ", "end"], {"_skipped": ["start 123 "]}) e = pp.Suppress(...) + pp.Literal("end") test(e, "start 123 end", ["end"], {}) e = pp.Literal("start") + ... + pp.Literal("end") test(e, "start 123 end", ["start", "123 ", "end"], {"_skipped": ["123 "]}) e = ... + pp.Literal("middle") + ... + pp.Literal("end") test( e, "start 123 middle 456 end", ["start 123 ", "middle", "456 ", "end"], {"_skipped": ["start 123 ", "456 "]}, ) e = pp.Suppress(...) + pp.Literal("middle") + ... + pp.Literal("end") test( e, "start 123 middle 456 end", ["middle", "456 ", "end"], {"_skipped": ["456 "]}, ) e = pp.Literal("start") + ... test(e, "start 123 end", None, None) e = pp.And(["start", ..., "end"]) test(e, "start 123 end", ["start", "123 ", "end"], {"_skipped": ["123 "]}) e = pp.And([..., "end"]) test(e, "start 123 end", ["start 123 ", "end"], {"_skipped": ["start 123 "]}) e = "start" + (num_word | ...) + "end" test(e, "start 456 end", ["start", "456", "end"], {}) test( e, "start 123 456 end", ["start", "123", "456 ", "end"], {"_skipped": ["456 "]}, ) test(e, "start end", ["start", "", "end"], {"_skipped": ["missing "]}) # e = define_expr('"start" + (num_word | ...)("inner") + "end"') # test(e, "start 456 end", ['start', '456', 'end'], {'inner': '456'}) e = "start" + (alpha_word[...] & num_word[...] | ...) + "end" test(e, "start 456 red end", ["start", "456", "red", "end"], {}) test(e, "start red 456 end", ["start", "red", "456", "end"], {}) test( e, "start 456 red + end", ["start", "456", "red", "+ ", "end"], {"_skipped": ["+ "]}, ) test(e, "start red end", ["start", "red", "end"], {}) test(e, "start 456 end", ["start", "456", "end"], {}) test(e, "start end", ["start", "end"], {}) test(e, "start 456 + end", ["start", "456", "+ ", "end"], {"_skipped": ["+ "]}) e = "start" + (alpha_word[1, ...] & num_word[1, ...] | ...) + "end" test(e, "start 456 red end", ["start", "456", "red", "end"], {}) test(e, "start red 456 end", ["start", "red", "456", "end"], {}) test( e, "start 456 red + end", ["start", "456", "red", "+ ", "end"], {"_skipped": ["+ "]}, ) test(e, "start red end", ["start", "red ", "end"], {"_skipped": ["red "]}) test(e, "start 456 end", ["start", "456 ", "end"], {"_skipped": ["456 "]}) test( e, "start end", ["start", "", "end"], {"_skipped": ["missing <{{alpha}... & {int}...}>"]}, ) test(e, "start 456 + end", ["start", "456 + ", "end"], {"_skipped": ["456 + "]}) e = "start" + (alpha_word | ...) + (num_word | ...) + "end" test(e, "start red 456 end", ["start", "red", "456", "end"], {}) test( e, "start red end", ["start", "red", "", "end"], {"_skipped": ["missing "]}, ) test( e, "start 456 end", ["start", "", "456", "end"], {"_skipped": ["missing "]}, ) test( e, "start end", ["start", "", "", "end"], {"_skipped": ["missing ", "missing "]}, ) e = pp.Literal("start") + ... + "+" + ... + "end" test( e, "start red + 456 end", ["start", "red ", "+", "456 ", "end"], {"_skipped": ["red ", "456 "]}, ) def testSkipToPreParseIgnoreExprs(self): # added to verify fix to Issue #475 from pyparsing import Word, alphanums, python_style_comment some_grammar = Word(alphanums) + ":=" + ... + ";" some_grammar.ignore(python_style_comment) try: result = some_grammar.parse_string( """\ var1 := 2 # 3; <== this semi-colon will match! + 1; """, parse_all=True, ) except ParseException as pe: print(pe.explain()) raise else: print(result.dump()) def testSkipToIgnoreExpr2(self): a, star = pp.Literal.using_each("a*") wrapper = a + ... + a expr = star + pp.SkipTo(star, ignore=wrapper) + star # pyparsing 3.0.9 -> ['*', 'a_*_a', '*'] # pyparsing 3.1.0 -> ['*', '', '*'] self.assertParseAndCheckList(expr, "*a_*_a*", ["*", "a_*_a", "*"]) def testEllipsisRepetition(self): word = pp.Word(pp.alphas).set_name("word") num = pp.Word(pp.nums).set_name("num") exprs = [ word[...] + num, word * ... + num, word[0, ...] + num, word[1, ...] + num, word[2, ...] + num, word[..., 3] + num, word[2] + num, ] expected_res = [ r"([abcd]+ )*\d+", r"([abcd]+ )*\d+", r"([abcd]+ )*\d+", r"([abcd]+ )+\d+", r"([abcd]+ ){2,}\d+", r"([abcd]+ ){0,3}\d+", r"([abcd]+ ){2}\d+", ] tests = ["aa bb cc dd 123", "bb cc dd 123", "cc dd 123", "dd 123", "123"] all_success = True for expr, expected_re in zip(exprs, expected_res): successful_tests = [t for t in tests if re.match(expected_re, t)] failure_tests = [t for t in tests if not re.match(expected_re, t)] success1, _ = expr.run_tests(successful_tests) success2, _ = expr.run_tests(failure_tests, failure_tests=True) all_success = all_success and success1 and success2 if not all_success: print("Failed expression:", expr) break self.assertTrue(all_success, "failed getItem_ellipsis test") def testEllipsisRepetitionWithResultsNames(self): label = pp.Word(pp.alphas) val = ppc.integer() parser = label("label") + pp.ZeroOrMore(val)("values") _, results = parser.run_tests( """ a 1 b 1 2 3 c """ ) expected = [ (["a", 1], {"label": "a", "values": [1]}), (["b", 1, 2, 3], {"label": "b", "values": [1, 2, 3]}), (["c"], {"label": "c", "values": []}), ] for obs, exp in zip(results, expected): test, result = obs exp_list, exp_dict = exp self.assertParseResultsEquals( result, expected_list=exp_list, expected_dict=exp_dict ) parser = label("label") + val[...]("values") _, results = parser.run_tests( """ a 1 b 1 2 3 c """ ) expected = [ (["a", 1], {"label": "a", "values": [1]}), (["b", 1, 2, 3], {"label": "b", "values": [1, 2, 3]}), (["c"], {"label": "c", "values": []}), ] for obs, exp in zip(results, expected): test, result = obs exp_list, exp_dict = exp self.assertParseResultsEquals( result, expected_list=exp_list, expected_dict=exp_dict ) pt = pp.Group(val("x") + pp.Suppress(",") + val("y")) parser = label("label") + pt[...]("points") _, results = parser.run_tests( """ a 1,1 b 1,1 2,2 3,3 c """ ) expected = [ (["a", [1, 1]], {"label": "a", "points": [{"x": 1, "y": 1}]}), ( ["b", [1, 1], [2, 2], [3, 3]], { "label": "b", "points": [{"x": 1, "y": 1}, {"x": 2, "y": 2}, {"x": 3, "y": 3}], }, ), (["c"], {"label": "c", "points": []}), ] for obs, exp in zip(results, expected): test, result = obs exp_list, exp_dict = exp self.assertParseResultsEquals( result, expected_list=exp_list, expected_dict=exp_dict ) def testCustomQuotes(self): testString = r""" sdlfjs :sdf\:jls::djf: sl:kfsjf sdlfjs -sdf\:jls::--djf: sl-kfsjf sdlfjs -sdf\:::jls::--djf: sl:::-kfsjf sdlfjs ^sdf\:jls^^--djf^ sl-kfsjf sdlfjs ^^^==sdf\:j=lz::--djf: sl=^^=kfsjf sdlfjs ==sdf\:j=ls::--djf: sl==kfsjf^^^ """ print(testString) colonQuotes = pp.QuotedString(":", "\\", "::") dashQuotes = pp.QuotedString("-", "\\", "--") hatQuotes = pp.QuotedString("^", "\\") hatQuotes1 = pp.QuotedString("^", "\\", "^^") dblEqQuotes = pp.QuotedString("==", "\\") def test(label, quoteExpr, expected): print(label) print(quoteExpr.pattern) print(quoteExpr.search_string(testString)) print(quoteExpr.search_string(testString)[0][0]) print(f"{expected}") self.assertEqual( expected, quoteExpr.search_string(testString)[0][0], f"failed to match {quoteExpr}, expected '{expected}', got '{quoteExpr.search_string(testString)[0]}'", ) print() test("colonQuotes", colonQuotes, r"sdf:jls:djf") test("dashQuotes", dashQuotes, r"sdf:jls::-djf: sl") test("hatQuotes", hatQuotes, r"sdf:jls") test("hatQuotes1", hatQuotes1, r"sdf:jls^--djf") test("dblEqQuotes", dblEqQuotes, r"sdf:j=ls::--djf: sl") test("::: quotes", pp.QuotedString(":::"), "jls::--djf: sl") test("==-- quotes", pp.QuotedString("==", end_quote_char="--"), r"sdf\:j=lz::") test( "^^^ multiline quotes", pp.QuotedString("^^^", multiline=True), r"""==sdf\:j=lz::--djf: sl=^^=kfsjf sdlfjs ==sdf\:j=ls::--djf: sl==kfsjf""", ) with self.assertRaises(ValueError): pp.QuotedString("", "\\") def testCustomQuotes2(self): qs = pp.QuotedString(quote_char=".[", end_quote_char="].") print(qs.reString) self.assertParseAndCheckList(qs, ".[...].", ["..."]) self.assertParseAndCheckList(qs, ".[].", [""]) self.assertParseAndCheckList(qs, ".[]].", ["]"]) self.assertParseAndCheckList(qs, ".[]]].", ["]]"]) qs = pp.QuotedString(quote_char="+*", end_quote_char="*+") print(qs.reString) self.assertParseAndCheckList(qs, "+*...*+", ["..."]) self.assertParseAndCheckList(qs, "+**+", [""]) self.assertParseAndCheckList(qs, "+***+", ["*"]) self.assertParseAndCheckList(qs, "+****+", ["**"]) qs = pp.QuotedString(quote_char="*/", end_quote_char="/*") print(qs.reString) self.assertParseAndCheckList(qs, "*/.../*", ["..."]) self.assertParseAndCheckList(qs, "*//*", [""]) self.assertParseAndCheckList(qs, "*///*", ["/"]) self.assertParseAndCheckList(qs, "*////*", ["//"]) def testRepeater(self): if ParserElement._packratEnabled or ParserElement._left_recursion_enabled: print("skipping this test, not compatible with memoization") return first = pp.Word("abcdef").set_name("word1") bridge = pp.Word(pp.nums).set_name("number") second = pp.match_previous_literal(first).set_name("repeat(word1Literal)") seq = first + bridge + second tests = [ ("abc12abc", True), ("abc12aabc", False), ("abc12cba", True), ("abc12bca", True), ] for tst, expected in tests: found = False for tokens, start, end in seq.scan_string(tst): f, b, s = tokens print(f, b, s) found = True if not found: print("No literal match in", tst) self.assertEqual( expected, found, f"Failed repeater for test: {tst}, matching {seq}", ) print() # retest using match_previous_expr instead of match_previous_literal second = pp.match_previous_expr(first).set_name("repeat(word1expr)") seq = first + bridge + second tests = [("abc12abc", True), ("abc12cba", False), ("abc12abcdef", False)] for tst, expected in tests: found = False for tokens, start, end in seq.scan_string(tst): print(tokens) found = True if not found: print("No expression match in", tst) self.assertEqual( expected, found, f"Failed repeater for test: {tst}, matching {seq}", ) print() first = pp.Word("abcdef").set_name("word1") bridge = pp.Word(pp.nums).set_name("number") second = pp.match_previous_expr(first).set_name("repeat(word1)") seq = first + bridge + second csFirst = seq.set_name("word-num-word") csSecond = pp.match_previous_expr(csFirst) compoundSeq = csFirst + ":" + csSecond compoundSeq.streamline() print(compoundSeq) tests = [ ("abc12abc:abc12abc", True), ("abc12cba:abc12abc", False), ("abc12abc:abc12abcdef", False), ] for tst, expected in tests: found = False for tokens, start, end in compoundSeq.scan_string(tst): print("match:", tokens) found = True break if not found: print("No expression match in", tst) self.assertEqual( expected, found, f"Failed repeater for test: {tst}, matching {seq}", ) print() eFirst = pp.Word(pp.nums) eSecond = pp.match_previous_expr(eFirst) eSeq = eFirst + ":" + eSecond tests = [("1:1A", True), ("1:10", False)] for tst, expected in tests: found = False for tokens, start, end in eSeq.scan_string(tst): print(tokens) found = True if not found: print("No match in", tst) self.assertEqual( expected, found, f"Failed repeater for test: {tst}, matching {seq}", ) def testRepeater2(self): """test match_previous_literal with empty repeater""" if ParserElement._packratEnabled or ParserElement._left_recursion_enabled: print("skipping this test, not compatible with memoization") return first = pp.Optional(pp.Word("abcdef").set_name("words1")) bridge = pp.Word(pp.nums).set_name("number") second = pp.match_previous_literal(first).set_name("repeat(word1Literal)") seq = first + bridge + second tst = "12" expected = ["12"] result = seq.parse_string(tst, parse_all=True) print(result.dump()) self.assertParseResultsEquals(result, expected_list=expected) def testRepeater3(self): """test match_previous_literal with multiple repeater tokens""" if ParserElement._packratEnabled or ParserElement._left_recursion_enabled: print("skipping this test, not compatible with memoization") return first = pp.Word("a") + pp.Word("d") bridge = pp.Word(pp.nums).set_name("number") second = pp.match_previous_literal(first) # ("second") seq = first + bridge + second tst = "aaaddd12aaaddd" expected = ["aaa", "ddd", "12", "aaa", "ddd"] result = seq.parse_string(tst, parse_all=True) print(result.dump()) self.assertParseResultsEquals(result, expected_list=expected) def testRepeater4(self): """test match_previous_expr with multiple repeater tokens""" if ParserElement._packratEnabled or ParserElement._left_recursion_enabled: print("skipping this test, not compatible with memoization") return first = pp.Group(pp.Word(pp.alphas) + pp.Word(pp.alphas)) bridge = pp.Word(pp.nums) # no matching is used - this is just here for a sanity check # second = pp.Group(pp.Word(pp.alphas) + pp.Word(pp.alphas))("second") # second = pp.Group(pp.Word(pp.alphas) + pp.Word(pp.alphas)).set_results_name("second") # ISSUE: when match_previous_expr returns multiple tokens the matching tokens are nested an extra level deep. # This behavior is not seen with a single return token (see testRepeater5 directly below.) second = pp.match_previous_expr(first) expr = first + bridge.suppress() + second tst = "aaa ddd 12 aaa ddd" expected = [["aaa", "ddd"], ["aaa", "ddd"]] result = expr.parse_string(tst, parse_all=True) print(result.dump()) self.assertParseResultsEquals(result, expected_list=expected) def testRepeater5(self): """a simplified testRepeater4 to examine match_previous_expr with a single repeater token""" if ParserElement._packratEnabled or ParserElement._left_recursion_enabled: print("skipping this test, not compatible with memoization") return first = pp.Word(pp.alphas) bridge = pp.Word(pp.nums) second = pp.match_previous_expr(first) expr = first + bridge.suppress() + second tst = "aaa 12 aaa" expected = tst.replace("12", "").split() result = expr.parse_string(tst, parse_all=True) print(result.dump()) self.assertParseResultsEquals(result, expected_list=expected) def testRecursiveCombine(self): testInput = "myc(114)r(11)dd" stream = pp.Forward() stream <<= pp.Optional(pp.Word(pp.alphas)) + pp.Optional( "(" + pp.Word(pp.nums) + ")" + stream ) expected = ["".join(stream.parse_string(testInput, parse_all=True))] print(expected) stream = pp.Forward() stream << pp.Combine( pp.Optional(pp.Word(pp.alphas)) + pp.Optional("(" + pp.Word(pp.nums) + ")" + stream) ) testVal = stream.parse_string(testInput, parse_all=True) print(testVal) self.assertParseResultsEquals(testVal, expected_list=expected) def testSetNameToStrAndNone(self): wd = pp.Word(pp.alphas) with self.subTest(): self.assertEqual("W:(A-Za-z)", wd.name) with self.subTest(): wd.set_name("test_word") self.assertEqual("test_word", wd.name) with self.subTest(): wd.set_name(None) self.assertEqual("W:(A-Za-z)", wd.name) # same tests but using name property setter with self.subTest(): wd.name = "test_word" self.assertEqual("test_word", wd.name) with self.subTest(): wd.name = None self.assertEqual("W:(A-Za-z)", wd.name) def testCombineSetName(self): ab = pp.Combine( pp.Literal("a").set_name("AAA") | pp.Literal("b").set_name("BBB") ).set_name("AB") self.assertEqual("AB", ab.name) self.assertEqual("AB", str(ab)) with self.assertRaisesParseException(expected_msg="Expected AB"): ab.parse_string("C") def testHTMLEntities(self): html_source = dedent( """\ This & that 2 > 1 0 < 1 Don't get excited! I said "Don't get excited!" Copyright © 2021 Dot ⟶ ˙ """ ) transformer = pp.common_html_entity().add_parse_action(pp.replace_html_entity) transformed = transformer.transform_string(html_source) print(transformed) expected = dedent( """\ This & that 2 > 1 0 < 1 Don't get excited! I said "Don't get excited!" Copyright © 2021 Dot ⟶ ˙ """ ) self.assertEqual(expected, transformed) def testInfixNotationBasicArithEval(self): import ast integer = pp.Word(pp.nums).set_parse_action(lambda t: int(t[0])) variable = pp.Word(pp.alphas, exact=1) operand = integer | variable expop = pp.Literal("^") signop = pp.one_of("+ -") multop = pp.one_of("* /") plusop = pp.one_of("+ -") factop = pp.Literal("!") # fmt: off expr = pp.infix_notation( operand, [ (factop, 1, pp.OpAssoc.LEFT), (expop, 2, pp.OpAssoc.RIGHT), (signop, 1, pp.OpAssoc.RIGHT), (multop, 2, pp.OpAssoc.LEFT), (plusop, 2, pp.OpAssoc.LEFT), ], ) # fmt: on test = [ "9 + 2 + 3", "9 + 2 * 3", "(9 + 2) * 3", "(9 + -2) * 3", "(9 + --2) * 3", "(9 + -2) * 3^2^2", "(9! + -2) * 3^2^2", "M*X + B", "M*(X + B)", "1+2*-3^4*5+-+-6", "3!!", ] expected = """[[9, '+', 2, '+', 3]] [[9, '+', [2, '*', 3]]] [[[9, '+', 2], '*', 3]] [[[9, '+', ['-', 2]], '*', 3]] [[[9, '+', ['-', ['-', 2]]], '*', 3]] [[[9, '+', ['-', 2]], '*', [3, '^', [2, '^', 2]]]] [[[[9, '!'], '+', ['-', 2]], '*', [3, '^', [2, '^', 2]]]] [[['M', '*', 'X'], '+', 'B']] [['M', '*', ['X', '+', 'B']]] [[1, '+', [2, '*', ['-', [3, '^', 4]], '*', 5], '+', ['-', ['+', ['-', 6]]]]] [[3, '!', '!']]""".split( "\n" ) expected = [ast.literal_eval(x.strip()) for x in expected] for test_str, exp_list in zip(test, expected): self.assertParseAndCheckList(expr, test_str, exp_list, verbose=True) def testInfixNotationEvalBoolExprUsingAstClasses(self): boolVars = {"True": True, "False": False} class BoolOperand: reprsymbol = "" def __init__(self, t): self.args = t[0][0::2] def __str__(self): sep = f" {self.reprsymbol} " return f"({sep.join(map(str, self.args))})" class BoolAnd(BoolOperand): reprsymbol = "&" def __bool__(self): for a in self.args: if isinstance(a, str): v = boolVars[a] else: v = bool(a) if not v: return False return True class BoolOr(BoolOperand): reprsymbol = "|" def __bool__(self): for a in self.args: if isinstance(a, str): v = boolVars[a] else: v = bool(a) if v: return True return False class BoolNot: def __init__(self, t): self.arg = t[0][1] def __str__(self): return f"~{self.arg}" def __bool__(self): if isinstance(self.arg, str): v = boolVars[self.arg] else: v = bool(self.arg) return not v boolOperand = pp.Word(pp.alphas, max=1, as_keyword=True) | pp.one_of( "True False" ) # fmt: off boolExpr = pp.infix_notation( boolOperand, [ ("not", 1, pp.OpAssoc.RIGHT, BoolNot), ("and", 2, pp.OpAssoc.LEFT, BoolAnd), ("or", 2, pp.OpAssoc.LEFT, BoolOr), ], ) # fmt: on test = [ "p and not q", "not not p", "not(p and q)", "q or not p and r", "q or not p or not r", "q or not (p and r)", "p or q or r", "p or q or r and False", "(p or q or r) and False", ] boolVars["p"] = True boolVars["q"] = False boolVars["r"] = True print("p =", boolVars["p"]) print("q =", boolVars["q"]) print("r =", boolVars["r"]) print() for t in test: res = boolExpr.parse_string(t, parse_all=True) print(t, "\n", res[0], "=", bool(res[0]), "\n") expected = eval(t, {}, boolVars) self.assertEqual(expected, bool(res[0]), f"failed boolean eval test {t}") def testInfixNotationMinimalParseActionCalls(self): count = 0 def evaluate_int(t): nonlocal count value = int(t[0]) print("evaluate_int", value) count += 1 return value integer = pp.Word(pp.nums).set_parse_action(evaluate_int) variable = pp.Word(pp.alphas, exact=1) operand = integer | variable expop = pp.Literal("^") signop = pp.one_of("+ -") multop = pp.one_of("* /") plusop = pp.one_of("+ -") factop = pp.Literal("!") # fmt: off expr = pp.infix_notation( operand, [ (factop, 1, pp.OpAssoc.LEFT), (expop, 2, pp.OpAssoc.LEFT), (signop, 1, pp.OpAssoc.RIGHT), (multop, 2, pp.OpAssoc.LEFT), (plusop, 2, pp.OpAssoc.LEFT), ], ) # fmt: on test = ["9"] for t in test: count = 0 print(f"{t!r} => {expr.parse_string(t, parse_all=True)} (count={count})") self.assertEqual(1, count, "count evaluated too many times!") def testInfixNotationWithParseActions(self): word = pp.Word(pp.alphas) def supLiteral(s): """Returns the suppressed literal s""" return pp.Literal(s).suppress() def booleanExpr(atom): ops = [ (supLiteral("!"), 1, pp.OpAssoc.RIGHT, lambda s, l, t: ["!", t[0][0]]), (pp.one_of("= !="), 2, pp.OpAssoc.LEFT), (supLiteral("&"), 2, pp.OpAssoc.LEFT, lambda s, l, t: ["&", t[0]]), (supLiteral("|"), 2, pp.OpAssoc.LEFT, lambda s, l, t: ["|", t[0]]), ] return pp.infix_notation(atom, ops) f = booleanExpr(word) + pp.StringEnd() tests = [ ("bar = foo", [["bar", "=", "foo"]]), ( "bar = foo & baz = fee", ["&", [["bar", "=", "foo"], ["baz", "=", "fee"]]], ), ] for test, expected in tests: print(test) results = f.parse_string(test, parse_all=True) print(results) self.assertParseResultsEquals(results, expected_list=expected) print() def testInfixNotationGrammarTest5(self): expop = pp.Literal("**") signop = pp.one_of("+ -") multop = pp.one_of("* /") plusop = pp.one_of("+ -") class ExprNode: def __init__(self, tokens): self.tokens = tokens[0] def eval(self): return None class NumberNode(ExprNode): def eval(self): return self.tokens class SignOp(ExprNode): def eval(self): mult = {"+": 1, "-": -1}[self.tokens[0]] return mult * self.tokens[1].eval() class BinOp(ExprNode): opn_map = {} def eval(self): ret = self.tokens[0].eval() for op, operand in zip(self.tokens[1::2], self.tokens[2::2]): ret = self.opn_map[op](ret, operand.eval()) return ret class ExpOp(BinOp): opn_map = {"**": lambda a, b: b**a} class MultOp(BinOp): import operator opn_map = {"*": operator.mul, "/": operator.truediv} class AddOp(BinOp): import operator opn_map = {"+": operator.add, "-": operator.sub} operand = ppc.number().set_parse_action(NumberNode) # fmt: off expr = pp.infix_notation( operand, [ (expop, 2, pp.OpAssoc.LEFT, (lambda pr: [pr[0][::-1]], ExpOp)), (signop, 1, pp.OpAssoc.RIGHT, SignOp), (multop, 2, pp.OpAssoc.LEFT, MultOp), (plusop, 2, pp.OpAssoc.LEFT, AddOp), ], ) # fmt: on tests = """\ 2+7 2**3 2**3**2 3**9 3**3**2 """ for t in tests.splitlines(): t = t.strip() if not t: continue parsed = expr.parse_string(t, parse_all=True) eval_value = parsed[0].eval() self.assertEqual( eval(t), eval_value, f"Error evaluating {t!r}, expected {eval(t)!r}, got {eval_value!r}", ) def testInfixNotationExceptions(self): num = pp.Word(pp.nums) # fmt: off # arity 3 with None opExpr - should raise ValueError with self.assertRaises(ValueError): expr = pp.infix_notation( num, [ (None, 3, pp.OpAssoc.LEFT), ] ) # arity 3 with invalid tuple - should raise ValueError with self.assertRaises(ValueError): expr = pp.infix_notation( num, [ (("+", "-", "*"), 3, pp.OpAssoc.LEFT), ] ) # left arity > 3 - should raise ValueError with self.assertRaises(ValueError): expr = pp.infix_notation( num, [ ("*", 4, pp.OpAssoc.LEFT), ] ) # right arity > 3 - should raise ValueError with self.assertRaises(ValueError): expr = pp.infix_notation( num, [ ("*", 4, pp.OpAssoc.RIGHT), ] ) # assoc not from OpAssoc - should raise ValueError with self.assertRaises(ValueError): expr = pp.infix_notation( num, [ ("*", 2, "LEFT"), ] ) # fmt: on def testInfixNotationWithNonOperators(self): # left arity 2 with None expr # right arity 2 with None expr num = pp.Word(pp.nums).add_parse_action(pp.token_map(int)) ident = ppc.identifier() # fmt: off for assoc in (pp.OpAssoc.LEFT, pp.OpAssoc.RIGHT): expr = pp.infix_notation( num | ident, [ (None, 2, assoc), ("+", 2, pp.OpAssoc.LEFT), ] ) self.assertParseAndCheckList(expr, "3x+2", [[[3, "x"], "+", 2]]) # fmt: on def testInfixNotationTernaryOperator(self): # left arity 3 # right arity 3 num = pp.Word(pp.nums).add_parse_action(pp.token_map(int)) # fmt: off for assoc in (pp.OpAssoc.LEFT, pp.OpAssoc.RIGHT): expr = pp.infix_notation( num, [ ("+", 2, pp.OpAssoc.LEFT), (("?", ":"), 3, assoc), ] ) self.assertParseAndCheckList( expr, "3 + 2? 12: 13", [[[3, "+", 2], "?", 12, ":", 13]] ) # fmt: on def testInfixNotationWithAlternateParenSymbols(self): num = pp.Word(pp.nums).add_parse_action(pp.token_map(int)) # fmt: off expr = pp.infix_notation( num, [ ("+", 2, pp.OpAssoc.LEFT), ], lpar="(", rpar=")", ) self.assertParseAndCheckList( expr, "3 + (2 + 11)", [[3, '+', [2, '+', 11]]] ) expr = pp.infix_notation( num, [ ("+", 2, pp.OpAssoc.LEFT), ], lpar="<", rpar=">", ) self.assertParseAndCheckList( expr, "3 + <2 + 11>", [[3, '+', [2, '+', 11]]] ) expr = pp.infix_notation( num, [ ("+", 2, pp.OpAssoc.LEFT), ], lpar=pp.Literal("<"), rpar=pp.Literal(">"), ) self.assertParseAndCheckList( expr, "3 + <2 + 11>", [[3, '+', ['<', [2, '+', 11], '>']]] ) expr = pp.infix_notation( num, [ ("+", 2, pp.OpAssoc.LEFT), ], lpar=pp.Literal("<<"), rpar=pp.Literal(">>"), ) self.assertParseAndCheckList( expr, "3 + <<2 + 11>>", [[3, '+', ['<<', [2, '+', 11], '>>']]] ) # fmt: on def testParseResultsPickle(self): import pickle # test 1 body = pp.make_html_tags("BODY")[0] result = body.parse_string( "", parse_all=True ) print(result.dump()) for protocol in range(pickle.HIGHEST_PROTOCOL + 1): print("Test pickle dump protocol", protocol) try: pickleString = pickle.dumps(result, protocol) except Exception as e: print("dumps exception:", e) newresult = pp.ParseResults() else: newresult = pickle.loads(pickleString) print(newresult.dump()) self.assertEqual( result.dump(), newresult.dump(), f"Error pickling ParseResults object (protocol={protocol})", ) def testParseResultsPickle2(self): import pickle word = pp.Word(pp.alphas + "'.") salutation = pp.OneOrMore(word) comma = pp.Literal(",") greetee = pp.OneOrMore(word) endpunc = pp.one_of("! ?") greeting = ( salutation("greeting") + pp.Suppress(comma) + greetee("greetee") + endpunc("punc*")[1, ...] ) string = "Good morning, Miss Crabtree!" result = greeting.parse_string(string, parse_all=True) self.assertParseResultsEquals( result, ["Good", "morning", "Miss", "Crabtree", "!"], { "greeting": ["Good", "morning"], "greetee": ["Miss", "Crabtree"], "punc": ["!"], }, ) print(result.dump()) for protocol in range(pickle.HIGHEST_PROTOCOL + 1): print("Test pickle dump protocol", protocol) try: pickleString = pickle.dumps(result, protocol) except Exception as e: print("dumps exception:", e) newresult = pp.ParseResults() else: newresult = pickle.loads(pickleString) print(newresult.dump()) self.assertEqual( newresult.dump(), result.dump(), f"failed to pickle/unpickle ParseResults: expected {result!r}, got {newresult!r}", ) def testParseResultsPickle3(self): import pickle # result with aslist=False res_not_as_list = pp.Word("ABC").parse_string("BABBAB", parse_all=True) # result with aslist=True res_as_list = pp.Group(pp.Word("ABC")).parse_string("BABBAB", parse_all=True) # result with modal=True res_modal = pp.Word("ABC")("name").parse_string("BABBAB", parse_all=True) # self.assertTrue(res_modal._modal) # result with modal=False res_not_modal = pp.Word("ABC")("name*").parse_string("BABBAB", parse_all=True) # self.assertFalse(res_not_modal._modal) for result in (res_as_list, res_not_as_list, res_modal, res_not_modal): for protocol in range(pickle.HIGHEST_PROTOCOL + 1): print("Test pickle dump protocol", protocol) try: pickleString = pickle.dumps(result, protocol) except Exception as e: print("dumps exception:", e) newresult = pp.ParseResults() else: newresult = pickle.loads(pickleString) print(newresult.dump()) self.assertEqual( newresult.dump(), result.dump(), f"failed to pickle/unpickle ParseResults: expected {result!r}, got {newresult!r}", ) def testParseResultsInsertWithResultsNames(self): test_string = "1 2 3 dice rolled first try" wd = pp.Word(pp.alphas) num = ppc.number expr = ( pp.Group(num[1, ...])("nums") + wd("label") + pp.Group(wd[...])("additional") ) result = expr.parse_string(test_string, parse_all=True) print("Pre-insert") print(result.dump()) result.insert(1, sum(result.nums)) print("\nPost-insert") print(result.dump()) self.assertParseResultsEquals( result, expected_list=[[1, 2, 3], 6, "dice", ["rolled", "first", "try"]], expected_dict={ "additional": ["rolled", "first", "try"], "label": "dice", "nums": [1, 2, 3], }, ) def testParseResultsStringListUsingCombine(self): test_string = "1 2 3 dice rolled first try" wd = pp.Word(pp.alphas) num = ppc.number expr = pp.Combine( pp.Group(num[1, ...])("nums") + wd("label") + pp.Group(wd[...])("additional"), join_string="/", adjacent=False, ) self.assertEqual( "123/dice/rolledfirsttry", expr.parse_string(test_string, parse_all=True)[0] ) def testParseResultsAcceptingACollectionTypeValue(self): # from Issue #276 - ParseResults parameterizes generic types if passed as the value of toklist parameter # https://github.com/pyparsing/pyparsing/issues/276?notification_referrer_id=MDE4Ok5vdGlmaWNhdGlvblRocmVhZDE4MzU4NDYwNzI6MzgzODc1 # # behavior of ParseResults code changed with Python 3.9 results_with_int = pp.ParseResults(toklist=int, name="type_", aslist=False) self.assertEqual(int, results_with_int["type_"]) results_with_tuple = pp.ParseResults(toklist=tuple, name="type_", aslist=False) self.assertEqual(tuple, results_with_tuple["type_"]) def testParseResultsReturningDunderAttribute(self): # from Issue #208 parser = pp.Word(pp.alphas)("A") result = parser.parse_string("abc", parse_all=True) print(result.dump()) self.assertEqual("abc", result.A) self.assertEqual("", result.B) with self.assertRaises(AttributeError): result.__xyz__ def testParseResultsNamedResultWithEmptyString(self): # from Issue #470 # Check which values can be returned from a parse action for test_value, expected_in_result_by_name in [ ("x", True), ("", True), (True, True), (False, True), (1, True), (0, True), (None, True), (b"", True), (b"a", True), ([], False), ((), False), ]: msg = ( f"value = {test_value!r}," f" expected X {'not ' if not expected_in_result_by_name else ''}in result" ) with self.subTest(msg): print(msg) grammar = ( (pp.Suppress("a") + pp.ZeroOrMore("x")) .add_parse_action(lambda p: test_value) .set_results_name("X") ) result = grammar.parse_string("a") print(result.dump()) if expected_in_result_by_name: self.assertIn( "X", result, f"Expected X not found for parse action value {test_value!r}", ) print(repr(result["X"])) else: self.assertNotIn( "X", result, f"Unexpected X found for parse action value {test_value!r}", ) with self.assertRaises(KeyError): print(repr(result["X"])) print() # Do not add a parse result. msg = "value = , expected X in result" with self.subTest(msg): print(msg) grammar = (pp.Suppress("a") + pp.ZeroOrMore("x")).set_results_name("X") result = grammar.parse_string("a") print(result.dump()) self.assertIn("X", result, f"Expected X not found with no parse action") print() # Test by directly creating a ParseResults print("Create empty string value directly") result = pp.ParseResults("", name="X") print(result.dump()) self.assertIn( "X", result, "failed to construct ParseResults with named value using empty string", ) print(repr(result["X"])) print() print("Create empty string value from a dict") result = pp.ParseResults.from_dict({"X": ""}) print(result.dump()) self.assertIn( "X", result, "failed to construct ParseResults with named value using from_dict", ) print(repr(result["X"])) def testMatchOnlyAtCol(self): """successfully use match_only_at_col helper function""" expr = pp.Word(pp.nums) expr.set_parse_action(pp.match_only_at_col(5)) largerExpr = pp.ZeroOrMore(pp.Word("A")) + expr + pp.ZeroOrMore(pp.Word("A")) res = largerExpr.parse_string("A A 3 A", parse_all=True) print(res.dump()) def testMatchOnlyAtColErr(self): """raise a ParseException in match_only_at_col with incorrect col""" expr = pp.Word(pp.nums) expr.set_parse_action(pp.match_only_at_col(1)) largerExpr = pp.ZeroOrMore(pp.Word("A")) + expr + pp.ZeroOrMore(pp.Word("A")) with self.assertRaisesParseException(): largerExpr.parse_string("A A 3 A", parse_all=True) def testParseResultsWithNamedTuple(self): expr = pp.Literal("A")("Achar") expr.set_parse_action(pp.replace_with(tuple(["A", "Z"]))) res = expr.parse_string("A", parse_all=True) print(repr(res)) print(res.Achar) self.assertParseResultsEquals( res, expected_dict={"Achar": ("A", "Z")}, msg=f"Failed accessing named results containing a tuple, got {res.Achar!r}", ) def testParserElementAddOperatorWithOtherTypes(self): """test the overridden "+" operator with other data types""" # ParserElement + str with self.subTest(): expr = pp.Word(pp.alphas)("first") + pp.Word(pp.alphas)("second") + "suf" result = expr.parse_string("spam eggs suf", parse_all=True) print(result) expected_l = ["spam", "eggs", "suf"] self.assertParseResultsEquals( result, expected_l, msg="issue with ParserElement + str" ) # str + ParserElement with self.subTest(): expr = "pre" + pp.Word(pp.alphas)("first") + pp.Word(pp.alphas)("second") result = expr.parse_string("pre spam eggs", parse_all=True) print(result) expected_l = ["pre", "spam", "eggs"] self.assertParseResultsEquals( result, expected_l, msg="issue with str + ParserElement" ) # ParserElement + int with self.subTest(): expr = None with self.assertRaises(TypeError, msg="failed to warn ParserElement + int"): expr = pp.Word(pp.alphas)("first") + pp.Word(pp.alphas)("second") + 12 self.assertEqual(expr, None) # int + ParserElement with self.subTest(): expr = None with self.assertRaises(TypeError, msg="failed to warn int + ParserElement"): expr = 12 + pp.Word(pp.alphas)("first") + pp.Word(pp.alphas)("second") self.assertEqual(expr, None) def testParserElementSubOperatorWithOtherTypes(self): """test the overridden "-" operator with other data types""" # ParserElement - str with self.subTest(): expr = pp.Word(pp.alphas)("first") + pp.Word(pp.alphas)("second") - "suf" result = expr.parse_string("spam eggs suf", parse_all=True) print(result) expected = ["spam", "eggs", "suf"] self.assertParseResultsEquals( result, expected, msg="issue with ParserElement - str" ) # str - ParserElement with self.subTest(): expr = "pre" - pp.Word(pp.alphas)("first") + pp.Word(pp.alphas)("second") result = expr.parse_string("pre spam eggs", parse_all=True) print(result) expected = ["pre", "spam", "eggs"] self.assertParseResultsEquals( result, expected, msg="issue with str - ParserElement" ) # ParserElement - int with self.subTest(): expr = None with self.assertRaises(TypeError, msg="failed to warn ParserElement - int"): expr = pp.Word(pp.alphas)("first") + pp.Word(pp.alphas)("second") - 12 self.assertEqual(expr, None) # int - ParserElement with self.subTest(): expr = None with self.assertRaises(TypeError, msg="failed to warn int - ParserElement"): expr = 12 - pp.Word(pp.alphas)("first") + pp.Word(pp.alphas)("second") self.assertEqual(expr, None) def testParserElementMulOperatorWithTuples(self): """test ParserElement "*" with various tuples""" # ParserElement * (None, n) expr = pp.Word(pp.alphas)("first") + pp.Word(pp.nums)("second*") * (None, 3) with self.subTest(): results1 = expr.parse_string("spam", parse_all=True) print(results1.dump()) expected = ["spam"] self.assertParseResultsEquals( results1, expected, msg="issue with ParserElement * w/ optional matches" ) with self.subTest(): results2 = expr.parse_string("spam 12 23 34", parse_all=True) print(results2.dump()) expected = ["spam", "12", "23", "34"] self.assertParseResultsEquals( results2, expected, msg="issue with ParserElement * w/ optional matches" ) # ParserElement * (1, 1) with self.subTest(): expr = pp.Word(pp.alphas)("first") + pp.Word(pp.nums)("second*") * (1, 1) results = expr.parse_string("spam 45", parse_all=True) print(results.dump()) expected = ["spam", "45"] self.assertParseResultsEquals( results, expected, msg="issue with ParserElement * (1, 1)" ) # ParserElement * (1, 1+n) with self.subTest(): expr = pp.Word(pp.alphas)("first") + pp.Word(pp.nums)("second*") * (1, 3) results1 = expr.parse_string("spam 100", parse_all=True) print(results1.dump()) expected = ["spam", "100"] self.assertParseResultsEquals( results1, expected, msg="issue with ParserElement * (1, 1+n)" ) with self.subTest(): results2 = expr.parse_string("spam 100 200 300", parse_all=True) print(results2.dump()) expected = ["spam", "100", "200", "300"] self.assertParseResultsEquals( results2, expected, msg="issue with ParserElement * (1, 1+n)" ) # ParserElement * (lesser, greater) with self.subTest(): expr = pp.Word(pp.alphas)("first") + pp.Word(pp.nums)("second*") * (2, 3) results1 = expr.parse_string("spam 1 2", parse_all=True) print(results1.dump()) expected = ["spam", "1", "2"] self.assertParseResultsEquals( results1, expected, msg="issue with ParserElement * (lesser, greater)" ) with self.subTest(): results2 = expr.parse_string("spam 1 2 3", parse_all=True) print(results2.dump()) expected = ["spam", "1", "2", "3"] self.assertParseResultsEquals( results2, expected, msg="issue with ParserElement * (lesser, greater)" ) # ParserElement * (greater, lesser) with self.subTest(): with self.assertRaises( ValueError, msg="ParserElement * (greater, lesser) should raise error" ): expr = pp.Word(pp.alphas)("first") + pp.Word(pp.nums)("second") * (3, 2) # ParserElement * (str, str) with self.subTest(): with self.assertRaises( TypeError, msg="ParserElement * (str, str) should raise error" ): expr = pp.Word(pp.alphas)("first") + pp.Word(pp.nums)("second") * ( "2", "3", ) def testParserElementMulByZero(self): alpwd = pp.Word(pp.alphas) numwd = pp.Word(pp.nums) test_string = "abd def ghi jkl" with self.subTest(): parser = alpwd * 2 + numwd * 0 + alpwd * 2 self.assertParseAndCheckList( parser, test_string, expected_list=test_string.split() ) with self.subTest(): parser = alpwd * 2 + numwd * (0, 0) + alpwd * 2 self.assertParseAndCheckList( parser, test_string, expected_list=test_string.split() ) def testParserElementMulOperatorWithOtherTypes(self): """test the overridden "*" operator with other data types""" # ParserElement * str with self.subTest(): with self.assertRaises( TypeError, msg="ParserElement * str should raise error" ): expr = pp.Word(pp.alphas)("first") + pp.Word(pp.nums)("second") * "3" # str * ParserElement with self.subTest(): with self.assertRaises( TypeError, msg="str * ParserElement should raise error" ): expr = pp.Word(pp.alphas)("first") + "3" * pp.Word(pp.nums)("second") # ParserElement * int with self.subTest(): expr = pp.Word(pp.alphas)("first") + pp.Word(pp.nums)("second*") * 2 results = expr.parse_string("spam 11 22", parse_all=True) print(results.dump()) expected = ["spam", "11", "22"] self.assertParseResultsEquals( results, expected, msg="issue with ParserElement * int" ) # int * ParserElement with self.subTest(): expr = pp.Word(pp.alphas)("first") + 2 * pp.Word(pp.nums)("second*") results = expr.parse_string("spam 111 222", parse_all=True) print(results.dump()) expected = ["spam", "111", "222"] self.assertParseResultsEquals( results, expected, msg="issue with int * ParserElement" ) def testParserElementMatchFirstOperatorWithOtherTypes(self): """test the overridden "|" operator with other data types""" # ParserElement | int with self.subTest(): expr = None with self.assertRaises(TypeError, msg="failed to warn ParserElement | int"): expr = pp.Word(pp.alphas)("first") + (pp.Word(pp.alphas)("second") | 12) self.assertEqual(expr, None) # int | ParserElement with self.subTest(): expr = None with self.assertRaises(TypeError, msg="failed to warn int | ParserElement"): expr = pp.Word(pp.alphas)("first") + (12 | pp.Word(pp.alphas)("second")) self.assertEqual(expr, None) def testParserElementMatchLongestWithOtherTypes(self): """test the overridden "^" operator with other data types""" # ParserElement ^ str with self.subTest(): expr = pp.Word(pp.alphas)("first") + (pp.Word(pp.nums)("second") ^ "eggs") result = expr.parse_string("spam eggs", parse_all=True) print(result) expected = ["spam", "eggs"] self.assertParseResultsEquals( result, expected, msg="issue with ParserElement ^ str" ) # str ^ ParserElement with self.subTest(): expr = ("pre" ^ pp.Word("pr")("first")) + pp.Word(pp.alphas)("second") result = expr.parse_string("pre eggs", parse_all=True) print(result) expected = ["pre", "eggs"] self.assertParseResultsEquals( result, expected, msg="issue with str ^ ParserElement" ) # ParserElement ^ int with self.subTest(): expr = None with self.assertRaises(TypeError, msg="failed to warn ParserElement ^ int"): expr = pp.Word(pp.alphas)("first") + (pp.Word(pp.alphas)("second") ^ 54) self.assertEqual(expr, None) # int ^ ParserElement with self.subTest(): expr = None with self.assertRaises(TypeError, msg="failed to warn int ^ ParserElement"): expr = pp.Word(pp.alphas)("first") + (65 ^ pp.Word(pp.alphas)("second")) self.assertEqual(expr, None) def testParserElementEachOperatorWithOtherTypes(self): """test the overridden "&" operator with other data types""" # ParserElement & str with self.subTest(): expr = pp.Word(pp.alphas)("first") + (pp.Word(pp.alphas)("second") & "and") with self.assertRaisesParseException(msg="issue with ParserElement & str"): result = expr.parse_string("spam and eggs", parse_all=True) # str & ParserElement with self.subTest(): expr = pp.Word(pp.alphas)("first") + ("and" & pp.Word(pp.alphas)("second")) result = expr.parse_string("spam and eggs", parse_all=True) print(result.dump()) expected_l = ["spam", "and", "eggs"] expected_d = {"first": "spam", "second": "eggs"} self.assertParseResultsEquals( result, expected_list=expected_l, expected_dict=expected_d, msg="issue with str & ParserElement", ) # ParserElement & int with self.subTest(): expr = None with self.assertRaises(TypeError, msg="failed to warn ParserElement & int"): expr = pp.Word(pp.alphas)("first") + (pp.Word(pp.alphas) & 78) self.assertEqual(expr, None) # int & ParserElement with self.subTest(): expr = None with self.assertRaises(TypeError, msg="failed to warn int & ParserElement"): expr = pp.Word(pp.alphas)("first") + (89 & pp.Word(pp.alphas)) self.assertEqual(expr, None) def testLshiftOperatorWithOtherTypes(self): # Forward << ParserElement with self.subTest(): f = pp.Forward() f << pp.Word(pp.alphas)[...] test_string = "sljdf sldkjf Ljs" result = f.parse_string(test_string) print(result) self.assertEqual(test_string.split(), result.as_list()) # Forward << str with self.subTest(): f = pp.Forward() f << "AAA" test_string = "AAA" result = f.parse_string(test_string) print(result) self.assertEqual(test_string.split(), result.as_list()) # Forward << int with self.subTest(): f = pp.Forward() with self.assertRaises(TypeError, msg="failed to warn int & ParserElement"): f << 12 def testParserElementPassedThreeArgsToMultiplierShorthand(self): """test the ParserElement form expr[m,n,o]""" with self.assertRaises( TypeError, msg="failed to warn three index arguments to expr[m, n, o]" ): expr = pp.Word(pp.alphas)[2, 3, 4] def testParserElementPassedStrToMultiplierShorthand(self): """test the ParserElement form expr[str]""" with self.assertRaises( TypeError, msg="failed to raise expected error using string multiplier" ): expr2 = pp.Word(pp.alphas)["2"] def testParseResultsNewEdgeCases(self): """test less common paths of ParseResults.__new__()""" parser = pp.Word(pp.alphas)[...] result = parser.parse_string("sldkjf sldkjf", parse_all=True) # hasattr uses __getattr__, which for ParseResults will return "" if the # results name is not defined. So hasattr() won't work with ParseResults. # Have to use __contains__ instead to test for existence. # self.assertFalse(hasattr(result, "A")) self.assertFalse("A" in result) # create new ParseResults w/ None result1 = pp.ParseResults(None) print(result1.dump()) self.assertParseResultsEquals( result1, [], msg="ParseResults(None) should return empty ParseResults" ) # create new ParseResults w/ integer name result2 = pp.ParseResults(name=12) print(result2.dump()) self.assertEqual( "12", result2.get_name(), "ParseResults int name should be accepted and converted to str", ) # create new ParseResults w/ generator type gen = (a for a in range(1, 6)) result3 = pp.ParseResults(gen) print(result3.dump()) expected3 = [1, 2, 3, 4, 5] self.assertParseResultsEquals( result3, expected3, msg="issue initializing ParseResults w/ gen type" ) def testParseResultsReversed(self): """test simple case of reversed(ParseResults)""" tst = "1 2 3 4 5" expr = pp.OneOrMore(pp.Word(pp.nums)) result = expr.parse_string(tst, parse_all=True) reversed_list = [ii for ii in reversed(result)] print(reversed_list) expected = ["5", "4", "3", "2", "1"] self.assertEqual( expected, reversed_list, msg="issue calling reversed(ParseResults)" ) def testParseResultsValues(self): """test simple case of ParseResults.values()""" expr = pp.Word(pp.alphas)("first") + pp.Word(pp.alphas)("second") result = expr.parse_string("spam eggs", parse_all=True) values_set = set(result.values()) print(values_set) expected = {"spam", "eggs"} self.assertEqual( expected, values_set, msg="issue calling ParseResults.values()" ) def testParseResultsAppend(self): """test simple case of ParseResults.append()""" # use a parse action to compute the sum of the parsed integers, and add it to the end def append_sum(tokens): tokens.append(sum(map(int, tokens))) expr = pp.OneOrMore(pp.Word(pp.nums)).add_parse_action(append_sum) result = expr.parse_string("0 123 321", parse_all=True) expected = ["0", "123", "321", 444] print(result.dump()) self.assertParseResultsEquals( result, expected, msg="issue with ParseResults.append()" ) def testParseResultsClear(self): """test simple case of ParseResults.clear()""" tst = "spam eggs" expr = pp.Word(pp.alphas)("first") + pp.Word(pp.alphas)("second") result = expr.parse_string(tst, parse_all=True) print(result.dump()) self.assertParseResultsEquals( result, ["spam", "eggs"], msg="issue with ParseResults before clear()" ) result.clear() print(result.dump()) self.assertParseResultsEquals( result, expected_list=[], expected_dict={}, msg="issue with ParseResults.clear()", ) def testParseResultsExtendWithString(self): """test ParseResults.extend() with input of type str""" # use a parse action to append the reverse of the matched strings to make a palindrome def make_palindrome(tokens): tokens.extend(reversed([t[::-1] for t in tokens])) tst = "abc def ghi" expr = pp.OneOrMore(pp.Word(pp.alphas)) result = expr.add_parse_action(make_palindrome).parse_string( tst, parse_all=True ) print(result.dump()) expected = ["abc", "def", "ghi", "ihg", "fed", "cba"] self.assertParseResultsEquals( result, expected, msg="issue with ParseResults.extend(str)" ) def testParseResultsExtendWithParseResults(self): """test ParseResults.extend() with input of type ParseResults""" expr = pp.OneOrMore(pp.Word(pp.alphas)) result1 = expr.parse_string("spam eggs", parse_all=True) result2 = expr.parse_string("foo bar", parse_all=True) result1.extend(result2) print(result1.dump()) expected = ["spam", "eggs", "foo", "bar"] self.assertParseResultsEquals( result1, expected, msg="issue with ParseResults.extend(ParseResults)" ) def testQuotedStringLoc(self): expr = pp.QuotedString("'") expr.add_parse_action(lambda t: t[0].upper()) test_string = "Using 'quotes' for 'sarcasm' or 'emphasis' is not good 'style'." transformed = expr.transform_string(test_string) print(test_string) print(transformed) expected = re.sub(r"'([^']+)'", lambda match: match[1].upper(), test_string) self.assertEqual(expected, transformed) def testParseResultsWithNestedNames(self): from pyparsing import ( Dict, Literal, Group, Optional, Regex, QuotedString, one_of, Or, CaselessKeyword, ZeroOrMore, ) RELATION_SYMBOLS = "= > < >= <= <> ==" def _set_info(string, location, tokens): for t in tokens: try: t["_info_"] = (string, location) except TypeError: pass tokens["_info_"] = (string, location) def keywords(name): words = "any all within encloses adj".split() return Or(map(CaselessKeyword, words)) charString1 = Group(Regex(r'[^()=<>"/\s]+'))("identifier") charString1.add_parse_action(_set_info) charString2 = Group(QuotedString('"', "\\"))("quoted") charString2.add_parse_action(_set_info) term = Group(charString1 | charString2) modifier_key = charString1 # relations comparitor_symbol = one_of(RELATION_SYMBOLS) named_comparitors = keywords("comparitors") comparitor = Group(comparitor_symbol | named_comparitors)("comparitor") comparitor.add_parse_action(_set_info) def modifier_list1(key): modifier = Dict( Literal("/") + Group(modifier_key(key))("name") + Optional(comparitor_symbol("symbol") + term("value")) )("modifier") modifier.add_parse_action(_set_info) return ZeroOrMore(modifier)("modifier_list") def modifier_list2(key): modifier = Dict( Literal("/") + Group(modifier_key(key))("name") + Optional(comparitor_symbol("symbol") + term("value")), asdict=True, )("modifier") modifier.add_parse_action(_set_info) return ZeroOrMore(modifier)("modifier_list") def modifier_list3(key): modifier = Group( # this line is different from the others, must group to get results names Dict( Literal("/") + Group(modifier_key(key))("name") + Optional(comparitor_symbol("symbol") + term("value")) ) ) modifier.add_parse_action(_set_info) return ZeroOrMore(modifier)("modifier_list") def modifier_list4(key): modifier = Dict( Literal("/") + Group(modifier_key(key))("name") + Optional(comparitor_symbol("symbol") + term("value")), asdict=True, ) modifier.add_parse_action(_set_info) return ZeroOrMore(modifier)("modifier_list") for modifier_list_fn in ( modifier_list1, modifier_list2, modifier_list3, modifier_list4, ): modifier_parser = modifier_list_fn("default") result = modifier_parser.parse_string( "/respectaccents/ignoreaccents", parse_all=True ) for r in result: print(r) print(r.get("_info_")) self.assertEqual([0, 15], [r["_info_"][1] for r in result]) def testParseResultsFromDict(self): """test helper classmethod ParseResults.from_dict()""" dict = { "first": "123", "second": 456, "third": {"threeStr": "789", "threeInt": 789}, } name = "trios" result = pp.ParseResults.from_dict(dict, name=name) print(result.dump()) expected = {name: dict} self.assertParseResultsEquals( result, expected_dict=expected, msg="issue creating ParseResults.from _dict()", ) def testParseResultsDir(self): """test dir(ParseResults)""" dict = {"first": "123", "second": "456", "third": "789"} name = "trios" result = pp.ParseResults.from_dict(dict, name=name) dir_result = dir(result) print(dir_result) self.assertIn( name, dir_result, msg="name value wasn't returned by dir(ParseResults)" ) self.assertIn( "as_list", dir_result, msg="as_list was not returned by dir(ParseResults)" ) def testParseResultsInsert(self): """test ParseResults.insert() with named tokens""" from random import randint result = pp.Word(pp.alphas)[...].parse_string( "A B C D E F G H I J", parse_all=True ) compare_list = result.as_list() print(result) print(compare_list) for s in "abcdefghij": index = randint(-5, 5) result.insert(index, s) compare_list.insert(index, s) print(result) print(compare_list) self.assertParseResultsEquals( result, compare_list, msg="issue with ParseResults.insert()" ) def testParseResultsAddingSuppressedTokenWithResultsName(self): parser = "aaa" + (pp.NoMatch() | pp.Suppress("-"))("B") try: dd = parser.parse_string("aaa -").as_dict() except RecursionError: self.fail("fail getting named result when empty") def testParseResultsBool(self): result = pp.Word(pp.alphas)[...].parse_string("AAA", parse_all=True) self.assertTrue(result, "non-empty ParseResults evaluated as False") result = pp.Word(pp.alphas)[...].parse_string("", parse_all=True) self.assertFalse(result, "empty ParseResults evaluated as True") result["A"] = 0 self.assertTrue( result, "ParseResults with empty list but containing a results name evaluated as False", ) def testParseResultsWithAsListWithAndWithoutFlattening(self): ppc = pp.common # define a recursive grammar so we can easily build nested ParseResults LPAR, RPAR = pp.Suppress.using_each("()") fn_call = pp.Forward() fn_arg = fn_call | ppc.identifier | ppc.number fn_call <<= ppc.identifier + pp.Group( LPAR + pp.Optional(pp.DelimitedList(fn_arg)) + RPAR ) tests = [ ("random()", ["random", []]), ("sin(theta)", ["sin", ["theta"]]), ("sin(rad(30))", ["sin", ["rad", [30]]]), ("sin(rad(30), rad(60, 180))", ["sin", ["rad", [30], "rad", [60, 180]]]), ( "sin(rad(30), rad(60, 180), alpha)", ["sin", ["rad", [30], "rad", [60, 180], "alpha"]], ), ] for test_string, expected in tests: with self.subTest(): print(test_string) observed = fn_call.parse_string(test_string, parse_all=True) print(observed.as_list()) self.assertEqual(expected, observed.as_list()) print(observed.as_list(flatten=True)) self.assertEqual(flatten(expected), observed.as_list(flatten=True)) print() def testParseResultsCopy(self): expr = ( pp.Word(pp.nums) + pp.Group(pp.Word(pp.alphas)("key") + "=" + pp.Word(pp.nums)("value"))[...] ) result = expr.parse_string("1 a=100 b=200 c=300") print(result.dump()) r2 = result.copy() print(r2.dump()) # check copy is different, but contained results is the same as in original self.assertFalse(r2 is result, "copy failed") self.assertTrue(r2[1] is result[1], "shallow copy failed") # update result sub-element in place result[1][0] = "z" self.assertParseResultsEquals( result, expected_list=[ "1", ["z", "=", "100"], ["b", "=", "200"], ["c", "=", "300"], ], ) # update contained results, verify list and dict contents are updated as expected result[1][0] = result[1]["key"] = "q" result[1]["xyz"] = 1000 print(result.dump()) self.assertParseResultsEquals( result, expected_list=[ "1", ["q", "=", "100"], ["b", "=", "200"], ["c", "=", "300"], ], ) self.assertParseResultsEquals( result[1], expected_dict={"key": "q", "value": "100", "xyz": 1000} ) # verify that list and dict contents are the same in copy self.assertParseResultsEquals( r2, expected_list=[ "1", ["q", "=", "100"], ["b", "=", "200"], ["c", "=", "300"], ], ) self.assertParseResultsEquals( r2[1], expected_dict={"key": "q", "value": "100", "xyz": 1000} ) def testParseResultsDeepcopy(self): expr = ( pp.Word(pp.nums) + pp.Group(pp.Word(pp.alphas)("key") + "=" + pp.Word(pp.nums)("value"))[...] ) result = expr.parse_string("1 a=100 b=200 c=300") orig_elements = result._toklist[:] r2 = result.deepcopy() print(r2.dump()) # check copy and contained results are different from original self.assertFalse(r2 is result, "copy failed") self.assertFalse(r2[1] is result[1], "deep copy failed") # check copy and original are equal self.assertEqual(result.as_dict(), r2.as_dict()) self.assertEqual(result.as_list(), r2.as_list()) # check original is unchanged self.assertTrue( all( orig_element is result_element for orig_element, result_element in zip(orig_elements, result._toklist) ) ) # update contained results result[1][0] = result[1]["key"] = "q" result[1]["xyz"] = 1000 print(result.dump()) # verify that list and dict contents are unchanged in the copy self.assertParseResultsEquals( r2, expected_list=[ "1", ["a", "=", "100"], ["b", "=", "200"], ["c", "=", "300"], ], ) self.assertParseResultsEquals(r2[1], expected_dict={"key": "a", "value": "100"}) def testParseResultsDeepcopy2(self): expr = ( pp.Word(pp.nums) + pp.Group( pp.Word(pp.alphas)("key") + "=" + pp.Word(pp.nums)("value"), aslist=True )[...] ) result = expr.parse_string("1 a=100 b=200 c=300") r2 = result.deepcopy() print(r2.dump()) # check copy and contained results are different from original self.assertFalse(r2 is result, "copy failed") self.assertFalse(r2[1] is result[1], "deep copy failed") # update contained results result[1][0] = "q" print(result.dump()) # verify that list and dict contents are unchanged in the copy self.assertParseResultsEquals( r2, expected_list=[ "1", ["a", "=", "100"], ["b", "=", "200"], ["c", "=", "300"], ], ) def testParseResultsDeepcopy3(self): expr = ( pp.Word(pp.nums) + pp.Group( ( pp.Word(pp.alphas)("key") + "=" + pp.Word(pp.nums)("value") ).add_parse_action(lambda t: tuple(t)) )[...] ) result = expr.parse_string("1 a=100 b=200 c=300") r2 = result.deepcopy() print(r2.dump()) # check copy and contained results are different from original self.assertFalse(r2 is result, "copy failed") self.assertFalse(r2[1] is result[1], "deep copy failed") # update contained results result[1][0] = "q" print(result.dump()) # verify that list and dict contents are unchanged in the copy self.assertParseResultsEquals( r2, expected_list=[ "1", [("a", "=", "100")], [("b", "=", "200")], [("c", "=", "300")], ], ) def testIgnoreString(self): """test ParserElement.ignore() passed a string arg""" tst = "I like totally like love pickles" expr = pp.Word(pp.alphas)[...].ignore("like") result = expr.parse_string(tst, parse_all=True) print(result) expected = ["I", "totally", "love", "pickles"] self.assertParseResultsEquals(result, expected, msg="issue with ignore(string)") def testParseHTMLTags(self): test = """ """ results = [ ("startBody", False, "", ""), ("startBody", False, "#00FFCC", ""), ("startBody", True, "#00FFAA", ""), ("startBody", False, "#00FFBB", "black"), ("startBody", True, "", ""), ("endBody", False, "", ""), ] bodyStart, bodyEnd = pp.make_html_tags("BODY") resIter = iter(results) for t, s, e in (bodyStart | bodyEnd).scan_string(test): print(test[s:e], "->", t) (expectedType, expectedEmpty, expectedBG, expectedFG) = next(resIter) print(t.dump()) if "startBody" in t: self.assertEqual( expectedEmpty, bool(t.empty), f"expected {expectedEmpty and 'empty' or 'not empty'} token," f" got {t.empty and 'empty' or 'not empty'}", ) self.assertEqual( expectedBG, t.bgcolor, f"failed to match BGCOLOR, expected {expectedBG}, got {t.bgcolor}", ) self.assertEqual( expectedFG, t.fgcolor, f"failed to match FGCOLOR, expected {expectedFG}, got {t.bgcolor}", ) elif "endBody" in t: print("end tag") pass else: print("BAD!!!") def testSetParseActionUncallableErr(self): """raise a TypeError in set_parse_action() by adding uncallable arg""" expr = pp.Literal("A")("Achar") uncallable = 12 with self.assertRaises(TypeError): expr.set_parse_action(uncallable) res = expr.parse_string("A", parse_all=True) print(res.dump()) def testMulWithNegativeNumber(self): """raise a ValueError in __mul__ by multiplying a negative number""" with self.assertRaises(ValueError): pp.Literal("A")("Achar") * (-1) def testMulWithEllipsis(self): """multiply an expression with Ellipsis as ``expr * ...`` to match ZeroOrMore""" expr = pp.Literal("A")("Achar") * ... res = expr.parse_string("A", parse_all=True) self.assertEqual( ["A"], res.as_list(), "expected expr * ... to match ZeroOrMore" ) print(res.dump()) def testUpcaseDowncaseUnicode(self): import sys ppu = pp.pyparsing_unicode a = "\u00bfC\u00f3mo esta usted?" if not JYTHON_ENV: ualphas = ppu.alphas else: ualphas = "".join( chr(i) for i in list(range(0xD800)) + list(range(0xE000, sys.maxunicode)) if chr(i).isalpha() ) uword = pp.Word(ualphas).set_parse_action(ppc.upcase_tokens) print = lambda *args: None print(uword.search_string(a)) uword = pp.Word(ualphas).set_parse_action(ppc.downcase_tokens) print(uword.search_string(a)) kw = pp.Keyword("mykey", caseless=True).set_parse_action(ppc.upcase_tokens)( "rname" ) ret = kw.parse_string("mykey", parse_all=True) print(ret.rname) self.assertEqual( "MYKEY", ret.rname, "failed to upcase with named result (pyparsing_common)" ) kw = pp.Keyword("MYKEY", caseless=True).set_parse_action(ppc.downcase_tokens)( "rname" ) ret = kw.parse_string("mykey", parse_all=True) print(ret.rname) self.assertEqual("mykey", ret.rname, "failed to upcase with named result") if not IRON_PYTHON_ENV: # test html data html = " \ Производитель, модель \ BenQ-Siemens CF61 \ " # .decode('utf-8') # 'Manufacturer, model text_manuf = "Производитель, модель" manufacturer = pp.Literal(text_manuf) td_start, td_end = pp.make_html_tags("td") manuf_body = ( td_start.suppress() + manufacturer + pp.SkipTo(td_end)("cells*") + td_end.suppress() ) def testRegexDeferredCompile(self): """test deferred compilation of Regex patterns""" re_expr = pp.Regex(r"[A-Z]*") self.assertIsNone( re_expr._may_return_empty, "failed to initialize _may_return_empty flag to None", ) self.assertEqual(re_expr._re, None) compiled = re_expr.re self.assertTrue( re_expr._may_return_empty, "failed to set _may_return_empty flag to True" ) self.assertEqual(re_expr._re, compiled) non_empty_re_expr = pp.Regex(r"[A-Z]+") self.assertIsNone( non_empty_re_expr._may_return_empty, "failed to initialize _may_return_empty flag to None", ) self.assertEqual(non_empty_re_expr._re, None) compiled = non_empty_re_expr.re self.assertFalse( non_empty_re_expr._may_return_empty, "failed to set _may_return_empty flag to False", ) self.assertEqual(non_empty_re_expr._re, compiled) def testRegexDeferredCompileCommonHtmlEntity(self): # this is the most important expression to defer, because it takes a long time to compile perf_test_common_html_entity = pp.common_html_entity() # force internal var to None, to simulate a fresh instance perf_test_common_html_entity._re = None # just how long does this take anyway? from time import perf_counter start = perf_counter() perf_test_common_html_entity.re # noqa elapsed = perf_counter() - start print(f"elapsed time to compile common_html_entity: {elapsed:.4f} sec") def testParseUsingRegex(self): signedInt = pp.Regex(r"[-+][0-9]+") unsignedInt = pp.Regex(r"[0-9]+") simpleString = pp.Regex(r'("[^\"]*")|(\'[^\']*\')') namedGrouping = pp.Regex(r'("(?P[^\"]*)")') compiledRE = pp.Regex(re.compile(r"[A-Z]+")) def testMatch(expression, instring, shouldPass, expectedString=None): if shouldPass: try: result = expression.parse_string(instring, parse_all=False) print(f"{repr(expression)} correctly matched {repr(instring)}") if expectedString != result[0]: print("\tbut failed to match the pattern as expected:") print( f"\tproduced {repr(result[0])} instead of {repr(expectedString)}" ) return False return True except pp.ParseException: print(f"{expression!r} incorrectly failed to match {instring!r}") else: try: result = expression.parse_string(instring, parse_all=False) print(f"{expression!r} incorrectly matched {instring!r}") print(f"\tproduced {result[0]!r} as a result") except pp.ParseException: print(f"{expression!r} correctly failed to match {instring!r}") return True return False # These should fail for i, (test_expr, test_string) in enumerate( [ (signedInt, "1234 foo"), (signedInt, " +foo"), (unsignedInt, "abc"), (unsignedInt, "+123 foo"), (simpleString, "foo"), (simpleString, "\"foo bar'"), (simpleString, "'foo bar\""), (compiledRE, "blah"), ], start=1, ): with self.subTest(test_expr=test_expr, test_string=test_string): self.assertTrue( testMatch( test_expr, test_string, False, ), f"Re: ({i}) passed, expected fail", ) # These should pass for i, (test_expr, test_string, expected_match) in enumerate( [ (signedInt, " +123", "+123"), (signedInt, "+123", "+123"), (signedInt, "+123 foo", "+123"), (signedInt, "-0 foo", "-0"), (unsignedInt, "123 foo", "123"), (unsignedInt, "0 foo", "0"), (simpleString, '"foo"', '"foo"'), (simpleString, "'foo bar' baz", "'foo bar'"), (compiledRE, "BLAH", "BLAH"), (namedGrouping, '"foo bar" baz', '"foo bar"'), ], start=i + 1, ): with self.subTest(test_expr=test_expr, test_string=test_string): self.assertTrue( testMatch( test_expr, test_string, True, expected_match, ), f"Re: ({i}) failed, expected pass", ) ret = namedGrouping.parse_string('"zork" blah', parse_all=False) print(ret) print(list(ret.items())) print(ret.content) self.assertEqual("zork", ret.content, "named group lookup failed") self.assertEqual( simpleString.parse_string('"zork" blah', parse_all=False)[0], ret[0], "Regex not properly returning ParseResults for named vs. unnamed groups", ) try: print("lets try an invalid RE") invRe = pp.Regex("(\"[^\"]*\")|('[^']*'").re except ValueError as e: print("successfully rejected an invalid RE:", end=" ") print(e) else: self.fail("failed to reject invalid RE") with self.assertRaises( ValueError, msg="failed to warn empty string passed to Regex" ): pp.Regex("").re # noqa def testRegexAsType(self): test_str = "sldkjfj 123 456 lsdfkj" print("return as list of match groups") expr = pp.Regex(r"\w+ (\d+) (\d+) (\w+)", as_group_list=True) expected_group_list = [tuple(test_str.split()[1:])] result = expr.parse_string(test_str, parse_all=True) print(result.dump()) print(expected_group_list) self.assertParseResultsEquals( result, expected_list=expected_group_list, msg="incorrect group list returned by Regex)", ) print("return as re.match instance") expr = pp.Regex( r"\w+ (?P\d+) (?P\d+) (?P\w+)", as_match=True ) result = expr.parse_string(test_str, parse_all=True) print(result.dump()) print(result[0].groups()) print(expected_group_list) self.assertEqual( {"num1": "123", "num2": "456", "last_word": "lsdfkj"}, result[0].groupdict(), "invalid group dict from Regex(as_match=True)", ) self.assertEqual( expected_group_list[0], result[0].groups(), "incorrect group list returned by Regex(as_match)", ) def testRegexSub(self): print("test sub with string") expr = pp.Regex(r"").sub("'Richard III'") result = expr.transform_string("This is the title: <title>") print(result) self.assertEqual( "This is the title: 'Richard III'", result, "incorrect Regex.sub result with simple string", ) print("test sub with re string") expr = pp.Regex(r"([Hh]\d):\s*(.*)").sub(r"<\1>\2</\1>") result = expr.transform_string( "h1: This is the main heading\nh2: This is the sub-heading" ) print(result) self.assertEqual( "<h1>This is the main heading</h1>\n<h2>This is the sub-heading</h2>", result, "incorrect Regex.sub result with re string", ) print("test sub with re string (Regex returns re.match)") expr = pp.Regex(r"([Hh]\d):\s*(.*)", as_match=True).sub(r"<\1>\2</\1>") result = expr.transform_string( "h1: This is the main heading\nh2: This is the sub-heading" ) print(result) self.assertEqual( "<h1>This is the main heading</h1>\n<h2>This is the sub-heading</h2>", result, "incorrect Regex.sub result with re string", ) print("test sub with callable that return str") expr = pp.Regex(r"<(.*?)>").sub(lambda m: m.group(1).upper()) result = expr.transform_string("I want this in upcase: <what? what?>") print(result) self.assertEqual( "I want this in upcase: WHAT? WHAT?", result, "incorrect Regex.sub result with callable", ) with self.assertRaises(TypeError): pp.Regex(r"<(.*?)>", as_match=True).sub(lambda m: m.group(1).upper()) with self.assertRaises(TypeError): pp.Regex(r"<(.*?)>", as_group_list=True).sub(lambda m: m.group(1).upper()) with self.assertRaises(TypeError): pp.Regex(r"<(.*?)>", as_group_list=True).sub("") def testRegexInvalidType(self): """test Regex of an invalid type""" with self.assertRaises(TypeError, msg="issue with Regex of type int"): expr = pp.Regex(12) def testRegexLoopPastEndOfString(self): """test Regex matching after end of string""" NL = pp.LineEnd().suppress() empty_line = pp.rest_of_line() + NL result = empty_line[1, 10].parse_string("\n\n") self.assertEqual(3, len(result)) def testPrecededBy(self): num = pp.Word(pp.nums).set_parse_action(lambda t: int(t[0])) interesting_num = pp.PrecededBy(pp.Char("abc")("prefix*")) + num semi_interesting_num = pp.PrecededBy("_") + num crazy_num = pp.PrecededBy(pp.Word("^", "$%^")("prefix*"), 10) + num boring_num = ~pp.PrecededBy(pp.Char("abc_$%^" + pp.nums)) + num very_boring_num = pp.PrecededBy(pp.WordStart()) + num finicky_num = pp.PrecededBy(pp.Word("^", "$%^"), retreat=3) + num s = "c384 b8324 _9293874 _293 404 $%^$^%$2939" print(s) for expr, expected_list, expected_dict in [ (interesting_num, [384, 8324], {"prefix": ["c", "b"]}), (semi_interesting_num, [9293874, 293], {}), (boring_num, [404], {}), (crazy_num, [2939], {"prefix": ["^%$"]}), (finicky_num, [2939], {}), (very_boring_num, [404], {}), ]: # print(expr.search_string(s)) result = sum(expr.search_string(s)) print(result.dump()) self.assertParseResultsEquals(result, expected_list, expected_dict) # infinite loop test - from Issue #127 string_test = "notworking" # negs = pp.Or(['not', 'un'])('negs') negs_pb = pp.PrecededBy("not", retreat=100)("negs_lb") # negs_pb = pp.PrecededBy(negs, retreat=100)('negs_lb') pattern = (negs_pb + pp.Literal("working"))("main") results = pattern.search_string(string_test) try: print(results.dump()) except RecursionError: self.fail("got maximum excursion limit exception") else: print("got maximum excursion limit exception") def testCountedArray(self): testString = "2 5 7 6 0 1 2 3 4 5 0 3 5 4 3" integer = pp.Word(pp.nums).set_parse_action(lambda t: int(t[0])) countedField = pp.counted_array(integer) r = pp.OneOrMore(pp.Group(countedField)).parse_string( testString, parse_all=True ) print(testString) print(r) self.assertParseResultsEquals( r, expected_list=[[5, 7], [0, 1, 2, 3, 4, 5], [], [5, 4, 3]] ) # addresses bug raised by Ralf Vosseler def testCountedArrayTest2(self): testString = "2 5 7 6 0 1 2 3 4 5 0 3 5 4 3" integer = pp.Word(pp.nums).set_parse_action(lambda t: int(t[0])) countedField = pp.counted_array(integer) dummy = pp.Word("A") r = pp.OneOrMore(pp.Group(dummy ^ countedField)).parse_string( testString, parse_all=True ) print(testString) print(r) self.assertParseResultsEquals( r, expected_list=[[5, 7], [0, 1, 2, 3, 4, 5], [], [5, 4, 3]] ) def testCountedArrayTest3(self): int_chars = "_" + pp.alphas array_counter = pp.Word(int_chars).set_parse_action( lambda t: int_chars.index(t[0]) ) # 123456789012345678901234567890 testString = "B 5 7 F 0 1 2 3 4 5 _ C 5 4 3" integer = pp.Word(pp.nums).set_parse_action(lambda t: int(t[0])) countedField = pp.counted_array(integer, int_expr=array_counter) r = pp.OneOrMore(pp.Group(countedField)).parse_string( testString, parse_all=True ) print(testString) print(r) self.assertParseResultsEquals( r, expected_list=[[5, 7], [0, 1, 2, 3, 4, 5], [], [5, 4, 3]] ) def testCountedArrayTest4(self): ppc = pp.pyparsing_common # array counter contains several fields - first field *must* be the number of # items in the array # - number of elements # - type of elements # - source of elements counter_with_metadata = ( ppc.integer("count") + ppc.identifier("type") + ppc.identifier("source") ) countedField = pp.counted_array( pp.Word(pp.alphanums), int_expr=counter_with_metadata ) testString = ( "5 string input item1 item2 item3 item4 item5 0 int user 2 int file 3 8" ) r = pp.Group(countedField("items"))[...].parse_string( testString, parse_all=True ) print(testString) print(r.dump()) print(f"type = {r.type!r}") print(f"source = {r.source!r}") self.assertParseResultsEquals( r, expected_list=[ ["item1", "item2", "item3", "item4", "item5"], [], ["3", "8"], ], ) self.assertParseResultsEquals( r[0], expected_dict={ "count": 5, "source": "input", "type": "string", "items": ["item1", "item2", "item3", "item4", "item5"], }, ) # parse with additional fields between the count and the actual list items count_with_metadata = ppc.integer + pp.Word(pp.alphas)("type") typed_array = pp.counted_array( pp.Word(pp.alphanums), int_expr=count_with_metadata )("items") result = typed_array.parse_string("3 bool True True False", parse_all=True) print(result.dump()) self.assertParseResultsEquals( result, expected_list=["True", "True", "False"], expected_dict={"type": "bool", "items": ["True", "True", "False"]}, ) def testLineStart(self): pass_tests = [ """\ AAA BBB """, """\ AAA... BBB """, ] fail_tests = [ """\ AAA... ...BBB """, """\ AAA BBB """, ] # cleanup test strings pass_tests = [ "\n".join(s.lstrip() for s in t.splitlines()).replace(".", " ") for t in pass_tests ] fail_tests = [ "\n".join(s.lstrip() for s in t.splitlines()).replace(".", " ") for t in fail_tests ] test_patt = pp.Word("A") - pp.LineStart() + pp.Word("B") print(test_patt.streamline()) success, _ = test_patt.run_tests(pass_tests) self.assertTrue(success, "failed LineStart passing tests (1)") success, _ = test_patt.run_tests(fail_tests, failure_tests=True) self.assertTrue(success, "failed LineStart failure mode tests (1)") with ppt.reset_pyparsing_context(): print(r"no \n in default whitespace chars") pp.ParserElement.set_default_whitespace_chars(" ") test_patt = pp.Word("A") - pp.LineStart() + pp.Word("B") print(test_patt.streamline()) # should fail the pass tests too, since \n is no longer valid whitespace and we aren't parsing for it success, _ = test_patt.run_tests(pass_tests, failure_tests=True) self.assertTrue(success, "failed LineStart passing tests (2)") success, _ = test_patt.run_tests(fail_tests, failure_tests=True) self.assertTrue(success, "failed LineStart failure mode tests (2)") test_patt = ( pp.Word("A") - pp.LineEnd().suppress() + pp.LineStart() + pp.Word("B") + pp.LineEnd().suppress() ) print(test_patt.streamline()) success, _ = test_patt.run_tests(pass_tests) self.assertTrue(success, "failed LineStart passing tests (3)") success, _ = test_patt.run_tests(fail_tests, failure_tests=True) self.assertTrue(success, "failed LineStart failure mode tests (3)") def testLineStart2(self): test = """\ AAA 1 AAA 2 AAA B AAA """ test = dedent(test) print(pp.testing.with_line_numbers(test)) print("normal parsing") for t, s, e in (pp.LineStart() + "AAA").scan_string(test): print(s, e, pp.lineno(s, test), pp.line(s, test), repr(t)) print() self.assertEqual( "A", t[0][0], "failed LineStart with insignificant newlines" ) print(r"parsing without \n in whitespace chars") with ppt.reset_pyparsing_context(): pp.ParserElement.set_default_whitespace_chars(" ") for t, s, e in (pp.LineStart() + "AAA").scan_string(test): print(s, e, pp.lineno(s, test), pp.line(s, test), repr(test[s])) print() self.assertEqual( "A", t[0][0], "failed LineStart with insignificant newlines" ) def testLineStartWithLeadingSpaces(self): # testing issue #272 # reverted in 3.0.2 - LineStart() + expr will match expr even if there # are leading spaces. To force "only at column 1" matching, use # AtLineStart(expr). instring = dedent( """ a b c d e f g """ ) print(pp.testing.with_line_numbers(instring)) alpha_line = ( pp.LineStart().leave_whitespace() + pp.Word(pp.alphas) + pp.LineEnd().suppress() ) tests = [ alpha_line, pp.Group(alpha_line), alpha_line | pp.Word("_"), alpha_line | alpha_line, pp.MatchFirst([alpha_line, alpha_line]), alpha_line ^ pp.Word("_"), alpha_line ^ alpha_line, pp.Or([alpha_line, pp.Word("_")]), pp.LineStart() + pp.Word(pp.alphas) + pp.LineEnd().suppress(), pp.And([pp.LineStart(), pp.Word(pp.alphas), pp.LineEnd().suppress()]), ] fails = [] for test in tests: print(test.search_string(instring)) if ["a", "b", "c", "d", "e", "f", "g"] != flatten( sum(test.search_string(instring)).as_list() ): fails.append(test) if fails: self.fail( "failed LineStart tests:\n{}".format( "\n".join(str(expr) for expr in fails) ) ) def testAtLineStart(self): test = dedent( """\ AAA this line AAA and this line AAA but not this one B AAA and definitely not this one """ ) expr = pp.AtLineStart("AAA") + pp.rest_of_line for t in expr.search_string(test): print(t) self.assertEqual( ["AAA", " this line", "AAA", " and this line"], sum(expr.search_string(test)).as_list(), ) def testStringStart(self): self.assertParseAndCheckList( pp.StringStart() + pp.Word(pp.nums), "123", ["123"] ) self.assertParseAndCheckList( pp.StringStart() + pp.Word(pp.nums), " 123", ["123"] ) self.assertParseAndCheckList(pp.StringStart() + "123", "123", ["123"]) self.assertParseAndCheckList(pp.StringStart() + "123", " 123", ["123"]) self.assertParseAndCheckList(pp.AtStringStart(pp.Word(pp.nums)), "123", ["123"]) self.assertParseAndCheckList(pp.AtStringStart("123"), "123", ["123"]) with self.assertRaisesParseException(): pp.AtStringStart(pp.Word(pp.nums)).parse_string(" 123") with self.assertRaisesParseException(): pp.AtStringStart("123").parse_string(" 123") def testStringStartAndLineStartInsideAnd(self): # fmt: off P_MTARG = ( pp.StringStart() + pp.Word("abcde") + pp.StringEnd() ) P_MTARG2 = ( pp.LineStart() + pp.Word("abcde") + pp.StringEnd() ) P_MTARG3 = ( pp.AtLineStart(pp.Word("abcde")) + pp.StringEnd() ) # fmt: on def test(expr, string): expr.streamline() print(expr, repr(string), end=" ") print(expr.parse_string(string)) test(P_MTARG, "aaa") test(P_MTARG2, "aaa") test(P_MTARG2, "\naaa") test(P_MTARG2, " aaa") test(P_MTARG2, "\n aaa") with self.assertRaisesParseException(): test(P_MTARG3, " aaa") with self.assertRaisesParseException(): test(P_MTARG3, "\n aaa") def testLineAndStringEnd(self): NLs = pp.OneOrMore(pp.line_end) bnf1 = pp.DelimitedList(pp.Word(pp.alphanums).leave_whitespace(), NLs) bnf2 = pp.Word(pp.alphanums) + pp.string_end bnf3 = pp.Word(pp.alphanums) + pp.SkipTo(pp.string_end) tests = [ ("testA\ntestB\ntestC\n", ["testA", "testB", "testC"]), ("testD\ntestE\ntestF", ["testD", "testE", "testF"]), ("a", ["a"]), ] for test, expected in tests: res1 = bnf1.parse_string(test, parse_all=True) print(res1, "=?", expected) self.assertParseResultsEquals( res1, expected_list=expected, msg=f"Failed line_end/string_end test (1): {test!r} -> {res1}", ) res2 = bnf2.search_string(test)[0] print(res2, "=?", expected[-1:]) self.assertParseResultsEquals( res2, expected_list=expected[-1:], msg=f"Failed line_end/string_end test (2): {test!r} -> {res2}", ) res3 = bnf3.parse_string(test, parse_all=True) first = res3[0] rest = res3[1] # ~ print res3.dump() print(repr(rest), "=?", repr(test[len(first) + 1 :])) self.assertEqual( rest, test[len(first) + 1 :], msg=f"Failed line_end/string_end test (3): {test!r} -> {res3.as_list()}", ) print() k = pp.Regex(r"a+", flags=re.S + re.M) k = k.parse_with_tabs() k = k.leave_whitespace() tests = [ (r"aaa", ["aaa"]), (r"\naaa", None), (r"a\naa", None), (r"aaa\n", None), ] for i, (src, expected) in enumerate(tests): with self.subTest("", src=src, expected=expected): print(i, repr(src).replace("\\\\", "\\"), end=" ") if expected is None: with self.assertRaisesParseException(): k.parse_string(src, parse_all=True) else: res = k.parse_string(src, parse_all=True) self.assertParseResultsEquals( res, expected, msg=f"Failed on parse_all=True test {i}" ) def testVariableParseActionArgs(self): pa3 = lambda s, l, t: t pa2 = lambda l, t: t pa1 = lambda t: t pa0 = lambda: None class Callable3: def __call__(self, s, l, t): return t class Callable2: def __call__(self, l, t): return t class Callable1: def __call__(self, t): return t class Callable0: def __call__(self): return class CallableS3: @staticmethod def __call__(s, l, t): return t class CallableS2: @staticmethod def __call__(l, t): return t class CallableS1: @staticmethod def __call__(t): return t class CallableS0: @staticmethod def __call__(): return class CallableC3: @classmethod def __call__(cls, s, l, t): return t class CallableC2: @classmethod def __call__(cls, l, t): return t class CallableC1: @classmethod def __call__(cls, t): return t class CallableC0: @classmethod def __call__(cls): return class parseActionHolder: @staticmethod def pa3(s, l, t): return t @staticmethod def pa2(l, t): return t @staticmethod def pa1(t): return t @staticmethod def pa0(): return def paArgs(*args): print(args) return args[2] class ClassAsPA0: def __init__(self): pass def __str__(self): return "A" class ClassAsPA1: def __init__(self, t): print("making a ClassAsPA1") self.t = t def __str__(self): return self.t[0] class ClassAsPA2: def __init__(self, l, t): self.t = t def __str__(self): return self.t[0] class ClassAsPA3: def __init__(self, s, l, t): self.t = t def __str__(self): return self.t[0] class ClassAsPAStarNew(tuple): def __new__(cls, *args): print("make a ClassAsPAStarNew", args) return tuple.__new__(cls, *args[2].as_list()) def __str__(self): return "".join(self) A = pp.Literal("A").set_parse_action(pa0) B = pp.Literal("B").set_parse_action(pa1) C = pp.Literal("C").set_parse_action(pa2) D = pp.Literal("D").set_parse_action(pa3) E = pp.Literal("E").set_parse_action(Callable0()) F = pp.Literal("F").set_parse_action(Callable1()) G = pp.Literal("G").set_parse_action(Callable2()) H = pp.Literal("H").set_parse_action(Callable3()) I = pp.Literal("I").set_parse_action(CallableS0()) J = pp.Literal("J").set_parse_action(CallableS1()) K = pp.Literal("K").set_parse_action(CallableS2()) L = pp.Literal("L").set_parse_action(CallableS3()) M = pp.Literal("M").set_parse_action(CallableC0()) N = pp.Literal("N").set_parse_action(CallableC1()) O = pp.Literal("O").set_parse_action(CallableC2()) P = pp.Literal("P").set_parse_action(CallableC3()) Q = pp.Literal("Q").set_parse_action(paArgs) R = pp.Literal("R").set_parse_action(parseActionHolder.pa3) S = pp.Literal("S").set_parse_action(parseActionHolder.pa2) T = pp.Literal("T").set_parse_action(parseActionHolder.pa1) U = pp.Literal("U").set_parse_action(parseActionHolder.pa0) V = pp.Literal("V") # fmt: off gg = pp.OneOrMore( A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | U | V | B | T ) # fmt: on testString = "VUTSRQPONMLKJIHGFEDCBA" res = gg.parse_string(testString, parse_all=True) print(res) self.assertParseResultsEquals( res, expected_list=list(testString), msg="Failed to parse using variable length parse actions", ) A = pp.Literal("A").set_parse_action(ClassAsPA0) B = pp.Literal("B").set_parse_action(ClassAsPA1) C = pp.Literal("C").set_parse_action(ClassAsPA2) D = pp.Literal("D").set_parse_action(ClassAsPA3) E = pp.Literal("E").set_parse_action(ClassAsPAStarNew) # fmt: off gg = pp.OneOrMore( A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V ) # fmt: on testString = "VUTSRQPONMLKJIHGFEDCBA" res = gg.parse_string(testString, parse_all=True) print(list(map(str, res))) self.assertEqual( list(testString), list(map(str, res)), "Failed to parse using variable length parse actions " "using class constructors as parse actions", ) def testSingleArgException(self): testMessage = "just one arg" try: raise pp.ParseFatalException(testMessage) except pp.ParseBaseException as pbe: print("Received expected exception:", pbe) raisedMsg = pbe.msg self.assertEqual( testMessage, raisedMsg, "Failed to get correct exception message" ) def testOriginalTextFor(self): def rfn(t): return f"{t.src}:{len(''.join(t))}" makeHTMLStartTag = lambda tag: pp.original_text_for( pp.make_html_tags(tag)[0], as_string=False ) # use the lambda, Luke start = makeHTMLStartTag("IMG") # don't replace our fancy parse action with rfn, # append rfn to the list of parse actions start.add_parse_action(rfn) text = """_<img src="images/cal.png" alt="cal image" width="16" height="15">_""" s = start.transform_string(text) print(s) self.assertTrue( s.startswith("_images/cal.png:"), "failed to preserve input s properly" ) self.assertTrue( s.endswith("77_"), "failed to return full original text properly" ) tag_fields = makeHTMLStartTag("IMG").search_string(text)[0] print(sorted(tag_fields.keys())) self.assertEqual( ["alt", "empty", "height", "src", "startImg", "tag", "width"], sorted(tag_fields.keys()), "failed to preserve results names in original_text_for", ) def testPackratParsingCacheCopy(self): integer = pp.Word(pp.nums).set_name("integer") id = pp.Word(pp.alphas + "_", pp.alphanums + "_") simpleType = pp.Literal("int") arrayType = simpleType + ("[" + pp.DelimitedList(integer) + "]")[...] varType = arrayType | simpleType varDec = varType + pp.DelimitedList(id + pp.Optional("=" + integer)) + ";" codeBlock = pp.Literal("{}") funcDef = ( pp.Optional(varType | "void") + id + "(" + (pp.DelimitedList(varType + id) | "void" | pp.empty) + ")" + codeBlock ) program = varDec | funcDef input = "int f(){}" self.assertParseAndCheckList( program, input, ["int", "f", "(", ")", "{}"], msg="Error in packrat parsing", verbose=True, ) def testPackratParsingCacheCopyTest2(self): DO, AA = list(map(pp.Keyword, "DO AA".split())) LPAR, RPAR = list(map(pp.Suppress, "()")) identifier = ~AA + pp.Word("Z") function_name = identifier.copy() # ~ function_name = ~AA + Word("Z") #identifier.copy() expr = pp.Forward().set_name("expr") expr <<= pp.Group( function_name + LPAR + pp.Optional(pp.DelimitedList(expr)) + RPAR ).set_name("functionCall") | identifier.set_name( "ident" ) # .set_debug()#.set_break() stmt = DO + pp.Group(pp.DelimitedList(identifier + ".*" | expr)) result = stmt.parse_string("DO Z", parse_all=True) print(result.as_list()) self.assertEqual( 1, len(result[1]), "packrat parsing is duplicating And term exprs" ) def testParseResultsDel(self): grammar = pp.OneOrMore(pp.Word(pp.nums))("ints") + pp.OneOrMore( pp.Word(pp.alphas) )("words") res = grammar.parse_string("123 456 ABC DEF", parse_all=True) print(res.dump()) origInts = res.ints.as_list() origWords = res.words.as_list() del res[1] del res["words"] print(res.dump()) self.assertEqual("ABC", res[1], "failed to delete 0'th element correctly") self.assertEqual( origInts, res.ints.as_list(), "updated named attributes, should have updated list only", ) self.assertEqual("", res.words, "failed to update named attribute correctly") self.assertEqual( "DEF", res[-1], "updated list, should have updated named attributes only" ) def testWithAttributeParseAction(self): """ This unit test checks with_attribute in these ways: * Argument forms as keywords and tuples * Selecting matching tags by attribute * Case-insensitive attribute matching * Correctly matching tags having the attribute, and rejecting tags not having the attribute (Unit test written by voigts as part of the Google Highly Open Participation Contest) """ data = """ <a>1</a> <a b="x">2</a> <a B="x">3</a> <a b="X">4</a> <a b="y">5</a> <a class="boo">8</ a> """ tagStart, tagEnd = pp.make_html_tags("a") expr = tagStart + pp.Word(pp.nums)("value") + tagEnd expected = ( [ ["a", ["b", "x"], False, "2", "</a>"], ["a", ["b", "x"], False, "3", "</a>"], ], [ ["a", ["b", "x"], False, "2", "</a>"], ["a", ["b", "x"], False, "3", "</a>"], ], [["a", ["class", "boo"], False, "8", "</a>"]], ) for attrib, exp in zip( [ pp.with_attribute(b="x"), # with_attribute(B="x"), pp.with_attribute(("b", "x")), # with_attribute(("B", "x")), pp.with_class("boo"), ], expected, ): tagStart.set_parse_action(attrib) result = expr.search_string(data) print(result.dump()) self.assertParseResultsEquals( result, expected_list=exp, msg=f"Failed test, expected {expected}, got {result.as_list()}", ) def testNestedExpressions(self): """ This unit test checks nested_expr in these ways: - use of default arguments - use of non-default arguments (such as a pyparsing-defined comment expression in place of quoted_string) - use of a custom content expression - use of a pyparsing expression for opener and closer is *OPTIONAL* - use of input data containing nesting delimiters - correct grouping of parsed tokens according to nesting of opening and closing delimiters in the input string (Unit test written by christoph... as part of the Google Highly Open Participation Contest) """ # All defaults. Straight out of the example script. Also, qualifies for # the bonus: note the fact that (Z | (E^F) & D) is not parsed :-). # Tests for bug fixed in 1.4.10 print("Test defaults:") teststring = "((ax + by)*C) (Z | (E^F) & D)" expr = pp.nested_expr() expected = [[["ax", "+", "by"], "*C"]] result = expr.parse_string(teststring, parse_all=False) print(result.dump()) self.assertParseResultsEquals( result, expected_list=expected, msg=f"Defaults didn't work. That's a bad sign. Expected: {expected}, got: {result}", ) # Going through non-defaults, one by one; trying to think of anything # odd that might not be properly handled. # Change opener print("\nNon-default opener") teststring = "[[ ax + by)*C)" expected = [[["ax", "+", "by"], "*C"]] expr = pp.nested_expr("[") self.assertParseAndCheckList( expr, teststring, expected, f"Non-default opener didn't work. Expected: {expected}, got: {result}", verbose=True, ) # Change closer print("\nNon-default closer") teststring = "((ax + by]*C]" expected = [[["ax", "+", "by"], "*C"]] expr = pp.nested_expr(closer="]") self.assertParseAndCheckList( expr, teststring, expected, f"Non-default closer didn't work. Expected: {expected}, got: {result}", verbose=True, ) # #Multicharacter opener, closer # opener = "bar" # closer = "baz" print("\nLiteral expressions for opener and closer") opener, closer = map(pp.Literal, "bar baz".split()) expr = pp.nested_expr( opener, closer, content=pp.Regex(r"([^b ]|b(?!a)|ba(?![rz]))+") ) teststring = "barbar ax + bybaz*Cbaz" expected = [[["ax", "+", "by"], "*C"]] self.assertParseAndCheckList( expr, teststring, expected, f"Multicharacter opener and closer didn't work. Expected: {expected}, got: {result}", verbose=True, ) # Lisp-ish comments print("\nUse ignore expression (1)") comment = pp.Regex(r";;.*") teststring = """ (let ((greeting "Hello, world!")) ;;(foo bar (display greeting)) """ expected = [ [ "let", [["greeting", '"Hello,', 'world!"']], ";;(foo bar", ["display", "greeting"], ] ] expr = pp.nested_expr(ignore_expr=comment) self.assertParseAndCheckList( expr, teststring, expected, f'Lisp-ish comments (";; <...> $") didn\'t work. Expected: {expected}, got: {result}', verbose=True, ) # Lisp-ish comments, using a standard bit of pyparsing, and an Or. print("\nUse ignore expression (2)") comment = ";;" + pp.rest_of_line teststring = """ (let ((greeting "Hello, )world!")) ;;(foo bar (display greeting)) """ expected = [ [ "let", [["greeting", '"Hello, )world!"']], ";;", "(foo bar", ["display", "greeting"], ] ] expr = pp.nested_expr(ignore_expr=(comment ^ pp.quoted_string)) self.assertParseAndCheckList( expr, teststring, expected, f'Lisp-ish comments (";; <...> $") and quoted strings didn\'t work. Expected: {expected}, got: {result}', verbose=True, ) def testNestedExpressions2(self): """test nested_expr with conditions that explore other paths identical opener and closer opener and/or closer of type other than string or iterable multi-character opener and/or closer single character opener and closer with ignore_expr=None multi-character opener and/or closer with ignore_expr=None """ name = pp.Word(pp.alphanums + "_") # identical opener and closer with self.assertRaises( ValueError, msg="matching opener and closer should raise error" ): expr = name + pp.nested_expr(opener="{", closer="{") # opener and/or closer of type other than string or iterable with self.assertRaises( ValueError, msg="opener and closer as ints should raise error" ): expr = name + pp.nested_expr(opener=12, closer=18) # multi-character opener and/or closer tstMulti = "aName {{ outer {{ 'inner with opener {{ and closer }} in quoted string' }} }}" expr = name + pp.nested_expr(opener="{{", closer="}}") result = expr.parse_string(tstMulti, parse_all=True) expected = [ "aName", ["outer", ["'inner with opener {{ and closer }} in quoted string'"]], ] print(result.dump()) self.assertParseResultsEquals( result, expected, msg="issue with multi-character opener and closer" ) # single character opener and closer with ignore_expr=None tst = "aName { outer { 'inner with opener { and closer } in quoted string' }}" expr = name + pp.nested_expr(opener="{", closer="}", ignore_expr=None) singleCharResult = expr.parse_string(tst, parse_all=True) print(singleCharResult.dump()) # multi-character opener and/or closer with ignore_expr=None expr = name + pp.nested_expr(opener="{{", closer="}}", ignore_expr=None) multiCharResult = expr.parse_string(tstMulti, parse_all=True) print(multiCharResult.dump()) self.assertParseResultsEquals( singleCharResult, multiCharResult.as_list(), msg="using different openers and closers shouldn't affect resulting ParseResults", ) def testNestedExpressions3(self): prior_ws_chars = pp.ParserElement.DEFAULT_WHITE_CHARS with ppt.reset_pyparsing_context(): pp.ParserElement.set_default_whitespace_chars("") input_str = dedent( """\ selector { a:b; c:d; selector { a:b; c:d; } y:z; }""" ) print(ppt.with_line_numbers(input_str, 1, 100)) nested_result = ( pp.nested_expr("{", "}").parse_string("{" + input_str + "}").as_list() ) expected_result = [ [ "selector\n", [ "\n a:b;\n c:d;\n selector\n ", ["\n a:b;\n c:d;\n "], "\n y:z;\n", ], ] ] self.assertEqual(nested_result, expected_result) # make sure things have been put back properly self.assertEqual(pp.ParserElement.DEFAULT_WHITE_CHARS, prior_ws_chars) def testNestedExpressions4(self): allowed = pp.alphas plot_options_short = pp.nested_expr( "[", "]", content=pp.OneOrMore(pp.Word(allowed) ^ pp.quoted_string) ).set_results_name("plot_options") self.assertParseAndCheckList( plot_options_short, "[slkjdfl sldjf [lsdf'lsdf']]", [["slkjdfl", "sldjf", ["lsdf", "'lsdf'"]]], ) def testNestedExpressionDoesNotOverwriteParseActions(self): content = pp.Word(pp.nums + " ") content.add_parse_action(lambda t: None) orig_pa = content.parseAction[0] expr = pp.nested_expr(content=content) assert content.parseAction[0] is orig_pa def testNestedExpressionRandom(self): import random word_chars = pp.alphanums def get_random_character(_charset=word_chars + " "): return random.choice(_charset) def create_random_quoted_string(): quote_char = random.choice(('"', "'")) yield quote_char yield from (get_random_character() for _ in range(random.randint(0, 12))) yield quote_char def create_random_nested_expression(): yield "[" if random.random() < 0.25: yield from create_random_quoted_string() for _ in range(random.randint(0, 16)): rnd = random.random() if rnd < 0.25: yield from create_random_quoted_string() elif rnd < 0.3: yield from create_random_nested_expression() else: yield from ( get_random_character() for _ in range(random.randint(1, 4)) ) if random.random() < 0.25: yield from create_random_quoted_string() yield "]" num_reps = 150 # simulate nested_expr LBRACK, RBRACK = pp.Suppress.using_each("[]") wd = pp.Word(word_chars) qs = pp.quoted_string() ls = pp.Forward() ls <<= pp.Group(LBRACK + (qs | ls | wd)[...] + RBRACK) def crack_nested_string(s) -> list: return ls.parse_string(s, parse_all=True).as_list() expr = pp.nested_expr("[", "]") for _ in range(num_reps): nested_str = "".join(create_random_nested_expression()) # print(nested_str) cracked_result = crack_nested_string(nested_str) self.assertParseAndCheckList( expr, nested_str, cracked_result, f"Failed: {nested_str}, expected {cracked_result}", verbose=False, ) # test multi-character nesting delimiters expr = pp.nested_expr("<<", ">>") for _ in range(num_reps): nested_str = "".join(create_random_nested_expression()) # print(nested_str) cracked_result = crack_nested_string(nested_str) nested_str = nested_str.replace("[", "<<").replace("]", ">>") self.assertParseAndCheckList( expr, nested_str, cracked_result, f"Failed: {nested_str}, expected {cracked_result}", verbose=False, ) # test with no ignore_expr (no quoted string handling) expr = pp.nested_expr("[", "]", ignore_expr=None) for _ in range(num_reps): nested_str = "".join(create_random_nested_expression()) nested_str = nested_str.replace('"', "").replace("'", "") # print(nested_str) cracked_result = crack_nested_string(nested_str) self.assertParseAndCheckList( expr, nested_str, cracked_result, f"Failed: {nested_str}, expected {cracked_result}", verbose=False, ) # test multi-character nesting delimiters, with no ignore_expr expr = pp.nested_expr("<<", ">>", ignore_expr=None) for _ in range(num_reps): nested_str = "".join(create_random_nested_expression()) nested_str = nested_str.replace('"', "").replace("'", "") # print(nested_str) cracked_result = crack_nested_string(nested_str) nested_str = nested_str.replace("[", "<<").replace("]", ">>") self.assertParseAndCheckList( expr, nested_str, cracked_result, f"Failed: {nested_str}, expected {cracked_result}", verbose=False, ) def testWordMinMaxArgs(self): parsers = [ "A" + pp.Word(pp.nums), "A" + pp.Word(pp.nums, min=1), "A" + pp.Word(pp.nums, max=6), "A" + pp.Word(pp.nums, min=1, max=6), "A" + pp.Word(pp.nums, min=1), "A" + pp.Word(pp.nums, min=2), "A" + pp.Word(pp.nums, min=2, max=6), pp.Word("A", pp.nums), pp.Word("A", pp.nums, min=1), pp.Word("A", pp.nums, max=6), pp.Word("A", pp.nums, min=1, max=6), pp.Word("A", pp.nums, min=1), pp.Word("A", pp.nums, min=2), pp.Word("A", pp.nums, min=2, max=6), pp.Word(pp.alphas, pp.nums), pp.Word(pp.alphas, pp.nums, min=1), pp.Word(pp.alphas, pp.nums, max=6), pp.Word(pp.alphas, pp.nums, min=1, max=6), pp.Word(pp.alphas, pp.nums, min=1), pp.Word(pp.alphas, pp.nums, min=2), pp.Word(pp.alphas, pp.nums, min=2, max=6), ] fails = [] for p in parsers: print(p, getattr(p, "reString", "..."), end=" ", flush=True) try: p.parse_string("A123", parse_all=True) except Exception as e: print(" <<< FAIL") fails.append(p) else: print() if fails: self.fail(f"{','.join(str(f) for f in fails)} failed to match") def testWordMinMaxExactArgs(self): for minarg in range(1, 9): for maxarg in range(minarg, 10): with self.subTest(minarg=minarg, maxarg=maxarg): expr = pp.Word("AB", pp.nums, min=minarg, max=maxarg) print(minarg, maxarg, expr.reString, end=" ") trailing = expr.reString.rpartition("]")[-1] expected_special = { (1, 1): "", (1, 2): "?", (2, 2): "", } expected_default = ( f"{{{minarg - 1}}}" if minarg == maxarg else f"{{{minarg - 1},{maxarg - 1}}}" ) expected = expected_special.get((minarg, maxarg), expected_default) print(trailing == expected) self.assertEqual(trailing, expected) self.assertParseAndCheckList( expr + pp.rest_of_line.suppress(), "A1234567890", ["A1234567890"[:maxarg]], ) for exarg in range(1, 9): with self.subTest(exarg=exarg): expr = pp.Word("AB", pp.nums, exact=exarg) print(exarg, expr.reString, end=" ") trailing = expr.reString.rpartition("]")[-1] if exarg < 3: expected = "" else: expected = f"{{{exarg - 1}}}" print(trailing == expected) self.assertEqual(trailing, expected) self.assertParseAndCheckList( expr + pp.rest_of_line.suppress(), "A1234567890", ["A1234567890"[:exarg]], ) def testWordMin(self): # failing tests for min_val in range(3, 5): with self.subTest(min_val=min_val): wd = pp.Word("a", "1", min=min_val) print(min_val, wd.reString) with self.assertRaisesParseException(): wd.parse_string("a1") for min_val in range(2, 5): with self.subTest(min_val=min_val): wd = pp.Word("a", min=min_val) print(min_val, wd.reString) with self.assertRaisesParseException(): wd.parse_string("a") for min_val in range(3, 5): with self.subTest(min_val=min_val): wd = pp.Word("a", "1", min=min_val) print(min_val, wd.reString) with self.assertRaisesParseException(): wd.parse_string("a1") # passing tests for min_val in range(2, 5): with self.subTest(min_val=min_val): wd = pp.Word("a", min=min_val) test_string = "a" * min_val self.assertParseAndCheckList( wd, test_string, [test_string], msg=f"Word(min={min_val}) failed", verbose=True, ) for min_val in range(2, 5): with self.subTest(min_val=min_val): wd = pp.Word("a", "1", min=min_val) test_string = "a" + "1" * (min_val - 1) self.assertParseAndCheckList( wd, test_string, [test_string], msg=f"Word(min={min_val}) failed", verbose=True, ) def testWordExact(self): # failing tests for exact_val in range(2, 5): with self.subTest(exact_val=exact_val): wd = pp.Word("a", exact=exact_val) print(exact_val, wd.reString) with self.assertRaisesParseException(): wd.parse_string("a") # passing tests for exact_val in range(2, 5): with self.subTest(exact_val=exact_val): wd = pp.Word("a", exact=exact_val) test_string = "a" * exact_val self.assertParseAndCheckList( wd, test_string, [test_string], msg=f"Word(exact={exact_val}) failed", verbose=True, ) def testInvalidMinMaxArgs(self): with self.assertRaises(ValueError): wd = pp.Word(min=2, max=1) def testWordExclude(self): allButPunc = pp.Word(pp.printables, exclude_chars=".,:;-_!?") test = "Hello, Mr. Ed, it's Wilbur!" result = allButPunc.search_string(test).as_list() print(result) self.assertEqual( [["Hello"], ["Mr"], ["Ed"], ["it's"], ["Wilbur"]], result, "failed WordExcludeTest", ) def testWordExclude2(self): punc_chars = ".,:;-_!?" all_but_punc = pp.Word(pp.printables, exclude_chars=punc_chars) all_and_punc = pp.Word(pp.printables) assert set(punc_chars) & set(all_but_punc.init_chars) == set() expr = all_but_punc("no_punc*") | all_and_punc("with_punc*") self.assertParseAndCheckDict( expr[...], "Mr. Ed,", {"no_punc": ["Mr", "Ed"], "with_punc": [".", ","]}, "failed matching with exclude_chars (1)", ) self.assertParseAndCheckDict( expr[...], ":Mr. Ed,", {"no_punc": ["Ed"], "with_punc": [":Mr.", ","]}, "failed matching with exclude_chars (2)", ) def testWordMinOfZero(self): """test a Word with min=0""" with self.assertRaises(ValueError, msg="expected min 0 to error"): expr = pp.Word(pp.nums, min=0, max=10) @staticmethod def setup_testWordMaxGreaterThanZeroAndAsKeyword(): # fmt: off bool_operand = ( pp.Word(pp.alphas, max=1, as_keyword=True) | pp.one_of("True False") ) test_string = "p q r False" return SimpleNamespace(**locals()) # fmt: on def testWordMaxGreaterThanZeroAndAsKeyword1(self): """test a Word with max>0 and as_keyword=True""" setup = self.setup_testWordMaxGreaterThanZeroAndAsKeyword() result = setup.bool_operand[...].parse_string(setup.test_string, parse_all=True) self.assertParseAndCheckList( setup.bool_operand[...], setup.test_string, setup.test_string.split(), msg=f"{__()}Failed to parse Word(max=1, as_keyword=True)", verbose=True, ) def testWordMaxGreaterThanZeroAndAsKeyword2(self): """test a Word with max>0 and as_keyword=True""" setup = self.setup_testWordMaxGreaterThanZeroAndAsKeyword() with self.assertRaisesParseException( msg=f"{__()}Failed to detect Word with max > 0 and as_keyword=True" ): setup.bool_operand.parse_string("abc", parse_all=True) def testCharAsKeyword(self): """test a Char with as_keyword=True""" grade = pp.OneOrMore(pp.Char("ABCDF", as_keyword=True)) # all single char words result = grade.parse_string("B B C A D", parse_all=True) print(result) expected = ["B", "B", "C", "A", "D"] self.assertParseResultsEquals( result, expected, msg="issue with Char as_keyword=True" ) # NOT all single char words test2 = "B BB C A D" result2 = grade.parse_string(test2, parse_all=False) print(result2) expected2 = ["B"] self.assertParseResultsEquals( result2, expected2, msg="issue with Char as_keyword=True parsing 2 chars" ) def testCharRe(self): expr = pp.Char("ABCDEFG") self.assertEqual("[A-G]", expr.reString) def testCharsNotIn(self): """test CharsNotIn initialized with various arguments""" vowels = "AEIOU" tst = "bcdfghjklmnpqrstvwxyz" # default args consonants = pp.CharsNotIn(vowels) result = consonants.parse_string(tst, parse_all=True) print(result) self.assertParseResultsEquals( result, [tst], msg="issue with CharsNotIn w/ default args" ) # min = 0 with self.assertRaises(ValueError, msg="issue with CharsNotIn w/ min=0"): consonants = pp.CharsNotIn(vowels, min=0) # max > 0 consonants = pp.CharsNotIn(vowels, max=5) result = consonants.parse_string(tst, parse_all=False) print(result) self.assertParseResultsEquals( result, [tst[:5]], msg="issue with CharsNotIn w max > 0" ) # exact > 0 consonants = pp.CharsNotIn(vowels, exact=10) result = consonants.parse_string(tst[:10], parse_all=True) print(result) self.assertParseResultsEquals( result, [tst[:10]], msg="issue with CharsNotIn w/ exact > 0" ) # min > length consonants = pp.CharsNotIn(vowels, min=25) with self.assertRaisesParseException(msg="issue with CharsNotIn min > tokens"): result = consonants.parse_string(tst, parse_all=True) def testParseAll(self): testExpr = pp.Word("A") tests = [ ("AAAAA", False, True), ("AAAAA", True, True), ("AAABB", False, True), ("AAABB", True, False), ] for s, parse_allFlag, shouldSucceed in tests: try: print( f"'{s}' parse_all={parse_allFlag} (shouldSucceed={shouldSucceed})" ) testExpr.parse_string(s, parse_all=parse_allFlag) self.assertTrue( shouldSucceed, "successfully parsed when should have failed" ) except ParseException as pe: print(pe.explain()) self.assertFalse( shouldSucceed, "failed to parse when should have succeeded" ) # add test for trailing comments testExpr.ignore(pp.cpp_style_comment) tests = [ ("AAAAA //blah", False, True), ("AAAAA //blah", True, True), ("AAABB //blah", False, True), ("AAABB //blah", True, False), ] for s, parse_allFlag, shouldSucceed in tests: try: print( f"'{s}' parse_all={parse_allFlag} (shouldSucceed={shouldSucceed})" ) testExpr.parse_string(s, parse_all=parse_allFlag) self.assertTrue( shouldSucceed, "successfully parsed when should have failed" ) except ParseException as pe: print(pe.explain()) self.assertFalse( shouldSucceed, "failed to parse when should have succeeded" ) # add test with very long expression string # testExpr = pp.MatchFirst([pp.Literal(c) for c in pp.printables if c != 'B'])[1, ...] anything_but_an_f = pp.OneOrMore( pp.MatchFirst([pp.Literal(c) for c in pp.printables if c != "f"]) ) testExpr = pp.Word("012") + anything_but_an_f tests = [ ("00aab", False, True), ("00aab", True, True), ("00aaf", False, True), ("00aaf", True, False), ] for s, parse_allFlag, shouldSucceed in tests: try: print( f"'{s}' parse_all={parse_allFlag} (shouldSucceed={shouldSucceed})" ) testExpr.parse_string(s, parse_all=parse_allFlag) self.assertTrue( shouldSucceed, "successfully parsed when should have failed" ) except ParseException as pe: print(pe.explain()) self.assertFalse( shouldSucceed, "failed to parse when should have succeeded" ) def testGreedyQuotedStrings(self): src = """\ "string1", "strin""g2" 'string1', 'string2' ^string1^, ^string2^ <string1>, <string2>""" testExprs = ( pp.sgl_quoted_string, pp.dbl_quoted_string, pp.quoted_string, pp.QuotedString('"', esc_quote='""'), pp.QuotedString("'", esc_quote="''"), pp.QuotedString("^"), pp.QuotedString("<", end_quote_char=">"), ) for expr in testExprs: strs = pp.DelimitedList(expr).search_string(src) print(strs) self.assertTrue( bool(strs), f"no matches found for test expression '{expr}'" ) for lst in strs: self.assertEqual( 2, len(lst), f"invalid match found for test expression '{expr}'" ) src = """'ms1',1,0,'2009-12-22','2009-12-22 10:41:22') ON DUPLICATE KEY UPDATE sent_count = sent_count + 1, mtime = '2009-12-22 10:41:22';""" tok_sql_quoted_value = pp.QuotedString( "'", "\\", "''", True, False ) ^ pp.QuotedString('"', "\\", '""', True, False) tok_sql_computed_value = pp.Word(pp.nums) tok_sql_identifier = pp.Word(pp.alphas) val = tok_sql_quoted_value | tok_sql_computed_value | tok_sql_identifier vals = pp.DelimitedList(val) print(vals.parse_string(src, parse_all=False)) self.assertEqual( 5, len(vals.parse_string(src, parse_all=False)), "error in greedy quote escaping", ) def testQuotedStringEscapedQuotes(self): quoted = pp.QuotedString('"', esc_quote='""') res = quoted.parse_string('"like ""SQL"""', parse_all=True) print(res.as_list()) self.assertEqual(['like "SQL"'], res.as_list()) # Issue #263 - handle case when the esc_quote is not a repeated character quoted = pp.QuotedString("y", esc_char=None, esc_quote="xy") res = quoted.parse_string("yaaay", parse_all=True) self.assertEqual(["aaa"], res.as_list()) res = quoted.parse_string("yaaaxyaaay", parse_all=True) print(res.as_list()) self.assertEqual(["aaayaaa"], res.as_list()) def testQuotedStringEscapedExtendedChars(self): quoted = pp.QuotedString("'") self.assertParseAndCheckList( quoted, "'null: \0 octal: \267 hex: \xb7 unicode: \u00b7'", ["null: \x00 octal: · hex: · unicode: ·"], "failed to parse embedded numeric escapes", ) def testWordBoundaryExpressions(self): ws = pp.WordStart() we = pp.WordEnd() vowel = pp.one_of(list("AEIOUY")) consonant = pp.one_of(list("BCDFGHJKLMNPQRSTVWXZ")) leadingVowel = ws + vowel trailingVowel = vowel + we leadingConsonant = ws + consonant trailingConsonant = consonant + we internalVowel = ~ws + vowel + ~we bnf = leadingVowel | trailingVowel tests = """\ ABC DEF GHI JKL MNO PQR STU VWX YZ """.splitlines() tests.append("\n".join(tests)) expectedResult = [ [["D", "G"], ["A"], ["C", "F"], ["I"], ["E"], ["A", "I"]], [["J", "M", "P"], [], ["L", "R"], ["O"], [], ["O"]], [["S", "V"], ["Y"], ["X", "Z"], ["U"], [], ["U", "Y"]], [ ["D", "G", "J", "M", "P", "S", "V"], ["A", "Y"], ["C", "F", "L", "R", "X", "Z"], ["I", "O", "U"], ["E"], ["A", "I", "O", "U", "Y"], ], ] for t, expected in zip(tests, expectedResult): print(t) results = [ flatten(e.search_string(t).as_list()) for e in [ leadingConsonant, leadingVowel, trailingConsonant, trailingVowel, internalVowel, bnf, ] ] print(results) print() self.assertEqual( expected, results, f"Failed WordBoundaryTest, expected {expected}, got {results}", ) def testWordBoundaryExpressions2(self): from itertools import product ws1 = pp.WordStart(pp.alphas) ws2 = pp.WordStart(word_chars=pp.alphas) ws3 = pp.WordStart(word_chars=pp.alphas) we1 = pp.WordEnd(pp.alphas) we2 = pp.WordEnd(word_chars=pp.alphas) we3 = pp.WordEnd(word_chars=pp.alphas) for i, (ws, we) in enumerate(product((ws1, ws2, ws3), (we1, we2, we3))): try: expr = "(" + ws + pp.Word(pp.alphas) + we + ")" expr.parse_string("(abc)", parse_all=True) except pp.ParseException as pe: self.fail(f"Test {i} failed: {pe}") else: pass def testRequiredEach(self): parser = pp.Keyword("bam") & pp.Keyword("boo") try: res1 = parser.parse_string("bam boo", parse_all=True) print(res1.as_list()) res2 = parser.parse_string("boo bam", parse_all=True) print(res2.as_list()) except ParseException: failed = True else: failed = False self.assertFalse(failed, "invalid logic in Each") self.assertEqual( set(res1), set(res2), f"Failed RequiredEachTest, expected {res1.as_list()}" f" and {res2.as_list} to contain the same words in any order", ) def testOptionalEachTest1(self): for the_input in [ "Tal Weiss Major", "Tal Major", "Weiss Major", "Major", "Major Tal", "Major Weiss", "Major Tal Weiss", ]: print(the_input) parser1 = (pp.Optional("Tal") + pp.Optional("Weiss")) & pp.Keyword("Major") parser2 = pp.Optional( pp.Optional("Tal") + pp.Optional("Weiss") ) & pp.Keyword("Major") parser3 = (pp.Keyword("Tal") | pp.Keyword("Weiss"))[...] & pp.Keyword( "Major" ) p1res = parser1.parse_string(the_input, parse_all=True) p2res = parser2.parse_string(the_input, parse_all=True) self.assertEqual( p1res.as_list(), p2res.as_list(), f"Each failed to match with nested Optionals, {p1res.as_list()} should match {p2res.as_list()}", ) p3res = parser3.parse_string(the_input, parse_all=True) self.assertEqual( p1res.as_list(), p3res.as_list(), f"Each failed to match with repeated Optionals, {p1res.as_list()} should match {p3res.as_list()}", ) def testOptionalEachTest2(self): word = pp.Word(pp.alphanums + "_").set_name("word") with_stmt = "with" + pp.OneOrMore(pp.Group(word("key") + "=" + word("value")))( "overrides" ) using_stmt = "using" + pp.Regex("id-[0-9a-f]{8}")("id") modifiers = pp.Optional(with_stmt("with_stmt")) & pp.Optional( using_stmt("using_stmt") ) self.assertEqual("with foo=bar bing=baz using id-deadbeef", modifiers) self.assertNotEqual( "with foo=bar bing=baz using id-deadbeef using id-feedfeed", modifiers ) def testOptionalEachTest3(self): foo = pp.Literal("foo") bar = pp.Literal("bar") openBrace = pp.Suppress(pp.Literal("{")) closeBrace = pp.Suppress(pp.Literal("}")) exp = openBrace + (foo[1, ...]("foo") & bar[...]("bar")) + closeBrace tests = """\ {foo} {bar foo bar foo bar foo} """.splitlines() for test in tests: test = test.strip() if not test: continue self.assertParseAndCheckList( exp, test, test.strip("{}").split(), f"failed to parse Each expression {test!r}", verbose=True, ) with self.assertRaisesParseException(): exp.parse_string("{bar}", parse_all=True) def testOptionalEachTest4(self): expr = (~ppc.iso8601_date + ppc.integer("id")) & ( pp.Group(ppc.iso8601_date)("date*")[...] ) success, _ = expr.run_tests( """ 1999-12-31 100 2001-01-01 42 """ ) self.assertTrue(success) def testEachWithParseFatalException(self): option_expr = pp.Keyword("options") - "(" + ppc.integer + ")" step_expr1 = pp.Keyword("step") - "(" + ppc.integer + ")" step_expr2 = pp.Keyword("step") - "(" + ppc.integer + "Z" + ")" step_expr = step_expr1 ^ step_expr2 parser = option_expr & step_expr[...] tests = [ ( "options(100) step(A)", "Expected integer, found 'A' (at char 18), (line:1, col:19)", ), ( "step(A) options(100)", "Expected integer, found 'A' (at char 5), (line:1, col:6)", ), ( "options(100) step(100A)", """Expected 'Z', found 'A' (at char 21), (line:1, col:22)""", ), ( "options(100) step(22) step(100ZA)", """Expected ')', found 'A' (at char 31), (line:1, col:32)""", ), ] test_lookup = dict(tests) success, output = parser.run_tests((t[0] for t in tests), failure_tests=True) for test_str, result in output: self.assertEqual( test_lookup[test_str], str(result), f"incorrect exception raised for test string {test_str!r}", ) def testEachWithMultipleMatch(self): size = "size" + pp.one_of("S M L XL") color = pp.Group( "color" + pp.one_of("red orange yellow green blue purple white black brown") ) size.set_name("size_spec") color.set_name("color_spec") spec0 = size("size") & color[...]("colors") spec1 = size("size") & color[1, ...]("colors") for spec in (spec0, spec1): for test, expected_dict in [ ( "size M color red color yellow", { "colors": [["color", "red"], ["color", "yellow"]], "size": ["size", "M"], }, ), ( "color green size M color red color yellow", { "colors": [ ["color", "green"], ["color", "red"], ["color", "yellow"], ], "size": ["size", "M"], }, ), ]: result = spec.parse_string(test, parse_all=True) self.assertParseResultsEquals(result, expected_dict=expected_dict) def testSumParseResults(self): samplestr1 = "garbage;DOB 10-10-2010;more garbage\nID PARI12345678;more garbage" samplestr2 = "garbage;ID PARI12345678;more garbage\nDOB 10-10-2010;more garbage" samplestr3 = "garbage;DOB 10-10-2010" samplestr4 = "garbage;ID PARI12345678;more garbage- I am cool" res1 = "ID:PARI12345678 DOB:10-10-2010 INFO:" res2 = "ID:PARI12345678 DOB:10-10-2010 INFO:" res3 = "ID: DOB:10-10-2010 INFO:" res4 = "ID:PARI12345678 DOB: INFO: I am cool" dob_ref = "DOB" + pp.Regex(r"\d{2}-\d{2}-\d{4}")("dob") id_ref = "ID" + pp.Word(pp.alphanums, exact=12)("id") info_ref = "-" + pp.rest_of_line("info") person_data = dob_ref | id_ref | info_ref tests = (samplestr1, samplestr2, samplestr3, samplestr4) results = (res1, res2, res3, res4) for test, expected in zip(tests, results): person = sum(person_data.search_string(test)) result = f"ID:{person.id} DOB:{person.dob} INFO:{person.info}" print(test) print(expected) print(result) for pd in person_data.search_string(test): print(pd.dump()) print() self.assertEqual( expected, result, f"Failed to parse '{test}' correctly, \nexpected '{expected}', got '{result}'", ) def testMarkInputLine(self): samplestr1 = "DOB 100-10-2010;more garbage\nID PARI12345678;more garbage" dob_ref = "DOB" + pp.Regex(r"\d{2}-\d{2}-\d{4}")("dob") try: res = dob_ref.parse_string(samplestr1, parse_all=True) except ParseException as pe: outstr = pe.mark_input_line() print(outstr) self.assertEqual( "DOB >!<100-10-2010;more garbage", outstr, "did not properly create marked input line", ) else: self.fail("test construction failed - should have raised an exception") def testDeprecatedNonPep8Names(self): word = pp.Word(pp.alphas) with self.assertWarns(PyparsingDeprecationWarning): word[...].parseString("ABC DEF") with self.assertWarns(DeprecationWarning): word[...].parseString("ABC DEF") def testLocatedExpr(self): # 012345678901234567890123456789012345678901234567890 samplestr1 = "DOB 10-10-2010;more garbage;ID PARI12345678 ;more garbage" with self.assertWarns(PyparsingDeprecationWarning): id_ref = pp.locatedExpr("ID" + pp.Word(pp.alphanums, exact=12)("id")) res = id_ref.search_string(samplestr1)[0][0] print(res.dump()) self.assertEqual( "ID PARI12345678", samplestr1[res.locn_start : res.locn_end], "incorrect location calculation", ) def testLocatedExprUsingLocated(self): # 012345678901234567890123456789012345678901234567890 samplestr1 = "DOB 10-10-2010;more garbage;ID PARI12345678 ;more garbage" id_ref = pp.Located("ID" + pp.Word(pp.alphanums, exact=12)("id")) res = id_ref.search_string(samplestr1)[0] print(res.dump()) self.assertEqual( "ID PARI12345678", samplestr1[res.locn_start : res.locn_end], "incorrect location calculation", ) self.assertParseResultsEquals( res, [28, ["ID", "PARI12345678"], 43], {"locn_end": 43, "locn_start": 28, "value": {"id": "PARI12345678"}}, ) self.assertEqual("PARI12345678", res.value.id) # if Located has a results name, handle appropriately id_ref = pp.Located("ID" + pp.Word(pp.alphanums, exact=12)("id"))("loc") res = id_ref.search_string(samplestr1)[0] print(res.dump()) self.assertEqual( "ID PARI12345678", samplestr1[res.loc.locn_start : res.loc.locn_end], "incorrect location calculation", ) self.assertParseResultsEquals( res.loc, [28, ["ID", "PARI12345678"], 43], {"locn_end": 43, "locn_start": 28, "value": {"id": "PARI12345678"}}, ) self.assertEqual("PARI12345678", res.loc.value.id) wd = pp.Word(pp.alphas) test_string = "ljsdf123lksdjjf123lkkjj1222" pp_matches = pp.Located(wd).search_string(test_string) re_matches = find_all_re_matches("[a-z]+", test_string) for pp_match, re_match in zip(pp_matches, re_matches): self.assertParseResultsEquals( pp_match, [re_match.start(), [re_match.group(0)], re_match.end()] ) print(pp_match) print(re_match) print(pp_match.value) def testPop(self): source = "AAA 123 456 789 234" patt = pp.Word(pp.alphas)("name") + pp.Word(pp.nums) * (1,) result = patt.parse_string(source, parse_all=True) tests = [ (0, "AAA", ["123", "456", "789", "234"]), (None, "234", ["123", "456", "789"]), ("name", "AAA", ["123", "456", "789"]), (-1, "789", ["123", "456"]), ] for test in tests: idx, val, remaining = test if idx is not None: ret = result.pop(idx) else: ret = result.pop() print("EXP:", val, remaining) print("GOT:", ret, result.as_list()) print(ret, result.as_list()) self.assertEqual( val, ret, f"wrong value returned, got {ret!r}, expected {val!r}", ) self.assertEqual( remaining, result.as_list(), f"list is in wrong state after pop, got {result.as_list()!r}, expected {remaining!r}", ) print() prevlist = result.as_list() ret = result.pop("name", default="noname") print(ret) print(result.as_list()) self.assertEqual( "noname", ret, f"default value not successfully returned, got {ret!r}, expected {'noname'!r}", ) self.assertEqual( prevlist, result.as_list(), f"list is in wrong state after pop, got {result.as_list()!r}, expected {remaining!r}", ) def testPopKwargsErr(self): """raise a TypeError in pop by adding invalid named args""" source = "AAA 123 456 789 234" patt = pp.Word(pp.alphas)("name") + pp.Word(pp.nums) * (1,) result = patt.parse_string(source, parse_all=True) print(result.dump()) with self.assertRaises(TypeError): result.pop(notDefault="foo") def testAddCondition(self): numParser = pp.Word(pp.nums) numParser.add_parse_action(lambda s, l, t: int(t[0])) numParser.add_condition(lambda s, l, t: t[0] % 2) numParser.add_condition(lambda s, l, t: t[0] >= 7) result = numParser.search_string("1 2 3 4 5 6 7 8 9 10") print(result.as_list()) self.assertEqual( [[7], [9]], result.as_list(), "failed to properly process conditions" ) numParser = pp.Word(pp.nums) numParser.add_parse_action(lambda s, l, t: int(t[0])) rangeParser = numParser("from_") + pp.Suppress("-") + numParser("to") result = rangeParser.search_string("1-4 2-4 4-3 5 6 7 8 9 10") print(result.as_list()) self.assertEqual( [[1, 4], [2, 4], [4, 3]], result.as_list(), "failed to properly process conditions", ) rangeParser.add_condition( lambda t: t.to > t.from_, message="from must be <= to", fatal=False ) result = rangeParser.search_string("1-4 2-4 4-3 5 6 7 8 9 10") print(result.as_list()) self.assertEqual( [[1, 4], [2, 4]], result.as_list(), "failed to properly process conditions" ) rangeParser = numParser("from_") + pp.Suppress("-") + numParser("to") rangeParser.add_condition( lambda t: t.to > t.from_, message="from must be <= to", fatal=True ) try: result = rangeParser.search_string("1-4 2-4 4-3 5 6 7 8 9 10") self.fail("failed to interrupt parsing on fatal condition failure") except ParseFatalException: print("detected fatal condition") def testPatientOr(self): # Two expressions and a input string which could - syntactically - be matched against # both expressions. The "Literal" expression is considered invalid though, so this PE # should always detect the "Word" expression. def validate(token): if token[0] == "def": raise pp.ParseException("signalling invalid token") return token a = pp.Word("de").set_name("Word") # .set_debug() b = ( pp.Literal("def").set_name("Literal").set_parse_action(validate) ) # .set_debug() c = pp.Literal("d").set_name("d") # .set_debug() # The "Literal" expressions's ParseAction is not executed directly after syntactically # detecting the "Literal" Expression but only after the Or-decision has been made # (which is too late)... try: result = (a ^ b ^ c).parse_string("def", parse_all=False) print(result) self.assertEqual( ["de"], result.as_list(), f"failed to select longest match, chose {result}", ) except ParseException: failed = True else: failed = False if failed: self.fail( "invalid logic in Or, fails on longest match with exception in parse action" ) # from issue #93 word = pp.Word(pp.alphas).set_name("word") word_1 = ( pp.Word(pp.alphas) .set_name("word_1") .add_condition(lambda t: len(t[0]) == 1) ) a = word + (word_1 + word ^ word) b = word * 3 c = a ^ b c.streamline() print(c) test_string = "foo bar temp" result = c.parse_string(test_string, parse_all=True) print(test_string, "->", result.as_list()) self.assertEqual( test_string.split(), result.as_list(), "failed to match longest choice" ) def testEachWithOptionalWithResultsName(self): result = (pp.Optional("foo")("one") & pp.Optional("bar")("two")).parse_string( "bar foo", parse_all=True ) print(result.dump()) self.assertEqual(sorted(["one", "two"]), sorted(result.keys())) def testUnicodeExpression(self): z = "a" | pp.Literal("\u1111") z.streamline() try: z.parse_string("b", parse_all=True) except ParseException as pe: self.assertEqual( r"""Expected {'a' | 'ᄑ'}""", pe.msg, f"Invalid error message raised, got {pe.msg!r}", ) def testSetName(self): a = pp.one_of("a b c") b = pp.one_of("d e f") # fmt: off arith_expr = pp.infix_notation( pp.Word(pp.nums), [ (pp.one_of("* /").set_name("* | /"), 2, pp.OpAssoc.LEFT), (pp.one_of("+ -").set_name("+ | -"), 2, pp.OpAssoc.LEFT), ], ) arith_expr2 = pp.infix_notation( pp.Word(pp.nums), [ (("?", ":"), 3, pp.OpAssoc.LEFT), ] ) # fmt: on recursive = pp.Forward() recursive <<= a + (b + recursive)[...] tests = [ a, b, (a | b), arith_expr, arith_expr.expr, arith_expr2, arith_expr2.expr, recursive, pp.DelimitedList(pp.Word(pp.nums).set_name("int")), pp.counted_array(pp.Word(pp.nums).set_name("int")), pp.nested_expr(), pp.make_html_tags("Z"), (pp.any_open_tag, pp.any_close_tag), pp.common_html_entity, pp.common_html_entity.set_parse_action( pp.replace_html_entity ).transform_string("lsdjkf <lsdjkf>&'"&xyzzy;"), ] expected = map( str.strip, """\ 'a' | 'b' | 'c' 'd' | 'e' | 'f' {'a' | 'b' | 'c' | 'd' | 'e' | 'f'} W:(0-9)_expression + | - operations W:(0-9)_expression ?: operations Forward: {'a' | 'b' | 'c' [{'d' | 'e' | 'f' : ...}]...} int [, int]... (len) int... nested () expression (<Z>, </Z>) (<any tag>, </any tag>) common HTML entity lsdjkf <lsdjkf>&'"&xyzzy;""".splitlines(), ) for t, e in zip(tests, expected): with self.subTest("set_name", t=t, e=e): tname = str(t) print(tname) self.assertEqual( e, tname, f"expression name mismatch, expected {e} got {tname}", ) def testTrimArityExceptionMasking(self): invalid_message = "<lambda>() missing 1 required positional argument: 't'" try: pp.Word("a").set_parse_action(lambda t: t[0] + 1).parse_string( "aaa", parse_all=True ) except Exception as e: exc_msg = str(e) self.assertNotEqual( exc_msg, invalid_message, "failed to catch TypeError thrown in _trim_arity", ) def testTrimArityExceptionMaskingTest2(self): # construct deep call tree def A(): import traceback traceback.print_stack(limit=2) invalid_message = "<lambda>() missing 1 required positional argument: 't'" try: pp.Word("a").set_parse_action(lambda t: t[0] + 1).parse_string( "aaa", parse_all=True ) except Exception as e: exc_msg = str(e) self.assertNotEqual( exc_msg, invalid_message, "failed to catch TypeError thrown in _trim_arity", ) def B(): A() def C(): B() def D(): C() def E(): D() def F(): E() def G(): F() def H(): G() def J(): H() def K(): J() K() def testClearParseActions(self): realnum = ppc.real() self.assertEqual( 3.14159, realnum.parse_string("3.14159", parse_all=True)[0], "failed basic real number parsing", ) # clear parse action that converts to float realnum.set_parse_action(None) self.assertEqual( "3.14159", realnum.parse_string("3.14159", parse_all=True)[0], "failed clearing parse action", ) # add a new parse action that tests if a '.' is prsent realnum.add_parse_action(lambda t: "." in t[0]) self.assertEqual( True, realnum.parse_string("3.14159", parse_all=True)[0], "failed setting new parse action after clearing parse action", ) def testOneOrMoreStop(self): test = "BEGIN aaa bbb ccc END" BEGIN, END = map(pp.Keyword, "BEGIN,END".split(",")) body_word = pp.Word(pp.alphas).set_name("word") for ender in (END, "END", pp.CaselessKeyword("END")): expr = BEGIN + pp.OneOrMore(body_word, stop_on=ender) + END self.assertEqual( expr, test, f"Did not successfully stop on ending expression {ender!r}" ) expr = BEGIN + body_word[1, ...].stopOn(ender) + END self.assertParseAndCheckList( expr, test, test.split(), f"Did not successfully stop on ending expression {ender!r}", ) expr = BEGIN + body_word[1, ...:ender] + END self.assertParseAndCheckList( expr, test, test.split(), f"Did not successfully stop on ending expression {ender!r}", ) expr = BEGIN + body_word[(1, ...):ender] + END self.assertParseAndCheckList( expr, test, test.split(), f"Did not successfully stop on ending expression {ender!r}", ) number = pp.Word(pp.nums + ",.()").set_name("number with optional commas") parser = pp.OneOrMore(pp.Word(pp.alphanums + "-/."), stop_on=number)( "id" ).set_parse_action(" ".join) + number("data") self.assertParseAndCheckList( parser, " XXX Y/123 1,234.567890", ["XXX Y/123", "1,234.567890"], f"Did not successfully stop on ending expression {number!r}", verbose=True, ) def testZeroOrMoreStop(self): test = "BEGIN END" BEGIN, END = map(pp.Keyword, "BEGIN,END".split(",")) body_word = pp.Word(pp.alphas).set_name("word") for ender in (END, "END", pp.CaselessKeyword("END")): expr = BEGIN + pp.ZeroOrMore(body_word, stop_on=ender) + END self.assertParseAndCheckList( expr, test, test.split(), f"Did not successfully stop on ending expression {ender!r}", ) expr = BEGIN + body_word[...].stopOn(ender) + END self.assertParseAndCheckList( expr, test, test.split(), f"Did not successfully stop on ending expression {ender!r}", ) expr = BEGIN + body_word[...:ender] + END self.assertParseAndCheckList( expr, test, test.split(), f"Did not successfully stop on ending expression {ender!r}", ) expr = BEGIN + body_word[:ender] + END self.assertParseAndCheckList( expr, test, test.split(), f"Did not successfully stop on ending expression {ender!r}", ) def testNestedAsDict(self): equals = pp.Literal("=").suppress() lbracket = pp.Literal("[").suppress() rbracket = pp.Literal("]").suppress() lbrace = pp.Literal("{").suppress() rbrace = pp.Literal("}").suppress() value_dict = pp.Forward() value_list = pp.Forward() value_string = pp.Word(pp.alphanums + "@. ") value = value_list ^ value_dict ^ value_string values = pp.Group(pp.DelimitedList(value, ",")) # ~ values = DelimitedList(value, ",").set_parse_action(lambda toks: [toks.as_list()]) value_list <<= lbracket + values + rbracket identifier = pp.Word(pp.alphanums + "_.") assignment = pp.Group(identifier + equals + pp.Optional(value)) assignments = pp.Dict(pp.DelimitedList(assignment, ";")) value_dict <<= lbrace + assignments + rbrace response = assignments rsp = ( "username=goat; errors={username=[already taken, too short]}; empty_field=" ) result_dict = response.parse_string(rsp, parse_all=True).as_dict() print(result_dict) self.assertEqual( "goat", result_dict["username"], "failed to process string in ParseResults correctly", ) self.assertEqual( ["already taken", "too short"], result_dict["errors"]["username"], "failed to process nested ParseResults correctly", ) def testTraceParseActionDecorator(self): @pp.trace_parse_action def convert_to_int(t): return int(t[0]) class Z: def __call__(self, other): return other[0] * 1000 integer = pp.Word(pp.nums).add_parse_action(convert_to_int) integer.add_parse_action(pp.trace_parse_action(lambda t: t[0] * 10)) integer.add_parse_action(pp.trace_parse_action(Z())) integer.parse_string("132", parse_all=True) def testTraceParseActionDecorator_with_exception(self): @pp.trace_parse_action def convert_to_int_raising_type_error(t): return int(t[0]) + ".000" @pp.trace_parse_action def convert_to_int_raising_index_error(t): return int(t[1]) @pp.trace_parse_action def convert_to_int_raising_value_error(t): a, b = t[0] return int(t[1]) @pp.trace_parse_action def convert_to_int_raising_parse_exception(t): pp.Word(pp.alphas).parse_string("123") for pa, expected_message in ( (convert_to_int_raising_type_error, "TypeError:"), (convert_to_int_raising_index_error, "IndexError:"), (convert_to_int_raising_value_error, "ValueError:"), (convert_to_int_raising_parse_exception, "ParseException:"), ): print(f"Using parse action {pa.__name__!r}") integer = pp.Word(pp.nums).set_parse_action(pa) stderr_capture = StringIO() try: with contextlib.redirect_stderr(stderr_capture): integer.parse_string("132", parse_all=True) except Exception as exc: print(f"Exception raised: {type(exc).__name__}: {exc}") else: print("No exception raised") stderr_text = stderr_capture.getvalue() print(stderr_text) self.assertTrue( expected_message in stderr_text, f"Expected exception type {expected_message!r} not found in trace_parse_action output", ) def testRunTests(self): integer = pp.Word(pp.nums).set_parse_action(lambda t: int(t[0])) intrange = integer("start") + "-" + integer("end") intrange.add_condition( lambda t: t.end > t.start, message="invalid range, start must be <= end", fatal=True, ) intrange.add_parse_action(lambda t: list(range(t.start, t.end + 1))) indices = pp.DelimitedList(intrange | integer) indices.add_parse_action(lambda t: sorted(set(t))) tests = """\ # normal data 1-3,2-4,6,8-10,16 # lone integer 11""" results = indices.run_tests(tests, print_results=False)[1] expectedResults = [[1, 2, 3, 4, 6, 8, 9, 10, 16], [11]] for res, expected in zip(results, expectedResults): print(res[1].as_list()) print(expected) self.assertEqual( expected, res[1].as_list(), "failed test: " + str(expected) ) tests = """\ # invalid range 1-2, 3-1, 4-6, 7, 12 """ success, _ = indices.run_tests(tests, print_results=False, failure_tests=True) self.assertTrue(success, "failed to raise exception on improper range test") def testRunTestsPostParse(self): integer = ppc.integer fraction = integer("numerator") + "/" + integer("denominator") accum = [] def eval_fraction(test, result): accum.append((test, result.as_list())) return f"eval: {result.numerator / result.denominator}" success, _ = fraction.run_tests( """\ 1/2 1/0 """, post_parse=eval_fraction, ) self.assertTrue(success, "failed to parse fractions in RunTestsPostParse") expected_accum = [("1/2", [1, "/", 2]), ("1/0", [1, "/", 0])] self.assertEqual( expected_accum, accum, "failed to call post_parse method during run_tests" ) def testConvertToDateErr(self): """raise a ParseException in convert_to_date with incompatible date str""" expr = pp.Word(pp.alphanums + "-") expr.add_parse_action(ppc.convert_to_date()) with self.assertRaisesParseException(): expr.parse_string("1997-07-error", parse_all=True) def testConvertToDatetimeErr(self): """raise a ParseException in convert_to_datetime with incompatible datetime str""" expr = pp.Word(pp.alphanums + "-") expr.add_parse_action(ppc.convert_to_datetime()) with self.assertRaisesParseException(): expr.parse_string("1997-07-error", parse_all=True) def testCommonExpressions(self): import ast with self.subTest("MAC address success run_tests"): success, _ = ppc.mac_address.run_tests( """ AA:BB:CC:DD:EE:FF AA.BB.CC.DD.EE.FF AA-BB-CC-DD-EE-FF """ ) self.assertTrue(success, "error in parsing valid MAC address") with self.subTest("MAC address expected failure run_tests"): success, _ = ppc.mac_address.run_tests( """ # mixed delimiters AA.BB:CC:DD:EE:FF """, failure_tests=True, ) self.assertTrue(success, "error in detecting invalid mac address") with self.subTest("IPv4 address success run_tests"): success, _ = ppc.ipv4_address.run_tests( """ 0.0.0.0 1.1.1.1 127.0.0.1 1.10.100.199 255.255.255.255 """ ) self.assertTrue(success, "error in parsing valid IPv4 address") with self.subTest("IPv4 address expected failure run_tests"): success, _ = ppc.ipv4_address.run_tests( """ # out of range value 256.255.255.255 """, failure_tests=True, ) self.assertTrue(success, "error in detecting invalid IPv4 address") with self.subTest("IPv6 address success run_tests"): success, _ = ppc.ipv6_address.run_tests( """ 2001:0db8:85a3:0000:0000:8a2e:0370:7334 2134::1234:4567:2468:1236:2444:2106 0:0:0:0:0:0:A00:1 1080::8:800:200C:417A ::A00:1 # loopback address ::1 # the null address :: # ipv4 compatibility form ::ffff:192.168.0.1 """ ) self.assertTrue(success, "error in parsing valid IPv6 address") with self.subTest("IPv6 address expected failure run_tests"): success, _ = ppc.ipv6_address.run_tests( """ # too few values 1080:0:0:0:8:800:200C # too many ::'s, only 1 allowed 2134::1234:4567::2444:2106 """, failure_tests=True, ) self.assertTrue(success, "error in detecting invalid IPv6 address") with self.subTest("ppc.number success run_tests"): success, _ = ppc.number.run_tests( """ 100 -100 +100 3.14159 6.02e23 1e-12 """ ) self.assertTrue(success, "error in parsing valid numerics") with self.subTest("ppc.sci_real success run_tests"): success, _ = ppc.sci_real.run_tests( """ 1e12 -1e12 3.14159 6.02e23 """ ) self.assertTrue(success, "error in parsing valid scientific notation reals") # any int or real number, returned as float with self.subTest("ppc.fnumber success run_tests"): success, _ = ppc.fnumber.run_tests( """ 100 -100 +100 3.14159 6.02e23 1e-12 """ ) self.assertTrue(success, "error in parsing valid numerics") with self.subTest("ppc.ieee_float success run_tests"): success, _ = ppc.ieee_float.run_tests( """ 100 3.14159 6.02e23 1E-12 0 -0 NaN -nan inf -Infinity """ ) self.assertTrue(success, "error in parsing valid floating-point literals") with self.subTest("ppc.iso8601_date success run_tests"): success, results = ppc.iso8601_date.run_tests( """ 1997 1997-07 1997-07-16 """ ) self.assertTrue(success, "error in parsing valid iso8601_date") expected = [ ("1997", None, None), ("1997", "07", None), ("1997", "07", "16"), ] for r, exp in zip(results, expected): self.assertEqual( exp, (r[1].year, r[1].month, r[1].day), "failed to parse date into fields", ) with self.subTest("ppc.iso8601_date conversion success run_tests"): success, results = ( ppc.iso8601_date() .add_parse_action(ppc.convert_to_date()) .run_tests( """ 1997-07-16 """ ) ) self.assertTrue( success, "error in parsing valid iso8601_date with parse action" ) self.assertEqual( datetime.date(1997, 7, 16), results[0][1][0], "error in parsing valid iso8601_date with parse action - incorrect value", ) with self.subTest("ppc.iso8601_datetime success run_tests"): success, results = ppc.iso8601_datetime.run_tests( """ 1997-07-16T19:20+01:00 1997-07-16T19:20:30+01:00 1997-07-16T19:20:30.45Z 1997-07-16 19:20:30.45 """ ) self.assertTrue(success, "error in parsing valid iso8601_datetime") with self.subTest("ppc.iso8601_datetime conversion success run_tests"): success, results = ( ppc.iso8601_datetime() .add_parse_action(ppc.convert_to_datetime()) .run_tests( """ 1997-07-16T19:20:30.45 """ ) ) self.assertTrue(success, "error in parsing valid iso8601_datetime") self.assertEqual( datetime.datetime(1997, 7, 16, 19, 20, 30, 450000), results[0][1][0], "error in parsing valid iso8601_datetime - incorrect value", ) with self.subTest("ppc.uuid success run_tests"): success, _ = ppc.uuid.run_tests( """ 123e4567-e89b-12d3-a456-426655440000 """ ) self.assertTrue(success, "failed to parse valid uuid") with self.subTest("ppc.fraction success run_tests"): success, _ = ppc.fraction.run_tests( """ 1/2 -15/16 -3/-4 """ ) self.assertTrue(success, "failed to parse valid fraction") with self.subTest("ppc.mixed_integer success run_tests"): success, _ = ppc.mixed_integer.run_tests( """ 1/2 -15/16 -3/-4 1 1/2 2 -15/16 0 -3/-4 12 """ ) self.assertTrue(success, "failed to parse valid mixed integer") with self.subTest("ppc.number success run_tests"): success, results = ppc.number.run_tests( """ 100 -3 1.732 -3.14159 6.02e23""" ) self.assertTrue(success, "failed to parse numerics") for test, result in results: expected = ast.literal_eval(test) self.assertEqual( expected, result[0], f"numeric parse failed (wrong value) ({result[0]} should be {expected})", ) self.assertEqual( type(expected), type(result[0]), f"numeric parse failed (wrong type) ({type(result[0])} should be {type(expected)})", ) def testDateTimeValidation(self): if sys.version_info[:2] < (3, 10): return ppc = pp.pyparsing_common date_expr = ppc.iso8601_date_validated datetime_expr = ppc.iso8601_datetime_validated valid_dates = [ "2023-01-01", "2024-02-29", # Leap year "2000-02-29", # Century leap year "1900-01-01", "9999-12-31", "2023-12", # Optional day "2023", # Optional month and day ] for d in valid_dates: with self.subTest(date=d): date_expr.parse_string(d, parse_all=True) invalid_dates = [ "2023-02-29", # Not a leap year "2023-04-31", # April has 30 days "2023-13-01", # Invalid month "2023-00-01", # Invalid month "2023-01-32", # Invalid day "2023-01-00", # Invalid day "1900-02-29", # 1900 was not a leap year ] for d in invalid_dates: with self.subTest(date=d): with self.assertRaises(pp.ParseException): date_expr.parse_string(d, parse_all=True) valid_datetimes = [ "2023-01-01T12:00:00", "2023-01-01 12:00:00", "2023-01-01T12:00:00Z", "2023-01-01T12:00:00+05:00", "2023-01-01T12:00:00-05:00", "2023-01-01T12:00:00.123", "2023-01-01T12:00:00.123Z", "2024-02-29T23:59:59", ] for dt in valid_datetimes: with self.subTest(datetime=dt): datetime_expr.parse_string(dt, parse_all=True) invalid_datetimes = [ "2023-02-29T12:00:00", # Invalid date "2023-01-01T24:00:00", # Invalid hour "2023-01-01T12:60:00", # Invalid minute "2023-01-01T12:00:60", # Invalid second # "2023-01-01T12:00:00+24:00", # Invalid timezone (Regex might catch it or not, valid_date_time doesn't check it) ] for dt in invalid_datetimes: with self.subTest(datetime=dt): with self.assertRaises(pp.ParseException): datetime_expr.parse_string(dt, parse_all=True) def testCommonUrl(self): url_good_tests = """\ http://foo.com/blah_blah http://foo.com/blah_blah/ http://foo.com/blah_blah_(wikipedia) http://foo.com/blah_blah_(wikipedia)_(again) http://www.example.com/wpstyle/?p=364 https://www.example.com/foo/?bar=baz&inga=42&quux http://✪df.ws/123 http://userid:password@example.com:8080 http://userid:password@example.com:8080/ http://userid@example.com http://userid@example.com/ http://userid@example.com:8080 http://userid@example.com:8080/ http://userid:password@example.com http://userid:password@example.com/ http://142.42.1.1/ http://142.42.1.1:8080/ http://➡.ws/䨹 http://⌘.ws http://⌘.ws/ http://foo.com/blah_(wikipedia)#cite-1 http://foo.com/blah_(wikipedia)_blah#cite-1 http://foo.com/unicode_(✪)_in_parens http://foo.com/(something)?after=parens http://☺.damowmow.com/ http://code.google.com/events/#&product=browser http://j.mp ftp://foo.bar/baz http://foo.bar/?q=Test%20URL-encoded%20stuff http://مثال.إختبار """ success, report = ppc.url.run_tests(url_good_tests) self.assertTrue(success) url_bad_tests = """\ http:// http://. http://.. http://../ http://? http://?? http://??/ http://# http://## http://##/ # skip: http://foo.bar?q=Spaces should be encoded // //a ///a /// http:///a foo.com rdar://1234 h://test http:// shouldfail.com :// should fail http://foo.bar/foo(bar)baz quux ftps://foo.bar/ http://-error-.invalid/ # skip: http://a.b--c.de/ http://-a.b.co http://a.b-.co http://0.0.0.0 http://10.1.1.0 http://10.1.1.255 http://224.1.1.1 http://1.1.1.1.1 http://123.123.123 http://3628126748 http://.www.foo.bar/ # skip: http://www.foo.bar./ http://.www.foo.bar./ http://10.1.1.1 """ success, report = ppc.url.run_tests(url_bad_tests, failure_tests=True) self.assertTrue(success) def testCommonUrlParts(self): from urllib.parse import urlparse sample_url = "https://bob:secret@www.example.com:8080/path/to/resource?filter=int#book-mark" parts = urlparse(sample_url) expected = { "scheme": parts.scheme, "auth": f"{parts.username}:{parts.password}", "host": parts.hostname, "port": str(parts.port), "path": parts.path, "query": parts.query, "fragment": parts.fragment, "url": sample_url, } self.assertParseAndCheckDict(ppc.url, sample_url, expected, verbose=True) def testCommonUrlExprs(self): def extract_parts(s, split=" "): return [[_.strip(split)] for _ in s.strip(split).split(split)] test_string = "http://example.com https://blah.org " self.assertParseAndCheckList( pp.Group(ppc.url)[...], test_string, extract_parts(test_string) ) test_string = test_string.replace(" ", " , ") self.assertParseAndCheckList( pp.DelimitedList(pp.Group(ppc.url), allow_trailing_delim=True), test_string, extract_parts(test_string, " , "), ) def testNumericExpressions(self): # disable parse actions that do type conversion so we don't accidentally trigger # conversion exceptions when what we want to check is the parsing expression real = ppc.real().set_parse_action(None) sci_real = ppc.sci_real().set_parse_action(None) signed_integer = ppc.signed_integer().set_parse_action(None) from itertools import product def make_tests(): leading_sign = ["+", "-", ""] leading_digit = ["0", ""] dot = [".", ""] decimal_digit = ["1", ""] e = ["e", "E", ""] e_sign = ["+", "-", ""] e_int = ["22", ""] stray = ["9", ".", ""] seen = set() seen.add("") for parts in product( leading_sign, stray, leading_digit, dot, decimal_digit, stray, e, e_sign, e_int, stray, ): parts_str = "".join(parts).strip() if parts_str in seen: continue seen.add(parts_str) yield parts_str print(len(seen) - 1, "tests produced") # collect tests into valid/invalid sets, depending on whether they evaluate to valid Python floats or ints valid_ints = set() valid_reals = set() valid_sci_reals = set() invalid_ints = set() invalid_reals = set() invalid_sci_reals = set() # check which strings parse as valid floats or ints, and store in related valid or invalid test sets for test_str in make_tests(): if "." in test_str or "e" in test_str.lower(): try: float(test_str) except ValueError: invalid_sci_reals.add(test_str) if "e" not in test_str.lower(): invalid_reals.add(test_str) else: valid_sci_reals.add(test_str) if "e" not in test_str.lower(): valid_reals.add(test_str) try: int(test_str) except ValueError: invalid_ints.add(test_str) else: valid_ints.add(test_str) # now try all the test sets against their respective expressions all_pass = True suppress_results = {"print_results": False} for expr, tests, is_fail, fn in zip( [real, sci_real, signed_integer] * 2, [ valid_reals, valid_sci_reals, valid_ints, invalid_reals, invalid_sci_reals, invalid_ints, ], [False, False, False, True, True, True], [float, float, int] * 2, ): # # success, test_results = expr.run_tests(sorted(tests, key=len), failure_tests=is_fail, **suppress_results) # filter_result_fn = (lambda r: isinstance(r, Exception), # lambda r: not isinstance(r, Exception))[is_fail] # print(expr, ('FAIL', 'PASS')[success], "{}valid tests ({})".format(len(tests), # 'in' if is_fail else '')) # if not success: # all_pass = False # for test_string, result in test_results: # if filter_result_fn(result): # try: # test_value = fn(test_string) # except ValueError as ve: # test_value = str(ve) # print("{!r}: {} {} {}".format(test_string, result, # expr.matches(test_string, parse_all=True), test_value)) success = True for t in tests: if expr.matches(t, parse_all=True): if is_fail: print(t, "should fail but did not") success = False else: if not is_fail: print(t, "should not fail but did") success = False print( expr, ("FAIL", "PASS")[success], f"{'in' if is_fail else ''}valid tests ({len(tests)})", ) all_pass = all_pass and success self.assertTrue(all_pass, "failed one or more numeric tests") def testTokenMap(self): parser = pp.OneOrMore(pp.Word(pp.hexnums)).set_parse_action( pp.token_map(int, 16) ) success, report = parser.run_tests( """ 00 11 22 aa FF 0a 0d 1a """ ) self.assertRunTestResults( (success, report), [([0, 17, 34, 170, 255, 10, 13, 26], "token_map parse action failed")], msg="failed to parse hex integers", ) def testParseFile(self): s = """ 123 456 789 """ from pathlib import Path integer = ppc.integer test_parser = integer[1, ...] input_file_as_stringio = StringIO(s) input_file_as_str = "tests/parsefiletest_input_file.txt" input_file_as_path = Path(input_file_as_str) expected_list = [int(i) for i in s.split()] for input_file in ( input_file_as_stringio, input_file_as_str, input_file_as_path, ): with self.subTest(input_file=input_file): print(f"parse_file() called with {type(input_file).__name__}") results = test_parser.parse_file(input_file) print(results) self.assertEqual(expected_list, results.as_list()) def testHTMLStripper(self): sample = """ <html> Here is some sample <i>HTML</i> text. </html> """ read_everything = pp.original_text_for(pp.OneOrMore(pp.Word(pp.printables))) read_everything.add_parse_action(ppc.strip_html_tags) result = read_everything.parse_string(sample, parse_all=True) self.assertEqual("Here is some sample HTML text.", result[0].strip()) def testExprSplitter(self): expr = pp.Literal(";") + pp.Empty() expr.ignore(pp.quoted_string) expr.ignore(pp.python_style_comment) sample = """ def main(): this_semi_does_nothing(); neither_does_this_but_there_are_spaces_afterward(); a = "a;b"; return a # this is a comment; it has a semicolon! def b(): if False: z=1000;b("; in quotes"); c=200;return z return ';' class Foo(object): def bar(self): '''a docstring; with a semicolon''' a = 10; b = 11; c = 12 # this comment; has several; semicolons if self.spam: x = 12; return x # so; does; this; one x = 15;;; y += x; return y def baz(self): return self.bar """ expected = [ [" this_semi_does_nothing()", ""], [" neither_does_this_but_there_are_spaces_afterward()", ""], [ ' a = "a;b"', "return a # this is a comment; it has a semicolon!", ], [" z=1000", 'b("; in quotes")', "c=200", "return z"], [" return ';'"], [" '''a docstring; with a semicolon'''"], [" a = 10", "b = 11", "c = 12"], [" # this comment; has several; semicolons"], [" x = 12", "return x # so; does; this; one"], [" x = 15", "", "", "y += x", "return y"], ] exp_iter = iter(expected) for line in filter(lambda ll: ";" in ll, sample.splitlines()): print(str(list(expr.split(line))) + ",") self.assertEqual( next(exp_iter), list(expr.split(line)), "invalid split on expression" ) print() expected = [ [" this_semi_does_nothing()", ";", ""], [" neither_does_this_but_there_are_spaces_afterward()", ";", ""], [ ' a = "a;b"', ";", "return a # this is a comment; it has a semicolon!", ], [ " z=1000", ";", 'b("; in quotes")', ";", "c=200", ";", "return z", ], [" return ';'"], [" '''a docstring; with a semicolon'''"], [" a = 10", ";", "b = 11", ";", "c = 12"], [" # this comment; has several; semicolons"], [" x = 12", ";", "return x # so; does; this; one"], [ " x = 15", ";", "", ";", "", ";", "y += x", ";", "return y", ], ] exp_iter = iter(expected) for line in filter(lambda ll: ";" in ll, sample.splitlines()): print(str(list(expr.split(line, include_separators=True))) + ",") self.assertEqual( next(exp_iter), list(expr.split(line, include_separators=True)), "invalid split on expression", ) print() expected = [ [" this_semi_does_nothing()", ""], [" neither_does_this_but_there_are_spaces_afterward()", ""], [ ' a = "a;b"', "return a # this is a comment; it has a semicolon!", ], [" z=1000", 'b("; in quotes"); c=200;return z'], [" a = 10", "b = 11; c = 12"], [" x = 12", "return x # so; does; this; one"], [" x = 15", ";; y += x; return y"], ] exp_iter = iter(expected) for line in sample.splitlines(): pieces = list(expr.split(line, maxsplit=1)) print(str(pieces) + ",") if len(pieces) == 2: exp = next(exp_iter) self.assertEqual( exp, pieces, "invalid split on expression with maxSplits=1" ) elif len(pieces) == 1: self.assertEqual( 0, len(expr.search_string(line)), "invalid split with maxSplits=1 when expr not present", ) else: print("\n>>> " + line) self.fail("invalid split on expression with maxSplits=1, corner case") def testParseFatalException(self): with self.assertRaisesParseException( exc_type=ParseFatalException, msg="failed to raise ErrorStop exception" ): expr = "ZZZ" - pp.Word(pp.nums) expr.parse_string("ZZZ bad", parse_all=True) def testParseFatalException2(self): # Fatal exception raised in MatchFirst should not be superseded later non-fatal exceptions # addresses Issue #251 def raise_exception(tokens): raise pp.ParseSyntaxException("should raise here") test = pp.MatchFirst( ( pp.pyparsing_common.integer + pp.pyparsing_common.identifier ).set_parse_action(raise_exception) | pp.pyparsing_common.number ) with self.assertRaisesParseException(pp.ParseFatalException): test.parse_string("1s", parse_all=True) def testParseFatalException3(self): # Fatal exception raised in MatchFirst should not be superseded later non-fatal exceptions # addresses Issue #251 test = pp.MatchFirst( (pp.pyparsing_common.integer - pp.pyparsing_common.identifier) | pp.pyparsing_common.integer ) with self.assertRaisesParseException(pp.ParseFatalException): test.parse_string("1", parse_all=True) def testInlineLiteralsUsing(self): wd = pp.Word(pp.alphas) pp.ParserElement.inline_literals_using(pp.Suppress) result = (wd + "," + wd + pp.one_of("! . ?")).parse_string( "Hello, World!", parse_all=True ) self.assertEqual(3, len(result), "inline_literals_using(Suppress) failed!") pp.ParserElement.inline_literals_using(pp.Literal) result = (wd + "," + wd + pp.one_of("! . ?")).parse_string( "Hello, World!", parse_all=True ) self.assertEqual(4, len(result), "inline_literals_using(Literal) failed!") pp.ParserElement.inline_literals_using(pp.CaselessKeyword) self.assertParseAndCheckList( "SELECT" + wd + "FROM" + wd, "select color from colors", expected_list=["SELECT", "color", "FROM", "colors"], msg="inline_literals_using(CaselessKeyword) failed!", verbose=True, ) pp.ParserElement.inline_literals_using(pp.CaselessLiteral) self.assertParseAndCheckList( "SELECT" + wd + "FROM" + wd, "select color from colors", expected_list=["SELECT", "color", "FROM", "colors"], msg="inline_literals_using(CaselessLiteral) failed!", verbose=True, ) integer = pp.Word(pp.nums) pp.ParserElement.inline_literals_using(pp.Literal) date_str = integer("year") + "/" + integer("month") + "/" + integer("day") self.assertParseAndCheckList( date_str, "1999/12/31", expected_list=["1999", "/", "12", "/", "31"], msg="inline_literals_using(example 1) failed!", verbose=True, ) # change to Suppress pp.ParserElement.inline_literals_using(pp.Suppress) date_str = integer("year") + "/" + integer("month") + "/" + integer("day") self.assertParseAndCheckList( date_str, "1999/12/31", expected_list=["1999", "12", "31"], msg="inline_literals_using(example 2) failed!", verbose=True, ) def testCloseMatch(self): searchseq = pp.CloseMatch("ATCATCGAATGGA", 2) _, results = searchseq.run_tests( """ ATCATCGAATGGA XTCATCGAATGGX ATCATCGAAXGGA ATCAXXGAATGGA ATCAXXGAATGXA ATCAXXGAATGG """ ) expected = ([], [0, 12], [9], [4, 5], None, None) for r, exp in zip(results, expected): if exp is not None: self.assertEqual( exp, r[1].mismatches, f"fail CloseMatch between {searchseq.match_string!r} and {r[0]!r}", ) print( r[0], ( f"exc: {r[1]}" if exp is None and isinstance(r[1], Exception) else ("no match", "match")[r[1].mismatches == exp] ), ) def testCloseMatchCaseless(self): searchseq = pp.CloseMatch("ATCATCGAATGGA", 2, caseless=True) _, results = searchseq.run_tests( """ atcatcgaatgga xtcatcgaatggx atcatcgaaxgga atcaxxgaatgga atcaxxgaatgxa atcaxxgaatgg """ ) expected = ([], [0, 12], [9], [4, 5], None, None) for r, exp in zip(results, expected): if exp is not None: self.assertEqual( exp, r[1].mismatches, f"fail CaselessCloseMatch between {searchseq.match_string!r} and {r[0]!r}", ) print( r[0], ( f"exc: {r[1]}" if exp is None and isinstance(r[1], Exception) else ("no match", "match")[r[1].mismatches == exp] ), ) def testDefaultKeywordChars(self): with self.assertRaisesParseException( msg="failed to fail matching keyword using updated keyword chars" ): pp.Keyword("start").parse_string("start1000", parse_all=True) try: pp.Keyword("start", ident_chars=pp.alphas).parse_string( "start1000", parse_all=False ) except pp.ParseException: self.fail("failed to match keyword using updated keyword chars") with ppt.reset_pyparsing_context(): pp.Keyword.set_default_keyword_chars(pp.alphas) try: pp.Keyword("start").parse_string("start1000", parse_all=False) except pp.ParseException: self.fail("failed to match keyword using updated keyword chars") with self.assertRaisesParseException( msg="failed to fail matching keyword using updated keyword chars" ): pp.CaselessKeyword("START").parse_string("start1000", parse_all=False) try: pp.CaselessKeyword("START", ident_chars=pp.alphas).parse_string( "start1000", parse_all=False ) except pp.ParseException: self.fail("failed to match keyword using updated keyword chars") with ppt.reset_pyparsing_context(): pp.Keyword.set_default_keyword_chars(pp.alphas) try: pp.CaselessKeyword("START").parse_string("start1000", parse_all=False) except pp.ParseException: self.assertTrue( False, "failed to match keyword using updated keyword chars" ) def testKeywordCopyIdentChars(self): a_keyword = pp.Keyword("start", ident_chars="_") b_keyword = a_keyword.copy() self.assertEqual(a_keyword.ident_chars, b_keyword.ident_chars) def testCopyLiteralAttrs(self): lit = pp.Literal("foo").leave_whitespace() lit2 = lit.copy() self.assertFalse(lit2.skipWhitespace) lit3 = lit2.ignore_whitespace().copy() self.assertTrue(lit3.skipWhitespace) def testWordParseImpl(self): ppc = pp.common ppu = pp.unicode ident_exprs = [ ppc.identifier, pp.Word(pp.alphas), pp.Literal("identifier"), pp.Regex(r"[a-zA-Z_][a-zA-Z0-9_]*"), pp.Regex(r"[a-zA-Z_][a-zA-Z0-9_]*", as_match=True), pp.Regex(r"[a-zA-Z_][a-zA-Z0-9_]*", as_group_list=True), ppu.BMP.identifier, pp.Char(pp.alphas), pp.Keyword("identifier"), ] for ident in ident_exprs: with self.subTest(msg=f"Using expression type {type(ident).__name__}"): custom_id = ( ident() .set_name("standard identifier") .copy() .set_name("custom identifier") ) with self.assertRaisesParseException( expected_msg="Expected custom identifier" ): custom_id.parse_string("1", parse_all=True) with self.subTest(msg="Using integer"): custom_int = ( ppc.integer() .set_name("standard integer") .copy() .set_name("custom integer") ) with self.assertRaisesParseException( expected_msg="Expected custom integer" ): custom_int.parse_string("z", parse_all=True) def testWordCopyWhenWordCharsIncludeSpace(self): # Issue #618 - with copy() word_with_space = pp.Word(pp.alphas + " ") word_with_space.parse_string("ABC") # no longer raises exception word_with_space.copy().parse_string("ABC") def testWordCopyWhenWordCharsIncludeSpace2(self): # Issue #618 - with DelimitedList() element = pp.QuotedString('"') | pp.Combine( pp.Word(" abcdefghijklmnopqrstuvwxyz") ) element.parse_string("abc") element_list = pp.DelimitedList(element) # no longer raises exception element_list.parse_string("abc") def testWordCopyWhenWordCharsIncludeSpace3(self): # Issue #618 - with results name word_with_space = pp.Word(pp.alphas + " ") word_with_space.parse_string("ABC") # no longer raises exception word_with_space("trouble").parse_string("ABC") def testLiteralVsKeyword(self): integer = ppc.integer literal_expr = integer + pp.Literal("start") + integer keyword_expr = integer + pp.Keyword("start") + integer caseless_keyword_expr = integer + pp.CaselessKeyword("START") + integer word_keyword_expr = ( integer + pp.Word(pp.alphas, as_keyword=True).set_name("word") + integer ) print() test_string = "1 start 2" print(test_string) print(literal_expr, literal_expr.parse_string(test_string, parse_all=True)) print(keyword_expr, keyword_expr.parse_string(test_string, parse_all=True)) print( caseless_keyword_expr, caseless_keyword_expr.parse_string(test_string, parse_all=True), ) print( word_keyword_expr, word_keyword_expr.parse_string(test_string, parse_all=True), ) print() test_string = "3 start4" print(test_string) print(literal_expr, literal_expr.parse_string(test_string, parse_all=True)) with self.assertRaisesParseException( msg="failed to fail matching keyword using updated keyword chars" ): print(keyword_expr.parse_string(test_string, parse_all=True)) with self.assertRaisesParseException( msg="failed to fail matching keyword using updated keyword chars" ): print(caseless_keyword_expr.parse_string(test_string, parse_all=True)) with self.assertRaisesParseException( msg="failed to fail matching keyword using updated keyword chars" ): print(word_keyword_expr.parse_string(test_string, parse_all=True)) print() test_string = "5start 6" print(test_string) print(literal_expr.parse_string(test_string, parse_all=True)) with self.assertRaisesParseException( msg="failed to fail matching keyword using updated keyword chars" ): print(keyword_expr.parse_string(test_string, parse_all=True)) with self.assertRaisesParseException( msg="failed to fail matching keyword using updated keyword chars" ): print(caseless_keyword_expr.parse_string(test_string, parse_all=True)) with self.assertRaisesParseException( msg="failed to fail matching keyword using updated keyword chars" ): print(word_keyword_expr.parse_string(test_string, parse_all=True)) def testCol(self): test = "*\n* \n* ALF\n*\n" initials = [c for i, c in enumerate(test) if pp.col(i, test) == 1] print(initials) self.assertTrue( len(initials) == 4 and all(c == "*" for c in initials), "fail col test" ) def testLiteralException(self): for cls in ( pp.Literal, pp.CaselessLiteral, pp.Keyword, pp.CaselessKeyword, pp.Word, pp.Regex, ): expr = cls("xyz") # .set_name('{}_expr'.format(cls.__name__.lower())) try: expr.parse_string(" ", parse_all=True) except Exception as e: print(cls.__name__, str(e)) self.assertTrue( isinstance(e, pp.ParseBaseException), f"class {cls.__name__} raised wrong exception type {type(e).__name__}", ) def testParseActionIndexErrorException(self): """ Tests raising an IndexError in a parse action """ import traceback number = pp.Word(pp.nums) def number_action(): raise IndexError # this is the important line! number.add_parse_action(number_action) symbol = pp.Word("abcd", max=1) expr = pp.Group(number) ^ symbol try: expr.parse_string("1 + 2", parse_all=True) except IndexError as ie: pass except Exception as e: traceback.print_exc() self.fail(f"Expected IndexError not raised, raised {type(e).__name__}: {e}") else: self.fail("Expected IndexError not raised") # tests Issue #22 def testParseActionNesting(self): vals = pp.OneOrMore(ppc.integer)("int_values") def add_total(tokens): tokens["total"] = sum(tokens) return tokens vals.add_parse_action(add_total) results = vals.parse_string("244 23 13 2343", parse_all=True) print(results.dump()) self.assertParseResultsEquals( results, expected_dict={"int_values": [244, 23, 13, 2343], "total": 2623}, msg="noop parse action changed ParseResults structure", ) name = pp.Word(pp.alphas)("name") score = pp.Word(pp.nums + ".")("score") nameScore = pp.Group(name + score) line1 = nameScore("Rider") result1 = line1.parse_string("Mauney 46.5", parse_all=True) print("### before parse action is added ###") print("result1.dump():\n" + result1.dump() + "\n") before_pa_dict = result1.as_dict() line1.set_parse_action(lambda t: t) result1 = line1.parse_string("Mauney 46.5", parse_all=True) after_pa_dict = result1.as_dict() print("### after parse action was added ###") print("result1.dump():\n" + result1.dump() + "\n") self.assertEqual( before_pa_dict, after_pa_dict, "noop parse action changed ParseResults structure", ) def testParseActionWithDelimitedList(self): class AnnotatedToken: def __init__(self, kind, elements): self.kind = kind self.elements = elements def __str__(self): return f"AnnotatedToken({self.kind!r}, {self.elements!r})" def __eq__(self, other): return ( type(self) == type(other) and self.kind == other.kind and self.elements == other.elements ) __repr__ = __str__ def annotate(name): def _(t): return AnnotatedToken(name, t.as_list()) return _ identifier = pp.Word(pp.srange("[a-z0-9]")) numeral = pp.Word(pp.nums) named_number_value = pp.Suppress("(") + numeral + pp.Suppress(")") named_number = identifier + named_number_value named_number_list = ( pp.Suppress("{") + pp.Group(pp.Optional(pp.DelimitedList(named_number))) + pp.Suppress("}") ) # repro but in #345 - DelimitedList silently changes contents of named_number named_number_value.set_parse_action(annotate("val")) test_string = "{ x1(1), x2(2) }" expected = [ ["x1", AnnotatedToken("val", ["1"]), "x2", AnnotatedToken("val", ["2"])] ] self.assertParseAndCheckList(named_number_list, test_string, expected) def testParseActionRunsInNotAny(self): # see Issue #482 data = """ [gog1] [G1] [gog2] [gog3] [gog4] [G2] [gog5] [G3] [gog6] """ poi_type = pp.Word(pp.alphas).set_results_name("type") poi = pp.Suppress("[") + poi_type + pp.Char(pp.nums) + pp.Suppress("]") def cnd_is_type(val): return lambda toks: toks.type == val poi_gog = poi("gog").add_condition(cnd_is_type("gog")) poi_g = poi("g").add_condition(cnd_is_type("G")) pattern = poi_gog + ~poi_g matches = pattern.search_string(data).as_list() self.assertEqual( [["gog", "2"], ["gog", "3"], ["gog", "6"]], matches, "failed testing parse actions being run inside a NotAny", ) def testParseResultsNameBelowUngroupedName(self): rule_num = pp.Regex("[0-9]+")("LIT_NUM*") list_num = pp.Group( pp.Literal("[")("START_LIST") + pp.DelimitedList(rule_num)("LIST_VALUES") + pp.Literal("]")("END_LIST") )("LIST") test_string = "[ 1,2,3,4,5,6 ]" success, _ = list_num.run_tests(test_string) self.assertTrue(success) U = list_num.parse_string(test_string, parse_all=True) self.assertTrue( "LIT_NUM" not in U.LIST.LIST_VALUES, "results name retained as sub in ungrouped named result", ) def testParseResultsNamesInGroupWithDict(self): key = ppc.identifier() value = ppc.integer() lat = ppc.real() long = ppc.real() EQ = pp.Suppress("=") data = ( lat("lat") + long("long") + pp.Dict(pp.OneOrMore(pp.Group(key + EQ + value))) ) site = pp.QuotedString('"')("name") + pp.Group(data)("data") test_string = '"Golden Gate Bridge" 37.819722 -122.478611 height=746 span=4200' success, _ = site.run_tests(test_string) self.assertTrue(success) a, aEnd = pp.make_html_tags("a") attrs = a.parse_string("<a href='blah'>", parse_all=True) print(attrs.dump()) self.assertParseResultsEquals( attrs, expected_dict={ "startA": {"href": "blah", "tag": "a", "empty": False}, "href": "blah", "tag": "a", "empty": False, }, ) def testMakeXMLTags(self): """test helper function make_xml_tags in simple use case""" body, bodyEnd = pp.make_xml_tags("body") tst = "<body>Hello</body>" expr = body + pp.Word(pp.alphas)("contents") + bodyEnd result = expr.parse_string(tst, parse_all=True) print(result.dump()) self.assertParseResultsEquals( result, ["body", False, "Hello", "</body>"], msg="issue using make_xml_tags" ) def testFollowedBy(self): expr = pp.Word(pp.alphas)("item") + pp.FollowedBy(ppc.integer("qty")) result = expr.parse_string("balloon 99", parse_all=False) print(result.dump()) self.assertTrue("qty" in result, "failed to capture results name in FollowedBy") self.assertEqual( {"item": "balloon", "qty": 99}, result.as_dict(), "invalid results name structure from FollowedBy", ) def testSetBreak(self): """ Test behavior of ParserElement.set_break(), to invoke the debugger before parsing that element is attempted. Temporarily monkeypatches sys.breakpointhook(). """ was_called = False def mock_set_trace(*args, **kwargs): nonlocal was_called was_called = True wd = pp.Word(pp.alphas) wd.set_break() print("Before parsing with set_break:", was_called) with ppt.reset_pyparsing_context(): sys.breakpointhook = mock_set_trace wd.parse_string("ABC", parse_all=True) print("After parsing with set_break:", was_called) sys.breakpointhook = sys.__breakpointhook__ self.assertTrue(was_called, "set_trace wasn't called by set_break") def testUnicodeTests(self): import unicodedata ppu = pp.pyparsing_unicode unicode_version = unicodedata.unidata_version print(f"Unicode version {unicode_version}") # verify ranges are converted to sets properly for unicode_property, expected_length in [ ("alphas", 48965), ("alphanums", 49430), ("identchars", 49013), ("identbodychars", 50729), ("printables", 65484), ]: charset = getattr(ppu.BMP, unicode_property) charset_len = len(charset) # this subtest is sensitive to the Unicode version used in the current # python version if unicode_version == "14.0.0": with self.subTest(unicode_property=unicode_property, msg="verify len"): print(f"ppu.BMP.{unicode_property:14}: {charset_len:6d}") self.assertEqual( charset_len, expected_length, f"incorrect number of ppu.BMP.{unicode_property}," f" found {charset_len} expected {expected_length}", ) with self.subTest(unicode_property=unicode_property, msg="verify unique"): char_counts = collections.Counter(charset) self.assertTrue( all(count == 1 for count in char_counts.values()), f"duplicate items found in ppu.BMP.{unicode_property}:" f" {[(ord(c), c) for c, count in char_counts.items() if count > 1]}", ) # verify proper merging of ranges by addition kanji_printables = ppu.Japanese.Kanji.printables katakana_printables = ppu.Japanese.Katakana.printables hiragana_printables = ppu.Japanese.Hiragana.printables japanese_printables = ppu.Japanese.printables with self.subTest(msg="verify constructing ranges by merging types"): self.assertEqual( set(kanji_printables + katakana_printables + hiragana_printables), set(japanese_printables), "failed to construct ranges by merging Japanese types", ) # verify proper merging of ranges using multiple inheritance cjk_printables = ppu.CJK.printables chinese_printables = ppu.Chinese.printables korean_printables = ppu.Korean.printables with self.subTest( msg="verify merging ranges by using multiple inheritance generates unique list of characters" ): char_counts = collections.Counter(cjk_printables) self.assertTrue( all(count == 1 for count in char_counts.values()), "duplicate items found in ppu.CJK.printables:" f" {[(ord(c), c) for c, count in char_counts.items() if count > 1]}", ) with self.subTest( msg="verify merging ranges by using multiple inheritance generates sorted list of characters" ): self.assertEqual( list(cjk_printables), sorted(cjk_printables), "CJK printables are not sorted", ) with self.subTest( msg="verify summing chars is equivalent to merging ranges by using multiple inheritance (CJK)" ): print( len(set(chinese_printables + korean_printables + japanese_printables)), len(cjk_printables), ) self.assertEqual( set(chinese_printables + korean_printables + japanese_printables), set(cjk_printables), "failed to construct ranges by merging Chinese, Japanese and Korean", ) def testUnicodeTests2(self): ppu = pp.unicode alphas = ppu.Greek.alphas greet = pp.Word(alphas) + "," + pp.Word(alphas) + "!" # input string hello = "Καλημέρα, κόσμε!" result = greet.parse_string(hello, parse_all=True) print(result) self.assertParseResultsEquals( result, expected_list=["Καλημέρα", ",", "κόσμε", "!"], msg="Failed to parse Greek 'Hello, World!' using " "pyparsing_unicode.Greek.alphas", ) # define a custom unicode range using multiple inheritance class Turkish_set(ppu.Latin1, ppu.LatinA): pass for attrname in "printables alphas nums identchars identbodychars".split(): with self.subTest( "verify unicode_set composed using MI", attrname=attrname ): latin1_value = getattr(ppu.Latin1, attrname) latinA_value = getattr(ppu.LatinA, attrname) turkish_value = getattr(Turkish_set, attrname) self.assertEqual( set(latin1_value + latinA_value), set(turkish_value), f"failed to construct ranges by merging Latin1 and LatinA ({attrname})", ) with self.subTest("Test using new Turkish_set for parsing"): key = pp.Word(Turkish_set.alphas) value = ppc.integer | pp.Word(Turkish_set.alphas, Turkish_set.alphanums) EQ = pp.Suppress("=") key_value = key + EQ + value sample = """\ şehir=İzmir ülke=Türkiye nüfus=4279677""" result = pp.Dict(pp.OneOrMore(pp.Group(key_value))).parse_string( sample, parse_all=True ) print(result.dump()) self.assertParseResultsEquals( result, expected_dict={"şehir": "İzmir", "ülke": "Türkiye", "nüfus": 4279677}, msg="Failed to parse Turkish key-value pairs", ) # Basic Multilingual Plane only contains chars up to 65535 def filter_16_bit(s): return "".join(c for c in s if ord(c) < 2**16) with self.subTest(): bmp_printables = ppu.BMP.printables sample = ( "".join( random.choice(filter_16_bit(unicode_set.printables)) for unicode_set in ( ppu.Japanese, Turkish_set, ppu.Greek, ppu.Hebrew, ppu.Devanagari, ppu.Hangul, ppu.Latin1, ppu.Chinese, ppu.Cyrillic, ppu.Arabic, ppu.Thai, ) for _ in range(8) ) + "\N{REPLACEMENT CHARACTER}" ) print(sample) self.assertParseAndCheckList(pp.Word(bmp_printables), sample, [sample]) def testUnicodeSetNameEquivalence(self): ppu = pp.unicode for ascii_name, unicode_name in [ ("Arabic", "العربية"), ("Chinese", "中文"), ("Cyrillic", "кириллица"), ("Greek", "Ελληνικά"), ("Hebrew", "עִברִית"), ("Japanese", "日本語"), ("Korean", "한국어"), ("Thai", "ไทย"), ("Devanagari", "देवनागरी"), ]: with self.subTest(ascii_name=ascii_name, unicode_name=unicode_name): self.assertTrue( eval(f"ppu.{ascii_name} is ppu.{unicode_name}", {}, locals()) ) def testIndentedBlock(self): # parse pseudo-yaml indented text EQ = pp.Suppress("=") stack = [1] key = ppc.identifier value = pp.Forward() key_value = pp.Group(key + EQ + value) compound_value = pp.Dict(pp.ungroup(pp.IndentedBlock(key_value, grouped=True))) value <<= ppc.integer | pp.QuotedString("'") | compound_value parser = pp.Dict(pp.OneOrMore(key_value)) text = """ a = 100 b = 101 c = c1 = 200 c2 = c21 = 999 c3 = 'A horse, a horse, my kingdom for a horse' d = 505 """ text = dedent(text) print(text) result = parser.parse_string(text, parse_all=True) print(result.dump()) self.assertEqual(100, result.a, "invalid indented block result") self.assertEqual(200, result.c.c1, "invalid indented block result") self.assertEqual(999, result.c.c2.c21, "invalid indented block result") # exercise indented_block with example posted in issue #87 def testIndentedBlockTest2(self): indent_stack = [1] key = pp.Word(pp.alphas, pp.alphanums) + pp.Suppress(":") stmt = pp.Forward() suite = pp.IndentedBlock(stmt, grouped=True) body = key + suite pattern = ( pp.Word(pp.alphas) + pp.Suppress("(") + pp.Word(pp.alphas) + pp.Suppress(")") ) stmt <<= pattern def key_parse_action(toks): print(f"Parsing '{toks[0]}'...") key.set_parse_action(key_parse_action) header = pp.Suppress("[") + pp.Literal("test") + pp.Suppress("]") content = header - pp.OneOrMore(pp.IndentedBlock(body)) contents = pp.Forward() suites = pp.IndentedBlock(content) extra = pp.Literal("extra") + pp.Suppress(":") - suites contents <<= content | extra parser = pp.OneOrMore(contents) sample = dedent( """ extra: [test] one0: two (three) four0: five (seven) extra: [test] one1: two (three) four1: five (seven) """ ) success, _ = parser.run_tests([sample]) self.assertTrue(success, "Failed IndentedBlock test for issue #87") sample2 = dedent( """ extra: [test] one: two (three) four: five (seven) extra: [test] one: two (three) four: five (seven) [test] one: two (three) four: five (seven) [test] eight: nine (ten) eleven: twelve (thirteen) fourteen: fifteen (sixteen) seventeen: eighteen (nineteen) """ ) del indent_stack[1:] success, _ = parser.run_tests([sample2]) self.assertTrue(success, "Failed indented_block multi-block test for issue #87") def testIndentedBlockScan(self): def get_parser(): """ A valid statement is the word "block:", followed by an indent, followed by the letter A only, or another block """ stack = [1] block = pp.Forward() body = pp.IndentedBlock(pp.Literal("A") ^ block) block <<= pp.Literal("block:") + body return block # This input string is a perfect match for the parser, so a single match is found p1 = get_parser() r1 = list( p1.scan_string( dedent( """\ block: A """ ) ) ) self.assertEqual(1, len(r1)) # This input string is a perfect match for the parser, except for the letter B instead of A, so this will fail (and should) p2 = get_parser() r2 = list( p2.scan_string( dedent( """\ block: B """ ) ) ) self.assertEqual(0, len(r2)) # This input string contains both string A and string B, and it finds one match (as it should) p3 = get_parser() r3 = list( p3.scan_string( dedent( """\ block: A block: B """ ) ) ) self.assertEqual(1, len(r3)) # This input string contains both string A and string B, but in a different order. p4 = get_parser() r4 = list( p4.scan_string( dedent( """\ block: B block: A """ ) ) ) self.assertEqual(1, len(r4)) # This is the same as case 3, but with nesting p5 = get_parser() r5 = list( p5.scan_string( dedent( """\ block: block: A block: block: B """ ) ) ) self.assertEqual(1, len(r5)) # This is the same as case 4, but with nesting p6 = get_parser() r6 = list( p6.scan_string( dedent( """\ block: block: B block: block: A """ ) ) ) self.assertEqual(1, len(r6)) def testIndentedBlockClass(self): data = """\ A 100 101 102 B 200 201 C 300 """ integer = ppc.integer group = pp.Group(pp.Char(pp.alphas) + pp.IndentedBlock(integer)) group[...].parse_string(data, parse_all=True).pprint() self.assertParseAndCheckList( group[...], data, [["A", [100, 101, 102]], ["B", [200, 201]], ["C", [300]]] ) def testIndentedBlockClass2(self): datas = [ """\ A 100 B 200 201 """, """\ A 100 B 200 201 """, """\ A 100 B 200 201 """, ] integer = ppc.integer group = pp.Group( pp.Char(pp.alphas) + pp.IndentedBlock(integer, recursive=False) ) for data in datas: print() print(ppt.with_line_numbers(data)) print(group[...].parse_string(data).as_list()) self.assertParseAndCheckList( group[...] + integer.suppress(), data, [["A", [100]], ["B", [200]]], verbose=False, ) def testIndentedBlockClassWithRecursion(self): data = """\ A 100 101 102 B b 200 201 C 300 """ integer = ppc.integer group = pp.Forward() group <<= pp.Group(pp.Char(pp.alphas) + pp.IndentedBlock(integer | group)) print("using search_string") print(group.search_string(data)) # print(sum(group.search_string(data)).dump()) self.assertParseAndCheckList( group[...], data, [["A", [100, 101, 102]], ["B", [["b", [200, 201]]]], ["C", [300]]], ) print("using parse_string") print(group[...].parse_string(data, parse_all=True).dump()) dotted_int = pp.DelimitedList( pp.Word(pp.nums), ".", allow_trailing_delim=True, combine=True ) indented_expr = pp.IndentedBlock(dotted_int, recursive=True, grouped=True) # indented_expr = pp.Forward() # indented_expr <<= pp.IndentedBlock(dotted_int + indented_expr)) good_data = """\ 1. 1.1 1.1.1 1.1.2 2.""" bad_data1 = """\ 1. 1.1 1.1.1 1.2 2.""" bad_data2 = """\ 1. 1.1 1.1.1 1.2 2.""" print("test good indentation") print(pp.pyparsing_test.with_line_numbers(good_data)) print(indented_expr.parse_string(good_data, parse_all=True).as_list()) print() print("test bad indentation") print(pp.pyparsing_test.with_line_numbers(bad_data1)) with self.assertRaisesParseException( msg="Failed to raise exception with bad indentation 1" ): indented_expr.parse_string(bad_data1, parse_all=True) print(pp.pyparsing_test.with_line_numbers(bad_data2)) with self.assertRaisesParseException( msg="Failed to raise exception with bad indentation 2" ): indented_expr.parse_string(bad_data2, parse_all=True) def testInvalidDiagSetting(self): with self.assertRaises( ValueError, msg="failed to raise exception when setting non-existent __diag__", ): pp.__diag__.enable("xyzzy") with self.assertWarns( UserWarning, msg="failed to warn disabling 'collect_all_And_tokens" ): pp.__compat__.disable("collect_all_And_tokens") def testParseResultsWithNameMatchFirst(self): expr_a = pp.Literal("not") + pp.Literal("the") + pp.Literal("bird") expr_b = pp.Literal("the") + pp.Literal("bird") expr = (expr_a | expr_b)("rexp") success, report = expr.run_tests( """\ not the bird the bird """ ) results = [rpt[1] for rpt in report] self.assertParseResultsEquals( results[0], ["not", "the", "bird"], {"rexp": ["not", "the", "bird"]} ) self.assertParseResultsEquals( results[1], ["the", "bird"], {"rexp": ["the", "bird"]} ) # test compatibility mode, no longer restoring pre-2.3.1 behavior with ppt.reset_pyparsing_context(): pp.__compat__.collect_all_And_tokens = False pp.enable_diag(pp.Diagnostics.warn_multiple_tokens_in_named_alternation) expr_a = pp.Literal("not") + pp.Literal("the") + pp.Literal("bird") expr_b = pp.Literal("the") + pp.Literal("bird") with self.assertWarns( UserWarning, msg="failed to warn of And within alternation" ): expr = (expr_a | expr_b)("rexp") with self.assertDoesNotWarn( UserWarning, msg="warned when And within alternation warning was suppressed", ): expr = (expr_a | expr_b).suppress_warning( pp.Diagnostics.warn_multiple_tokens_in_named_alternation )("rexp") success, report = expr.run_tests( """ not the bird the bird """ ) results = [rpt[1] for rpt in report] self.assertParseResultsEquals( results[0], ["not", "the", "bird"], {"rexp": ["not", "the", "bird"]} ) self.assertParseResultsEquals( results[1], ["the", "bird"], {"rexp": ["the", "bird"]} ) def testParseResultsWithNameOr(self): expr_a = pp.Literal("not") + pp.Literal("the") + pp.Literal("bird") expr_b = pp.Literal("the") + pp.Literal("bird") expr = (expr_a ^ expr_b)("rexp") success, _ = expr.run_tests( """\ not the bird the bird """ ) self.assertTrue(success) result = expr.parse_string("not the bird", parse_all=True) self.assertParseResultsEquals( result, ["not", "the", "bird"], {"rexp": ["not", "the", "bird"]} ) result = expr.parse_string("the bird", parse_all=True) self.assertParseResultsEquals( result, ["the", "bird"], {"rexp": ["the", "bird"]} ) expr = (expr_a | expr_b)("rexp") success, _ = expr.run_tests( """\ not the bird the bird """ ) self.assertTrue(success) result = expr.parse_string("not the bird", parse_all=True) self.assertParseResultsEquals( result, ["not", "the", "bird"], {"rexp": ["not", "the", "bird"]} ) result = expr.parse_string("the bird", parse_all=True) self.assertParseResultsEquals( result, ["the", "bird"], {"rexp": ["the", "bird"]} ) # test compatibility mode, no longer restoring pre-2.3.1 behavior with ppt.reset_pyparsing_context(): pp.__compat__.collect_all_And_tokens = False pp.enable_diag(pp.Diagnostics.warn_multiple_tokens_in_named_alternation) expr_a = pp.Literal("not") + pp.Literal("the") + pp.Literal("bird") expr_b = pp.Literal("the") + pp.Literal("bird") with self.assertWarns( UserWarning, msg="failed to warn of And within alternation" ): expr = (expr_a ^ expr_b)("rexp") with self.assertDoesNotWarn( UserWarning, msg="warned when And within alternation warning was suppressed", ): expr = (expr_a ^ expr_b).suppress_warning( pp.Diagnostics.warn_multiple_tokens_in_named_alternation )("rexp") success, _ = expr.run_tests( """\ not the bird the bird """ ) self.assertTrue(success) self.assertEqual( "not the bird".split(), list(expr.parse_string("not the bird", parse_all=True)["rexp"]), ) self.assertEqual( "the bird".split(), list(expr.parse_string("the bird", parse_all=True)["rexp"]), ) def testEmptyDictDoesNotRaiseException(self): key = pp.Word(pp.alphas) value = pp.Word(pp.nums) EQ = pp.Suppress("=") key_value_dict = pp.dict_of(key, EQ + value) print( key_value_dict.parse_string( """\ a = 10 b = 20 """, parse_all=True, ).dump() ) try: print(key_value_dict.parse_string("", parse_all=True).dump()) except pp.ParseException as pe: print(pp.ParseException.explain(pe)) else: self.fail("failed to raise exception when matching empty string") def testExplainException(self): expr = pp.Word(pp.nums).set_name("int") + pp.Word(pp.alphas).set_name("word") try: expr.parse_string("123 355", parse_all=True) except pp.ParseException as pe: print(pe.explain(depth=0)) expr = pp.Word(pp.nums).set_name("int") - pp.Word(pp.alphas).set_name("word") try: expr.parse_string("123 355 (test using ErrorStop)", parse_all=True) except pp.ParseSyntaxException as pe: print(pe.explain()) integer = pp.Word(pp.nums).set_name("int").add_parse_action(lambda t: int(t[0])) expr = integer + integer def divide_args(t): integer.parse_string("A", parse_all=True) return t[0] / t[1] expr.add_parse_action(divide_args) try: expr.parse_string("123 0", parse_all=True) except pp.ParseException as pe: print(pe.explain()) except Exception as exc: print(pp.ParseBaseException.explain_exception(exc)) raise def testExplainExceptionWithMemoizationCheck(self): if pp.ParserElement._left_recursion_enabled or pp.ParserElement._packratEnabled: print("test does local memoization enable/disable during test") return pp.ParserElement.disable_memoization() integer = pp.Word(pp.nums).set_name("int").add_parse_action(lambda t: int(t[0])) expr = integer + integer def divide_args(t): integer.parse_string("A", parse_all=True) return t[0] / t[1] expr.add_parse_action(divide_args) for memo_kind, enable_memo in [ ("Packrat", pp.ParserElement.enable_packrat), ("Left Recursion", pp.ParserElement.enable_left_recursion), ]: enable_memo(force=True) print("Explain for", memo_kind) try: expr.parse_string("123 0", parse_all=True) except pp.ParseException as pe: print(pe.explain()) except Exception as exc: print(pp.ParseBaseException.explain_exception(exc)) raise # make sure we leave the state compatible with everything pp.ParserElement.disable_memoization() def testCaselessKeywordVsKeywordCaseless(self): frule = pp.Keyword("t", caseless=True) + pp.Keyword("yes", caseless=True) crule = pp.CaselessKeyword("t") + pp.CaselessKeyword("yes") flist = frule.search_string("not yes").as_list() print(flist) clist = crule.search_string("not yes").as_list() print(clist) self.assertEqual( flist, clist, "CaselessKeyword not working the same as Keyword(caseless=True)", ) def testOneOf(self): expr = pp.one_of("a b abb") assert expr.pattern == "abb|a|b" expr = pp.one_of("a abb b abb") assert expr.pattern == "abb|a|b" expr = pp.one_of("a abb abbb b abb") assert expr.pattern == "abbb|abb|a|b" expr = pp.one_of("a abbb abb b abb") assert expr.pattern == "abbb|abb|a|b" # make sure regex-unsafe characters are properly escaped expr = pp.one_of("a+ b* c? () +a *b ?c") assert expr.pattern == r"a\+|b\*|c\?|\(\)|\+a|\*b|\?c" def testOneOfKeywords(self): literal_expr = pp.one_of("a b c") success, _ = literal_expr[...].run_tests( """ # literal one_of tests a b c a a a abc """ ) self.assertTrue(success, "failed literal one_of matching") keyword_expr = pp.one_of("a b c", as_keyword=True) success, _ = keyword_expr[...].run_tests( """ # keyword one_of tests a b c a a a """ ) self.assertTrue(success, "failed keyword one_of matching") success, _ = keyword_expr[...].run_tests( """ # keyword one_of failure tests abc """, failure_tests=True, ) self.assertTrue(success, "failed keyword one_of failure tests") def testWarnUngroupedNamedTokens(self): """ - warn_ungrouped_named_tokens_in_collection - flag to enable warnings when a results name is defined on a containing expression with ungrouped subexpressions that also have results names (default=True) """ with self.assertDoesNotWarn( msg=f"raised {pp.Diagnostics.warn_ungrouped_named_tokens_in_collection} warning when not enabled" ): COMMA = pp.Suppress(",").set_name("comma") coord = ppc.integer("x") + COMMA + ppc.integer("y") path = coord[...].set_results_name("path") with ppt.reset_pyparsing_context(): pp.enable_diag(pp.Diagnostics.warn_ungrouped_named_tokens_in_collection) COMMA = pp.Suppress(",").set_name("comma") coord = ppc.integer("x") + COMMA + ppc.integer("y") # this should emit a warning with self.assertWarns( UserWarning, msg="failed to warn with named repetition of" " ungrouped named expressions", ): path = coord[...].set_results_name("path") with self.assertDoesNotWarn( UserWarning, msg="warned when named repetition of" " ungrouped named expressions warning was suppressed", ): path = ( coord[...] .suppress_warning( pp.Diagnostics.warn_ungrouped_named_tokens_in_collection ) .set_results_name("path") ) def testDontWarnUngroupedNamedTokensIfWarningSuppressed(self): with ppt.reset_pyparsing_context(): pp.enable_diag(pp.Diagnostics.warn_ungrouped_named_tokens_in_collection) with self.assertDoesNotWarn( msg=f"raised {pp.Diagnostics.warn_ungrouped_named_tokens_in_collection}" f" warning when warn on ungrouped named tokens was suppressed (original_text_for)" ): pp.original_text_for(pp.Word("ABC")[...])("words") def testWarnNameSetOnEmptyForward(self): """ - warn_name_set_on_empty_Forward - flag to enable warnings when a Forward is defined with a results name, but has no contents defined (default=False) """ with self.assertDoesNotWarn( msg=f"raised {pp.Diagnostics.warn_name_set_on_empty_Forward} warning when not enabled" ): base = pp.Forward()("z") with ppt.reset_pyparsing_context(): pp.enable_diag(pp.Diagnostics.warn_name_set_on_empty_Forward) base = pp.Forward() with self.assertWarns( UserWarning, msg="failed to warn when naming an empty Forward expression", ): base("x") with self.assertDoesNotWarn( UserWarning, msg="warned when naming an empty Forward expression warning was suppressed", ): base.suppress_warning(pp.Diagnostics.warn_name_set_on_empty_Forward)( "x" ) def testWarnParsingEmptyForward(self): """ - warn_on_parse_using_empty_Forward - flag to enable warnings when a Forward has no contents defined (default=False) """ with self.assertDoesNotWarn( msg=f"raised {pp.Diagnostics.warn_on_parse_using_empty_Forward} warning when not enabled" ): base = pp.Forward() try: print(base.parse_string("x", parse_all=True)) except ParseException as pe: pass with ppt.reset_pyparsing_context(): pp.enable_diag(pp.Diagnostics.warn_on_parse_using_empty_Forward) base = pp.Forward() with self.assertWarns( UserWarning, msg="failed to warn when parsing using an empty Forward expression", ): try: print(base.parse_string("x", parse_all=True)) except ParseException as pe: pass with self.assertDoesNotWarn( UserWarning, msg="warned when parsing using an empty Forward expression warning was suppressed", ): base.suppress_warning(pp.Diagnostics.warn_on_parse_using_empty_Forward) try: print(base.parse_string("x", parse_all=True)) except ParseException as pe: pass def testWarnIncorrectAssignmentToForward(self): """ - warn_on_parse_using_empty_Forward - flag to enable warnings when a Forward has no contents defined (default=False) """ if PYPY_ENV: print("warn_on_assignment_to_Forward not supported on PyPy") return def a_method(): base = pp.Forward() base = pp.Word(pp.alphas)[...] | "(" + base + ")" with self.assertDoesNotWarn( msg=f"raised {pp.Diagnostics.warn_on_assignment_to_Forward} warning when not enabled" ): a_method() with ppt.reset_pyparsing_context(): pp.enable_diag(pp.Diagnostics.warn_on_assignment_to_Forward) with self.assertWarns( UserWarning, msg="failed to warn when using '=' to assign expression to a Forward", ): a_method() def a_method(): base = pp.Forward().suppress_warning( pp.Diagnostics.warn_on_assignment_to_Forward ) base = pp.Word(pp.alphas)[...] | "(" + base + ")" with self.assertDoesNotWarn( UserWarning, msg="warned when using '=' to assign expression to a Forward warning was suppressed", ): a_method() def testWarnOnMultipleStringArgsToOneOf(self): """ - warn_on_multiple_string_args_to_oneof - flag to enable warnings when one_of is incorrectly called with multiple str arguments (default=True) """ with self.assertDoesNotWarn( msg=f"raised {pp.Diagnostics.warn_on_multiple_string_args_to_oneof} warning when not enabled" ): a = pp.one_of("A", "B") with ppt.reset_pyparsing_context(): pp.enable_diag(pp.Diagnostics.warn_on_multiple_string_args_to_oneof) with self.assertWarns( UserWarning, msg="failed to warn when incorrectly calling one_of(string, string)", ): a = pp.one_of("A", "B") def testAutonameElements(self): with ppt.reset_pyparsing_context(): pp.enable_diag(pp.Diagnostics.enable_debug_on_named_expressions) a = pp.Literal("a") b = pp.Literal("b").set_name("bbb") z = pp.Literal("z") leading_a = a + pp.FollowedBy(z | a | b) grammar = (z | leading_a | b)[...] + "a" self.assertFalse(a.debug) self.assertFalse(a.customName) pp.autoname_elements() self.assertTrue(a.debug) self.assertEqual("a", a.name) self.assertEqual("bbb", b.name) def testDelimitedListName(self): bool_constant = pp.Literal("True") | "true" | "False" | "false" bool_list = pp.DelimitedList(bool_constant) print(bool_list) self.assertEqual( "{'True' | 'true' | 'False' | 'false'} [, {'True' | 'true' | 'False' | 'false'}]...", str(bool_list), ) bool_constant.set_name("bool") print(bool_constant) print(bool_constant.streamline()) bool_list2 = pp.DelimitedList(bool_constant) print(bool_constant) print(bool_constant.streamline()) print(bool_list2) with self.subTest(): self.assertEqual("bool [, bool]...", str(bool_list2)) with self.subTest(): street_address = pp.common.integer.set_name("integer") + pp.Word(pp.alphas)[ 1, ... ].set_name("street_name") self.assertEqual( "{integer street_name} [, {integer street_name}]...", str(pp.DelimitedList(street_address)), ) with self.subTest(): operand = pp.Char(pp.alphas).set_name("var") math = pp.infix_notation( operand, [ (pp.one_of("+ -"), 2, pp.OpAssoc.LEFT), ], ) self.assertEqual( "var_expression [, var_expression]...", str(pp.DelimitedList(math)), ) def testDelimitedListOfStrLiterals(self): expr = pp.DelimitedList("ABC") print(str(expr)) source = "ABC, ABC,ABC" self.assertParseAndCheckList( expr, source, [s.strip() for s in source.split(",")] ) def testDelimitedListMinMax(self): source = "ABC, ABC,ABC" with self.assertRaises(ValueError, msg="min must be greater than 0"): pp.DelimitedList("ABC", min=0) with self.assertRaises( ValueError, msg="max must be greater than, or equal to min" ): pp.DelimitedList("ABC", min=1, max=0) with self.assertRaises(pp.ParseException): pp.DelimitedList("ABC", min=4).parse_string(source) source_expr_pairs = [ ("ABC, ABC", pp.DelimitedList("ABC", max=2)), (source, pp.DelimitedList("ABC", min=2, max=4)), ] for source, expr in source_expr_pairs: print(str(expr)) self.assertParseAndCheckList( expr, source, [s.strip() for s in source.split(",")] ) def testDelimitedListParseActions1(self): # from issue #408 keyword = pp.Keyword("foobar") untyped_identifier = ~keyword + pp.Word(pp.alphas) dotted_vars = pp.DelimitedList(untyped_identifier, delim=".") lvalue = pp.Opt(dotted_vars) # uncomment this line to see the problem stmt = pp.DelimitedList(pp.Opt(dotted_vars)) # stmt = DelimitedList(dotted_vars) # stmt = pp.Opt(dotted_vars) def parse_identifier(toks): print("YAY!", toks) untyped_identifier.set_parse_action(parse_identifier) save_stdout = StringIO() with contextlib.redirect_stdout(save_stdout): dotted_vars.parse_string("B.C") self.assertEqual( dedent( """\ YAY! ['B'] YAY! ['C'] """ ), save_stdout.getvalue(), ) def testDelimitedListParseActions2(self): # from issue #408 keyword = pp.Keyword("foobar") untyped_identifier = ~keyword + pp.Word(pp.alphas) dotted_vars = pp.DelimitedList(untyped_identifier, delim=".") lvalue = pp.Opt(dotted_vars) # uncomment this line to see the problem # stmt = DelimitedList(Opt(dotted_vars)) stmt = pp.DelimitedList(dotted_vars) # stmt = pp.Opt(dotted_vars) def parse_identifier(toks): print("YAY!", toks) untyped_identifier.set_parse_action(parse_identifier) save_stdout = StringIO() with contextlib.redirect_stdout(save_stdout): dotted_vars.parse_string("B.C") self.assertEqual( dedent( """\ YAY! ['B'] YAY! ['C'] """ ), save_stdout.getvalue(), ) def testDelimitedListParseActions3(self): # from issue #408 keyword = pp.Keyword("foobar") untyped_identifier = ~keyword + pp.Word(pp.alphas) dotted_vars = pp.DelimitedList(untyped_identifier, delim=".") lvalue = pp.Opt(dotted_vars) # uncomment this line to see the problem # stmt = DelimitedList(Opt(dotted_vars)) # stmt = DelimitedList(dotted_vars) stmt = pp.Opt(dotted_vars) def parse_identifier(toks): print("YAY!", toks) untyped_identifier.set_parse_action(parse_identifier) save_stdout = StringIO() with contextlib.redirect_stdout(save_stdout): dotted_vars.parse_string("B.C") self.assertEqual( dedent( """\ YAY! ['B'] YAY! ['C'] """ ), save_stdout.getvalue(), ) def testTagElements(self): end_punc = ( ("." + pp.Tag("mood", "normal")) | ("!" + pp.Tag("mood", "excited")) | ("?" + pp.Tag("mood", "curious")) ) greeting = "Hello" + pp.Word(pp.alphas) + end_punc[1, ...] for ending, expected_mood in [ (".", "normal"), ("!", "excited"), ("?", "curious"), ("!!", "excited"), ("!?", "curious"), ]: self.assertParseAndCheckDict( greeting, f"Hello World{ending}", {"mood": expected_mood} ) def testEnableDebugOnNamedExpressions(self): """ - enable_debug_on_named_expressions - flag to auto-enable debug on all subsequent calls to ParserElement.set_name() (default=False) """ with ppt.reset_pyparsing_context(): test_stdout = StringIO() with resetting(sys, "stdout", "stderr"): sys.stdout = test_stdout sys.stderr = test_stdout pp.enable_diag(pp.Diagnostics.enable_debug_on_named_expressions) integer = pp.Word(pp.nums).set_name("integer") integer[...].parse_string("1 2 3", parse_all=True) expected_debug_output = dedent( """\ Match integer at loc 0(1,1) 1 2 3 ^ Matched integer -> ['1'] Match integer at loc 2(1,3) 1 2 3 ^ Matched integer -> ['2'] Match integer at loc 4(1,5) 1 2 3 ^ Matched integer -> ['3'] Match integer at loc 5(1,6) 1 2 3 ^ Match integer failed, ParseException raised: Expected integer, found end of text (at char 5), (line:1, col:6) """ ) output = test_stdout.getvalue() print(output) self.assertEqual( expected_debug_output, output, "failed to auto-enable debug on named expressions " "using enable_debug_on_named_expressions", ) def testEnableDebugOnExpressionWithParseAction(self): test_stdout = StringIO() with resetting(sys, "stdout", "stderr"): sys.stdout = test_stdout sys.stderr = test_stdout parser = (ppc.integer().set_debug() | pp.Word(pp.alphanums).set_debug())[ ... ] parser.set_debug() parser.parse_string("123 A100", parse_all=True) # now turn off debug - should only get output for components, not overall parser print() parser.set_debug(False) parser.parse_string("123 A100", parse_all=True) expected_debug_output = dedent( """\ Match [{integer | W:(0-9A-Za-z)}]... at loc 0(1,1) 123 A100 ^ Match integer at loc 0(1,1) 123 A100 ^ Matched integer -> [123] Match integer at loc 4(1,5) 123 A100 ^ Match integer failed, ParseException raised: Expected integer, found 'A100' (at char 4), (line:1, col:5) Match W:(0-9A-Za-z) at loc 4(1,5) 123 A100 ^ Matched W:(0-9A-Za-z) -> ['A100'] Match integer at loc 8(1,9) 123 A100 ^ Match integer failed, ParseException raised: Expected integer, found end of text (at char 8), (line:1, col:9) Match W:(0-9A-Za-z) at loc 8(1,9) 123 A100 ^ Match W:(0-9A-Za-z) failed, ParseException raised: Expected W:(0-9A-Za-z), found end of text (at char 8), (line:1, col:9) Matched [{integer | W:(0-9A-Za-z)}]... -> [123, 'A100'] Match integer at loc 0(1,1) 123 A100 ^ Matched integer -> [123] Match integer at loc 4(1,5) 123 A100 ^ Match integer failed, ParseException raised: Expected integer, found 'A100' (at char 4), (line:1, col:5) Match W:(0-9A-Za-z) at loc 4(1,5) 123 A100 ^ Matched W:(0-9A-Za-z) -> ['A100'] Match integer at loc 8(1,9) 123 A100 ^ Match integer failed, ParseException raised: Expected integer, found end of text (at char 8), (line:1, col:9) Match W:(0-9A-Za-z) at loc 8(1,9) 123 A100 ^ Match W:(0-9A-Za-z) failed, ParseException raised: Expected W:(0-9A-Za-z), found end of text (at char 8), (line:1, col:9) """ ) output = test_stdout.getvalue() print(output) self.assertEqual( expected_debug_output, output, "invalid debug output when using parse action", ) def testEnableDebugWithCachedExpressionsMarkedWithAsterisk(self): a = pp.Literal("a").set_name("A").set_debug() b = pp.Literal("b").set_name("B").set_debug() z = pp.Literal("z").set_name("Z").set_debug() leading_a = a + pp.FollowedBy(z | a | b) leading_a.set_name("leading_a").set_debug() grammar = (z | leading_a | b)[...] + "a" # parse test string and capture debug output test_stdout = StringIO() with resetting(sys, "stdout", "stderr"): sys.stdout = test_stdout sys.stderr = test_stdout grammar.parse_string("aba", parse_all=True) expected_debug_output = dedent( """\ Match Z at loc 0(1,1) aba ^ Match Z failed, ParseException raised: Expected Z, found 'aba' (at char 0), (line:1, col:1) Match leading_a at loc 0(1,1) aba ^ Match A at loc 0(1,1) aba ^ Matched A -> ['a'] Match Z at loc 1(1,2) aba ^ Match Z failed, ParseException raised: Expected Z, found 'ba' (at char 1), (line:1, col:2) Match A at loc 1(1,2) aba ^ Match A failed, ParseException raised: Expected A, found 'ba' (at char 1), (line:1, col:2) Match B at loc 1(1,2) aba ^ Matched B -> ['b'] Matched leading_a -> ['a'] *Match Z at loc 1(1,2) aba ^ *Match Z failed, ParseException raised: Expected Z, found 'ba' (at char 1), (line:1, col:2) Match leading_a at loc 1(1,2) aba ^ Match A at loc 1(1,2) aba ^ Match A failed, ParseException raised: Expected A, found 'ba' (at char 1), (line:1, col:2) Match leading_a failed, ParseException raised: Expected A, found 'ba' (at char 1), (line:1, col:2) *Match B at loc 1(1,2) aba ^ *Matched B -> ['b'] Match Z at loc 2(1,3) aba ^ Match Z failed, ParseException raised: Expected Z, found 'a' (at char 2), (line:1, col:3) Match leading_a at loc 2(1,3) aba ^ Match A at loc 2(1,3) aba ^ Matched A -> ['a'] Match Z at loc 3(1,4) aba ^ Match Z failed, ParseException raised: Expected Z, found end of text (at char 3), (line:1, col:4) Match A at loc 3(1,4) aba ^ Match A failed, ParseException raised: Expected A, found end of text (at char 3), (line:1, col:4) Match B at loc 3(1,4) aba ^ Match B failed, ParseException raised: Expected B, found end of text (at char 3), (line:1, col:4) Match leading_a failed, ParseException raised: Expected {Z | A | B}, found end of text (at char 3), (line:1, col:4) Match B at loc 2(1,3) aba ^ Match B failed, ParseException raised: Expected B, found 'a' (at char 2), (line:1, col:3) """ ) if pp.ParserElement._packratEnabled: packrat_status = "enabled" else: # remove '*' cache markers from expected output expected_debug_output = expected_debug_output.replace("*", "") packrat_status = "disabled" print("Packrat status:", packrat_status) output = test_stdout.getvalue() print(output) self.assertEqual( expected_debug_output, output, ( f"invalid debug output showing cached results marked with '*'," f" and packrat parsing {packrat_status}" ), ) def testSetDebugRecursively(self): expr = pp.Word(pp.alphas) contained = expr + pp.Empty().set_name("innermost") depth = 4 for _ in range(depth): contained = pp.Group(contained + pp.Empty()) contained.set_debug(recurse=True) self.assertTrue(expr.debug) # contained.parse_string("ABC") test_stdout = StringIO() with resetting(sys, "stdout", "stderr"): sys.stdout = test_stdout sys.stderr = test_stdout contained.parse_string("aba", parse_all=True) output = test_stdout.getvalue() print(output) self.assertEqual(depth, output.count("Matched Empty -> []")) self.assertEqual(1, output.count("Matched innermost -> []")) def testSetDebugRecursivelyWithForward(self): expr = pp.Word(pp.alphas).set_name("innermost") contained = pp.infix_notation( expr, [ ("NOT", 1, pp.OpAssoc.RIGHT), ("AND", 2, pp.OpAssoc.LEFT), ("OR", 2, pp.OpAssoc.LEFT), ], ) contained.set_debug(recurse=True) self.assertTrue(expr.debug) # contained.parse_string("ABC") test_stdout = StringIO() with resetting(sys, "stdout", "stderr"): sys.stdout = test_stdout sys.stderr = test_stdout contained.parse_string("aba", parse_all=True) output = test_stdout.getvalue() print(output) # count of matches varies with packrat state, can't match exact count, but at least test if contains # self.assertEqual(4, output.count("Matched innermost -> ['aba']")) self.assertTrue("Matched innermost -> ['aba']" in output) def testUndesirableButCommonPractices(self): # While these are valid constructs, and they are not encouraged # there is apparently a lot of code out there using these # coding styles. # # Even though they are not encouraged, we shouldn't break them. # Create an And using a list of expressions instead of using '+' operator expr = pp.And([pp.Word("abc"), pp.Word("123")]) success, _ = expr.run_tests( """ aaa 333 b 1 ababab 32123 """ ) self.assertTrue(success) success, _ = expr.run_tests( """\ aad 111 """, failure_tests=True, ) self.assertTrue(success) # Passing a single expression to a ParseExpression, when it really wants a sequence expr = pp.Or(pp.Or(ppc.integer)) success, _ = expr.run_tests( """\ 123 456 """ ) self.assertTrue(success) success, _ = expr.run_tests( """\ abc """, failure_tests=True, ) self.assertTrue(success) def testEnableWarnDiags(self): import pprint def filtered_vars(var_dict): dunders = [nm for nm in var_dict if nm.startswith("__")] return { k: v for k, v in var_dict.items() if isinstance(v, bool) and k not in dunders } pprint.pprint(filtered_vars(vars(pp.__diag__)), width=30) warn_names = pp.__diag__._warning_names other_names = pp.__diag__._debug_names # make sure they are off by default for diag_name in warn_names: self.assertFalse( getattr(pp.__diag__, diag_name), f"__diag__.{diag_name} not set to True", ) with ppt.reset_pyparsing_context(): # enable all warn_* diag_names pp.enable_all_warnings() pprint.pprint(filtered_vars(vars(pp.__diag__)), width=30) # make sure they are on after being enabled for diag_name in warn_names: self.assertTrue( getattr(pp.__diag__, diag_name), f"__diag__.{diag_name} not set to True", ) # non-warn diag_names must be enabled individually for diag_name in other_names: self.assertFalse( getattr(pp.__diag__, diag_name), f"__diag__.{diag_name} not set to True", ) # make sure they are off after AutoReset for diag_name in warn_names: self.assertFalse( getattr(pp.__diag__, diag_name), f"__diag__.{diag_name} not set to True", ) def testWordInternalReRangeWithConsecutiveChars(self): self.assertParseAndCheckList( pp.Word("ABCDEMNXYZ"), "ABCDEMNXYZABCDEMNXYZABCDEMNXYZ", ["ABCDEMNXYZABCDEMNXYZABCDEMNXYZ"], ) def testWordInternalReRangesKnownSet(self): tests = [ ("ABCDEMNXYZ", "[A-EMNX-Z]+"), (pp.printables, "[!-~]+"), (pp.alphas, "[A-Za-z]+"), (pp.alphanums, "[0-9A-Za-z]+"), (pp.pyparsing_unicode.Latin1.printables, "[!-~¡-ÿ]+"), (pp.pyparsing_unicode.Latin1.alphas, "[A-Za-zªµºÀ-ÖØ-öø-ÿ]+"), (pp.pyparsing_unicode.Latin1.alphanums, "[0-9A-Za-zª²³µ¹ºÀ-ÖØ-öø-ÿ]+"), (pp.alphas8bit, "[À-ÖØ-öø-ÿ]+"), ] failed = [] for word_string, expected_re in tests: try: msg = f"failed to generate correct internal re for {word_string!r}" resultant_re = pp.Word(word_string).reString self.assertEqual( expected_re, resultant_re, msg + f"; expected {expected_re!r} got {resultant_re!r}", ) except AssertionError: failed.append(msg) if failed: print("Errors:\n{}".format("\n".join(failed))) self.fail("failed to generate correct internal re's") def testWordInternalReRanges(self): import random esc_chars = r"\^-][" esc_chars2 = r"*+.?" def esc_re_set_char(c): return "\\" + c if c in esc_chars else c def esc_re_set2_char(c): return "\\" + c if c in esc_chars + esc_chars2 else c for esc_char in esc_chars + esc_chars2: # test escape char as first character in range next_char = chr(ord(esc_char) + 1) prev_char = chr(ord(esc_char) - 1) esc_word = pp.Word(esc_char + next_char) expected = rf"[{esc_re_set_char(esc_char)}{esc_re_set_char(next_char)}]+" print( f"Testing escape char: {esc_char} -> {esc_word} re: '{esc_word.reString}')" ) self.assertEqual( expected, esc_word.reString, "failed to generate correct internal re" ) test_string = "".join( random.choice([esc_char, next_char]) for __ in range(16) ) print( f"Match '{test_string}' -> {test_string == esc_word.parse_string(test_string, parse_all=True)[0]}" ) self.assertEqual( test_string, esc_word.parse_string(test_string, parse_all=True)[0], "Word using escaped range char failed to parse", ) # test escape char as last character in range esc_word = pp.Word(prev_char + esc_char) expected = rf"[{esc_re_set_char(prev_char)}{esc_re_set_char(esc_char)}]+" print( f"Testing escape char: {esc_char} -> {esc_word} re: '{esc_word.reString}')" ) self.assertEqual( expected, esc_word.reString, "failed to generate correct internal re" ) test_string = "".join( random.choice([esc_char, prev_char]) for __ in range(16) ) print( f"Match '{test_string}' -> {test_string == esc_word.parse_string(test_string, parse_all=True)[0]}" ) self.assertEqual( test_string, esc_word.parse_string(test_string, parse_all=True)[0], "Word using escaped range char failed to parse", ) # test escape char as first character in range next_char = chr(ord(esc_char) + 1) prev_char = chr(ord(esc_char) - 1) esc_word = pp.Word(esc_char + next_char) expected = rf"[{esc_re_set_char(esc_char)}{esc_re_set_char(next_char)}]+" print( f"Testing escape char: {esc_char} -> {esc_word} re: '{esc_word.reString}')" ) self.assertEqual( expected, esc_word.reString, "failed to generate correct internal re" ) test_string = "".join( random.choice([esc_char, next_char]) for __ in range(16) ) print( f"Match '{test_string}' -> {test_string == esc_word.parse_string(test_string, parse_all=True)[0]}" ) self.assertEqual( test_string, esc_word.parse_string(test_string, parse_all=True)[0], "Word using escaped range char failed to parse", ) # test escape char as only character in range esc_word = pp.Word(esc_char, pp.alphas.upper()) expected = rf"{esc_re_set2_char(esc_char)}[A-Z]*" print( f"Testing escape char: {esc_char} -> {esc_word} re: '{esc_word.reString}')" ) self.assertEqual( expected, esc_word.reString, "failed to generate correct internal re" ) test_string = esc_char + "".join( random.choice(pp.alphas.upper()) for __ in range(16) ) print( f"Match '{test_string}' -> {test_string == esc_word.parse_string(test_string, parse_all=True)[0]}" ) self.assertEqual( test_string, esc_word.parse_string(test_string, parse_all=True)[0], "Word using escaped range char failed to parse", ) # test escape char as only character esc_word = pp.Word(esc_char, pp.alphas.upper()) expected = rf"{re.escape(esc_char)}[A-Z]*" print( f"Testing escape char: {esc_char} -> {esc_word} re: '{esc_word.reString}')" ) self.assertEqual( expected, esc_word.reString, "failed to generate correct internal re" ) test_string = esc_char + "".join( random.choice(pp.alphas.upper()) for __ in range(16) ) print( f"Match '{test_string}' -> {test_string == esc_word.parse_string(test_string, parse_all=True)[0]}" ) self.assertEqual( test_string, esc_word.parse_string(test_string, parse_all=True)[0], "Word using escaped range char failed to parse", ) print() def testWordWithIdentChars(self): ppu = pp.pyparsing_unicode latin_identifier = pp.Word(pp.identchars, pp.identbodychars)("latin*") japanese_identifier = ppu.Japanese.identifier("japanese*") cjk_identifier = ppu.CJK.identifier("cjk*") greek_identifier = ppu.Greek.identifier("greek*") cyrillic_identifier = ppu.Cyrillic.identifier("cyrillic*") thai_identifier = ppu.Thai.identifier("thai*") idents = ( latin_identifier | japanese_identifier | cjk_identifier # must follow japanese_identifier, since CJK is superset | thai_identifier | greek_identifier | cyrillic_identifier ) result = idents[...].parse_string( "abc_100 кириллицаx_10 日本語f_300 ไทยg_600 def_200 漢字y_300 한국어_中文c_400 Ελληνικάb_500", parse_all=True, ) self.assertParseResultsEquals( result, [ "abc_100", "кириллицаx_10", "日本語f_300", "ไทยg_600", "def_200", "漢字y_300", "한국어_中文c_400", "Ελληνικάb_500", ], { "cjk": ["한국어_中文c_400"], "cyrillic": ["кириллицаx_10"], "greek": ["Ελληνικάb_500"], "japanese": ["日本語f_300", "漢字y_300"], "latin": ["abc_100", "def_200"], "thai": ["ไทยg_600"], }, ) def testChainedTernaryOperator(self): # fmt: off TERNARY_INFIX = pp.infix_notation( ppc.integer, [ (("?", ":"), 3, pp.OpAssoc.LEFT), ] ) self.assertParseAndCheckList( TERNARY_INFIX, "1?1:0?1:0", [[1, "?", 1, ":", 0, "?", 1, ":", 0]] ) TERNARY_INFIX = pp.infix_notation( ppc.integer, [ (("?", ":"), 3, pp.OpAssoc.RIGHT), ] ) self.assertParseAndCheckList( TERNARY_INFIX, "1?1:0?1:0", [[1, "?", 1, ":", [0, "?", 1, ":", 0]]] ) # fmt: on def testOneOfWithDuplicateSymbols(self): # test making one_of with duplicate symbols print("verify one_of handles duplicate symbols") try: test1 = pp.one_of("a b c d a") except RuntimeError: self.fail( "still have infinite loop in one_of with duplicate symbols (string input)" ) print("verify one_of handles duplicate symbols") try: test1 = pp.one_of("a a a b c d a") except RuntimeError: self.fail( "still have infinite loop in one_of with duplicate symbols (string input)" ) assert test1.pattern == "[abcd]" print("verify one_of handles generator input") try: test1 = pp.one_of(c for c in "a b c d a d d d" if not c.isspace()) except RuntimeError: self.fail( "still have infinite loop in one_of with duplicate symbols (generator input)" ) assert test1.pattern == "[abcd]" print("verify one_of handles list input") try: test1 = pp.one_of("a b c d a".split()) except RuntimeError: self.fail( "still have infinite loop in one_of with duplicate symbols (list input)" ) assert test1.pattern == "[abcd]" print("verify one_of handles set input") try: test1 = pp.one_of(set("a b c d a".split())) except RuntimeError: self.fail( "still have infinite loop in one_of with duplicate symbols (set input)" ) # set will generate scrambled letters, get pattern but resort to test pattern_letters = test1.pattern[1:-1] assert sorted(pattern_letters) == sorted("abcd") def testOneOfWithEmptyList(self): """test one_of helper function with an empty list as input""" tst = [] result = pp.one_of(tst) expected = True found = isinstance(result, pp.NoMatch) self.assertEqual(expected, found) def testOneOfWithUnexpectedInput(self): """test one_of with an input that isn't a string or iterable""" with self.assertRaises( TypeError, msg="failed to warn use of integer for one_of" ): expr = pp.one_of(6) def testMatchFirstIteratesOverAllChoices(self): # test MatchFirst bugfix print("verify MatchFirst iterates properly") results = pp.quoted_string.parse_string( "'this is a single quoted string'", parse_all=True ) self.assertTrue( len(results) > 0, "MatchFirst error - not iterating over all choices" ) def testStreamlineOfExpressionsAfterSetName(self): bool_constant = pp.Literal("True") | "true" | "False" | "false" self.assertEqual( "{'True' | 'true' | 'False' | 'false'}", str(bool_constant.streamline()) ) bool_constant.set_name("bool") self.assertEqual("bool", str(bool_constant.streamline())) def testStreamlineOfSubexpressions(self): # verify streamline of subexpressions print("verify proper streamline logic") compound = pp.Literal("A") + "B" + "C" + "D" self.assertEqual(2, len(compound.exprs), "bad test setup") print(compound) compound.streamline() print(compound) self.assertEqual(4, len(compound.exprs), "streamline not working") def testOptionalWithResultsNameAndNoMatch(self): # test for Optional with results name and no match print("verify Optional's do not cause match failure if have results name") testGrammar = pp.Literal("A") + pp.Optional("B")("gotB") + pp.Literal("C") try: testGrammar.parse_string("ABC", parse_all=True) testGrammar.parse_string("AC", parse_all=True) except pp.ParseException as pe: print(pe.pstr, "->", pe) self.fail(f"error in Optional matching of string {pe.pstr}") def testReturnOfFurthestException(self): # test return of furthest exception testGrammar = ( pp.Literal("A") | (pp.Literal("B") + pp.Literal("C")) | pp.Literal("E") ) try: testGrammar.parse_string("BC", parse_all=True) testGrammar.parse_string("BD", parse_all=True) except pp.ParseException as pe: print(pe.pstr, "->", pe) self.assertEqual("BD", pe.pstr, "wrong test string failed to parse") self.assertEqual( 1, pe.loc, "error in Optional matching, pe.loc=" + str(pe.loc) ) self.assertTrue( "found 'D'" in str(pe), "wrong alternative raised exception" ) def testValidateCorrectlyDetectsInvalidLeftRecursion(self): # test validate print("verify behavior of validate()") if IRON_PYTHON_ENV: print("disable this test under IronPython") return def testValidation(grmr, gnam, isValid): try: grmr.streamline() with self.assertWarns( PyparsingDeprecationWarning, msg="failed to warn validate() is deprecated", ): grmr.validate() self.assertTrue(isValid, "validate() accepted invalid grammar " + gnam) except pp.RecursiveGrammarException as rge: print(grmr) print(rge) self.assertFalse(isValid, "validate() rejected valid grammar " + gnam) fwd = pp.Forward() g1 = pp.OneOrMore((pp.Literal("A") + "B" + "C") | fwd) g2 = ("C" + g1)[...] fwd <<= pp.Group(g2) testValidation(fwd, "fwd", isValid=True) fwd2 = pp.Forward() fwd2 <<= pp.Group("A" | fwd2) testValidation(fwd2, "fwd2", isValid=False) fwd3 = pp.Forward() fwd3 <<= pp.Optional("A") + fwd3 testValidation(fwd3, "fwd3", isValid=False) def testGetNameBehavior(self): # test get_name print("verify behavior of get_name()") aaa = pp.Group(pp.Word("a")("A")) bbb = pp.Group(pp.Word("b")("B")) ccc = pp.Group(":" + pp.Word("c")("C")) g1 = "XXX" + (aaa | bbb | ccc)[...] teststring = "XXX b bb a bbb bbbb aa bbbbb :c bbbbbb aaa" names = [] print(g1.parse_string(teststring, parse_all=True).dump()) for t in g1.parse_string(teststring, parse_all=True): print(t, repr(t)) try: names.append(t[0].get_name()) except Exception: try: names.append(t.get_name()) except Exception: names.append(None) print(teststring) print(names) self.assertEqual( [None, "B", "B", "A", "B", "B", "A", "B", None, "B", "A"], names, "failure in getting names for tokens", ) IF, AND, BUT = map(pp.Keyword, "if and but".split()) ident = ~(IF | AND | BUT) + pp.Word(pp.alphas)("non-key") scanner = pp.OneOrMore(IF | AND | BUT | ident) def getNameTester(s, l, t): print(t, t.get_name()) ident.add_parse_action(getNameTester) scanner.parse_string("lsjd sldkjf IF Saslkj AND lsdjf", parse_all=True) # test ParseResults.get() method print("verify behavior of ParseResults.get()") # use sum() to merge separate groups into single ParseResults res = sum(g1.parse_string(teststring, parse_all=True)[1:]) print(res.dump()) print(res.get("A", "A not found")) print(res.get("D", "!D")) self.assertEqual( "aaa", res.get("A", "A not found"), "get on existing key failed" ) self.assertEqual("!D", res.get("D", "!D"), "get on missing key failed") def testOptionalBeyondEndOfString(self): print("verify handling of Optional's beyond the end of string") testGrammar = "A" + pp.Optional("B") + pp.Optional("C") + pp.Optional("D") testGrammar.parse_string("A", parse_all=True) testGrammar.parse_string("AB", parse_all=True) def testCreateLiteralWithEmptyString(self): # test creating Literal with empty string print('verify that Literal("") is optimized to Empty()') e = pp.Literal("") self.assertIsInstance(e, pp.Empty) def testLineMethodSpecialCaseAtStart(self): # test line() behavior when starting at 0 and the opening line is an \n print("verify correct line() behavior when first line is empty string") self.assertEqual( "", pp.line(0, "\nabc\ndef\n"), "Error in line() with empty first line in text", ) txt = "\nabc\ndef\n" results = [pp.line(i, txt) for i in range(len(txt))] self.assertEqual( ["", "abc", "abc", "abc", "abc", "def", "def", "def", "def"], results, "Error in line() with empty first line in text", ) txt = "abc\ndef\n" results = [pp.line(i, txt) for i in range(len(txt))] self.assertEqual( ["abc", "abc", "abc", "abc", "def", "def", "def", "def"], results, "Error in line() with non-empty first line in text", ) def testRepeatedTokensWhenPackratting(self): # test bugfix with repeated tokens when packrat parsing enabled print("verify behavior with repeated tokens when packrat parsing is enabled") a = pp.Literal("a") b = pp.Literal("b") c = pp.Literal("c") abb = a + b + b abc = a + b + c aba = a + b + a grammar = abb | abc | aba self.assertEqual( "aba", "".join(grammar.parse_string("aba", parse_all=True)), "Packrat ABA failure!", ) def testSetResultsNameWithOneOrMoreAndZeroOrMore(self): print("verify behavior of set_results_name with OneOrMore and ZeroOrMore") stmt = pp.Keyword("test") print(stmt[...]("tests").parse_string("test test", parse_all=True).tests) print(stmt[1, ...]("tests").parse_string("test test", parse_all=True).tests) print( pp.Optional(stmt[1, ...]("tests")) .parse_string("test test", parse_all=True) .tests ) print( pp.Optional(stmt[1, ...])("tests") .parse_string("test test", parse_all=True) .tests ) print( pp.Optional(pp.DelimitedList(stmt))("tests") .parse_string("test,test", parse_all=True) .tests ) self.assertEqual( 2, len(stmt[...]("tests").parse_string("test test", parse_all=True).tests), "ZeroOrMore failure with set_results_name", ) self.assertEqual( 2, len(stmt[1, ...]("tests").parse_string("test test", parse_all=True).tests), "OneOrMore failure with set_results_name", ) self.assertEqual( 2, len( pp.Optional(stmt[1, ...]("tests")) .parse_string("test test", parse_all=True) .tests ), "OneOrMore failure with set_results_name", ) self.assertEqual( 2, len( pp.Optional(pp.DelimitedList(stmt))("tests") .parse_string("test,test", parse_all=True) .tests ), "DelimitedList failure with set_results_name", ) self.assertEqual( 2, len((stmt * 2)("tests").parse_string("test test", parse_all=True).tests), "multiplied(1) failure with set_results_name", ) self.assertEqual( 2, len(stmt[..., 2]("tests").parse_string("test test", parse_all=True).tests), "multiplied(2) failure with set_results_name", ) self.assertEqual( 2, len(stmt[1, ...]("tests").parse_string("test test", parse_all=True).tests), "multiplied(3) failure with set_results_name", ) self.assertEqual( 2, len(stmt[2, ...]("tests").parse_string("test test", parse_all=True).tests), "multiplied(3) failure with set_results_name", ) def testParseResultsReprWithResultsNames(self): word = pp.Word(pp.printables)("word") res = word[...].parse_string("test blub", parse_all=True) print(repr(res)) print(res["word"]) print(res.as_dict()) self.assertEqual( "ParseResults(['test', 'blub'], {'word': 'blub'})", repr(res), "incorrect repr for ParseResults with list_all_matches=False", ) word = pp.Word(pp.printables)("word*") res = word[...].parse_string("test blub", parse_all=True) print(repr(res)) print(res["word"]) print(res.as_dict()) self.assertEqual( "ParseResults(['test', 'blub'], {'word': ['test', 'blub']})", repr(res), "incorrect repr for ParseResults with list_all_matches=True", ) def testWarnUsingLshiftForward(self): print( "verify that using '<<' operator with a Forward raises a warning if there is a dangling '|' operator" ) fwd = pp.Forward() print("unsafe << and |, but diag not enabled, should not warn") fwd << pp.Word("a") | pp.Word("b") pp.enable_diag(pp.Diagnostics.warn_on_match_first_with_lshift_operator) with self.assertWarns( UserWarning, msg="failed to warn of using << and | operators" ): fwd = pp.Forward() print("unsafe << and |, should warn") fwd << pp.Word("a") | pp.Word("b") with self.assertWarns( UserWarning, msg="failed to warn of using << and | operators (within lambda)", ): fwd = pp.Forward() print("unsafe << and |, should warn") fwd_fn = lambda expr1, expr2: fwd << expr1 | expr2 fwd_fn(pp.Word("a"), pp.Word("b")) fwd = pp.Forward() print("safe <<= and |, should not warn") fwd <<= pp.Word("a") | pp.Word("b") c = fwd | pp.Word("c") print("safe << and (|), should not warn") with self.assertDoesNotWarn( "warning raised on safe use of << with Forward and MatchFirst" ): fwd = pp.Forward() fwd << (pp.Word("a") | pp.Word("b")) c = fwd | pp.Word("c") def testParseExpressionsWithRegex(self): from itertools import product match_empty_regex = pp.Regex(r"[a-z]*") match_nonempty_regex = pp.Regex(r"[a-z]+") parser_classes = pp.ParseExpression.__subclasses__() test_string = "abc def" expected = ["abc"] for expr, cls in product( (match_nonempty_regex, match_empty_regex), parser_classes ): print(expr, cls) parser = cls([expr]) parsed_result = parser.parse_string(test_string, parse_all=False) print(parsed_result.dump()) self.assertParseResultsEquals(parsed_result, expected) for expr, cls in product( (match_nonempty_regex, match_empty_regex), (pp.MatchFirst, pp.Or) ): parser = cls([expr, expr]) print(parser) parsed_result = parser.parse_string(test_string, parse_all=False) print(parsed_result.dump()) self.assertParseResultsEquals(parsed_result, expected) def testAssertParseAndCheckDict(self): """test assertParseAndCheckDict in test framework""" expr = pp.Word(pp.alphas)("item") + pp.Word(pp.nums)("qty") self.assertParseAndCheckDict( expr, "balloon 25", {"item": "balloon", "qty": "25"} ) exprWithInt = pp.Word(pp.alphas)("item") + ppc.integer("qty") self.assertParseAndCheckDict( exprWithInt, "rucksack 49", {"item": "rucksack", "qty": 49} ) def testOnlyOnce(self): """test class OnlyOnce and its reset method""" # use a parse action to compute the sum of the parsed integers, # and add it to the end def append_sum(tokens): tokens.append(sum(map(int, tokens))) pa = pp.OnlyOnce(append_sum) expr = pp.OneOrMore(pp.Word(pp.nums)).add_parse_action(pa) result = expr.parse_string("0 123 321", parse_all=True) print(result.dump()) expected = ["0", "123", "321", 444] self.assertParseResultsEquals( result, expected, msg="issue with OnlyOnce first call" ) with self.assertRaisesParseException( msg="failed to raise exception calling OnlyOnce more than once" ): result2 = expr.parse_string("1 2 3 4 5", parse_all=True) pa.reset() result = expr.parse_string("100 200 300") print(result.dump()) expected = ["100", "200", "300", 600] self.assertParseResultsEquals( result, expected, msg="issue with OnlyOnce after reset" ) def testGoToColumn(self): """tests for GoToColumn class""" dateExpr = pp.Regex(r"\d\d(\.\d\d){2}")("date") numExpr = ppc.number("num") sample = """\ date Not Important value NotImportant2 11.11.13 | useless . useless,21 useless 2 | 14.21 | asmdakldm 21.12.12 | fmpaosmfpoamsp 4 | 41 | ajfa9si90""".splitlines() # Column number finds match patt = dateExpr + pp.GoToColumn(70).ignore("|") + numExpr + pp.rest_of_line infile = iter(sample) next(infile) expecteds = [["11.11.13", 14.21], ["21.12.12", 41]] for line, expected in zip(infile, expecteds): result = patt.parse_string(line, parse_all=True) print(result) self.assertEqual( expected, [result.date, result.num], msg="issue with GoToColumn" ) # Column number does NOT match patt = dateExpr("date") + pp.GoToColumn(30) + numExpr + pp.rest_of_line infile = iter(sample) next(infile) for line in infile: with self.assertRaisesParseException( msg="issue with GoToColumn not finding match" ): result = patt.parse_string(line, parse_all=True) def testExceptionExplainVariations(self): class Modifier: def modify_upper(self, tokens): tokens[:] = map(str.upper, tokens) modder = Modifier() # force an exception in the attached parse action # integer has a parse action to convert to an int; # this parse action should fail with a TypeError, since # str.upper expects a str argument, not an int grammar = ppc.integer().add_parse_action(modder.modify_upper) self_testcase_name = "tests.test_unit." + type(self).__name__ try: grammar.parse_string("1000", parse_all=True) except Exception as e: # extract the exception explanation explain_str = ParseException.explain_exception(e) print(explain_str) explain_str_lines = explain_str.splitlines() expected = [ self_testcase_name, "pyparsing.core.Word - integer", "tests.test_unit.Modifier", "pyparsing.results.ParseResults", ] # verify the list of names shown in the explain "stack" self.assertEqual( expected, explain_str_lines[-len(expected) :], msg="invalid explain str" ) # check type of raised exception matches explain output # (actual exception text varies by Python version, and even # by how the exception is raised, so we can only check the # type name) exception_line = explain_str_lines[-(len(expected) + 1)] self.assertTrue( exception_line.startswith("TypeError:"), msg=f"unexpected exception line ({exception_line!r})", ) def testExceptionMessageCustomization(self): with resetting(pp.ParseBaseException, "formatted_message"): def custom_exception_message(exc) -> str: found_phrase = f", found {exc.found}" if exc.found else "" return f"{exc.lineno}:{exc.column} {exc.msg}{found_phrase}" pp.ParseBaseException.formatted_message = custom_exception_message try: pp.Word(pp.nums).parse_string("ABC") except ParseException as pe: pe_msg = str(pe) else: pe_msg = "" self.assertEqual("1:1 Expected W:(0-9), found 'ABC'", pe_msg) def testForwardReferenceException(self): token = pp.Forward() num = pp.Word(pp.nums) num.set_name("num") text = pp.Word(pp.alphas) text.set_name("text") fail = pp.Regex(r"\\[A-Za-z]*")("name") def parse_fail(s, loc, toks): raise pp.ParseFatalException(s, loc, f"Unknown symbol: {toks['name']}") fail.set_parse_action(parse_fail) token <<= num | text | fail # If no name is given, do not intercept error messages with self.assertRaises(pp.ParseFatalException, msg="Unknown symbol: \\fail"): token.parse_string("\\fail") # If name is given, do intercept error messages token.set_name("token") with self.assertRaises(pp.ParseFatalException, msg="Expected token, found.*"): token.parse_string("\\fail") def testForwardExceptionText(self): wd = pp.Word(pp.alphas) ff = pp.Forward().set_name("fffff!") ff <<= wd + pp.Opt(ff) with self.assertRaises(pp.ParseFatalException, msg="no numbers!"): try: ff.parse_string("123") except pp.ParseException as pe: raise pp.ParseSyntaxException("no numbers! just alphas!") from pe with self.assertRaises(pp.ParseException, msg="Expected W:(A-Za-z)"): ff2 = pp.Forward() ff2 <<= wd ff2.parse_string("123") def testForwardExceptionText2(self): """ Test various expressions for error messages, under conditions in wrapped ParserElements """ v = "(omit closing paren" w = "('omit closing quote)" for s, expr, expected in ( (v, pp.nested_expr(), "Expected ')'"), (v, pp.Combine(pp.nested_expr(), adjacent=False), "Expected ')'"), ( v, pp.QuotedString("(", end_quote_char=")"), "Expected quoted string, starting with ( ending with ), found '('", ), (w, pp.nested_expr(content=pp.sgl_quoted_string), "Expected ')'"), ("", pp.nested_expr(), ""), ("", pp.Word("A"), ""), ): print(repr(s)) print(expr) with self.subTest("parse expr", expr=expr, s=s, expected=expected): with self.assertRaisesParseException(expected_msg=expected) as ctx: expr.parse_string(s, parse_all=True) print(ctx.exception) with self.subTest("parse expr[1, ...]", expr=expr, s=s, expected=expected): with self.assertRaisesParseException(expected_msg=expected) as ctx: expr[1, ...].parse_string(s, parse_all=True) print(ctx.exception) with self.subTest( "parse DelimitedList(expr)", expr=expr, s=s, expected=expected ): with self.assertRaisesParseException(expected_msg=expected) as ctx: pp.DelimitedList(expr).parse_string(s, parse_all=True) print(ctx.exception) print() def testMiscellaneousExceptionBits(self): pp.ParserElement.verbose_stacktrace = True self_testcase_name = "tests.test_unit." + type(self).__name__ # force a parsing exception - match an integer against "ABC" try: pp.Word(pp.nums).parse_string("ABC", parse_all=True) except pp.ParseException as pe: expected_str = "Expected W:(0-9), found 'ABC' (at char 0), (line:1, col:1)" self.assertEqual(expected_str, str(pe), "invalid ParseException str") self.assertEqual(expected_str, repr(pe), "invalid ParseException repr") self.assertEqual( ">!<ABC", pe.mark_input_line(), "invalid default mark input line" ) self.assertEqual( "ABC", pe.mark_input_line(""), "invalid mark input line with '' marker" ) # test explain using depth=None, 0, 1 depth_none_explain_str = pe.explain(depth=None) depth_0_explain_str = pe.explain(depth=0) depth_1_explain_str = pe.explain(depth=1) print(depth_none_explain_str) print() print(depth_0_explain_str) print() print(depth_1_explain_str) expr_name = "pyparsing.core.Word - W:(0-9)" for expected_function in [self_testcase_name, expr_name]: self.assertTrue( expected_function in depth_none_explain_str, f"{expected_function!r} not found in ParseException.explain()", ) self.assertFalse( expected_function in depth_0_explain_str, f"{expected_function!r} found in ParseException.explain(depth=0)", ) self.assertTrue( expr_name in depth_1_explain_str, f"{expected_function!r} not found in ParseException.explain()", ) self.assertFalse( self_testcase_name in depth_1_explain_str, f"{expected_function!r} not found in ParseException.explain()", ) def testExpressionDefaultStrings(self): expr = pp.Word(pp.nums) print(expr) self.assertEqual("W:(0-9)", repr(expr)) expr = pp.Word(pp.nums, exact=3) print(expr) self.assertEqual("W:(0-9){3}", repr(expr)) expr = pp.Word(pp.nums, min=2) print(expr) self.assertEqual("W:(0-9){2,...}", repr(expr)) expr = pp.Word(pp.nums, max=3) print(expr) self.assertEqual("W:(0-9){1,3}", repr(expr)) expr = pp.Word(pp.nums, min=2, max=3) print(expr) self.assertEqual("W:(0-9){2,3}", repr(expr)) expr = pp.Char(pp.nums) print(expr) self.assertEqual("(0-9)", repr(expr)) def testEmptyExpressionsAreHandledProperly(self): try: from pyparsing.diagram import to_railroad except ModuleNotFoundError as mnfe: print( "Failed 'from pyparsing.diagram import to_railroad'" f"\n {type(mnfe).__name__}: {mnfe}" ) if mnfe.__cause__: print(f"\n {type(mnfe.__cause__).__name__}: {mnfe.__cause__}") self.skipTest("Failed 'from pyparsing.diagram import to_railroad'") for cls in (pp.And, pp.Or, pp.MatchFirst, pp.Each): print("testing empty", cls.__name__) expr = cls([]) expr.streamline() to_railroad(expr) def testForwardsDoProperStreamlining(self): wd = pp.Word(pp.alphas) w3 = wd + wd + wd # before streamlining, w3 is {{W:(A-Za-z) W:(A-Za-z)} W:(A-Za-z)} self.assertIsInstance(w3.exprs[0], pp.And) self.assertEqual(len(w3.exprs), 2) ff = pp.Forward() ff <<= w3 + pp.Opt(ff) # before streamlining, ff is {{{W:(A-Za-z) W:(A-Za-z)} W:(A-Za-z)} [Forward: None]} self.assertEqual(len(ff.expr.exprs), 2) ff.streamline() # after streamlining: # w3 is {W:(A-Za-z) W:(A-Za-z) W:(A-Za-z)} # ff is {W:(A-Za-z) W:(A-Za-z) W:(A-Za-z) [Forward: None]} self.assertEqual(len(ff.expr.exprs), 4) self.assertEqual(len(w3.exprs), 3) test_exception_messages_tests = ( (pp.Word(pp.alphas), "123", "Expected W:(A-Za-z), found '123'"), (pp.Word(pp.alphas).set_name("word"), "123", "Expected word, found '123'"), ( pp.Group(pp.Word(pp.alphas).set_name("word")), "123", "Expected word, found '123'", ), ( pp.OneOrMore(pp.Word(pp.alphas).set_name("word")), "123", "Expected word, found '123'", ), ( pp.DelimitedList(pp.Word(pp.alphas).set_name("word")), "123", "Expected word, found '123'", ), ( pp.Suppress(pp.Word(pp.alphas).set_name("word")), "123", "Expected word, found '123'", ), ( pp.Forward() << pp.Word(pp.alphas).set_name("word"), "123", "Expected word, found '123'", ), ( pp.Forward() << pp.Word(pp.alphas), "123", "Expected W:(A-Za-z), found '123'", ), ( pp.Group(pp.Word(pp.alphas)), "123", "Expected W:(A-Za-z), found '123'", ), ( "prefix" + (pp.Regex("a").set_name("a") | pp.Regex("b").set_name("b")), "prefixc", "Expected {a | b}, found 'c'", ), ( "prefix" + (pp.Regex("a").set_name("a") | pp.Regex("b").set_name("b")), "prefix c", "Expected {a | b}, found 'c'", ), ( "prefix" + (pp.Regex("a").set_name("a") ^ pp.Regex("b").set_name("b")), "prefixc", "Expected {a ^ b}, found 'c'", ), ( "prefix" + (pp.Regex("a").set_name("a") ^ pp.Regex("b").set_name("b")), "prefix c", "Expected {a ^ b}, found 'c'", ), ) def test_exception_messages(self, tests=test_exception_messages_tests): for expr, input_str, expected_msg in tests: with self.subTest(expr=expr, input_str=input_str): with self.assertRaisesParseException(expected_msg=expected_msg): expr.parse_string(input_str) def test_exception_messages_with_exception_subclass(self): class TooManyRepsException(pp.ParseFatalException): pass @pp.trace_parse_action def no_more_than_3(t): if len(t) > 3: raise TooManyRepsException(f"{len(t)} is too many, only 3 allowed") # parse an int followed by no more than 3 words parser = pp.Word(pp.nums) + pp.Group( pp.Word(pp.alphas)[...].add_parse_action(no_more_than_3) ) # should succeed result = parser.parse_string("1000 abc def ghi") print(result.dump()) # should raise exception with local exception message with self.assertRaisesParseException( exc_type=ParseFatalException, expected_msg="4 is too many, only 3 allowed", msg="wrong exception message", ) as pe_context: result = parser.parse_string("2000 abc def ghi jkl") print(pe_context.exception) def test_pep8_synonyms(self): """ Test that staticmethods wrapped by replaced_by_pep8 wrapper are properly callable as staticmethods. """ def run_subtest(fn_name, expr=None, args=""): bool_expr = pp.one_of("true false", as_keyword=True) if expr is None: expr = "bool_expr" # try calling a ParserElement staticmethod via a ParserElement instance with self.subTest(fn_name=fn_name): exec(f"{expr}.{fn_name}({args})", globals(), locals()) # access staticmethod synonyms using a ParserElement parser_element_staticmethod_names = """ enable_packrat disable_memoization enable_left_recursion reset_cache """.split() if not ( pp.ParserElement._packratEnabled or pp.ParserElement._left_recursion_enabled ): for name in parser_element_staticmethod_names: run_subtest(name) pp.ParserElement.disable_memoization() run_subtest("set_default_whitespace_chars", args="' '") run_subtest("inline_literals_using", args="pp.Suppress") run_subtest( "set_default_keyword_chars", expr="pp.Keyword('START')", args="'abcde'" ) pass class Test03_EnablePackratParsing(TestCase): def runTest(self): Test02_WithoutPackrat.suite_context.restore() ParserElement.enable_packrat() # SAVE A NEW SUITE CONTEXT Test02_WithoutPackrat.suite_context = ppt.reset_pyparsing_context().save() class Test04_WithPackrat(Test02_WithoutPackrat): """ rerun Test2 tests, now that packrat is enabled """ def test000_assert_packrat_status(self): print("Packrat enabled:", ParserElement._packratEnabled) print( "Packrat cache:", type(ParserElement.packrat_cache).__name__, getattr(ParserElement.packrat_cache, "size", "- no size attribute -"), ) self.assertTrue(ParserElement._packratEnabled, "packrat not enabled") self.assertEqual( "_FifoCache", type(ParserElement.packrat_cache).__name__, msg="incorrect cache type", ) class Test05_EnableBoundedPackratParsing(TestCase): def runTest(self): Test02_WithoutPackrat.suite_context = Test02_WithoutPackrat.save_suite_context Test02_WithoutPackrat.suite_context.restore() ParserElement.enable_packrat(cache_size_limit=16) # SAVE A NEW SUITE CONTEXT Test02_WithoutPackrat.suite_context = ppt.reset_pyparsing_context().save() class Test06_WithBoundedPackrat(Test02_WithoutPackrat): """ rerun Test2 tests, now with bounded packrat cache """ def test000_assert_packrat_status(self): print("Packrat enabled:", ParserElement._packratEnabled) print( "Packrat cache:", type(ParserElement.packrat_cache).__name__, getattr(ParserElement.packrat_cache, "size", "- no size attribute -"), ) self.assertTrue(ParserElement._packratEnabled, "packrat not enabled") self.assertEqual( "_FifoCache", type(ParserElement.packrat_cache).__name__, msg="incorrect cache type", ) def test_exceeding_fifo_cache_size(self): letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" letter_lit = pp.MatchFirst(pp.Literal.using_each(letters)) result = letter_lit[...].parse_string(letters, parse_all=True) self.assertEqual(list(result), list(letters)) class Test07_EnableUnboundedPackratParsing(TestCase): def runTest(self): Test02_WithoutPackrat.suite_context = Test02_WithoutPackrat.save_suite_context Test02_WithoutPackrat.suite_context.restore() ParserElement.enable_packrat(cache_size_limit=None) # SAVE A NEW SUITE CONTEXT Test02_WithoutPackrat.suite_context = ppt.reset_pyparsing_context().save() class Test08_WithUnboundedPackrat(Test02_WithoutPackrat): """ rerun Test2 tests, now with unbounded packrat cache """ def test000_assert_packrat_status(self): print("Packrat enabled:", ParserElement._packratEnabled) print( "Packrat cache:", type(ParserElement.packrat_cache).__name__, getattr(ParserElement.packrat_cache, "size", "- no size attribute -"), ) self.assertTrue(ParserElement._packratEnabled, "packrat not enabled") self.assertEqual( "_UnboundedCache", type(ParserElement.packrat_cache).__name__, msg="incorrect cache type", ) class Test09_WithLeftRecursionParsing(Test02_WithoutPackrat): """ rerun Test2 tests, now with unbounded left recursion cache """ def setUp(self): ParserElement.enable_left_recursion(force=True) def tearDown(self): default_suite_context.restore() def test000_assert_packrat_status(self): print("Left-Recursion enabled:", ParserElement._left_recursion_enabled) self.assertTrue( ParserElement._left_recursion_enabled, "left recursion not enabled" ) self.assertIsInstance(ParserElement.recursion_memos, pp.util.UnboundedMemo) class Test10_WithLeftRecursionParsingBoundedMemo(Test02_WithoutPackrat): """ rerun Test2 tests, now with bounded left recursion cache """ def setUp(self): ParserElement.enable_left_recursion(cache_size_limit=4, force=True) def tearDown(self): default_suite_context.restore() def test000_assert_packrat_status(self): print("Left-Recursion enabled:", ParserElement._left_recursion_enabled) self.assertTrue( ParserElement._left_recursion_enabled, "left recursion not enabled" ) self.assertIsInstance(ParserElement.recursion_memos, pp.util.LRUMemo) # check that the cache matches roughly what we expect # – it may be larger due to action handling self.assertLessEqual(ParserElement.recursion_memos._capacity, 4) self.assertGreater(ParserElement.recursion_memos._capacity * 3, 4) class Test11_LR1_Recursion(ppt.TestParseResultsAsserts, TestCase): """ Tests for recursive parsing """ suite_context = None save_suite_context = None def setUp(self): recursion_suite_context.restore() def tearDown(self): default_suite_context.restore() def test_repeat_as_recurse(self): """repetition rules formulated with recursion""" one_or_more = pp.Forward().set_name("one_or_more") one_or_more <<= one_or_more + "a" | "a" self.assertParseResultsEquals( one_or_more.parse_string("a", parse_all=True), expected_list=["a"] ) self.assertParseResultsEquals( one_or_more.parse_string("aaa aa", parse_all=True), expected_list=["a", "a", "a", "a", "a"], ) DelimitedList = pp.Forward().set_name("DelimitedList") DelimitedList <<= DelimitedList + pp.Suppress(",") + "b" | "b" self.assertParseResultsEquals( DelimitedList.parse_string("b", parse_all=True), expected_list=["b"] ) self.assertParseResultsEquals( DelimitedList.parse_string("b,b", parse_all=True), expected_list=["b", "b"] ) self.assertParseResultsEquals( DelimitedList.parse_string("b,b , b, b,b", parse_all=True), expected_list=["b", "b", "b", "b", "b"], ) def test_binary_recursive(self): """parsing of single left-recursive binary operator""" expr = pp.Forward().set_name("expr") num = pp.Word(pp.nums) expr <<= expr + "+" - num | num self.assertParseResultsEquals( expr.parse_string("1+2", parse_all=True), expected_list=["1", "+", "2"] ) self.assertParseResultsEquals( expr.parse_string("1+2+3+4", parse_all=True), expected_list=["1", "+", "2", "+", "3", "+", "4"], ) def test_binary_associative(self): """associative is preserved for single left-recursive binary operator""" expr = pp.Forward().set_name("expr") num = pp.Word(pp.nums) expr <<= pp.Group(expr) + "+" - num | num self.assertParseResultsEquals( expr.parse_string("1+2", parse_all=True), expected_list=[["1"], "+", "2"] ) self.assertParseResultsEquals( expr.parse_string("1+2+3+4", parse_all=True), expected_list=[[[["1"], "+", "2"], "+", "3"], "+", "4"], ) def test_add_sub(self): """indirectly left-recursive/associative add/sub calculator""" expr = pp.Forward().set_name("expr") num = pp.Word(pp.nums).set_parse_action(lambda t: int(t[0])) expr <<= ( (expr + "+" - num).set_parse_action(lambda t: t[0] + t[2]) | (expr + "-" - num).set_parse_action(lambda t: t[0] - t[2]) | num ) self.assertEqual(expr.parse_string("1+2", parse_all=True)[0], 3) self.assertEqual(expr.parse_string("1+2+3", parse_all=True)[0], 6) self.assertEqual(expr.parse_string("1+2-3", parse_all=True)[0], 0) self.assertEqual(expr.parse_string("1-2+3", parse_all=True)[0], 2) self.assertEqual(expr.parse_string("1-2-3", parse_all=True)[0], -4) def test_math(self): """precedence climbing parser for math""" # named references expr = pp.Forward().set_name("expr") add_sub = pp.Forward().set_name("add_sub") mul_div = pp.Forward().set_name("mul_div") power = pp.Forward().set_name("power") terminal = pp.Forward().set_name("terminal") # concrete rules number = pp.Word(pp.nums).set_parse_action(lambda t: int(t[0])) signed = ("+" - expr) | ("-" - expr).set_parse_action(lambda t: -t[1]) group = pp.Suppress("(") - expr - pp.Suppress(")") add_sub <<= ( (add_sub + "+" - mul_div).set_parse_action(lambda t: t[0] + t[2]) | (add_sub + "-" - mul_div).set_parse_action(lambda t: t[0] - t[2]) | mul_div ) mul_div <<= ( (mul_div + "*" - power).set_parse_action(lambda t: t[0] * t[2]) | (mul_div + "/" - power).set_parse_action(lambda t: t[0] / t[2]) | power ) power <<= (terminal + "^" - power).set_parse_action( lambda t: t[0] ** t[2] ) | terminal terminal <<= number | signed | group expr <<= add_sub # simple add_sub expressions self.assertEqual(expr.parse_string("1+2", parse_all=True)[0], 3) self.assertEqual(expr.parse_string("1+2+3", parse_all=True)[0], 6) self.assertEqual(expr.parse_string("1+2-3", parse_all=True)[0], 0) self.assertEqual(expr.parse_string("1-2+3", parse_all=True)[0], 2) self.assertEqual(expr.parse_string("1-2-3", parse_all=True)[0], -4) # precedence overwriting via parentheses self.assertEqual(expr.parse_string("1+(2+3)", parse_all=True)[0], 6) self.assertEqual(expr.parse_string("1+(2-3)", parse_all=True)[0], 0) self.assertEqual(expr.parse_string("1-(2+3)", parse_all=True)[0], -4) self.assertEqual(expr.parse_string("1-(2-3)", parse_all=True)[0], 2) # complicated math expressions – same as Python expressions self.assertEqual(expr.parse_string("1----3", parse_all=True)[0], 1 - ---3) self.assertEqual(expr.parse_string("1+2*3", parse_all=True)[0], 1 + 2 * 3) self.assertEqual(expr.parse_string("1*2+3", parse_all=True)[0], 1 * 2 + 3) self.assertEqual(expr.parse_string("1*2^3", parse_all=True)[0], 1 * 2**3) self.assertEqual(expr.parse_string("4^3^2^1", parse_all=True)[0], 4**3**2**1) def test_terminate_empty(self): """Recursion with ``Empty`` terminates""" empty = pp.Forward().set_name("e") empty <<= empty + pp.Empty() | pp.Empty() self.assertParseResultsEquals( empty.parse_string("", parse_all=True), expected_list=[] ) def test_non_peg(self): """Recursion works for non-PEG operators""" expr = pp.Forward().set_name("expr") expr <<= expr + "a" ^ expr + "ab" ^ expr + "abc" ^ "." self.assertParseResultsEquals( expr.parse_string(".abcabaabc", parse_all=True), expected_list=[".", "abc", "ab", "a", "abc"], ) class TestShowBestPractices(unittest.TestCase): def test_loads_markdown_file(self): # Mock the file read to simulate the Markdown content mock_content = "## Test Best Practices\n- Example guideline" mock_file = mock_open(read_data=mock_content) with patch("importlib.resources.files") as mock_files: # mock path.open() to use our mock_file mock_path = mock_files.return_value.joinpath.return_value mock_path.open = mock_file result = pp.show_best_practices(file=None) self.assertEqual(result, mock_content) def test_fallback_when_file_missing(self): # Patch files().joinpath().open to raise FileNotFoundError with patch("importlib.resources.files") as mock_files: mock_path = mock_files.return_value.joinpath.return_value mock_path.open.side_effect = FileNotFoundError result = pp.show_best_practices(file=None) self.assertIn("## Planning", result) # Fallback contains "Planning" section self.assertIn("## Implementing", result) self.assertIn("## Testing", result) self.assertIn("## Debugging", result) def test_cli_invocation_with_module_flag(self): # Invoke the CLI the same way a user or AI would: # python -m pyparsing.show_best_practices cmd = [sys.executable, "-m", "pyparsing.ai.show_best_practices"] subproc = subprocess.run(cmd, capture_output=True, text=True) self.assertEqual(subproc.returncode, 0, msg=f"stderr: {subproc.stderr}") subproc_stdout = subproc.stdout # Should print the best practices markdown (either from file or fallback) self.assertIn("## Planning", subproc_stdout) self.assertIn("## Implementing", subproc_stdout) self.assertIn("## Testing", subproc_stdout) self.assertIn("## Debugging", subproc_stdout) # force clear of packrat parsing flags before saving contexts pp.ParserElement.disable_memoization() Test02_WithoutPackrat.suite_context = ppt.reset_pyparsing_context().save() Test02_WithoutPackrat.save_suite_context = ppt.reset_pyparsing_context().save() default_suite_context = ppt.reset_pyparsing_context().save() pp.ParserElement.enable_left_recursion() recursion_suite_context = ppt.reset_pyparsing_context().save() default_suite_context.restore() ���������������������������������������������������������������././@PaxHeader��������������������������������������������������������������������������������������0000000�0000000�0000000�00000000034�00000000000�010212� x����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������28 mtime=1768949007.7248077 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������pyparsing-3.3.2/tests/test_util.py������������������������������������������������������������������0000644�0000000�0000000�00000023025�15134002420�014202� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������import random from typing import Union, Iterable import pytest import pyparsing as pp @pytest.mark.parametrize( "test_label, input_list, expected_output", [ ("Empty list", [], []), ("Flat list", [1, 2, 3], [1, 2, 3]), ("Nested list", [[1, 2], [3, 4]], [1, 2, 3, 4]), ("Mixed list with single values and lists", [1, [2, 3], 4], [1, 2, 3, 4]), ("Deeper nested lists", [1, [2, [3, 4]], 5], [1, 2, 3, 4, 5]), ("Deeper nesting with sublists", [[[1], 2], [3]], [1, 2, 3]), ( "Mixed empty and non-empty nested lists", [[], [1], [2, [3]], [[4, 5]]], [1, 2, 3, 4, 5], ), ("Deeply nested empty lists", [[[[]]]], []), ("Mixed empty lists and non-empty elements", [1, [], 2, [3, []]], [1, 2, 3]), ( "ParseResults instead of lists", [pp.ParseResults([1, 2]), pp.ParseResults([3, 4])], [1, 2, 3, 4], ), ( "ParseResults with mixed types", [1, pp.ParseResults([2, 3]), 4], [1, 2, 3, 4], ), ( "Nested ParseResults", [pp.ParseResults([1, pp.ParseResults([2, 3])]), 4], [1, 2, 3, 4], ), ( "Empty ParseResults", [pp.ParseResults([]), 1, pp.ParseResults([2, 3])], [1, 2, 3], ), ], ) def test_flatten(test_label: str, input_list: list, expected_output: list): from pyparsing.util import _flatten """Test flatten with various inputs.""" print(test_label) assert _flatten(input_list) == expected_output @pytest.mark.parametrize( "test_label, input_string, re_escape, expected_output", [ ("Empty string", "", True, ""), ("Single character", "a", True, "a"), ("Two consecutive characters", "ab", True, "ab"), ("Two non-consecutive characters", "az", True, "az"), ("Three consecutive characters", "abcg", True, "a-cg"), ("Full consecutive alphabet", "abcdefghijklmnopqrstuvwxyz", True, "a-z"), ("Consecutive characters with special regex chars", "^-]", True, r"\-\]\^"), ("Consecutive characters without escaping", "^-]", False, "-]^"), ("Mixed consecutive and non-consecutive", "abcxyz", True, "a-cx-z"), ("Reversed order input", "cba", True, "a-c"), ("Characters with duplicates", "aaxxxddddbbcc", True, "a-dx"), ("Non-alphabetic consecutive characters", "012345", True, "0-5"), ("Non-alphabetic mixed characters", "@05", True, "05@"), ("Non-alphabetic, non-consecutive characters", "02", True, "02"), ("Verify range ending with '-' creates valid regex", "*+,-", True, r"*-\-"), ("Verify range ending with ']' creates valid regex", r"WXYZ[\]", True, r"W-\]"), ("Verify range starting with '^' creates valid regex", "^_`a", True, r"\^-a"), ], ) def test_collapse_string_to_ranges( test_label: str, input_string: Union[str, Iterable[str]], re_escape: bool, expected_output: str, ): """Test collapsing a string into character ranges with and without regex escaping.""" from pyparsing.util import _collapse_string_to_ranges from random import random import re print(test_label) collapsed = _collapse_string_to_ranges(input_string, re_escape) print(f"{input_string!r} -> {collapsed!r}") assert collapsed == expected_output if input_string: # for added coverage, randomly shuffle input string shuffled = "".join(sorted(list(input_string), key=lambda _: random())) collapsed = _collapse_string_to_ranges(shuffled, re_escape) print(f"{shuffled!r} -> {collapsed!r}") assert collapsed == expected_output # added test to assert that the collapsed string can be used as a valid regex range string if re_escape: collapsed_re = re.compile(f"[{collapsed}]+") match = collapsed_re.match(input_string) print(f"re.match:'{collapsed_re.pattern}' -> {match and match[0]!r}") assert match is not None and match[0] == input_string print() @pytest.mark.parametrize( "test_label, loc, input_string, expected_output", [ ("First column, no newline", 0, "abcdef", 1), ("Second column, no newline", 1, "abcdef", 2), ("First column after newline", 4, "abc\ndef", 1), ("Second column after newline", 5, "abc\ndef", 2), ("Column after multiple newlines", 9, "abc\ndef\nghi", 2), ("Location at start of string", 0, "abcdef", 1), ("Location at end of string", 5, "abcdef", 6), ("Column after newline at end", 3, "abc\n", 4), ("Tab character in the string", 4, "a\tbcd\tef", 5), ("Multiple lines with tab", 8, "a\tb\nc\td", 5), ], ) def test_col(test_label: str, loc: int, input_string: str, expected_output: int): from pyparsing.util import col print(test_label) assert col(loc, input_string) == expected_output @pytest.mark.parametrize( "test_label, loc, input_string, expected_output", [ ("Single line, no newlines", 0, "abcdef", "abcdef"), ("First line in multi-line string", 2, "abc\ndef", "abc"), ("Second line in multi-line string", 5, "abc\ndef", "def"), ("Location at start of second line", 4, "abc\ndef", "def"), ("Empty string", 0, "", ""), ("Location at newline character", 3, "abc\ndef", "abc"), ("Last line without trailing newline", 7, "abc\ndef\nghi", "def"), ("Single line with newline at end", 2, "abc\n", "abc"), ("Multi-line with multiple newlines", 6, "line1\nline2\nline3", "line2"), ("Multi-line with trailing newline", 11, "line1\nline2\nline3\n", "line2"), ], ) def test_line(test_label: str, loc: int, input_string: str, expected_output: str): from pyparsing import line print(test_label) assert line(loc, input_string) == expected_output @pytest.mark.parametrize( "test_label, loc, input_string, expected_output", [ ("Single line, no newlines", 0, "abcdef", 1), ("First line in multi-line string", 2, "abc\ndef", 1), ("Second line in multi-line string", 5, "abc\ndef", 2), ("Location at start of second line", 4, "abc\ndef", 2), ("Multiple newlines, third line", 10, "abc\ndef\nghi", 3), ("Empty string", 0, "", 1), ("Location at newline character", 3, "abc\ndef", 1), ("Last line without trailing newline", 7, "abc\ndef\nghi", 2), ("Single line with newline at end", 4, "abc\n", 2), ("Multi-line with trailing newline", 12, "line1\nline2\nline3\n", 3), ("Location in middle of a tabbed string", 7, "a\tb\nc\td", 2), ], ) def test_lineno(test_label: str, loc: int, input_string: str, expected_output: int): from pyparsing import lineno assert lineno(loc, input_string) == expected_output def test_html_entities() -> None: import html.entities from pyparsing import common_html_entity # create test string from all known HTML5 entities, in random order entity_strings = [f'&{e.rstrip(";")};' for e in html.entities.html5] random.shuffle(entity_strings) test_string = " ".join(entity_strings) # verify that all are parsed parsed = common_html_entity()[...].parse_string(test_string, parse_all=True) assert len(parsed) == len(html.entities.html5) def test_make_compressed_re() -> None: import re from pyparsing.util import make_compressed_re words = "blue brown black blues bluesky co ci ce ca cu".split() for i in range(1, 9): print(i, make_compressed_re(words, max_level=i)) regex = re.compile(make_compressed_re(words, max_level=i) + "$") assert all(regex.match(wd) for wd in words) def test_make_compressed_re_bad_input(): from pyparsing.util import make_compressed_re with pytest.raises(ValueError): make_compressed_re([]) with pytest.raises(ValueError): make_compressed_re(["a", "", "b", "c"]) # handle duplicate input strings assert make_compressed_re(["a", "b", "c"]) == make_compressed_re(["a", "b", "c", "a"]) def test_make_compressed_re_random(): import itertools import re from pyparsing.util import make_compressed_re def generate_random_word(max_length: int) -> str: import random import string length = random.randint(1, max_length) return ''.join(random.choice(string.ascii_lowercase + ".*? ") for _ in range(length)) def generate_word_lists(num_lists: int, num_words: int, word_length: int) -> Iterable[list[str]]: yield from ( [generate_random_word(word_length) for _ in range(num_words)] for _ in range(num_lists) ) for word_length, list_length in itertools.product(range(3, 9), range(1, 32)): for word_list in generate_word_lists(100, list_length, word_length): regex_pattern = make_compressed_re(word_list) try: regex = re.compile(f"^({regex_pattern})$") except Exception as e: assert False, f"Failed to compile {word_list} to regex pattern {regex_pattern!r}: {e}" for word in word_list: assert regex.match(word), f"Regex {regex_pattern!r} did not match word: {word}" # Check that the regex does not match a random word not in the list random_word = generate_random_word(word_length) while random_word in word_list: random_word = generate_random_word(word_length) assert regex.match(random_word) is None, f"Regex {regex_pattern!r} incorrectly matched word: {random_word!r}" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������././@PaxHeader��������������������������������������������������������������������������������������0000000�0000000�0000000�00000000034�00000000000�010212� x����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������28 mtime=1768949007.7248077 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������pyparsing-3.3.2/tox.ini�����������������������������������������������������������������������������0000644�0000000�0000000�00000001657�15134002420�011774� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[tox] skip_missing_interpreters=true envlist = py39-unit,py{310,311,312,313,314,314t,py3}-{unit,doctest},mypy-check isolated_build = True [testenv] deps = unit: pytest unit: matplotlib; implementation_name != 'pypy' and python_version <= '3.15' doctest: sphinx doctest: myst-parser doctest: alabaster extras = unit: diagrams setenv = PYTHONPATH = {env:PYTHONPATH}{:}{toxinidir} commands = unit: pytest tests examples/tiny/tests {posargs} doctest: sphinx-build -b doctest docs docs\_build\doctest allowlist_externals = pytest python sphinx-build [testenv:py314t-unit] description = Run tests with the free-threaded Python 3.14 interpreter. base_python = python3.14t [testenv:py314t-doctest] description = Run doctests with the free-threaded Python 3.14 interpreter. base_python = python3.14t [testenv:mypy-check] deps = mypy commands = mypy --show-error-codes --warn-unused-ignores pyparsing ���������������������������������������������������������������������������������pyparsing-3.3.2/PKG-INFO����������������������������������������������������������������������������0000644�0000000�0000000�00000013227�00000000000�011524� 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Metadata-Version: 2.4 Name: pyparsing Version: 3.3.2 Summary: pyparsing - Classes and methods to define and execute parsing grammars Author-email: Paul McGuire <ptmcg.gm+pyparsing@gmail.com> Requires-Python: >=3.9 Description-Content-Type: text/x-rst License-Expression: MIT Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Information Technology Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: 3.14 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Software Development :: Compilers Classifier: Topic :: Text Processing Classifier: Typing :: Typed License-File: LICENSE Requires-Dist: railroad-diagrams ; extra == "diagrams" Requires-Dist: jinja2 ; extra == "diagrams" Project-URL: Documentation, https://pyparsing-docs.readthedocs.io/en/latest/ Project-URL: Homepage, https://github.com/pyparsing/pyparsing/ Project-URL: Source, https://github.com/pyparsing/pyparsing.git Provides-Extra: diagrams PyParsing -- A Python Parsing Module ==================================== |Version| |Build Status| |Coverage| |License| |Python Versions| |Snyk Score| Introduction ============ The pyparsing module is an alternative approach to creating and executing simple grammars, vs. the traditional lex/yacc approach, or the use of regular expressions. The pyparsing module provides a library of classes that client code uses to construct the grammar directly in Python code. *[Since first writing this description of pyparsing in late 2003, this technique for developing parsers has become more widespread, under the name Parsing Expression Grammars - PEGs. See more information on PEGs* `here <https://en.wikipedia.org/wiki/Parsing_expression_grammar>`__ *.]* Here is a program to parse ``"Hello, World!"`` (or any greeting of the form ``"salutation, addressee!"``): .. code:: python from pyparsing import Word, alphas greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" print(hello, "->", greet.parse_string(hello)) The program outputs the following:: Hello, World! -> ['Hello', ',', 'World', '!'] The Python representation of the grammar is quite readable, owing to the self-explanatory class names, and the use of '+', '|' and '^' operator definitions. The parsed results returned from ``parse_string()`` is a collection of type ``ParseResults``, which can be accessed as a nested list, a dictionary, or an object with named attributes. The pyparsing module handles some of the problems that are typically vexing when writing text parsers: - extra or missing whitespace (the above program will also handle ``"Hello,World!"``, ``"Hello , World !"``, etc.) - quoted strings - embedded comments The examples directory includes a simple SQL parser, simple CORBA IDL parser, a config file parser, a chemical formula parser, and a four- function algebraic notation parser, among many others. Documentation ============= There are many examples in the online docstrings of the classes and methods in pyparsing. You can find them compiled into `online docs <https://pyparsing-docs.readthedocs.io/en/latest/>`__. Additional documentation resources and project info are listed in the online `GitHub wiki <https://github.com/pyparsing/pyparsing/wiki>`__. An entire directory of examples can be found `here <https://github.com/pyparsing/pyparsing/tree/master/examples>`__. AI Instructions =============== There are also instructions for AI agents to use when helping you to create your parser. They can be pulled from the GitHub project repository, at pyparsing/ai/best_practices.md. You can also tell the AI to access them programmatically after installing pyparsing, either from the CLI with ``python -m pyparsing.ai.show_best_practices`` or within python with ``import pyparsing; pyparsing.show_best_practices()``. License ======= MIT License. See header of the `pyparsing __init__.py <https://github.com/pyparsing/pyparsing/blob/master/pyparsing/__init__.py#L1-L23>`__ file. History ======= See `CHANGES <https://github.com/pyparsing/pyparsing/blob/master/CHANGES>`__ file. Performance benchmarks ====================== For usage instructions and details on the performance benchmark suite, see ``tests/README.md`` in this repository. .. |Build Status| image:: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml/badge.svg :target: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml .. |Coverage| image:: https://codecov.io/gh/pyparsing/pyparsing/branch/master/graph/badge.svg :target: https://codecov.io/gh/pyparsing/pyparsing .. |Version| image:: https://img.shields.io/pypi/v/pyparsing?style=flat-square :target: https://pypi.org/project/pyparsing/ :alt: Version .. |License| image:: https://img.shields.io/pypi/l/pyparsing.svg?style=flat-square :target: https://pypi.org/project/pyparsing/ :alt: License .. |Python Versions| image:: https://img.shields.io/pypi/pyversions/pyparsing.svg?style=flat-square :target: https://pypi.org/project/python-liquid/ :alt: Python versions .. |Snyk Score| image:: https://snyk.io//advisor/python/pyparsing/badge.svg :target: https://snyk.io//advisor/python/pyparsing :alt: pyparsing �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

GitHub repo for this page regex-inverter