ausecon-mcp-server 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. ausecon_mcp_server-0.5.0/.github/workflows/ci.yml +42 -0
  2. ausecon_mcp_server-0.5.0/.github/workflows/release.yml +43 -0
  3. ausecon_mcp_server-0.5.0/.gitignore +11 -0
  4. ausecon_mcp_server-0.5.0/AGENTS.md +74 -0
  5. ausecon_mcp_server-0.5.0/CHANGELOG.md +145 -0
  6. ausecon_mcp_server-0.5.0/CLAUDE.md +74 -0
  7. ausecon_mcp_server-0.5.0/LICENSE +21 -0
  8. ausecon_mcp_server-0.5.0/PKG-INFO +412 -0
  9. ausecon_mcp_server-0.5.0/README.md +371 -0
  10. ausecon_mcp_server-0.5.0/docs/superpowers/plans/2026-04-12-rba-abs-mcp-server.md +61 -0
  11. ausecon_mcp_server-0.5.0/docs/variant_candidates.md +14 -0
  12. ausecon_mcp_server-0.5.0/examples/claude_desktop_config.json +13 -0
  13. ausecon_mcp_server-0.5.0/fastmcp.json +11 -0
  14. ausecon_mcp_server-0.5.0/pyproject.toml +49 -0
  15. ausecon_mcp_server-0.5.0/scripts/dump_variant_candidates.py +152 -0
  16. ausecon_mcp_server-0.5.0/src/ausecon_mcp/__init__.py +1 -0
  17. ausecon_mcp_server-0.5.0/src/ausecon_mcp/cache.py +29 -0
  18. ausecon_mcp_server-0.5.0/src/ausecon_mcp/catalogue/__init__.py +1 -0
  19. ausecon_mcp_server-0.5.0/src/ausecon_mcp/catalogue/abs.py +889 -0
  20. ausecon_mcp_server-0.5.0/src/ausecon_mcp/catalogue/rba.py +947 -0
  21. ausecon_mcp_server-0.5.0/src/ausecon_mcp/catalogue/resolver.py +333 -0
  22. ausecon_mcp_server-0.5.0/src/ausecon_mcp/catalogue/search.py +134 -0
  23. ausecon_mcp_server-0.5.0/src/ausecon_mcp/errors.py +17 -0
  24. ausecon_mcp_server-0.5.0/src/ausecon_mcp/models.py +61 -0
  25. ausecon_mcp_server-0.5.0/src/ausecon_mcp/parsers/__init__.py +1 -0
  26. ausecon_mcp_server-0.5.0/src/ausecon_mcp/parsers/abs_csv.py +100 -0
  27. ausecon_mcp_server-0.5.0/src/ausecon_mcp/parsers/abs_structure.py +72 -0
  28. ausecon_mcp_server-0.5.0/src/ausecon_mcp/parsers/rba_csv.py +131 -0
  29. ausecon_mcp_server-0.5.0/src/ausecon_mcp/providers/__init__.py +1 -0
  30. ausecon_mcp_server-0.5.0/src/ausecon_mcp/providers/_retry.py +43 -0
  31. ausecon_mcp_server-0.5.0/src/ausecon_mcp/providers/abs.py +105 -0
  32. ausecon_mcp_server-0.5.0/src/ausecon_mcp/providers/rba.py +113 -0
  33. ausecon_mcp_server-0.5.0/src/ausecon_mcp/server.py +245 -0
  34. ausecon_mcp_server-0.5.0/src/ausecon_mcp/validation.py +150 -0
  35. ausecon_mcp_server-0.5.0/tests/conftest.py +8 -0
  36. ausecon_mcp_server-0.5.0/tests/fixtures/abs_ana_agg_sample.csv +4 -0
  37. ausecon_mcp_server-0.5.0/tests/fixtures/abs_cpi_sample.csv +4 -0
  38. ausecon_mcp_server-0.5.0/tests/fixtures/abs_cpi_structure.xml +133 -0
  39. ausecon_mcp_server-0.5.0/tests/fixtures/rba_a2_sample.csv +14 -0
  40. ausecon_mcp_server-0.5.0/tests/fixtures/rba_g1_sample.csv +14 -0
  41. ausecon_mcp_server-0.5.0/tests/test_abs_provider.py +132 -0
  42. ausecon_mcp_server-0.5.0/tests/test_catalogue.py +127 -0
  43. ausecon_mcp_server-0.5.0/tests/test_parsers.py +88 -0
  44. ausecon_mcp_server-0.5.0/tests/test_rba_provider.py +155 -0
  45. ausecon_mcp_server-0.5.0/tests/test_repository_hygiene.py +84 -0
  46. ausecon_mcp_server-0.5.0/tests/test_resolver.py +214 -0
  47. ausecon_mcp_server-0.5.0/tests/test_server.py +348 -0
  48. ausecon_mcp_server-0.5.0/uv.lock +1624 -0
