livepilot 1.10.6 → 1.10.8
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.
- package/CHANGELOG.md +168 -0
- package/README.md +12 -10
- package/bin/livepilot.js +168 -30
- package/installer/install.js +117 -11
- package/m4l_device/LivePilot_Analyzer.amxd +0 -0
- package/m4l_device/livepilot_bridge.js +215 -3
- package/mcp_server/__init__.py +1 -1
- package/mcp_server/atlas/__init__.py +132 -33
- package/mcp_server/atlas/tools.py +56 -15
- package/mcp_server/composer/layer_planner.py +27 -0
- package/mcp_server/composer/prompt_parser.py +15 -6
- package/mcp_server/connection.py +11 -3
- package/mcp_server/corpus/__init__.py +14 -4
- package/mcp_server/creative_constraints/tools.py +206 -33
- package/mcp_server/experiment/engine.py +7 -9
- package/mcp_server/hook_hunter/analyzer.py +62 -9
- package/mcp_server/hook_hunter/tools.py +60 -9
- package/mcp_server/m4l_bridge.py +68 -12
- package/mcp_server/musical_intelligence/detectors.py +32 -0
- package/mcp_server/performance_engine/tools.py +112 -29
- package/mcp_server/preview_studio/engine.py +89 -8
- package/mcp_server/preview_studio/tools.py +22 -6
- package/mcp_server/project_brain/automation_graph.py +71 -19
- package/mcp_server/project_brain/builder.py +2 -0
- package/mcp_server/project_brain/tools.py +55 -5
- package/mcp_server/reference_engine/profile_builder.py +129 -3
- package/mcp_server/reference_engine/tools.py +47 -6
- package/mcp_server/runtime/execution_router.py +66 -2
- package/mcp_server/runtime/mcp_dispatch.py +75 -3
- package/mcp_server/runtime/remote_commands.py +10 -2
- package/mcp_server/sample_engine/analyzer.py +131 -4
- package/mcp_server/sample_engine/critics.py +29 -8
- package/mcp_server/sample_engine/models.py +42 -4
- package/mcp_server/sample_engine/tools.py +48 -14
- package/mcp_server/semantic_moves/__init__.py +1 -0
- package/mcp_server/semantic_moves/compiler.py +9 -1
- package/mcp_server/semantic_moves/device_creation_compilers.py +47 -0
- package/mcp_server/semantic_moves/mix_compilers.py +170 -0
- package/mcp_server/semantic_moves/mix_moves.py +1 -1
- package/mcp_server/semantic_moves/models.py +5 -0
- package/mcp_server/semantic_moves/sound_design_compilers.py +22 -59
- package/mcp_server/semantic_moves/tools.py +15 -4
- package/mcp_server/semantic_moves/transition_compilers.py +12 -19
- package/mcp_server/server.py +75 -5
- package/mcp_server/services/singletons.py +68 -0
- package/mcp_server/session_continuity/models.py +4 -0
- package/mcp_server/session_continuity/tracker.py +14 -1
- package/mcp_server/song_brain/builder.py +110 -12
- package/mcp_server/song_brain/tools.py +77 -13
- package/mcp_server/sound_design/tools.py +112 -1
- package/mcp_server/splice_client/client.py +29 -8
- package/mcp_server/stuckness_detector/detector.py +90 -0
- package/mcp_server/stuckness_detector/tools.py +41 -0
- package/mcp_server/tools/_agent_os_engine/critics.py +24 -0
- package/mcp_server/tools/_composition_engine/__init__.py +2 -2
- package/mcp_server/tools/_composition_engine/harmony.py +90 -0
- package/mcp_server/tools/_composition_engine/sections.py +47 -4
- package/mcp_server/tools/_harmony_engine.py +52 -8
- package/mcp_server/tools/_research_engine.py +98 -19
- package/mcp_server/tools/_theory_engine.py +138 -9
- package/mcp_server/tools/agent_os.py +20 -3
- package/mcp_server/tools/analyzer.py +105 -6
- package/mcp_server/tools/clips.py +46 -1
- package/mcp_server/tools/composition.py +66 -23
- package/mcp_server/tools/devices.py +22 -1
- package/mcp_server/tools/harmony.py +115 -14
- package/mcp_server/tools/midi_io.py +23 -1
- package/mcp_server/tools/mixing.py +35 -1
- package/mcp_server/tools/motif.py +49 -3
- package/mcp_server/tools/research.py +24 -0
- package/mcp_server/tools/theory.py +108 -16
- package/mcp_server/tools/tracks.py +1 -1
- package/mcp_server/tools/transport.py +1 -1
- package/mcp_server/transition_engine/critics.py +18 -11
- package/mcp_server/translation_engine/tools.py +8 -4
- package/package.json +25 -3
- package/remote_script/LivePilot/__init__.py +77 -2
- package/remote_script/LivePilot/arrangement.py +12 -2
- package/remote_script/LivePilot/browser.py +16 -6
- package/remote_script/LivePilot/clips.py +69 -0
- package/remote_script/LivePilot/devices.py +10 -5
- package/remote_script/LivePilot/mixing.py +117 -0
- package/remote_script/LivePilot/notes.py +13 -2
- package/remote_script/LivePilot/router.py +13 -1
- package/remote_script/LivePilot/server.py +51 -13
- package/remote_script/LivePilot/version_detect.py +7 -4
- package/server.json +20 -0
- package/.claude-plugin/marketplace.json +0 -21
- package/.mcpbignore +0 -57
- package/AGENTS.md +0 -46
- package/CODE_OF_CONDUCT.md +0 -27
- package/CONTRIBUTING.md +0 -131
- package/SECURITY.md +0 -48
- package/livepilot/.Codex-plugin/plugin.json +0 -8
- package/livepilot/.claude-plugin/plugin.json +0 -8
- package/livepilot/agents/livepilot-producer/AGENT.md +0 -313
- package/livepilot/commands/arrange.md +0 -47
- package/livepilot/commands/beat.md +0 -77
- package/livepilot/commands/evaluate.md +0 -49
- package/livepilot/commands/memory.md +0 -22
- package/livepilot/commands/mix.md +0 -44
- package/livepilot/commands/perform.md +0 -42
- package/livepilot/commands/session.md +0 -13
- package/livepilot/commands/sounddesign.md +0 -43
- package/livepilot/skills/livepilot-arrangement/SKILL.md +0 -155
- package/livepilot/skills/livepilot-composition-engine/SKILL.md +0 -107
- package/livepilot/skills/livepilot-composition-engine/references/form-patterns.md +0 -97
- package/livepilot/skills/livepilot-composition-engine/references/transition-archetypes.md +0 -102
- package/livepilot/skills/livepilot-core/SKILL.md +0 -184
- package/livepilot/skills/livepilot-core/references/ableton-workflow-patterns.md +0 -831
- package/livepilot/skills/livepilot-core/references/automation-atlas.md +0 -272
- package/livepilot/skills/livepilot-core/references/device-atlas/00-index.md +0 -110
- package/livepilot/skills/livepilot-core/references/device-atlas/distortion-and-character.md +0 -687
- package/livepilot/skills/livepilot-core/references/device-atlas/drums-and-percussion.md +0 -753
- package/livepilot/skills/livepilot-core/references/device-atlas/dynamics-and-punch.md +0 -525
- package/livepilot/skills/livepilot-core/references/device-atlas/eq-and-filtering.md +0 -402
- package/livepilot/skills/livepilot-core/references/device-atlas/midi-tools.md +0 -963
- package/livepilot/skills/livepilot-core/references/device-atlas/movement-and-modulation.md +0 -874
- package/livepilot/skills/livepilot-core/references/device-atlas/space-and-depth.md +0 -571
- package/livepilot/skills/livepilot-core/references/device-atlas/spectral-and-weird.md +0 -714
- package/livepilot/skills/livepilot-core/references/device-atlas/synths-native.md +0 -953
- package/livepilot/skills/livepilot-core/references/device-knowledge/00-index.md +0 -34
- package/livepilot/skills/livepilot-core/references/device-knowledge/automation-as-music.md +0 -204
- package/livepilot/skills/livepilot-core/references/device-knowledge/chains-genre.md +0 -173
- package/livepilot/skills/livepilot-core/references/device-knowledge/creative-thinking.md +0 -211
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-distortion.md +0 -188
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-space.md +0 -162
- package/livepilot/skills/livepilot-core/references/device-knowledge/effects-spectral.md +0 -229
- package/livepilot/skills/livepilot-core/references/device-knowledge/instruments-synths.md +0 -243
- package/livepilot/skills/livepilot-core/references/m4l-devices.md +0 -352
- package/livepilot/skills/livepilot-core/references/memory-guide.md +0 -107
- package/livepilot/skills/livepilot-core/references/midi-recipes.md +0 -402
- package/livepilot/skills/livepilot-core/references/mixing-patterns.md +0 -578
- package/livepilot/skills/livepilot-core/references/overview.md +0 -290
- package/livepilot/skills/livepilot-core/references/sample-manipulation.md +0 -724
- package/livepilot/skills/livepilot-core/references/sound-design-deep.md +0 -140
- package/livepilot/skills/livepilot-core/references/sound-design.md +0 -393
- package/livepilot/skills/livepilot-devices/SKILL.md +0 -169
- package/livepilot/skills/livepilot-evaluation/SKILL.md +0 -156
- package/livepilot/skills/livepilot-evaluation/references/capability-modes.md +0 -118
- package/livepilot/skills/livepilot-evaluation/references/evaluation-contracts.md +0 -121
- package/livepilot/skills/livepilot-evaluation/references/memory-promotion.md +0 -110
- package/livepilot/skills/livepilot-mix-engine/SKILL.md +0 -123
- package/livepilot/skills/livepilot-mix-engine/references/mix-critics.md +0 -143
- package/livepilot/skills/livepilot-mix-engine/references/mix-moves.md +0 -105
- package/livepilot/skills/livepilot-mixing/SKILL.md +0 -157
- package/livepilot/skills/livepilot-notes/SKILL.md +0 -130
- package/livepilot/skills/livepilot-performance-engine/SKILL.md +0 -122
- package/livepilot/skills/livepilot-performance-engine/references/performance-safety.md +0 -98
- package/livepilot/skills/livepilot-release/SKILL.md +0 -130
- package/livepilot/skills/livepilot-sample-engine/SKILL.md +0 -105
- package/livepilot/skills/livepilot-sample-engine/references/sample-critics.md +0 -87
- package/livepilot/skills/livepilot-sample-engine/references/sample-philosophy.md +0 -51
- package/livepilot/skills/livepilot-sample-engine/references/sample-techniques.md +0 -131
- package/livepilot/skills/livepilot-sound-design-engine/SKILL.md +0 -168
- package/livepilot/skills/livepilot-sound-design-engine/references/patch-model.md +0 -119
- package/livepilot/skills/livepilot-sound-design-engine/references/sound-design-critics.md +0 -118
- package/livepilot/skills/livepilot-wonder/SKILL.md +0 -79
- package/m4l_device/LivePilot_Analyzer.maxpat +0 -2705
- package/manifest.json +0 -91
- package/mcp_server/splice_client/protos/app_pb2.pyi +0 -1153
- package/scripts/generate_tool_catalog.py +0 -131
- package/scripts/sync_metadata.py +0 -132
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Generate tool catalog from live runtime metadata.
|
|
3
|
-
|
|
4
|
-
Produces a markdown tool catalog validated against mcp.list_tools().
|
|
5
|
-
This is the single source of truth — hand-edited catalogs are replaced.
|
|
6
|
-
|
|
7
|
-
Usage: python3 scripts/generate_tool_catalog.py > docs/manual/tool-catalog-generated.md
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import asyncio
|
|
11
|
-
import inspect
|
|
12
|
-
import sys
|
|
13
|
-
from collections import defaultdict
|
|
14
|
-
from pathlib import Path
|
|
15
|
-
|
|
16
|
-
ROOT = Path(__file__).resolve().parent.parent
|
|
17
|
-
sys.path.insert(0, str(ROOT))
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def get_tools() -> list[dict]:
|
|
21
|
-
"""Get all registered tools with metadata."""
|
|
22
|
-
from mcp_server.server import mcp
|
|
23
|
-
|
|
24
|
-
tools_raw = asyncio.run(mcp.list_tools())
|
|
25
|
-
tools = []
|
|
26
|
-
for t in tools_raw:
|
|
27
|
-
# Get the module path to determine domain
|
|
28
|
-
func = t.fn if hasattr(t, "fn") else None
|
|
29
|
-
module = ""
|
|
30
|
-
if func:
|
|
31
|
-
module = func.__module__ if hasattr(func, "__module__") else ""
|
|
32
|
-
|
|
33
|
-
# Get parameter names
|
|
34
|
-
params = []
|
|
35
|
-
if func:
|
|
36
|
-
sig = inspect.signature(func)
|
|
37
|
-
for name, param in sig.parameters.items():
|
|
38
|
-
if name == "ctx":
|
|
39
|
-
continue
|
|
40
|
-
required = param.default is inspect.Parameter.empty
|
|
41
|
-
params.append({"name": name, "required": required})
|
|
42
|
-
|
|
43
|
-
tools.append({
|
|
44
|
-
"name": t.name,
|
|
45
|
-
"description": t.description[:120] if hasattr(t, "description") and t.description else "",
|
|
46
|
-
"module": module,
|
|
47
|
-
"params": params,
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
return tools
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def infer_domain(module: str) -> str:
|
|
54
|
-
"""Infer domain from module path."""
|
|
55
|
-
if "semantic_moves" in module:
|
|
56
|
-
return "Semantic Moves"
|
|
57
|
-
if "experiment" in module:
|
|
58
|
-
return "Experiments"
|
|
59
|
-
if "musical_intelligence" in module:
|
|
60
|
-
return "Musical Intelligence"
|
|
61
|
-
if "memory.tools" in module:
|
|
62
|
-
return "Memory Fabric"
|
|
63
|
-
if "mix_engine" in module:
|
|
64
|
-
return "Mix Engine"
|
|
65
|
-
if "sound_design" in module:
|
|
66
|
-
return "Sound Design"
|
|
67
|
-
if "transition_engine" in module:
|
|
68
|
-
return "Transition Engine"
|
|
69
|
-
if "reference_engine" in module:
|
|
70
|
-
return "Reference Engine"
|
|
71
|
-
if "translation_engine" in module:
|
|
72
|
-
return "Translation Engine"
|
|
73
|
-
if "performance_engine" in module:
|
|
74
|
-
return "Performance Engine"
|
|
75
|
-
if "project_brain" in module:
|
|
76
|
-
return "Project Brain"
|
|
77
|
-
if "evaluation" in module:
|
|
78
|
-
return "Evaluation"
|
|
79
|
-
if "runtime" in module:
|
|
80
|
-
return "Runtime"
|
|
81
|
-
|
|
82
|
-
# Core tools — extract from module name
|
|
83
|
-
parts = module.split(".")
|
|
84
|
-
for p in reversed(parts):
|
|
85
|
-
if p in ("transport", "tracks", "clips", "notes", "devices", "scenes",
|
|
86
|
-
"mixing", "browser", "arrangement", "memory", "analyzer",
|
|
87
|
-
"automation", "theory", "generative", "harmony", "midi_io",
|
|
88
|
-
"perception", "agent_os", "composition", "motif", "research",
|
|
89
|
-
"planner"):
|
|
90
|
-
return p.replace("_", " ").title()
|
|
91
|
-
|
|
92
|
-
return "Other"
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def main():
|
|
96
|
-
tools = get_tools()
|
|
97
|
-
total = len(tools)
|
|
98
|
-
|
|
99
|
-
# Group by domain
|
|
100
|
-
domains = defaultdict(list)
|
|
101
|
-
for t in tools:
|
|
102
|
-
domain = infer_domain(t["module"])
|
|
103
|
-
domains[domain].append(t)
|
|
104
|
-
|
|
105
|
-
print(f"# LivePilot — Full Tool Catalog (Generated)")
|
|
106
|
-
print()
|
|
107
|
-
print(f"{total} tools across {len(domains)} domains.")
|
|
108
|
-
print()
|
|
109
|
-
print("> Auto-generated from `mcp.list_tools()`. Do not hand-edit.")
|
|
110
|
-
print("> Regenerate: `python3 scripts/generate_tool_catalog.py`")
|
|
111
|
-
print()
|
|
112
|
-
print("---")
|
|
113
|
-
print()
|
|
114
|
-
|
|
115
|
-
for domain in sorted(domains.keys()):
|
|
116
|
-
tool_list = sorted(domains[domain], key=lambda t: t["name"])
|
|
117
|
-
print(f"## {domain} ({len(tool_list)})")
|
|
118
|
-
print()
|
|
119
|
-
print("| Tool | Description |")
|
|
120
|
-
print("|------|-------------|")
|
|
121
|
-
for t in tool_list:
|
|
122
|
-
desc = t["description"].split("\n")[0].strip()
|
|
123
|
-
print(f"| `{t['name']}` | {desc} |")
|
|
124
|
-
print()
|
|
125
|
-
|
|
126
|
-
print(f"---")
|
|
127
|
-
print(f"*Generated from {total} registered tools.*")
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if __name__ == "__main__":
|
|
131
|
-
main()
|
package/scripts/sync_metadata.py
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Metadata sync — single source of truth for version and tool count.
|
|
3
|
-
|
|
4
|
-
Reads version from package.json, tool count from test_tools_contract.py,
|
|
5
|
-
and verifies all known locations are in sync.
|
|
6
|
-
|
|
7
|
-
Usage:
|
|
8
|
-
python scripts/sync_metadata.py --check # verify, exit 1 if stale
|
|
9
|
-
python scripts/sync_metadata.py --fix # auto-fix stale references
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import json
|
|
13
|
-
import re
|
|
14
|
-
import sys
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
|
|
17
|
-
ROOT = Path(__file__).resolve().parents[1]
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def get_version() -> str:
|
|
21
|
-
"""Read version from package.json (source of truth)."""
|
|
22
|
-
pkg = json.loads((ROOT / "package.json").read_text(encoding="utf-8"))
|
|
23
|
-
return pkg["version"]
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def get_tool_count() -> int:
|
|
27
|
-
"""Read tool count from test_tools_contract.py assertion."""
|
|
28
|
-
src = (ROOT / "tests" / "test_tools_contract.py").read_text(encoding="utf-8")
|
|
29
|
-
match = re.search(r"assert len\(tools\) == (\d+)", src)
|
|
30
|
-
if match:
|
|
31
|
-
return int(match.group(1))
|
|
32
|
-
raise ValueError("Could not find tool count assertion in test_tools_contract.py")
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
# Files that must contain the version string
|
|
36
|
-
VERSION_FILES = [
|
|
37
|
-
"package.json",
|
|
38
|
-
"server.json",
|
|
39
|
-
"manifest.json",
|
|
40
|
-
"livepilot/.claude-plugin/plugin.json",
|
|
41
|
-
"livepilot/.Codex-plugin/plugin.json",
|
|
42
|
-
".claude-plugin/marketplace.json",
|
|
43
|
-
"mcp_server/__init__.py",
|
|
44
|
-
"remote_script/LivePilot/__init__.py",
|
|
45
|
-
"CLAUDE.md",
|
|
46
|
-
"AGENTS.md",
|
|
47
|
-
"livepilot/skills/livepilot-core/references/overview.md",
|
|
48
|
-
"docs/M4L_BRIDGE.md",
|
|
49
|
-
]
|
|
50
|
-
|
|
51
|
-
# Files that must contain the tool count
|
|
52
|
-
TOOL_COUNT_FILES = [
|
|
53
|
-
"README.md",
|
|
54
|
-
"package.json",
|
|
55
|
-
"server.json",
|
|
56
|
-
"CLAUDE.md",
|
|
57
|
-
"AGENTS.md",
|
|
58
|
-
"CONTRIBUTING.md",
|
|
59
|
-
"livepilot/.claude-plugin/plugin.json",
|
|
60
|
-
"livepilot/.Codex-plugin/plugin.json",
|
|
61
|
-
"livepilot/skills/livepilot-core/SKILL.md",
|
|
62
|
-
"livepilot/skills/livepilot-core/references/overview.md",
|
|
63
|
-
"docs/manual/index.md",
|
|
64
|
-
"docs/manual/tool-reference.md",
|
|
65
|
-
"docs/manual/tool-catalog.md",
|
|
66
|
-
]
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def check_version(version: str) -> list[str]:
|
|
70
|
-
"""Check all version files for staleness."""
|
|
71
|
-
issues = []
|
|
72
|
-
for rel_path in VERSION_FILES:
|
|
73
|
-
path = ROOT / rel_path
|
|
74
|
-
if not path.exists():
|
|
75
|
-
continue
|
|
76
|
-
content = path.read_text(encoding="utf-8")
|
|
77
|
-
if version not in content:
|
|
78
|
-
# Find what version IS there
|
|
79
|
-
old = re.search(r"1\.\d+\.\d+", content)
|
|
80
|
-
old_ver = old.group(0) if old else "???"
|
|
81
|
-
if old_ver != version:
|
|
82
|
-
issues.append(f" {rel_path}: has {old_ver}, expected {version}")
|
|
83
|
-
return issues
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def check_tool_count(count: int) -> list[str]:
|
|
87
|
-
"""Check all tool count files for staleness."""
|
|
88
|
-
issues = []
|
|
89
|
-
count_str = str(count)
|
|
90
|
-
for rel_path in TOOL_COUNT_FILES:
|
|
91
|
-
path = ROOT / rel_path
|
|
92
|
-
if not path.exists():
|
|
93
|
-
continue
|
|
94
|
-
content = path.read_text(encoding="utf-8")
|
|
95
|
-
# Look for "N tools" pattern
|
|
96
|
-
matches = re.findall(r"(\d+)\s+tools", content)
|
|
97
|
-
for m in matches:
|
|
98
|
-
if m != count_str and int(m) > 250: # ignore subset counts like "210 tools"
|
|
99
|
-
issues.append(f" {rel_path}: has '{m} tools', expected '{count_str} tools'")
|
|
100
|
-
break
|
|
101
|
-
return issues
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def main():
|
|
105
|
-
mode = sys.argv[1] if len(sys.argv) > 1 else "--check"
|
|
106
|
-
|
|
107
|
-
version = get_version()
|
|
108
|
-
tool_count = get_tool_count()
|
|
109
|
-
|
|
110
|
-
print(f"Source of truth: version={version}, tools={tool_count}")
|
|
111
|
-
|
|
112
|
-
version_issues = check_version(version)
|
|
113
|
-
count_issues = check_tool_count(tool_count)
|
|
114
|
-
|
|
115
|
-
all_issues = version_issues + count_issues
|
|
116
|
-
|
|
117
|
-
if all_issues:
|
|
118
|
-
print(f"\nFound {len(all_issues)} stale reference(s):")
|
|
119
|
-
for issue in all_issues:
|
|
120
|
-
print(issue)
|
|
121
|
-
if mode == "--check":
|
|
122
|
-
sys.exit(1)
|
|
123
|
-
elif mode == "--fix":
|
|
124
|
-
print("\n--fix mode not yet implemented. Fix manually.")
|
|
125
|
-
sys.exit(1)
|
|
126
|
-
else:
|
|
127
|
-
print("All metadata in sync.")
|
|
128
|
-
sys.exit(0)
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if __name__ == "__main__":
|
|
132
|
-
main()
|