@hupan56/wlkj 3.3.13 → 3.3.15

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 (54) hide show
  1. package/bin/cli.js +0 -7
  2. package/package.json +29 -29
  3. package/templates/qoder/commands/optional/wl-spec.md +0 -8
  4. package/templates/qoder/commands/optional/wl-status.md +0 -8
  5. package/templates/qoder/commands/wl-code.md +0 -8
  6. package/templates/qoder/commands/wl-commit.md +0 -8
  7. package/templates/qoder/commands/wl-init.md +129 -129
  8. package/templates/qoder/commands/wl-search.md +0 -8
  9. package/templates/qoder/commands/wl-task.md +0 -8
  10. package/templates/qoder/commands/wl-test.md +0 -8
  11. package/templates/qoder/config.yaml +2 -3
  12. package/templates/qoder/contracts/insight.md +55 -55
  13. package/templates/qoder/hooks/pre-tool-use-commit.py +124 -124
  14. package/templates/qoder/hooks/session-start.py +384 -384
  15. package/templates/qoder/hooks/stop-eval.py +383 -383
  16. package/templates/qoder/scripts/capability/adapters/mcp.py +322 -322
  17. package/templates/qoder/scripts/capability/registry.py +245 -245
  18. package/templates/qoder/scripts/deployment/setup/install_qoderwork.py +14 -0
  19. package/templates/qoder/scripts/deployment/setup/setup.py +0 -11
  20. package/templates/qoder/scripts/domain/task/wlkj_panel.py +1503 -1503
  21. package/templates/qoder/scripts/foundation/bootstrap.py +145 -156
  22. package/templates/qoder/scripts/foundation/io/context_cache.py +94 -94
  23. package/templates/qoder/scripts/orchestration/wlkj.py +295 -306
  24. package/templates/qoder/scripts/tool_guide.md +70 -70
  25. package/templates/qoder/scripts/validation/eval/alignment_matrix.py +176 -176
  26. package/templates/qoder/scripts/validation/eval/bf2_content_fidelity.py +110 -110
  27. package/templates/qoder/scripts/validation/eval/bf2_llmjudge.py +104 -104
  28. package/templates/qoder/scripts/validation/eval/bf_score.py +218 -218
  29. package/templates/qoder/scripts/validation/eval/code_flywheel.py +150 -150
  30. package/templates/qoder/scripts/validation/eval/dispatcher_ab.py +156 -156
  31. package/templates/qoder/scripts/validation/eval/dispatcher_ab_2026-07-21.json +23 -23
  32. package/templates/qoder/scripts/validation/eval/feature_fidelity_flywheel.py +143 -143
  33. package/templates/qoder/scripts/validation/eval/gradient_matrix.py +261 -261
  34. package/templates/qoder/scripts/validation/eval/gradient_matrix_baseline_2026-07-21.json +33 -33
  35. package/templates/qoder/scripts/validation/eval/metrics_dashboard.py +105 -105
  36. package/templates/qoder/scripts/validation/eval/multi_turn_flywheel.py +118 -118
  37. package/templates/qoder/scripts/validation/eval/prd_fidelity_flywheel.py +128 -128
  38. package/templates/qoder/scripts/validation/eval/prd_flywheel.py +148 -148
  39. package/templates/qoder/scripts/validation/eval/prototype_fidelity_flywheel.py +166 -166
  40. package/templates/qoder/scripts/validation/eval/recall_flywheel.py +148 -148
  41. package/templates/qoder/scripts/validation/eval/robustness_flywheel.py +139 -139
  42. package/templates/qoder/scripts/validation/eval/speed_accuracy_flywheel.py +188 -188
  43. package/templates/qoder/scripts/validation/eval/task_flywheel.py +124 -124
  44. package/templates/qoder/scripts/validation/eval/token_flywheel.py +88 -88
  45. package/templates/qoder/scripts/validation/metrics/eval_code_ac.py +177 -177
  46. package/templates/qoder/scripts/validation/metrics/lint_cases.py +170 -170
  47. package/templates/qoder/scripts/validation/test/test_context_cache.py +78 -78
  48. package/templates/qoder/scripts/validation/test/test_lint_cases.py +60 -60
  49. package/templates/qoder/scripts/validation/test/test_pre_tool_use_commit.py +70 -70
  50. package/templates/qoder/commands/wl-data.md +0 -46
  51. package/templates/qoder/commands/wl-fix.md +0 -47
  52. package/templates/qoder/commands/wl-knowledge.md +0 -41
  53. package/templates/qoder/commands/wl-review.md +0 -49
  54. package/templates/workspace/specs/REQ-TEST-CTX/.context-cache.json +0 -1
