camstreamerlib 4.0.0-beta.2 → 4.0.0-beta.4
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/cjs/CamOverlayAPI.js +176 -0
- package/cjs/CamOverlayDrawingAPI.js +235 -0
- package/cjs/CamOverlayPainter/Frame.js +301 -0
- package/{CamOverlayPainter → cjs/CamOverlayPainter}/Painter.d.ts +14 -3
- package/cjs/CamOverlayPainter/Painter.js +171 -0
- package/cjs/CamOverlayPainter/ResourceManager.js +46 -0
- package/cjs/CamScripterAPI.js +70 -0
- package/cjs/CamScripterAPICameraEventsGenerator.js +162 -0
- package/cjs/CamStreamerAPI.js +65 -0
- package/{CamSwitcherAPI.d.ts → cjs/CamSwitcherAPI.d.ts} +3 -3
- package/cjs/CamSwitcherAPI.js +350 -0
- package/{CamSwitcherEvents.d.ts → cjs/CamSwitcherEvents.d.ts} +1 -1
- package/cjs/CamSwitcherEvents.js +67 -0
- package/cjs/CreatePackage.js +106 -0
- package/{VapixAPI.d.ts → cjs/VapixAPI.d.ts} +9 -9
- package/cjs/VapixAPI.js +462 -0
- package/cjs/VapixEvents.js +88 -0
- package/cjs/errors/errors.js +79 -0
- package/cjs/events/AxisCameraStationEvents.js +48 -0
- package/cjs/events/GenetecAgent.js +123 -0
- package/cjs/index.d.ts +11 -0
- package/cjs/index.js +31 -0
- package/cjs/internal/Digest.js +42 -0
- package/cjs/internal/ProxyClient.js +44 -0
- package/{internal → cjs/internal}/common.d.ts +0 -1
- package/cjs/internal/common.js +27 -0
- package/cjs/internal/constants.js +4 -0
- package/cjs/internal/transformers.js +32 -0
- package/cjs/internal/utils.js +46 -0
- package/cjs/internal/versionCompare.js +53 -0
- package/cjs/node/DefaultClient.js +54 -0
- package/cjs/node/HttpRequestSender.js +89 -0
- package/cjs/node/HttpServer.js +96 -0
- package/cjs/node/WsClient.js +149 -0
- package/cjs/node/WsEventClient.js +22 -0
- package/cjs/node/index.d.ts +2 -0
- package/cjs/node/index.js +7 -0
- package/cjs/types/CamOverlayAPI.js +47 -0
- package/cjs/types/CamScripterAPI.js +20 -0
- package/cjs/types/CamStreamerAPI.js +28 -0
- package/cjs/types/CamSwitcherAPI.js +137 -0
- package/cjs/types/CamSwitcherEvents.js +62 -0
- package/{types → cjs/types}/VapixAPI.d.ts +40 -61
- package/cjs/types/VapixAPI.js +130 -0
- package/cjs/types/common.js +14 -0
- package/cjs/web/DefaultClient.js +20 -0
- package/cjs/web/WsClient.js +62 -0
- package/cjs/web/index.d.ts +2 -0
- package/cjs/web/index.js +7 -0
- package/esm/CamOverlayAPI.d.ts +31 -0
- package/esm/CamOverlayDrawingAPI.d.ts +86 -0
- package/{CamOverlayDrawingAPI.js → esm/CamOverlayDrawingAPI.js} +6 -3
- package/esm/CamOverlayPainter/Frame.d.ts +96 -0
- package/esm/CamOverlayPainter/Painter.d.ts +48 -0
- package/{CamOverlayPainter → esm/CamOverlayPainter}/Painter.js +4 -1
- package/esm/CamOverlayPainter/ResourceManager.d.ts +14 -0
- package/{CamOverlayPainter → esm/CamOverlayPainter}/ResourceManager.js +6 -10
- package/esm/CamScripterAPI.d.ts +19 -0
- package/esm/CamScripterAPICameraEventsGenerator.d.ts +74 -0
- package/{CamScripterAPICameraEventsGenerator.js → esm/CamScripterAPICameraEventsGenerator.js} +6 -3
- package/esm/CamStreamerAPI.d.ts +16 -0
- package/esm/CamSwitcherAPI.d.ts +48 -0
- package/{CamSwitcherAPI.js → esm/CamSwitcherAPI.js} +19 -23
- package/esm/CamSwitcherEvents.d.ts +18 -0
- package/{CamSwitcherEvents.js → esm/CamSwitcherEvents.js} +1 -1
- package/esm/CreatePackage.d.ts +1 -0
- package/esm/VapixAPI.d.ts +66 -0
- package/{VapixAPI.js → esm/VapixAPI.js} +20 -16
- package/esm/VapixEvents.d.ts +43 -0
- package/{VapixEvents.js → esm/VapixEvents.js} +3 -3
- package/esm/errors/errors.d.ts +34 -0
- package/esm/events/AxisCameraStationEvents.d.ts +9 -0
- package/esm/events/GenetecAgent.d.ts +174 -0
- package/esm/index.d.ts +11 -0
- package/esm/index.js +11 -0
- package/esm/internal/Digest.d.ts +4 -0
- package/{internal → esm/internal}/Digest.js +6 -6
- package/esm/internal/ProxyClient.d.ts +11 -0
- package/esm/internal/common.d.ts +39 -0
- package/{internal → esm/internal}/common.js +0 -3
- package/esm/internal/constants.d.ts +1 -0
- package/esm/internal/transformers.d.ts +5 -0
- package/esm/internal/utils.d.ts +11 -0
- package/esm/internal/versionCompare.d.ts +6 -0
- package/esm/node/DefaultClient.d.ts +15 -0
- package/{node → esm/node}/DefaultClient.js +1 -1
- package/esm/node/HttpRequestSender.d.ts +28 -0
- package/esm/node/HttpServer.d.ts +21 -0
- package/{node → esm/node}/HttpServer.js +1 -1
- package/esm/node/WsClient.d.ts +39 -0
- package/esm/node/WsEventClient.d.ts +13 -0
- package/esm/node/index.d.ts +2 -0
- package/esm/node/index.js +2 -0
- package/esm/types/CamOverlayAPI.d.ts +188 -0
- package/esm/types/CamScripterAPI.d.ts +67 -0
- package/esm/types/CamStreamerAPI.d.ts +139 -0
- package/esm/types/CamSwitcherAPI.d.ts +814 -0
- package/esm/types/CamSwitcherEvents.d.ts +491 -0
- package/esm/types/VapixAPI.d.ts +1683 -0
- package/{types → esm/types}/VapixAPI.js +10 -12
- package/esm/types/common.d.ts +37 -0
- package/esm/web/DefaultClient.d.ts +6 -0
- package/esm/web/WsClient.d.ts +13 -0
- package/esm/web/index.d.ts +2 -0
- package/esm/web/index.js +2 -0
- package/package.json +6 -5
- package/README.md +0 -97
- /package/{CamOverlayAPI.d.ts → cjs/CamOverlayAPI.d.ts} +0 -0
- /package/{CamOverlayDrawingAPI.d.ts → cjs/CamOverlayDrawingAPI.d.ts} +0 -0
- /package/{CamOverlayPainter → cjs/CamOverlayPainter}/Frame.d.ts +0 -0
- /package/{CamOverlayPainter → cjs/CamOverlayPainter}/ResourceManager.d.ts +0 -0
- /package/{CamScripterAPI.d.ts → cjs/CamScripterAPI.d.ts} +0 -0
- /package/{CamScripterAPICameraEventsGenerator.d.ts → cjs/CamScripterAPICameraEventsGenerator.d.ts} +0 -0
- /package/{CamStreamerAPI.d.ts → cjs/CamStreamerAPI.d.ts} +0 -0
- /package/{CreatePackage.d.ts → cjs/CreatePackage.d.ts} +0 -0
- /package/{VapixEvents.d.ts → cjs/VapixEvents.d.ts} +0 -0
- /package/{errors → cjs/errors}/errors.d.ts +0 -0
- /package/{events → cjs/events}/AxisCameraStationEvents.d.ts +0 -0
- /package/{events → cjs/events}/GenetecAgent.d.ts +0 -0
- /package/{internal → cjs/internal}/Digest.d.ts +0 -0
- /package/{internal → cjs/internal}/ProxyClient.d.ts +0 -0
- /package/{internal → cjs/internal}/constants.d.ts +0 -0
- /package/{internal → cjs/internal}/transformers.d.ts +0 -0
- /package/{internal → cjs/internal}/utils.d.ts +0 -0
- /package/{internal → cjs/internal}/versionCompare.d.ts +0 -0
- /package/{node → cjs/node}/DefaultClient.d.ts +0 -0
- /package/{node → cjs/node}/HttpRequestSender.d.ts +0 -0
- /package/{node → cjs/node}/HttpServer.d.ts +0 -0
- /package/{node → cjs/node}/WsClient.d.ts +0 -0
- /package/{node → cjs/node}/WsEventClient.d.ts +0 -0
- /package/{types → cjs/types}/CamOverlayAPI.d.ts +0 -0
- /package/{types → cjs/types}/CamScripterAPI.d.ts +0 -0
- /package/{types → cjs/types}/CamStreamerAPI.d.ts +0 -0
- /package/{types → cjs/types}/CamSwitcherAPI.d.ts +0 -0
- /package/{types/CamswitcherEvents.d.ts → cjs/types/CamSwitcherEvents.d.ts} +0 -0
- /package/{types → cjs/types}/common.d.ts +0 -0
- /package/{web → cjs/web}/DefaultClient.d.ts +0 -0
- /package/{web → cjs/web}/WsClient.d.ts +0 -0
- /package/{CamOverlayAPI.js → esm/CamOverlayAPI.js} +0 -0
- /package/{CamOverlayPainter → esm/CamOverlayPainter}/Frame.js +0 -0
- /package/{CamScripterAPI.js → esm/CamScripterAPI.js} +0 -0
- /package/{CamStreamerAPI.js → esm/CamStreamerAPI.js} +0 -0
- /package/{CreatePackage.js → esm/CreatePackage.js} +0 -0
- /package/{errors → esm/errors}/errors.js +0 -0
- /package/{events → esm/events}/AxisCameraStationEvents.js +0 -0
- /package/{events → esm/events}/GenetecAgent.js +0 -0
- /package/{internal → esm/internal}/ProxyClient.js +0 -0
- /package/{internal → esm/internal}/constants.js +0 -0
- /package/{internal → esm/internal}/transformers.js +0 -0
- /package/{internal → esm/internal}/utils.js +0 -0
- /package/{internal → esm/internal}/versionCompare.js +0 -0
- /package/{node → esm/node}/HttpRequestSender.js +0 -0
- /package/{node → esm/node}/WsClient.js +0 -0
- /package/{node → esm/node}/WsEventClient.js +0 -0
- /package/{types → esm/types}/CamOverlayAPI.js +0 -0
- /package/{types → esm/types}/CamScripterAPI.js +0 -0
- /package/{types → esm/types}/CamStreamerAPI.js +0 -0
- /package/{types → esm/types}/CamSwitcherAPI.js +0 -0
- /package/{types/CamswitcherEvents.js → esm/types/CamSwitcherEvents.js} +0 -0
- /package/{types → esm/types}/common.js +0 -0
- /package/{web → esm/web}/DefaultClient.js +0 -0
- /package/{web → esm/web}/WsClient.js +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import { CamOverlayDrawingAPI, TAlign, TCairoCreateResponse, TUploadImageResponse } from '../CamOverlayDrawingAPI';
|
|
4
|
+
import ResourceManager from './ResourceManager';
|
|
5
|
+
export type TRgb = [number, number, number];
|
|
6
|
+
export type TRgba = [number, number, number, number];
|
|
7
|
+
export type TTmf = 'TFM_OVERFLOW' | 'TFM_SCALE' | 'TFM_TRUNCATE';
|
|
8
|
+
export type TObjectFitType = 'fill' | 'fit' | 'none';
|
|
9
|
+
export type TFrameOptions = {
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
text?: string;
|
|
16
|
+
fontColor?: TRgb;
|
|
17
|
+
font?: string;
|
|
18
|
+
bgColor?: TRgba;
|
|
19
|
+
bgImage?: string;
|
|
20
|
+
bgType?: TObjectFitType;
|
|
21
|
+
borderRadius?: number;
|
|
22
|
+
borderWidth?: number;
|
|
23
|
+
borderColor?: TRgba;
|
|
24
|
+
customDraw?: TDrawingCallback;
|
|
25
|
+
layer?: number;
|
|
26
|
+
};
|
|
27
|
+
export type TFrameInfo = {
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
};
|
|
31
|
+
export type TDrawingCallback = (cod: CamOverlayDrawingAPI, cairo: string, info: TFrameInfo) => Promise<void>;
|
|
32
|
+
export interface Frame {
|
|
33
|
+
on(event: 'open', listener: () => void): this;
|
|
34
|
+
on(event: 'close', listener: () => void): this;
|
|
35
|
+
on(event: 'layoutChanged', listener: () => void): this;
|
|
36
|
+
emit(event: 'open'): boolean;
|
|
37
|
+
emit(event: 'close'): boolean;
|
|
38
|
+
emit(event: 'layoutChanged'): boolean;
|
|
39
|
+
}
|
|
40
|
+
export declare class Frame extends EventEmitter {
|
|
41
|
+
protected enabled: boolean;
|
|
42
|
+
protected posX: number;
|
|
43
|
+
protected posY: number;
|
|
44
|
+
protected width: number;
|
|
45
|
+
protected height: number;
|
|
46
|
+
private text;
|
|
47
|
+
private fontColor;
|
|
48
|
+
private fontName?;
|
|
49
|
+
private font?;
|
|
50
|
+
private align;
|
|
51
|
+
private textType;
|
|
52
|
+
private bgColor?;
|
|
53
|
+
private bgImageName?;
|
|
54
|
+
private bgImage?;
|
|
55
|
+
private bgType?;
|
|
56
|
+
private borderRadius;
|
|
57
|
+
private borderWidth;
|
|
58
|
+
private borderColor;
|
|
59
|
+
private customDraw?;
|
|
60
|
+
private layer;
|
|
61
|
+
protected children: Frame[];
|
|
62
|
+
constructor(opt: TFrameOptions);
|
|
63
|
+
enable(): void;
|
|
64
|
+
disable(): void;
|
|
65
|
+
setFramePosition(x: number, y: number): void;
|
|
66
|
+
setFrameSize(width: number, height: number): void;
|
|
67
|
+
setText(text: string, align: TAlign, textType?: TTmf, fontColor?: TRgb): void;
|
|
68
|
+
setFontColor(fontColor: TRgb): void;
|
|
69
|
+
setFont(fontName: string): void;
|
|
70
|
+
setFontData(fontData: TCairoCreateResponse): void;
|
|
71
|
+
setBgColor(color: TRgba): void;
|
|
72
|
+
setBgImage(imageName: string, type?: TObjectFitType): void;
|
|
73
|
+
setBgImageData(imageData: TUploadImageResponse, type?: TObjectFitType): void;
|
|
74
|
+
setBgType(type: TObjectFitType): void;
|
|
75
|
+
setBorderRadius(radius: number): void;
|
|
76
|
+
setBorderWidth(width: number): void;
|
|
77
|
+
setBorderColor(color: TRgba): void;
|
|
78
|
+
setCustomDraw(customDraw: TDrawingCallback): void;
|
|
79
|
+
resetFont(): void;
|
|
80
|
+
resetBgColor(): void;
|
|
81
|
+
resetBgImage(): void;
|
|
82
|
+
resetCustomDraw(): void;
|
|
83
|
+
clear(): void;
|
|
84
|
+
insert(...frames: Frame[]): void;
|
|
85
|
+
getLayers(): Set<number>;
|
|
86
|
+
protected layoutChanged(): void;
|
|
87
|
+
displayImage(cod: CamOverlayDrawingAPI, resourceManager: ResourceManager, cairo: string, ppX: number, ppY: number, scale: number, layer: number): Promise<void>;
|
|
88
|
+
private prepareResources;
|
|
89
|
+
protected displayOwnImage(cod: CamOverlayDrawingAPI, cairo: string, ppX: number, ppY: number, scale: number): Promise<void>;
|
|
90
|
+
private clipDrawing;
|
|
91
|
+
private drawFrame;
|
|
92
|
+
private drawImage;
|
|
93
|
+
private drawText;
|
|
94
|
+
private drawBorder;
|
|
95
|
+
private drawRectPath;
|
|
96
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { CamOverlayDrawingAPI, CamOverlayDrawingOptions } from '../CamOverlayDrawingAPI';
|
|
2
|
+
import ResourceManager from './ResourceManager';
|
|
3
|
+
import { Frame, TFrameOptions } from './Frame';
|
|
4
|
+
export declare const COORD: {
|
|
5
|
+
readonly top_left: readonly [-1, -1];
|
|
6
|
+
readonly center_left: readonly [-1, 0];
|
|
7
|
+
readonly bottom_left: readonly [-1, 1];
|
|
8
|
+
readonly top_center: readonly [0, -1];
|
|
9
|
+
readonly center: readonly [0, 0];
|
|
10
|
+
readonly bottom_center: readonly [0, 1];
|
|
11
|
+
readonly top_right: readonly [1, -1];
|
|
12
|
+
readonly center_right: readonly [1, 0];
|
|
13
|
+
readonly bottom_right: readonly [1, 1];
|
|
14
|
+
};
|
|
15
|
+
type TCoAlignment = keyof typeof COORD;
|
|
16
|
+
export type TPainterOptions = TFrameOptions & {
|
|
17
|
+
screenWidth: number;
|
|
18
|
+
screenHeight: number;
|
|
19
|
+
coAlignment: TCoAlignment;
|
|
20
|
+
};
|
|
21
|
+
export declare class Painter extends Frame {
|
|
22
|
+
private screenWidth;
|
|
23
|
+
private screenHeight;
|
|
24
|
+
private coAlignment;
|
|
25
|
+
private cod;
|
|
26
|
+
private rm;
|
|
27
|
+
private refreshLayers;
|
|
28
|
+
private layers;
|
|
29
|
+
constructor(opt: TPainterOptions, coopt: CamOverlayDrawingOptions);
|
|
30
|
+
get camOverlayDrawingAPI(): CamOverlayDrawingAPI;
|
|
31
|
+
get resourceManager(): ResourceManager;
|
|
32
|
+
connect(): void;
|
|
33
|
+
disconnect(): void;
|
|
34
|
+
isConnected(): boolean;
|
|
35
|
+
registerImage(moniker: string, fileName: string): void;
|
|
36
|
+
registerFont(moniker: string, fileName: string): void;
|
|
37
|
+
setScreenSize(sw: number, sh: number): void;
|
|
38
|
+
setCoAlignment(coAlignment: TCoAlignment): void;
|
|
39
|
+
protected layoutChanged(): void;
|
|
40
|
+
display(scale?: number): Promise<void>;
|
|
41
|
+
hide(): Promise<void>;
|
|
42
|
+
invalidateLayer(layer: number): Promise<void>;
|
|
43
|
+
private prepareLayers;
|
|
44
|
+
private prepareSurface;
|
|
45
|
+
private cleanupSurface;
|
|
46
|
+
private positionConvertor;
|
|
47
|
+
}
|
|
48
|
+
export { Frame, TFrameOptions as FrameOptions, ResourceManager, CamOverlayDrawingOptions };
|
|
@@ -82,6 +82,9 @@ export class Painter extends Frame {
|
|
|
82
82
|
let lastCachedLayer;
|
|
83
83
|
for (let i = 0; i < this.layers.length; i++) {
|
|
84
84
|
const layer = this.layers[i];
|
|
85
|
+
if (layer === undefined) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
85
88
|
if (layer.cairoCache !== undefined &&
|
|
86
89
|
layer.surfaceCache !== undefined &&
|
|
87
90
|
surface === undefined &&
|
|
@@ -115,7 +118,7 @@ export class Painter extends Frame {
|
|
|
115
118
|
}
|
|
116
119
|
for (let i = layerIdx; i < this.layers.length; i++) {
|
|
117
120
|
const currentLayer = this.layers[i];
|
|
118
|
-
if (currentLayer
|
|
121
|
+
if (currentLayer?.surfaceCache !== undefined && currentLayer.cairoCache !== undefined) {
|
|
119
122
|
await this.cleanupSurface(currentLayer.surfaceCache, currentLayer.cairoCache);
|
|
120
123
|
currentLayer.surfaceCache = undefined;
|
|
121
124
|
currentLayer.cairoCache = undefined;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CamOverlayDrawingAPI, TUploadImageResponse, TCairoCreateResponse } from '../CamOverlayDrawingAPI';
|
|
2
|
+
export default class ResourceManager {
|
|
3
|
+
private co;
|
|
4
|
+
private imgFileNames;
|
|
5
|
+
private fontFileNames;
|
|
6
|
+
private images;
|
|
7
|
+
private fonts;
|
|
8
|
+
constructor(co: CamOverlayDrawingAPI);
|
|
9
|
+
registerImage(moniker: string, fileName: string): void;
|
|
10
|
+
registerFont(moniker: string, fileName: string): void;
|
|
11
|
+
image(moniker: string): Promise<TUploadImageResponse>;
|
|
12
|
+
font(moniker: string): Promise<TCairoCreateResponse>;
|
|
13
|
+
clear(): void;
|
|
14
|
+
}
|
|
@@ -15,30 +15,26 @@ export default class ResourceManager {
|
|
|
15
15
|
this.fontFileNames[moniker] = process.env.INSTALL_PATH + '/fonts/' + fileName;
|
|
16
16
|
}
|
|
17
17
|
async image(moniker) {
|
|
18
|
-
if (moniker
|
|
18
|
+
if (this.images[moniker] !== undefined) {
|
|
19
19
|
return this.images[moniker];
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
if (this.imgFileNames[moniker] !== undefined) {
|
|
22
22
|
const imgData = await fs.readFile(this.imgFileNames[moniker]);
|
|
23
23
|
this.images[moniker] = await this.co.uploadImageData(imgData);
|
|
24
24
|
return this.images[moniker];
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
throw new Error('Error! Unknown image requested!');
|
|
28
|
-
}
|
|
26
|
+
throw new Error('Error! Unknown image requested!');
|
|
29
27
|
}
|
|
30
28
|
async font(moniker) {
|
|
31
|
-
if (moniker
|
|
29
|
+
if (this.fonts[moniker] !== undefined) {
|
|
32
30
|
return this.fonts[moniker];
|
|
33
31
|
}
|
|
34
|
-
|
|
32
|
+
if (this.fontFileNames[moniker] !== undefined) {
|
|
35
33
|
const fontData = await fs.readFile(this.fontFileNames[moniker]);
|
|
36
34
|
this.fonts[moniker] = await this.co.uploadFontData(fontData);
|
|
37
35
|
return this.fonts[moniker];
|
|
38
36
|
}
|
|
39
|
-
|
|
40
|
-
throw new Error('Error! Unknown font requested!');
|
|
41
|
-
}
|
|
37
|
+
throw new Error('Error! Unknown font requested!');
|
|
42
38
|
}
|
|
43
39
|
clear() {
|
|
44
40
|
this.images = {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { IClient } from './internal/common';
|
|
2
|
+
import { CamScripterOptions, TNodeState, TPackageInfoList, TStorage, TStorageType } from './types/CamScripterAPI';
|
|
3
|
+
import { TNetworkCamera } from './types/common';
|
|
4
|
+
export declare class CamOverlayAPI {
|
|
5
|
+
private client;
|
|
6
|
+
constructor(options?: CamScripterOptions | IClient);
|
|
7
|
+
checkCameraTime(): Promise<boolean>;
|
|
8
|
+
getStorageInfo(): Promise<TStorage>;
|
|
9
|
+
getNetworkCameraList(): Promise<TNetworkCamera[]>;
|
|
10
|
+
getPackageList(): Promise<TPackageInfoList>;
|
|
11
|
+
installPackages(formData: FormData, storage: TStorageType): Promise<void>;
|
|
12
|
+
uninstallPackage(packageId: string): Promise<void>;
|
|
13
|
+
importSettings(packageId: string, formData: FormData): Promise<void>;
|
|
14
|
+
exportSettings(packageId: string, formData: FormData): Promise<void>;
|
|
15
|
+
getNodejsStatus(): Promise<TNodeState>;
|
|
16
|
+
installNodejs(storage: TStorageType): Promise<void>;
|
|
17
|
+
private get;
|
|
18
|
+
private post;
|
|
19
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import * as EventEmitter from 'events';
|
|
3
|
+
import { WsOptions } from './internal/common';
|
|
4
|
+
export type CamScripterOptions = WsOptions;
|
|
5
|
+
export type TDeclaration = {
|
|
6
|
+
type?: '' | 'SOURCE' | 'DATA';
|
|
7
|
+
namespace: string;
|
|
8
|
+
key: string;
|
|
9
|
+
value: string | boolean | number;
|
|
10
|
+
value_type: 'STRING' | 'INT' | 'BOOL' | 'DOUBLE';
|
|
11
|
+
key_nice_name?: string;
|
|
12
|
+
value_nice_name?: string;
|
|
13
|
+
};
|
|
14
|
+
export type TEventDeclaration = {
|
|
15
|
+
declaration_id: string;
|
|
16
|
+
stateless: boolean;
|
|
17
|
+
declaration: TDeclaration[];
|
|
18
|
+
};
|
|
19
|
+
export type TEventUndeclaration = {
|
|
20
|
+
declaration_id: string;
|
|
21
|
+
};
|
|
22
|
+
export type TEventData = {
|
|
23
|
+
namespace: string;
|
|
24
|
+
key: string;
|
|
25
|
+
value: string | boolean | number;
|
|
26
|
+
value_type: 'STRING' | 'INT' | 'BOOL' | 'DOUBLE';
|
|
27
|
+
};
|
|
28
|
+
export type TEvent = {
|
|
29
|
+
declaration_id: string;
|
|
30
|
+
event_data: TEventData[];
|
|
31
|
+
};
|
|
32
|
+
export type TResponse = {
|
|
33
|
+
call_id: number;
|
|
34
|
+
message: string;
|
|
35
|
+
};
|
|
36
|
+
export type TErrorResponse = {
|
|
37
|
+
error: string;
|
|
38
|
+
call_id?: number;
|
|
39
|
+
};
|
|
40
|
+
export interface CamScripterAPICameraEventsGenerator {
|
|
41
|
+
on(event: 'open', listener: () => void): this;
|
|
42
|
+
on(event: 'close', listener: () => void): this;
|
|
43
|
+
on(event: 'error', listener: (err: Error) => void): this;
|
|
44
|
+
emit(event: 'open'): boolean;
|
|
45
|
+
emit(event: 'close'): boolean;
|
|
46
|
+
emit(event: 'error', err: Error): boolean;
|
|
47
|
+
}
|
|
48
|
+
export declare class CamScripterAPICameraEventsGenerator extends EventEmitter {
|
|
49
|
+
private tls;
|
|
50
|
+
private tlsInsecure;
|
|
51
|
+
private ip;
|
|
52
|
+
private port;
|
|
53
|
+
private user;
|
|
54
|
+
private pass;
|
|
55
|
+
private callId;
|
|
56
|
+
private sendMessages;
|
|
57
|
+
private timeoutCheckTimer;
|
|
58
|
+
private wsConnected;
|
|
59
|
+
private ws;
|
|
60
|
+
constructor(options?: CamScripterOptions);
|
|
61
|
+
connect(): void;
|
|
62
|
+
disconnect(): void;
|
|
63
|
+
declareEvent(eventDeclaration: TEventDeclaration): Promise<TResponse>;
|
|
64
|
+
undeclareEvent(eventUndeclaration: TEventUndeclaration): Promise<TResponse>;
|
|
65
|
+
sendEvent(event: TEvent): Promise<TResponse>;
|
|
66
|
+
private createWsClient;
|
|
67
|
+
private incomingWsMessageHandler;
|
|
68
|
+
private sendMessage;
|
|
69
|
+
private startMsgsTimeoutCheck;
|
|
70
|
+
private stopMsgsTimeoutCheck;
|
|
71
|
+
private reconnectWithError;
|
|
72
|
+
private reportErr;
|
|
73
|
+
private reportClose;
|
|
74
|
+
}
|
package/{CamScripterAPICameraEventsGenerator.js → esm/CamScripterAPICameraEventsGenerator.js}
RENAMED
|
@@ -88,10 +88,10 @@ export class CamScripterAPICameraEventsGenerator extends EventEmitter {
|
|
|
88
88
|
}
|
|
89
89
|
if (dataJSON.call_id !== undefined) {
|
|
90
90
|
if (errorResponse !== undefined) {
|
|
91
|
-
this.sendMessages[dataJSON.call_id]
|
|
91
|
+
this.sendMessages[dataJSON.call_id]?.reject(new Error(errorResponse.error));
|
|
92
92
|
}
|
|
93
93
|
else {
|
|
94
|
-
this.sendMessages[dataJSON.call_id]
|
|
94
|
+
this.sendMessages[dataJSON.call_id]?.resolve(dataJSON);
|
|
95
95
|
}
|
|
96
96
|
delete this.sendMessages[dataJSON.call_id];
|
|
97
97
|
}
|
|
@@ -124,6 +124,9 @@ export class CamScripterAPICameraEventsGenerator extends EventEmitter {
|
|
|
124
124
|
const now = Date.now();
|
|
125
125
|
for (const callId in this.sendMessages) {
|
|
126
126
|
const msg = this.sendMessages[callId];
|
|
127
|
+
if (!msg) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
127
130
|
if (now - msg.sentTimestamp > 10000) {
|
|
128
131
|
reconnect = true;
|
|
129
132
|
msg.reject(new Error('Message timeout'));
|
|
@@ -147,7 +150,7 @@ export class CamScripterAPICameraEventsGenerator extends EventEmitter {
|
|
|
147
150
|
}
|
|
148
151
|
reportClose() {
|
|
149
152
|
for (const callId in this.sendMessages) {
|
|
150
|
-
this.sendMessages[callId]
|
|
153
|
+
this.sendMessages[callId]?.reject(new Error('Connection lost'));
|
|
151
154
|
}
|
|
152
155
|
this.sendMessages = {};
|
|
153
156
|
this.emit('close');
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IClient } from './internal/common';
|
|
2
|
+
import { CamStreamerAPIOptions, TStreamAttributes, TStreamList } from './types/CamStreamerAPI';
|
|
3
|
+
export declare class CamStreamerAPI {
|
|
4
|
+
private client;
|
|
5
|
+
constructor(options?: CamStreamerAPIOptions | IClient);
|
|
6
|
+
getStreamList(): Promise<TStreamList>;
|
|
7
|
+
getStream(streamID: string): Promise<TStreamAttributes>;
|
|
8
|
+
getStreamParameter(streamID: string, paramName: string): Promise<string>;
|
|
9
|
+
setStream(streamID: string, params: Partial<TStreamAttributes>): Promise<void>;
|
|
10
|
+
setStreamParameter(streamID: string, paramName: string, value: string): Promise<void>;
|
|
11
|
+
isStreaming(streamID: string): Promise<boolean>;
|
|
12
|
+
deleteStream(streamID: string): Promise<void>;
|
|
13
|
+
wsAutoratization(): Promise<string>;
|
|
14
|
+
getUtcTime(): Promise<number>;
|
|
15
|
+
private get;
|
|
16
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { IClient } from './internal/common';
|
|
2
|
+
import { TAudioPushInfo, TOutputInfo, TStorageInfo, TStreamSaveList, TClipList, TStreamSaveLoadList, TClipSaveLoadList, TPlaylistSaveLoadList, TTrackerSaveList, TrackerSaveLoadList, TClipSaveList, TPlaylistSaveList, TCameraOptions, TGlobalAudioSettings, TSecondaryAudioSettings } from './types/CamSwitcherAPI';
|
|
3
|
+
import { TAudioChannel, TNetworkCamera, TStorageType } from './types/common';
|
|
4
|
+
export declare class CamSwitcherAPI<Client extends IClient = IClient> {
|
|
5
|
+
client: Client;
|
|
6
|
+
private vapixAgent;
|
|
7
|
+
constructor(client: Client);
|
|
8
|
+
static getProxyUrlPath: () => string;
|
|
9
|
+
static getWsEventsUrlPath: () => string;
|
|
10
|
+
static getClipPreviewUrlPath: (id: string, storage: TStorageType) => string;
|
|
11
|
+
generateSilence(sampleRate: number, channels: TAudioChannel): Promise<void>;
|
|
12
|
+
checkCameraTime(): Promise<boolean>;
|
|
13
|
+
getIpListFromNetworkCheck(): Promise<TNetworkCamera[]>;
|
|
14
|
+
getMaxFps(source: number): Promise<number>;
|
|
15
|
+
getStorageInfo(): Promise<TStorageInfo[]>;
|
|
16
|
+
wsAuthorization(): Promise<string>;
|
|
17
|
+
getOutputInfo(): Promise<TOutputInfo>;
|
|
18
|
+
getAudioPushInfo(): Promise<TAudioPushInfo>;
|
|
19
|
+
getStreamSaveList(): Promise<TStreamSaveLoadList>;
|
|
20
|
+
getClipSaveList(): Promise<TClipSaveLoadList>;
|
|
21
|
+
getPlaylistSaveList(): Promise<TPlaylistSaveLoadList>;
|
|
22
|
+
getTrackerSaveList(): Promise<TrackerSaveLoadList>;
|
|
23
|
+
setStreamSaveList(data: TStreamSaveList): Promise<boolean>;
|
|
24
|
+
setClipSaveList(data: TClipSaveList): Promise<boolean>;
|
|
25
|
+
setPlaylistSaveList(data: TPlaylistSaveList): Promise<boolean>;
|
|
26
|
+
setTrackerSaveList(data: TTrackerSaveList): Promise<boolean>;
|
|
27
|
+
playlistSwitch(playlistName: string): Promise<void>;
|
|
28
|
+
playlistQueuePush(playlistName: string): Promise<void>;
|
|
29
|
+
playlistQueueClear(): Promise<void>;
|
|
30
|
+
playlistQueueList(): Promise<string[]>;
|
|
31
|
+
playlistQueuePlayNext(): Promise<void>;
|
|
32
|
+
addNewClip(file: any, clipType: 'video' | 'audio', storage: TStorageType, id: string, fileName?: string): Promise<void>;
|
|
33
|
+
removeClip(id: string, storage: TStorageType): Promise<any>;
|
|
34
|
+
getClipList(): Promise<TClipList>;
|
|
35
|
+
setCamSwitchOptions(data: TCameraOptions, cameraFWVersion: string): Promise<boolean>;
|
|
36
|
+
setGlobalAudioSettings(settings: TGlobalAudioSettings): Promise<boolean>;
|
|
37
|
+
setSecondaryAudioSettings(settings: TSecondaryAudioSettings): Promise<boolean>;
|
|
38
|
+
setDefaultPlaylist(id: string): Promise<boolean>;
|
|
39
|
+
setPermanentRtspUrlToken(token: string): Promise<boolean>;
|
|
40
|
+
getCamSwitchOptions(): Promise<Partial<TCameraOptions>>;
|
|
41
|
+
getGlobalAudioSettings(): Promise<TGlobalAudioSettings>;
|
|
42
|
+
getSecondaryAudioSettings(): Promise<TSecondaryAudioSettings>;
|
|
43
|
+
getPermanentRtspUrlToken(): Promise<string>;
|
|
44
|
+
private get;
|
|
45
|
+
private set;
|
|
46
|
+
private setParamFromCameraJSON;
|
|
47
|
+
private getParamFromCameraAndJSONParse;
|
|
48
|
+
}
|
|
@@ -15,9 +15,9 @@ export class CamSwitcherAPI {
|
|
|
15
15
|
this.client = client;
|
|
16
16
|
this.vapixAgent = new VapixAPI(client, () => '');
|
|
17
17
|
}
|
|
18
|
-
static
|
|
19
|
-
static
|
|
20
|
-
static
|
|
18
|
+
static getProxyUrlPath = () => `${baseUrl}/proxy.cgi`;
|
|
19
|
+
static getWsEventsUrlPath = () => `/local/camswitcher/events`;
|
|
20
|
+
static getClipPreviewUrlPath = (id, storage) => `${baseUrl}/clip_preview.cgi?clip_name=${id}&storage=${storage}`;
|
|
21
21
|
async generateSilence(sampleRate, channels) {
|
|
22
22
|
await this.client.get(`${baseUrl}/generate_silence.cgi`, {
|
|
23
23
|
sample_rate: sampleRate.toString(),
|
|
@@ -292,16 +292,12 @@ const parseBitrateOptionsToBitrateVapixParams = (firmWareVersion, bitrateMode, c
|
|
|
292
292
|
if (bitrateMode === null) {
|
|
293
293
|
return '';
|
|
294
294
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if (bitrateMode === 'ABR') {
|
|
302
|
-
return `videobitratemode=abr&videoabrtargetbitrate=${cameraOptions.maximumBitRate}&videoabrretentiontime=${cameraOptions.retentionTime}&videoabrmaxbitrate=${cameraOptions.bitRateLimit}`;
|
|
303
|
-
}
|
|
304
|
-
throw new Error('Unknown bitrateMode param in getVapixParams method.');
|
|
295
|
+
const data = {
|
|
296
|
+
VBR: 'videobitratemode=vbr',
|
|
297
|
+
MBR: `videobitratemode=mbr&videomaxbitrate=${cameraOptions.maximumBitRate}`,
|
|
298
|
+
ABR: `videobitratemode=abr&videoabrtargetbitrate=${cameraOptions.maximumBitRate}&videoabrretentiontime=${cameraOptions.retentionTime}&videoabrmaxbitrate=${cameraOptions.bitRateLimit}`,
|
|
299
|
+
};
|
|
300
|
+
return data[bitrateMode];
|
|
305
301
|
};
|
|
306
302
|
const parseVapixParamsToBitrateOptions = (bitrateVapixParams) => {
|
|
307
303
|
const params = {};
|
|
@@ -312,7 +308,7 @@ const parseVapixParamsToBitrateOptions = (bitrateVapixParams) => {
|
|
|
312
308
|
const bitrateMode = params['videobitratemode'] !== undefined ? params['videobitratemode'].toUpperCase() : undefined;
|
|
313
309
|
const hasLowerFw = bitrateMode === undefined && params['videomaxbitrate'] !== undefined;
|
|
314
310
|
if (hasLowerFw) {
|
|
315
|
-
const maximumBitRate = parseInt(params['videomaxbitrate'], 10);
|
|
311
|
+
const maximumBitRate = parseInt(params['videomaxbitrate'] ?? '0', 10);
|
|
316
312
|
return {
|
|
317
313
|
bitrateMode: 'MBR',
|
|
318
314
|
maximumBitRate: maximumBitRate,
|
|
@@ -321,19 +317,19 @@ const parseVapixParamsToBitrateOptions = (bitrateVapixParams) => {
|
|
|
321
317
|
};
|
|
322
318
|
}
|
|
323
319
|
if (bitrateMode === 'ABR') {
|
|
324
|
-
const maximumBitRate = parseInt(params['videoabrtargetbitrate'], 10);
|
|
325
|
-
const retentionTime = parseInt(params['videoabrretentiontime'], 10);
|
|
326
|
-
const
|
|
320
|
+
const maximumBitRate = parseInt(params['videoabrtargetbitrate'] ?? '0', 10);
|
|
321
|
+
const retentionTime = parseInt(params['videoabrretentiontime'] ?? '0', 10);
|
|
322
|
+
const bitRateLimit = parseInt(params['videoabrmaxbitrate'] ?? '0', 10);
|
|
327
323
|
return {
|
|
328
|
-
bitrateMode
|
|
329
|
-
maximumBitRate
|
|
330
|
-
retentionTime
|
|
331
|
-
bitRateLimit
|
|
324
|
+
bitrateMode,
|
|
325
|
+
maximumBitRate,
|
|
326
|
+
retentionTime,
|
|
327
|
+
bitRateLimit,
|
|
332
328
|
};
|
|
333
329
|
}
|
|
334
330
|
else if (bitrateMode === 'MBR') {
|
|
335
|
-
const maximumBitRate = parseInt(params['videomaxbitrate'], 10);
|
|
336
|
-
const oldMaximumBitrateParamValue = parseInt(params['videombrmaxbitrate'], 10);
|
|
331
|
+
const maximumBitRate = params['videomaxbitrate'] !== undefined ? parseInt(params['videomaxbitrate'], 10) : null;
|
|
332
|
+
const oldMaximumBitrateParamValue = parseInt(params['videombrmaxbitrate'] ?? '0', 10);
|
|
337
333
|
return {
|
|
338
334
|
bitrateMode: bitrateMode,
|
|
339
335
|
maximumBitRate: maximumBitRate ?? oldMaximumBitrateParamValue,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { IWebsocket } from './internal/common';
|
|
2
|
+
import { TCamSwitcherEventOfType, TCamSwitcherEventType } from './types/CamSwitcherEvents';
|
|
3
|
+
type TListenerFunction<T extends TCamSwitcherEventType> = (data: TCamSwitcherEventOfType<T>, isInit: boolean) => void;
|
|
4
|
+
export declare class CamSwitcherEvents<Event extends {
|
|
5
|
+
data: string;
|
|
6
|
+
}> {
|
|
7
|
+
isDestroyed: boolean;
|
|
8
|
+
private ws;
|
|
9
|
+
private listeners;
|
|
10
|
+
setWebsocket(ws: IWebsocket<Event>): void;
|
|
11
|
+
resendInitData(): void;
|
|
12
|
+
addListener<T extends TCamSwitcherEventType>(type: T, listener: TListenerFunction<T>, id: string): void;
|
|
13
|
+
removeListener<T extends TCamSwitcherEventType>(type: T, id: string): void;
|
|
14
|
+
private onMessage;
|
|
15
|
+
private processMessage;
|
|
16
|
+
destroy(): void;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { IClient, TParameters } from './internal/common';
|
|
2
|
+
import { TApplication, TAudioSampleRates, TSDCardInfo, TPtzOverview, TCameraPTZItem, TCameraPTZItemData, TAudioDevice } from './types/VapixAPI';
|
|
3
|
+
import { ProxyClient } from './internal/ProxyClient';
|
|
4
|
+
import { TCameraImageConfig, TProxyParam } from './types/common';
|
|
5
|
+
export declare class VapixAPI<Client extends IClient = IClient> {
|
|
6
|
+
client: ProxyClient<Client>;
|
|
7
|
+
constructor(client: Client, getProxyUrl: () => string);
|
|
8
|
+
getUrlEncoded(proxy: TProxyParam, path: string, parameters?: TParameters, headers?: Record<string, string>): Promise<import("./internal/common").TResponse>;
|
|
9
|
+
postJson(proxy: TProxyParam, path: string, jsonData: Record<string, any>, headers?: Record<string, string>): Promise<import("./internal/common").TResponse>;
|
|
10
|
+
getCameraImage(params: TCameraImageConfig, proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
|
|
11
|
+
getEventDeclarations(proxy?: TProxyParam): Promise<string>;
|
|
12
|
+
getSupportedAudioSampleRate(proxy?: TProxyParam): Promise<TAudioSampleRates[]>;
|
|
13
|
+
performAutofocus(proxy?: TProxyParam): Promise<void>;
|
|
14
|
+
checkSDCard(proxy?: TProxyParam): Promise<TSDCardInfo>;
|
|
15
|
+
mountSDCard(proxy?: TProxyParam): Promise<number>;
|
|
16
|
+
unmountSDCard(proxy?: TProxyParam): Promise<number>;
|
|
17
|
+
private _doSDCardMountAction;
|
|
18
|
+
fetchSDCardJobProgress(jobId: number, proxy?: TProxyParam): Promise<number>;
|
|
19
|
+
downloadCameraReport(proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
|
|
20
|
+
getSystemLog(proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
|
|
21
|
+
getMaxFps(channel: number, proxy?: TProxyParam): Promise<number>;
|
|
22
|
+
getTimezone(proxy?: TProxyParam): Promise<string>;
|
|
23
|
+
getDateTimeInfo(proxy?: TProxyParam): Promise<{
|
|
24
|
+
data: {
|
|
25
|
+
dateTime: string;
|
|
26
|
+
dstEnabled: boolean;
|
|
27
|
+
localDateTime: string;
|
|
28
|
+
posixTimeZone: string;
|
|
29
|
+
timeZone: string;
|
|
30
|
+
};
|
|
31
|
+
}>;
|
|
32
|
+
getDevicesSettings(proxy?: TProxyParam): Promise<TAudioDevice[]>;
|
|
33
|
+
fetchRemoteDeviceInfo<T extends Record<string, any>>(payload: T, proxy?: TProxyParam): Promise<any>;
|
|
34
|
+
getHeaders(proxy?: TProxyParam): Promise<Record<string, string>>;
|
|
35
|
+
setHeaders(headers: Record<string, string>, proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
|
|
36
|
+
getParameter(paramNames: string | string[], proxy?: TProxyParam): Promise<Record<string, string>>;
|
|
37
|
+
setParameter(params: Record<string, string | number | boolean>, proxy?: TProxyParam): Promise<boolean>;
|
|
38
|
+
getGuardTourList(proxy?: TProxyParam): Promise<{
|
|
39
|
+
name: string;
|
|
40
|
+
id: string;
|
|
41
|
+
running: string;
|
|
42
|
+
tour: {
|
|
43
|
+
moveSpeed?: unknown;
|
|
44
|
+
position?: unknown;
|
|
45
|
+
presetNbr?: unknown;
|
|
46
|
+
waitTime?: unknown;
|
|
47
|
+
waitTimeViewType?: unknown;
|
|
48
|
+
}[];
|
|
49
|
+
camNbr?: unknown;
|
|
50
|
+
randomEnabled?: unknown;
|
|
51
|
+
timeBetweenSequences?: unknown;
|
|
52
|
+
}[]>;
|
|
53
|
+
setGuardTourEnabled(guardTourID: string, enable: boolean, proxy?: TProxyParam): Promise<boolean>;
|
|
54
|
+
getPTZPresetList(channel: number, proxy?: TProxyParam): Promise<string[]>;
|
|
55
|
+
listPTZ(camera: number, proxy?: TProxyParam): Promise<TCameraPTZItem[]>;
|
|
56
|
+
listPtzVideoSourceOverview(proxy?: TProxyParam): Promise<TPtzOverview>;
|
|
57
|
+
goToPreset(channel: number, presetName: string, proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
|
|
58
|
+
getPtzPosition(camera: number, proxy?: TProxyParam): Promise<TCameraPTZItemData>;
|
|
59
|
+
getInputState(port: number, proxy?: TProxyParam): Promise<boolean>;
|
|
60
|
+
setOutputState(port: number, active: boolean, proxy?: TProxyParam): Promise<import("./internal/common").TResponse>;
|
|
61
|
+
getApplicationList(proxy?: TProxyParam): Promise<TApplication[]>;
|
|
62
|
+
startApplication(applicationID: string, proxy?: TProxyParam): Promise<void>;
|
|
63
|
+
restartApplication(applicationID: string, proxy?: TProxyParam): Promise<void>;
|
|
64
|
+
stopApplication(applicationID: string, proxy?: TProxyParam): Promise<void>;
|
|
65
|
+
installApplication(data: Blob, fileName: string): Promise<void>;
|
|
66
|
+
}
|