skedyul 1.4.4 → 1.4.7
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/cli/index.js +83 -16
- package/dist/config/app-config.d.ts +5 -0
- package/dist/config/types/app-event.d.ts +40 -0
- package/dist/config/types/index.d.ts +1 -0
- package/dist/dedicated/server.js +38 -2
- package/dist/esm/index.mjs +166 -65
- package/dist/events/types.d.ts +11 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +168 -65
- package/dist/ratelimit/errors.d.ts +6 -0
- package/dist/ratelimit/index.d.ts +1 -1
- package/dist/schemas/agent-schema-v3.d.ts +4 -0
- package/dist/schemas/agent-schema-v3.js +3 -1
- package/dist/schemas/agent-schema-v3.mjs +3 -1
- package/dist/schemas.d.ts +138 -0
- package/dist/server.js +38 -2
- package/dist/serverless/server.mjs +38 -2
- package/dist/triggers/types.d.ts +3 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/tool.d.ts +21 -2
- package/dist/workflows/types.d.ts +8 -0
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -307,6 +307,16 @@ var AppAuthInvalidError = class extends Error {
|
|
|
307
307
|
}
|
|
308
308
|
};
|
|
309
309
|
|
|
310
|
+
// src/ratelimit/errors.ts
|
|
311
|
+
var RateLimitExceededError = class extends Error {
|
|
312
|
+
constructor(retryAfterMs, message = "Rate limit exceeded. Please try again later.") {
|
|
313
|
+
super(message);
|
|
314
|
+
this.code = "RATE_LIMITED";
|
|
315
|
+
this.name = "RateLimitExceededError";
|
|
316
|
+
this.retryAfterMs = retryAfterMs;
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
310
320
|
// src/server/context-logger.ts
|
|
311
321
|
var import_async_hooks3 = require("async_hooks");
|
|
312
322
|
var logContextStorage = new import_async_hooks3.AsyncLocalStorage();
|
|
@@ -404,6 +414,7 @@ function buildToolMetadata(registry) {
|
|
|
404
414
|
const rawRetries = tool.retries ?? toolConfig.retries;
|
|
405
415
|
const timeout = typeof rawTimeout === "number" && rawTimeout > 0 ? rawTimeout : 1e4;
|
|
406
416
|
const retries = typeof rawRetries === "number" && rawRetries >= 1 ? rawRetries : 1;
|
|
417
|
+
const queueTouchPoints = tool.queueTouchPoints ?? toolConfig.queueTouchPoints;
|
|
407
418
|
return {
|
|
408
419
|
name: tool.name,
|
|
409
420
|
displayName: tool.label || tool.name,
|
|
@@ -413,10 +424,12 @@ function buildToolMetadata(registry) {
|
|
|
413
424
|
// Include timeout/retries at top-level for tools/list response (used by syncExecutableTools)
|
|
414
425
|
timeout,
|
|
415
426
|
retries,
|
|
427
|
+
queueTouchPoints,
|
|
416
428
|
config: {
|
|
417
429
|
timeout,
|
|
418
430
|
retries,
|
|
419
|
-
completionHints: toolConfig.completionHints
|
|
431
|
+
completionHints: toolConfig.completionHints,
|
|
432
|
+
queueTouchPoints
|
|
420
433
|
}
|
|
421
434
|
};
|
|
422
435
|
});
|
|
@@ -559,6 +572,27 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
559
572
|
cursor: functionResult.cursor
|
|
560
573
|
};
|
|
561
574
|
} catch (error) {
|
|
575
|
+
if (error instanceof RateLimitExceededError) {
|
|
576
|
+
return {
|
|
577
|
+
success: false,
|
|
578
|
+
output: null,
|
|
579
|
+
billing: { credits: 0 },
|
|
580
|
+
meta: {
|
|
581
|
+
success: false,
|
|
582
|
+
message: error.message,
|
|
583
|
+
toolName
|
|
584
|
+
},
|
|
585
|
+
error: {
|
|
586
|
+
code: "RATE_LIMITED",
|
|
587
|
+
message: error.message,
|
|
588
|
+
category: "external"
|
|
589
|
+
},
|
|
590
|
+
retry: {
|
|
591
|
+
allowed: true,
|
|
592
|
+
afterMs: error.retryAfterMs
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
}
|
|
562
596
|
if (error instanceof AppAuthInvalidError) {
|
|
563
597
|
return {
|
|
564
598
|
output: null,
|
|
@@ -922,7 +956,8 @@ function serializeConfig(config) {
|
|
|
922
956
|
description: tool.description,
|
|
923
957
|
// Read timeout/retries from top-level first, then fallback to config
|
|
924
958
|
timeout: tool.timeout ?? tool.config?.timeout,
|
|
925
|
-
retries: tool.retries ?? tool.config?.retries
|
|
959
|
+
retries: tool.retries ?? tool.config?.retries,
|
|
960
|
+
queueTouchPoints: tool.queueTouchPoints ?? tool.config?.queueTouchPoints
|
|
926
961
|
})) : [],
|
|
927
962
|
webhooks: webhookRegistry ? Object.values(webhookRegistry).map((w) => ({
|
|
928
963
|
name: w.name,
|
|
@@ -932,6 +967,7 @@ function serializeConfig(config) {
|
|
|
932
967
|
})) : [],
|
|
933
968
|
provision: isProvisionConfig(config.provision) ? config.provision : void 0,
|
|
934
969
|
agents: config.agents,
|
|
970
|
+
events: config.events,
|
|
935
971
|
queues: config.queues
|
|
936
972
|
};
|
|
937
973
|
}
|
|
@@ -268,6 +268,16 @@ var AppAuthInvalidError = class extends Error {
|
|
|
268
268
|
}
|
|
269
269
|
};
|
|
270
270
|
|
|
271
|
+
// src/ratelimit/errors.ts
|
|
272
|
+
var RateLimitExceededError = class extends Error {
|
|
273
|
+
constructor(retryAfterMs, message = "Rate limit exceeded. Please try again later.") {
|
|
274
|
+
super(message);
|
|
275
|
+
this.code = "RATE_LIMITED";
|
|
276
|
+
this.name = "RateLimitExceededError";
|
|
277
|
+
this.retryAfterMs = retryAfterMs;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
271
281
|
// src/server/context-logger.ts
|
|
272
282
|
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
273
283
|
var logContextStorage = new AsyncLocalStorage3();
|
|
@@ -365,6 +375,7 @@ function buildToolMetadata(registry) {
|
|
|
365
375
|
const rawRetries = tool.retries ?? toolConfig.retries;
|
|
366
376
|
const timeout = typeof rawTimeout === "number" && rawTimeout > 0 ? rawTimeout : 1e4;
|
|
367
377
|
const retries = typeof rawRetries === "number" && rawRetries >= 1 ? rawRetries : 1;
|
|
378
|
+
const queueTouchPoints = tool.queueTouchPoints ?? toolConfig.queueTouchPoints;
|
|
368
379
|
return {
|
|
369
380
|
name: tool.name,
|
|
370
381
|
displayName: tool.label || tool.name,
|
|
@@ -374,10 +385,12 @@ function buildToolMetadata(registry) {
|
|
|
374
385
|
// Include timeout/retries at top-level for tools/list response (used by syncExecutableTools)
|
|
375
386
|
timeout,
|
|
376
387
|
retries,
|
|
388
|
+
queueTouchPoints,
|
|
377
389
|
config: {
|
|
378
390
|
timeout,
|
|
379
391
|
retries,
|
|
380
|
-
completionHints: toolConfig.completionHints
|
|
392
|
+
completionHints: toolConfig.completionHints,
|
|
393
|
+
queueTouchPoints
|
|
381
394
|
}
|
|
382
395
|
};
|
|
383
396
|
});
|
|
@@ -520,6 +533,27 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
520
533
|
cursor: functionResult.cursor
|
|
521
534
|
};
|
|
522
535
|
} catch (error) {
|
|
536
|
+
if (error instanceof RateLimitExceededError) {
|
|
537
|
+
return {
|
|
538
|
+
success: false,
|
|
539
|
+
output: null,
|
|
540
|
+
billing: { credits: 0 },
|
|
541
|
+
meta: {
|
|
542
|
+
success: false,
|
|
543
|
+
message: error.message,
|
|
544
|
+
toolName
|
|
545
|
+
},
|
|
546
|
+
error: {
|
|
547
|
+
code: "RATE_LIMITED",
|
|
548
|
+
message: error.message,
|
|
549
|
+
category: "external"
|
|
550
|
+
},
|
|
551
|
+
retry: {
|
|
552
|
+
allowed: true,
|
|
553
|
+
afterMs: error.retryAfterMs
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
523
557
|
if (error instanceof AppAuthInvalidError) {
|
|
524
558
|
return {
|
|
525
559
|
output: null,
|
|
@@ -883,7 +917,8 @@ function serializeConfig(config) {
|
|
|
883
917
|
description: tool.description,
|
|
884
918
|
// Read timeout/retries from top-level first, then fallback to config
|
|
885
919
|
timeout: tool.timeout ?? tool.config?.timeout,
|
|
886
|
-
retries: tool.retries ?? tool.config?.retries
|
|
920
|
+
retries: tool.retries ?? tool.config?.retries,
|
|
921
|
+
queueTouchPoints: tool.queueTouchPoints ?? tool.config?.queueTouchPoints
|
|
887
922
|
})) : [],
|
|
888
923
|
webhooks: webhookRegistry ? Object.values(webhookRegistry).map((w) => ({
|
|
889
924
|
name: w.name,
|
|
@@ -893,6 +928,7 @@ function serializeConfig(config) {
|
|
|
893
928
|
})) : [],
|
|
894
929
|
provision: isProvisionConfig(config.provision) ? config.provision : void 0,
|
|
895
930
|
agents: config.agents,
|
|
931
|
+
events: config.events,
|
|
896
932
|
queues: config.queues
|
|
897
933
|
};
|
|
898
934
|
}
|
package/dist/triggers/types.d.ts
CHANGED
|
@@ -73,6 +73,7 @@ export declare const TriggerContextSchema: z.ZodObject<{
|
|
|
73
73
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
74
74
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
75
75
|
"thread.reminder.due": "thread.reminder.due";
|
|
76
|
+
"thread.signal.created": "thread.signal.created";
|
|
76
77
|
}>, z.ZodString]>;
|
|
77
78
|
payload: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
78
79
|
participant: z.ZodOptional<z.ZodObject<{
|
|
@@ -199,6 +200,7 @@ export declare const ResolvedTriggerSchema: z.ZodObject<{
|
|
|
199
200
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
200
201
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
201
202
|
"thread.reminder.due": "thread.reminder.due";
|
|
203
|
+
"thread.signal.created": "thread.signal.created";
|
|
202
204
|
}>, z.ZodString]>>>;
|
|
203
205
|
condition: z.ZodOptional<z.ZodString>;
|
|
204
206
|
}, z.core.$strip>>;
|
|
@@ -220,6 +222,7 @@ export declare const ResolvedTriggerSchema: z.ZodObject<{
|
|
|
220
222
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
221
223
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
222
224
|
"thread.reminder.due": "thread.reminder.due";
|
|
225
|
+
"thread.signal.created": "thread.signal.created";
|
|
223
226
|
}>, z.ZodString]>;
|
|
224
227
|
payload: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
225
228
|
participant: z.ZodOptional<z.ZodObject<{
|
package/dist/types/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export type { InvocationType, ServerHookHandle, InvocationContext, } from './inv
|
|
|
9
9
|
export { createToolCallContext, createServerHookContext, createWebhookContext, createWorkflowStepContext, } from './invocation';
|
|
10
10
|
export type { ToolTrigger, ProvisionToolContext, DeveloperPageActionToolContext, DeveloperFormSubmitToolContext, FieldChangeToolContext, PageActionToolContext, FormSubmitToolContext, AgentToolContext, WorkflowToolContext, CronToolContext, CronContext, ToolExecutionContext, } from './tool-context';
|
|
11
11
|
export { isProvisionContext, isRuntimeContext, isCronContext, isDeveloperContext } from './tool-context';
|
|
12
|
-
export type { ToolResult, ToolSuccess, ToolFailure, ErrorCode, ErrorCategory, ToolWarning, ToolPagination, ToolBilling, ToolRetry, ToolTiming, ToolCompletionHints, ToolConfig, BillingInfo, ToolResponseMeta, ToolEffect, ToolError, ToolExecutionResult, ToolSchemaWithJson, ToolSchema, ToolHandler, ToolDefinition, ToolRegistryEntry, ToolRegistry, ToolName, ToolMetadata, ToolCallResponse, ExecutionScope, } from './tool';
|
|
12
|
+
export type { ToolResult, ToolSuccess, ToolFailure, ErrorCode, ErrorCategory, ToolWarning, ToolPagination, ToolBilling, ToolRetry, ToolTiming, ToolCompletionHints, ToolConfig, QueueTouchPoint, BillingInfo, ToolResponseMeta, ToolEffect, ToolError, ToolExecutionResult, ToolSchemaWithJson, ToolSchema, ToolHandler, ToolDefinition, ToolRegistryEntry, ToolRegistry, ToolName, ToolMetadata, ToolCallResponse, ExecutionScope, } from './tool';
|
|
13
13
|
export { ToolResponseMetaSchema } from './tool';
|
|
14
14
|
export { createSuccessResponse, createListResponse, createErrorResponse, createValidationError, createNotFoundError, createAuthError, createRateLimitError, createExternalError, createTimeoutError, createPermissionError, createConflictError, isSuccess, isFailure, isRetryable, getRetryDelay, } from './tool-response';
|
|
15
15
|
export type { HealthStatus, ComputeLayer, DedicatedServerInstance, ServerlessServerInstance, SkedyulServerInstance, } from './server';
|
package/dist/types/tool.d.ts
CHANGED
|
@@ -92,9 +92,18 @@ export interface ToolCompletionHints {
|
|
|
92
92
|
idempotent?: boolean;
|
|
93
93
|
}
|
|
94
94
|
/**
|
|
95
|
-
*
|
|
96
|
-
* Groups timeout, retry, and completion hint settings.
|
|
95
|
+
* Declares which rate-limit queues a tool may touch (for orchestration probes).
|
|
97
96
|
*/
|
|
97
|
+
export interface QueueTouchPoint {
|
|
98
|
+
/** Queue name from skedyul.config queues (e.g. petbooqz_api) */
|
|
99
|
+
queue: string;
|
|
100
|
+
/** Conservative max upstream HTTP calls this handler may make */
|
|
101
|
+
estimatedCalls: number;
|
|
102
|
+
/** Arg field used as sub-key for per-resource mutex queues */
|
|
103
|
+
subKeyFromArg?: string;
|
|
104
|
+
/** True for correctness mutexes — excluded from rate-limit probe admission */
|
|
105
|
+
mutexOnly?: boolean;
|
|
106
|
+
}
|
|
98
107
|
export interface ToolConfig {
|
|
99
108
|
/** Timeout in milliseconds. Defaults to 10000 (10 seconds) if not specified. */
|
|
100
109
|
timeout?: number;
|
|
@@ -102,6 +111,8 @@ export interface ToolConfig {
|
|
|
102
111
|
retries?: number;
|
|
103
112
|
/** Hints for controlling tool completion behavior in agent loops */
|
|
104
113
|
completionHints?: ToolCompletionHints;
|
|
114
|
+
/** Rate-limit queue touch points for orchestration admission probes */
|
|
115
|
+
queueTouchPoints?: QueueTouchPoint[];
|
|
105
116
|
}
|
|
106
117
|
/**
|
|
107
118
|
* Successful tool execution result.
|
|
@@ -179,6 +190,8 @@ export interface ToolExecutionResult<Output = unknown> {
|
|
|
179
190
|
meta?: ToolResponseMeta;
|
|
180
191
|
effect?: ToolEffect;
|
|
181
192
|
error?: ToolError | null;
|
|
193
|
+
/** Retry guidance for transient failures (e.g. rate limiting) */
|
|
194
|
+
retry?: ToolRetry;
|
|
182
195
|
/** Rich data blocks for UI rendering (profiles, spreadsheets, datetime cards) */
|
|
183
196
|
dataBlocks?: import('./data-blocks').DataBlock[];
|
|
184
197
|
/** Cursor state for cron subscriptions - saved and passed to the next run */
|
|
@@ -215,6 +228,8 @@ export interface ToolDefinition<Input = unknown, Output = unknown, InputSchema e
|
|
|
215
228
|
outputSchema?: ToolSchema<OutputSchema>;
|
|
216
229
|
/** Tool execution configuration (timeout, retries, completion hints) */
|
|
217
230
|
config?: ToolConfig;
|
|
231
|
+
/** Rate-limit queue touch points (also accepted at top level for ergonomics) */
|
|
232
|
+
queueTouchPoints?: QueueTouchPoint[];
|
|
218
233
|
/**
|
|
219
234
|
* Execution scope for this tool.
|
|
220
235
|
* - `installation` (default): Requires appInstallationId, receives sk_wkp_ token.
|
|
@@ -233,6 +248,8 @@ export interface ToolRegistryEntry {
|
|
|
233
248
|
outputSchema?: ToolSchema;
|
|
234
249
|
/** Tool execution configuration (timeout, retries, completion hints) */
|
|
235
250
|
config?: ToolConfig;
|
|
251
|
+
/** Rate-limit queue touch points */
|
|
252
|
+
queueTouchPoints?: QueueTouchPoint[];
|
|
236
253
|
/** Execution scope for this tool */
|
|
237
254
|
executionScope?: ExecutionScope;
|
|
238
255
|
[key: string]: unknown;
|
|
@@ -251,6 +268,8 @@ export interface ToolMetadata {
|
|
|
251
268
|
retries?: number;
|
|
252
269
|
/** Tool execution configuration (timeout, retries, completion hints) */
|
|
253
270
|
config?: ToolConfig;
|
|
271
|
+
/** Rate-limit queue touch points for orchestration admission probes */
|
|
272
|
+
queueTouchPoints?: QueueTouchPoint[];
|
|
254
273
|
/** Execution scope for this tool */
|
|
255
274
|
executionScope?: ExecutionScope;
|
|
256
275
|
}
|
|
@@ -82,6 +82,7 @@ export declare const WorkflowYAMLSchema: z.ZodObject<{
|
|
|
82
82
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
83
83
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
84
84
|
"thread.reminder.due": "thread.reminder.due";
|
|
85
|
+
"thread.signal.created": "thread.signal.created";
|
|
85
86
|
}>, z.ZodString]>>>;
|
|
86
87
|
condition: z.ZodOptional<z.ZodString>;
|
|
87
88
|
emits: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodEnum<{
|
|
@@ -98,6 +99,7 @@ export declare const WorkflowYAMLSchema: z.ZodObject<{
|
|
|
98
99
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
99
100
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
100
101
|
"thread.reminder.due": "thread.reminder.due";
|
|
102
|
+
"thread.signal.created": "thread.signal.created";
|
|
101
103
|
}>, z.ZodString]>>>;
|
|
102
104
|
waits: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
103
105
|
event: z.ZodUnion<readonly [z.ZodEnum<{
|
|
@@ -114,6 +116,7 @@ export declare const WorkflowYAMLSchema: z.ZodObject<{
|
|
|
114
116
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
115
117
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
116
118
|
"thread.reminder.due": "thread.reminder.due";
|
|
119
|
+
"thread.signal.created": "thread.signal.created";
|
|
117
120
|
}>, z.ZodString]>;
|
|
118
121
|
timeout: z.ZodOptional<z.ZodString>;
|
|
119
122
|
onTimeout: z.ZodOptional<z.ZodString>;
|
|
@@ -132,6 +135,7 @@ export declare const WorkflowYAMLSchema: z.ZodObject<{
|
|
|
132
135
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
133
136
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
134
137
|
"thread.reminder.due": "thread.reminder.due";
|
|
138
|
+
"thread.signal.created": "thread.signal.created";
|
|
135
139
|
}>, z.ZodString]>>>;
|
|
136
140
|
cancelCondition: z.ZodOptional<z.ZodString>;
|
|
137
141
|
}, z.core.$strip>>;
|
|
@@ -192,6 +196,7 @@ export declare const WorkflowMetadataSchema: z.ZodObject<{
|
|
|
192
196
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
193
197
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
194
198
|
"thread.reminder.due": "thread.reminder.due";
|
|
199
|
+
"thread.signal.created": "thread.signal.created";
|
|
195
200
|
}>, z.ZodString]>>>;
|
|
196
201
|
condition: z.ZodOptional<z.ZodString>;
|
|
197
202
|
emits: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodEnum<{
|
|
@@ -208,6 +213,7 @@ export declare const WorkflowMetadataSchema: z.ZodObject<{
|
|
|
208
213
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
209
214
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
210
215
|
"thread.reminder.due": "thread.reminder.due";
|
|
216
|
+
"thread.signal.created": "thread.signal.created";
|
|
211
217
|
}>, z.ZodString]>>>;
|
|
212
218
|
waits: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
213
219
|
event: z.ZodUnion<readonly [z.ZodEnum<{
|
|
@@ -224,6 +230,7 @@ export declare const WorkflowMetadataSchema: z.ZodObject<{
|
|
|
224
230
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
225
231
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
226
232
|
"thread.reminder.due": "thread.reminder.due";
|
|
233
|
+
"thread.signal.created": "thread.signal.created";
|
|
227
234
|
}>, z.ZodString]>;
|
|
228
235
|
timeout: z.ZodOptional<z.ZodString>;
|
|
229
236
|
onTimeout: z.ZodOptional<z.ZodString>;
|
|
@@ -242,6 +249,7 @@ export declare const WorkflowMetadataSchema: z.ZodObject<{
|
|
|
242
249
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
243
250
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
244
251
|
"thread.reminder.due": "thread.reminder.due";
|
|
252
|
+
"thread.signal.created": "thread.signal.created";
|
|
245
253
|
}>, z.ZodString]>>>;
|
|
246
254
|
cancelCondition: z.ZodOptional<z.ZodString>;
|
|
247
255
|
}, z.core.$strip>>;
|