@usine/executor 0.0.0 → 0.1.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/LICENSE +21 -0
- package/README.md +57 -1
- package/dist/child-command.d.ts +18 -0
- package/dist/child-command.d.ts.map +1 -0
- package/dist/child-command.js +47 -0
- package/dist/child-command.js.map +1 -0
- package/dist/exe-dev/channel.d.ts +8 -0
- package/dist/exe-dev/channel.d.ts.map +1 -0
- package/dist/exe-dev/channel.js +45 -0
- package/dist/exe-dev/channel.js.map +1 -0
- package/dist/exe-dev/commands.d.ts +22 -0
- package/dist/exe-dev/commands.d.ts.map +1 -0
- package/dist/exe-dev/commands.js +67 -0
- package/dist/exe-dev/commands.js.map +1 -0
- package/dist/exe-dev/grants.d.ts +9 -0
- package/dist/exe-dev/grants.d.ts.map +1 -0
- package/dist/exe-dev/grants.js +88 -0
- package/dist/exe-dev/grants.js.map +1 -0
- package/dist/exe-dev/index.d.ts +8 -0
- package/dist/exe-dev/index.d.ts.map +1 -0
- package/dist/exe-dev/index.js +239 -0
- package/dist/exe-dev/index.js.map +1 -0
- package/dist/exe-dev/model.d.ts +58 -0
- package/dist/exe-dev/model.d.ts.map +1 -0
- package/dist/exe-dev/model.js +33 -0
- package/dist/exe-dev/model.js.map +1 -0
- package/dist/exe-dev/preflight.d.ts +9 -0
- package/dist/exe-dev/preflight.d.ts.map +1 -0
- package/dist/exe-dev/preflight.js +82 -0
- package/dist/exe-dev/preflight.js.map +1 -0
- package/dist/exe-dev/shell.d.ts +12 -0
- package/dist/exe-dev/shell.d.ts.map +1 -0
- package/dist/exe-dev/shell.js +31 -0
- package/dist/exe-dev/shell.js.map +1 -0
- package/dist/exe-dev/sweep.d.ts +12 -0
- package/dist/exe-dev/sweep.d.ts.map +1 -0
- package/dist/exe-dev/sweep.js +119 -0
- package/dist/exe-dev/sweep.js.map +1 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/invalid-frame.d.ts +17 -0
- package/dist/invalid-frame.d.ts.map +1 -0
- package/dist/invalid-frame.js +110 -0
- package/dist/invalid-frame.js.map +1 -0
- package/dist/keyed-lock.d.ts +11 -0
- package/dist/keyed-lock.d.ts.map +1 -0
- package/dist/keyed-lock.js +21 -0
- package/dist/keyed-lock.js.map +1 -0
- package/dist/local/index.d.ts +15 -0
- package/dist/local/index.d.ts.map +1 -0
- package/dist/local/index.js +302 -0
- package/dist/local/index.js.map +1 -0
- package/dist/provision.d.ts +33 -0
- package/dist/provision.d.ts.map +1 -0
- package/dist/provision.js +76 -0
- package/dist/provision.js.map +1 -0
- package/dist/run-host-session.d.ts +22 -0
- package/dist/run-host-session.d.ts.map +1 -0
- package/dist/run-host-session.js +228 -0
- package/dist/run-host-session.js.map +1 -0
- package/package.json +51 -4
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { Attempt, AttemptChannel, AttemptFailure, Instance, Repository } from "@usine/core";
|
|
2
|
+
import { Effect, FileSystem, Layer, Path, Redacted, Ref, Result, Schema, Stream, } from "effect";
|
|
3
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
|
|
4
|
+
import { allowlistedEnvironment, collectCommand, requireSuccess } from "../child-command.js";
|
|
5
|
+
import { CheckoutRequest, CredentialProvider, Executor, ExecutorError, ExecutorOperationError, logPreflightFailure, WorkerCapabilityError, } from "../index.js";
|
|
6
|
+
import { keyedLockFor } from "../keyed-lock.js";
|
|
7
|
+
import { provisionWorktree, safeSegment } from "../provision.js";
|
|
8
|
+
import { runHostSessionFor } from "../run-host-session.js";
|
|
9
|
+
const isExecutorError = Schema.is(ExecutorError);
|
|
10
|
+
/**
|
|
11
|
+
* The run host gets a minimal environment, never the orchestrator's: the App
|
|
12
|
+
* private key and every other orchestrator secret must not reach the agent
|
|
13
|
+
* (ADR 0011's single-repo worker token is the only credential it holds).
|
|
14
|
+
*/
|
|
15
|
+
const HOST_ENVIRONMENT_ALLOWLIST = [
|
|
16
|
+
"HOME",
|
|
17
|
+
"LANG",
|
|
18
|
+
"LC_ALL",
|
|
19
|
+
"PATH",
|
|
20
|
+
"SHELL",
|
|
21
|
+
"TMPDIR",
|
|
22
|
+
"USER",
|
|
23
|
+
];
|
|
24
|
+
const executorError = (operation, message, cause) => new ExecutorOperationError({ operation, message, cause });
|
|
25
|
+
/** The credential must never survive into a persisted error message. */
|
|
26
|
+
const scrubbed = (text, credential) => text.replaceAll(Redacted.value(credential), "[REDACTED]");
|
|
27
|
+
const credentialEnvironment = (base, credential) => {
|
|
28
|
+
const token = Redacted.value(credential);
|
|
29
|
+
return {
|
|
30
|
+
...base,
|
|
31
|
+
GH_TOKEN: token,
|
|
32
|
+
GITHUB_TOKEN: token,
|
|
33
|
+
GIT_CONFIG_COUNT: "1",
|
|
34
|
+
GIT_CONFIG_KEY_0: "credential.helper",
|
|
35
|
+
GIT_CONFIG_VALUE_0: "!f() { echo username=x-access-token; echo password=$GITHUB_TOKEN; }; f",
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const makeLocalExecutor = (options) => Effect.gen(function* () {
|
|
39
|
+
const credentials = yield* CredentialProvider;
|
|
40
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
41
|
+
const path = yield* Path.Path;
|
|
42
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
43
|
+
const fetches = yield* keyedLockFor();
|
|
44
|
+
const preparedStates = yield* Ref.make(new Map());
|
|
45
|
+
const baseEnvironment = yield* allowlistedEnvironment(HOST_ENVIRONMENT_ALLOWLIST);
|
|
46
|
+
const repositoryUrl = options.repositoryUrl ??
|
|
47
|
+
((repository) => `https://github.com/${repository}.git`);
|
|
48
|
+
const runHost = options.runHost;
|
|
49
|
+
const interruptGrace = options.interruptGrace ?? "2 seconds";
|
|
50
|
+
const workersRoot = path.join(options.instanceDirectory, ".usine", "workers");
|
|
51
|
+
const executeCommand = Effect.fn("LocalExecutor.executeCommand")(function* (operation, command, args, commandOptions = {}) {
|
|
52
|
+
yield* Effect.annotateCurrentSpan({ host: "local", operation });
|
|
53
|
+
const result = yield* collectCommand(spawner, operation, command, args, {
|
|
54
|
+
env: baseEnvironment,
|
|
55
|
+
extendEnv: false,
|
|
56
|
+
...commandOptions,
|
|
57
|
+
});
|
|
58
|
+
return yield* requireSuccess(operation, "local", command, args, result);
|
|
59
|
+
});
|
|
60
|
+
const run = Effect.fn("LocalExecutor.run")(function* (operation, command, args, commandOptions = {}) {
|
|
61
|
+
yield* executeCommand(operation, command, args, commandOptions);
|
|
62
|
+
});
|
|
63
|
+
// ADR 0006: worktrees never outlive their Attempt. A crashed orchestrator
|
|
64
|
+
// leaves both directories and bare-cache registrations behind; the sweep
|
|
65
|
+
// reclaims them at the next layer build, before new Attempts start.
|
|
66
|
+
const sweepAbandonedWorktrees = Effect.fn("LocalExecutor.sweepAbandonedWorktrees")(function* () {
|
|
67
|
+
if (!(yield* fileSystem.exists(workersRoot)))
|
|
68
|
+
return;
|
|
69
|
+
const workers = yield* fileSystem.readDirectory(workersRoot);
|
|
70
|
+
for (const worker of workers) {
|
|
71
|
+
const attemptsRoot = path.join(workersRoot, worker, "attempts");
|
|
72
|
+
if (yield* fileSystem.exists(attemptsRoot)) {
|
|
73
|
+
const leftovers = yield* fileSystem.readDirectory(attemptsRoot);
|
|
74
|
+
for (const leftover of leftovers) {
|
|
75
|
+
const target = path.join(attemptsRoot, leftover);
|
|
76
|
+
yield* Effect.logInfo("Sweeping abandoned Attempt worktree", {
|
|
77
|
+
worker,
|
|
78
|
+
host: "local",
|
|
79
|
+
worktree: target,
|
|
80
|
+
});
|
|
81
|
+
yield* fileSystem.remove(target, { recursive: true, force: true });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const reposRoot = path.join(workersRoot, worker, "repos");
|
|
85
|
+
if (yield* fileSystem.exists(reposRoot)) {
|
|
86
|
+
const caches = yield* fileSystem.readDirectory(reposRoot);
|
|
87
|
+
for (const cache of caches) {
|
|
88
|
+
yield* run("cleanup", "git", [
|
|
89
|
+
"--git-dir",
|
|
90
|
+
path.join(reposRoot, cache),
|
|
91
|
+
"worktree",
|
|
92
|
+
"prune",
|
|
93
|
+
]).pipe(Effect.tapError((error) => Effect.logWarning("Could not prune a bare cache during the sweep", {
|
|
94
|
+
worker,
|
|
95
|
+
host: "local",
|
|
96
|
+
cache,
|
|
97
|
+
message: error.message,
|
|
98
|
+
})), Effect.ignore);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
yield* sweepAbandonedWorktrees().pipe(Effect.tapError((error) => Effect.logWarning("Abandoned-worktree sweep failed; continuing", {
|
|
104
|
+
message: String(error),
|
|
105
|
+
})), Effect.ignore);
|
|
106
|
+
const preflight = Effect.fn("LocalExecutor.preflight")(function* (worker) {
|
|
107
|
+
yield* Effect.annotateCurrentSpan({ worker, host: "local" });
|
|
108
|
+
const gitVersion = (yield* executeCommand("preflight", "git", ["--version"])).trim();
|
|
109
|
+
if (!gitVersion.startsWith("git version ")) {
|
|
110
|
+
return yield* new WorkerCapabilityError({
|
|
111
|
+
worker,
|
|
112
|
+
capability: "toolchain",
|
|
113
|
+
message: `Worker ${worker} returned an unrecognized git version`,
|
|
114
|
+
cause: new Error(gitVersion),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
const reported = (yield* executeCommand("preflight", runHost.command, [
|
|
118
|
+
...runHost.args,
|
|
119
|
+
"--protocol-version",
|
|
120
|
+
])).trim();
|
|
121
|
+
if (reported !== String(AttemptChannel.PROTOCOL_VERSION)) {
|
|
122
|
+
return yield* new WorkerCapabilityError({
|
|
123
|
+
worker,
|
|
124
|
+
capability: "run-host",
|
|
125
|
+
message: `Worker ${worker} has run-host protocol ${reported || "unknown"}; expected ${AttemptChannel.PROTOCOL_VERSION}`,
|
|
126
|
+
cause: new Error("run-host protocol mismatch"),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
yield* Effect.logInfo("Worker preflight verified", {
|
|
130
|
+
worker,
|
|
131
|
+
host: "local",
|
|
132
|
+
gitVersion,
|
|
133
|
+
protocolVersion: AttemptChannel.PROTOCOL_VERSION,
|
|
134
|
+
});
|
|
135
|
+
}, logPreflightFailure);
|
|
136
|
+
const prepare = Effect.fn("LocalExecutor.prepare")(function* (request) {
|
|
137
|
+
yield* Effect.annotateCurrentSpan({
|
|
138
|
+
attemptId: request.attemptId,
|
|
139
|
+
worker: request.worker,
|
|
140
|
+
host: "local",
|
|
141
|
+
repository: request.repository,
|
|
142
|
+
});
|
|
143
|
+
const credential = yield* credentials.issue(request.repository, request.attemptId);
|
|
144
|
+
const workerRoot = path.join(workersRoot, request.worker);
|
|
145
|
+
const cache = path.join(workerRoot, "repos", `${safeSegment(request.repository)}.git`);
|
|
146
|
+
const worktree = path.join(workerRoot, "attempts", safeSegment(request.attemptId));
|
|
147
|
+
const environment = credentialEnvironment(baseEnvironment, credential);
|
|
148
|
+
const commandOptions = { env: environment, extendEnv: false };
|
|
149
|
+
yield* Effect.logInfo("Preparing Attempt workspace", {
|
|
150
|
+
attemptId: request.attemptId,
|
|
151
|
+
worker: request.worker,
|
|
152
|
+
repository: request.repository,
|
|
153
|
+
revision: request.revision,
|
|
154
|
+
cache,
|
|
155
|
+
worktree,
|
|
156
|
+
});
|
|
157
|
+
const remove = (target) => fileSystem.remove(target, { recursive: true, force: true });
|
|
158
|
+
const ops = {
|
|
159
|
+
ensureRoots: Effect.andThen(fileSystem.makeDirectory(path.dirname(cache), { recursive: true }), fileSystem.makeDirectory(path.dirname(worktree), { recursive: true })),
|
|
160
|
+
removePath: remove,
|
|
161
|
+
cacheExists: fileSystem.exists(cache),
|
|
162
|
+
promoteStaging: fileSystem.rename(`${cache}.cloning`, cache),
|
|
163
|
+
git: (args) => executeCommand("prepare", "git", args, commandOptions),
|
|
164
|
+
};
|
|
165
|
+
const prepared = yield* fetches
|
|
166
|
+
.withLock(request.repository)(provisionWorktree({
|
|
167
|
+
request,
|
|
168
|
+
url: repositoryUrl(request.repository),
|
|
169
|
+
host: "local",
|
|
170
|
+
layout: { cache, staging: `${cache}.cloning`, worktree },
|
|
171
|
+
ops,
|
|
172
|
+
}))
|
|
173
|
+
.pipe(Effect.mapError((error) => isExecutorError(error)
|
|
174
|
+
? error
|
|
175
|
+
: executorError("prepare", "Attempt workspace preparation failed", error)), Effect.onError(() => Effect.gen(function* () {
|
|
176
|
+
yield* fileSystem.remove(worktree, { recursive: true, force: true }).pipe(Effect.tapError((error) => Effect.logWarning("Could not remove a partial local workspace", {
|
|
177
|
+
attemptId: request.attemptId,
|
|
178
|
+
worker: request.worker,
|
|
179
|
+
host: "local",
|
|
180
|
+
worktree,
|
|
181
|
+
message: String(error),
|
|
182
|
+
})), Effect.ignore);
|
|
183
|
+
Redacted.wipeUnsafe(credential);
|
|
184
|
+
})));
|
|
185
|
+
yield* Ref.update(preparedStates, (current) => {
|
|
186
|
+
const next = new Map(current);
|
|
187
|
+
next.set(request.attemptId, { cache, credential });
|
|
188
|
+
return next;
|
|
189
|
+
});
|
|
190
|
+
yield* Effect.logInfo("Attempt workspace ready", {
|
|
191
|
+
attemptId: request.attemptId,
|
|
192
|
+
baseCommit: prepared.spec.baseCommit,
|
|
193
|
+
worktree,
|
|
194
|
+
});
|
|
195
|
+
return prepared;
|
|
196
|
+
});
|
|
197
|
+
const spawn = Effect.fn("LocalExecutor.spawnRunHost")(function* (prepared, input) {
|
|
198
|
+
const attemptId = prepared.spec.attemptId;
|
|
199
|
+
yield* Effect.annotateCurrentSpan({
|
|
200
|
+
attemptId,
|
|
201
|
+
worker: prepared.worker,
|
|
202
|
+
host: "local",
|
|
203
|
+
});
|
|
204
|
+
const stored = (yield* Ref.get(preparedStates)).get(attemptId);
|
|
205
|
+
if (stored === undefined) {
|
|
206
|
+
return yield* new AttemptFailure.InfraFailure({
|
|
207
|
+
message: `Attempt ${attemptId} has no prepared credential`,
|
|
208
|
+
cause: new Error("prepared Attempt state missing"),
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
yield* Effect.logInfo("Launching the run host", {
|
|
212
|
+
attemptId,
|
|
213
|
+
worker: prepared.worker,
|
|
214
|
+
host: "local",
|
|
215
|
+
command: runHost.command,
|
|
216
|
+
worktree: prepared.worktree,
|
|
217
|
+
});
|
|
218
|
+
const handle = yield* spawner.spawn(ChildProcess.make(runHost.command, runHost.args, {
|
|
219
|
+
cwd: prepared.worktree,
|
|
220
|
+
env: credentialEnvironment(baseEnvironment, stored.credential),
|
|
221
|
+
extendEnv: false,
|
|
222
|
+
stdin: { stream: Stream.fromQueue(input), endOnDone: true },
|
|
223
|
+
}));
|
|
224
|
+
return {
|
|
225
|
+
handle,
|
|
226
|
+
host: "local",
|
|
227
|
+
scrub: (text) => scrubbed(text, stored.credential),
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
const session = yield* runHostSessionFor({ interruptGrace, spawn });
|
|
231
|
+
const cleanup = Effect.fn("LocalExecutor.cleanup")(function* (prepared) {
|
|
232
|
+
const attemptId = prepared.spec.attemptId;
|
|
233
|
+
yield* Effect.annotateCurrentSpan({
|
|
234
|
+
attemptId,
|
|
235
|
+
worker: prepared.worker,
|
|
236
|
+
host: "local",
|
|
237
|
+
});
|
|
238
|
+
yield* Effect.logInfo("Cleaning Attempt workspace", {
|
|
239
|
+
attemptId,
|
|
240
|
+
worker: prepared.worker,
|
|
241
|
+
host: "local",
|
|
242
|
+
worktree: prepared.worktree,
|
|
243
|
+
});
|
|
244
|
+
const state = (yield* Ref.get(preparedStates)).get(attemptId);
|
|
245
|
+
if (state === undefined) {
|
|
246
|
+
yield* fileSystem
|
|
247
|
+
.remove(prepared.worktree, { recursive: true, force: true })
|
|
248
|
+
.pipe(Effect.mapError((cause) => executorError("cleanup", `Could not remove ${prepared.worktree}`, cause)));
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const finish = Effect.gen(function* () {
|
|
252
|
+
const removedFromGit = yield* run("cleanup", "git", [
|
|
253
|
+
"--git-dir",
|
|
254
|
+
state.cache,
|
|
255
|
+
"worktree",
|
|
256
|
+
"remove",
|
|
257
|
+
"--force",
|
|
258
|
+
prepared.worktree,
|
|
259
|
+
]).pipe(Effect.result);
|
|
260
|
+
const removedFromDisk = yield* fileSystem
|
|
261
|
+
.remove(prepared.worktree, { recursive: true, force: true })
|
|
262
|
+
.pipe(Effect.mapError((cause) => executorError("cleanup", `Could not remove ${prepared.worktree}`, cause)), Effect.result);
|
|
263
|
+
const pruned = yield* run("cleanup", "git", [
|
|
264
|
+
"--git-dir",
|
|
265
|
+
state.cache,
|
|
266
|
+
"worktree",
|
|
267
|
+
"prune",
|
|
268
|
+
]).pipe(Effect.result);
|
|
269
|
+
for (const result of [removedFromGit, removedFromDisk, pruned]) {
|
|
270
|
+
if (Result.isFailure(result)) {
|
|
271
|
+
return yield* result.failure;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}).pipe(Effect.mapError((cause) => isExecutorError(cause)
|
|
275
|
+
? cause
|
|
276
|
+
: executorError("cleanup", `Could not clean Attempt ${attemptId}`, cause)));
|
|
277
|
+
yield* finish.pipe(Effect.ensuring(Effect.gen(function* () {
|
|
278
|
+
yield* Ref.update(preparedStates, (current) => {
|
|
279
|
+
const next = new Map(current);
|
|
280
|
+
next.delete(attemptId);
|
|
281
|
+
return next;
|
|
282
|
+
});
|
|
283
|
+
Redacted.wipeUnsafe(state.credential);
|
|
284
|
+
})));
|
|
285
|
+
yield* Effect.logInfo("Attempt cleanup completed", {
|
|
286
|
+
attemptId,
|
|
287
|
+
worker: prepared.worker,
|
|
288
|
+
host: "local",
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
return Executor.of({
|
|
292
|
+
kind: "local",
|
|
293
|
+
cancel: session.cancel,
|
|
294
|
+
cleanup,
|
|
295
|
+
launch: session.launch,
|
|
296
|
+
preflight,
|
|
297
|
+
prepare,
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
/** Node-only local executor; the package root remains platform-free. */
|
|
301
|
+
export const layer = (options) => Layer.effect(Executor, makeLocalExecutor(options));
|
|
302
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/local/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EACL,MAAM,EACN,UAAU,EACV,KAAK,EACL,IAAI,EAEJ,QAAQ,EACR,GAAG,EACH,MAAM,EACN,MAAM,EACN,MAAM,GACP,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC7F,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,aAAa,EACb,sBAAsB,EACtB,mBAAmB,EAGnB,qBAAqB,GAEtB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAqB,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAqB,MAAM,wBAAwB,CAAC;AAiB9E,MAAM,eAAe,GAAG,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;AAEjD;;;;GAIG;AACH,MAAM,0BAA0B,GAAG;IACjC,MAAM;IACN,MAAM;IACN,QAAQ;IACR,MAAM;IACN,OAAO;IACP,QAAQ;IACR,MAAM;CACE,CAAC;AAEX,MAAM,aAAa,GAAG,CACpB,SAA4B,EAC5B,OAAe,EACf,KAAc,EACU,EAAE,CAAC,IAAI,sBAAsB,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;AAEvF,wEAAwE;AACxE,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,UAAqC,EAAU,EAAE,CAC/E,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC,CAAC;AAE5D,MAAM,qBAAqB,GAAG,CAC5B,IAA4B,EAC5B,UAAqC,EACrC,EAAE;IACF,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzC,OAAO;QACL,GAAG,IAAI;QACP,QAAQ,EAAE,KAAK;QACf,YAAY,EAAE,KAAK;QACnB,gBAAgB,EAAE,GAAG;QACrB,gBAAgB,EAAE,mBAAmB;QACrC,kBAAkB,EAAE,wEAAwE;KACpF,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,OAA6B,EAAE,EAAE,CAC1D,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,kBAAkB,CAAC;IAC9C,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;IAChD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC9B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAC,mBAAmB,CAAC;IAC/D,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,YAAY,EAAmB,CAAC;IACvD,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,EAAoC,CAAC,CAAC;IACpF,MAAM,eAAe,GAAG,KAAK,CAAC,CAAC,sBAAsB,CAAC,0BAA0B,CAAC,CAAC;IAClF,MAAM,aAAa,GACjB,OAAO,CAAC,aAAa;QACrB,CAAC,CAAC,UAA2B,EAAU,EAAE,CAAC,sBAAsB,UAAU,MAAM,CAAC,CAAC;IACpF,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,WAAW,CAAC;IAC7D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAE9E,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,8BAA8B,CAAC,CAAC,QAAQ,CAAC,EACxE,SAA4B,EAC5B,OAAe,EACf,IAA2B,EAC3B,cAAc,GAAgC,EAAE;QAEhD,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE;YACtE,GAAG,EAAE,eAAe;YACpB,SAAS,EAAE,KAAK;YAChB,GAAG,cAAc;SAClB,CAAC,CAAC;QACH,OAAO,KAAK,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,EAClD,SAA4B,EAC5B,OAAe,EACf,IAA2B,EAC3B,cAAc,GAAgC,EAAE;QAEhD,KAAK,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,0EAA0E;IAC1E,yEAAyE;IACzE,oEAAoE;IACpE,MAAM,uBAAuB,GAAG,MAAM,CAAC,EAAE,CAAC,uCAAuC,CAAC,CAChF,QAAQ,CAAC;QACP,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAAE,OAAO;QACrD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QAC7D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;YAChE,IAAI,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC3C,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;gBAChE,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;oBACjC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;oBACjD,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,qCAAqC,EAAE;wBAC3D,MAAM;wBACN,IAAI,EAAE,OAAO;wBACb,QAAQ,EAAE,MAAM;qBACjB,CAAC,CAAC;oBACH,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACrE,CAAC;YACH,CAAC;YACD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;YAC1D,IAAI,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBACxC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;gBAC1D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAC3B,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE;wBAC3B,WAAW;wBACX,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC;wBAC3B,UAAU;wBACV,OAAO;qBACR,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,MAAM,CAAC,UAAU,CAAC,+CAA+C,EAAE;wBACjE,MAAM;wBACN,IAAI,EAAE,OAAO;wBACb,KAAK;wBACL,OAAO,EAAE,KAAK,CAAC,OAAO;qBACvB,CAAC,CACH,EACD,MAAM,CAAC,MAAM,CACd,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CACF,CAAC;IACF,KAAK,CAAC,CAAC,uBAAuB,EAAE,CAAC,IAAI,CACnC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,MAAM,CAAC,UAAU,CAAC,6CAA6C,EAAE;QAC/D,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;KACvB,CAAC,CACH,EACD,MAAM,CAAC,MAAM,CACd,CAAC;IAEF,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,QAAQ,CAAC,EAC9D,MAAiC;QAEjC,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7D,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACrF,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YAC3C,OAAO,KAAK,CAAC,CAAC,IAAI,qBAAqB,CAAC;gBACtC,MAAM;gBACN,UAAU,EAAE,WAAW;gBACvB,OAAO,EAAE,UAAU,MAAM,uCAAuC;gBAChE,KAAK,EAAE,IAAI,KAAK,CAAC,UAAU,CAAC;aAC7B,CAAC,CAAC;QACL,CAAC;QACD,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,OAAO,CAAC,OAAO,EAAE;YACpE,GAAG,OAAO,CAAC,IAAI;YACf,oBAAoB;SACrB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACX,IAAI,QAAQ,KAAK,MAAM,CAAC,cAAc,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACzD,OAAO,KAAK,CAAC,CAAC,IAAI,qBAAqB,CAAC;gBACtC,MAAM;gBACN,UAAU,EAAE,UAAU;gBACtB,OAAO,EAAE,UAAU,MAAM,0BAA0B,QAAQ,IAAI,SAAS,cAAc,cAAc,CAAC,gBAAgB,EAAE;gBACvH,KAAK,EAAE,IAAI,KAAK,CAAC,4BAA4B,CAAC;aAC/C,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,2BAA2B,EAAE;YACjD,MAAM;YACN,IAAI,EAAE,OAAO;YACb,UAAU;YACV,eAAe,EAAE,cAAc,CAAC,gBAAgB;SACjD,CAAC,CAAC;IACL,CAAC,EAAE,mBAAmB,CAAC,CAAC;IAExB,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAwB;QACpF,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC;YAChC,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,IAAI,EAAE,OAAO;YACb,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QACnF,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACvF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;QACnF,MAAM,WAAW,GAAG,qBAAqB,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;QACvE,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAW,CAAC;QACvE,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,6BAA6B,EAAE;YACnD,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,KAAK;YACL,QAAQ;SACT,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,CAAC,MAAc,EAAoD,EAAE,CAClF,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,MAAM,GAAG,GAAuE;YAC9E,WAAW,EAAE,MAAM,CAAC,OAAO,CACzB,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAClE,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CACtE;YACD,UAAU,EAAE,MAAM;YAClB,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC;YACrC,cAAc,EAAE,UAAU,CAAC,MAAM,CAAC,GAAG,KAAK,UAAU,EAAE,KAAK,CAAC;YAC5D,GAAG,EAAE,CAAC,IAA2B,EAAiD,EAAE,CAClF,cAAc,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,CAAC;SACzD,CAAC;QACF,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,OAAO;aAC5B,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAC3B,iBAAiB,CAAC;YAChB,OAAO;YACP,GAAG,EAAE,aAAa,CAAC,OAAO,CAAC,UAAU,CAAC;YACtC,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,KAAK,UAAU,EAAE,QAAQ,EAAE;YACxD,GAAG;SACJ,CAAC,CACH;aACA,IAAI,CACH,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,eAAe,CAAC,KAAK,CAAC;YACpB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,aAAa,CAAC,SAAS,EAAE,sCAAsC,EAAE,KAAK,CAAC,CAC5E,EACD,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAClB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CACvE,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,MAAM,CAAC,UAAU,CAAC,4CAA4C,EAAE;gBAC9D,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,IAAI,EAAE,OAAO;gBACb,QAAQ;gBACR,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;aACvB,CAAC,CACH,EACD,MAAM,CAAC,MAAM,CACd,CAAC;YACF,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAClC,CAAC,CAAC,CACH,CACF,CAAC;QAEJ,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,OAAO,EAAE,EAAE;YAC5C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;YAC9B,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,yBAAyB,EAAE;YAC/C,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU;YACpC,QAAQ;SACT,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,4BAA4B,CAAC,CAAC,QAAQ,CAAC,EAC7D,QAAyB,EACzB,KAAmB;QAEnB,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;QAC1C,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC;YAChC,SAAS;YACT,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC,CAAC,IAAI,cAAc,CAAC,YAAY,CAAC;gBAC5C,OAAO,EAAE,WAAW,SAAS,6BAA6B;gBAC1D,KAAK,EAAE,IAAI,KAAK,CAAC,gCAAgC,CAAC;aACnD,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,wBAAwB,EAAE;YAC9C,SAAS;YACT,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;SAC5B,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CACjC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;YAC/C,GAAG,EAAE,QAAQ,CAAC,QAAQ;YACtB,GAAG,EAAE,qBAAqB,CAAC,eAAe,EAAE,MAAM,CAAC,UAAU,CAAC;YAC9D,SAAS,EAAE,KAAK;YAChB,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;SAC5D,CAAC,CACH,CAAC;QACF,OAAO;YACL,MAAM;YACN,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC;SACnE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,iBAAiB,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;IAEpE,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAyB;QACrF,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;QAC1C,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC;YAChC,SAAS;YACT,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;QACH,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,4BAA4B,EAAE;YAClD,SAAS;YACT,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,IAAI,EAAE,OAAO;YACb,QAAQ,EAAE,QAAQ,CAAC,QAAQ;SAC5B,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC9D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,CAAC,UAAU;iBACd,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;iBAC3D,IAAI,CACH,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,aAAa,CAAC,SAAS,EAAE,oBAAoB,QAAQ,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC,CACzE,CACF,CAAC;YACJ,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YACjC,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE;gBAClD,WAAW;gBACX,KAAK,CAAC,KAAK;gBACX,UAAU;gBACV,QAAQ;gBACR,SAAS;gBACT,QAAQ,CAAC,QAAQ;aAClB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACvB,MAAM,eAAe,GAAG,KAAK,CAAC,CAAC,UAAU;iBACtC,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;iBAC3D,IAAI,CACH,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,aAAa,CAAC,SAAS,EAAE,oBAAoB,QAAQ,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC,CACzE,EACD,MAAM,CAAC,MAAM,CACd,CAAC;YACJ,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE;gBAC1C,WAAW;gBACX,KAAK,CAAC,KAAK;gBACX,UAAU;gBACV,OAAO;aACR,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACvB,KAAK,MAAM,MAAM,IAAI,CAAC,cAAc,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,CAAC;gBAC/D,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC7B,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;gBAC/B,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,eAAe,CAAC,KAAK,CAAC;YACpB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,aAAa,CAAC,SAAS,EAAE,2BAA2B,SAAS,EAAE,EAAE,KAAK,CAAC,CAC5E,CACF,CAAC;QACF,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAChB,MAAM,CAAC,QAAQ,CACb,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,OAAO,EAAE,EAAE;gBAC5C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC9B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBACvB,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,CAAC;YACH,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACxC,CAAC,CAAC,CACH,CACF,CAAC;QACF,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,2BAA2B,EAAE;YACjD,SAAS;YACT,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,EAAE,CAAC;QACjB,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO;QACP,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,SAAS;QACT,OAAO;KACR,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,wEAAwE;AACxE,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,OAA6B,EAK7B,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { ExecutorOperationError, PreparedAttempt, type CheckoutRequest } from "./index.ts";
|
|
3
|
+
export declare const safeSegment: (value: string) => string;
|
|
4
|
+
export interface WorkspaceLayout {
|
|
5
|
+
readonly cache: string;
|
|
6
|
+
readonly staging: string;
|
|
7
|
+
readonly worktree: string;
|
|
8
|
+
}
|
|
9
|
+
/** The adapter-specific primitives; everything else about provisioning is shared. */
|
|
10
|
+
export interface WorkspaceOps<E> {
|
|
11
|
+
readonly ensureRoots: Effect.Effect<void, E>;
|
|
12
|
+
readonly removePath: (target: string) => Effect.Effect<void, E>;
|
|
13
|
+
readonly cacheExists: Effect.Effect<boolean, E>;
|
|
14
|
+
/** Atomically promote the finished staging clone to the cache path. */
|
|
15
|
+
readonly promoteStaging: Effect.Effect<void, E>;
|
|
16
|
+
readonly git: (args: ReadonlyArray<string>) => Effect.Effect<string, E>;
|
|
17
|
+
}
|
|
18
|
+
export interface ProvisionOptions<E> {
|
|
19
|
+
readonly request: CheckoutRequest;
|
|
20
|
+
readonly url: string;
|
|
21
|
+
readonly host: string;
|
|
22
|
+
readonly layout: WorkspaceLayout;
|
|
23
|
+
readonly ops: WorkspaceOps<E>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* One canonical cached-clone-to-worktree choreography shared by every
|
|
27
|
+
* Executor: clone into a staging sibling and promote on success (an
|
|
28
|
+
* interrupted clone must never leave a half-initialized cache that every
|
|
29
|
+
* later fetch for the repository would poison), fetch the requested
|
|
30
|
+
* revision, and check out a detached worktree at the resolved commit.
|
|
31
|
+
*/
|
|
32
|
+
export declare const provisionWorktree: <E>(options: ProvisionOptions<E>) => Effect.Effect<PreparedAttempt, E | ExecutorOperationError, never>;
|
|
33
|
+
//# sourceMappingURL=provision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provision.d.ts","sourceRoot":"","sources":["../src/provision.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AACxC,OAAO,EACL,sBAAsB,EACtB,eAAe,EAEf,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,WAAW,UAAW,MAAM,KAAG,MAAoD,CAAC;AAIjG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,qFAAqF;AACrF,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAChE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAChD,uEAAuE;IACvE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAChD,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;CACzE;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAsD,CAAC,oGA6EnF,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { AttemptChannel, Repository } from "@usine/core";
|
|
2
|
+
import { Effect, Schema } from "effect";
|
|
3
|
+
import { ExecutorOperationError, PreparedAttempt, WorktreePath, } from "./index.js";
|
|
4
|
+
export const safeSegment = (value) => value.replaceAll(/[^A-Za-z0-9_.-]/gu, "_");
|
|
5
|
+
const decodeCommit = Schema.decodeUnknownEffect(Repository.CommitSha);
|
|
6
|
+
/**
|
|
7
|
+
* One canonical cached-clone-to-worktree choreography shared by every
|
|
8
|
+
* Executor: clone into a staging sibling and promote on success (an
|
|
9
|
+
* interrupted clone must never leave a half-initialized cache that every
|
|
10
|
+
* later fetch for the repository would poison), fetch the requested
|
|
11
|
+
* revision, and check out a detached worktree at the resolved commit.
|
|
12
|
+
*/
|
|
13
|
+
export const provisionWorktree = Effect.fn("Executor.provisionWorktree")(function* (options) {
|
|
14
|
+
const { layout, ops, request } = options;
|
|
15
|
+
yield* Effect.annotateCurrentSpan({
|
|
16
|
+
attemptId: request.attemptId,
|
|
17
|
+
worker: request.worker,
|
|
18
|
+
host: options.host,
|
|
19
|
+
repository: request.repository,
|
|
20
|
+
});
|
|
21
|
+
yield* ops.ensureRoots;
|
|
22
|
+
yield* ops.removePath(layout.worktree);
|
|
23
|
+
if (yield* ops.cacheExists) {
|
|
24
|
+
yield* ops.git(["--git-dir", layout.cache, "remote", "set-url", "origin", options.url]);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
yield* ops.removePath(layout.staging);
|
|
28
|
+
yield* ops.git(["clone", "--bare", "--filter=blob:none", options.url, layout.staging]).pipe(Effect.onError(() => ops.removePath(layout.staging).pipe(Effect.tapError((error) => Effect.logWarning("Could not remove a partial clone", {
|
|
29
|
+
attemptId: request.attemptId,
|
|
30
|
+
worker: request.worker,
|
|
31
|
+
host: options.host,
|
|
32
|
+
staging: layout.staging,
|
|
33
|
+
message: String(error),
|
|
34
|
+
})), Effect.ignore)));
|
|
35
|
+
yield* ops.promoteStaging;
|
|
36
|
+
}
|
|
37
|
+
yield* ops.git([
|
|
38
|
+
"--git-dir",
|
|
39
|
+
layout.cache,
|
|
40
|
+
"fetch",
|
|
41
|
+
"--force",
|
|
42
|
+
"--prune",
|
|
43
|
+
"origin",
|
|
44
|
+
request.revision,
|
|
45
|
+
]);
|
|
46
|
+
const resolved = (yield* ops.git(["--git-dir", layout.cache, "rev-parse", "FETCH_HEAD"])).trim();
|
|
47
|
+
const baseCommit = yield* decodeCommit(resolved).pipe(Effect.mapError((cause) => new ExecutorOperationError({
|
|
48
|
+
operation: "prepare",
|
|
49
|
+
message: "git returned an invalid object id",
|
|
50
|
+
cause,
|
|
51
|
+
})));
|
|
52
|
+
yield* ops.git([
|
|
53
|
+
"--git-dir",
|
|
54
|
+
layout.cache,
|
|
55
|
+
"worktree",
|
|
56
|
+
"add",
|
|
57
|
+
"--detach",
|
|
58
|
+
layout.worktree,
|
|
59
|
+
baseCommit,
|
|
60
|
+
]);
|
|
61
|
+
return new PreparedAttempt({
|
|
62
|
+
worker: request.worker,
|
|
63
|
+
spec: new AttemptChannel.RunSpec({
|
|
64
|
+
attemptId: request.attemptId,
|
|
65
|
+
repository: request.repository,
|
|
66
|
+
revision: request.revision,
|
|
67
|
+
baseCommit,
|
|
68
|
+
payload: request.payload,
|
|
69
|
+
task: request.task,
|
|
70
|
+
agent: request.agent,
|
|
71
|
+
parentModel: request.parentModel,
|
|
72
|
+
}),
|
|
73
|
+
worktree: WorktreePath.make(layout.worktree),
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=provision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provision.js","sourceRoot":"","sources":["../src/provision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,YAAY,GAEb,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;AAEjG,MAAM,YAAY,GAAG,MAAM,CAAC,mBAAmB,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AA0BtE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,EAAE,CAAC,4BAA4B,CAAC,CAAC,QAAQ,CAAC,EAChF,OAA4B;IAE5B,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACzC,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC;QAChC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC,CAAC;IACH,KAAK,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;IACvB,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QAC3B,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1F,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACtC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CACzF,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAClB,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CACjC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,MAAM,CAAC,UAAU,CAAC,kCAAkC,EAAE;YACpD,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;SACvB,CAAC,CACH,EACD,MAAM,CAAC,MAAM,CACd,CACF,CACF,CAAC;QACF,KAAK,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC;IAC5B,CAAC;IACD,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QACb,WAAW;QACX,MAAM,CAAC,KAAK;QACZ,OAAO;QACP,SAAS;QACT,SAAS;QACT,QAAQ;QACR,OAAO,CAAC,QAAQ;KACjB,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACjG,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,IAAI,CACnD,MAAM,CAAC,QAAQ,CACb,CAAC,KAAK,EAAE,EAAE,CACR,IAAI,sBAAsB,CAAC;QACzB,SAAS,EAAE,SAAS;QACpB,OAAO,EAAE,mCAAmC;QAC5C,KAAK;KACN,CAAC,CACL,CACF,CAAC;IACF,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QACb,WAAW;QACX,MAAM,CAAC,KAAK;QACZ,UAAU;QACV,KAAK;QACL,UAAU;QACV,MAAM,CAAC,QAAQ;QACf,UAAU;KACX,CAAC,CAAC;IACH,OAAO,IAAI,eAAe,CAAC;QACzB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,IAAI,EAAE,IAAI,cAAc,CAAC,OAAO,CAAC;YAC/B,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,UAAU;YACV,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,WAAW,EAAE,OAAO,CAAC,WAAW;SACjC,CAAC;QACF,QAAQ,EAAE,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;KAC7C,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Attempt, AttemptChannel, AttemptFailure, StepResult } from "@usine/core";
|
|
2
|
+
import { Cause, Effect, Queue, Scope, type PlatformError } from "effect";
|
|
3
|
+
import type { ChildProcessHandle } from "effect/unstable/process/ChildProcessSpawner";
|
|
4
|
+
import { ExecutorError, type PreparedAttempt } from "./index.ts";
|
|
5
|
+
export interface SpawnedRunHost {
|
|
6
|
+
readonly handle: ChildProcessHandle;
|
|
7
|
+
readonly host: string;
|
|
8
|
+
/** Redacts the Attempt credential from any run-host output before it is persisted. */
|
|
9
|
+
readonly scrub: (text: string) => string;
|
|
10
|
+
}
|
|
11
|
+
export type RunHostInput = Queue.Queue<Uint8Array, Cause.Done>;
|
|
12
|
+
export interface RunHostSessionOptions {
|
|
13
|
+
readonly interruptGrace: Parameters<typeof Effect.timeoutOption>[1];
|
|
14
|
+
readonly spawn: (prepared: PreparedAttempt, input: RunHostInput) => Effect.Effect<SpawnedRunHost, AttemptFailure.AttemptFailure | PlatformError.PlatformError, Scope.Scope>;
|
|
15
|
+
}
|
|
16
|
+
export interface RunHostSession {
|
|
17
|
+
readonly cancel: (attemptId: Attempt.AttemptId) => Effect.Effect<void, ExecutorError>;
|
|
18
|
+
readonly launch: (prepared: PreparedAttempt, io: AttemptChannel.Sink) => Effect.Effect<StepResult.StepResult, AttemptFailure.AttemptFailure>;
|
|
19
|
+
}
|
|
20
|
+
/** One canonical byte-channel state machine shared by every process-backed Executor. */
|
|
21
|
+
export declare const runHostSessionFor: (options: RunHostSessionOptions) => Effect.Effect<RunHostSession>;
|
|
22
|
+
//# sourceMappingURL=run-host-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-host-session.d.ts","sourceRoot":"","sources":["../src/run-host-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EACL,KAAK,EAEL,MAAM,EAGN,KAAK,EAIL,KAAK,EAEL,KAAK,aAAa,EACnB,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6CAA6C,CAAC;AACtF,OAAO,EAAE,aAAa,EAA0B,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAGzF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC1C;AAED,MAAM,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;AAE/D,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,QAAQ,CAAC,KAAK,EAAE,CACd,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,YAAY,KAChB,MAAM,CAAC,MAAM,CAChB,cAAc,EACd,cAAc,CAAC,cAAc,GAAG,aAAa,CAAC,aAAa,EAC3D,KAAK,CAAC,KAAK,CACZ,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IACtF,QAAQ,CAAC,MAAM,EAAE,CACf,QAAQ,EAAE,eAAe,EACzB,EAAE,EAAE,cAAc,CAAC,IAAI,KACpB,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;CAC1E;AAwCD,wFAAwF;AACxF,eAAO,MAAM,iBAAiB,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,MAAM,CAAC,MAAM,CAAC,cAAc,CAqT5F,CAAC"}
|