@@ -1,23 +1,23 @@
1
- {
2
- "task": "T1.1 mode dispatcher 确定性路由 (wl-search)",
3
- "date": "2026-07-21",
4
- "ruler": "scripts/validation/eval/dispatcher_ab.py",
5
- "env": "云 10.89.7.120, DashScope turbo/plus/max, 14 gold 查询(7通道x2)",
6
- "change": "wl-search '第一步:先判断问题类型'(纯LLM猜测) -> '确定性路由(按顺序首匹配信号,零猜测)' 7行表+默认rag_search; sync packages->.qoder diff空",
7
- "matrix": {
8
- "weak": {"old_acc": 0.857, "new_acc": 1.0, "gain_pp": 14.3},
9
- "mid": {"old_acc": 0.857, "new_acc": 1.0, "gain_pp": 14.3},
10
- "strong": {"old_acc": 0.857, "new_acc": 1.0, "gain_pp": 14.3}
11
- },
12
- "old_failures": [
13
- "status 字段有哪些枚举值 -> gold=db, got=rag_search (旧表 db 只在括号注)",
14
- "盘点考勤有哪些代码和字段 -> gold=context_pack, got=rag_search (旧表'盘点'非明确信号)"
15
- ],
16
- "insight": "三档同错同对(2错全修)再次印证 T1.0: 结构好时弱模型=强模型; dispatcher 价值在表结构非模型档位",
17
- "honest_caveats": [
18
- "gold 仅14条 + 作者同时写 gold 和新表, 有小样本/作者重叠风险(新表可能贴 gold)",
19
- "2 修复项(枚举->db/盘点->context_pack)确为旧表缺新表补的显式信号, 改进真实",
20
- "🖥️ 宿主端到端(弱模型跑真/wl-search 是否真按表走) 待用户验"
21
- ],
22
- "status": "代码改+sync+自验A/B完成; 🖥️宿主端到端列入 §12 V1.2"
23
- }
1
+ {
2
+ "task": "T1.1 mode dispatcher 确定性路由 (wl-search)",
3
+ "date": "2026-07-21",
4
+ "ruler": "scripts/validation/eval/dispatcher_ab.py",
5
+ "env": "云 10.89.7.120, DashScope turbo/plus/max, 14 gold 查询(7通道x2)",
6
+ "change": "wl-search '第一步:先判断问题类型'(纯LLM猜测) -> '确定性路由(按顺序首匹配信号,零猜测)' 7行表+默认rag_search; sync packages->.qoder diff空",
7
+ "matrix": {
8
+ "weak": {"old_acc": 0.857, "new_acc": 1.0, "gain_pp": 14.3},
9
+ "mid": {"old_acc": 0.857, "new_acc": 1.0, "gain_pp": 14.3},
10
+ "strong": {"old_acc": 0.857, "new_acc": 1.0, "gain_pp": 14.3}
11
+ },
12
+ "old_failures": [
13
+ "status 字段有哪些枚举值 -> gold=db, got=rag_search (旧表 db 只在括号注)",
14
+ "盘点考勤有哪些代码和字段 -> gold=context_pack, got=rag_search (旧表'盘点'非明确信号)"
15
+ ],
16
+ "insight": "三档同错同对(2错全修)再次印证 T1.0: 结构好时弱模型=强模型; dispatcher 价值在表结构非模型档位",
17
+ "honest_caveats": [
18
+ "gold 仅14条 + 作者同时写 gold 和新表, 有小样本/作者重叠风险(新表可能贴 gold)",
19
+ "2 修复项(枚举->db/盘点->context_pack)确为旧表缺新表补的显式信号, 改进真实",
20
+ "🖥️ 宿主端到端(弱模型跑真/wl-search 是否真按表走) 待用户验"
21
+ ],
22
+ "status": "代码改+sync+自验A/B完成; 🖥️宿主端到端列入 §12 V1.2"
23
+ }
@@ -1,143 +1,143 @@
1
- """feature_fidelity_flywheel.py — FW10 BF5/BF6 feature-scoped 业务保真飞轮。
2
-
3
- 关键:precision 改成 vs【该 feature 真业务实体集】(非任意真实体)。
4
- 之前 code/search 量"列出的是不是真实体"(可列真但不相关的实体也得分)→ 业务保真虚高。
5
- BF5/BF6 量"列出的是不是【这个 feature 的】真实体"——真业务相关,非泛实体。
6
- - BF6 search feature相关率 = 返回实体 ∈ feature_gold / 返回总数
7
- - BF5 code feature精准 = 改实体 ∈ feature_gold / 改总数
8
- bare(无接地→泛/编造) vs +该feature gold接地。
9
-
10
- 跑法: docker exec -i wlinkj-workspace-backend-1 python /app/scripts/validation/eval/feature_fidelity_flywheel.py
11
- """
12
- import os
13
- import re
14
- import sys
15
- import json
16
- import time
17
- import urllib.request
18
- import urllib.error
19
-
20
- for _p in ("/app", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))):
21
- if os.path.isdir(_p) and _p not in sys.path:
22
- sys.path.insert(0, _p)
23
-
24
- from sqlalchemy import text # noqa: E402
25
- from app.db import SessionLocal # noqa: E402
26
-
27
- CHAT_URL = os.environ.get("ALI_CHAT_BASE", "").rstrip("/") + "/chat/completions"
28
- CHAT_KEY = os.environ.get("DASHSCOPE_API_KEY", "")
29
- MODEL = "qwen-turbo"
30
- FEATURES = [("车辆保险管理", "保险"), ("异常记录管理", "异常"), ("合同维护", "合同")]
31
- _LINE_CLEAN = re.compile(r"^[\-\*\d\.\)、\s]+")
32
- _TOK = re.compile(r"[A-Za-z_][\w./\-:]{2,}")
33
-
34
-
35
- def chat(prompt, max_tokens=400, timeout=80):
36
- body = json.dumps({"model": MODEL,
37
- "messages": [{"role": "system", "content": "你是车辆物联网系统(ICS)助手,只答真实存在的对象。"},
38
- {"role": "user", "content": prompt}], "temperature": 0.0, "max_tokens": max_tokens}).encode()
39
- for a in range(3):
40
- try:
41
- req = urllib.request.Request(CHAT_URL, data=body,
42
- headers={"Authorization": f"Bearer {CHAT_KEY}", "Content-Type": "application/json"})
43
- return json.loads(urllib.request.urlopen(req, timeout=timeout).read())["choices"][0]["message"]["content"]
44
- except (urllib.error.URLError, TimeoutError, OSError, KeyError) as e:
45
- if a < 2: time.sleep(1.0*(a+1))
46
- else: return ""
47
-
48
-
49
- def _q(s, sql, p=None):
50
- try: return s.execute(text(sql), p or {}).fetchall()
51
- except Exception:
52
- try: s.rollback()
53
- except Exception: pass
54
- return []
55
-
56
-
57
- def feature_gold(theme, k=20):
58
- """该 feature 的真业务实体集(BF5/BF6 的 gold)。"""
59
- s = SessionLocal()
60
- rows = _q(s, "SELECT canonical, cn FROM entities WHERE (canonical ILIKE :p OR cn ILIKE :p) "
61
- "AND type IN ('CONTROLLER','SERVICE','TABLE','COLUMN','FUNCTION') LIMIT :n",
62
- {"p": f"%{theme}%", "n": k})
63
- s.close()
64
- return [(c, n) for c, n in rows if c]
65
-
66
-
67
- def extract_names(ans):
68
- out = set()
69
- for line in ans.splitlines():
70
- line = _LINE_CLEAN.sub("", line).strip()
71
- if line and len(line) <= 60:
72
- m = _TOK.findall(line)
73
- if m: out.add(m[0])
74
- return out
75
-
76
-
77
- def feature_precision(ans, gold):
78
- """feature 保真:列出的 ∈ 该feature gold 比例(非任意真实体)。"""
79
- cands = extract_names(ans)
80
- if not cands: return 0.0, 0
81
- gold_canon = {c for c, _ in gold}
82
- hit = sum(1 for c in cands if c in gold_canon)
83
- # 也算 cn 命中(ans 文本含 gold cn)
84
- # precision = 命中gold的候选 / 总候选
85
- feat_hit = 0
86
- for c in cands:
87
- if c in gold_canon:
88
- feat_hit += 1
89
- return round(feat_hit / len(cands), 3), len(cands)
90
-
91
-
92
- def run():
93
- rep = {"features": []}
94
- for feat, theme in FEATURES:
95
- gold = feature_gold(theme, 20)
96
- gold_ctx = "\n".join("%s (%s)" % (c, n) for c, n in gold) or "(无)"
97
- # BF6 search
98
- b_search = chat(f"找 ICS 系统「{feat}」相关的具体对象(类/表/字段/接口),逐行列出,勿编造。")
99
- s_search = chat(f"找 ICS 系统「{feat}」相关对象。知识图谱检索到(均真实):\n{gold_ctx}\n请把检索结果实体全部逐行列出,直接用名称,勿编造。")
100
- bP_s, bN_s = feature_precision(b_search, gold)
101
- sP_s, sN_s = feature_precision(s_search, gold)
102
- # BF5 code
103
- b_code = chat(f"给「{feat}」加功能,逐行列出需修改的代码类/方法名,勿编造。")
104
- s_code = chat(f"给「{feat}」加功能。get_impact 检索到真实实体:\n{gold_ctx}\n请把检索结果实体全部逐行列出,直接用名称,勿编造。")
105
- bP_c, bN_c = feature_precision(b_code, gold)
106
- sP_c, sN_c = feature_precision(s_code, gold)
107
- rep["features"].append({"feature": feat, "gold_n": len(gold),
108
- "BF6_bare": bP_s, "BF6_scaffold": sP_s,
109
- "BF5_bare": bP_c, "BF5_scaffold": sP_c})
110
- print(" %s(gold=%d): BF6 search 相关率 bare=%.0f%%→scaff=%.0f%% | BF5 code 精准 bare=%.0f%%→scaff=%.0f%%" % (
111
- feat, len(gold), bP_s*100, sP_s*100, bP_c*100, sP_c*100))
112
- n = len(FEATURES) or 1
113
- rep["agg"] = {
114
- "BF6_bare": round(sum(f["BF6_bare"] for f in rep["features"])/n, 3),
115
- "BF6_scaffold": round(sum(f["BF6_scaffold"] for f in rep["features"])/n, 3),
116
- "BF5_bare": round(sum(f["BF5_bare"] for f in rep["features"])/n, 3),
117
- "BF5_scaffold": round(sum(f["BF5_scaffold"] for f in rep["features"])/n, 3),
118
- }
119
- return rep
120
-
121
-
122
- def main():
123
- import argparse
124
- ap = argparse.ArgumentParser()
125
- ap.add_argument("--json", action="store_true")
126
- args = ap.parse_args()
127
- r = run()
128
- a = r["agg"]
129
- if args.json:
130
- print(json.dumps(r, ensure_ascii=False, indent=2))
131
- return
132
- print("\n## FW10 BF5/BF6 feature-scoped 业务保真飞轮(列的是【该feature】真实体,非任意真实体)")
133
- print("| 指标 | bare | +该feature gold接地 | 目标 |")
134
- print("|---|---|---|---|")
135
- print("| BF6 search feature相关率 | %.0f%% | %.0f%% | ≥85%% |" % (a["BF6_bare"]*100, a["BF6_scaffold"]*100))
136
- print("| BF5 code feature精准 | %.0f%% | %.0f%% | ≥85%% |" % (a["BF5_bare"]*100, a["BF5_scaffold"]*100))
137
- b6 = a["BF6_scaffold"] >= 0.85; b5 = a["BF5_scaffold"] >= 0.85
138
- print("\nBF6达标?" , "✓" if b6 else "✗", "| BF5达标?", "✓" if b5 else "✗",
139
- "| 不达标续转(更强feature接地/拒非feature实体)")
140
-
141
-
142
- if __name__ == "__main__":
143
- main()
1
+ """feature_fidelity_flywheel.py — FW10 BF5/BF6 feature-scoped 业务保真飞轮。
2
+
3
+ 关键:precision 改成 vs【该 feature 真业务实体集】(非任意真实体)。
4
+ 之前 code/search 量"列出的是不是真实体"(可列真但不相关的实体也得分)→ 业务保真虚高。
5
+ BF5/BF6 量"列出的是不是【这个 feature 的】真实体"——真业务相关,非泛实体。
6
+ - BF6 search feature相关率 = 返回实体 ∈ feature_gold / 返回总数
7
+ - BF5 code feature精准 = 改实体 ∈ feature_gold / 改总数
8
+ bare(无接地→泛/编造) vs +该feature gold接地。
9
+
10
+ 跑法: docker exec -i wlinkj-workspace-backend-1 python /app/scripts/validation/eval/feature_fidelity_flywheel.py
11
+ """
12
+ import os
13
+ import re
14
+ import sys
15
+ import json
16
+ import time
17
+ import urllib.request
18
+ import urllib.error
19
+
20
+ for _p in ("/app", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))):
21
+ if os.path.isdir(_p) and _p not in sys.path:
22
+ sys.path.insert(0, _p)
23
+
24
+ from sqlalchemy import text # noqa: E402
25
+ from app.db import SessionLocal # noqa: E402
26
+
27
+ CHAT_URL = os.environ.get("ALI_CHAT_BASE", "").rstrip("/") + "/chat/completions"
28
+ CHAT_KEY = os.environ.get("DASHSCOPE_API_KEY", "")
29
+ MODEL = "qwen-turbo"
30
+ FEATURES = [("车辆保险管理", "保险"), ("异常记录管理", "异常"), ("合同维护", "合同")]
31
+ _LINE_CLEAN = re.compile(r"^[\-\*\d\.\)、\s]+")
32
+ _TOK = re.compile(r"[A-Za-z_][\w./\-:]{2,}")
33
+
34
+
35
+ def chat(prompt, max_tokens=400, timeout=80):
36
+ body = json.dumps({"model": MODEL,
37
+ "messages": [{"role": "system", "content": "你是车辆物联网系统(ICS)助手,只答真实存在的对象。"},
38
+ {"role": "user", "content": prompt}], "temperature": 0.0, "max_tokens": max_tokens}).encode()
39
+ for a in range(3):
40
+ try:
41
+ req = urllib.request.Request(CHAT_URL, data=body,
42
+ headers={"Authorization": f"Bearer {CHAT_KEY}", "Content-Type": "application/json"})
43
+ return json.loads(urllib.request.urlopen(req, timeout=timeout).read())["choices"][0]["message"]["content"]
44
+ except (urllib.error.URLError, TimeoutError, OSError, KeyError) as e:
45
+ if a < 2: time.sleep(1.0*(a+1))
46
+ else: return ""
47
+
48
+
49
+ def _q(s, sql, p=None):
50
+ try: return s.execute(text(sql), p or {}).fetchall()
51
+ except Exception:
52
+ try: s.rollback()
53
+ except Exception: pass
54
+ return []
55
+
56
+
57
+ def feature_gold(theme, k=20):
58
+ """该 feature 的真业务实体集(BF5/BF6 的 gold)。"""
59
+ s = SessionLocal()
60
+ rows = _q(s, "SELECT canonical, cn FROM entities WHERE (canonical ILIKE :p OR cn ILIKE :p) "
61
+ "AND type IN ('CONTROLLER','SERVICE','TABLE','COLUMN','FUNCTION') LIMIT :n",
62
+ {"p": f"%{theme}%", "n": k})
63
+ s.close()
64
+ return [(c, n) for c, n in rows if c]
65
+
66
+
67
+ def extract_names(ans):
68
+ out = set()
69
+ for line in ans.splitlines():
70
+ line = _LINE_CLEAN.sub("", line).strip()
71
+ if line and len(line) <= 60:
72
+ m = _TOK.findall(line)
73
+ if m: out.add(m[0])
74
+ return out
75
+
76
+
77
+ def feature_precision(ans, gold):
78
+ """feature 保真:列出的 ∈ 该feature gold 比例(非任意真实体)。"""
79
+ cands = extract_names(ans)
80
+ if not cands: return 0.0, 0
81
+ gold_canon = {c for c, _ in gold}
82
+ hit = sum(1 for c in cands if c in gold_canon)
83
+ # 也算 cn 命中(ans 文本含 gold cn)
84
+ # precision = 命中gold的候选 / 总候选
85
+ feat_hit = 0
86
+ for c in cands:
87
+ if c in gold_canon:
88
+ feat_hit += 1
89
+ return round(feat_hit / len(cands), 3), len(cands)
90
+
91
+
92
+ def run():
93
+ rep = {"features": []}
94
+ for feat, theme in FEATURES:
95
+ gold = feature_gold(theme, 20)
96
+ gold_ctx = "\n".join("%s (%s)" % (c, n) for c, n in gold) or "(无)"
97
+ # BF6 search
98
+ b_search = chat(f"找 ICS 系统「{feat}」相关的具体对象(类/表/字段/接口),逐行列出,勿编造。")
99
+ s_search = chat(f"找 ICS 系统「{feat}」相关对象。知识图谱检索到(均真实):\n{gold_ctx}\n请把检索结果实体全部逐行列出,直接用名称,勿编造。")
100
+ bP_s, bN_s = feature_precision(b_search, gold)
101
+ sP_s, sN_s = feature_precision(s_search, gold)
102
+ # BF5 code
103
+ b_code = chat(f"给「{feat}」加功能,逐行列出需修改的代码类/方法名,勿编造。")
104
+ s_code = chat(f"给「{feat}」加功能。get_impact 检索到真实实体:\n{gold_ctx}\n请把检索结果实体全部逐行列出,直接用名称,勿编造。")
105
+ bP_c, bN_c = feature_precision(b_code, gold)
106
+ sP_c, sN_c = feature_precision(s_code, gold)
107
+ rep["features"].append({"feature": feat, "gold_n": len(gold),
108
+ "BF6_bare": bP_s, "BF6_scaffold": sP_s,
109
+ "BF5_bare": bP_c, "BF5_scaffold": sP_c})
110
+ print(" %s(gold=%d): BF6 search 相关率 bare=%.0f%%→scaff=%.0f%% | BF5 code 精准 bare=%.0f%%→scaff=%.0f%%" % (
111
+ feat, len(gold), bP_s*100, sP_s*100, bP_c*100, sP_c*100))
112
+ n = len(FEATURES) or 1
113
+ rep["agg"] = {
114
+ "BF6_bare": round(sum(f["BF6_bare"] for f in rep["features"])/n, 3),
115
+ "BF6_scaffold": round(sum(f["BF6_scaffold"] for f in rep["features"])/n, 3),
116
+ "BF5_bare": round(sum(f["BF5_bare"] for f in rep["features"])/n, 3),
117
+ "BF5_scaffold": round(sum(f["BF5_scaffold"] for f in rep["features"])/n, 3),
118
+ }
119
+ return rep
120
+
121
+
122
+ def main():
123
+ import argparse
124
+ ap = argparse.ArgumentParser()
125
+ ap.add_argument("--json", action="store_true")
126
+ args = ap.parse_args()
127
+ r = run()
128
+ a = r["agg"]
129
+ if args.json:
130
+ print(json.dumps(r, ensure_ascii=False, indent=2))
131
+ return
132
+ print("\n## FW10 BF5/BF6 feature-scoped 业务保真飞轮(列的是【该feature】真实体,非任意真实体)")
133
+ print("| 指标 | bare | +该feature gold接地 | 目标 |")
134
+ print("|---|---|---|---|")
135
+ print("| BF6 search feature相关率 | %.0f%% | %.0f%% | ≥85%% |" % (a["BF6_bare"]*100, a["BF6_scaffold"]*100))
136
+ print("| BF5 code feature精准 | %.0f%% | %.0f%% | ≥85%% |" % (a["BF5_bare"]*100, a["BF5_scaffold"]*100))
137
+ b6 = a["BF6_scaffold"] >= 0.85; b5 = a["BF5_scaffold"] >= 0.85
138
+ print("\nBF6达标?" , "✓" if b6 else "✗", "| BF5达标?", "✓" if b5 else "✗",
139
+ "| 不达标续转(更强feature接地/拒非feature实体)")
140
+
141
+
142
+ if __name__ == "__main__":
143
+ main()