shadok-ai 0.17.41 → 0.17.42
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/dist/migrate-groups.d.ts +39 -8
- package/dist/migrate-groups.js +84 -9
- package/dist/migrate-groups.js.map +1 -1
- package/dist/server.js +55 -30
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/migrate-groups.d.ts
CHANGED
|
@@ -99,15 +99,46 @@ export declare function commonsOsUser(input: {
|
|
|
99
99
|
* path is unreadable and the guard dies `check-failed` in silence. The migration
|
|
100
100
|
* relocates the `.claude` tree into the new HOME, so the reference must follow.
|
|
101
101
|
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
102
|
+
* The `<oldHome>/.claude` base is ALWAYS rewritten — the tree the migration moved —
|
|
103
|
+
* plus any extra RELATIVE prefix the caller passes (the `~/.shadok-ai/<dir>` script
|
|
104
|
+
* dirs a guard also names; see `shadokScriptDirs`). Every OTHER `/root/...` mention
|
|
105
|
+
* is left intact, so a reference to a dir that was NOT relocated keeps pointing at
|
|
106
|
+
* the original. Identity when the home did not move (mono-tenant, or old === new) or
|
|
107
|
+
* when either base is blank (never blank out a path). A `$HOME`-relative check is
|
|
108
|
+
* already portable and contains no absolute base to match, so it passes through
|
|
109
|
+
* untouched. Pure, so the boot self-heal that walks the cron file stays a thin
|
|
110
|
+
* caller — and the exact substitution is locked by test, the twin of
|
|
111
|
+
* `rewriteSkillsBase`.
|
|
109
112
|
*/
|
|
110
|
-
export declare function rewriteCronCheckHome(check: string, oldHome: string, newHome: string): string;
|
|
113
|
+
export declare function rewriteCronCheckHome(check: string, oldHome: string, newHome: string, extraRelPrefixes?: readonly string[]): string;
|
|
114
|
+
/**
|
|
115
|
+
* Shadok's OWN directories under `~/.shadok-ai` — NEVER carried into the commons
|
|
116
|
+
* HOME by the stranded-script heal, even if a cron check names one. The credential
|
|
117
|
+
* stores (`ssh`, `users`, `secrets`) are the load-bearing entries: copying them
|
|
118
|
+
* into `/home/main` would hand every commons agent the SSH private key, the
|
|
119
|
+
* per-session signing keys and the account password hashes. The rest are internal
|
|
120
|
+
* per-instance state a guard has no business reading. A denylist (not an allowlist)
|
|
121
|
+
* on purpose: an operator/agent names its script dir whatever it likes (`scripts`,
|
|
122
|
+
* `checks`, `marketing`, …), and an allowlist would silently fail to heal a
|
|
123
|
+
* custom-named one — reintroducing the exact silent breakage this closes.
|
|
124
|
+
*/
|
|
125
|
+
export declare const SHADOK_INTERNAL_DIRS: readonly string[];
|
|
126
|
+
/**
|
|
127
|
+
* The `~/.shadok-ai/<dir>` script directories a cron `check` references under the
|
|
128
|
+
* OLD commons HOME (`oldHome`, i.e. `/root`). These are operator/agent-authored
|
|
129
|
+
* monitoring scripts dropped straight under the data dir — a DIFFERENT location
|
|
130
|
+
* from `~/.claude/skills` (#419) that the HOME move also stranded: a dropped `main`
|
|
131
|
+
* guard cannot traverse `/root` (0700), so `/root/.shadok-ai/checks/x.sh` is
|
|
132
|
+
* unreadable exactly like a `/root/.claude` one, and the guard dies `check-failed`
|
|
133
|
+
* in silence.
|
|
134
|
+
*
|
|
135
|
+
* Returns the distinct RELATIVE prefixes (`".shadok-ai/checks"`, …), deduped and
|
|
136
|
+
* ready to feed `rewriteCronCheckHome`'s extra prefixes and `path.join`. Only the
|
|
137
|
+
* `<dir>/<something>` shape is matched (a segment that is a DIRECTORY, with a path
|
|
138
|
+
* component after it), so a top-level FILE (`/root/.shadok-ai/secrets.json`) is
|
|
139
|
+
* never caught; a dir on `SHADOK_INTERNAL_DIRS` is refused outright. Pure.
|
|
140
|
+
*/
|
|
141
|
+
export declare function shadokScriptDirs(check: string, oldHome: string): string[];
|
|
111
142
|
/**
|
|
112
143
|
* The running agents to respawn, as session ids — deduped, order preserved so
|
|
113
144
|
* the caller cycles them ONE AT A TIME (the OAuth refresh-token race,
|
package/dist/migrate-groups.js
CHANGED
|
@@ -100,18 +100,93 @@ export function commonsOsUser(input) {
|
|
|
100
100
|
* path is unreadable and the guard dies `check-failed` in silence. The migration
|
|
101
101
|
* relocates the `.claude` tree into the new HOME, so the reference must follow.
|
|
102
102
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
103
|
+
* The `<oldHome>/.claude` base is ALWAYS rewritten — the tree the migration moved —
|
|
104
|
+
* plus any extra RELATIVE prefix the caller passes (the `~/.shadok-ai/<dir>` script
|
|
105
|
+
* dirs a guard also names; see `shadokScriptDirs`). Every OTHER `/root/...` mention
|
|
106
|
+
* is left intact, so a reference to a dir that was NOT relocated keeps pointing at
|
|
107
|
+
* the original. Identity when the home did not move (mono-tenant, or old === new) or
|
|
108
|
+
* when either base is blank (never blank out a path). A `$HOME`-relative check is
|
|
109
|
+
* already portable and contains no absolute base to match, so it passes through
|
|
110
|
+
* untouched. Pure, so the boot self-heal that walks the cron file stays a thin
|
|
111
|
+
* caller — and the exact substitution is locked by test, the twin of
|
|
112
|
+
* `rewriteSkillsBase`.
|
|
110
113
|
*/
|
|
111
|
-
export function rewriteCronCheckHome(check, oldHome, newHome) {
|
|
114
|
+
export function rewriteCronCheckHome(check, oldHome, newHome, extraRelPrefixes = []) {
|
|
112
115
|
if (!check || !oldHome || !newHome || oldHome === newHome)
|
|
113
116
|
return check;
|
|
114
|
-
|
|
117
|
+
let out = check;
|
|
118
|
+
for (const rel of [".claude", ...extraRelPrefixes]) {
|
|
119
|
+
out = out.split(oldHome + "/" + rel).join(newHome + "/" + rel);
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
/** Escape a string for literal use inside a `RegExp`. */
|
|
124
|
+
function escapeRegExp(s) {
|
|
125
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Shadok's OWN directories under `~/.shadok-ai` — NEVER carried into the commons
|
|
129
|
+
* HOME by the stranded-script heal, even if a cron check names one. The credential
|
|
130
|
+
* stores (`ssh`, `users`, `secrets`) are the load-bearing entries: copying them
|
|
131
|
+
* into `/home/main` would hand every commons agent the SSH private key, the
|
|
132
|
+
* per-session signing keys and the account password hashes. The rest are internal
|
|
133
|
+
* per-instance state a guard has no business reading. A denylist (not an allowlist)
|
|
134
|
+
* on purpose: an operator/agent names its script dir whatever it likes (`scripts`,
|
|
135
|
+
* `checks`, `marketing`, …), and an allowlist would silently fail to heal a
|
|
136
|
+
* custom-named one — reintroducing the exact silent breakage this closes.
|
|
137
|
+
*/
|
|
138
|
+
export const SHADOK_INTERNAL_DIRS = [
|
|
139
|
+
"app",
|
|
140
|
+
"browsers",
|
|
141
|
+
"channels",
|
|
142
|
+
"config",
|
|
143
|
+
"crons",
|
|
144
|
+
"files",
|
|
145
|
+
"keys",
|
|
146
|
+
"ledger",
|
|
147
|
+
"locks",
|
|
148
|
+
"media",
|
|
149
|
+
"peers",
|
|
150
|
+
"pilotctl",
|
|
151
|
+
"profiles",
|
|
152
|
+
"run",
|
|
153
|
+
"secrets",
|
|
154
|
+
"self",
|
|
155
|
+
"ssh",
|
|
156
|
+
"tail",
|
|
157
|
+
"tokens",
|
|
158
|
+
"users",
|
|
159
|
+
"whisper",
|
|
160
|
+
"worktrees",
|
|
161
|
+
"wt",
|
|
162
|
+
];
|
|
163
|
+
/**
|
|
164
|
+
* The `~/.shadok-ai/<dir>` script directories a cron `check` references under the
|
|
165
|
+
* OLD commons HOME (`oldHome`, i.e. `/root`). These are operator/agent-authored
|
|
166
|
+
* monitoring scripts dropped straight under the data dir — a DIFFERENT location
|
|
167
|
+
* from `~/.claude/skills` (#419) that the HOME move also stranded: a dropped `main`
|
|
168
|
+
* guard cannot traverse `/root` (0700), so `/root/.shadok-ai/checks/x.sh` is
|
|
169
|
+
* unreadable exactly like a `/root/.claude` one, and the guard dies `check-failed`
|
|
170
|
+
* in silence.
|
|
171
|
+
*
|
|
172
|
+
* Returns the distinct RELATIVE prefixes (`".shadok-ai/checks"`, …), deduped and
|
|
173
|
+
* ready to feed `rewriteCronCheckHome`'s extra prefixes and `path.join`. Only the
|
|
174
|
+
* `<dir>/<something>` shape is matched (a segment that is a DIRECTORY, with a path
|
|
175
|
+
* component after it), so a top-level FILE (`/root/.shadok-ai/secrets.json`) is
|
|
176
|
+
* never caught; a dir on `SHADOK_INTERNAL_DIRS` is refused outright. Pure.
|
|
177
|
+
*/
|
|
178
|
+
export function shadokScriptDirs(check, oldHome) {
|
|
179
|
+
if (!check || !oldHome)
|
|
180
|
+
return [];
|
|
181
|
+
const re = new RegExp(escapeRegExp(oldHome + "/.shadok-ai/") + "([^/\\s'\"]+)/", "g");
|
|
182
|
+
const out = new Set();
|
|
183
|
+
for (let m = re.exec(check); m; m = re.exec(check)) {
|
|
184
|
+
const seg = m[1];
|
|
185
|
+
if (SHADOK_INTERNAL_DIRS.includes(seg))
|
|
186
|
+
continue;
|
|
187
|
+
out.add(".shadok-ai/" + seg);
|
|
188
|
+
}
|
|
189
|
+
return [...out];
|
|
115
190
|
}
|
|
116
191
|
/**
|
|
117
192
|
* The running agents to respawn, as session ids — deduped, order preserved so
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate-groups.js","sourceRoot":"","sources":["../src/migrate-groups.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;kDACkD;AAClD,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;AAEnC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAuB5D;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,KAK7B;IACC,IAAI,KAAK,CAAC,eAAe;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc;QAAE,OAAO,IAAI,CAAC;IAE/C,4EAA4E;IAC5E,uEAAuE;IACvE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,0BAA0B,GAAa,EAAE,CAAC;IAChD,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,SAAS;QAChC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACZ,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC;IAED,0EAA0E;IAC1E,0EAA0E;IAC1E,MAAM,iBAAiB,GAAG,KAAK,CAAC,cAAc;SAC3C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,YAAY,CAAC;SAClE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAEpB,OAAO;QACL,iBAAiB,EAAE,IAAI;QACvB,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,IAAI;QACjB,0BAA0B;QAC1B,mBAAmB,EAAE,IAAI;QACzB,iBAAiB;KAClB,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,KAAkD;IAC9E,OAAO,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/E,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"migrate-groups.js","sourceRoot":"","sources":["../src/migrate-groups.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -34,7 +34,7 @@ import { readGroundAt } from "./ground.js";
|
|
|
34
34
|
import { homeGreetingBrief } from "./greeting.js";
|
|
35
35
|
import { ensureSshIdentity } from "./ssh.js";
|
|
36
36
|
import { accountsEnabled, deploymentMode, probeCanProvision } from "./capability.js";
|
|
37
|
-
import { migrationPlan, runMigration, respawnPlan, commonsOsUser, COMMONS_USER, MIGRATION_MARKER_FILE, rewriteCronCheckHome, } from "./migrate-groups.js";
|
|
37
|
+
import { migrationPlan, runMigration, respawnPlan, commonsOsUser, COMMONS_USER, MIGRATION_MARKER_FILE, rewriteCronCheckHome, shadokScriptDirs, } from "./migrate-groups.js";
|
|
38
38
|
import { relayOAuthCallback } from "./oauth-relay.js";
|
|
39
39
|
import { openBrowser } from "./open-browser.js";
|
|
40
40
|
import { parseSkillMeta, prepromptParts, prepromptFingerprint, stalenessReasons, LEGACY_FINGERPRINT, } from "./preprompt.js";
|
|
@@ -3013,20 +3013,24 @@ async function ensureGroupsProvisioned() {
|
|
|
3013
3013
|
preseedGroupHomes();
|
|
3014
3014
|
// And heal the commons agent's own helper scripts + cron guards, which the HOME
|
|
3015
3015
|
// move off /root left stranded (see below).
|
|
3016
|
-
await
|
|
3016
|
+
await healCommonsStrandedScripts();
|
|
3017
3017
|
}
|
|
3018
3018
|
/**
|
|
3019
|
-
* Boot self-heal for the commons agent's OWN
|
|
3020
|
-
*
|
|
3019
|
+
* Boot self-heal for the commons agent's OWN helper scripts and cron guards after
|
|
3020
|
+
* its HOME moved off `/root` to `/home/main`. A cron guard runs DROPPED as the
|
|
3021
|
+
* commons `main` user, which cannot traverse `/root` (0700) — so ANY absolute
|
|
3022
|
+
* `/root/...` path it names (script or sibling state file) is unreadable and the
|
|
3023
|
+
* guard dies `check-failed` in silence (measured on a live instance: monitoring
|
|
3024
|
+
* crons stuck, "son script est sous /root"). New agents are fine (their HOME is
|
|
3025
|
+
* already `/home/main`); this is the one-way carry for what predates the move.
|
|
3021
3026
|
*
|
|
3022
|
-
*
|
|
3023
|
-
*
|
|
3024
|
-
*
|
|
3025
|
-
*
|
|
3026
|
-
*
|
|
3027
|
-
*
|
|
3028
|
-
*
|
|
3029
|
-
* `/home/main`); this is the one-way carry for what predates the move.
|
|
3027
|
+
* Two kinds of stranded location, both relocated here and then repointed:
|
|
3028
|
+
* 1. `~/.claude/skills` — the subtree `migChownTreeToCommons` skipped, where an
|
|
3029
|
+
* agent keeps the custom monitoring scripts it authored (#419).
|
|
3030
|
+
* 2. `~/.shadok-ai/<dir>` — operator/agent script dirs dropped straight under the
|
|
3031
|
+
* data dir (`checks`, `scripts`, `marketing`, …), discovered from the cron
|
|
3032
|
+
* checks that name them. `shadokScriptDirs` denylists shadok's own state and
|
|
3033
|
+
* credential stores, so a key/secret dir is NEVER copied into `/home/main`.
|
|
3030
3034
|
*
|
|
3031
3035
|
* Runs on EVERY capable boot, independent of the migration marker (the twin of
|
|
3032
3036
|
* the reprovision reconciler above), so an ALREADY-migrated instance self-heals on
|
|
@@ -3035,38 +3039,58 @@ async function ensureGroupsProvisioned() {
|
|
|
3035
3039
|
* (`cp -rn`, non-clobber) and the checks already rewritten (identity). No-op unless
|
|
3036
3040
|
* the HOME actually moved (mono-tenant / pre-migration: old === new).
|
|
3037
3041
|
*/
|
|
3038
|
-
async function
|
|
3042
|
+
async function healCommonsStrandedScripts() {
|
|
3039
3043
|
if (DEPLOYMENT_MODE !== "multi-tenant")
|
|
3040
3044
|
return;
|
|
3041
3045
|
const oldHome = os.homedir();
|
|
3042
3046
|
const newHome = homeForUser(COMMONS_USER, GROUP_HOME_BASE);
|
|
3043
3047
|
if (!newHome || newHome === oldHome)
|
|
3044
3048
|
return; // not migrated off /root → nothing moved
|
|
3045
|
-
|
|
3046
|
-
//
|
|
3047
|
-
//
|
|
3048
|
-
//
|
|
3049
|
+
const owner = `${COMMONS_USER}:${COMMONS_USER}`;
|
|
3050
|
+
// Carry one relative tree <oldHome>/<rel> → <newHome>/<rel>, non-clobber, owned
|
|
3051
|
+
// by `main`. The parent is `install -d`'d too so `~/.shadok-ai` exists in the new
|
|
3052
|
+
// HOME. No-op when the source is absent.
|
|
3053
|
+
const copyTree = async (rel) => {
|
|
3054
|
+
const src = path.join(oldHome, rel);
|
|
3055
|
+
if (!fs.existsSync(src))
|
|
3056
|
+
return;
|
|
3057
|
+
const dst = path.join(newHome, rel);
|
|
3058
|
+
await runPrivileged("install", ["-d", "-o", COMMONS_USER, "-g", COMMONS_USER, path.dirname(dst)]);
|
|
3059
|
+
await runPrivileged("install", ["-d", "-o", COMMONS_USER, "-g", COMMONS_USER, dst]);
|
|
3060
|
+
await runPrivileged("cp", ["-rn", `${src}/.`, `${dst}/`], { timeoutMs: TREE_OP_TIMEOUT_MS });
|
|
3061
|
+
await runPrivileged("chown", ["-R", owner, dst], { timeoutMs: TREE_OP_TIMEOUT_MS });
|
|
3062
|
+
};
|
|
3063
|
+
// Load once; the same list feeds the dir discovery AND the rewrite below.
|
|
3064
|
+
let crons = [];
|
|
3049
3065
|
try {
|
|
3050
|
-
|
|
3051
|
-
if (fs.existsSync(srcSkills)) {
|
|
3052
|
-
const owner = `${COMMONS_USER}:${COMMONS_USER}`;
|
|
3053
|
-
const dstSkills = path.join(newHome, ".claude", "skills");
|
|
3054
|
-
await runPrivileged("install", ["-d", "-o", COMMONS_USER, "-g", COMMONS_USER, dstSkills]);
|
|
3055
|
-
await runPrivileged("cp", ["-rn", `${srcSkills}/.`, `${dstSkills}/`], { timeoutMs: TREE_OP_TIMEOUT_MS });
|
|
3056
|
-
await runPrivileged("chown", ["-R", owner, dstSkills], { timeoutMs: TREE_OP_TIMEOUT_MS });
|
|
3057
|
-
}
|
|
3066
|
+
crons = loadCrons();
|
|
3058
3067
|
}
|
|
3059
3068
|
catch (e) {
|
|
3060
|
-
console.error(`heal:
|
|
3069
|
+
console.error(`heal: reading crons failed (best-effort): ${e?.message ?? e}`);
|
|
3070
|
+
}
|
|
3071
|
+
// The ~/.shadok-ai/<dir> script dirs the guards name, deduped (never a
|
|
3072
|
+
// credential/state dir — shadokScriptDirs denylists those).
|
|
3073
|
+
const scriptDirs = [
|
|
3074
|
+
...new Set(crons.flatMap((c) => (c.check ? shadokScriptDirs(c.check, oldHome) : []))),
|
|
3075
|
+
];
|
|
3076
|
+
// 1) Relocate the skills subtree the migration skipped, plus every discovered
|
|
3077
|
+
// ~/.shadok-ai script dir. Each copy is independent and best-effort.
|
|
3078
|
+
for (const rel of [path.join(".claude", "skills"), ...scriptDirs]) {
|
|
3079
|
+
try {
|
|
3080
|
+
await copyTree(rel);
|
|
3081
|
+
}
|
|
3082
|
+
catch (e) {
|
|
3083
|
+
console.error(`heal: relocating commons ~/${rel} failed (best-effort): ${e?.message ?? e}`);
|
|
3084
|
+
}
|
|
3061
3085
|
}
|
|
3062
|
-
// 2) Repoint this instance's cron guards
|
|
3086
|
+
// 2) Repoint this instance's cron guards: the .claude base AND the relocated
|
|
3087
|
+
// ~/.shadok-ai script dirs. A /root path that was NOT relocated stays intact.
|
|
3063
3088
|
try {
|
|
3064
|
-
const crons = loadCrons();
|
|
3065
3089
|
let changed = false;
|
|
3066
3090
|
for (const c of crons) {
|
|
3067
3091
|
if (!c.check)
|
|
3068
3092
|
continue;
|
|
3069
|
-
const next = rewriteCronCheckHome(c.check, oldHome, newHome);
|
|
3093
|
+
const next = rewriteCronCheckHome(c.check, oldHome, newHome, scriptDirs);
|
|
3070
3094
|
if (next !== c.check) {
|
|
3071
3095
|
c.check = next;
|
|
3072
3096
|
changed = true;
|
|
@@ -3074,7 +3098,8 @@ async function healCommonsClaudeScripts() {
|
|
|
3074
3098
|
}
|
|
3075
3099
|
if (changed) {
|
|
3076
3100
|
saveCrons(crons);
|
|
3077
|
-
console.log(`heal: repointed cron guard path(s) from ${oldHome}
|
|
3101
|
+
console.log(`heal: repointed cron guard path(s) from ${oldHome} → ${newHome} ` +
|
|
3102
|
+
`(.claude${scriptDirs.length ? ", " + scriptDirs.join(", ") : ""})`);
|
|
3078
3103
|
}
|
|
3079
3104
|
}
|
|
3080
3105
|
catch (e) {
|