larksr_websdk 3.2.340 → 3.2.342
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/doc/config.md +222 -0
- package/dist/doc/event_codes.md +286 -0
- package/dist/doc/events.md +229 -0
- package/dist/doc/functions.md +603 -0
- package/dist/doc/index.md +83 -0
- package/dist/doc/member_variables.md +407 -0
- package/dist/doc/sdkid_encryption.md +40 -0
- package/dist/doc/update.md +447 -0
- package/dist/larksr-web-sdk.min.js +1 -1
- package/dist/types/api.d.ts +132 -0
- package/dist/types/appli_params.d.ts +298 -0
- package/dist/types/common/cmd.d.ts +28 -0
- package/dist/types/common/constant.d.ts +4 -0
- package/dist/types/common/interface.d.ts +30 -0
- package/dist/types/config.d.ts +59 -0
- package/dist/types/event/event_base.d.ts +11 -0
- package/dist/types/event/iframe_poster.d.ts +9 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/lark/Worker.d.ts +0 -0
- package/dist/types/lark/application.d.ts +191 -0
- package/dist/types/lark/canvas_render.d.ts +28 -0
- package/dist/types/lark/custom.d.ts +7 -0
- package/dist/types/lark/ice_candiadate_parser.d.ts +24 -0
- package/dist/types/lark/lark_event_type.d.ts +114 -0
- package/dist/types/lark/media_share_interface.d.ts +46 -0
- package/dist/types/lark/message.d.ts +22 -0
- package/dist/types/lark/peer_connection.d.ts +191 -0
- package/dist/types/lark/peer_connection_media_share.d.ts +101 -0
- package/dist/types/lark/recoder.d.ts +55 -0
- package/dist/types/lark/sdp_util.d.ts +36 -0
- package/dist/types/lark/test_pixel_streaming.d.ts +54 -0
- package/dist/types/lark/websocket_channel.d.ts +57 -0
- package/dist/types/lark/websocket_proxy.d.ts +56 -0
- package/dist/types/larksr.d.ts +1231 -0
- package/dist/types/localization/base.d.ts +8 -0
- package/dist/types/localization/gesture_ins.d.ts +4 -0
- package/dist/types/localization/language.d.ts +6 -0
- package/dist/types/localization/loader.d.ts +14 -0
- package/dist/types/localization/message.d.ts +81 -0
- package/dist/types/localization/ui.d.ts +60 -0
- package/dist/types/operation/gamepad_handler.d.ts +67 -0
- package/dist/types/operation/gesture.d.ts +72 -0
- package/dist/types/operation/gesture_handler.d.ts +53 -0
- package/dist/types/operation/handler_base.d.ts +8 -0
- package/dist/types/operation/keyboard_handler.d.ts +21 -0
- package/dist/types/operation/keymap.d.ts +24 -0
- package/dist/types/operation/letter_keymap.d.ts +8 -0
- package/dist/types/operation/mouse_handler.d.ts +42 -0
- package/dist/types/operation/num_keymap.d.ts +12 -0
- package/dist/types/operation/operation.d.ts +97 -0
- package/dist/types/operation/pixel_streaming_input.d.ts +82 -0
- package/dist/types/operation/touch_handler.d.ts +11 -0
- package/dist/types/operation/utils.d.ts +18 -0
- package/dist/types/protobuf/cloudlark.d.ts +8221 -0
- package/dist/types/screen_state.d.ts +120 -0
- package/dist/types/utils/browser_type.d.ts +37 -0
- package/dist/types/utils/capabilities.d.ts +54 -0
- package/dist/types/utils/full_screen.d.ts +25 -0
- package/dist/types/utils/ios-inner-height.d.ts +4 -0
- package/dist/types/utils/lock_pointer.d.ts +23 -0
- package/dist/types/utils/log.d.ts +25 -0
- package/dist/types/utils/scale_mode.d.ts +26 -0
- package/dist/types/utils/unit.d.ts +148 -0
- package/package.json +1 -1
- package/types/lark/application.d.ts +5 -3
- package/types/lark/canvas_render.d.ts +28 -0
- package/types/lark/custom.d.ts +7 -0
- package/types/lark/media_share_interface.d.ts +2 -2
- package/types/lark/peer_connection.d.ts +5 -2
- package/types/lark/peer_connection_media_share.d.ts +3 -2
- package/types/larksr.d.ts +7 -2
- package/types/protobuf/cloudlark.d.ts +8221 -0
- package/types/screen_state.d.ts +2 -0
- package/types/utils/ios-inner-height.d.ts +4 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { EventBase, LocalEvent } from '../event/event_base';
|
|
2
|
+
import { LarkSR } from '../larksr';
|
|
3
|
+
import { MediaShareInterface, RTCMediaTrackBinding } from './media_share_interface';
|
|
4
|
+
import { CloudLark } from '@/protobuf/cloudlark';
|
|
5
|
+
export declare enum WEBRTC_MEDIA_SHARE_EVENT_TYPE {
|
|
6
|
+
RTC_SDP = 0,
|
|
7
|
+
RTC_ICECANDIDATE = 1,
|
|
8
|
+
ICE_STATE_CHANGE = 2,
|
|
9
|
+
ERROR = 3,
|
|
10
|
+
INFO = 4
|
|
11
|
+
}
|
|
12
|
+
export interface WebRTCMediaShareEvent extends LocalEvent<WEBRTC_MEDIA_SHARE_EVENT_TYPE> {
|
|
13
|
+
data?: any;
|
|
14
|
+
}
|
|
15
|
+
export interface WebRTCConfig {
|
|
16
|
+
serverIP: string;
|
|
17
|
+
preferPubOutIp: string;
|
|
18
|
+
}
|
|
19
|
+
export default class PeerConnectionMediaShare extends EventBase<WEBRTC_MEDIA_SHARE_EVENT_TYPE, WebRTCMediaShareEvent> implements MediaShareInterface {
|
|
20
|
+
get audioDeviceId(): string | undefined;
|
|
21
|
+
get audioTrack(): MediaStreamTrack | undefined;
|
|
22
|
+
get videoDeviceId(): string | undefined;
|
|
23
|
+
get videoTrack(): MediaStreamTrack | undefined;
|
|
24
|
+
get audioPaused(): boolean;
|
|
25
|
+
get videoPaused(): boolean;
|
|
26
|
+
private larksr;
|
|
27
|
+
private offerOptions;
|
|
28
|
+
private _pcConfig;
|
|
29
|
+
set pcConfig(config: CloudLark.IRTCConfiguration | null | undefined);
|
|
30
|
+
get pcConfig(): CloudLark.IRTCConfiguration | null | undefined;
|
|
31
|
+
private pc;
|
|
32
|
+
private audioBinding;
|
|
33
|
+
private videoBinding;
|
|
34
|
+
private sdpCreateSuccess;
|
|
35
|
+
private readonly sendStream;
|
|
36
|
+
private canvasRender;
|
|
37
|
+
constructor(larksr: LarkSR);
|
|
38
|
+
create(config?: CloudLark.IRTCConfiguration | null | undefined): Promise<void>;
|
|
39
|
+
createOffer(): void;
|
|
40
|
+
close(): void;
|
|
41
|
+
setAudioEnable(enable: boolean): void;
|
|
42
|
+
setVideoEnable(enable: boolean): void;
|
|
43
|
+
setShareEnable(enable: boolean): void;
|
|
44
|
+
stopLocalAudio(): void;
|
|
45
|
+
stopLocalVideo(): void;
|
|
46
|
+
stopLocalShare(): void;
|
|
47
|
+
pauseAudioSending(): false | undefined;
|
|
48
|
+
resumeAudioSending(): false | undefined;
|
|
49
|
+
pauseVideoSending(): false | undefined;
|
|
50
|
+
resumeVideoSending(): false | undefined;
|
|
51
|
+
closeAudio(): false | undefined;
|
|
52
|
+
closeVideo(): false | undefined;
|
|
53
|
+
closeShare(): false | undefined;
|
|
54
|
+
private stopLocalTrackBing;
|
|
55
|
+
openAudio(deviceId?: string): Promise<{
|
|
56
|
+
streams: MediaStream;
|
|
57
|
+
rtcRtpSenders: RTCMediaTrackBinding[];
|
|
58
|
+
}>;
|
|
59
|
+
openVideo(audio?: boolean, cameraId?: string, width?: number, height?: number, front?: boolean): Promise<{
|
|
60
|
+
streams: MediaStream;
|
|
61
|
+
rtcRtpSenders: RTCMediaTrackBinding[];
|
|
62
|
+
}>;
|
|
63
|
+
openDefaultMedia(video?: boolean, audio?: boolean): Promise<{
|
|
64
|
+
streams: MediaStream;
|
|
65
|
+
rtcRtpSenders: RTCMediaTrackBinding[];
|
|
66
|
+
}>;
|
|
67
|
+
openShareMediaDevice(): Promise<void>;
|
|
68
|
+
getConnectedAudioinputDevices(): Promise<MediaDeviceInfo[]>;
|
|
69
|
+
getConnectedAudioOutputDevices(): Promise<MediaDeviceInfo[]>;
|
|
70
|
+
getConnectedVideoinputDevices(): Promise<MediaDeviceInfo[]>;
|
|
71
|
+
getConnectedDevices(type: MediaDeviceKind): Promise<MediaDeviceInfo[]>;
|
|
72
|
+
openAudioDevice(deviceId: string, kind?: "audioinput" | "audiooutput"): Promise<{
|
|
73
|
+
streams: MediaStream;
|
|
74
|
+
rtcRtpSenders: RTCMediaTrackBinding[];
|
|
75
|
+
}>;
|
|
76
|
+
openCamera(cameraId: string, width?: number, height?: number, audio?: boolean, front?: boolean): Promise<{
|
|
77
|
+
streams: MediaStream;
|
|
78
|
+
rtcRtpSenders: RTCMediaTrackBinding[];
|
|
79
|
+
}>;
|
|
80
|
+
openUserMeida(constraints?: MediaStreamConstraints, reset?: boolean): Promise<{
|
|
81
|
+
streams: MediaStream;
|
|
82
|
+
rtcRtpSenders: RTCMediaTrackBinding[];
|
|
83
|
+
}>;
|
|
84
|
+
private resumeOrCreateBinding;
|
|
85
|
+
addMediaTrack(track: MediaStreamTrack, ...streams: MediaStream[]): boolean;
|
|
86
|
+
removeMediaTrack(track: RTCRtpSender): boolean;
|
|
87
|
+
requestUserMediaPermission(constraints?: MediaStreamConstraints): Promise<MediaStream>;
|
|
88
|
+
/**
|
|
89
|
+
* 接收到sdp
|
|
90
|
+
* @param des sdp
|
|
91
|
+
*/
|
|
92
|
+
onRemoteDescription(des: RTCSessionDescriptionInit): void;
|
|
93
|
+
onReceiveCandidate(candateInit: RTCIceCandidateInit): void;
|
|
94
|
+
private addIceCandidate;
|
|
95
|
+
private onCreateOfferSuccess;
|
|
96
|
+
private onIceCandidate;
|
|
97
|
+
private onIceStateChange;
|
|
98
|
+
private iceStateChange;
|
|
99
|
+
private $emit;
|
|
100
|
+
private createEvent;
|
|
101
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { EventBase, LocalEvent } from '../event/event_base';
|
|
2
|
+
export declare enum RECORDER_STATE {
|
|
3
|
+
READY = 0,
|
|
4
|
+
RECORDING = 1
|
|
5
|
+
}
|
|
6
|
+
export declare const RECODER_DEFAULT_CONFIG: {
|
|
7
|
+
sampleRate: number;
|
|
8
|
+
sampleBits: number;
|
|
9
|
+
bufferSize: number;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* LarkSR 实例会发出的事件
|
|
13
|
+
*/
|
|
14
|
+
export declare enum RecodeEventType {
|
|
15
|
+
DATA = 0
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* LarkSR 发出的事件
|
|
19
|
+
*/
|
|
20
|
+
export interface RecodeEvent extends LocalEvent<RecodeEventType> {
|
|
21
|
+
voiceId: number;
|
|
22
|
+
sliceId: number;
|
|
23
|
+
data: Uint8Array;
|
|
24
|
+
}
|
|
25
|
+
export default class Recorder extends EventBase<RecodeEventType, RecodeEvent> {
|
|
26
|
+
get state(): RECORDER_STATE;
|
|
27
|
+
private _state;
|
|
28
|
+
private ctx;
|
|
29
|
+
private sampleRate;
|
|
30
|
+
private sampleBits;
|
|
31
|
+
private recorder;
|
|
32
|
+
private source;
|
|
33
|
+
private stream;
|
|
34
|
+
private buffer;
|
|
35
|
+
private bufferSize;
|
|
36
|
+
get voiceId(): number;
|
|
37
|
+
updateVoiceId(): number;
|
|
38
|
+
private _voiceId;
|
|
39
|
+
constructor({ bufferSize, sampleRate, sampleBits, }?: {
|
|
40
|
+
sampleRate: number;
|
|
41
|
+
sampleBits: number;
|
|
42
|
+
bufferSize: number;
|
|
43
|
+
});
|
|
44
|
+
start(): Promise<number>;
|
|
45
|
+
pause(): void;
|
|
46
|
+
clear(): void;
|
|
47
|
+
/**
|
|
48
|
+
* @deprecated
|
|
49
|
+
* @returns
|
|
50
|
+
*/
|
|
51
|
+
private getRecord;
|
|
52
|
+
private merge;
|
|
53
|
+
private compress;
|
|
54
|
+
private encodeToPCM;
|
|
55
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export default class SdpUtil {
|
|
2
|
+
private static vp8;
|
|
3
|
+
private static vp9;
|
|
4
|
+
private static h264;
|
|
5
|
+
private static av1x;
|
|
6
|
+
private static h265;
|
|
7
|
+
private static hevc;
|
|
8
|
+
private static svac;
|
|
9
|
+
private static tail;
|
|
10
|
+
private static config;
|
|
11
|
+
static isLoopIpAddress(ip: string): boolean;
|
|
12
|
+
static getRtpmapRegByMode(mode: 'VP8' | 'VP9' | 'H264' | 'AV1X' | 'H265' | 'HEVC' | 'SVAC'): RegExp;
|
|
13
|
+
static hasVp8(sdp: string): boolean;
|
|
14
|
+
static hasVp9(sdp: string): boolean;
|
|
15
|
+
static hasH264(sdp: string): boolean;
|
|
16
|
+
static hasAV1X(sdp: string): boolean;
|
|
17
|
+
static hasH265(sdp: string): boolean;
|
|
18
|
+
static hasHEVC(sdp: string): boolean;
|
|
19
|
+
static hasSVAC(sdp: string): boolean;
|
|
20
|
+
static hasMode(sdp: string, mode: 'VP8' | 'VP9' | 'H264' | 'AV1X' | 'H265' | 'HEVC' | 'SVAC'): boolean;
|
|
21
|
+
static setAudioBitrate(sdp: string, bitrate: number): string;
|
|
22
|
+
static setBitRate(sdp: string, startBitrate: number, maxBitrate: number, minBitrate: number): string;
|
|
23
|
+
static setModeBitRate(sdp: string, startBitrate: number, maxBitrate: number, minBitrate: number, mode: 'VP8' | 'VP9' | 'H264' | 'AV1X'): string;
|
|
24
|
+
static removeVp8(sdp: string): string;
|
|
25
|
+
static removeVp9(sdp: string): string;
|
|
26
|
+
static removeH264(sdp: string): string;
|
|
27
|
+
static removeAV1X(sdp: string): string;
|
|
28
|
+
static removeH265(sdp: string): string;
|
|
29
|
+
static removeHEVC(sdp: string): string;
|
|
30
|
+
static removeSVAC(sdp: string): string;
|
|
31
|
+
static sdpFilter(sdp: string, mode: 'VP8' | 'VP9' | 'H264' | 'AV1X' | 'H265' | 'HEVC' | 'SVAC'): string;
|
|
32
|
+
static sdpGooAttrLine(...attrs: string[]): string;
|
|
33
|
+
static sdpBlankAttrLine(...attrs: string[]): string;
|
|
34
|
+
static getBlankAttrs(sdpLine: string): string[];
|
|
35
|
+
static getAttrName(sdpLine: string): string;
|
|
36
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { EventBase, LocalEvent } from '../event/event_base';
|
|
2
|
+
import { LarkSR } from '../larksr';
|
|
3
|
+
export declare enum CHANNEL_EVENT_TYPE {
|
|
4
|
+
OPEN = 0,
|
|
5
|
+
CLOSE = 1,
|
|
6
|
+
ERROR = 2,
|
|
7
|
+
CLIENT_MSG = 3
|
|
8
|
+
}
|
|
9
|
+
export interface ChannelEvent extends LocalEvent<CHANNEL_EVENT_TYPE> {
|
|
10
|
+
data?: any;
|
|
11
|
+
}
|
|
12
|
+
export interface PixelStreamingWebscocketConfig {
|
|
13
|
+
serverAddress: string;
|
|
14
|
+
ip: string;
|
|
15
|
+
port: string;
|
|
16
|
+
path?: string;
|
|
17
|
+
}
|
|
18
|
+
export default class PixelStreamingWebsocketChannel extends EventBase<CHANNEL_EVENT_TYPE, ChannelEvent> {
|
|
19
|
+
private get wsServer();
|
|
20
|
+
private config;
|
|
21
|
+
private connection;
|
|
22
|
+
private keepAliveTimeout;
|
|
23
|
+
private larksr;
|
|
24
|
+
constructor(config: PixelStreamingWebscocketConfig, larksr: LarkSR);
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
*/
|
|
28
|
+
connect(): Promise<this>;
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
*/
|
|
32
|
+
close(): Promise<void>;
|
|
33
|
+
sendMsg(msg: any): void;
|
|
34
|
+
isOpen(): boolean;
|
|
35
|
+
private startKeepAlive;
|
|
36
|
+
private stopKeepAlive;
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
*/
|
|
40
|
+
private onMessage;
|
|
41
|
+
private onOpen;
|
|
42
|
+
/**
|
|
43
|
+
*
|
|
44
|
+
* @param e
|
|
45
|
+
*/
|
|
46
|
+
private onWSError;
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
* @param e
|
|
50
|
+
*/
|
|
51
|
+
private onWSClose;
|
|
52
|
+
private $emit;
|
|
53
|
+
private createEvent;
|
|
54
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { EventBase, LocalEvent } from '../event/event_base';
|
|
2
|
+
import * as Msg from '../protobuf/cloudlark';
|
|
3
|
+
import { LarkSR } from '../larksr';
|
|
4
|
+
export declare enum CHANNEL_EVENT_TYPE {
|
|
5
|
+
OPEN = 0,
|
|
6
|
+
CLOSE = 1,
|
|
7
|
+
ERROR = 2,
|
|
8
|
+
CLIENT_MSG = 3
|
|
9
|
+
}
|
|
10
|
+
export interface ChannelEvent extends LocalEvent<CHANNEL_EVENT_TYPE> {
|
|
11
|
+
data?: Msg.CloudLark.ToClientMessage;
|
|
12
|
+
}
|
|
13
|
+
export interface WebscocketConfig {
|
|
14
|
+
serverAddress: string;
|
|
15
|
+
ip: string;
|
|
16
|
+
port: string;
|
|
17
|
+
renderSSLServerPort?: string;
|
|
18
|
+
path?: string;
|
|
19
|
+
}
|
|
20
|
+
export default class WebsocketChannel extends EventBase<CHANNEL_EVENT_TYPE, ChannelEvent> {
|
|
21
|
+
private get wsServer();
|
|
22
|
+
private config;
|
|
23
|
+
private connection;
|
|
24
|
+
private keepAliveTimeout;
|
|
25
|
+
private larksr;
|
|
26
|
+
constructor(config: WebscocketConfig, larksr: LarkSR);
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
*/
|
|
30
|
+
connect(): Promise<this>;
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
*/
|
|
34
|
+
close(): Promise<void>;
|
|
35
|
+
sendMsg(msg: Msg.CloudLark.ToServerMessage): void;
|
|
36
|
+
sendBuffer(data: ArrayBuffer): void;
|
|
37
|
+
isOpen(): boolean;
|
|
38
|
+
private startKeepAlive;
|
|
39
|
+
private stopKeepAlive;
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
*/
|
|
43
|
+
private onMessage;
|
|
44
|
+
private onOpen;
|
|
45
|
+
/**
|
|
46
|
+
*
|
|
47
|
+
* @param e
|
|
48
|
+
*/
|
|
49
|
+
private onWSError;
|
|
50
|
+
/**
|
|
51
|
+
*
|
|
52
|
+
* @param e
|
|
53
|
+
*/
|
|
54
|
+
private onWSClose;
|
|
55
|
+
private $emit;
|
|
56
|
+
private createEvent;
|
|
57
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { EventBase, LocalEvent } from '../event/event_base';
|
|
2
|
+
import * as Msg from '../protobuf/cloudlark';
|
|
3
|
+
import { LarkSR } from '../larksr';
|
|
4
|
+
export declare enum PROXY_EVENT_TYPE {
|
|
5
|
+
OPEN = 0,
|
|
6
|
+
CLOSE = 1,
|
|
7
|
+
ERROR = 2,
|
|
8
|
+
CLIENT_MSG = 3
|
|
9
|
+
}
|
|
10
|
+
export interface ProxyEvent extends LocalEvent<PROXY_EVENT_TYPE> {
|
|
11
|
+
data?: Msg.CloudLark.ToClientMessage;
|
|
12
|
+
}
|
|
13
|
+
export interface ProxyConfig {
|
|
14
|
+
serverAddress: string;
|
|
15
|
+
appServer: string;
|
|
16
|
+
appPort: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const PROXY_PATH = "websocket";
|
|
19
|
+
export default class WebsocketProxy extends EventBase<PROXY_EVENT_TYPE, ProxyEvent> {
|
|
20
|
+
private get wsServer();
|
|
21
|
+
private config;
|
|
22
|
+
private connection;
|
|
23
|
+
private keepAliveTimeout;
|
|
24
|
+
private larksr;
|
|
25
|
+
constructor(config: ProxyConfig, larksr: LarkSR);
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
*/
|
|
29
|
+
connect(): Promise<this>;
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
33
|
+
close(): Promise<void>;
|
|
34
|
+
isOpen(): boolean;
|
|
35
|
+
sendMsg(msg: Msg.CloudLark.ToServerMessage): void;
|
|
36
|
+
sendBuffer(data: ArrayBuffer): void;
|
|
37
|
+
private startKeepAlive;
|
|
38
|
+
private stopKeepAlive;
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
*/
|
|
42
|
+
private onMessage;
|
|
43
|
+
private onOpen;
|
|
44
|
+
/**
|
|
45
|
+
*
|
|
46
|
+
* @param e
|
|
47
|
+
*/
|
|
48
|
+
private onWSError;
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
* @param e
|
|
52
|
+
*/
|
|
53
|
+
private onWSClose;
|
|
54
|
+
private $emit;
|
|
55
|
+
private createEvent;
|
|
56
|
+
}
|