chase-mcp 0.1.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.
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "chase-cps",
3
+ "description": "Plugins of the CHASE project (https://chase-cps.github.io).",
4
+ "owner": {
5
+ "name": "CHASE developers"
6
+ },
7
+ "plugins": [
8
+ {
9
+ "name": "chase",
10
+ "source": "./",
11
+ "description": "MCP server and skill for assume-guarantee contracts with CHASE."
12
+ }
13
+ ]
14
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "chase",
3
+ "version": "0.1.0",
4
+ "description": "Assume-guarantee contracts in LTL with CHASE: composition, quotient, refinement, consistency, compatibility, and realizability checks, with counterexamples.",
5
+ "author": {
6
+ "name": "CHASE developers"
7
+ },
8
+ "homepage": "https://chase-cps.github.io",
9
+ "repository": "https://github.com/chase-cps/chase-mcp",
10
+ "license": "BSD-3-Clause"
11
+ }
@@ -0,0 +1,36 @@
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-24.04
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 chase-cps from source
20
+ run: |
21
+ sudo apt-get update && sudo apt-get install -y uuid-dev libxml2 libedit2
22
+ pip install "chase-cps @ git+https://github.com/chase-cps/chase@master"
23
+
24
+ - name: Cache the back ends
25
+ uses: actions/cache@v4
26
+ with:
27
+ path: ~/.chase
28
+ key: chase-tools-nuxmv-2.2.0
29
+
30
+ - name: Install nuXmv with chase-cps install
31
+ run: test -x ~/.chase/bin/nuXmv || chase-cps install nuxmv --accept-license
32
+
33
+ - name: Install and test
34
+ run: |
35
+ pip install ".[test]"
36
+ pytest -q
@@ -0,0 +1,84 @@
1
+ name: Release
2
+
3
+ # Builds the chase-mcp package.
4
+ # - Manual run: the package is uploaded to TestPyPI, with the version
5
+ # X.Y.Z.devN (N is the number of the run), so that each run can be uploaded.
6
+ # - Tag v*: the package is uploaded to PyPI.
7
+ # Both use trusted publishing: the PyPI (and TestPyPI) project must list this
8
+ # repository, this workflow (release.yml), and the environment (pypi, testpypi).
9
+
10
+ on:
11
+ push:
12
+ tags: ["v*"]
13
+ workflow_dispatch:
14
+
15
+ jobs:
16
+ build:
17
+ runs-on: ubuntu-22.04
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.12"
24
+
25
+ - name: Check that the tag matches the version
26
+ if: startsWith(github.ref, 'refs/tags/v')
27
+ run: |
28
+ version=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
29
+ test "${GITHUB_REF_NAME#v}" = "$version"
30
+ grep -q "__version__ = \"$version\"" chase_mcp/__init__.py
31
+
32
+ - name: Use a development version on TestPyPI
33
+ if: github.event_name == 'workflow_dispatch'
34
+ shell: bash
35
+ run: |
36
+ python3 - "pyproject.toml chase_mcp/__init__.py" "${{ github.run_number }}" <<'PY'
37
+ import re, sys
38
+ files, run = sys.argv[1].split(), sys.argv[2]
39
+ for f in files:
40
+ s = open(f).read()
41
+ s = re.sub(r'^(version|__version__) = "([^"]+)"', rf'\1 = "\2.dev{run}"', s, flags=re.M)
42
+ open(f, "w").write(s)
43
+ PY
44
+
45
+ - name: Build
46
+ run: |
47
+ pip install build
48
+ python -m build
49
+
50
+ - uses: actions/upload-artifact@v4
51
+ with:
52
+ name: dist
53
+ path: dist/
54
+
55
+ testpypi:
56
+ if: github.event_name == 'workflow_dispatch'
57
+ needs: build
58
+ runs-on: ubuntu-22.04
59
+ environment: testpypi
60
+ permissions:
61
+ id-token: write
62
+ steps:
63
+ - uses: actions/download-artifact@v4
64
+ with:
65
+ name: dist
66
+ path: dist
67
+ - uses: pypa/gh-action-pypi-publish@release/v1
68
+ with:
69
+ repository-url: https://test.pypi.org/legacy/
70
+ skip-existing: true
71
+
72
+ pypi:
73
+ if: startsWith(github.ref, 'refs/tags/v')
74
+ needs: build
75
+ runs-on: ubuntu-22.04
76
+ environment: pypi
77
+ permissions:
78
+ id-token: write
79
+ steps:
80
+ - uses: actions/download-artifact@v4
81
+ with:
82
+ name: dist
83
+ path: dist
84
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,7 @@
1
+ __pycache__/
2
+ *.egg-info/
3
+ build/
4
+ dist/
5
+ .venv/
6
+ .pytest_cache/
7
+ .DS_Store
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "chase": {
4
+ "command": "uvx",
5
+ "args": ["chase-mcp"]
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026 by University of California, Berkeley
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,197 @@
1
+ Metadata-Version: 2.5
2
+ Name: chase-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server exposing the contract operations of CHASE as agent-callable tools
5
+ Project-URL: Homepage, https://chase-cps.github.io
6
+ Project-URL: Repository, https://github.com/chase-cps/chase-mcp
7
+ Project-URL: Issues, https://github.com/chase-cps/chase-mcp/issues
8
+ Author-email: Yifeng Xiao <yifengx@berkeley.edu>
9
+ License-Expression: BSD-3-Clause
10
+ License-File: LICENSE
11
+ Requires-Python: >=3.10
12
+ Requires-Dist: chase-cps>=0.1
13
+ Requires-Dist: mcp<3,>=2
14
+ Requires-Dist: pydantic>=2
15
+ Provides-Extra: test
16
+ Requires-Dist: pytest; extra == 'test'
17
+ Description-Content-Type: text/markdown
18
+
19
+ # CHASE MCP server
20
+
21
+ This repository contains a [Model Context Protocol][MCP] (MCP) server and an
22
+ agent skill for [CHASE][WEB] (Contract-based Heterogeneous Analysis and
23
+ Systems Exploration).
24
+
25
+ The server exposes the contract operations of CHASE as tools that an AI agent
26
+ can call: an agent can write assume-guarantee contracts, compose them, check
27
+ refinement, and use the counterexamples returned by the model checker to fix
28
+ the specification. The skill tells the agent how to use these tools.
29
+
30
+ ## Tools
31
+
32
+ Contract operations that build contracts (each tool returns a new
33
+ contract):
34
+
35
+ - **compose**: parallel composition of two or more contracts; variables with
36
+ the same name are connected.
37
+ - **conjoin** and **disjoin**: conjunction and disjunction (greatest lower
38
+ bound and least upper bound).
39
+ - **merge**: merging of viewpoints of the same component.
40
+ - **divide**: the quotient, i.e. the contract of a missing component.
41
+ - **separate**: separation, the adjoint of merging.
42
+ - **saturate**: the equivalent contract (A, A -> G).
43
+ - **simplify**: rewrites the formulas, as the simplify command of
44
+ `logics_tool` (negations moved to the atoms, temporal operators grouped).
45
+ - **remove_redundant**: removes the assumptions and guarantees implied by the
46
+ other terms of the contract.
47
+
48
+ Contract operations that check contracts (each tool returns a status and,
49
+ when the check fails, a counterexample):
50
+
51
+ - **refines**: whether a contract refines another one, and which part fails
52
+ (assumptions or guarantees).
53
+ - **verify**: compatibility and consistency; **is_compatible** (some
54
+ environment satisfies the assumptions) and **is_consistent** (some behavior
55
+ satisfies the contract) check them one at a time.
56
+ - **is_realizable**: GR(1) realizability, with the counter-strategy of the
57
+ environment when unrealizable; **synthesize** also builds the controller.
58
+ - **accepts** and **implements**: whether the contract accepts an
59
+ environment, and whether an implementation implements the contract, both
60
+ given as LTL formulas.
61
+
62
+ LTL formulas:
63
+
64
+ - **implies** and **is_satisfiable**: validity of an implication and
65
+ satisfiability of a formula.
66
+
67
+ Specifications:
68
+
69
+ - **read_spec** and **write_spec**: read and write contracts in the logics
70
+ language of CHASE (the `.ltl` files of `logics_tool`).
71
+
72
+ A contract is given in JSON:
73
+
74
+ ```json
75
+ {"name": "Arbiter",
76
+ "inputs": {"req": "bool", "n": [0, 3]},
77
+ "outputs": {"grant": "bool"},
78
+ "assumptions": ["G F !req"],
79
+ "guarantees": ["G (req -> F grant)"]}
80
+ ```
81
+
82
+ Variables are Boolean (`"bool"`) or bounded integers (`[low, high]`). Formulas
83
+ use the standard LTL syntax: `! & | -> <-> G F X U R W`, relations, arithmetic,
84
+ and `x'` for the value of `x` in the next step.
85
+
86
+ ## Requirements
87
+
88
+ - The CHASE Python package, `chase-cps`, installed with the server.
89
+ - [nuXmv][NUXMV] for the checks (free for academic and non-commercial use),
90
+ in the `PATH` or given with the environment variable `CHASE_NUXMV`;
91
+ [NuSMV][NUSMV] where nuXmv cannot be used.
92
+ - [slugs][SLUGS] for the realizability checks.
93
+
94
+ `chase-cps install nuxmv --accept-license` and `chase-cps install slugs`
95
+ install them, and `chase-cps doctor` shows the tools found.
96
+ The [CHASE Docker image][CHASE] contains all of them.
97
+
98
+ ## Installation
99
+
100
+ The server is a Python program that runs on the standard input and output.
101
+ With [uv][UV] there is nothing to install: `uvx chase-mcp` downloads and runs
102
+ it. Otherwise:
103
+
104
+ `$> pip install chase-mcp`
105
+
106
+ and use `chase-mcp` in place of `uvx chase-mcp` below.
107
+
108
+ Until the first release on PyPI, install from the repositories:
109
+
110
+ `$> pip install "chase-cps @ git+https://github.com/chase-cps/chase" "chase-mcp @ git+https://github.com/chase-cps/chase-mcp"`
111
+
112
+ ### Claude Code
113
+
114
+ The server and the skill are packaged as a plugin:
115
+
116
+ ```
117
+ /plugin marketplace add chase-cps/chase-mcp
118
+ /plugin install chase@chase-cps
119
+ ```
120
+
121
+ Or only the server:
122
+
123
+ `$> claude mcp add chase -- uvx chase-mcp`
124
+
125
+ ### Codex
126
+
127
+ `$> codex mcp add chase -- uvx chase-mcp`
128
+
129
+ or, in `~/.codex/config.toml`:
130
+
131
+ ```toml
132
+ [mcp_servers.chase]
133
+ command = "uvx"
134
+ args = ["chase-mcp"]
135
+ ```
136
+
137
+ ### Cursor, Claude Desktop, Gemini CLI, and other clients
138
+
139
+ Most MCP clients read the same JSON configuration. Add the server to the
140
+ `mcpServers` object of the configuration file (`.cursor/mcp.json` or
141
+ `~/.cursor/mcp.json` for Cursor, `claude_desktop_config.json` for Claude
142
+ Desktop, `~/.gemini/settings.json` for Gemini CLI):
143
+
144
+ ```json
145
+ {"mcpServers": {"chase": {"command": "uvx", "args": ["chase-mcp"]}}}
146
+ ```
147
+
148
+ VS Code uses `servers` in `.vscode/mcp.json`:
149
+
150
+ ```json
151
+ {"servers": {"chase": {"type": "stdio", "command": "uvx", "args": ["chase-mcp"]}}}
152
+ ```
153
+
154
+ OpenCode uses `mcp` in `opencode.json`:
155
+
156
+ ```json
157
+ {"mcp": {"chase": {"type": "local", "command": ["uvx", "chase-mcp"]}}}
158
+ ```
159
+
160
+ To set the model checker, add `"env": {"CHASE_NUXMV": "/path/to/nuXmv"}` to
161
+ the server entry (`environment` in OpenCode, `env = { ... }` in Codex).
162
+
163
+ ## Skill
164
+
165
+ The skill is in `skills/chase-contracts`. It follows the [Agent Skills][SKILLS]
166
+ format (a `SKILL.md` file with instructions), and it also works without the
167
+ MCP server: the agent then uses the `chase_cps` Python package. The
168
+ `examples` folder of the skill contains complete examples; each one is run by
169
+ the tests, so the results they state are the ones CHASE returns.
170
+
171
+ - Claude Code: installed with the plugin, or copy the folder to
172
+ `~/.claude/skills/`.
173
+ - Codex: copy the folder to `~/.agents/skills/` (or `.agents/skills/` in a
174
+ project).
175
+ - Other agents that support Agent Skills: copy the folder to their skills
176
+ directory.
177
+
178
+ ## Testing
179
+
180
+ `$> pip install ".[test]"`
181
+
182
+ `$> pytest`
183
+
184
+ The tests need nuXmv (`chase-cps install nuxmv --accept-license`).
185
+
186
+ ## License
187
+
188
+ This project is released under the 3-Clause BSD License.
189
+
190
+ [MCP]: https://modelcontextprotocol.io
191
+ [WEB]: https://chase-cps.github.io
192
+ [CHASE]: https://github.com/chase-cps/chase
193
+ [NUXMV]: https://nuxmv.fbk.eu/
194
+ [NUSMV]: https://nusmv.fbk.eu/
195
+ [SLUGS]: https://github.com/VerifiableRobotics/slugs
196
+ [UV]: https://docs.astral.sh/uv/
197
+ [SKILLS]: https://agentskills.io
@@ -0,0 +1,179 @@
1
+ # CHASE MCP server
2
+
3
+ This repository contains a [Model Context Protocol][MCP] (MCP) server and an
4
+ agent skill for [CHASE][WEB] (Contract-based Heterogeneous Analysis and
5
+ Systems Exploration).
6
+
7
+ The server exposes the contract operations of CHASE as tools that an AI agent
8
+ can call: an agent can write assume-guarantee contracts, compose them, check
9
+ refinement, and use the counterexamples returned by the model checker to fix
10
+ the specification. The skill tells the agent how to use these tools.
11
+
12
+ ## Tools
13
+
14
+ Contract operations that build contracts (each tool returns a new
15
+ contract):
16
+
17
+ - **compose**: parallel composition of two or more contracts; variables with
18
+ the same name are connected.
19
+ - **conjoin** and **disjoin**: conjunction and disjunction (greatest lower
20
+ bound and least upper bound).
21
+ - **merge**: merging of viewpoints of the same component.
22
+ - **divide**: the quotient, i.e. the contract of a missing component.
23
+ - **separate**: separation, the adjoint of merging.
24
+ - **saturate**: the equivalent contract (A, A -> G).
25
+ - **simplify**: rewrites the formulas, as the simplify command of
26
+ `logics_tool` (negations moved to the atoms, temporal operators grouped).
27
+ - **remove_redundant**: removes the assumptions and guarantees implied by the
28
+ other terms of the contract.
29
+
30
+ Contract operations that check contracts (each tool returns a status and,
31
+ when the check fails, a counterexample):
32
+
33
+ - **refines**: whether a contract refines another one, and which part fails
34
+ (assumptions or guarantees).
35
+ - **verify**: compatibility and consistency; **is_compatible** (some
36
+ environment satisfies the assumptions) and **is_consistent** (some behavior
37
+ satisfies the contract) check them one at a time.
38
+ - **is_realizable**: GR(1) realizability, with the counter-strategy of the
39
+ environment when unrealizable; **synthesize** also builds the controller.
40
+ - **accepts** and **implements**: whether the contract accepts an
41
+ environment, and whether an implementation implements the contract, both
42
+ given as LTL formulas.
43
+
44
+ LTL formulas:
45
+
46
+ - **implies** and **is_satisfiable**: validity of an implication and
47
+ satisfiability of a formula.
48
+
49
+ Specifications:
50
+
51
+ - **read_spec** and **write_spec**: read and write contracts in the logics
52
+ language of CHASE (the `.ltl` files of `logics_tool`).
53
+
54
+ A contract is given in JSON:
55
+
56
+ ```json
57
+ {"name": "Arbiter",
58
+ "inputs": {"req": "bool", "n": [0, 3]},
59
+ "outputs": {"grant": "bool"},
60
+ "assumptions": ["G F !req"],
61
+ "guarantees": ["G (req -> F grant)"]}
62
+ ```
63
+
64
+ Variables are Boolean (`"bool"`) or bounded integers (`[low, high]`). Formulas
65
+ use the standard LTL syntax: `! & | -> <-> G F X U R W`, relations, arithmetic,
66
+ and `x'` for the value of `x` in the next step.
67
+
68
+ ## Requirements
69
+
70
+ - The CHASE Python package, `chase-cps`, installed with the server.
71
+ - [nuXmv][NUXMV] for the checks (free for academic and non-commercial use),
72
+ in the `PATH` or given with the environment variable `CHASE_NUXMV`;
73
+ [NuSMV][NUSMV] where nuXmv cannot be used.
74
+ - [slugs][SLUGS] for the realizability checks.
75
+
76
+ `chase-cps install nuxmv --accept-license` and `chase-cps install slugs`
77
+ install them, and `chase-cps doctor` shows the tools found.
78
+ The [CHASE Docker image][CHASE] contains all of them.
79
+
80
+ ## Installation
81
+
82
+ The server is a Python program that runs on the standard input and output.
83
+ With [uv][UV] there is nothing to install: `uvx chase-mcp` downloads and runs
84
+ it. Otherwise:
85
+
86
+ `$> pip install chase-mcp`
87
+
88
+ and use `chase-mcp` in place of `uvx chase-mcp` below.
89
+
90
+ Until the first release on PyPI, install from the repositories:
91
+
92
+ `$> pip install "chase-cps @ git+https://github.com/chase-cps/chase" "chase-mcp @ git+https://github.com/chase-cps/chase-mcp"`
93
+
94
+ ### Claude Code
95
+
96
+ The server and the skill are packaged as a plugin:
97
+
98
+ ```
99
+ /plugin marketplace add chase-cps/chase-mcp
100
+ /plugin install chase@chase-cps
101
+ ```
102
+
103
+ Or only the server:
104
+
105
+ `$> claude mcp add chase -- uvx chase-mcp`
106
+
107
+ ### Codex
108
+
109
+ `$> codex mcp add chase -- uvx chase-mcp`
110
+
111
+ or, in `~/.codex/config.toml`:
112
+
113
+ ```toml
114
+ [mcp_servers.chase]
115
+ command = "uvx"
116
+ args = ["chase-mcp"]
117
+ ```
118
+
119
+ ### Cursor, Claude Desktop, Gemini CLI, and other clients
120
+
121
+ Most MCP clients read the same JSON configuration. Add the server to the
122
+ `mcpServers` object of the configuration file (`.cursor/mcp.json` or
123
+ `~/.cursor/mcp.json` for Cursor, `claude_desktop_config.json` for Claude
124
+ Desktop, `~/.gemini/settings.json` for Gemini CLI):
125
+
126
+ ```json
127
+ {"mcpServers": {"chase": {"command": "uvx", "args": ["chase-mcp"]}}}
128
+ ```
129
+
130
+ VS Code uses `servers` in `.vscode/mcp.json`:
131
+
132
+ ```json
133
+ {"servers": {"chase": {"type": "stdio", "command": "uvx", "args": ["chase-mcp"]}}}
134
+ ```
135
+
136
+ OpenCode uses `mcp` in `opencode.json`:
137
+
138
+ ```json
139
+ {"mcp": {"chase": {"type": "local", "command": ["uvx", "chase-mcp"]}}}
140
+ ```
141
+
142
+ To set the model checker, add `"env": {"CHASE_NUXMV": "/path/to/nuXmv"}` to
143
+ the server entry (`environment` in OpenCode, `env = { ... }` in Codex).
144
+
145
+ ## Skill
146
+
147
+ The skill is in `skills/chase-contracts`. It follows the [Agent Skills][SKILLS]
148
+ format (a `SKILL.md` file with instructions), and it also works without the
149
+ MCP server: the agent then uses the `chase_cps` Python package. The
150
+ `examples` folder of the skill contains complete examples; each one is run by
151
+ the tests, so the results they state are the ones CHASE returns.
152
+
153
+ - Claude Code: installed with the plugin, or copy the folder to
154
+ `~/.claude/skills/`.
155
+ - Codex: copy the folder to `~/.agents/skills/` (or `.agents/skills/` in a
156
+ project).
157
+ - Other agents that support Agent Skills: copy the folder to their skills
158
+ directory.
159
+
160
+ ## Testing
161
+
162
+ `$> pip install ".[test]"`
163
+
164
+ `$> pytest`
165
+
166
+ The tests need nuXmv (`chase-cps install nuxmv --accept-license`).
167
+
168
+ ## License
169
+
170
+ This project is released under the 3-Clause BSD License.
171
+
172
+ [MCP]: https://modelcontextprotocol.io
173
+ [WEB]: https://chase-cps.github.io
174
+ [CHASE]: https://github.com/chase-cps/chase
175
+ [NUXMV]: https://nuxmv.fbk.eu/
176
+ [NUSMV]: https://nusmv.fbk.eu/
177
+ [SLUGS]: https://github.com/VerifiableRobotics/slugs
178
+ [UV]: https://docs.astral.sh/uv/
179
+ [SKILLS]: https://agentskills.io
@@ -0,0 +1,3 @@
1
+ """MCP server for CHASE: contract operations as agent-callable tools."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,3 @@
1
+ from .server import main
2
+
3
+ main()