ctf-agent 1.2.0

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 (152) hide show
  1. package/AGENTS.md +131 -0
  2. package/Dockerfile +192 -0
  3. package/README.md +522 -0
  4. package/agents/ctf-analyzer.md +58 -0
  5. package/agents/ctf-controller.md +151 -0
  6. package/agents/ctf-speedrun.md +74 -0
  7. package/bin/ctf-agent.js +119 -0
  8. package/docker-compose.yml +13 -0
  9. package/mcp_config.json +19 -0
  10. package/package.json +44 -0
  11. package/references/ctf-triage-ladder.md +68 -0
  12. package/references/exploit-databases.md +575 -0
  13. package/references/llm-safety-and-policy-compliance.md +173 -0
  14. package/references/multi-agent-orchestration-and-policy-routing.md +278 -0
  15. package/references/security-events-and-intelligence.md +566 -0
  16. package/references/version-matrix.md +59 -0
  17. package/rules/ctf-execution-rules.md +44 -0
  18. package/rules/ctf-safety-framing-rules.md +140 -0
  19. package/rules/flag-validation-rules.md +25 -0
  20. package/scripts/__init__.py +1 -0
  21. package/scripts/ctf-tools.lock +205 -0
  22. package/scripts/ctf_init.py +1026 -0
  23. package/scripts/ctf_update.py +583 -0
  24. package/scripts/ctfd_client.py +81 -0
  25. package/scripts/cve_lookup.py +453 -0
  26. package/scripts/extract_flags.py +155 -0
  27. package/scripts/install_as_agent.py +278 -0
  28. package/scripts/install_ctf_tools.sh +603 -0
  29. package/scripts/parallel_triage.py +395 -0
  30. package/scripts/prompt_policy_sanitizer.py +283 -0
  31. package/scripts/scope_guard.py +444 -0
  32. package/scripts/skill_validator.py +504 -0
  33. package/scripts/workspace_cleaner.py +141 -0
  34. package/skills/ctf-ai-ml/SKILL.md +120 -0
  35. package/skills/ctf-ai-ml/adversarial-ml.md +623 -0
  36. package/skills/ctf-ai-ml/llm-attacks.md +487 -0
  37. package/skills/ctf-ai-ml/model-attacks.md +422 -0
  38. package/skills/ctf-crypto/SKILL.md +320 -0
  39. package/skills/ctf-crypto/advanced-math.md +798 -0
  40. package/skills/ctf-crypto/classic-ciphers.md +651 -0
  41. package/skills/ctf-crypto/ecc-attacks.md +347 -0
  42. package/skills/ctf-crypto/exotic-crypto-2.md +380 -0
  43. package/skills/ctf-crypto/exotic-crypto.md +528 -0
  44. package/skills/ctf-crypto/historical.md +113 -0
  45. package/skills/ctf-crypto/lattice-and-lwe.md +524 -0
  46. package/skills/ctf-crypto/modern-ciphers-2.md +563 -0
  47. package/skills/ctf-crypto/modern-ciphers-3.md +453 -0
  48. package/skills/ctf-crypto/modern-ciphers.md +649 -0
  49. package/skills/ctf-crypto/prng-attacks.md +257 -0
  50. package/skills/ctf-crypto/prng.md +664 -0
  51. package/skills/ctf-crypto/rsa-attacks-2.md +792 -0
  52. package/skills/ctf-crypto/rsa-attacks.md +487 -0
  53. package/skills/ctf-crypto/stream-ciphers.md +390 -0
  54. package/skills/ctf-crypto/zkp-and-advanced.md +456 -0
  55. package/skills/ctf-forensics/3d-printing.md +121 -0
  56. package/skills/ctf-forensics/SKILL.md +379 -0
  57. package/skills/ctf-forensics/disk-advanced.md +497 -0
  58. package/skills/ctf-forensics/disk-and-memory.md +491 -0
  59. package/skills/ctf-forensics/disk-recovery.md +699 -0
  60. package/skills/ctf-forensics/linux-forensics.md +511 -0
  61. package/skills/ctf-forensics/network-advanced.md +583 -0
  62. package/skills/ctf-forensics/network.md +645 -0
  63. package/skills/ctf-forensics/peripheral-capture.md +287 -0
  64. package/skills/ctf-forensics/signals-and-hardware.md +713 -0
  65. package/skills/ctf-forensics/steganography.md +694 -0
  66. package/skills/ctf-forensics/stego-advanced-2.md +475 -0
  67. package/skills/ctf-forensics/stego-advanced.md +481 -0
  68. package/skills/ctf-forensics/stego-image.md +691 -0
  69. package/skills/ctf-forensics/windows.md +625 -0
  70. package/skills/ctf-malware/SKILL.md +181 -0
  71. package/skills/ctf-malware/c2-and-protocols.md +274 -0
  72. package/skills/ctf-malware/pe-and-dotnet.md +108 -0
  73. package/skills/ctf-malware/scripts-and-obfuscation.md +449 -0
  74. package/skills/ctf-misc/SKILL.md +498 -0
  75. package/skills/ctf-misc/bashjails.md +323 -0
  76. package/skills/ctf-misc/ctfd-navigation.md +465 -0
  77. package/skills/ctf-misc/dns.md +255 -0
  78. package/skills/ctf-misc/encodings-advanced.md +504 -0
  79. package/skills/ctf-misc/encodings.md +431 -0
  80. package/skills/ctf-misc/games-and-vms-2.md +254 -0
  81. package/skills/ctf-misc/games-and-vms-3.md +690 -0
  82. package/skills/ctf-misc/games-and-vms-4.md +229 -0
  83. package/skills/ctf-misc/games-and-vms.md +529 -0
  84. package/skills/ctf-misc/linux-privesc.md +333 -0
  85. package/skills/ctf-misc/pyjails.md +671 -0
  86. package/skills/ctf-misc/rf-sdr.md +91 -0
  87. package/skills/ctf-osint/SKILL.md +198 -0
  88. package/skills/ctf-osint/geolocation-and-media.md +464 -0
  89. package/skills/ctf-osint/social-media.md +312 -0
  90. package/skills/ctf-osint/web-and-dns.md +341 -0
  91. package/skills/ctf-pwn/SKILL.md +214 -0
  92. package/skills/ctf-pwn/advanced-exploits-2.md +579 -0
  93. package/skills/ctf-pwn/advanced-exploits-3.md +598 -0
  94. package/skills/ctf-pwn/advanced-exploits-4.md +590 -0
  95. package/skills/ctf-pwn/advanced-exploits-5.md +119 -0
  96. package/skills/ctf-pwn/advanced-exploits.md +773 -0
  97. package/skills/ctf-pwn/advanced.md +326 -0
  98. package/skills/ctf-pwn/field-notes.md +245 -0
  99. package/skills/ctf-pwn/format-string.md +694 -0
  100. package/skills/ctf-pwn/heap-fsop.md +285 -0
  101. package/skills/ctf-pwn/heap-techniques-2.md +333 -0
  102. package/skills/ctf-pwn/heap-techniques.md +513 -0
  103. package/skills/ctf-pwn/kernel-bypass.md +421 -0
  104. package/skills/ctf-pwn/kernel-techniques.md +366 -0
  105. package/skills/ctf-pwn/kernel.md +636 -0
  106. package/skills/ctf-pwn/overflow-basics.md +611 -0
  107. package/skills/ctf-pwn/rop-advanced.md +725 -0
  108. package/skills/ctf-pwn/rop-and-shellcode.md +659 -0
  109. package/skills/ctf-pwn/sandbox-escape.md +313 -0
  110. package/skills/ctf-reverse/SKILL.md +163 -0
  111. package/skills/ctf-reverse/anti-analysis-ctf.md +204 -0
  112. package/skills/ctf-reverse/anti-analysis.md +693 -0
  113. package/skills/ctf-reverse/field-notes.md +376 -0
  114. package/skills/ctf-reverse/languages-compiled.md +666 -0
  115. package/skills/ctf-reverse/languages-platforms.md +592 -0
  116. package/skills/ctf-reverse/languages.md +553 -0
  117. package/skills/ctf-reverse/patterns-ctf-2.md +397 -0
  118. package/skills/ctf-reverse/patterns-ctf-3.md +797 -0
  119. package/skills/ctf-reverse/patterns-ctf.md +670 -0
  120. package/skills/ctf-reverse/patterns-runtime.md +274 -0
  121. package/skills/ctf-reverse/patterns.md +572 -0
  122. package/skills/ctf-reverse/platforms-hardware.md +387 -0
  123. package/skills/ctf-reverse/platforms.md +664 -0
  124. package/skills/ctf-reverse/tools-advanced-2.md +421 -0
  125. package/skills/ctf-reverse/tools-advanced.md +407 -0
  126. package/skills/ctf-reverse/tools-dynamic.md +679 -0
  127. package/skills/ctf-reverse/tools-emulation.md +319 -0
  128. package/skills/ctf-reverse/tools.md +573 -0
  129. package/skills/ctf-web/SKILL.md +153 -0
  130. package/skills/ctf-web/auth-and-access-2.md +82 -0
  131. package/skills/ctf-web/auth-and-access.md +783 -0
  132. package/skills/ctf-web/auth-infra.md +321 -0
  133. package/skills/ctf-web/auth-jwt.md +186 -0
  134. package/skills/ctf-web/client-side-advanced.md +739 -0
  135. package/skills/ctf-web/client-side.md +529 -0
  136. package/skills/ctf-web/cves.md +373 -0
  137. package/skills/ctf-web/field-notes.md +482 -0
  138. package/skills/ctf-web/node-and-prototype.md +200 -0
  139. package/skills/ctf-web/server-side-2.md +337 -0
  140. package/skills/ctf-web/server-side-advanced-2.md +559 -0
  141. package/skills/ctf-web/server-side-advanced-3.md +125 -0
  142. package/skills/ctf-web/server-side-advanced-4.md +480 -0
  143. package/skills/ctf-web/server-side-advanced.md +378 -0
  144. package/skills/ctf-web/server-side-deser.md +443 -0
  145. package/skills/ctf-web/server-side-exec-2.md +799 -0
  146. package/skills/ctf-web/server-side-exec.md +457 -0
  147. package/skills/ctf-web/server-side.md +629 -0
  148. package/skills/ctf-web/sql-injection.md +790 -0
  149. package/skills/ctf-web/web3.md +374 -0
  150. package/skills/ctf-writeup/SKILL.md +90 -0
  151. package/skills/solve-challenge/SKILL.md +269 -0
  152. package/skills.json +16 -0
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ CTF-Agent Distribution & Deployment Manager (v1.0)
4
+ Deploys CTF-Agent skills, rules, subagents, and scripts into any CTF competition workspace (.agents/)
5
+ or globally into Antigravity user configuration (~/.gemini/config/).
6
+ """
7
+
8
+ import os
9
+ import sys
10
+ import shutil
11
+ import argparse
12
+ import json
13
+ import hashlib
14
+ import subprocess
15
+ from pathlib import Path
16
+ from typing import Optional
17
+
18
+ # Ensure safe UTF-8 output on Windows consoles
19
+ if hasattr(sys.stdout, "reconfigure"):
20
+ try:
21
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
22
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace")
23
+ except Exception:
24
+ pass
25
+
26
+ REPO_ROOT = Path(__file__).resolve().parent.parent
27
+
28
+ ESSENTIAL_DIRS = ["skills", "rules", "agents", "scripts", "references"]
29
+ ESSENTIAL_FILES = ["AGENTS.md", "mcp_config.json", "skills.json", "README.md"]
30
+ WORKSPACE_ROOT_FILES = ["AGENTS.md", "mcp_config.json", "skills.json"]
31
+
32
+ def win_to_wsl_path(p: Path) -> str:
33
+ """Converts a Windows Path (e.g. C:\\path\\to\\dir) to a WSL path (/mnt/c/path/to/dir)."""
34
+ resolved = p.resolve()
35
+ drive = resolved.drive.rstrip(':').lower()
36
+ parts = list(resolved.parts[1:])
37
+ return f"/mnt/{drive}/" + "/".join(parts)
38
+
39
+ def install_wsl_toolchain(target_path: Path, profile: str = "core", distro: str = "kali-linux"):
40
+ """Installs CTF tools into WSL for the target workspace."""
41
+ if shutil.which("wsl") is None:
42
+ print(" [!] WSL command not available on this system. Skipping WSL toolchain installation.")
43
+ return
44
+
45
+ wsl_target = win_to_wsl_path(target_path)
46
+ script_wsl = f"{wsl_target}/.agents/scripts/install_ctf_tools.sh"
47
+
48
+ profiles = [p.strip() for p in profile.split(",") if p.strip()]
49
+
50
+ print(f"\n[*] Provisioning WSL ({distro}) CTF toolchain for workspace...")
51
+ print(f" Target Workspace : {wsl_target}")
52
+ print(f" Profiles Selected: {', '.join(profiles)}")
53
+ print(f" Installer Script : {script_wsl}")
54
+
55
+ for prof in profiles:
56
+ cmd = ["wsl", "-d", distro, "bash", "-c", f"bash '{script_wsl}' {prof}"]
57
+ try:
58
+ print(f"\n[*] Executing install_ctf_tools.sh {prof} in WSL ({distro})...")
59
+ res = subprocess.run(cmd, check=False)
60
+ if res.returncode == 0:
61
+ print(f"[OK] WSL CTF toolchain [{prof}] installed successfully!")
62
+ else:
63
+ print(f"[!] WSL CTF toolchain installer exited with code {res.returncode}")
64
+ except Exception as e:
65
+ print(f"[!] Error running WSL installer: {e}")
66
+
67
+ # Run verification
68
+ verify_cmd = ["wsl", "-d", distro, "bash", "-c", f"bash '{script_wsl}' --verify {prof}"]
69
+ try:
70
+ print(f"[*] Running toolchain verification check for [{prof}] in WSL...")
71
+ subprocess.run(verify_cmd, check=False)
72
+ except Exception as e:
73
+ print(f"[!] Error running WSL verification: {e}")
74
+
75
+ def deploy_to_workspace(
76
+ target_path: Path,
77
+ use_symlink: bool = False,
78
+ force: bool = False,
79
+ setup_workspace: bool = True,
80
+ install_wsl: bool = True,
81
+ wsl_profile: str = "core",
82
+ wsl_distro: str = "kali-linux"
83
+ ):
84
+ """Deploy CTF-Agent into target directory under .agents/, configure workspace files, and provision WSL toolchain."""
85
+ dot_agents = target_path / ".agents"
86
+ print(f"[*] Deploying CTF-Agent to workspace: {dot_agents}")
87
+
88
+ if dot_agents.exists() and not force:
89
+ print(f"[!] Warning: {dot_agents} already exists. Use --force to overwrite.")
90
+ sys.exit(1)
91
+
92
+ dot_agents.mkdir(parents=True, exist_ok=True)
93
+
94
+ for dir_name in ESSENTIAL_DIRS:
95
+ src_dir = REPO_ROOT / dir_name
96
+ dest_dir = dot_agents / dir_name
97
+
98
+ if not src_dir.exists():
99
+ continue
100
+
101
+ if dest_dir.exists():
102
+ if dest_dir.is_symlink() or (os.name == 'nt' and dest_dir.is_junction()):
103
+ dest_dir.unlink()
104
+ else:
105
+ shutil.rmtree(dest_dir)
106
+
107
+ if use_symlink:
108
+ try:
109
+ if os.name == 'nt':
110
+ import _winapi
111
+ _winapi.CreateJunction(str(src_dir), str(dest_dir))
112
+ else:
113
+ dest_dir.symlink_to(src_dir, target_is_directory=True)
114
+ print(f" [+] Linked {dir_name}/ -> {dest_dir}")
115
+ except Exception as e:
116
+ print(f" [!] Symlink/Junction failed ({e}), falling back to copy...")
117
+ shutil.copytree(src_dir, dest_dir)
118
+ print(f" [+] Copied {dir_name}/ -> {dest_dir}")
119
+ else:
120
+ shutil.copytree(src_dir, dest_dir)
121
+ print(f" [+] Copied {dir_name}/ -> {dest_dir}")
122
+
123
+ for file_name in ESSENTIAL_FILES:
124
+ src_file = REPO_ROOT / file_name
125
+ dest_file = dot_agents / file_name
126
+ if src_file.exists():
127
+ shutil.copy2(src_file, dest_file)
128
+ print(f" [+] Copied {file_name} -> {dest_file}")
129
+
130
+ if setup_workspace:
131
+ print(f"\n[*] Configuring workspace root settings at {target_path}...")
132
+ for file_name in WORKSPACE_ROOT_FILES:
133
+ src_file = REPO_ROOT / file_name
134
+ dest_file = target_path / file_name
135
+ if src_file.exists():
136
+ if file_name == "AGENTS.md" and target_path != REPO_ROOT:
137
+ content = src_file.read_text(encoding="utf-8")
138
+ content = content.replace("](references/", "](.agents/references/")
139
+ content = content.replace("](rules/", "](.agents/rules/")
140
+ dest_file.write_text(content, encoding="utf-8")
141
+ else:
142
+ shutil.copy2(src_file, dest_file)
143
+ print(f" [+] Configured workspace root: {dest_file}")
144
+
145
+ # Synchronize scripts into workspace scripts/ if directory exists
146
+ ws_scripts = target_path / "scripts"
147
+ if ws_scripts.is_dir():
148
+ src_scripts = REPO_ROOT / "scripts"
149
+ for s_file in src_scripts.iterdir():
150
+ if s_file.is_file():
151
+ shutil.copy2(s_file, ws_scripts / s_file.name)
152
+ print(f" [+] Synchronized all scripts -> {ws_scripts}")
153
+
154
+ # Generate skills-lock.json with computed hashes of local skills
155
+ skills_lock = {"version": 1, "skills": {}}
156
+ skills_dir = dot_agents / "skills"
157
+ if skills_dir.exists():
158
+ for skill_path in sorted(skills_dir.iterdir()):
159
+ if skill_path.is_dir():
160
+ skill_md = skill_path / "SKILL.md"
161
+ if skill_md.exists():
162
+ h = hashlib.sha256(skill_md.read_bytes()).hexdigest()
163
+ skills_lock["skills"][skill_path.name] = {
164
+ "source": "CTF-Agent (local)",
165
+ "sourceType": "local",
166
+ "skillPath": f".agents/skills/{skill_path.name}/SKILL.md",
167
+ "computedHash": h
168
+ }
169
+ skills_lock_file = target_path / "skills-lock.json"
170
+ skills_lock_file.write_text(json.dumps(skills_lock, indent=2), encoding="utf-8")
171
+ print(f" [+] Generated {skills_lock_file}")
172
+
173
+ # Provision CTF toolchain into WSL
174
+ if install_wsl and os.name == 'nt':
175
+ install_wsl_toolchain(target_path, profile=wsl_profile, distro=wsl_distro)
176
+
177
+ print(f"\n[OK] Successfully deployed CTF-Agent into {dot_agents}!")
178
+ print(f" Available Subagents:")
179
+ print(f" - @ctf-controller : Master Orchestrator (SCO/TE context, refusal routing, deterministic fallback)")
180
+ print(f" - @ctf-speedrun : Ultra-fast Blitz mode (Stop-on-Flag, zero doc overhead, auto-clean)")
181
+ print(f" - @ctf-analyzer : In-depth Lab/Audit mode (Full RCA, resources/ preservation, writeup.md)")
182
+
183
+ def deploy_globally(force: bool = False):
184
+ """Deploy skills, rules, and subagents into ~/.gemini/config/ for global availability."""
185
+ home = Path.home()
186
+ global_config = home / ".gemini" / "config"
187
+ print(f"[*] Deploying CTF-Agent globally to: {global_config}")
188
+
189
+ if not global_config.exists():
190
+ global_config.mkdir(parents=True, exist_ok=True)
191
+
192
+ # 1. Deploy Skills
193
+ global_skills = global_config / "skills"
194
+ global_skills.mkdir(exist_ok=True)
195
+ for skill_path in (REPO_ROOT / "skills").iterdir():
196
+ if skill_path.is_dir():
197
+ dest = global_skills / skill_path.name
198
+ if dest.exists() and force:
199
+ shutil.rmtree(dest)
200
+ if not dest.exists():
201
+ shutil.copytree(skill_path, dest)
202
+ print(f" [+] Deployed skill: {skill_path.name}")
203
+
204
+ # 2. Deploy Agents
205
+ global_agents = global_config / "agents"
206
+ global_agents.mkdir(exist_ok=True)
207
+ for agent_path in (REPO_ROOT / "agents").iterdir():
208
+ if agent_path.is_file() and agent_path.suffix == ".md":
209
+ dest = global_agents / agent_path.name
210
+ shutil.copy2(agent_path, dest)
211
+ print(f" [+] Deployed agent: {agent_path.name}")
212
+
213
+ # 3. Deploy Rules
214
+ global_rules = global_config / "rules"
215
+ global_rules.mkdir(exist_ok=True)
216
+ for rule_path in (REPO_ROOT / "rules").iterdir():
217
+ if rule_path.is_file() and rule_path.suffix == ".md":
218
+ dest = global_rules / rule_path.name
219
+ shutil.copy2(rule_path, dest)
220
+ print(f" [+] Deployed rule: {rule_path.name}")
221
+
222
+ print(f"\n[OK] Successfully installed CTF-Agent globally across all Antigravity workspaces!")
223
+
224
+ def main():
225
+ if len(sys.argv) > 1 and sys.argv[1] in ("init", "--init"):
226
+ import ctf_init
227
+ sys.argv = [sys.argv[0]] + sys.argv[2:]
228
+ ctf_init.main()
229
+ return
230
+
231
+ if len(sys.argv) > 1 and sys.argv[1] in ("update", "--update"):
232
+ import ctf_update
233
+ sys.argv = [sys.argv[0]] + sys.argv[2:]
234
+ ctf_update.main()
235
+ return
236
+
237
+ parser = argparse.ArgumentParser(description="CTF-Agent Workspace & Global Deployment Manager")
238
+ parser.add_argument("target", nargs="?", help="Target CTF workspace directory (deploys as .agents/)")
239
+ parser.add_argument("--global", dest="is_global", action="store_true", help="Install CTF skills, rules, and subagents globally into ~/.gemini/config/")
240
+ parser.add_argument("--symlink", "--link", action="store_true", help="Use symlinks/junctions for workspace deployment to keep live sync")
241
+ parser.add_argument("--setup-workspace", dest="setup_workspace", action="store_true", default=True, help="Configure workspace root AGENTS.md, mcp_config.json, skills.json (default: True)")
242
+ parser.add_argument("--no-setup-workspace", dest="setup_workspace", action="store_false", help="Only deploy .agents/ without modifying workspace root files")
243
+ parser.add_argument("--wsl", dest="install_wsl", action="store_true", default=True, help="Automatically install CTF toolchain into WSL during setup (default: True)")
244
+ parser.add_argument("--no-wsl", "--skip-toolchain", dest="install_wsl", action="store_false", help="Skip toolchain installation into backend")
245
+ parser.add_argument("--wsl-profile", default="core", help="WSL toolchain profile to install: core, pwn, rev, crypto, forensics, web, all (default: core)")
246
+ parser.add_argument("--wsl-distro", default="kali-linux", help="WSL distribution target (default: kali-linux)")
247
+ parser.add_argument("--init", dest="is_init", action="store_true", help="Run intelligent preflight detector & workspace initializer")
248
+ parser.add_argument("--update", dest="is_update", action="store_true", help="Run workspace & skill update engine")
249
+ parser.add_argument("--force", "-f", action="store_true", help="Overwrite existing files or directories")
250
+
251
+ args = parser.parse_args()
252
+
253
+ if args.is_update:
254
+ import ctf_update
255
+ workspace = ctf_update.WorkspaceUpdater.resolve_workspace(args.target)
256
+ res = ctf_update.WorkspaceUpdater.update_workspace(workspace, force=args.force)
257
+ ctf_update.print_update_report(res)
258
+ return
259
+
260
+ if args.is_global:
261
+ deploy_globally(force=args.force)
262
+ elif args.target:
263
+ target_dir = Path(args.target).resolve()
264
+ deploy_to_workspace(
265
+ target_dir,
266
+ use_symlink=args.symlink,
267
+ force=args.force,
268
+ setup_workspace=args.setup_workspace,
269
+ install_wsl=args.install_wsl,
270
+ wsl_profile=args.wsl_profile,
271
+ wsl_distro=args.wsl_distro
272
+ )
273
+ else:
274
+ parser.print_help()
275
+ sys.exit(1)
276
+
277
+ if __name__ == "__main__":
278
+ main()