@@ -0,0 +1,42 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ['3.10', '3.12']
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Verify public repository hygiene
21
+ shell: bash
22
+ run: |
23
+ test -f LICENSE
24
+ if rg -n "rba_abs_mcp|<your-repo-url>" README.md examples pyproject.toml; then
25
+ echo "Found stale public references"
26
+ exit 1
27
+ fi
28
+
29
+ - uses: actions/setup-python@v5
30
+ with:
31
+ python-version: ${{ matrix.python-version }}
32
+
33
+ - uses: astral-sh/setup-uv@v6
34
+
35
+ - name: Install dependencies
36
+ run: uv sync --python ${{ matrix.python-version }} --extra dev
37
+
38
+ - name: Lint
39
+ run: uv run ruff check src tests
40
+
41
+ - name: Test
42
+ run: uv run pytest
@@ -0,0 +1,43 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: '3.12'
18
+
19
+ - name: Install build tooling
20
+ run: python -m pip install --upgrade build
21
+
22
+ - name: Build sdist and wheel
23
+ run: python -m build
24
+
25
+ - uses: actions/upload-artifact@v4
26
+ with:
27
+ name: dist
28
+ path: dist/
29
+
30
+ publish:
31
+ needs: build
32
+ runs-on: ubuntu-latest
33
+ environment: pypi
34
+ permissions:
35
+ id-token: write
36
+ steps:
37
+ - uses: actions/download-artifact@v4
38
+ with:
39
+ name: dist
40
+ path: dist/
41
+
42
+ - name: Publish to PyPI
43
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,11 @@
1
+ .venv/
2
+ __pycache__/
3
+ .pytest_cache/
4
+ .ruff_cache/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ coverage.xml
9
+ .coverage
10
+ ausecon-mcp-server-future-releases.png
11
+ .DS_Store
@@ -0,0 +1,74 @@
1
+ # AGENTS.md
2
+
3
+ This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ uv sync --python 3.12
10
+
11
+ # Run all tests
12
+ uv run pytest
13
+
14
+ # Run a single test file
15
+ uv run pytest tests/test_catalogue.py
16
+
17
+ # Run a single test by name
18
+ uv run pytest tests/test_catalogue.py::test_search_catalogue_prefers_high_value_alias_matches
19
+
20
+ # Lint and format
21
+ uv run ruff check src tests
22
+ uv run ruff format src tests
23
+
24
+ # Run the MCP server (stdio mode)
25
+ uv run ausecon-mcp-server
26
+ ```
27
+
28
+ ## Architecture
29
+
30
+ This is a **FastMCP server** that wraps ABS (Australian Bureau of Statistics) and RBA (Reserve Bank of Australia) data APIs. The design is intentionally thin on the MCP surface and delegates all logic to internal layers.
31
+
32
+ ### Layer structure
33
+
34
+ ```
35
+ server.py → FastMCP tool definitions, AuseconService orchestrator
36
+ providers/ → Async httpx clients for each source (ABS, RBA), TTLCache wrappers
37
+ parsers/ → Pure functions: raw HTTP response text → normalised dicts
38
+ catalogue/ → Static curated dicts (abs.py, rba.py) + search.py ranking logic
39
+ models.py → SeriesDescriptor and Observation dataclasses; shared to_dict() helpers
40
+ cache.py → In-memory TTLCache (monotonic clock, per-instance, no persistence)
41
+ ```
42
+
43
+ ### Data flow
44
+
45
+ 1. MCP tool call → `AuseconService` method
46
+ 2. `AuseconService` → `ABSProvider` or `RBAProvider` (checks TTLCache first)
47
+ 3. Provider → httpx GET → raw CSV or XML response
48
+ 4. Parser (`parse_abs_csv`, `parse_rba_csv`, `parse_abs_structure`) → `{metadata, series, observations}` dict
49
+ 5. Optional post-fetch filtering (`_slice_observations`, `_filter_rba_payload`) for `last_n`, date ranges, series IDs
50
+ 6. Result cached and returned as dict (not model instances)
51
+
52
+ ### ABS vs RBA differences
53
+
54
+ - **ABS** uses SDMX REST (`data.api.abs.gov.au/rest`): structure endpoint returns XML, data endpoint returns CSV with `format=csvfile`.
55
+ - **RBA** serves static CSVs at `rba.gov.au/statistics/tables/csv/{table_id}-data.csv`; all filtering is done client-side after download.
56
+
57
+ ### Tool injection pattern
58
+
59
+ `build_server()` in `server.py` creates the FastMCP instance and registers all tools as closures over an `AuseconService`. Tests inject mock providers directly into `AuseconService`, which is then passed to `build_server()`.
60
+
61
+ ### Catalogue search scoring
62
+
63
+ `search_catalogue` in `catalogue/search.py` ranks entries by weighted keyword matching: exact alias match (+120) > exact name match (+100) > substring in name (+45) > substring in description (+25) > alias term overlap (+20 per term). Source filtering (`source="abs"` or `"rba"`) is applied before scoring.
64
+
65
+ ### Response shape
66
+
67
+ All retrieval tools return `{metadata: {...}, series: [...], observations: [...]}`. Provenance fields (`retrieval_url`, `truncated`, `updated_after`) are added to `metadata` after parsing.
68
+
69
+ ## Key conventions
70
+
71
+ - All provider methods are `async`; `list_tables` on `RBAProvider` is the only sync exception (no I/O).
72
+ - `asyncio_mode = "auto"` is set in `pyproject.toml` — no `@pytest.mark.asyncio` decorator needed.
73
+ - Tests use `respx` for HTTP mocking and fixture files in `tests/fixtures/`.
74
+ - Ruff target is Python 3.10 with `E, F, I, B, UP` rules and line length 100.
@@ -0,0 +1,145 @@
1
+ # Changelog
2
+
3
+ All notable changes to `ausecon-mcp-server` are recorded here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres
5
+ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.5.0] - 2026-04-17
8
+
9
+ Semantic-defaults and release-readiness release. Curated
10
+ `get_economic_series` concepts now resolve to concrete series by default, and
11
+ the public onboarding docs now cover the main local MCP clients.
12
+
13
+ ### Changed
14
+ - `cash_rate_target`, `headline_cpi`, `trimmed_mean_inflation`, and
15
+ `gdp_growth` now resolve to narrowed default series instead of broad ABS
16
+ datasets or RBA tables.
17
+ - Curated catalogue entries for `CPI`, `ANA_AGG`, `a2`, and `g1` now include
18
+ populated default semantic variants used by the resolver.
19
+ - `README.md` now documents the actual `get_economic_series` inputs and
20
+ provides self-serve local setup instructions for Claude Desktop, Claude Code,
21
+ and Codex.
22
+
23
+ ### Fixed
24
+ - ABS structure parsing now handles the current SDMX structure shape where
25
+ dimension metadata is nested under `ConceptIdentity` / `LocalRepresentation`
26
+ and includes `TimeDimension` entries.
27
+ - ABS CSV parsing now handles current upstream column names such as
28
+ `TIME_PERIOD`, `UNIT_MEASURE`, `UNIT_MULT`, and `OBS_STATUS`, rather than
29
+ only the older labelled column variants.
30
+ - Repository hygiene and behavioural tests now pin the `v0.5.0` semantic
31
+ shortcut contract and public onboarding text.
32
+
33
+ ## [0.4.0] - 2026-04-17
34
+
35
+ Semantic resolver release. `get_economic_series` accepts variant / geography /
36
+ frequency and dispatches to narrowed ABS or RBA retrievals.
37
+
38
+ ### Added
39
+ - `ausecon_mcp.catalogue.resolver` module exposing `resolve()`, `build_abs_key()`,
40
+ `ResolvedQuery`, and the `CURATED_SHORTCUTS` map (replaces the removed
41
+ `CURATED_SERIES` dict on `server`).
42
+ - ABS SDMX key construction that orders dimensions by `position`, composes from
43
+ literal dot-keys or `DIM=code;DIM=code` variant fragments, and validates each
44
+ emitted code against the live codelist.
45
+ - RBA variant resolution returns the variant's `rba_series_ids` as the
46
+ `get_rba_table` filter.
47
+ - `tests/test_resolver.py` — 19 unit tests covering unknown/ambiguous concepts,
48
+ unknown/unpopulated variants, frequency/geography validation, key composition,
49
+ and codelist mismatches.
50
+ - First populated variant: `g1.headline` → `["GCPIAG"]`. Additional variants are
51
+ populated progressively as `scripts/dump_variant_candidates.py` output is
52
+ reviewed.
53
+
54
+ ### Changed
55
+ - `get_economic_series` no longer rejects `variant` / `geography` / `frequency`;
56
+ it routes through the new resolver. Unknown values raise actionable errors
57
+ listing what is available.
58
+ - When a curated shortcut has no variant supplied and no explicit variant is
59
+ declared, the response is identical to v0.3.2 (whole dataset or whole table).
60
+
61
+ ### Removed
62
+ - `CURATED_SERIES` dict and `_unsupported_semantic_options` helper from
63
+ `server.py`.
64
+
65
+ ## [0.3.2] - 2026-04-17
66
+
67
+ Bridge release between the v0.3.x discovery work and the upcoming v0.4.0 semantic
68
+ resolver. No tool-surface changes.
69
+
70
+ ### Added
71
+ - `CHANGELOG.md` seeded from git history. Earlier releases are reconstructed from
72
+ commit history and the README version notes.
73
+ - `scripts/dump_variant_candidates.py` — dev-only helper that fetches each curated
74
+ RBA table and ABS dataflow structure, then writes a reviewable reference doc at
75
+ `docs/variant_candidates.md`. Used to hand-populate `variants[*].abs_key` and
76
+ `variants[*].rba_series_ids` in preparation for the v0.4.0 resolver.
77
+
78
+ ### Changed
79
+ - `get_economic_series` now raises a version-neutral message when `variant`,
80
+ `geography`, or `frequency` are supplied. The previous message referenced
81
+ `v0.3.0` even in v0.3.1.
82
+
83
+ ## [0.3.1] - 2026-04-16
84
+
85
+ ### Fixed
86
+ - Support Python 3.10 by depending on `tomli` for pre-3.11 interpreters.
87
+ - Allow `pytest >= 9`.
88
+
89
+ ### Changed
90
+ - README now displays a release badge.
91
+
92
+ ## [0.3.0] - 2026-04-14
93
+
94
+ Discovery release. Same six-tool surface, materially expanded catalogue and
95
+ deterministic search ranking.
96
+
97
+ ### Added
98
+ - Expanded ABS catalogue to ~30 curated dataflows across prices, labour, national
99
+ accounts, activity, housing & construction, external sector, credit & finance,
100
+ and demographics.
101
+ - Expanded RBA catalogue to ~30 active tables (plus `discontinued: True` tagging
102
+ where applicable) across monetary policy, payments, money & credit, interest
103
+ rates, exchange rates, inflation, output & labour, external sector, and
104
+ household finance.
105
+ - `search_datasets` uses deterministic tiered scoring: exact id > exact alias >
106
+ exact name > full-term match > partial-term match > description match.
107
+ - Catalogue entries declare resolver schema fields (`frequencies`, `geographies`,
108
+ `variants`) that stay inert until the v0.4.0 resolver consumes them.
109
+ - Catalogue-coverage and search-ranking tests in `tests/test_catalogue.py`.
110
+
111
+ ## [0.2.0] - 2026-04-12
112
+
113
+ Hardening release.
114
+
115
+ ### Added
116
+ - `validation.py` — input validation for dataflow IDs, keys, ABS periods, ISO
117
+ dates, positive integers, series IDs, categories, and `updated_after`
118
+ timestamps. Applied at every tool boundary.
119
+ - `providers/_retry.py` — exponential backoff (0.1s → 0.2s → 0.4s, 3 attempts)
120
+ with 4xx-no-retry / 5xx-retry / timeout-retry behaviour.
121
+ - Provider-level error wrapping: `AuseconParseError` for malformed upstream
122
+ payloads, `AuseconUpstreamError` for HTTP failures.
123
+ - Per-provider TTLCache (3600s default) for raw upstream payloads.
124
+ - Support for ABS `a2` event-style tables.
125
+
126
+ ## [0.1.0] - 2026-04-12
127
+
128
+ Initial public release.
129
+
130
+ ### Added
131
+ - FastMCP server exposing six tools (`search_datasets`, `get_abs_data`,
132
+ `get_abs_dataset_structure`, `get_rba_table`, `list_rba_tables`,
133
+ `get_economic_series`).
134
+ - Async httpx providers for ABS SDMX REST and RBA statistical CSVs.
135
+ - Pure-function parsers for ABS SDMX CSV, ABS structure XML, and RBA CSVs.
136
+ - Initial curated catalogues for ABS and RBA, plus a four-concept
137
+ `CURATED_SERIES` semantic shortcut map.
138
+
139
+ [0.5.0]: https://github.com/AnthonyPuggs/ausecon-mcp-server/compare/v0.4.0...v0.5.0
140
+ [0.4.0]: https://github.com/AnthonyPuggs/ausecon-mcp-server/compare/v0.3.2...v0.4.0
141
+ [0.3.2]: https://github.com/AnthonyPuggs/ausecon-mcp-server/compare/v0.3.1...v0.3.2
142
+ [0.3.1]: https://github.com/AnthonyPuggs/ausecon-mcp-server/compare/v0.3.0...v0.3.1
143
+ [0.3.0]: https://github.com/AnthonyPuggs/ausecon-mcp-server/compare/v0.2.0...v0.3.0
144
+ [0.2.0]: https://github.com/AnthonyPuggs/ausecon-mcp-server/compare/v0.1.0...v0.2.0
145
+ [0.1.0]: https://github.com/AnthonyPuggs/ausecon-mcp-server/releases/tag/v0.1.0
@@ -0,0 +1,74 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ uv sync --python 3.12
10
+
11
+ # Run all tests
12
+ uv run pytest
13
+
14
+ # Run a single test file
15
+ uv run pytest tests/test_catalogue.py
16
+
17
+ # Run a single test by name
18
+ uv run pytest tests/test_catalogue.py::test_search_catalogue_prefers_high_value_alias_matches
19
+
20
+ # Lint and format
21
+ uv run ruff check src tests
22
+ uv run ruff format src tests
23
+
24
+ # Run the MCP server (stdio mode)
25
+ uv run ausecon-mcp-server
26
+ ```
27
+
28
+ ## Architecture
29
+
30
+ This is a **FastMCP server** that wraps ABS (Australian Bureau of Statistics) and RBA (Reserve Bank of Australia) data APIs. The design is intentionally thin on the MCP surface and delegates all logic to internal layers.
31
+
32
+ ### Layer structure
33
+
34
+ ```
35
+ server.py → FastMCP tool definitions, AuseconService orchestrator
36
+ providers/ → Async httpx clients for each source (ABS, RBA), TTLCache wrappers
37
+ parsers/ → Pure functions: raw HTTP response text → normalised dicts
38
+ catalogue/ → Static curated dicts (abs.py, rba.py) + search.py ranking logic
39
+ models.py → SeriesDescriptor and Observation dataclasses; shared to_dict() helpers
40
+ cache.py → In-memory TTLCache (monotonic clock, per-instance, no persistence)
41
+ ```
42
+
43
+ ### Data flow
44
+
45
+ 1. MCP tool call → `AuseconService` method
46
+ 2. `AuseconService` → `ABSProvider` or `RBAProvider` (checks TTLCache first)
47
+ 3. Provider → httpx GET → raw CSV or XML response
48
+ 4. Parser (`parse_abs_csv`, `parse_rba_csv`, `parse_abs_structure`) → `{metadata, series, observations}` dict
49
+ 5. Optional post-fetch filtering (`_slice_observations`, `_filter_rba_payload`) for `last_n`, date ranges, series IDs
50
+ 6. Result cached and returned as dict (not model instances)
51
+
52
+ ### ABS vs RBA differences
53
+
54
+ - **ABS** uses SDMX REST (`data.api.abs.gov.au/rest`): structure endpoint returns XML, data endpoint returns CSV with `format=csvfile`.
55
+ - **RBA** serves static CSVs at `rba.gov.au/statistics/tables/csv/{table_id}-data.csv`; all filtering is done client-side after download.
56
+
57
+ ### Tool injection pattern
58
+
59
+ `build_server()` in `server.py` creates the FastMCP instance and registers all tools as closures over an `AuseconService`. Tests inject mock providers directly into `AuseconService`, which is then passed to `build_server()`.
60
+
61
+ ### Catalogue search scoring
62
+
63
+ `search_catalogue` in `catalogue/search.py` ranks entries by weighted keyword matching: exact alias match (+120) > exact name match (+100) > substring in name (+45) > substring in description (+25) > alias term overlap (+20 per term). Source filtering (`source="abs"` or `"rba"`) is applied before scoring.
64
+
65
+ ### Response shape
66
+
67
+ All retrieval tools return `{metadata: {...}, series: [...], observations: [...]}`. Provenance fields (`retrieval_url`, `truncated`, `updated_after`) are added to `metadata` after parsing.
68
+
69
+ ## Key conventions
70
+
71
+ - All provider methods are `async`; `list_tables` on `RBAProvider` is the only sync exception (no I/O).
72
+ - `asyncio_mode = "auto"` is set in `pyproject.toml` — no `@pytest.mark.asyncio` decorator needed.
73
+ - Tests use `respx` for HTTP mocking and fixture files in `tests/fixtures/`.
74
+ - Ruff target is Python 3.10 with `E, F, I, B, UP` rules and line length 100.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anthony P
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.