@modelprofile.com/authswitch 6.3.0 → 6.5.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/authority-contract.d.ts +142 -0
- package/dist_ts/authority-contract.js +3 -0
- package/dist_ts/authority-runtime-contract.d.ts +34 -0
- package/dist_ts/authority-runtime-contract.js +2 -0
- package/dist_ts/classes.authoritybroker.d.ts +76 -0
- package/dist_ts/classes.authoritybroker.js +570 -0
- package/dist_ts/classes.authorityclient.d.ts +47 -0
- package/dist_ts/classes.authorityclient.js +261 -0
- package/dist_ts/classes.authoritydaemon.d.ts +46 -0
- package/dist_ts/classes.authoritydaemon.js +492 -0
- package/dist_ts/classes.authoritydatabase.d.ts +103 -0
- package/dist_ts/classes.authoritydatabase.js +835 -0
- package/dist_ts/classes.authorityframing.d.ts +8 -0
- package/dist_ts/classes.authorityframing.js +22 -0
- package/dist_ts/classes.authoritymodels.d.ts +239 -0
- package/dist_ts/classes.authoritymodels.js +893 -0
- package/dist_ts/classes.authoritysecrets.d.ts +9 -0
- package/dist_ts/classes.authoritysecrets.js +30 -0
- package/dist_ts/classes.authorityservice.d.ts +28 -0
- package/dist_ts/classes.authorityservice.js +71 -0
- package/dist_ts/classes.codexmanaged.d.ts +80 -0
- package/dist_ts/classes.codexmanaged.js +343 -0
- package/dist_ts/index.d.ts +3 -0
- package/dist_ts/index.js +27 -1
- package/dist_ts/plugins.d.ts +11 -3
- package/dist_ts/plugins.js +12 -4
- package/package.json +25 -4
- package/readme.md +59 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/authority-contract.ts +109 -0
- package/ts/authority-runtime-contract.ts +33 -0
- package/ts/classes.authoritybroker.ts +552 -0
- package/ts/classes.authorityclient.ts +252 -0
- package/ts/classes.authoritydaemon.ts +403 -0
- package/ts/classes.authoritydatabase.ts +818 -0
- package/ts/classes.authorityframing.ts +21 -0
- package/ts/classes.authoritymodels.ts +407 -0
- package/ts/classes.authoritysecrets.ts +27 -0
- package/ts/classes.authorityservice.ts +83 -0
- package/ts/classes.codexmanaged.ts +339 -0
- package/ts/index.ts +26 -0
- package/ts/plugins.ts +11 -3
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { AuthSwitchAuthorityBroker } from './classes.authoritybroker.js';
|
|
3
|
+
import { AuthSwitchAuthorityDatabase } from './classes.authoritydatabase.js';
|
|
4
|
+
import { AuthSwitchAuthorityFrameReader, authSwitchAuthorityFrameBytes, maxAuthSwitchAuthorityFrameBytes } from './classes.authorityframing.js';
|
|
5
|
+
import { AuthSwitchManagedCodex, findManagedCodexProcess } from './classes.codexmanaged.js';
|
|
6
|
+
const hasKeys = (value, keys) => value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
7
|
+
&& Object.keys(value).length === keys.length && keys.every(key => Object.hasOwn(value, key));
|
|
8
|
+
const invalid = () => { throw new plugins.typedrequest.TypedResponseError('Invalid authswitch authority request.'); };
|
|
9
|
+
/** TypedRequest handlers over a private one-request-per-connection Unix socket. */
|
|
10
|
+
export class AuthSwitchAuthorityDaemon {
|
|
11
|
+
options;
|
|
12
|
+
database;
|
|
13
|
+
broker;
|
|
14
|
+
managementRouter = new plugins.typedrequest.TypedRouter();
|
|
15
|
+
runtimeRouter = new plugins.typedrequest.TypedRouter();
|
|
16
|
+
managementServer;
|
|
17
|
+
runtimeServer;
|
|
18
|
+
sockets = new Set();
|
|
19
|
+
managedCodex = new Map();
|
|
20
|
+
managedCodexHomes = new Set();
|
|
21
|
+
managedCodexAccountIds = new Map();
|
|
22
|
+
drainingAccounts = new Set();
|
|
23
|
+
managedCodexStops = new Map();
|
|
24
|
+
managedCodexFailures = [];
|
|
25
|
+
closing = false;
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
this.database = new AuthSwitchAuthorityDatabase(options);
|
|
29
|
+
this.broker = new AuthSwitchAuthorityBroker(this.database, options.broker);
|
|
30
|
+
this.register();
|
|
31
|
+
}
|
|
32
|
+
register() {
|
|
33
|
+
this.managementRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('authswitch.authority.snapshot', async (request) => {
|
|
34
|
+
if (request === null || typeof request !== 'object' || Array.isArray(request))
|
|
35
|
+
invalid();
|
|
36
|
+
const keys = Object.keys(request);
|
|
37
|
+
if (keys.some(key => !['accountAfter', 'bindingAfter', 'limit'].includes(key)))
|
|
38
|
+
invalid();
|
|
39
|
+
return { snapshot: await this.broker.snapshot(request) };
|
|
40
|
+
}));
|
|
41
|
+
this.managementRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('authswitch.authority.events', async (request, tools) => {
|
|
42
|
+
if (!hasKeys(request, ['epoch', 'afterRevision', 'waitMs']))
|
|
43
|
+
invalid();
|
|
44
|
+
return this.broker.events(request.epoch, request.afterRevision, request.waitMs, tools?.abortSignal);
|
|
45
|
+
}));
|
|
46
|
+
this.managementRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('authswitch.authority.add', async (request) => {
|
|
47
|
+
if (!hasKeys(request, ['providerId', 'flow']) || request.providerId !== 'openai' || request.flow !== 'device')
|
|
48
|
+
invalid();
|
|
49
|
+
return { operation: await this.broker.beginAddOpenAi() };
|
|
50
|
+
}));
|
|
51
|
+
this.managementRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('authswitch.authority.reauth', async (request) => {
|
|
52
|
+
if (!hasKeys(request, ['accountId', 'flow']) || request.flow !== 'device' || typeof request.accountId !== 'string')
|
|
53
|
+
invalid();
|
|
54
|
+
if (this.drainingAccounts.has(request.accountId))
|
|
55
|
+
throw new Error('Account runtime drain is already in progress.');
|
|
56
|
+
this.drainingAccounts.add(request.accountId);
|
|
57
|
+
try {
|
|
58
|
+
await this.drainManagedCodexAccount(request.accountId);
|
|
59
|
+
const operation = await this.broker.beginReauthOpenAi(request.accountId);
|
|
60
|
+
void this.broker.waitOperation(operation.id).finally(() => this.drainingAccounts.delete(request.accountId)).catch(() => { });
|
|
61
|
+
return { operation };
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
this.drainingAccounts.delete(request.accountId);
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}));
|
|
68
|
+
this.managementRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('authswitch.authority.operation', async (request) => {
|
|
69
|
+
if (!hasKeys(request, ['operationId']) || typeof request.operationId !== 'string')
|
|
70
|
+
invalid();
|
|
71
|
+
return { operation: this.broker.getOperation(request.operationId) };
|
|
72
|
+
}));
|
|
73
|
+
this.managementRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('authswitch.authority.cancel', async (request) => {
|
|
74
|
+
if (!hasKeys(request, ['operationId']) || typeof request.operationId !== 'string')
|
|
75
|
+
invalid();
|
|
76
|
+
return { operation: await this.broker.cancelOperation(request.operationId) };
|
|
77
|
+
}));
|
|
78
|
+
this.managementRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('authswitch.authority.rename', async (request) => {
|
|
79
|
+
if (!hasKeys(request, ['accountId', 'expectedRevision', 'label']) || typeof request.accountId !== 'string'
|
|
80
|
+
|| typeof request.expectedRevision !== 'number' || typeof request.label !== 'string')
|
|
81
|
+
invalid();
|
|
82
|
+
return { account: await this.broker.renameAccount(request.accountId, request.expectedRevision, request.label) };
|
|
83
|
+
}));
|
|
84
|
+
this.managementRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('authswitch.authority.remove', async (request) => {
|
|
85
|
+
if (!hasKeys(request, ['accountId', 'expectedRevision']) || typeof request.accountId !== 'string'
|
|
86
|
+
|| typeof request.expectedRevision !== 'number')
|
|
87
|
+
invalid();
|
|
88
|
+
if (this.drainingAccounts.has(request.accountId))
|
|
89
|
+
throw new Error('Account runtime drain is already in progress.');
|
|
90
|
+
this.drainingAccounts.add(request.accountId);
|
|
91
|
+
try {
|
|
92
|
+
await this.drainManagedCodexAccount(request.accountId);
|
|
93
|
+
return { account: await this.broker.removeAccount(request.accountId, request.expectedRevision) };
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
this.drainingAccounts.delete(request.accountId);
|
|
97
|
+
}
|
|
98
|
+
}));
|
|
99
|
+
this.managementRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('authswitch.authority.bind', async (request) => {
|
|
100
|
+
if (!hasKeys(request, ['accountId', 'runtime', 'scopeId', 'incarnationId'])
|
|
101
|
+
|| typeof request.accountId !== 'string' || typeof request.scopeId !== 'string'
|
|
102
|
+
|| typeof request.incarnationId !== 'string')
|
|
103
|
+
invalid();
|
|
104
|
+
return this.broker.bindAccount(request);
|
|
105
|
+
}));
|
|
106
|
+
this.runtimeRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('authswitch.authority.resolveAccess', async (request) => {
|
|
107
|
+
if ((typeof request !== 'object' || request === null || Array.isArray(request))
|
|
108
|
+
|| !['bindingId', 'capability', 'minValidityMs'].every(key => Object.hasOwn(request, key))
|
|
109
|
+
|| Object.keys(request).some(key => !['bindingId', 'capability', 'minValidityMs',
|
|
110
|
+
'rejectedGrantGeneration'].includes(key))
|
|
111
|
+
|| typeof request.bindingId !== 'string' || typeof request.capability !== 'string'
|
|
112
|
+
|| typeof request.minValidityMs !== 'number'
|
|
113
|
+
|| (request.rejectedGrantGeneration !== undefined && typeof request.rejectedGrantGeneration !== 'number'))
|
|
114
|
+
invalid();
|
|
115
|
+
return this.broker.resolveAccess(request.bindingId, request.capability, request.minValidityMs, request.rejectedGrantGeneration);
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
async start() {
|
|
119
|
+
if (this.managementServer || this.runtimeServer)
|
|
120
|
+
throw new Error('Authswitch authority daemon is already started.');
|
|
121
|
+
await this.database.start();
|
|
122
|
+
try {
|
|
123
|
+
await this.broker.start();
|
|
124
|
+
const managementDirectory = plugins.path.dirname(this.options.authoritySocketPath);
|
|
125
|
+
const runtimeDirectory = plugins.path.dirname(this.options.runtimeSocketPath);
|
|
126
|
+
const databaseDirectory = plugins.path.dirname(this.options.socketPath);
|
|
127
|
+
if (managementDirectory === runtimeDirectory || databaseDirectory === runtimeDirectory
|
|
128
|
+
|| managementDirectory.startsWith(runtimeDirectory + plugins.path.sep)
|
|
129
|
+
|| databaseDirectory.startsWith(runtimeDirectory + plugins.path.sep)
|
|
130
|
+
|| runtimeDirectory.startsWith(managementDirectory + plugins.path.sep)
|
|
131
|
+
|| runtimeDirectory.startsWith(databaseDirectory + plugins.path.sep)) {
|
|
132
|
+
throw new Error('Runtime socket directory must contain no management or database endpoint.');
|
|
133
|
+
}
|
|
134
|
+
this.managementServer = await this.listen(this.options.authoritySocketPath, this.managementRouter);
|
|
135
|
+
this.runtimeServer = await this.listen(this.options.runtimeSocketPath, this.runtimeRouter);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
try {
|
|
139
|
+
await this.close();
|
|
140
|
+
}
|
|
141
|
+
catch { /* Preserve startup failure. */ }
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** Trusted in-process SDK admission; management RPC exposure belongs to the later CLI cutover. */
|
|
146
|
+
async drainManagedCodexAccount(accountId) {
|
|
147
|
+
const scopes = [...this.managedCodexAccountIds]
|
|
148
|
+
.filter(([, assignedAccountId]) => assignedAccountId === accountId).map(([scopeId]) => scopeId);
|
|
149
|
+
const results = await Promise.allSettled(scopes.map(scopeId => this.stopManagedCodex(scopeId)));
|
|
150
|
+
const failed = results.filter((result) => result.status === 'rejected');
|
|
151
|
+
if (failed.length)
|
|
152
|
+
throw new AggregateError(failed.map(result => result.reason), 'Managed Codex account drain failed.');
|
|
153
|
+
}
|
|
154
|
+
async startManagedCodex(input) {
|
|
155
|
+
if (!plugins.path.isAbsolute(input.codexHomeDirectory)
|
|
156
|
+
|| plugins.path.normalize(input.codexHomeDirectory) !== input.codexHomeDirectory) {
|
|
157
|
+
throw new Error('Managed Codex requires a normalized absolute state home.');
|
|
158
|
+
}
|
|
159
|
+
const homeId = plugins.crypto.createHash('sha256').update(JSON.stringify(['authswitch-codex-home-v1', input.codexHomeDirectory])).digest('hex');
|
|
160
|
+
if (this.closing || !this.managementServer || !this.runtimeServer
|
|
161
|
+
|| this.managedCodex.has(input.scopeId) || this.managedCodexStops.has(input.scopeId)
|
|
162
|
+
|| this.managedCodexHomes.has(homeId) || this.drainingAccounts.has(input.accountId)) {
|
|
163
|
+
throw new Error('Managed Codex scope is unavailable.');
|
|
164
|
+
}
|
|
165
|
+
this.managedCodexHomes.add(homeId);
|
|
166
|
+
this.managedCodexAccountIds.set(input.scopeId, input.accountId);
|
|
167
|
+
const runId = plugins.crypto.randomUUID();
|
|
168
|
+
const task = (async () => {
|
|
169
|
+
let bound;
|
|
170
|
+
let runtime;
|
|
171
|
+
let claimed = false;
|
|
172
|
+
try {
|
|
173
|
+
const home = input.codexHomeDirectory;
|
|
174
|
+
const parent = plugins.path.dirname(home);
|
|
175
|
+
const parentStat = await plugins.fs.promises.lstat(parent);
|
|
176
|
+
if (!parentStat.isDirectory() || parentStat.isSymbolicLink() || parentStat.uid !== process.getuid?.()
|
|
177
|
+
|| (parentStat.mode & 0o077) !== 0 || await plugins.fs.promises.realpath(parent) !== parent) {
|
|
178
|
+
throw new Error('Managed Codex home parent must be private and owned by this user.');
|
|
179
|
+
}
|
|
180
|
+
const nativeHomes = [plugins.path.join(plugins.os.homedir(), '.codex'), process.env.CODEX_HOME]
|
|
181
|
+
.filter((value) => typeof value === 'string' && plugins.path.isAbsolute(value));
|
|
182
|
+
if (nativeHomes.some(native => home === native || home.startsWith(native + plugins.path.sep)
|
|
183
|
+
|| native.startsWith(home + plugins.path.sep))) {
|
|
184
|
+
throw new Error('Managed Codex cannot adopt an active native Codex home.');
|
|
185
|
+
}
|
|
186
|
+
const existing = await this.database.readCodexHome(homeId);
|
|
187
|
+
if (existing && (existing.accountId !== input.accountId || existing.scopeId !== input.scopeId)) {
|
|
188
|
+
throw new Error('Managed Codex home already belongs to another account or scope.');
|
|
189
|
+
}
|
|
190
|
+
let homeExists = false;
|
|
191
|
+
try {
|
|
192
|
+
const stat = await plugins.fs.promises.lstat(home);
|
|
193
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid?.()
|
|
194
|
+
|| (stat.mode & 0o077) !== 0 || await plugins.fs.promises.realpath(home) !== home) {
|
|
195
|
+
throw new Error('Managed Codex home is not a private owned directory.');
|
|
196
|
+
}
|
|
197
|
+
homeExists = true;
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
if (!(error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT'))
|
|
201
|
+
throw error;
|
|
202
|
+
}
|
|
203
|
+
if (!existing && homeExists && (await plugins.fs.promises.readdir(home)).length) {
|
|
204
|
+
throw new Error('An existing Codex home needs explicit native-owner handoff before enrollment.');
|
|
205
|
+
}
|
|
206
|
+
await this.database.reserveCodexHome(input.accountId, input.scopeId, homeId, plugins.crypto.randomUUID());
|
|
207
|
+
if (!homeExists)
|
|
208
|
+
await plugins.fs.promises.mkdir(home, { mode: 0o700 });
|
|
209
|
+
bound = await this.broker.bindAccount({ accountId: input.accountId, runtime: 'codex',
|
|
210
|
+
scopeId: input.scopeId, incarnationId: plugins.crypto.randomUUID() });
|
|
211
|
+
runtime = new AuthSwitchManagedCodex({
|
|
212
|
+
runtimeDirectory: plugins.path.join(plugins.path.dirname(plugins.path.dirname(this.options.authoritySocketPath)), 'managed-codex'),
|
|
213
|
+
codexHomeDirectory: home, workspaceDirectory: input.workspaceDirectory, executable: input.executable,
|
|
214
|
+
onNotification: input.onNotification, onServerRequest: input.onServerRequest,
|
|
215
|
+
broker: this.broker, bindingId: bound.binding.id, capability: bound.capability,
|
|
216
|
+
onPreparedRun: async (socketPath) => {
|
|
217
|
+
const assigned = await this.database.readCodexHome(homeId);
|
|
218
|
+
if (!assigned || assigned.accountId !== input.accountId || assigned.scopeId !== input.scopeId) {
|
|
219
|
+
throw new Error('Managed Codex home assignment changed.');
|
|
220
|
+
}
|
|
221
|
+
if (assigned.activeRun) {
|
|
222
|
+
const survivor = await findManagedCodexProcess(assigned.activeRun.socketPath);
|
|
223
|
+
if (survivor)
|
|
224
|
+
throw new Error('Managed Codex home still has a live app-server owner.');
|
|
225
|
+
await this.database.changeCodexRun(homeId, assigned.activeRun.id, null, plugins.crypto.randomUUID());
|
|
226
|
+
}
|
|
227
|
+
await this.database.changeCodexRun(homeId, null, { id: runId, socketPath, pid: null, startedAt: null }, plugins.crypto.randomUUID());
|
|
228
|
+
claimed = true;
|
|
229
|
+
},
|
|
230
|
+
onChildSpawned: async (pid, startedAt) => {
|
|
231
|
+
const assigned = await this.database.readCodexHome(homeId);
|
|
232
|
+
if (assigned?.activeRun?.id !== runId || assigned.activeRun.pid !== null) {
|
|
233
|
+
throw new Error('Managed Codex run registration changed before process verification.');
|
|
234
|
+
}
|
|
235
|
+
await this.database.changeCodexRun(homeId, runId, { ...assigned.activeRun, pid, startedAt }, plugins.crypto.randomUUID());
|
|
236
|
+
},
|
|
237
|
+
onUnavailable: () => {
|
|
238
|
+
void this.stopManagedCodex(input.scopeId).catch(error => {
|
|
239
|
+
this.managedCodexFailures.push(error);
|
|
240
|
+
process.stderr.write('Managed Codex cleanup failed after its control connection closed.\n');
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
await runtime.start();
|
|
245
|
+
if (this.closing)
|
|
246
|
+
throw new Error('Managed Codex admission closed during startup.');
|
|
247
|
+
return { runtime, bindingId: bound.binding.id, capability: bound.capability, homeId, runId };
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
const cleanupErrors = [];
|
|
251
|
+
if (runtime)
|
|
252
|
+
try {
|
|
253
|
+
await runtime.close();
|
|
254
|
+
}
|
|
255
|
+
catch (cleanupError) {
|
|
256
|
+
cleanupErrors.push(cleanupError);
|
|
257
|
+
}
|
|
258
|
+
if (claimed && cleanupErrors.length === 0)
|
|
259
|
+
try {
|
|
260
|
+
await this.database.changeCodexRun(homeId, runId, null, plugins.crypto.randomUUID());
|
|
261
|
+
}
|
|
262
|
+
catch (cleanupError) {
|
|
263
|
+
cleanupErrors.push(cleanupError);
|
|
264
|
+
}
|
|
265
|
+
if (bound)
|
|
266
|
+
try {
|
|
267
|
+
await this.broker.revokeBinding(bound.binding.id, bound.capability);
|
|
268
|
+
}
|
|
269
|
+
catch (cleanupError) {
|
|
270
|
+
cleanupErrors.push(cleanupError);
|
|
271
|
+
}
|
|
272
|
+
if (cleanupErrors.length === 0) {
|
|
273
|
+
this.managedCodexHomes.delete(homeId);
|
|
274
|
+
this.managedCodexAccountIds.delete(input.scopeId);
|
|
275
|
+
}
|
|
276
|
+
if (cleanupErrors.length)
|
|
277
|
+
throw new AggregateError([error, ...cleanupErrors], 'Managed Codex admission cleanup failed.');
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
})();
|
|
281
|
+
this.managedCodex.set(input.scopeId, task);
|
|
282
|
+
try {
|
|
283
|
+
return (await task).runtime;
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
this.managedCodex.delete(input.scopeId);
|
|
287
|
+
throw error;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
stopManagedCodex(scopeId) {
|
|
291
|
+
const existing = this.managedCodexStops.get(scopeId);
|
|
292
|
+
if (existing)
|
|
293
|
+
return existing;
|
|
294
|
+
const task = this.managedCodex.get(scopeId);
|
|
295
|
+
if (!task)
|
|
296
|
+
return Promise.resolve();
|
|
297
|
+
this.managedCodex.delete(scopeId);
|
|
298
|
+
const stopping = (async () => {
|
|
299
|
+
let entry;
|
|
300
|
+
try {
|
|
301
|
+
entry = await task;
|
|
302
|
+
}
|
|
303
|
+
catch { /* Failed admission already closed its process and revoked its binding. */
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const { runtime, bindingId, capability, homeId, runId } = entry;
|
|
307
|
+
const errors = [];
|
|
308
|
+
try {
|
|
309
|
+
await runtime.close();
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
errors.push(error);
|
|
313
|
+
}
|
|
314
|
+
if (errors.length === 0)
|
|
315
|
+
try {
|
|
316
|
+
await this.database.changeCodexRun(homeId, runId, null, plugins.crypto.randomUUID());
|
|
317
|
+
this.managedCodexHomes.delete(homeId);
|
|
318
|
+
this.managedCodexAccountIds.delete(scopeId);
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
errors.push(error);
|
|
322
|
+
}
|
|
323
|
+
try {
|
|
324
|
+
await this.broker.revokeBinding(bindingId, capability);
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
errors.push(error);
|
|
328
|
+
}
|
|
329
|
+
if (errors.length)
|
|
330
|
+
throw new AggregateError(errors, 'Managed Codex shutdown was incomplete.');
|
|
331
|
+
})();
|
|
332
|
+
this.managedCodexStops.set(scopeId, stopping);
|
|
333
|
+
void stopping.finally(() => { if (this.managedCodexStops.get(scopeId) === stopping)
|
|
334
|
+
this.managedCodexStops.delete(scopeId); }).catch(() => { });
|
|
335
|
+
return stopping;
|
|
336
|
+
}
|
|
337
|
+
async listen(path, router) {
|
|
338
|
+
const directory = plugins.path.dirname(path);
|
|
339
|
+
await plugins.fs.promises.mkdir(directory, { recursive: true, mode: 0o700 });
|
|
340
|
+
const stat = await plugins.fs.promises.lstat(directory);
|
|
341
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid?.()) {
|
|
342
|
+
throw new Error('Authswitch authority socket directory is not private.');
|
|
343
|
+
}
|
|
344
|
+
await plugins.fs.promises.chmod(directory, 0o700);
|
|
345
|
+
await this.clearStaleSocket(path);
|
|
346
|
+
const server = plugins.net.createServer(socket => this.accept(socket, router));
|
|
347
|
+
try {
|
|
348
|
+
await new Promise((resolve, reject) => {
|
|
349
|
+
server.once('error', reject);
|
|
350
|
+
server.listen(path, () => { server.off('error', reject); resolve(); });
|
|
351
|
+
});
|
|
352
|
+
await plugins.fs.promises.chmod(path, 0o600);
|
|
353
|
+
return server;
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
if (server.listening)
|
|
357
|
+
await new Promise(resolve => server.close(() => resolve()));
|
|
358
|
+
throw error;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/** A killed daemon leaves a pathname behind; only remove an unchanged, owned, refused Unix socket. */
|
|
362
|
+
async clearStaleSocket(path) {
|
|
363
|
+
let before;
|
|
364
|
+
try {
|
|
365
|
+
before = await plugins.fs.promises.lstat(path);
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
if (error.code === 'ENOENT')
|
|
369
|
+
return;
|
|
370
|
+
throw error;
|
|
371
|
+
}
|
|
372
|
+
if (!before.isSocket() || before.uid !== process.getuid?.())
|
|
373
|
+
throw new Error('Authswitch socket path is unsafe.');
|
|
374
|
+
const refused = await new Promise((resolve, reject) => {
|
|
375
|
+
const probe = plugins.net.createConnection(path);
|
|
376
|
+
probe.setTimeout(1_000, () => { probe.destroy(); reject(new Error('Authswitch socket probe timed out.')); });
|
|
377
|
+
probe.once('connect', () => { probe.destroy(); resolve(false); });
|
|
378
|
+
probe.once('error', error => {
|
|
379
|
+
probe.destroy();
|
|
380
|
+
if (error.code === 'ECONNREFUSED')
|
|
381
|
+
resolve(true);
|
|
382
|
+
else
|
|
383
|
+
reject(error);
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
if (!refused)
|
|
387
|
+
throw new Error('Authswitch authority socket is already active.');
|
|
388
|
+
const after = await plugins.fs.promises.lstat(path);
|
|
389
|
+
if (!after.isSocket() || after.uid !== before.uid || after.dev !== before.dev || after.ino !== before.ino) {
|
|
390
|
+
throw new Error('Authswitch socket path changed during startup.');
|
|
391
|
+
}
|
|
392
|
+
await plugins.fs.promises.unlink(path);
|
|
393
|
+
}
|
|
394
|
+
accept(socket, router) {
|
|
395
|
+
this.sockets.add(socket);
|
|
396
|
+
const abort = new AbortController();
|
|
397
|
+
socket.on('close', () => { this.sockets.delete(socket); abort.abort(); });
|
|
398
|
+
const frame = new AuthSwitchAuthorityFrameReader();
|
|
399
|
+
let handled = false;
|
|
400
|
+
socket.setTimeout(35_000, () => socket.destroy());
|
|
401
|
+
socket.on('data', chunk => {
|
|
402
|
+
if (handled) {
|
|
403
|
+
socket.destroy();
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (!Buffer.isBuffer(chunk)) {
|
|
407
|
+
socket.destroy();
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
let input;
|
|
411
|
+
try {
|
|
412
|
+
input = frame.add(chunk);
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
socket.destroy();
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
if (input === null)
|
|
419
|
+
return;
|
|
420
|
+
handled = true;
|
|
421
|
+
let request;
|
|
422
|
+
try {
|
|
423
|
+
request = JSON.parse(input);
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
socket.destroy();
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
void router.routeAndAddResponse(request, { trustedLocalData: { authoritySocket: socket },
|
|
430
|
+
trustedAbortSignal: abort.signal })
|
|
431
|
+
.then(response => {
|
|
432
|
+
const raw = JSON.stringify(response);
|
|
433
|
+
if (authSwitchAuthorityFrameBytes(raw) > maxAuthSwitchAuthorityFrameBytes) {
|
|
434
|
+
socket.destroy();
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
socket.end(raw + '\n');
|
|
438
|
+
}).catch(() => socket.destroy());
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
async close() {
|
|
442
|
+
this.closing = true;
|
|
443
|
+
const errors = [];
|
|
444
|
+
for (const scopeId of [...this.managedCodex.keys()]) {
|
|
445
|
+
try {
|
|
446
|
+
await this.stopManagedCodex(scopeId);
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
errors.push(error);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
for (const stopping of [...this.managedCodexStops.values()]) {
|
|
453
|
+
try {
|
|
454
|
+
await stopping;
|
|
455
|
+
}
|
|
456
|
+
catch (error) {
|
|
457
|
+
errors.push(error);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
errors.push(...this.managedCodexFailures);
|
|
461
|
+
try {
|
|
462
|
+
await this.broker.close();
|
|
463
|
+
}
|
|
464
|
+
catch (error) {
|
|
465
|
+
errors.push(error);
|
|
466
|
+
}
|
|
467
|
+
const management = this.managementServer;
|
|
468
|
+
const runtime = this.runtimeServer;
|
|
469
|
+
this.managementServer = undefined;
|
|
470
|
+
this.runtimeServer = undefined;
|
|
471
|
+
for (const socket of this.sockets)
|
|
472
|
+
socket.destroy();
|
|
473
|
+
for (const server of [management, runtime]) {
|
|
474
|
+
if (server)
|
|
475
|
+
try {
|
|
476
|
+
await new Promise((resolve, reject) => server.close(error => error ? reject(error) : resolve()));
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
errors.push(error);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
try {
|
|
483
|
+
await this.database.stop();
|
|
484
|
+
}
|
|
485
|
+
catch (error) {
|
|
486
|
+
errors.push(error);
|
|
487
|
+
}
|
|
488
|
+
if (errors.length)
|
|
489
|
+
throw new AggregateError(errors, 'Authswitch authority shutdown was incomplete.');
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5hdXRob3JpdHlkYWVtb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLmF1dGhvcml0eWRhZW1vbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQU94QyxPQUFPLEVBQUUseUJBQXlCLEVBQTBDLE1BQU0sOEJBQThCLENBQUM7QUFDakgsT0FBTyxFQUFFLDJCQUEyQixFQUE0QyxNQUFNLGdDQUFnQyxDQUFDO0FBQ3ZILE9BQU8sRUFBRSw4QkFBOEIsRUFBRSw2QkFBNkIsRUFDcEUsZ0NBQWdDLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUMxRSxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsdUJBQXVCLEVBQXVDLE1BQU0sMkJBQTJCLENBQUM7QUFRakksTUFBTSxPQUFPLEdBQUcsQ0FBQyxLQUFjLEVBQUUsSUFBdUIsRUFBb0MsRUFBRSxDQUM1RixLQUFLLEtBQUssSUFBSSxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDO09BQ2pFLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxLQUFLLElBQUksQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7QUFDL0YsTUFBTSxPQUFPLEdBQUcsR0FBVSxFQUFFLEdBQUcsTUFBTSxJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsa0JBQWtCLENBQUMsdUNBQXVDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUU3SCxtRkFBbUY7QUFDbkYsTUFBTSxPQUFPLHlCQUF5QjtJQWlCUDtJQWhCYixRQUFRLENBQThCO0lBQ3RDLE1BQU0sQ0FBNEI7SUFDakMsZ0JBQWdCLEdBQUcsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzFELGFBQWEsR0FBRyxJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDaEUsZ0JBQWdCLENBQXNCO0lBQ3RDLGFBQWEsQ0FBc0I7SUFDMUIsT0FBTyxHQUFHLElBQUksR0FBRyxFQUFzQixDQUFDO0lBQ3hDLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFDa0IsQ0FBQztJQUN6QyxpQkFBaUIsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO0lBQ3RDLHNCQUFzQixHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO0lBQ25ELGdCQUFnQixHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDckMsaUJBQWlCLEdBQUcsSUFBSSxHQUFHLEVBQXlCLENBQUM7SUFDckQsb0JBQW9CLEdBQWMsRUFBRSxDQUFDO0lBQzlDLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFFeEIsWUFBNkIsT0FBMEM7UUFBMUMsWUFBTyxHQUFQLE9BQU8sQ0FBbUM7UUFDckUsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLDJCQUEyQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3pELElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSx5QkFBeUIsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUMzRSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDbEIsQ0FBQztJQUVPLFFBQVE7UUFDZCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ3pFLCtCQUErQixFQUFFLEtBQUssRUFBQyxPQUFPLEVBQUMsRUFBRTtZQUMvQyxJQUFJLE9BQU8sS0FBSyxJQUFJLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO2dCQUFFLE9BQU8sRUFBRSxDQUFDO1lBQ3pGLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDbEMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLGNBQWMsRUFBRSxjQUFjLEVBQUUsT0FBTyxDQUFDLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUFFLE9BQU8sRUFBRSxDQUFDO1lBQzFGLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQzNELENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDTixJQUFJLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ3pFLDZCQUE2QixFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEVBQUU7WUFDdEQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxPQUFPLEVBQUUsZUFBZSxFQUFFLFFBQVEsQ0FBQyxDQUFDO2dCQUFFLE9BQU8sRUFBRSxDQUFDO1lBQ3ZFLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsYUFBYSxFQUFFLE9BQU8sQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ3RHLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDTixJQUFJLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ3pFLDBCQUEwQixFQUFFLEtBQUssRUFBQyxPQUFPLEVBQUMsRUFBRTtZQUMxQyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUMsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxVQUFVLEtBQUssUUFBUSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssUUFBUTtnQkFBRSxPQUFPLEVBQUUsQ0FBQztZQUN6SCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsRUFBRSxDQUFDO1FBQzNELENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDTixJQUFJLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ3pFLDZCQUE2QixFQUFFLEtBQUssRUFBQyxPQUFPLEVBQUMsRUFBRTtZQUM3QyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLFdBQVcsRUFBRSxNQUFNLENBQUMsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssUUFBUSxJQUFJLE9BQU8sT0FBTyxDQUFDLFNBQVMsS0FBSyxRQUFRO2dCQUFFLE9BQU8sRUFBRSxDQUFDO1lBQzlILElBQUksSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDO2dCQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsK0NBQStDLENBQUMsQ0FBQztZQUNuSCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUM3QyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxJQUFJLENBQUMsd0JBQXdCLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUN2RCxNQUFNLFNBQVMsR0FBRyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUN6RSxLQUFLLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7Z0JBQzVILE9BQU8sRUFBRSxTQUFTLEVBQUUsQ0FBQztZQUN2QixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFBQyxNQUFNLEtBQUssQ0FBQztZQUFDLENBQUM7UUFDbkYsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNOLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxlQUFlLENBQUMsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FDekUsZ0NBQWdDLEVBQUUsS0FBSyxFQUFDLE9BQU8sRUFBQyxFQUFFO1lBQ2hELElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUMsSUFBSSxPQUFPLE9BQU8sQ0FBQyxXQUFXLEtBQUssUUFBUTtnQkFBRSxPQUFPLEVBQUUsQ0FBQztZQUM3RixPQUFPLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1FBQ3RFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDTixJQUFJLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ3pFLDZCQUE2QixFQUFFLEtBQUssRUFBQyxPQUFPLEVBQUMsRUFBRTtZQUM3QyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLGFBQWEsQ0FBQyxDQUFDLElBQUksT0FBTyxPQUFPLENBQUMsV0FBVyxLQUFLLFFBQVE7Z0JBQUUsT0FBTyxFQUFFLENBQUM7WUFDN0YsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1FBQy9FLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDTixJQUFJLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ3pFLDZCQUE2QixFQUFFLEtBQUssRUFBQyxPQUFPLEVBQUMsRUFBRTtZQUM3QyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLFdBQVcsRUFBRSxrQkFBa0IsRUFBRSxPQUFPLENBQUMsQ0FBQyxJQUFJLE9BQU8sT0FBTyxDQUFDLFNBQVMsS0FBSyxRQUFRO21CQUNyRyxPQUFPLE9BQU8sQ0FBQyxnQkFBZ0IsS0FBSyxRQUFRLElBQUksT0FBTyxPQUFPLENBQUMsS0FBSyxLQUFLLFFBQVE7Z0JBQUUsT0FBTyxFQUFFLENBQUM7WUFDbEcsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLGdCQUFnQixFQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ2xILENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDTixJQUFJLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ3pFLDZCQUE2QixFQUFFLEtBQUssRUFBQyxPQUFPLEVBQUMsRUFBRTtZQUM3QyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLFdBQVcsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDLElBQUksT0FBTyxPQUFPLENBQUMsU0FBUyxLQUFLLFFBQVE7bUJBQzVGLE9BQU8sT0FBTyxDQUFDLGdCQUFnQixLQUFLLFFBQVE7Z0JBQUUsT0FBTyxFQUFFLENBQUM7WUFDN0QsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUM7Z0JBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQywrQ0FBK0MsQ0FBQyxDQUFDO1lBQ25ILElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQzdDLElBQUksQ0FBQztnQkFDSCxNQUFNLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3ZELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLENBQUM7WUFDbkcsQ0FBQztvQkFBUyxDQUFDO2dCQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQUMsQ0FBQztRQUNoRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ04sSUFBSSxDQUFDLGdCQUFnQixDQUFDLGVBQWUsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUN6RSwyQkFBMkIsRUFBRSxLQUFLLEVBQUMsT0FBTyxFQUFDLEVBQUU7WUFDM0MsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxXQUFXLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxlQUFlLENBQUMsQ0FBQzttQkFDdEUsT0FBTyxPQUFPLENBQUMsU0FBUyxLQUFLLFFBQVEsSUFBSSxPQUFPLE9BQU8sQ0FBQyxPQUFPLEtBQUssUUFBUTttQkFDNUUsT0FBTyxPQUFPLENBQUMsYUFBYSxLQUFLLFFBQVE7Z0JBQUUsT0FBTyxFQUFFLENBQUM7WUFDMUQsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMxQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ04sSUFBSSxDQUFDLGFBQWEsQ0FBQyxlQUFlLENBQUMsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FDdEUsb0NBQW9DLEVBQUUsS0FBSyxFQUFDLE9BQU8sRUFBQyxFQUFFO1lBQ3BELElBQUksQ0FBQyxPQUFPLE9BQU8sS0FBSyxRQUFRLElBQUksT0FBTyxLQUFLLElBQUksSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO21CQUMxRSxDQUFDLENBQUMsV0FBVyxFQUFFLFlBQVksRUFBRSxlQUFlLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQzttQkFDdkYsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLFlBQVksRUFBRSxlQUFlO29CQUM5RSx5QkFBeUIsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQzttQkFDeEMsT0FBTyxPQUFPLENBQUMsU0FBUyxLQUFLLFFBQVEsSUFBSSxPQUFPLE9BQU8sQ0FBQyxVQUFVLEtBQUssUUFBUTttQkFDL0UsT0FBTyxPQUFPLENBQUMsYUFBYSxLQUFLLFFBQVE7bUJBQ3pDLENBQUMsT0FBTyxDQUFDLHVCQUF1QixLQUFLLFNBQVMsSUFBSSxPQUFPLE9BQU8sQ0FBQyx1QkFBdUIsS0FBSyxRQUFRLENBQUM7Z0JBQUUsT0FBTyxFQUFFLENBQUM7WUFDdkgsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLGFBQWEsRUFDM0YsT0FBTyxDQUFDLHVCQUF1QixDQUFDLENBQUM7UUFDckMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNSLENBQUM7SUFFTSxLQUFLLENBQUMsS0FBSztRQUNoQixJQUFJLElBQUksQ0FBQyxnQkFBZ0IsSUFBSSxJQUFJLENBQUMsYUFBYTtZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsaURBQWlELENBQUMsQ0FBQztRQUNwSCxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDNUIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQzFCLE1BQU0sbUJBQW1CLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lBQ25GLE1BQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1lBQzlFLE1BQU0saUJBQWlCLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUN4RSxJQUFJLG1CQUFtQixLQUFLLGdCQUFnQixJQUFJLGlCQUFpQixLQUFLLGdCQUFnQjttQkFDakYsbUJBQW1CLENBQUMsVUFBVSxDQUFDLGdCQUFnQixHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO21CQUNuRSxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7bUJBQ2pFLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxtQkFBbUIsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQzttQkFDbkUsZ0JBQWdCLENBQUMsVUFBVSxDQUFDLGlCQUFpQixHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDdkUsTUFBTSxJQUFJLEtBQUssQ0FBQywyRUFBMkUsQ0FBQyxDQUFDO1lBQy9GLENBQUM7WUFDRCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7WUFDbkcsSUFBSSxDQUFDLGFBQWEsR0FBRyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDN0YsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLENBQUM7Z0JBQUMsTUFBTSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFBQyxDQUFDO1lBQUMsTUFBTSxDQUFDLENBQUMsK0JBQStCLENBQUMsQ0FBQztZQUNyRSxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQsa0dBQWtHO0lBQzFGLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxTQUFpQjtRQUN0RCxNQUFNLE1BQU0sR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLHNCQUFzQixDQUFDO2FBQzVDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxpQkFBaUIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxpQkFBaUIsS0FBSyxTQUFTLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNsRyxNQUFNLE9BQU8sR0FBRyxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDaEcsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sRUFBbUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEtBQUssVUFBVSxDQUFDLENBQUM7UUFDekcsSUFBSSxNQUFNLENBQUMsTUFBTTtZQUFFLE1BQU0sSUFBSSxjQUFjLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxxQ0FBcUMsQ0FBQyxDQUFDO0lBQzFILENBQUM7SUFFTSxLQUFLLENBQUMsaUJBQWlCLENBQUMsS0FHd0M7UUFDckUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQztlQUNqRCxPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsa0JBQWtCLENBQUMsS0FBSyxLQUFLLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztZQUNuRixNQUFNLElBQUksS0FBSyxDQUFDLDBEQUEwRCxDQUFDLENBQUM7UUFDOUUsQ0FBQztRQUNELE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsMEJBQTBCLEVBQUUsS0FBSyxDQUFDLGtCQUFrQixDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNoSixJQUFJLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYTtlQUM1RCxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksSUFBSSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDO2VBQ2pGLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztZQUN0RixNQUFNLElBQUksS0FBSyxDQUFDLHFDQUFxQyxDQUFDLENBQUM7UUFDekQsQ0FBQztRQUNELElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbkMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNoRSxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQzFDLE1BQU0sSUFBSSxHQUFHLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDdkIsSUFBSSxLQUFzRSxDQUFDO1lBQzNFLElBQUksT0FBMkMsQ0FBQztZQUNoRCxJQUFJLE9BQU8sR0FBRyxLQUFLLENBQUM7WUFDcEIsSUFBSSxDQUFDO2dCQUNILE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQztnQkFDdEMsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQzFDLE1BQU0sVUFBVSxHQUFHLE1BQU0sT0FBTyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUMzRCxJQUFJLENBQUMsVUFBVSxDQUFDLFdBQVcsRUFBRSxJQUFJLFVBQVUsQ0FBQyxjQUFjLEVBQUUsSUFBSSxVQUFVLENBQUMsR0FBRyxLQUFLLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRTt1QkFDaEcsQ0FBQyxVQUFVLENBQUMsSUFBSSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsSUFBSSxNQUFNLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxNQUFNLEVBQUUsQ0FBQztvQkFDOUYsTUFBTSxJQUFJLEtBQUssQ0FBQyxtRUFBbUUsQ0FBQyxDQUFDO2dCQUN2RixDQUFDO2dCQUNELE1BQU0sV0FBVyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxRQUFRLENBQUMsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQztxQkFDNUYsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFtQixFQUFFLENBQUMsT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7Z0JBQ25HLElBQUksV0FBVyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLElBQUksS0FBSyxNQUFNLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7dUJBQ3ZGLE1BQU0sQ0FBQyxVQUFVLENBQUMsSUFBSSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO29CQUNqRCxNQUFNLElBQUksS0FBSyxDQUFDLHlEQUF5RCxDQUFDLENBQUM7Z0JBQzdFLENBQUM7Z0JBQ0QsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDM0QsSUFBSSxRQUFRLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxLQUFLLEtBQUssQ0FBQyxTQUFTLElBQUksUUFBUSxDQUFDLE9BQU8sS0FBSyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztvQkFDL0YsTUFBTSxJQUFJLEtBQUssQ0FBQyxpRUFBaUUsQ0FBQyxDQUFDO2dCQUNyRixDQUFDO2dCQUNELElBQUksVUFBVSxHQUFHLEtBQUssQ0FBQztnQkFDdkIsSUFBSSxDQUFDO29CQUNILE1BQU0sSUFBSSxHQUFHLE1BQU0sT0FBTyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUNuRCxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUUsSUFBSSxJQUFJLENBQUMsR0FBRyxLQUFLLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRTsyQkFDOUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsSUFBSSxNQUFNLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQzt3QkFDcEYsTUFBTSxJQUFJLEtBQUssQ0FBQyxzREFBc0QsQ0FBQyxDQUFDO29CQUMxRSxDQUFDO29CQUNELFVBQVUsR0FBRyxJQUFJLENBQUM7Z0JBQ3BCLENBQUM7Z0JBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztvQkFDZixJQUFJLENBQUMsQ0FBQyxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLE1BQU0sSUFBSSxLQUFLLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxRQUFRLENBQUM7d0JBQUUsTUFBTSxLQUFLLENBQUM7Z0JBQ3ZHLENBQUM7Z0JBQ0QsSUFBSSxDQUFDLFFBQVEsSUFBSSxVQUFVLElBQUksQ0FBQyxNQUFNLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDO29CQUNoRixNQUFNLElBQUksS0FBSyxDQUFDLCtFQUErRSxDQUFDLENBQUM7Z0JBQ25HLENBQUM7Z0JBQ0QsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO2dCQUMxRyxJQUFJLENBQUMsVUFBVTtvQkFBRSxNQUFNLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztnQkFDeEUsS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsRUFBRSxTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVMsRUFBRSxPQUFPLEVBQUUsT0FBTztvQkFDbEYsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsYUFBYSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUN4RSxPQUFPLEdBQUcsSUFBSSxzQkFBc0IsQ0FBQztvQkFDbkMsZ0JBQWdCLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLEVBQUUsZUFBZSxDQUFDO29CQUNsSSxrQkFBa0IsRUFBRSxJQUFJLEVBQUUsa0JBQWtCLEVBQUUsS0FBSyxDQUFDLGtCQUFrQixFQUFFLFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVTtvQkFDcEcsY0FBYyxFQUFFLEtBQUssQ0FBQyxjQUFjLEVBQUUsZUFBZSxFQUFFLEtBQUssQ0FBQyxlQUFlO29CQUM1RSxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxTQUFTLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO29CQUM5RSxhQUFhLEVBQUUsS0FBSyxFQUFDLFVBQVUsRUFBQyxFQUFFO3dCQUNoQyxNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDO3dCQUMzRCxJQUFJLENBQUMsUUFBUSxJQUFJLFFBQVEsQ0FBQyxTQUFTLEtBQUssS0FBSyxDQUFDLFNBQVMsSUFBSSxRQUFRLENBQUMsT0FBTyxLQUFLLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQzs0QkFDOUYsTUFBTSxJQUFJLEtBQUssQ0FBQyx3Q0FBd0MsQ0FBQyxDQUFDO3dCQUM1RCxDQUFDO3dCQUNELElBQUksUUFBUSxDQUFDLFNBQVMsRUFBRSxDQUFDOzRCQUN2QixNQUFNLFFBQVEsR0FBRyxNQUFNLHVCQUF1QixDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLENBQUM7NEJBQzlFLElBQUksUUFBUTtnQ0FBRSxNQUFNLElBQUksS0FBSyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7NEJBQ3ZGLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxTQUFTLENBQUMsRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7d0JBQ3ZHLENBQUM7d0JBQ0QsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUM3QyxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQzt3QkFDdEYsT0FBTyxHQUFHLElBQUksQ0FBQztvQkFDakIsQ0FBQztvQkFDRCxjQUFjLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsRUFBRTt3QkFDdkMsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQzt3QkFDM0QsSUFBSSxRQUFRLEVBQUUsU0FBUyxFQUFFLEVBQUUsS0FBSyxLQUFLLElBQUksUUFBUSxDQUFDLFNBQVMsQ0FBQyxHQUFHLEtBQUssSUFBSSxFQUFFLENBQUM7NEJBQ3pFLE1BQU0sSUFBSSxLQUFLLENBQUMscUVBQXFFLENBQUMsQ0FBQzt3QkFDekYsQ0FBQzt3QkFDRCxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQzlDLEVBQUUsR0FBRyxRQUFRLENBQUMsU0FBUyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7b0JBQzVFLENBQUM7b0JBQ0QsYUFBYSxFQUFFLEdBQUcsRUFBRTt3QkFDbEIsS0FBSyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsRUFBRTs0QkFDdEQsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQzs0QkFDdEMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMscUVBQXFFLENBQUMsQ0FBQzt3QkFDOUYsQ0FBQyxDQUFDLENBQUM7b0JBQ0wsQ0FBQztpQkFDRixDQUFDLENBQUM7Z0JBQ0gsTUFBTSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ3RCLElBQUksSUFBSSxDQUFDLE9BQU87b0JBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO2dCQUNwRixPQUFPLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUM7WUFDL0YsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsTUFBTSxhQUFhLEdBQWMsRUFBRSxDQUFDO2dCQUNwQyxJQUFJLE9BQU87b0JBQUUsSUFBSSxDQUFDO3dCQUFDLE1BQU0sT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUFDLENBQUM7b0JBQUMsT0FBTyxZQUFZLEVBQUUsQ0FBQzt3QkFBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO29CQUFDLENBQUM7Z0JBQ3RHLElBQUksT0FBTyxJQUFJLGFBQWEsQ0FBQyxNQUFNLEtBQUssQ0FBQztvQkFBRSxJQUFJLENBQUM7d0JBQzlDLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO29CQUN2RixDQUFDO29CQUFDLE9BQU8sWUFBWSxFQUFFLENBQUM7d0JBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztvQkFBQyxDQUFDO2dCQUM1RCxJQUFJLEtBQUs7b0JBQUUsSUFBSSxDQUFDO3dCQUFDLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO29CQUFDLENBQUM7b0JBQ3ZGLE9BQU8sWUFBWSxFQUFFLENBQUM7d0JBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztvQkFBQyxDQUFDO2dCQUMxRCxJQUFJLGFBQWEsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7b0JBQy9CLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7b0JBQ3RDLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUNwRCxDQUFDO2dCQUNELElBQUksYUFBYSxDQUFDLE1BQU07b0JBQUUsTUFBTSxJQUFJLGNBQWMsQ0FBQyxDQUFDLEtBQUssRUFBRSxHQUFHLGFBQWEsQ0FBQyxFQUFFLHlDQUF5QyxDQUFDLENBQUM7Z0JBQ3pILE1BQU0sS0FBSyxDQUFDO1lBQ2QsQ0FBQztRQUNILENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDTCxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQzNDLElBQUksQ0FBQztZQUFDLE9BQU8sQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUFDLENBQUM7UUFDcEMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUFDLE1BQU0sS0FBSyxDQUFDO1FBQUMsQ0FBQztJQUN6RSxDQUFDO0lBRU0sZ0JBQWdCLENBQUMsT0FBZTtRQUNyQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3JELElBQUksUUFBUTtZQUFFLE9BQU8sUUFBUSxDQUFDO1FBQzlCLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzVDLElBQUksQ0FBQyxJQUFJO1lBQUUsT0FBTyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDcEMsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbEMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRTtZQUMzQixJQUFJLEtBQTJCLENBQUM7WUFDaEMsSUFBSSxDQUFDO2dCQUFDLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQztZQUFDLENBQUM7WUFDM0IsTUFBTSxDQUFDLENBQUMsMEVBQTBFO2dCQUFDLE9BQU87WUFBQyxDQUFDO1lBQzVGLE1BQU0sRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLEdBQUcsS0FBSyxDQUFDO1lBQ2hFLE1BQU0sTUFBTSxHQUFjLEVBQUUsQ0FBQztZQUM3QixJQUFJLENBQUM7Z0JBQUMsTUFBTSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7WUFBQyxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQUMsQ0FBQztZQUNwRSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQztnQkFBRSxJQUFJLENBQUM7b0JBQzVCLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO29CQUNyRixJQUFJLENBQUMsaUJBQWlCLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUN0QyxJQUFJLENBQUMsc0JBQXNCLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUM5QyxDQUFDO2dCQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7b0JBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFBQyxDQUFDO1lBQ3ZDLElBQUksQ0FBQztnQkFBQyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLFNBQVMsRUFBRSxVQUFVLENBQUMsQ0FBQztZQUFDLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFBQyxDQUFDO1lBQ3JHLElBQUksTUFBTSxDQUFDLE1BQU07Z0JBQUUsTUFBTSxJQUFJLGNBQWMsQ0FBQyxNQUFNLEVBQUUsd0NBQXdDLENBQUMsQ0FBQztRQUNoRyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ0wsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDOUMsS0FBSyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksSUFBSSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsS0FBSyxRQUFRO1lBQUUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUMsQ0FBQztRQUMvSSxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFZLEVBQUUsTUFBd0M7UUFDekUsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDN0MsTUFBTSxPQUFPLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUM3RSxNQUFNLElBQUksR0FBRyxNQUFNLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN4RCxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUUsSUFBSSxJQUFJLENBQUMsR0FBRyxLQUFLLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUM7WUFDcEYsTUFBTSxJQUFJLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO1FBQzNFLENBQUM7UUFDRCxNQUFNLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDbEQsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDbEMsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQy9FLElBQUksQ0FBQztZQUNILE1BQU0sSUFBSSxPQUFPLENBQU8sQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7Z0JBQzFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUM3QixNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUUsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDekUsQ0FBQyxDQUFDLENBQUM7WUFDSCxNQUFNLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDN0MsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLE1BQU0sQ0FBQyxTQUFTO2dCQUFFLE1BQU0sSUFBSSxPQUFPLENBQU8sT0FBTyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQztZQUN4RixNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQsc0dBQXNHO0lBQzlGLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFZO1FBQ3pDLElBQUksTUFBd0IsQ0FBQztRQUM3QixJQUFJLENBQUM7WUFBQyxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFBQyxDQUFDO1FBQ3ZELE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDYixJQUFLLEtBQStCLENBQUMsSUFBSSxLQUFLLFFBQVE7Z0JBQUUsT0FBTztZQUMvRCxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7UUFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxJQUFJLE1BQU0sQ0FBQyxHQUFHLEtBQUssT0FBTyxDQUFDLE1BQU0sRUFBRSxFQUFFO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQ0FBbUMsQ0FBQyxDQUFDO1FBQ2xILE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBSSxPQUFPLENBQVUsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDN0QsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNqRCxLQUFLLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxHQUFHLEVBQUUsR0FBRyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsb0NBQW9DLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDN0csS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsR0FBRyxFQUFFLEdBQUcsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDbEUsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLEVBQUU7Z0JBQzFCLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDaEIsSUFBSyxLQUErQixDQUFDLElBQUksS0FBSyxjQUFjO29CQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQzs7b0JBQ3ZFLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNyQixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLE9BQU87WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7UUFDaEYsTUFBTSxLQUFLLEdBQUcsTUFBTSxPQUFPLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDcEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsSUFBSSxLQUFLLENBQUMsR0FBRyxLQUFLLE1BQU0sQ0FBQyxHQUFHLElBQUksS0FBSyxDQUFDLEdBQUcsS0FBSyxNQUFNLENBQUMsR0FBRyxJQUFJLEtBQUssQ0FBQyxHQUFHLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQzFHLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztRQUNwRSxDQUFDO1FBQ0QsTUFBTSxPQUFPLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVPLE1BQU0sQ0FBQyxNQUEwQixFQUFFLE1BQXdDO1FBQ2pGLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3pCLE1BQU0sS0FBSyxHQUFHLElBQUksZUFBZSxFQUFFLENBQUM7UUFDcEMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMxRSxNQUFNLEtBQUssR0FBRyxJQUFJLDhCQUE4QixFQUFFLENBQUM7UUFDbkQsSUFBSSxPQUFPLEdBQUcsS0FBSyxDQUFDO1FBQ3BCLE1BQU0sQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ2xELE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxFQUFFO1lBQ3hCLElBQUksT0FBTyxFQUFFLENBQUM7Z0JBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUFDLE9BQU87WUFBQyxDQUFDO1lBQzFDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUFDLE9BQU87WUFBQyxDQUFDO1lBQzFELElBQUksS0FBb0IsQ0FBQztZQUN6QixJQUFJLENBQUM7Z0JBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7WUFBQyxDQUFDO1lBQ2pDLE1BQU0sQ0FBQztnQkFBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQUMsT0FBTztZQUFDLENBQUM7WUFDbkMsSUFBSSxLQUFLLEtBQUssSUFBSTtnQkFBRSxPQUFPO1lBQzNCLE9BQU8sR0FBRyxJQUFJLENBQUM7WUFDZixJQUFJLE9BQXNCLENBQUM7WUFDM0IsSUFBSSxDQUFDO2dCQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBa0IsQ0FBQztZQUFDLENBQUM7WUFDckQsTUFBTSxDQUFDO2dCQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFBQyxPQUFPO1lBQUMsQ0FBQztZQUNuQyxLQUFLLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsRUFBRSxnQkFBZ0IsRUFBRSxFQUFFLGVBQWUsRUFBRSxNQUFNLEVBQUU7Z0JBQ3RGLGtCQUFrQixFQUFFLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztpQkFDbEMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFO2dCQUNmLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQ3JDLElBQUksNkJBQTZCLENBQUMsR0FBRyxDQUFDLEdBQUcsZ0NBQWdDLEVBQUUsQ0FBQztvQkFBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7b0JBQUMsT0FBTztnQkFBQyxDQUFDO2dCQUN4RyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsQ0FBQztZQUN6QixDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDckMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU0sS0FBSyxDQUFDLEtBQUs7UUFDaEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7UUFDcEIsTUFBTSxNQUFNLEdBQWMsRUFBRSxDQUFDO1FBQzdCLEtBQUssTUFBTSxPQUFPLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQ3BELElBQUksQ0FBQztnQkFBQyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUFDLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFBQyxDQUFDO1FBQ3JGLENBQUM7UUFDRCxLQUFLLE1BQU0sUUFBUSxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQzVELElBQUksQ0FBQztnQkFBQyxNQUFNLFFBQVEsQ0FBQztZQUFDLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFBQyxDQUFDO1FBQy9ELENBQUM7UUFDRCxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7UUFDMUMsSUFBSSxDQUFDO1lBQUMsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQUMsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQUMsQ0FBQztRQUN4RSxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUM7UUFDekMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQztRQUNuQyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsU0FBUyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxhQUFhLEdBQUcsU0FBUyxDQUFDO1FBQy9CLEtBQUssTUFBTSxNQUFNLElBQUksSUFBSSxDQUFDLE9BQU87WUFBRSxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDcEQsS0FBSyxNQUFNLE1BQU0sSUFBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQzNDLElBQUksTUFBTTtnQkFBRSxJQUFJLENBQUM7b0JBQ2YsTUFBTSxJQUFJLE9BQU8sQ0FBTyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDO2dCQUN6RyxDQUFDO2dCQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7b0JBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFBQyxDQUFDO1FBQ3pDLENBQUM7UUFDRCxJQUFJLENBQUM7WUFBQyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7UUFBQyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFBQyxDQUFDO1FBQ3pFLElBQUksTUFBTSxDQUFDLE1BQU07WUFBRSxNQUFNLElBQUksY0FBYyxDQUFDLE1BQU0sRUFBRSwrQ0FBK0MsQ0FBQyxDQUFDO0lBQ3ZHLENBQUM7Q0FDRiJ9
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { type IStoredAuthorityAccount, type IStoredAuthorityBinding, type IStoredAuthorityCodexHome, type IStoredAuthorityEnrollment, type IStoredAuthorityEvent, type IStoredAuthorityGrant, type IStoredAuthorityHandoff, type IStoredAuthorityMeta, type IStoredAuthorityMigrationLedger } from './classes.authoritymodels.js';
|
|
2
|
+
export interface IAuthSwitchAuthorityDatabaseOptions {
|
|
3
|
+
dataDirectory: string;
|
|
4
|
+
socketPath: string;
|
|
5
|
+
}
|
|
6
|
+
/** Separate account, grant, binding and journal records; the only global record is a revision counter. */
|
|
7
|
+
export declare class AuthSwitchAuthorityDatabase {
|
|
8
|
+
private readonly options;
|
|
9
|
+
private engine?;
|
|
10
|
+
private database?;
|
|
11
|
+
private started;
|
|
12
|
+
constructor(options: IAuthSwitchAuthorityDatabaseOptions);
|
|
13
|
+
private privateDirectory;
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
private db;
|
|
16
|
+
private transaction;
|
|
17
|
+
readMeta(): Promise<IStoredAuthorityMeta>;
|
|
18
|
+
readAccount(id: string): Promise<IStoredAuthorityAccount | null>;
|
|
19
|
+
readBinding(id: string): Promise<IStoredAuthorityBinding | null>;
|
|
20
|
+
readCodexHome(id: string): Promise<IStoredAuthorityCodexHome | null>;
|
|
21
|
+
/** Home path identity is hashed by the caller; no vendor files or raw paths enter SmartData. */
|
|
22
|
+
reserveCodexHome(accountId: string, scopeId: string, homeId: string, updateId: string): Promise<{
|
|
23
|
+
newlyRegistered: boolean;
|
|
24
|
+
}>;
|
|
25
|
+
/** Pre-spawn claim is durable; the exact socket lets a later daemon detect a child born before PID readback. */
|
|
26
|
+
changeCodexRun(homeId: string, expectedRunId: string | null, activeRun: IStoredAuthorityCodexHome['activeRun'], updateId: string): Promise<void>;
|
|
27
|
+
/** One consistent authorization view. Callers must not combine separate binding and grant reads. */
|
|
28
|
+
readBindingContext(id: string): Promise<{
|
|
29
|
+
binding: IStoredAuthorityBinding | null;
|
|
30
|
+
account: IStoredAuthorityAccount | null;
|
|
31
|
+
grant: IStoredAuthorityGrant | null;
|
|
32
|
+
}>;
|
|
33
|
+
readGrant(id: string): Promise<IStoredAuthorityGrant | null>;
|
|
34
|
+
readEnrollment(id: string): Promise<IStoredAuthorityEnrollment | null>;
|
|
35
|
+
readHandoff(id: string): Promise<IStoredAuthorityHandoff | null>;
|
|
36
|
+
readMigrationLedger(id: string): Promise<IStoredAuthorityMigrationLedger | null>;
|
|
37
|
+
migrationLedgerByStatus(status: IStoredAuthorityMigrationLedger['status'], after: string | null, limit?: number): Promise<IStoredAuthorityMigrationLedger[]>;
|
|
38
|
+
readAccountAndPrimaryGrant(id: string): Promise<{
|
|
39
|
+
account: IStoredAuthorityAccount | null;
|
|
40
|
+
grant: IStoredAuthorityGrant | null;
|
|
41
|
+
}>;
|
|
42
|
+
page(accountAfter: string | null, bindingAfter: string | null, limit: number): Promise<{
|
|
43
|
+
meta: IStoredAuthorityMeta;
|
|
44
|
+
accounts: Array<{
|
|
45
|
+
account: IStoredAuthorityAccount;
|
|
46
|
+
grant: IStoredAuthorityGrant | null;
|
|
47
|
+
}>;
|
|
48
|
+
bindings: IStoredAuthorityBinding[];
|
|
49
|
+
nextAccountCursor: string | null;
|
|
50
|
+
nextBindingCursor: string | null;
|
|
51
|
+
}>;
|
|
52
|
+
grantsByState(state: IStoredAuthorityGrant['state'], after: string | null, limit?: number): Promise<IStoredAuthorityGrant[]>;
|
|
53
|
+
grantsForAccount(accountId: string, after: string | null, limit?: number): Promise<IStoredAuthorityGrant[]>;
|
|
54
|
+
eventsAfter(revision: number, limit?: number): Promise<IStoredAuthorityEvent[]>;
|
|
55
|
+
private appendEvent;
|
|
56
|
+
private persistAccount;
|
|
57
|
+
private persistGrant;
|
|
58
|
+
/** Atomic account/grant enrollment or reauthentication. Both records become visible together. */
|
|
59
|
+
changeAccountAndGrant(updateId: string, accountId: string, grantId: string, change: (account: IStoredAuthorityAccount | null, grant: IStoredAuthorityGrant | null) => {
|
|
60
|
+
account: IStoredAuthorityAccount;
|
|
61
|
+
grant: IStoredAuthorityGrant;
|
|
62
|
+
}): Promise<{
|
|
63
|
+
meta: IStoredAuthorityMeta;
|
|
64
|
+
account: IStoredAuthorityAccount;
|
|
65
|
+
grant: IStoredAuthorityGrant;
|
|
66
|
+
}>;
|
|
67
|
+
/** Grant transition and public account revision share a transaction and one event. */
|
|
68
|
+
changeGrant(updateId: string, grantId: string, change: (grant: IStoredAuthorityGrant, account: IStoredAuthorityAccount) => IStoredAuthorityGrant): Promise<{
|
|
69
|
+
meta: IStoredAuthorityMeta;
|
|
70
|
+
account: IStoredAuthorityAccount;
|
|
71
|
+
grant: IStoredAuthorityGrant;
|
|
72
|
+
}>;
|
|
73
|
+
/** Add a distinct per-purpose grant without replacing the account's primary grant. */
|
|
74
|
+
changeSecondaryGrant(updateId: string, accountId: string, grantId: string, change: (grant: IStoredAuthorityGrant | null, account: IStoredAuthorityAccount) => IStoredAuthorityGrant): Promise<{
|
|
75
|
+
account: IStoredAuthorityAccount;
|
|
76
|
+
grant: IStoredAuthorityGrant;
|
|
77
|
+
}>;
|
|
78
|
+
/** Remove all managed grants in one transaction; native owners must be stopped and handed off first. */
|
|
79
|
+
removeAccountAndGrants(updateId: string, accountId: string, expectedRevision: number, statusObservedAt: string): Promise<IStoredAuthorityAccount>;
|
|
80
|
+
changeAccount(updateId: string, accountId: string, change: (draft: IStoredAuthorityAccount | null) => IStoredAuthorityAccount): Promise<{
|
|
81
|
+
meta: IStoredAuthorityMeta;
|
|
82
|
+
account: IStoredAuthorityAccount;
|
|
83
|
+
}>;
|
|
84
|
+
changeBinding(updateId: string, bindingId: string, accountId: string, change: (draft: IStoredAuthorityBinding | null, account: IStoredAuthorityAccount, grant: IStoredAuthorityGrant | null) => IStoredAuthorityBinding): Promise<{
|
|
85
|
+
meta: IStoredAuthorityMeta;
|
|
86
|
+
binding: IStoredAuthorityBinding;
|
|
87
|
+
}>;
|
|
88
|
+
/** Closing an owned runtime revokes only its exact capability/incarnation. */
|
|
89
|
+
revokeBinding(updateId: string, bindingId: string, capabilityHash: string): Promise<boolean>;
|
|
90
|
+
/** Enrollment metadata is sealed by the caller and cannot become detached from an account. */
|
|
91
|
+
changeEnrollment(updateId: string, enrollmentId: string, accountId: string, change: (current: IStoredAuthorityEnrollment | null) => IStoredAuthorityEnrollment): Promise<IStoredAuthorityEnrollment>;
|
|
92
|
+
/** Journal and grant advance together; no intermediate phase may expose an active daemon grant. */
|
|
93
|
+
changeHandoffAndGrant(updateId: string, handoffId: string, grantId: string, change: (current: IStoredAuthorityHandoff | null, grant: IStoredAuthorityGrant, account: IStoredAuthorityAccount) => {
|
|
94
|
+
handoff: IStoredAuthorityHandoff;
|
|
95
|
+
grant: IStoredAuthorityGrant;
|
|
96
|
+
}): Promise<{
|
|
97
|
+
handoff: IStoredAuthorityHandoff;
|
|
98
|
+
grant: IStoredAuthorityGrant;
|
|
99
|
+
}>;
|
|
100
|
+
/** Ledger transitions never silently replace an active credential or waive backup proof. */
|
|
101
|
+
changeMigrationLedger(updateId: string, ledgerId: string, change: (current: IStoredAuthorityMigrationLedger | null) => IStoredAuthorityMigrationLedger): Promise<IStoredAuthorityMigrationLedger>;
|
|
102
|
+
stop(): Promise<void>;
|
|
103
|
+
}
|