@workglow/job-queue 0.1.2 → 0.2.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/browser.js +88 -27
- package/dist/browser.js.map +8 -7
- package/dist/bun.js +88 -27
- package/dist/bun.js.map +8 -7
- package/dist/common.d.ts +1 -0
- package/dist/common.d.ts.map +1 -1
- package/dist/job/JobError.d.ts +0 -4
- package/dist/job/JobError.d.ts.map +1 -1
- package/dist/job/JobErrorDiagnostics.d.ts +26 -0
- package/dist/job/JobErrorDiagnostics.d.ts.map +1 -0
- package/dist/job/JobQueueClient.d.ts.map +1 -1
- package/dist/job/JobQueueWorker.d.ts.map +1 -1
- package/dist/node.js +88 -27
- package/dist/node.js.map +8 -7
- package/package.json +10 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JobQueueWorker.d.ts","sourceRoot":"","sources":["../../src/job/JobQueueWorker.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAa,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,
|
|
1
|
+
{"version":3,"file":"JobQueueWorker.d.ts","sourceRoot":"","sources":["../../src/job/JobQueueWorker.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAa,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EACL,YAAY,EAMb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAGL,QAAQ,EAIT,MAAM,YAAY,CAAC;AAIpB;;GAEG;AACH,MAAM,MAAM,4BAA4B,CAAC,KAAK,EAAE,MAAM,IAAI;IACxD,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACvE,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,KAAK,IAAI,CAAC;IACpD,YAAY,EAAE,CACZ,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,KACpC,IAAI,CAAC;IACV,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,MAAM,4BAA4B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAExF;;GAEG;AACH,MAAM,WAAW,qBAAqB,CAAC,KAAK,EAAE,MAAM;IAClD,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;;GAGG;AACH,qBAAa,cAAc,CACzB,KAAK,EACL,MAAM,EACN,QAAQ,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC;IAExD,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACzD,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACrD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IACrC,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAC1C,SAAS,CAAC,QAAQ,CAAC,MAAM,4DAAmE;IAE5F,SAAS,CAAC,OAAO,UAAS;IAE1B;;;OAGG;IACH,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,SAAS,CAA8C;IAE/D;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,yBAAyB,EAAE,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC,CAAa;IAExF;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAa;IAErE,YAAY,QAAQ,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,EAO3F;IAED;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAQlC;IAED;;;OAGG;IACI,MAAM,IAAI,IAAI,CASpB;IAED;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAwBjC;IAED;;OAEG;IACU,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAa3C;IAED;;OAEG;IACI,SAAS,IAAI,OAAO,CAE1B;IAED;;OAEG;IACI,iBAAiB,IAAI,MAAM,CAEjC;IAED;;OAEG;IACI,wBAAwB,IAAI,MAAM,GAAG,SAAS,CAIpD;IAMM,EAAE,CAAC,KAAK,SAAS,oBAAoB,EAC1C,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,4BAA4B,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAC3D,IAAI,CAEN;IAEM,GAAG,CAAC,KAAK,SAAS,oBAAoB,EAC3C,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,4BAA4B,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAC3D,IAAI,CAEN;IAMD;;OAEG;IACH,UAAgB,IAAI,IAAI,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAIpD;IAED;;;;;;;;;;;OAWG;IACH,UAAgB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAoC3C;YASa,YAAY;IAe1B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAc5B;;OAEG;IACH,UAAgB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQpD;IAED;;OAEG;IACH,UAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAmEvE;IAED;;OAEG;IACH,UAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAMxF;IAED;;OAEG;IACH,UAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAW,EACpB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAW,GAC7C,OAAO,CAAC,IAAI,CAAC,CAMf;IAED;;OAEG;IACH,UAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBnF;IAED;;OAEG;IACH,UAAgB,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/E;IAED;;OAEG;IACH,UAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAejE;IAED;;OAEG;IACH,UAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBtF;IAED;;OAEG;IACH,SAAS,CAAC,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAW/D;IAED;;OAEG;IACH,UAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAQzD;IAED;;OAEG;IACH,UAAgB,MAAM,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAI3E;IAED;;OAEG;IACH,UAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBvE;IAED;;OAEG;IACH,SAAS,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAQ/C;IAED;;OAEG;IACH,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAEzC;IAED;;OAEG;IACH,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAErF;IAED;;OAEG;IACH,SAAS,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAEjF;CACF"}
|
package/dist/node.js
CHANGED
|
@@ -5,13 +5,8 @@ import { JobStatus } from "@workglow/storage";
|
|
|
5
5
|
import { BaseError } from "@workglow/util";
|
|
6
6
|
|
|
7
7
|
class JobError extends BaseError {
|
|
8
|
-
message;
|
|
9
8
|
static type = "JobError";
|
|
10
9
|
retryable = false;
|
|
11
|
-
constructor(message) {
|
|
12
|
-
super(message);
|
|
13
|
-
this.message = message;
|
|
14
|
-
}
|
|
15
10
|
}
|
|
16
11
|
|
|
17
12
|
class JobNotFoundError extends JobError {
|
|
@@ -33,16 +28,10 @@ class RetryableJobError extends JobError {
|
|
|
33
28
|
|
|
34
29
|
class PermanentJobError extends JobError {
|
|
35
30
|
static type = "PermanentJobError";
|
|
36
|
-
constructor(message) {
|
|
37
|
-
super(message);
|
|
38
|
-
}
|
|
39
31
|
}
|
|
40
32
|
|
|
41
33
|
class AbortSignalJobError extends PermanentJobError {
|
|
42
34
|
static type = "AbortSignalJobError";
|
|
43
|
-
constructor(message) {
|
|
44
|
-
super(message);
|
|
45
|
-
}
|
|
46
35
|
}
|
|
47
36
|
|
|
48
37
|
class JobDisabledError extends PermanentJobError {
|
|
@@ -134,6 +123,57 @@ class Job {
|
|
|
134
123
|
}
|
|
135
124
|
}
|
|
136
125
|
|
|
126
|
+
// src/job/JobErrorDiagnostics.ts
|
|
127
|
+
var JOB_ERROR_DIAGNOSTICS_MARKER = `
|
|
128
|
+
|
|
129
|
+
--- Error diagnostics ---
|
|
130
|
+
`;
|
|
131
|
+
var DEFAULT_MAX_DIAGNOSTICS_CHARS = 48000;
|
|
132
|
+
function formatErrorChainForDiagnostics(err, maxChars = DEFAULT_MAX_DIAGNOSTICS_CHARS) {
|
|
133
|
+
const lines = [];
|
|
134
|
+
let current = err;
|
|
135
|
+
for (let depth = 0;depth < 8 && current != null; depth++) {
|
|
136
|
+
if (current instanceof Error) {
|
|
137
|
+
lines.push(`${current.name}: ${current.message}`);
|
|
138
|
+
if (current.stack) {
|
|
139
|
+
lines.push(current.stack);
|
|
140
|
+
}
|
|
141
|
+
const next = current.cause;
|
|
142
|
+
if (next === undefined || next === null) {
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
lines.push("");
|
|
146
|
+
current = next;
|
|
147
|
+
} else {
|
|
148
|
+
lines.push(typeof current === "string" ? current : String(current));
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const text = lines.join(`
|
|
153
|
+
`);
|
|
154
|
+
if (text.length <= maxChars) {
|
|
155
|
+
return text;
|
|
156
|
+
}
|
|
157
|
+
return `${text.slice(0, maxChars)}
|
|
158
|
+
…(truncated)`;
|
|
159
|
+
}
|
|
160
|
+
function withJobErrorDiagnostics(summaryLine, err) {
|
|
161
|
+
const diag = formatErrorChainForDiagnostics(err);
|
|
162
|
+
if (diag.length === 0) {
|
|
163
|
+
return summaryLine;
|
|
164
|
+
}
|
|
165
|
+
return `${summaryLine}${JOB_ERROR_DIAGNOSTICS_MARKER}${diag}`;
|
|
166
|
+
}
|
|
167
|
+
function applyPersistedDiagnosticsToStack(jobError, fullMessage) {
|
|
168
|
+
if (!fullMessage.includes(JOB_ERROR_DIAGNOSTICS_MARKER)) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const firstLine = fullMessage.split(`
|
|
172
|
+
`)[0] ?? fullMessage;
|
|
173
|
+
jobError.stack = `${jobError.name}: ${firstLine}
|
|
174
|
+
${fullMessage}`;
|
|
175
|
+
}
|
|
176
|
+
|
|
137
177
|
// src/job/JobQueueClient.ts
|
|
138
178
|
import { JobStatus as JobStatus2 } from "@workglow/storage";
|
|
139
179
|
import { EventEmitter } from "@workglow/util";
|
|
@@ -464,18 +504,28 @@ class JobQueueClient {
|
|
|
464
504
|
}
|
|
465
505
|
buildErrorFromCode(message, errorCode) {
|
|
466
506
|
if (errorCode === "PermanentJobError") {
|
|
467
|
-
|
|
507
|
+
const err2 = new PermanentJobError(message);
|
|
508
|
+
applyPersistedDiagnosticsToStack(err2, message);
|
|
509
|
+
return err2;
|
|
468
510
|
}
|
|
469
511
|
if (errorCode === "RetryableJobError") {
|
|
470
|
-
|
|
512
|
+
const err2 = new RetryableJobError(message);
|
|
513
|
+
applyPersistedDiagnosticsToStack(err2, message);
|
|
514
|
+
return err2;
|
|
471
515
|
}
|
|
472
516
|
if (errorCode === "AbortSignalJobError") {
|
|
473
|
-
|
|
517
|
+
const err2 = new AbortSignalJobError(message);
|
|
518
|
+
applyPersistedDiagnosticsToStack(err2, message);
|
|
519
|
+
return err2;
|
|
474
520
|
}
|
|
475
521
|
if (errorCode === "JobDisabledError") {
|
|
476
|
-
|
|
522
|
+
const err2 = new JobDisabledError(message);
|
|
523
|
+
applyPersistedDiagnosticsToStack(err2, message);
|
|
524
|
+
return err2;
|
|
477
525
|
}
|
|
478
|
-
|
|
526
|
+
const err = new JobError(message);
|
|
527
|
+
applyPersistedDiagnosticsToStack(err, message);
|
|
528
|
+
return err;
|
|
479
529
|
}
|
|
480
530
|
}
|
|
481
531
|
|
|
@@ -502,7 +552,14 @@ class NullLimiter {
|
|
|
502
552
|
|
|
503
553
|
// src/job/JobQueueWorker.ts
|
|
504
554
|
import { JobStatus as JobStatus3 } from "@workglow/storage";
|
|
505
|
-
import {
|
|
555
|
+
import {
|
|
556
|
+
EventEmitter as EventEmitter2,
|
|
557
|
+
getLogger,
|
|
558
|
+
getTelemetryProvider,
|
|
559
|
+
sleep,
|
|
560
|
+
SpanStatusCode,
|
|
561
|
+
uuid4
|
|
562
|
+
} from "@workglow/util";
|
|
506
563
|
class JobQueueWorker {
|
|
507
564
|
queueName;
|
|
508
565
|
workerId;
|
|
@@ -736,7 +793,7 @@ class JobQueueWorker {
|
|
|
736
793
|
await this.storage.complete(this.classToStorage(job));
|
|
737
794
|
this.events.emit("job_complete", job.id, output);
|
|
738
795
|
} catch (err) {
|
|
739
|
-
|
|
796
|
+
getLogger().error("completeJob errored:", { error: err });
|
|
740
797
|
} finally {
|
|
741
798
|
this.cleanupJob(job.id);
|
|
742
799
|
}
|
|
@@ -753,7 +810,7 @@ class JobQueueWorker {
|
|
|
753
810
|
await this.storage.complete(this.classToStorage(job));
|
|
754
811
|
this.events.emit("job_error", job.id, error.message, error.constructor.name);
|
|
755
812
|
} catch (err) {
|
|
756
|
-
|
|
813
|
+
getLogger().error("failJob errored:", { error: err });
|
|
757
814
|
} finally {
|
|
758
815
|
this.cleanupJob(job.id);
|
|
759
816
|
}
|
|
@@ -768,7 +825,7 @@ class JobQueueWorker {
|
|
|
768
825
|
await this.storage.complete(this.classToStorage(job));
|
|
769
826
|
this.events.emit("job_disabled", job.id);
|
|
770
827
|
} catch (err) {
|
|
771
|
-
|
|
828
|
+
getLogger().error("disableJob errored:", { error: err });
|
|
772
829
|
} finally {
|
|
773
830
|
this.cleanupJob(job.id);
|
|
774
831
|
}
|
|
@@ -785,7 +842,7 @@ class JobQueueWorker {
|
|
|
785
842
|
await this.storage.complete(this.classToStorage(job));
|
|
786
843
|
this.events.emit("job_retry", job.id, job.runAfter);
|
|
787
844
|
} catch (err) {
|
|
788
|
-
|
|
845
|
+
getLogger().error("rescheduleJob errored:", { error: err });
|
|
789
846
|
}
|
|
790
847
|
}
|
|
791
848
|
createAbortController(jobId) {
|
|
@@ -802,7 +859,7 @@ class JobQueueWorker {
|
|
|
802
859
|
async handleAbort(jobId) {
|
|
803
860
|
const job = await this.getJob(jobId);
|
|
804
861
|
if (!job) {
|
|
805
|
-
|
|
862
|
+
getLogger().error("handleAbort: job not found", { jobId });
|
|
806
863
|
return;
|
|
807
864
|
}
|
|
808
865
|
const error = new AbortSignalJobError("Job Aborted");
|
|
@@ -836,7 +893,7 @@ class JobQueueWorker {
|
|
|
836
893
|
return err;
|
|
837
894
|
}
|
|
838
895
|
if (err instanceof Error) {
|
|
839
|
-
return new PermanentJobError(err.message);
|
|
896
|
+
return new PermanentJobError(withJobErrorDiagnostics(err.message, err));
|
|
840
897
|
}
|
|
841
898
|
return new PermanentJobError(String(err));
|
|
842
899
|
}
|
|
@@ -1145,10 +1202,10 @@ class CompositeLimiter {
|
|
|
1145
1202
|
return true;
|
|
1146
1203
|
}
|
|
1147
1204
|
async recordJobStart() {
|
|
1148
|
-
this.limiters.
|
|
1205
|
+
await Promise.all(this.limiters.map((limiter) => limiter.recordJobStart()));
|
|
1149
1206
|
}
|
|
1150
1207
|
async recordJobCompletion() {
|
|
1151
|
-
this.limiters.
|
|
1208
|
+
await Promise.all(this.limiters.map((limiter) => limiter.recordJobCompletion()));
|
|
1152
1209
|
}
|
|
1153
1210
|
async getNextAvailableTime() {
|
|
1154
1211
|
let maxDate = new Date;
|
|
@@ -1166,7 +1223,7 @@ class CompositeLimiter {
|
|
|
1166
1223
|
}
|
|
1167
1224
|
}
|
|
1168
1225
|
async clear() {
|
|
1169
|
-
this.limiters.
|
|
1226
|
+
await Promise.all(this.limiters.map((limiter) => limiter.clear()));
|
|
1170
1227
|
}
|
|
1171
1228
|
}
|
|
1172
1229
|
|
|
@@ -1404,8 +1461,11 @@ class RateLimiter {
|
|
|
1404
1461
|
}
|
|
1405
1462
|
}
|
|
1406
1463
|
export {
|
|
1464
|
+
withJobErrorDiagnostics,
|
|
1407
1465
|
storageToClass,
|
|
1466
|
+
formatErrorChainForDiagnostics,
|
|
1408
1467
|
classToStorage,
|
|
1468
|
+
applyPersistedDiagnosticsToStack,
|
|
1409
1469
|
RetryableJobError,
|
|
1410
1470
|
RateLimiter,
|
|
1411
1471
|
PermanentJobError,
|
|
@@ -1420,6 +1480,7 @@ export {
|
|
|
1420
1480
|
JobDisabledError,
|
|
1421
1481
|
Job,
|
|
1422
1482
|
JOB_LIMITER,
|
|
1483
|
+
JOB_ERROR_DIAGNOSTICS_MARKER,
|
|
1423
1484
|
EvenlySpacedRateLimiter,
|
|
1424
1485
|
EVENLY_SPACED_JOB_RATE_LIMITER,
|
|
1425
1486
|
DelayLimiter,
|
|
@@ -1429,4 +1490,4 @@ export {
|
|
|
1429
1490
|
AbortSignalJobError
|
|
1430
1491
|
};
|
|
1431
1492
|
|
|
1432
|
-
//# debugId=
|
|
1493
|
+
//# debugId=93B340A5BCA30A6964756E2164756E21
|