@copilotkitnext/runtime 1.51.2-next.1 → 1.51.3-next.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/{chunk-4NPALSVP.mjs → chunk-HN3TDK74.mjs} +130 -72
- package/dist/chunk-HN3TDK74.mjs.map +1 -0
- package/dist/express.d.mts +1 -1
- package/dist/express.d.ts +1 -1
- package/dist/express.js +148 -92
- package/dist/express.js.map +1 -1
- package/dist/express.mjs +3 -2
- package/dist/express.mjs.map +1 -1
- package/dist/index.d.mts +35 -5
- package/dist/index.d.ts +35 -5
- package/dist/index.js +161 -97
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +16 -8
- package/dist/index.mjs.map +1 -1
- package/dist/{runtime-BEcxV64L.d.mts → runtime-biMoHc-z.d.mts} +1 -1
- package/dist/{runtime-BEcxV64L.d.ts → runtime-biMoHc-z.d.ts} +1 -1
- package/package.json +9 -7
- package/dist/chunk-4NPALSVP.mjs.map +0 -1
package/dist/express.js
CHANGED
|
@@ -377,7 +377,7 @@ async function handleStopAgent({
|
|
|
377
377
|
// package.json
|
|
378
378
|
var package_default = {
|
|
379
379
|
name: "@copilotkitnext/runtime",
|
|
380
|
-
version: "1.51.
|
|
380
|
+
version: "1.51.3-next.0",
|
|
381
381
|
description: "Server-side runtime package for CopilotKit2",
|
|
382
382
|
main: "dist/index.js",
|
|
383
383
|
types: "dist/index.d.ts",
|
|
@@ -413,7 +413,6 @@ var package_default = {
|
|
|
413
413
|
"@types/express": "^4.17.21",
|
|
414
414
|
"@types/node": "^22.15.3",
|
|
415
415
|
eslint: "^9.30.0",
|
|
416
|
-
openai: "^5.9.0",
|
|
417
416
|
supertest: "^7.1.1",
|
|
418
417
|
tsup: "^8.5.0",
|
|
419
418
|
typescript: "5.8.2",
|
|
@@ -426,11 +425,14 @@ var package_default = {
|
|
|
426
425
|
"@copilotkitnext/shared": "workspace:*",
|
|
427
426
|
cors: "^2.8.5",
|
|
428
427
|
express: "^4.21.2",
|
|
429
|
-
hono: "^4.
|
|
428
|
+
hono: "^4.11.4",
|
|
430
429
|
rxjs: "7.8.1"
|
|
431
430
|
},
|
|
432
431
|
peerDependencies: {
|
|
433
|
-
|
|
432
|
+
"@ag-ui/client": "0.0.42",
|
|
433
|
+
"@ag-ui/core": "0.0.42",
|
|
434
|
+
"@ag-ui/encoder": "0.0.42",
|
|
435
|
+
"@copilotkitnext/shared": "workspace:*"
|
|
434
436
|
},
|
|
435
437
|
peerDependenciesMeta: {},
|
|
436
438
|
engines: {
|
|
@@ -528,73 +530,135 @@ async function handleGetRuntimeInfo({
|
|
|
528
530
|
}
|
|
529
531
|
|
|
530
532
|
// src/handlers/handle-transcribe.ts
|
|
533
|
+
var import_shared2 = require("@copilotkitnext/shared");
|
|
534
|
+
var ERROR_STATUS_CODES = {
|
|
535
|
+
[import_shared2.TranscriptionErrorCode.SERVICE_NOT_CONFIGURED]: 503,
|
|
536
|
+
[import_shared2.TranscriptionErrorCode.INVALID_AUDIO_FORMAT]: 400,
|
|
537
|
+
[import_shared2.TranscriptionErrorCode.AUDIO_TOO_LONG]: 400,
|
|
538
|
+
[import_shared2.TranscriptionErrorCode.AUDIO_TOO_SHORT]: 400,
|
|
539
|
+
[import_shared2.TranscriptionErrorCode.RATE_LIMITED]: 429,
|
|
540
|
+
[import_shared2.TranscriptionErrorCode.AUTH_FAILED]: 401,
|
|
541
|
+
[import_shared2.TranscriptionErrorCode.PROVIDER_ERROR]: 500,
|
|
542
|
+
[import_shared2.TranscriptionErrorCode.NETWORK_ERROR]: 502,
|
|
543
|
+
[import_shared2.TranscriptionErrorCode.INVALID_REQUEST]: 400
|
|
544
|
+
};
|
|
545
|
+
var VALID_AUDIO_TYPES = [
|
|
546
|
+
"audio/mpeg",
|
|
547
|
+
"audio/mp3",
|
|
548
|
+
"audio/mp4",
|
|
549
|
+
"audio/wav",
|
|
550
|
+
"audio/webm",
|
|
551
|
+
"audio/ogg",
|
|
552
|
+
"audio/flac",
|
|
553
|
+
"audio/aac"
|
|
554
|
+
];
|
|
555
|
+
function isValidAudioType(type) {
|
|
556
|
+
const baseType = type.split(";")[0]?.trim() ?? "";
|
|
557
|
+
return VALID_AUDIO_TYPES.includes(baseType) || baseType === "" || baseType === "application/octet-stream";
|
|
558
|
+
}
|
|
559
|
+
function createErrorResponse(errorResponse) {
|
|
560
|
+
const status = ERROR_STATUS_CODES[errorResponse.error] ?? 500;
|
|
561
|
+
return new Response(JSON.stringify(errorResponse), {
|
|
562
|
+
status,
|
|
563
|
+
headers: { "Content-Type": "application/json" }
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
function base64ToFile(base64, mimeType, filename) {
|
|
567
|
+
const base64Data = base64.includes(",") ? base64.split(",")[1] ?? base64 : base64;
|
|
568
|
+
const binaryString = atob(base64Data);
|
|
569
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
570
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
571
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
572
|
+
}
|
|
573
|
+
return new File([bytes], filename, { type: mimeType });
|
|
574
|
+
}
|
|
575
|
+
async function extractAudioFromFormData(request) {
|
|
576
|
+
const formData = await request.formData();
|
|
577
|
+
const audioFile = formData.get("audio");
|
|
578
|
+
if (!audioFile || !(audioFile instanceof File)) {
|
|
579
|
+
const err = import_shared2.TranscriptionErrors.invalidRequest(
|
|
580
|
+
"No audio file found in form data. Please include an 'audio' field."
|
|
581
|
+
);
|
|
582
|
+
return { error: createErrorResponse(err) };
|
|
583
|
+
}
|
|
584
|
+
if (!isValidAudioType(audioFile.type)) {
|
|
585
|
+
const err = import_shared2.TranscriptionErrors.invalidAudioFormat(audioFile.type, VALID_AUDIO_TYPES);
|
|
586
|
+
return { error: createErrorResponse(err) };
|
|
587
|
+
}
|
|
588
|
+
return { file: audioFile };
|
|
589
|
+
}
|
|
590
|
+
async function extractAudioFromJson(request) {
|
|
591
|
+
let body;
|
|
592
|
+
try {
|
|
593
|
+
body = await request.json();
|
|
594
|
+
} catch {
|
|
595
|
+
const err = import_shared2.TranscriptionErrors.invalidRequest("Request body must be valid JSON");
|
|
596
|
+
return { error: createErrorResponse(err) };
|
|
597
|
+
}
|
|
598
|
+
if (!body.audio || typeof body.audio !== "string") {
|
|
599
|
+
const err = import_shared2.TranscriptionErrors.invalidRequest(
|
|
600
|
+
"Request must include 'audio' field with base64-encoded audio data"
|
|
601
|
+
);
|
|
602
|
+
return { error: createErrorResponse(err) };
|
|
603
|
+
}
|
|
604
|
+
if (!body.mimeType || typeof body.mimeType !== "string") {
|
|
605
|
+
const err = import_shared2.TranscriptionErrors.invalidRequest(
|
|
606
|
+
"Request must include 'mimeType' field (e.g., 'audio/webm')"
|
|
607
|
+
);
|
|
608
|
+
return { error: createErrorResponse(err) };
|
|
609
|
+
}
|
|
610
|
+
if (!isValidAudioType(body.mimeType)) {
|
|
611
|
+
const err = import_shared2.TranscriptionErrors.invalidAudioFormat(body.mimeType, VALID_AUDIO_TYPES);
|
|
612
|
+
return { error: createErrorResponse(err) };
|
|
613
|
+
}
|
|
614
|
+
try {
|
|
615
|
+
const filename = body.filename || "recording.webm";
|
|
616
|
+
const file = base64ToFile(body.audio, body.mimeType, filename);
|
|
617
|
+
return { file };
|
|
618
|
+
} catch {
|
|
619
|
+
const err = import_shared2.TranscriptionErrors.invalidRequest("Failed to decode base64 audio data");
|
|
620
|
+
return { error: createErrorResponse(err) };
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
function categorizeProviderError(error) {
|
|
624
|
+
const message = error instanceof Error ? error.message : "Unknown error occurred";
|
|
625
|
+
const errorStr = String(error).toLowerCase();
|
|
626
|
+
if (errorStr.includes("rate") || errorStr.includes("429") || errorStr.includes("too many")) {
|
|
627
|
+
return import_shared2.TranscriptionErrors.rateLimited();
|
|
628
|
+
}
|
|
629
|
+
if (errorStr.includes("auth") || errorStr.includes("401") || errorStr.includes("api key") || errorStr.includes("unauthorized")) {
|
|
630
|
+
return import_shared2.TranscriptionErrors.authFailed();
|
|
631
|
+
}
|
|
632
|
+
if (errorStr.includes("too long") || errorStr.includes("duration") || errorStr.includes("length")) {
|
|
633
|
+
return import_shared2.TranscriptionErrors.audioTooLong();
|
|
634
|
+
}
|
|
635
|
+
return import_shared2.TranscriptionErrors.providerError(message);
|
|
636
|
+
}
|
|
531
637
|
async function handleTranscribe({
|
|
532
638
|
runtime,
|
|
533
639
|
request
|
|
534
640
|
}) {
|
|
535
641
|
try {
|
|
536
642
|
if (!runtime.transcriptionService) {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
error: "Transcription service not configured",
|
|
540
|
-
message: "No transcription service has been configured in the runtime"
|
|
541
|
-
}),
|
|
542
|
-
{
|
|
543
|
-
status: 503,
|
|
544
|
-
headers: { "Content-Type": "application/json" }
|
|
545
|
-
}
|
|
546
|
-
);
|
|
547
|
-
}
|
|
548
|
-
const contentType = request.headers.get("content-type");
|
|
549
|
-
if (!contentType || !contentType.includes("multipart/form-data")) {
|
|
550
|
-
return new Response(
|
|
551
|
-
JSON.stringify({
|
|
552
|
-
error: "Invalid content type",
|
|
553
|
-
message: "Request must contain multipart/form-data with an audio file"
|
|
554
|
-
}),
|
|
555
|
-
{
|
|
556
|
-
status: 400,
|
|
557
|
-
headers: { "Content-Type": "application/json" }
|
|
558
|
-
}
|
|
559
|
-
);
|
|
643
|
+
const err = import_shared2.TranscriptionErrors.serviceNotConfigured();
|
|
644
|
+
return createErrorResponse(err);
|
|
560
645
|
}
|
|
561
|
-
const
|
|
562
|
-
|
|
563
|
-
if (
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
status: 400,
|
|
571
|
-
headers: { "Content-Type": "application/json" }
|
|
572
|
-
}
|
|
646
|
+
const contentType = request.headers.get("content-type") || "";
|
|
647
|
+
let extractResult;
|
|
648
|
+
if (contentType.includes("multipart/form-data")) {
|
|
649
|
+
extractResult = await extractAudioFromFormData(request);
|
|
650
|
+
} else if (contentType.includes("application/json")) {
|
|
651
|
+
extractResult = await extractAudioFromJson(request);
|
|
652
|
+
} else {
|
|
653
|
+
const err = import_shared2.TranscriptionErrors.invalidRequest(
|
|
654
|
+
"Request must be multipart/form-data or application/json with base64 audio"
|
|
573
655
|
);
|
|
656
|
+
return createErrorResponse(err);
|
|
574
657
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
"audio/mp3",
|
|
578
|
-
"audio/mp4",
|
|
579
|
-
"audio/wav",
|
|
580
|
-
"audio/webm",
|
|
581
|
-
"audio/ogg",
|
|
582
|
-
"audio/flac",
|
|
583
|
-
"audio/aac"
|
|
584
|
-
];
|
|
585
|
-
const isValidType = validAudioTypes.includes(audioFile.type) || audioFile.type === "" || audioFile.type === "application/octet-stream";
|
|
586
|
-
if (!isValidType) {
|
|
587
|
-
return new Response(
|
|
588
|
-
JSON.stringify({
|
|
589
|
-
error: "Invalid file type",
|
|
590
|
-
message: `Unsupported audio file type: ${audioFile.type}. Supported types: ${validAudioTypes.join(", ")}, or files with unknown/empty types`
|
|
591
|
-
}),
|
|
592
|
-
{
|
|
593
|
-
status: 400,
|
|
594
|
-
headers: { "Content-Type": "application/json" }
|
|
595
|
-
}
|
|
596
|
-
);
|
|
658
|
+
if ("error" in extractResult) {
|
|
659
|
+
return extractResult.error;
|
|
597
660
|
}
|
|
661
|
+
const audioFile = extractResult.file;
|
|
598
662
|
const transcription = await runtime.transcriptionService.transcribeFile({
|
|
599
663
|
audioFile,
|
|
600
664
|
mimeType: audioFile.type,
|
|
@@ -612,24 +676,15 @@ async function handleTranscribe({
|
|
|
612
676
|
}
|
|
613
677
|
);
|
|
614
678
|
} catch (error) {
|
|
615
|
-
return
|
|
616
|
-
JSON.stringify({
|
|
617
|
-
error: "Transcription failed",
|
|
618
|
-
message: error instanceof Error ? error.message : "Unknown error occurred during transcription"
|
|
619
|
-
}),
|
|
620
|
-
{
|
|
621
|
-
status: 500,
|
|
622
|
-
headers: { "Content-Type": "application/json" }
|
|
623
|
-
}
|
|
624
|
-
);
|
|
679
|
+
return createErrorResponse(categorizeProviderError(error));
|
|
625
680
|
}
|
|
626
681
|
}
|
|
627
682
|
|
|
628
683
|
// src/endpoints/express.ts
|
|
629
|
-
var
|
|
684
|
+
var import_shared5 = require("@copilotkitnext/shared");
|
|
630
685
|
|
|
631
686
|
// src/middleware.ts
|
|
632
|
-
var
|
|
687
|
+
var import_shared3 = require("@copilotkitnext/shared");
|
|
633
688
|
async function callBeforeRequestMiddleware({
|
|
634
689
|
runtime,
|
|
635
690
|
request,
|
|
@@ -640,7 +695,7 @@ async function callBeforeRequestMiddleware({
|
|
|
640
695
|
if (typeof mw === "function") {
|
|
641
696
|
return mw({ runtime, request, path });
|
|
642
697
|
}
|
|
643
|
-
|
|
698
|
+
import_shared3.logger.warn({ mw }, "Unsupported beforeRequestMiddleware value \u2013 skipped");
|
|
644
699
|
return;
|
|
645
700
|
}
|
|
646
701
|
async function callAfterRequestMiddleware({
|
|
@@ -653,14 +708,14 @@ async function callAfterRequestMiddleware({
|
|
|
653
708
|
if (typeof mw === "function") {
|
|
654
709
|
return mw({ runtime, response, path });
|
|
655
710
|
}
|
|
656
|
-
|
|
711
|
+
import_shared3.logger.warn({ mw }, "Unsupported afterRequestMiddleware value \u2013 skipped");
|
|
657
712
|
}
|
|
658
713
|
|
|
659
714
|
// src/endpoints/express-utils.ts
|
|
660
715
|
var import_node_stream = require("stream");
|
|
661
716
|
var import_node_stream2 = require("stream");
|
|
662
717
|
var import_node_util = require("util");
|
|
663
|
-
var
|
|
718
|
+
var import_shared4 = require("@copilotkitnext/shared");
|
|
664
719
|
var streamPipeline = (0, import_node_util.promisify)(import_node_stream2.pipeline);
|
|
665
720
|
var METHODS_WITHOUT_BODY = /* @__PURE__ */ new Set(["GET", "HEAD"]);
|
|
666
721
|
function createFetchRequestFromExpress(req) {
|
|
@@ -696,7 +751,7 @@ function createFetchRequestFromExpress(req) {
|
|
|
696
751
|
if (body !== void 0) {
|
|
697
752
|
init.body = body;
|
|
698
753
|
}
|
|
699
|
-
|
|
754
|
+
import_shared4.logger.info(
|
|
700
755
|
{
|
|
701
756
|
url,
|
|
702
757
|
method,
|
|
@@ -708,7 +763,7 @@ function createFetchRequestFromExpress(req) {
|
|
|
708
763
|
);
|
|
709
764
|
} else {
|
|
710
765
|
headers.delete("content-length");
|
|
711
|
-
|
|
766
|
+
import_shared4.logger.warn(
|
|
712
767
|
{ url, method },
|
|
713
768
|
"Request stream already consumed but no body was available; sending empty body"
|
|
714
769
|
);
|
|
@@ -736,13 +791,13 @@ function createFetchRequestFromExpress(req) {
|
|
|
736
791
|
headers.set("content-type", contentType);
|
|
737
792
|
}
|
|
738
793
|
init.body = body;
|
|
739
|
-
|
|
794
|
+
import_shared4.logger.info(
|
|
740
795
|
{ url, method },
|
|
741
796
|
"Request stream disturbed while constructing Request; reused parsed body"
|
|
742
797
|
);
|
|
743
798
|
} else {
|
|
744
799
|
init.body = void 0;
|
|
745
|
-
|
|
800
|
+
import_shared4.logger.warn(
|
|
746
801
|
{ url, method },
|
|
747
802
|
"Request stream was disturbed; falling back to empty body"
|
|
748
803
|
);
|
|
@@ -839,7 +894,7 @@ function createRouteHandler(runtime, factory) {
|
|
|
839
894
|
request = maybeModifiedRequest;
|
|
840
895
|
}
|
|
841
896
|
} catch (error) {
|
|
842
|
-
|
|
897
|
+
import_shared5.logger.error({ err: error, url: request.url, path }, "Error running before request middleware");
|
|
843
898
|
if (error instanceof Response) {
|
|
844
899
|
try {
|
|
845
900
|
await sendFetchResponse(res, error);
|
|
@@ -855,7 +910,7 @@ function createRouteHandler(runtime, factory) {
|
|
|
855
910
|
const response = await factory({ request, req });
|
|
856
911
|
await sendFetchResponse(res, response);
|
|
857
912
|
callAfterRequestMiddleware({ runtime, response, path }).catch((error) => {
|
|
858
|
-
|
|
913
|
+
import_shared5.logger.error({ err: error, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
|
|
859
914
|
});
|
|
860
915
|
} catch (error) {
|
|
861
916
|
if (error instanceof Response) {
|
|
@@ -866,11 +921,11 @@ function createRouteHandler(runtime, factory) {
|
|
|
866
921
|
return;
|
|
867
922
|
}
|
|
868
923
|
callAfterRequestMiddleware({ runtime, response: error, path }).catch((mwError) => {
|
|
869
|
-
|
|
924
|
+
import_shared5.logger.error({ err: mwError, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
|
|
870
925
|
});
|
|
871
926
|
return;
|
|
872
927
|
}
|
|
873
|
-
|
|
928
|
+
import_shared5.logger.error({ err: error, url: request.url, path }, "Error running request handler");
|
|
874
929
|
next(error);
|
|
875
930
|
}
|
|
876
931
|
};
|
|
@@ -903,7 +958,7 @@ function joinPath(basePath, suffix) {
|
|
|
903
958
|
// src/endpoints/express-single.ts
|
|
904
959
|
var import_express2 = __toESM(require("express"));
|
|
905
960
|
var import_cors2 = __toESM(require("cors"));
|
|
906
|
-
var
|
|
961
|
+
var import_shared6 = require("@copilotkitnext/shared");
|
|
907
962
|
|
|
908
963
|
// src/endpoints/single-route-helpers.ts
|
|
909
964
|
var METHOD_NAMES = [
|
|
@@ -1017,7 +1072,7 @@ function createSingleRouteHandler(runtime) {
|
|
|
1017
1072
|
request = maybeModifiedRequest;
|
|
1018
1073
|
}
|
|
1019
1074
|
} catch (error) {
|
|
1020
|
-
|
|
1075
|
+
import_shared6.logger.error({ err: error, url: request.url, path }, "Error running before request middleware");
|
|
1021
1076
|
if (error instanceof Response) {
|
|
1022
1077
|
try {
|
|
1023
1078
|
await sendFetchResponse(res, error);
|
|
@@ -1034,7 +1089,7 @@ function createSingleRouteHandler(runtime) {
|
|
|
1034
1089
|
methodCall = await parseMethodCall(request);
|
|
1035
1090
|
} catch (error) {
|
|
1036
1091
|
if (error instanceof Response) {
|
|
1037
|
-
|
|
1092
|
+
import_shared6.logger.warn({ url: request.url }, "Invalid single-route payload");
|
|
1038
1093
|
try {
|
|
1039
1094
|
await sendFetchResponse(res, error);
|
|
1040
1095
|
} catch (streamError) {
|
|
@@ -1042,7 +1097,7 @@ function createSingleRouteHandler(runtime) {
|
|
|
1042
1097
|
}
|
|
1043
1098
|
return;
|
|
1044
1099
|
}
|
|
1045
|
-
|
|
1100
|
+
import_shared6.logger.warn({ err: error, url: request.url }, "Invalid single-route payload");
|
|
1046
1101
|
res.status(400).json({
|
|
1047
1102
|
error: "invalid_request",
|
|
1048
1103
|
message: error instanceof Error ? error.message : "Invalid request payload"
|
|
@@ -1075,7 +1130,8 @@ function createSingleRouteHandler(runtime) {
|
|
|
1075
1130
|
break;
|
|
1076
1131
|
}
|
|
1077
1132
|
case "transcribe": {
|
|
1078
|
-
|
|
1133
|
+
const handlerRequest = createJsonRequest(request, methodCall.body);
|
|
1134
|
+
response = await handleTranscribe({ runtime, request: handlerRequest });
|
|
1079
1135
|
break;
|
|
1080
1136
|
}
|
|
1081
1137
|
default: {
|
|
@@ -1085,7 +1141,7 @@ function createSingleRouteHandler(runtime) {
|
|
|
1085
1141
|
}
|
|
1086
1142
|
await sendFetchResponse(res, response);
|
|
1087
1143
|
callAfterRequestMiddleware({ runtime, response, path }).catch((error) => {
|
|
1088
|
-
|
|
1144
|
+
import_shared6.logger.error({ err: error, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
|
|
1089
1145
|
});
|
|
1090
1146
|
} catch (error) {
|
|
1091
1147
|
if (error instanceof Response) {
|
|
@@ -1096,11 +1152,11 @@ function createSingleRouteHandler(runtime) {
|
|
|
1096
1152
|
return;
|
|
1097
1153
|
}
|
|
1098
1154
|
callAfterRequestMiddleware({ runtime, response: error, path }).catch((mwError) => {
|
|
1099
|
-
|
|
1155
|
+
import_shared6.logger.error({ err: mwError, url: req.originalUrl ?? req.url, path }, "Error running after request middleware");
|
|
1100
1156
|
});
|
|
1101
1157
|
return;
|
|
1102
1158
|
}
|
|
1103
|
-
|
|
1159
|
+
import_shared6.logger.error({ err: error, url: request.url, path }, "Error running single-route handler");
|
|
1104
1160
|
next(error);
|
|
1105
1161
|
}
|
|
1106
1162
|
};
|