machina-abstractrix 0.0.1__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.
- machina_abstractrix-0.0.1/LICENSE +21 -0
- machina_abstractrix-0.0.1/MANIFEST.in +1 -0
- machina_abstractrix-0.0.1/PKG-INFO +76 -0
- machina_abstractrix-0.0.1/README.md +60 -0
- machina_abstractrix-0.0.1/pyproject.toml +32 -0
- machina_abstractrix-0.0.1/setup.cfg +4 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/__init__.py +20 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/cli.py +136 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/config.py +43 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/functions.py +493 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/githf.py +83 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/machina.yaml +70 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/main.py +125 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/providers/__init__.py +7 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/providers/camelids.py +161 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/providers/depsek.py +164 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/providers/metai.py +170 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/providers/openai.py +169 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/providers/strangelove.py +170 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix/utilities.py +433 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix.egg-info/PKG-INFO +76 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix.egg-info/SOURCES.txt +28 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix.egg-info/dependency_links.txt +1 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix.egg-info/entry_points.txt +2 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix.egg-info/requires.txt +1 -0
- machina_abstractrix-0.0.1/src/machina_abstractrix.egg-info/top_level.txt +1 -0
- machina_abstractrix-0.0.1/tests/test_cli.py +20 -0
- machina_abstractrix-0.0.1/tests/test_e2e.py +45 -0
- machina_abstractrix-0.0.1/tests/test_llm_soup.py +71 -0
- machina_abstractrix-0.0.1/tests/test_utilities.py +69 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Alexander Fedotov
|
|
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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include src/machina_abstractrix/*.yaml
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: machina-abstractrix
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Abstracting Machine (a machine that acts as an abstractor).
|
|
5
|
+
Author-email: Machina Ratiocinatrix <machina.ratio@gmail.com>, Alexander Fedotov <alex.fedotov@aol.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/machina-abstractrix/machina-abstractrix
|
|
7
|
+
Keywords: machina-abstractrix
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: pyyaml==6.0.3
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# Machina-Abstractrix
|
|
18
|
+
Abstracting Machine (a machine that acts as an abstractor).
|
|
19
|
+
|
|
20
|
+
In order to launch it from the command line or as a Python subprocess:
|
|
21
|
+
```bash
|
|
22
|
+
echo "Theodotos-Alexandreus: I need a more abstract view of it, machine!" \
|
|
23
|
+
| uvx machina-abstractrix \
|
|
24
|
+
--provider-api-key=sk-proj-... \
|
|
25
|
+
--github-token=ghp_...
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or, with a local pip installation:
|
|
29
|
+
```bash
|
|
30
|
+
pip install machina-abstractrix
|
|
31
|
+
```
|
|
32
|
+
Set the environment variables:
|
|
33
|
+
```bash
|
|
34
|
+
export PROVIDER_API_KEY="sk-proj-..."
|
|
35
|
+
export GITHUB_TOKEN="ghp_..."
|
|
36
|
+
```
|
|
37
|
+
Then:
|
|
38
|
+
```bash
|
|
39
|
+
machina-abstractrix multilogue.txt
|
|
40
|
+
```
|
|
41
|
+
Or:
|
|
42
|
+
```bash
|
|
43
|
+
machina-abstractrix multilogue.txt > output.txt
|
|
44
|
+
```
|
|
45
|
+
Or:
|
|
46
|
+
```bash
|
|
47
|
+
machina-abstractrix multilogue.txt > tmp && mv tmp multilogue.txt
|
|
48
|
+
```
|
|
49
|
+
Or:
|
|
50
|
+
```bash
|
|
51
|
+
cat multilogue.txt new_turn.txt | machina-abstractrix
|
|
52
|
+
```
|
|
53
|
+
Or:
|
|
54
|
+
```bash
|
|
55
|
+
cat multilogue.txt new_turn.txt | machina-abstractrix > tmp && mv tmp multilogue.txt
|
|
56
|
+
```
|
|
57
|
+
Or:
|
|
58
|
+
```bash
|
|
59
|
+
(cat multilogue.txt; echo:"Theodotos: What do you think, Machina-Abstractrix?") \
|
|
60
|
+
| machina-abstractrix
|
|
61
|
+
```
|
|
62
|
+
Or:
|
|
63
|
+
```bash
|
|
64
|
+
cat multilogue.txt new_turn.txt | machina-abstractrix > tmp && mv tmp multilogue.txt
|
|
65
|
+
```
|
|
66
|
+
Or, if you have installed other machines:
|
|
67
|
+
```bash
|
|
68
|
+
cat multilogue.md | machina-abstractrix \
|
|
69
|
+
| summarizing-machine | judging-machine > summary_judgment.md
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Or use it in your Python code:
|
|
73
|
+
```Python
|
|
74
|
+
# Python
|
|
75
|
+
import machina_abstractrix
|
|
76
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Machina-Abstractrix
|
|
2
|
+
Abstracting Machine (a machine that acts as an abstractor).
|
|
3
|
+
|
|
4
|
+
In order to launch it from the command line or as a Python subprocess:
|
|
5
|
+
```bash
|
|
6
|
+
echo "Theodotos-Alexandreus: I need a more abstract view of it, machine!" \
|
|
7
|
+
| uvx machina-abstractrix \
|
|
8
|
+
--provider-api-key=sk-proj-... \
|
|
9
|
+
--github-token=ghp_...
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Or, with a local pip installation:
|
|
13
|
+
```bash
|
|
14
|
+
pip install machina-abstractrix
|
|
15
|
+
```
|
|
16
|
+
Set the environment variables:
|
|
17
|
+
```bash
|
|
18
|
+
export PROVIDER_API_KEY="sk-proj-..."
|
|
19
|
+
export GITHUB_TOKEN="ghp_..."
|
|
20
|
+
```
|
|
21
|
+
Then:
|
|
22
|
+
```bash
|
|
23
|
+
machina-abstractrix multilogue.txt
|
|
24
|
+
```
|
|
25
|
+
Or:
|
|
26
|
+
```bash
|
|
27
|
+
machina-abstractrix multilogue.txt > output.txt
|
|
28
|
+
```
|
|
29
|
+
Or:
|
|
30
|
+
```bash
|
|
31
|
+
machina-abstractrix multilogue.txt > tmp && mv tmp multilogue.txt
|
|
32
|
+
```
|
|
33
|
+
Or:
|
|
34
|
+
```bash
|
|
35
|
+
cat multilogue.txt new_turn.txt | machina-abstractrix
|
|
36
|
+
```
|
|
37
|
+
Or:
|
|
38
|
+
```bash
|
|
39
|
+
cat multilogue.txt new_turn.txt | machina-abstractrix > tmp && mv tmp multilogue.txt
|
|
40
|
+
```
|
|
41
|
+
Or:
|
|
42
|
+
```bash
|
|
43
|
+
(cat multilogue.txt; echo:"Theodotos: What do you think, Machina-Abstractrix?") \
|
|
44
|
+
| machina-abstractrix
|
|
45
|
+
```
|
|
46
|
+
Or:
|
|
47
|
+
```bash
|
|
48
|
+
cat multilogue.txt new_turn.txt | machina-abstractrix > tmp && mv tmp multilogue.txt
|
|
49
|
+
```
|
|
50
|
+
Or, if you have installed other machines:
|
|
51
|
+
```bash
|
|
52
|
+
cat multilogue.md | machina-abstractrix \
|
|
53
|
+
| summarizing-machine | judging-machine > summary_judgment.md
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or use it in your Python code:
|
|
57
|
+
```Python
|
|
58
|
+
# Python
|
|
59
|
+
import machina_abstractrix
|
|
60
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools==82.0.1"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "machina-abstractrix"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
authors = [
|
|
9
|
+
{name="Machina Ratiocinatrix", email="machina.ratio@gmail.com"},
|
|
10
|
+
{name="Alexander Fedotov", email="alex.fedotov@aol.com"}
|
|
11
|
+
]
|
|
12
|
+
description = "Abstracting Machine (a machine that acts as an abstractor)."
|
|
13
|
+
readme = "README.md"
|
|
14
|
+
requires-python = ">=3.10"
|
|
15
|
+
classifiers=[
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
]
|
|
20
|
+
keywords = ["machina-abstractrix"]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"pyyaml == 6.0.3"
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.scripts]
|
|
26
|
+
machina-abstractrix = "machina_abstractrix.cli:run"
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
"Homepage" = "https://github.com/machina-abstractrix/machina-abstractrix"
|
|
30
|
+
|
|
31
|
+
[dependency-groups]
|
|
32
|
+
dev = ["pytest>=8.0.0"]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Python
|
|
3
|
+
|
|
4
|
+
"""Copyright (c) Alexander Fedotov.
|
|
5
|
+
This source code is licensed under the license found in the
|
|
6
|
+
LICENSE file in the root directory of this source tree.
|
|
7
|
+
"""
|
|
8
|
+
from .config import Config
|
|
9
|
+
from .main import machina
|
|
10
|
+
from .githf import fetch_instructions
|
|
11
|
+
from .utilities import (plato_text_to_muj,
|
|
12
|
+
plato_text_to_mpuj,
|
|
13
|
+
llm_soup_to_text,
|
|
14
|
+
new_plato_text)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
'machina',
|
|
18
|
+
'fetch_instructions',
|
|
19
|
+
'Config'
|
|
20
|
+
]
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Python
|
|
3
|
+
|
|
4
|
+
"""Copyright (c) Alexander Fedotov.
|
|
5
|
+
This source code is licensed under the license found in the
|
|
6
|
+
LICENSE file in the root directory of this source tree.
|
|
7
|
+
"""
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
import select
|
|
11
|
+
import fileinput
|
|
12
|
+
import argparse
|
|
13
|
+
import syslog
|
|
14
|
+
from .config import Config
|
|
15
|
+
from .utilities import new_plato_text
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def options_and_arguments():
|
|
19
|
+
parser = argparse.ArgumentParser(
|
|
20
|
+
description="Machina-Ratiocinatrix ratiocinates.",
|
|
21
|
+
epilog="Example: machina input_text.txt > output_text.txt"
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# Give the access key and token, or set the environment variables in advance.
|
|
25
|
+
parser.add_argument('-p', '--provider-api-key',
|
|
26
|
+
default=os.getenv('PROVIDER_API_KEY', 'no_key'),
|
|
27
|
+
help="LLM provider API key (defaults to $PROVIDER_API_KEY)")
|
|
28
|
+
parser.add_argument('-g', '--github-token',
|
|
29
|
+
default=os.getenv('GITHUB_TOKEN', 'no_token'),
|
|
30
|
+
help="GitHub API token (defaults to $GITHUB_TOKEN)")
|
|
31
|
+
|
|
32
|
+
parser.add_argument('-a', '--append',
|
|
33
|
+
action='store_true',
|
|
34
|
+
help="Append the proceeds to the input.")
|
|
35
|
+
|
|
36
|
+
parser.add_argument('-d', '--debug',
|
|
37
|
+
action='store_true',
|
|
38
|
+
help="Debug flag.")
|
|
39
|
+
|
|
40
|
+
parser.add_argument('-i', '--interactive',
|
|
41
|
+
action='store_true',
|
|
42
|
+
help="Enable interactive mode (defaults to False)")
|
|
43
|
+
|
|
44
|
+
# Positional arguments (files)
|
|
45
|
+
# '*' captures zero or more arguments into a list, nargs='+' one or more.
|
|
46
|
+
parser.add_argument('filenames',
|
|
47
|
+
nargs='*',
|
|
48
|
+
help="Zero (when text comes though a pipe) or more files to process.")
|
|
49
|
+
return parser
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def run():
|
|
53
|
+
"""After installation, on Linux prompt
|
|
54
|
+
$ machina file1.txt file2.txt > output.txt
|
|
55
|
+
"""
|
|
56
|
+
args = options_and_arguments().parse_args()
|
|
57
|
+
|
|
58
|
+
# If no files are provided AND no data is being piped in - exit.
|
|
59
|
+
# if not args.filenames:
|
|
60
|
+
# # Check if stdin (fd 0) is ready to be read
|
|
61
|
+
# readable, _, _ = select.select([sys.stdin], [], [], 0.1)
|
|
62
|
+
# if not readable:
|
|
63
|
+
# print("Error: No input files or piped text stream.")
|
|
64
|
+
# options_and_arguments().print_help()
|
|
65
|
+
# sys.exit(1)
|
|
66
|
+
|
|
67
|
+
# Ingest files line by line. Join is here for long files.
|
|
68
|
+
# lines = []
|
|
69
|
+
# for line in fileinput.input(files=args.filenames or ['-'], encoding="utf-8"):
|
|
70
|
+
# lines.append(line)
|
|
71
|
+
# raw_input = "".join(lines)
|
|
72
|
+
|
|
73
|
+
config = Config()
|
|
74
|
+
|
|
75
|
+
if args.provider_api_key:
|
|
76
|
+
if args.provider_api_key.startswith('sk-'):
|
|
77
|
+
if args.provider_api_key.startswith('sk-proj-'):
|
|
78
|
+
config.provider = 'OpenAI'
|
|
79
|
+
os.environ['OPENAI_API_KEY'] = args.provider_api_key
|
|
80
|
+
elif args.provider_api_key.startswith('sk-ant-'):
|
|
81
|
+
config.provider = 'Anthropic'
|
|
82
|
+
os.environ['ANTHROPIC_API_KEY'] = args.provider_api_key
|
|
83
|
+
elif args.provider_api_key.startswith('LLM|'):
|
|
84
|
+
config.provider = 'MetAI'
|
|
85
|
+
os.environ['METAI_API_KEY'] = args.provider_api_key
|
|
86
|
+
else:
|
|
87
|
+
config.provider = 'DepSek'
|
|
88
|
+
os.environ['DEPSEK_API_KEY'] = args.provider_api_key
|
|
89
|
+
|
|
90
|
+
config.provider_api_key = args.provider_api_key
|
|
91
|
+
|
|
92
|
+
if args.github_token:
|
|
93
|
+
config.github_token = args.github_token
|
|
94
|
+
os.environ['GITHUB_TOKEN'] = args.github_token
|
|
95
|
+
|
|
96
|
+
# Ingest files line by line. Join is here for long files.
|
|
97
|
+
lines = []
|
|
98
|
+
for line in fileinput.input(files=args.filenames or ['-'], encoding="utf-8"):
|
|
99
|
+
lines.append(line)
|
|
100
|
+
raw_input = "".join(lines)
|
|
101
|
+
|
|
102
|
+
from .main import machina
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
thoughts, text = machina(raw_input, config)
|
|
106
|
+
output = new_plato_text(thoughts, text, config.name)
|
|
107
|
+
if args.append:
|
|
108
|
+
output = raw_input + '\n\n' + output
|
|
109
|
+
sys.stdout.write(output)
|
|
110
|
+
sys.stdout.flush()
|
|
111
|
+
|
|
112
|
+
# Assesment and signals.
|
|
113
|
+
|
|
114
|
+
utterance = "Machina is ready"
|
|
115
|
+
# Open syslog connection
|
|
116
|
+
syslog.openlog(
|
|
117
|
+
ident="machina-ratiocinatrix",
|
|
118
|
+
logoption=syslog.LOG_NDELAY,
|
|
119
|
+
facility=syslog.LOG_USER
|
|
120
|
+
)
|
|
121
|
+
# Signal (single line less than 4096 only!)
|
|
122
|
+
syslog.syslog(syslog.LOG_INFO, utterance)
|
|
123
|
+
syslog.closelog()
|
|
124
|
+
|
|
125
|
+
except Exception as e:
|
|
126
|
+
if args.debug:
|
|
127
|
+
import traceback
|
|
128
|
+
traceback.print_exc()
|
|
129
|
+
else:
|
|
130
|
+
sys.stderr.write(f'Machina did not work {e}\n')
|
|
131
|
+
sys.stderr.flush()
|
|
132
|
+
sys.exit(1)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
if __name__ == '__main__':
|
|
136
|
+
run()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Python
|
|
3
|
+
|
|
4
|
+
"""Copyright (c) Alexander Fedotov.
|
|
5
|
+
This source code is licensed under the license found in the
|
|
6
|
+
LICENSE file in the root directory of this source tree.
|
|
7
|
+
"""
|
|
8
|
+
from os import environ
|
|
9
|
+
from dataclasses import dataclass, field, fields, asdict
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class Config:
|
|
14
|
+
github_token: str = field(default_factory=lambda: environ.get('GITHUB_TOKEN', ''))
|
|
15
|
+
github_name: str = field(default_factory=lambda: environ.get('GITHUB_NAME', ''))
|
|
16
|
+
github_email: str = field(default_factory=lambda: environ.get('GITHUB_EMAIL', ''))
|
|
17
|
+
provider_api_key: str = field(default_factory=lambda: environ.get('PROVIDER_API_KEY', ''))
|
|
18
|
+
provider: str = field(default_factory=lambda: environ.get('PROVIDER', ''))
|
|
19
|
+
machine_organization_name: str = field(
|
|
20
|
+
default_factory=lambda: environ.get('ORGANIZATION_NAME', 'machina-ratiocinatrix'))
|
|
21
|
+
private_repo_with_text: str = field(
|
|
22
|
+
default_factory=lambda: environ.get('REPO_WITH_INSTRUCTIONS', 'machina_ratiocinatrix'))
|
|
23
|
+
system_prompt_file: str = field(default_factory=lambda: environ.get('SYSTEM_INSTRUCTIONS_FILE', 'machina.yaml'))
|
|
24
|
+
name: str = field(default_factory=lambda: environ.get('NAME', ''))
|
|
25
|
+
instructions: str = field(default_factory=lambda: environ.get('INSTRUCTIONS', ''))
|
|
26
|
+
verb: str = field(default_factory=lambda: environ.get('VERB', ''))
|
|
27
|
+
tools: str = field(
|
|
28
|
+
default_factory=lambda: environ.get('TOOLS', '')) # Swapped [] to '' for consistency with str annotation
|
|
29
|
+
rubric: str = field(default_factory=lambda: environ.get('RUBRIC', ''))
|
|
30
|
+
|
|
31
|
+
def to_dict(self):
|
|
32
|
+
return asdict(self)
|
|
33
|
+
|
|
34
|
+
def update_from_dict(self, data: dict):
|
|
35
|
+
# Now self.__dict__ is fully populated, but fields() is still safer!
|
|
36
|
+
valid_fields = {f.name for f in fields(self)}
|
|
37
|
+
for key, value in data.items():
|
|
38
|
+
if key in valid_fields:
|
|
39
|
+
setattr(self, key, value)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
if __name__ == '__main__':
|
|
43
|
+
...
|