deel-local-cli 1.20.12 → 2.0.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.
- package/README.ko.md +96 -77
- package/README.md +119 -80
- package/bin/deel.js +398 -32
- package/package.json +2 -1
- package/src/acp/jsonrpc.js +87 -7
- package/src/acp/map.js +62 -13
- package/src/acp/serve.js +338 -30
- package/src/agent/agents.js +110 -12
- package/src/agent/askcheck.js +50 -6
- package/src/agent/asks.js +59 -5
- package/src/agent/budget.js +9 -2
- package/src/agent/card.js +8 -2
- package/src/agent/commit.js +168 -16
- package/src/agent/compact.js +93 -21
- package/src/agent/{/354/213/240/353/242/260/353/217/204.js → confidence.js} +1 -1
- package/src/agent/effort.js +85 -15
- package/src/agent/evidence.js +63 -7
- package/src/agent/evolve.js +132 -24
- package/src/agent/grade.js +12 -3
- package/src/agent/loop.js +408 -81
- package/src/agent/memory.js +176 -29
- package/src/agent/mention.js +22 -5
- package/src/agent/models.js +31 -7
- package/src/agent/modes.js +25 -10
- package/src/agent/outschema.js +381 -56
- package/src/agent/pins.js +33 -2
- package/src/agent/project.js +73 -8
- package/src/agent/recall.js +40 -9
- package/src/agent/{/354/204/261/355/225/234/352/270/260/353/241/235.js → recordshape.js} +19 -8
- package/src/agent/review.js +143 -13
- package/src/agent/route.js +506 -32
- package/src/agent/salvage.js +2 -1
- package/src/agent/session.js +457 -31
- package/src/agent/store.js +232 -22
- package/src/agent/threads.js +52 -3
- package/src/backend/adapter.js +508 -85
- package/src/backend/azure.js +12 -1
- package/src/backend/cachemark.js +31 -5
- package/src/backend/clientcert.js +23 -1
- package/src/backend/ctxsize.js +56 -9
- package/src/backend/detect.js +252 -19
- package/src/backend/http.js +383 -42
- package/src/backend/learn.js +101 -11
- package/src/backend/mcp.js +333 -24
- package/src/backend/price.js +61 -13
- package/src/backend/probe.js +188 -36
- package/src/backend/proxy.js +108 -14
- package/src/backend/quota.js +226 -30
- package/src/backend/retry.js +46 -3
- package/src/backend/scan.js +47 -10
- package/src/backend/scanui.js +57 -7
- package/src/backend/toolfit.js +204 -22
- package/src/backend/vision.js +14 -1
- package/src/backend/wire.js +58 -10
- package/src/cmdnames.js +16 -0
- package/src/commands/common.js +70 -0
- package/src/commands/extend.js +300 -0
- package/src/commands/model.js +852 -0
- package/src/commands/view.js +328 -0
- package/src/commands/work.js +823 -0
- package/src/commands.js +193 -2082
- package/src/completion.js +45 -3
- package/src/config.js +452 -39
- package/src/configexplain.js +125 -14
- package/src/doctor.js +164 -26
- package/src/i18n/en.js +22 -0
- package/src/i18n/index.js +31 -1
- package/src/i18n/ja.js +25 -1
- package/src/i18n/ko.js +25 -2
- package/src/i18n/zh.js +25 -1
- package/src/lsp/client.js +111 -9
- package/src/lsp/servers.js +86 -22
- package/src/oneshot.js +325 -65
- package/src/pack/sbom.js +28 -5
- package/src/pack/selfpack.js +54 -5
- package/src/pack/sheet.en.js +24 -3
- package/src/pack/tar.js +45 -8
- package/src/pack/zip.js +103 -8
- package/src/plugins/manage.js +165 -14
- package/src/preview/serve.js +239 -23
- package/src/providers/bedrock.js +30 -5
- package/src/providers/gemini.js +8 -0
- package/src/providers/index.js +17 -1
- package/src/repl.js +254 -61
- package/src/report.js +7 -2
- package/src/reset.js +151 -25
- package/src/safety/audit.js +108 -8
- package/src/safety/authcmd.js +75 -5
- package/src/safety/guard.js +507 -15
- package/src/safety/hooks.js +172 -20
- package/src/safety/keystore.js +178 -18
- package/src/safety/network.js +209 -6
- package/src/safety/policy.js +377 -36
- package/src/safety/runmode.js +9 -2
- package/src/safety/secrets.js +243 -17
- package/src/safety/shellenv.js +64 -3
- package/src/safety/trust.js +298 -32
- package/src/safety/undo.js +409 -17
- package/src/setup.js +175 -17
- package/src/skills/discover.js +122 -19
- package/src/stats.js +57 -16
- package/src/tools/{/355/231/225/354/235/270/353/262/225.js → checkmethods.js} +26 -1
- package/src/tools/clipboard.js +53 -20
- package/src/tools/convert.js +118 -37
- package/src/tools/desc.en.js +48 -5
- package/src/tools/doc2md.js +11 -1
- package/src/tools/docs.js +94 -18
- package/src/tools/edit-match.js +212 -13
- package/src/tools/encoding.js +525 -28
- package/src/tools/excel-com.js +63 -15
- package/src/tools/excel.js +12 -7
- package/src/tools/fastgrep.js +444 -36
- package/src/tools/fig.js +40 -9
- package/src/tools/fsutil.js +235 -21
- package/src/tools/hwpxwrite.js +80 -19
- package/src/tools/ignore.js +55 -7
- package/src/tools/index.js +1029 -145
- package/src/tools/jobs.js +325 -50
- package/src/tools/kiwi.js +50 -5
- package/src/tools/lsp.js +164 -32
- package/src/tools/outline.js +52 -12
- package/src/tools/pdf.js +366 -56
- package/src/tools/shell.js +12 -4
- package/src/tools/spawn.js +203 -18
- package/src/tools/todo.js +73 -4
- package/src/tools/verify.js +312 -43
- package/src/tools/webfetch.js +184 -25
- package/src/tools/xlsx.js +232 -31
- package/src/ui/ansi.js +209 -15
- package/src/ui/banner.js +2 -1
- package/src/ui/complete.js +46 -4
- package/src/ui/diff.js +4 -2
- package/src/ui/export.js +91 -17
- package/src/ui/inputbox.js +58 -18
- package/src/ui/intro.js +9 -2
- package/src/ui/level.js +32 -7
- package/src/ui/md.js +101 -15
- package/src/ui/motion.js +5 -2
- package/src/ui/notify.js +7 -1
- package/src/ui/office.js +37 -5
- package/src/ui/pastechip.js +3 -2
- package/src/ui/pick.js +85 -12
- package/src/ui/prompt.js +176 -13
- package/src/ui/screen.js +2 -1
- package/src/ui/spinner.js +6 -1
- package/src/ui/status.js +80 -12
- package/src/ui/wrap.js +23 -37
- /package/src/agent/{/353/213/250/352/263/204.js" → phase.js} +0 -0
- /package/src/skills/builtin/{/352/271/212/354/235/264/354/236/210/352/262/214-/353/247/214/353/223/244/352/270/260/SKILL.md" → build-deep/SKILL.md} +0 -0
- /package/src/skills/builtin/{/354/260/250/352/267/274/354/260/250/352/267/274-/353/224/224/353/262/204/352/271/205/SKILL.md" → debug-step-by-step/SKILL.md} +0 -0
- /package/src/skills/builtin/{/353/201/235/352/271/214/354/247/200-/355/225/230/352/270/260/SKILL.md" → finish-all/SKILL.md} +0 -0
- /package/src/skills/builtin/{/354/212/244/354/212/244/353/241/234-/352/262/200/355/206/240/SKILL.md" → self-review/SKILL.md} +0 -0
- /package/src/skills/builtin/{/354/275/224/353/223/234-/354/244/204/354/235/264/352/270/260/SKILL.md" → simplify-code/SKILL.md} +0 -0
- /package/src/skills/builtin/{/354/260/224/353/237/254/353/263/264/352/270/260/SKILL.md" → spike/SKILL.md} +0 -0
- /package/src/skills/builtin/{/352/262/200/354/202/254-/353/250/274/354/240/200/SKILL.md" → test-first/SKILL.md} +0 -0
package/src/backend/learn.js
CHANGED
|
@@ -41,8 +41,18 @@ const 성한수 = (v) => {
|
|
|
41
41
|
* asked 우리가 요청했던 값 (알 수 있으면)
|
|
42
42
|
*/
|
|
43
43
|
export function 배울것(message) {
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
44
|
+
const 원문 = String(message ?? '');
|
|
45
|
+
if (!원문) return null;
|
|
46
|
+
/*
|
|
47
|
+
* 천 단위 쉼표를 먼저 뗀다. 게이트웨이가 숫자를 사람 눈에 맞춰 적으면(`128,000 tokens`) 아래 표의
|
|
48
|
+
* `\d+` 가 첫 조각에서 끊겨 어느 줄에도 안 걸리고, 맨 끝 「작은 쪽이 한계」 로 떨어져 괄호 속
|
|
49
|
+
* `30,000 in the completion` 을 창 크기로 배웠다 — 128,000 창을 30,000 으로 줄였다 (6회차 Gemini
|
|
50
|
+
* 애저배움6 L1). 떼는 것은 「숫자,세 자리」 뿐이다 — `messages, 30,000` 같은 목록 쉼표는 그대로 둔다.
|
|
51
|
+
* 화면에 보일 글(text)은 원문 그대로 둔다.
|
|
52
|
+
*/
|
|
53
|
+
const s = 원문.replace(/(\d),(?=\d{3}(?!\d))/g, '$1');
|
|
54
|
+
// 분당·하루 속도 한도는 창도 답 길이도 아니다 — 거기서 뽑은 숫자는 한계가 아니다 (속도한도인가).
|
|
55
|
+
if (속도한도인가(s)) return null;
|
|
46
56
|
|
|
47
57
|
// ── 1) 컨텍스트 한계 ──────────────────────────────────────────────────
|
|
48
58
|
// OpenAI·vLLM·LiteLLM·대부분의 게이트웨이가 이 모양으로 말한다.
|
|
@@ -60,12 +70,44 @@ export function 배울것(message) {
|
|
|
60
70
|
// 한국어로 옮겨 놓은 사내 게이트웨이
|
|
61
71
|
/(?:최대\s*)?컨텍스트[^\d]{0,20}(\d{3,})/,
|
|
62
72
|
];
|
|
73
|
+
/*
|
|
74
|
+
* 한국어 문장은 요청 수가 한계보다 **먼저** 오기도 한다 (2.0.0 6회차 · Gemini 백엔드5역).
|
|
75
|
+
*
|
|
76
|
+
* 컨텍스트 길이를 초과했습니다: 요청 15000 토큰, 최대 8192 토큰
|
|
77
|
+
*
|
|
78
|
+
* 아래 표의 한국어 줄은 「컨텍스트」 뒤 첫 숫자를 집어 15000 을 한계로 배웠다. 한계가 실제보다
|
|
79
|
+
* 크니 줄여 다시 부르지 않고 같은 거절을 되풀이한다. 그래서 「최대·한도·한계·제한」 뒤 숫자를
|
|
80
|
+
* 먼저 보고, 「요청」 뒤 숫자는 asked 로 둔다. 그런 말이 없으면 표의 옛 꼴로 간다.
|
|
81
|
+
*
|
|
82
|
+
* ── 그 낱말이 **넘긴 것의 이름**일 때 ────────────────────────────────
|
|
83
|
+
*
|
|
84
|
+
* 컨텍스트 한도 초과: 요청 15000 토큰, 최대 8192 토큰
|
|
85
|
+
*
|
|
86
|
+
* 여기 「한도」 는 한계를 가리키는 말이 아니라 **무엇을 넘겼는지**를 적은
|
|
87
|
+
* 말이고, 그 뒤 첫 숫자는 한계가 아니라 우리가 요청한 값이다. 그런데 위
|
|
88
|
+
* 규칙이 그 15000 을 한계로 집었다 — 위 문단이 막으려던 바로 그 틀림을
|
|
89
|
+
* 낱말만 바꿔 되풀이한 셈이다 (8회차 뒷단-배우기). 대조군 「길이를
|
|
90
|
+
* 초과했습니다」 는 그 낱말이 뒤에만 있어 처음부터 옳았다.
|
|
91
|
+
*
|
|
92
|
+
* 그래서 낱말과 숫자 **사이에 「요청」 이 끼면** 그 자리는 건너뛴다. 그러면
|
|
93
|
+
* 정규식이 알아서 다음 자리(「최대 8192」)로 가서 옳은 수를 집는다.
|
|
94
|
+
*/
|
|
95
|
+
if (/컨텍스트/.test(s)) {
|
|
96
|
+
const 최대 = /(?:최대|한도|한계|제한)(?:(?!요청)[^\d]){0,12}(\d{3,})/.exec(s);
|
|
97
|
+
/*
|
|
98
|
+
* 요청 수는 「요청」 **앞**에 오기도 한다(`15000 토큰 요청, 최대 8192 토큰`). 뒤만 보면 「최대 8192」 의
|
|
99
|
+
* 8192 를 집어 asked 가 limit 과 같아졌다 (6회차 Gemini 애저배움6 L5). 앞에 붙은 수를 먼저 본다.
|
|
100
|
+
*/
|
|
101
|
+
const 요청 = /(\d{3,})\s*(?:토큰\s*)?요청|요청[^\d]{0,12}(\d{3,})/.exec(s);
|
|
102
|
+
const limit = 성한수(최대?.[1]);
|
|
103
|
+
if (limit) return { kind: 'ctx', limit, asked: 성한수(요청?.[1] ?? 요청?.[2]) ?? null, text: 짧게(원문) };
|
|
104
|
+
}
|
|
63
105
|
for (const re of ctx표) {
|
|
64
106
|
const m = re.exec(s);
|
|
65
107
|
if (!m) continue;
|
|
66
108
|
const limit = 성한수(m[1]);
|
|
67
109
|
if (!limit) continue;
|
|
68
|
-
return { kind: 'ctx', limit, asked: 성한수(m[2]) ?? null, text: 짧게(
|
|
110
|
+
return { kind: 'ctx', limit, asked: 성한수(m[2]) ?? null, text: 짧게(원문) };
|
|
69
111
|
}
|
|
70
112
|
|
|
71
113
|
// ── 2) 답 길이 한계 ───────────────────────────────────────────────────
|
|
@@ -81,16 +123,37 @@ export function 배울것(message) {
|
|
|
81
123
|
* 숫자가 둘인데 **앞이 우리가 요청한 값**이고 뒤가 한계다. 아래 표는 이름
|
|
82
124
|
* 뒤의 첫 숫자를 집으므로, 그대로 두면 방금 거절당한 바로 그 값을 한계로
|
|
83
125
|
* 배운다. 그러면 같은 값으로 곧장 다시 부르고 또 거절당하는데, 그때는 이미
|
|
84
|
-
* 배운 뒤라 두 번은 못 배우고 턴이 죽는다(loop.js).
|
|
85
|
-
*
|
|
86
|
-
*
|
|
126
|
+
* 배운 뒤라 두 번은 못 배우고 턴이 죽는다(loop.js).
|
|
127
|
+
*
|
|
128
|
+
* (사냥5 확인) 여기에는 「배운 값은 연결저장() 으로 프로필에 적혀 다음에 켤 때도 똑같이
|
|
129
|
+
* 죽는다」 고 적혀 있었다. 사실이 아니다 — loop.js 는 ctx.연결저장 이 있을 때만 부르는데
|
|
130
|
+
* src 어디에서도 그 칸을 채우지 않는다. 배운 한계는 **그 연결(conn)이 사는 동안만** 간다.
|
|
131
|
+
* 그러니 잘못 배운 피해는 그 실행 안에서 끝나지만, 맞게 배운 값도 다음 실행에서 다시
|
|
132
|
+
* 거절당하고 다시 배운다. 적어 두려면 conn 을 쥔 쪽(repl.js)이 그 칸을 채워야 한다.
|
|
87
133
|
*
|
|
88
134
|
* 표보다 먼저 본다. 표에 한 번 걸리고 나면 되돌릴 자리가 없다.
|
|
89
135
|
*/
|
|
90
136
|
const 넘김 = /max_(?:completion_)?tokens\s*[:=]?\s*(\d{3,})\s*>\s*(\d{3,})/i.exec(s);
|
|
91
137
|
if (넘김) {
|
|
92
138
|
const limit = 성한수(넘김[2]);
|
|
93
|
-
if (limit) return { kind: 'out', limit, asked: 성한수(넘김[1]), text: 짧게(
|
|
139
|
+
if (limit) return { kind: 'out', limit, asked: 성한수(넘김[1]), text: 짧게(원문) };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/*
|
|
143
|
+
* 「>」 없이 말로 넘었다고 하는 꼴 — `max_tokens 16384 exceeds the model limit of 4096`.
|
|
144
|
+
* 아래 표의 `max_tokens[^\d]{0,40}(\d{3,})` 가 이름 뒤 첫 수(방금 거절당한 16384)를 한계로 배워, 같은 값으로
|
|
145
|
+
* 곧장 다시 부르고 또 거절당했다 (6회차 Gemini 애저배움6 L2). 이름 뒤 수 다음에 넘음·한계 말과 **더 작은**
|
|
146
|
+
* 수가 오면 그 작은 수가 한계다. 수가 하나뿐인 문장(`less than or equal to 8192`)은 여기 안 걸린다.
|
|
147
|
+
*
|
|
148
|
+
* 답 길이 칸의 이름은 규격마다 다르다 — llama.cpp 는 `n_predict`, Ollama 는 `num_predict`.
|
|
149
|
+
* 이름 하나가 빠지면 그 서버에서만 이 갈래를 못 타고 맨 끝 짐작(작은 쪽이 한계)으로 떨어져
|
|
150
|
+
* **답 길이 한계를 창 크기로** 배운다 (8회차 뒷단-배우기).
|
|
151
|
+
*/
|
|
152
|
+
const 넘음말 = /(?:max_(?:completion_)?tokens|n(?:um)?_predict)[^\d]{0,20}(\d{3,})[^\d]{0,80}?(?:exceed|greater than|larger than|more than|above|limit|maximum|at most)[^\d]{0,40}(\d{3,})/i.exec(s);
|
|
153
|
+
if (넘음말) {
|
|
154
|
+
const 요청값 = 성한수(넘음말[1]);
|
|
155
|
+
const limit = 성한수(넘음말[2]);
|
|
156
|
+
if (limit && 요청값 && limit < 요청값) return { kind: 'out', limit, asked: 요청값, text: 짧게(원문) };
|
|
94
157
|
}
|
|
95
158
|
|
|
96
159
|
const out표 = [
|
|
@@ -98,15 +161,25 @@ export function 배울것(message) {
|
|
|
98
161
|
/supports? at most\s+(\d+)\s*(?:completion\s*)?tokens?/i,
|
|
99
162
|
// "max_tokens must be less than or equal to 8192"
|
|
100
163
|
/max_(?:completion_)?tokens[^\d]{0,40}(\d{3,})/i,
|
|
101
|
-
|
|
102
|
-
|
|
164
|
+
// Ollama 는 `num_predict`, llama.cpp 는 `n_predict` — 같은 칸의 두 이름이다.
|
|
165
|
+
// 둘 중 하나만 적어 두면 그 서버에서만 아래 짐작으로 떨어져 창을 줄인다.
|
|
166
|
+
/n(?:um)?_predict[^\d]{0,20}(\d{3,})/i,
|
|
167
|
+
/*
|
|
168
|
+
* 한국어로 옮긴 게이트웨이. `답` 은 **낱말로 설 때만** 본다 (사냥5 B5-04).
|
|
169
|
+
*
|
|
170
|
+
* `답` 한 글자에 걸었더니 「답변 생성 실패: 요청 ID 123456」 의 답변, 「응답 대기
|
|
171
|
+
* 시간이 초과되었습니다 (60000ms)」 의 응답에 걸려 요청 번호와 밀리초를 출력 상한으로
|
|
172
|
+
* 배웠다. 배운 값은 conn 에 적혀 그 대화 내내 답 길이를 엉뚱한 값으로 묶는다.
|
|
173
|
+
* 앞뒤가 한글이면 다른 낱말의 한 조각이고, 숫자 뒤에 ms·초·분이 붙으면 시간이다.
|
|
174
|
+
*/
|
|
175
|
+
/(?:최대\s*)?(?:출력|(?<![가-힣])답(?![가-힣]))[^\d]{0,20}(\d{3,})(?!\d|\s*(?:ms|밀리초|초|분|s\b))/,
|
|
103
176
|
];
|
|
104
177
|
for (const re of out표) {
|
|
105
178
|
const m = re.exec(s);
|
|
106
179
|
if (!m) continue;
|
|
107
180
|
const limit = 성한수(m[1]);
|
|
108
181
|
if (!limit) continue;
|
|
109
|
-
return { kind: 'out', limit, asked: null, text: 짧게(
|
|
182
|
+
return { kind: 'out', limit, asked: null, text: 짧게(원문) };
|
|
110
183
|
}
|
|
111
184
|
|
|
112
185
|
/*
|
|
@@ -140,7 +213,7 @@ export function 배울것(message) {
|
|
|
140
213
|
const 작은것 = Math.min(...숫자들);
|
|
141
214
|
const 큰것 = Math.max(...숫자들);
|
|
142
215
|
// 둘이 같으면 뭘 뽑은 건지 알 수 없다. 그때는 배웠다고 하지 않는다.
|
|
143
|
-
if (작은것 < 큰것) return { kind: 'ctx', limit: 작은것, asked: 큰것, text: 짧게(
|
|
216
|
+
if (작은것 < 큰것) return { kind: 'ctx', limit: 작은것, asked: 큰것, text: 짧게(원문), 짐작: true };
|
|
144
217
|
}
|
|
145
218
|
}
|
|
146
219
|
|
|
@@ -155,6 +228,8 @@ export function 배울것(message) {
|
|
|
155
228
|
*/
|
|
156
229
|
export function 길이문제인가(message) {
|
|
157
230
|
const s = String(message ?? '');
|
|
231
|
+
// 속도 한도는 창 이야기가 아니다 — 창을 반으로 줄여도 분당 한도는 안 움직인다 (속도한도인가).
|
|
232
|
+
if (속도한도인가(s)) return false;
|
|
158
233
|
return /context (?:length|size|window)|too (?:long|large|many tokens)|exceeds?[^.]{0,30}(?:context|limit|token)|max_tokens|token limit|컨텍스트|너무 (?:깁|많|큽)/i.test(s)
|
|
159
234
|
// 아래는 서버마다 말이 달라 위 표에 안 잡히던 것들이다. 전부 실제 문장이다.
|
|
160
235
|
// TGI "input length 41003 exceeds maximum 8192"
|
|
@@ -163,6 +238,21 @@ export function 길이문제인가(message) {
|
|
|
163
238
|
|| /overflow|input length|prompt (?:is )?too|exceeds?\s+maximum|n_ctx|n_predict|입력이 (?:너무|깁)/i.test(s);
|
|
164
239
|
}
|
|
165
240
|
|
|
241
|
+
/**
|
|
242
|
+
* 분당·시간당·하루 **속도 한도** 문장인가 (사냥5 B5-03).
|
|
243
|
+
*
|
|
244
|
+
* 「Request too large for gpt-4o … on tokens per min (TPM): Limit 30000, Requested 45000」 은
|
|
245
|
+
* 요청 한 번이 **분당 토큰 한도**보다 크다는 말이다. 「too large」 와 숫자 둘이 들어 있어서
|
|
246
|
+
* 배울것 의 짐작 규칙(작은 쪽이 한계)에 그대로 걸렸고, 30,000 을 **창 크기**로 배워 128k
|
|
247
|
+
* 창을 줄였다. 창을 줄여도 분당 한도는 안 움직이므로 같은 거절이 또 온다. 부르는 자리
|
|
248
|
+
* (loop.js)가 429 를 걸러도, 이 함수가 그 문장을 창 이야기로 안 읽어야 새 부르는 자리에서도
|
|
249
|
+
* 안전하다.
|
|
250
|
+
*/
|
|
251
|
+
export function 속도한도인가(message) {
|
|
252
|
+
return /(?:tokens?|requests?)\s+per\s+(?:min(?:ute)?|hour|day)|\b(?:TPM|RPM|TPD|RPD|TPH)\b|rate[\s_-]?limit/i
|
|
253
|
+
.test(String(message ?? ''));
|
|
254
|
+
}
|
|
255
|
+
|
|
166
256
|
function 짧게(s) {
|
|
167
257
|
return String(s).replace(/\s+/g, ' ').trim().slice(0, 200);
|
|
168
258
|
}
|