@jibb-open/jssdk 3.5.8 → 3.5.10

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.
Files changed (83) hide show
  1. package/api/admin.js +418 -0
  2. package/api/auth.js +246 -0
  3. package/api/eventbus.js +249 -0
  4. package/api/index.js +53 -0
  5. package/api/meeting.js +488 -0
  6. package/api/recording.js +260 -0
  7. package/api/superadmin.js +105 -0
  8. package/api/user.js +51 -0
  9. package/api/webexbot.js +41 -0
  10. package/api/whiteboard.js +179 -0
  11. package/config.js +16 -0
  12. package/examples/browser/462.jibb.js +306 -0
  13. package/{src/examples → examples}/browser/index.html +0 -0
  14. package/examples/browser/jibb.js +7381 -0
  15. package/examples/browser/startSession.js +102 -0
  16. package/{src/examples → examples}/examples.js +1 -0
  17. package/examples/webexDevicesMacros/cameraPresets/jibb.js +280 -0
  18. package/examples/webexDevicesMacros/simplestExample/jibb.js +182 -0
  19. package/examples/webexDevicesMacros/webexDevice JSSDK/jibb_WebexXapi.js +3033 -0
  20. package/examples/webexDevicesMacros/withCameraControl/jibb.js +264 -0
  21. package/package.json +1 -1
  22. package/post-processing.js +43 -0
  23. package/types/exceptions.js +55 -0
  24. package/{src/types → types}/jibb.pb.js +5 -38
  25. package/types/proto.js +15 -0
  26. package/types/types.js +67 -0
  27. package/utils/cached_variable.js +25 -0
  28. package/utils/future.js +31 -0
  29. package/utils/http/http.axios.js +41 -0
  30. package/utils/http/index.js +10 -0
  31. package/utils/index.js +11 -0
  32. package/utils/logger/index.js +19 -0
  33. package/utils/logger/logger.empty.js +25 -0
  34. package/utils/logger/logger.pino.js +19 -0
  35. package/ws/connection_base.js +95 -0
  36. package/ws/eventbus.js +376 -0
  37. package/ws/index.js +36 -0
  38. package/ws/ipsa.js +262 -0
  39. package/ws/meeting.js +181 -0
  40. package/ws/observable_connection.js +87 -0
  41. package/ws/retry_connection.js +94 -0
  42. package/.babelrc +0 -31
  43. package/README.md +0 -4
  44. package/src/api/admin.js +0 -333
  45. package/src/api/auth.js +0 -208
  46. package/src/api/eventbus.js +0 -246
  47. package/src/api/index.js +0 -26
  48. package/src/api/meeting.js +0 -421
  49. package/src/api/recording.js +0 -225
  50. package/src/api/superadmin.js +0 -84
  51. package/src/api/user.js +0 -46
  52. package/src/api/webexbot.js +0 -32
  53. package/src/api/whiteboard.js +0 -175
  54. package/src/config.js +0 -12
  55. package/src/examples/browser/462.jibb.js +0 -1
  56. package/src/examples/browser/jibb.js +0 -2
  57. package/src/examples/browser/startSession.js +0 -112
  58. package/src/examples/webexDevicesMacros/cameraPresets/jibb.js +0 -338
  59. package/src/examples/webexDevicesMacros/simplestExample/jibb.js +0 -212
  60. package/src/examples/webexDevicesMacros/webexDevice JSSDK/jibb_WebexXapi.js +0 -2
  61. package/src/examples/webexDevicesMacros/withCameraControl/jibb.js +0 -303
  62. package/src/index.webex-devices.js +0 -13
  63. package/src/post-processing.js +0 -39
  64. package/src/types/exceptions.js +0 -48
  65. package/src/types/proto.js +0 -7
  66. package/src/types/types.js +0 -64
  67. package/src/utils/cached_variable.js +0 -23
  68. package/src/utils/future.js +0 -24
  69. package/src/utils/http/http.axios.js +0 -34
  70. package/src/utils/http/http.xapi.js +0 -87
  71. package/src/utils/http/index.js +0 -8
  72. package/src/utils/index.js +0 -5
  73. package/src/utils/logger/index.js +0 -11
  74. package/src/utils/logger/logger.empty.js +0 -25
  75. package/src/utils/logger/logger.pino.js +0 -15
  76. package/src/ws/connection_base.js +0 -81
  77. package/src/ws/eventbus.js +0 -363
  78. package/src/ws/index.js +0 -15
  79. package/src/ws/ipsa.js +0 -246
  80. package/src/ws/meeting.js +0 -170
  81. package/src/ws/observable_connection.js +0 -84
  82. package/src/ws/retry_connection.js +0 -82
  83. package/webpack.config.cjs +0 -144
@@ -1,363 +0,0 @@
1
- import {Config} from "../config.js";
2
- import {logger} from "../utils/logger/index.js"
3
- import {InvalidArgumentError} from '../types/exceptions.js';
4
- import {RetryConnection} from "./retry_connection.js";
5
- import {ConnectionStatus} from "./connection_base.js";
6
- import {UserClaims} from "../types/types.js";
7
- import {types, cilix} from "../types/proto.js"
8
- import {Auth} from "../api/auth.js";
9
-
10
- const ClientType = types.ClientType
11
- const ErrorCode = types.Code
12
- const BusMessage = cilix.BusMessage
13
-
14
-
15
- function getClientNameByType(clientType) {
16
- let found = Object.entries(ClientType).find(([k, v]) => {
17
- return v == clientType
18
- });
19
- if (!found)
20
- throw new InvalidArgumentError(`Invalid client type: ${clientType}`)
21
- let name = found[0].toLowerCase()
22
- return name
23
- }
24
-
25
- class WSConnection extends RetryConnection {
26
- #expiryTimer
27
-
28
- constructor(clientType, name) {
29
- let clientName = getClientNameByType(clientType).toLowerCase()
30
- super(`eventbus-${clientName}`)
31
- this.clientType = clientType
32
- this.socket = null
33
- this.userToken = null
34
- this.clientName = clientName
35
- this.name = name
36
- this.#expiryTimer = null
37
- }
38
-
39
- async start() {
40
- this.userToken = await Auth.getUserToken()
41
- this.userClaims = new UserClaims(this.userToken)
42
- let seconds = this.userClaims.getSecondsUntilExpiry()
43
- if (seconds <= 0) {
44
- this.onErrorMessage(ErrorCode.ERR_TIMEOUT, "token expired");
45
- return
46
- }
47
- this.#expiryTimer = setTimeout(() => {
48
- this.stop()
49
- this.onErrorMessage(ErrorCode.ERR_TIMEOUT, "token expired");
50
- }, seconds)
51
- super.start()
52
- }
53
-
54
- async stop() {
55
- clearTimeout(this.#expiryTimer)
56
- super.stop()
57
- }
58
-
59
- disconnect() {
60
- if (this.socket != null) {
61
- this.socket.close();
62
- this.socket = null;
63
- //this.fireOnError(ErrorLevel.WARNING, ErrorCode.ERR_CLOSED, "closed") //this one fired after diconnection error causes multiple connection (it call retray connection again)
64
- logger.info("eventbus disconnect ", this.clientName);
65
- }
66
-
67
- super.disconnect()
68
- }
69
-
70
- async write(msg) {
71
- await super.waitForConnection()
72
- logger.debug(`${this.getName()}.write: `, BusMessage.toObject(msg))
73
- let data = BusMessage.encode(msg).finish();
74
- this.socket.send(data)
75
- }
76
-
77
- writeObject(msg) {
78
- let err = BusMessage.verify(msg)
79
- if (err)
80
- throw new Error(err)
81
-
82
- let request = BusMessage.fromObject(msg)
83
- return this.write(request)
84
- }
85
-
86
- async connect() {
87
- if (this.getConnectionStatus() != ConnectionStatus.DISCONNECTED)
88
- return
89
-
90
- super.connect()
91
- let self = this;
92
-
93
- try {
94
- let c = new UserClaims(this.userToken)
95
- if (c.isExpired()) {
96
- self.onErrorMessage(ErrorCode.ERR_TIMEOUT, "token expired");
97
- return
98
- }
99
- } catch (err) {
100
- logger.error(e)
101
- self.onErrorMessage(ErrorCode.ERR_UNAUTHORIZED, "unauthorized");
102
- return
103
- }
104
-
105
- let base = new URL(Config.apiBaseURL)
106
- let uri = `wss://${base.hostname}/ws/eventbus/${this.clientName}?user_token=${this.userToken}&name=${this.name}`;
107
-
108
- this.socket = new WebSocket(uri);
109
- this.socket.binaryType = "arraybuffer"
110
- this.socket.addEventListener("open", () => {
111
- self.onConnected()
112
- });
113
- this.socket.addEventListener("close", () => {
114
- self.onDisconnected()
115
- });
116
- this.socket.addEventListener("message", (event) => {
117
- self.#handleMessage(event.data)
118
- });
119
- this.socket.addEventListener("error", (err) => {
120
- self.onWarningMessage(ErrorCode.ERR_IO, err);
121
- });
122
- }
123
-
124
- async #handleMessage(msg) {
125
- try {
126
- if (msg instanceof ArrayBuffer) {
127
- let buffer = new Uint8Array(msg)
128
- let response = BusMessage.decode(buffer)
129
- buffer = null
130
- logger.debug(`${this.getName()}.read: `, response)
131
- this.onMessage(response)
132
- return
133
- }
134
- } catch (err) {
135
- logger.error(err)
136
- }
137
-
138
- try {
139
- let Error = JSON.parse(msg);
140
- switch (Error.code) {
141
- case ErrorCode.ERR_TOO_MANY_CONNECTIONS:
142
- case ErrorCode.ERR_UNAUTHORIZED:
143
- case ErrorCode.ERR_BAD_REQUEST:
144
- case ErrorCode.ERR_TIMEOUT:
145
- this.onErrorMessage(Error.code, Error.reason)
146
- break
147
- default:
148
- this.onInfoMessage(Error.code, Error.reason)
149
- break
150
- }
151
- } catch (e) {
152
- this.onWarningMessage(ErrorCode.ERR_IO, e)
153
- }
154
- }
155
-
156
-
157
-
158
- onMessage(response) {
159
- logger.debug(response)
160
- }
161
- }
162
-
163
- class EventBusConnection extends WSConnection {
164
- static instances = new Map()
165
-
166
- static getInstance(clientType = ClientType.WEBAPP, name = "") {
167
- let c = EventBusConnection.instances.get(clientType)
168
- if (!c) {
169
- c = new EventBusConnection(clientType, name)
170
- EventBusConnection.instances.set(clientType, c)
171
- }
172
- return c
173
- }
174
-
175
- constructor(clientType = ClientType.WEBAPP, name = "") {
176
- super(clientType, name)
177
- }
178
-
179
- async onMessage(msg) {
180
- if (!msg || typeof msg !== 'object')
181
- return
182
-
183
- try {
184
- msg.clientConnected && this.#onClientConnected(msg)
185
- msg.clientDisconnected && this.#onClientDisconnected(msg)
186
- msg.cameraListRequest && this.#onCameraListRequest(msg)
187
- msg.cameraListResponse && this.#onCameraListResponse(msg)
188
- msg.runtimeConfigRequest && this.#onRuntimeConfigRequest(msg)
189
- msg.startRequest && this.#onStartRequest(msg)
190
- msg.stopRequest && this.#onStopRequest(msg)
191
- msg.previewRequest && this.#onPreviewRequest(msg)
192
- msg.previewResponse && this.#onPreviewResponse(msg)
193
- msg.ipsaResponse && this.#onIPSAResponse(msg)
194
- msg.tooManyPublishers && this.#onTooManyPublishers(msg)
195
- msg.recordingStarted && this.#onRecordingStarted(msg)
196
- msg.recordingStopped && this.#onRecordingStopped(msg)
197
- } catch (e) {
198
- logger.error(e);
199
- }
200
- }
201
-
202
- stopStream(clientId) {
203
- return this.writeObject({
204
- stopRequest: {
205
- },
206
- dst: {
207
- id: clientId,
208
- }
209
- })
210
- }
211
-
212
- startStream({
213
- appConfig,
214
- config,
215
- runtimeConfig,
216
- camera,
217
- sipUri,
218
- clientId
219
- }) {
220
- return this.writeObject({
221
- startRequest: {
222
- config,
223
- appConfig,
224
- runtimeConfig,
225
- camera,
226
- sipUri,
227
- },
228
- dst: {
229
- id: clientId,
230
- }
231
- })
232
- }
233
-
234
- requestCameraPreview(clientId, sourceId) {
235
- return this.writeObject({
236
- previewRequest: {
237
- source: {id: sourceId, }
238
- },
239
- dst: {
240
- id: clientId,
241
- }
242
- });
243
- }
244
-
245
- setRuntimeConfig(clientId, cfg) {
246
- return this.writeObject({
247
- runtimeConfigRequest: cfg,
248
- dst: {
249
- id: clientId,
250
- }
251
- });
252
- }
253
-
254
- getCameraList(clientId) {
255
- let request = {
256
- cameraListRequest: {
257
- },
258
- dst: {
259
- id: clientId
260
- }
261
- }
262
- return this.write(request);
263
- }
264
-
265
- sendCameraList(camList, src, dst) {
266
- let response = {
267
- cameraListResponse: {
268
- items: camList
269
- },
270
- src: src,
271
- dst: dst
272
- };
273
- return this.writeObject(response);
274
- }
275
-
276
- getClientStatusList() {
277
- let request = {
278
- clientStatusRequest: {
279
- }
280
- }
281
-
282
- return this.writeObject(request);
283
- }
284
-
285
- #sendPreview(image, dst) {
286
- let response = {
287
- previewResponse: {
288
- image: image
289
- },
290
- dst: dst,
291
- };
292
- return this.write(response);
293
- }
294
-
295
- async #onCameraListRequest(msg) {
296
- let response = await this.callSubscribers('onCameraListRequest', msg.cameraListRequest)
297
- this.sendCameraList(response, msg.dst, msg.src);
298
- }
299
-
300
- #onCameraListResponse(msg) {
301
- this.notify('onCameraListResponse', msg.cameraListResponse)
302
- }
303
-
304
- #onClientConnected(msg) {
305
- logger.info(`${this.getName()}: client connected: `, msg.src)
306
- this.notify('onClientConnected', msg.src)
307
- }
308
-
309
- #onClientDisconnected(msg) {
310
- logger.warn(`${this.getName()}: client disconnected: `, msg.src)
311
- this.notify('onClientDisconnected', msg.src)
312
- }
313
-
314
- #onRuntimeConfigRequest(msg) {
315
- this.notify('onRuntimeConfigRequest', msg.runtimeConfigRequest)
316
- }
317
-
318
- #onStopRequest(msg) {
319
- this.notify('onStopRequest', msg.stopRequest)
320
- }
321
-
322
- async #onPreviewRequest(msg) {
323
- let response = await this.callSubscribers('onPreviewRequest', msg.previewRequest)
324
- this.#sendPreview(response, msg.src);
325
- }
326
-
327
- #onPreviewResponse(msg) {
328
- this.notify('onPreviewResponse', msg.previewResponse)
329
- }
330
-
331
- #onStartRequest(msg) {
332
- let req = msg.startRequest
333
- if (!req?.camera?.id && !req?.sipUri && req?.inputSource?.id) {
334
- req.camera = {
335
- id: req.inputSource.id
336
- };
337
- }
338
- this.notify('onStartRequest', req)
339
- }
340
-
341
- #onCornersReceived(msg) {
342
- this.notify('onCornersReceived', msg.corners.corners)
343
- }
344
-
345
-
346
- #onIPSAResponse(msg) {
347
- msg && this.notify('onIPSAResponse', msg.ipsaResponse)
348
- }
349
-
350
- #onTooManyPublishers(msg) {
351
- this.notify('onTooManyPublishers', msg.tooManyPublishers)
352
- }
353
-
354
- #onRecordingStarted(msg) {
355
- this.notify('onRecordingStarted', msg.recordingStarted)
356
- }
357
-
358
- #onRecordingStopped(msg) {
359
- this.notify('onRecordingStopped', msg.recordingStopped)
360
- }
361
- }
362
-
363
- export {EventBusConnection}
package/src/ws/index.js DELETED
@@ -1,15 +0,0 @@
1
- import {EventBusConnection} from "./eventbus.js";
2
- import {IPSA} from "./ipsa.js";
3
- import {MeetingConnection} from "./meeting.js";
4
-
5
- if (globalThis?.WebSocket == undefined) {
6
- import("isomorphic-ws").then((webSocket) => {
7
- globalThis.WebSocket = webSocket.default;
8
- });
9
- }
10
-
11
- export {
12
- MeetingConnection,
13
- EventBusConnection,
14
- IPSA,
15
- }
package/src/ws/ipsa.js DELETED
@@ -1,246 +0,0 @@
1
- import {Config as SDKConfig} from "../config.js";
2
- import {logger} from "../utils/logger/index.js"
3
- import {RetryConnection} from "./retry_connection.js";
4
- import {ConnectionStatus} from "./connection_base.js";
5
- import {UserClaims, MeetingClaims} from "../types/types.js";
6
- import {ipsa, types} from "../types/proto.js"
7
- const ErrorCode = types.Code
8
-
9
- class IPSAClass extends RetryConnection {
10
- #expiryTimer
11
-
12
- constructor() {
13
- super('ipsa')
14
- this.socket = null
15
- this.onInputImage = null
16
- this.onError = null
17
- this.onResponse = null
18
- this.userToken = null
19
- this.#expiryTimer = null
20
- this.#clear()
21
- }
22
-
23
- start({userToken, request, onInputImage, onError, onResponse}) {
24
- if (!this.isStarted()) {
25
- this.setRuntimeConfig(request.runtimeConfig)
26
- this.setAppConfig(request.appConfig)
27
- this.#setConfig(request.config)
28
- this.onInputImage = onInputImage
29
- this.onError = onError
30
- this.onResponse = onResponse
31
- this.userToken = userToken
32
-
33
- let meetingClaims = new MeetingClaims(this.appConfigRequest.appConfig.meetingToken)
34
- let userClaims = new UserClaims(this.userToken)
35
- let seconds = Math.min(userClaims.getSecondsUntilExpiry(), meetingClaims.getSecondsUntilExpiry())
36
- if (seconds <= 0) {
37
- this.onErrorMessage(ErrorCode.ERR_TIMEOUT, "token expired");
38
- return
39
- } else {
40
- this.#expiryTimer = setTimeout(() => {
41
- this.stop()
42
- this.onErrorMessage(ErrorCode.ERR_TIMEOUT, "token expired");
43
- }, seconds)
44
- }
45
- }
46
- super.start()
47
- }
48
-
49
- stop() {
50
- clearTimeout(this.#expiryTimer)
51
- this.#clear()
52
- super.stop()
53
- }
54
-
55
- #clear() {
56
- this.appConfigRequest = null
57
- this.configRequest = null
58
- this.runtimeConfigRequest = null
59
- this.stats = new Map();
60
- this.requestId = 0
61
- }
62
-
63
- disconnect() {
64
- super.disconnect()
65
- if (this.socket != null) {
66
- this.socket.close();
67
- this.socket = null;
68
- // this.fireOnError(ErrorLevel.ERROR, ErrorCode.ERR_CLOSED, "closed") //this one fired after diconnection error causes multiple connection (it call retray connection again)
69
- }
70
- }
71
-
72
- async #write(msg) {
73
- let err = ipsa.Request.verify(msg)
74
- if (err)
75
- throw new Error("invalid message: " + err)
76
-
77
- if (msg) {
78
- let data = ipsa.Request.encode(msg).finish()
79
- this.socket.send(data)
80
- }
81
- }
82
-
83
- async connect() {
84
- if (this.getConnectionStatus() != ConnectionStatus.DISCONNECTED)
85
- return
86
-
87
- super.connect()
88
-
89
- let meetingId = this.appConfigRequest.appConfig.meetingId
90
- let meetingToken = this.appConfigRequest.appConfig.meetingToken
91
-
92
- try {
93
- let c = new UserClaims(this.userToken)
94
- if (c.isExpired()) {
95
- this.onErrorMessage(ErrorCode.ERR_TIMEOUT, "token expired");
96
- return
97
- }
98
- } catch (err) {
99
- this.onErrorMessage(ErrorCode.ERR_UNAUTHORIZED, "unauthorized");
100
- return
101
- }
102
-
103
- logger.info(`Connecting IPSA to meeting ${meetingId}...`);
104
- let base = new URL(SDKConfig.apiBaseURL)
105
- let uri = `wss://${base.hostname}/ws/ipsa/${meetingId}?user_token=${this.userToken}&meeting_token=${meetingToken}`;
106
-
107
- this.socket = new WebSocket(uri);
108
- this.socket.binaryType = "arraybuffer"
109
- this.socket.addEventListener("open", async () => {
110
- try {
111
- await this.#write(this.configRequest)
112
- await this.#write(this.runtimeConfigRequest)
113
- await this.#write(this.appConfigRequest)
114
- this.onConnected()
115
- } catch (err) {
116
- this.onWarningMessage(ErrorCode.ERR_IO, err)
117
- this.disconnect()
118
- return
119
- }
120
-
121
- let loopFunction = () => {
122
- if (!this.isConnected() || !this.isStarted())
123
- return
124
-
125
- if (this.socket.bufferedAmount > 0) {
126
- logger.warn("ipsa: low internet speed connection")
127
- setTimeout(loopFunction, 100)
128
- } else {
129
- setTimeout(loopFunction, 500)
130
- this.#writeInputImage().catch(err => logger.error(err))
131
- }
132
- }
133
-
134
- loopFunction()
135
- });
136
- this.socket.addEventListener("close", () => {
137
- this.onDisconnected()
138
- });
139
- this.socket.addEventListener("message", (event) => {
140
- this.#handleMessage(event.data);
141
- });
142
- this.socket.addEventListener("error", (err) => {
143
- this.onWarningMessage(ErrorCode.ERR_IO, err);
144
- });
145
- }
146
-
147
- getAverageResponseTime() {
148
- let avg = NaN
149
-
150
- try {
151
- let items = Array.from(this.stats.values())
152
- .map(e => (e.responseTime - e.requestTime))
153
- .filter(e => !isNaN(e));
154
-
155
- let sum = items.reduce((a, b) => (a + b));
156
- avg = sum / items.length;
157
- } catch (err) {
158
- }
159
-
160
- return avg;
161
- }
162
-
163
- async #handleMessage(msg) {
164
- try {
165
- if (msg instanceof ArrayBuffer) {
166
- let buffer = new Uint8Array(msg)
167
- let response = ipsa.Response.decode(buffer)
168
- this.#onResponse(response);
169
- return
170
- }
171
- } catch (err) {
172
- logger.error(err)
173
- }
174
-
175
- try {
176
- msg = JSON.parse(msg);
177
-
178
- switch (msg.code) {
179
- case ErrorCode.ERR_TOO_MANY_CONNECTIONS:
180
- case ErrorCode.ERR_UNAUTHORIZED:
181
- case ErrorCode.ERR_BAD_REQUEST:
182
- this.onErrorMessage(msg?.code, msg?.reason)
183
- this.stop()
184
- break
185
- default:
186
- this.onInfoMessage(msg?.code, msg?.reason)
187
- break
188
- }
189
- } catch (e) {
190
- this.onWarningMessage(ErrorCode.ERR_IO, e)
191
- }
192
- }
193
-
194
- #onResponse(response) {
195
- if (response.id >= 100) {
196
- let id = response.id - 100
197
- let s = this.stats.get(id) || {}
198
- s.responseTime = performance.now()
199
- this.stats.set(id, s)
200
- }
201
-
202
- if (this.onResponse) {
203
- this.onResponse(response)
204
- }
205
- }
206
-
207
- async #writeInputImage() {
208
- let img = await this.onInputImage()
209
- this.requestId = (this.requestId + 1) % 8
210
- this.stats.set(this.requestId, {requestTime: performance.now()})
211
-
212
- let request = ipsa.Request.create({
213
- id: this.requestId + 100,
214
- ipsa: {
215
- data: img,
216
- }
217
- })
218
- this.#write(request)
219
- }
220
-
221
-
222
- #setConfig(cfg) {
223
- let request = ipsa.Request.create({config: cfg})
224
- this.configRequest = request
225
- if (this.isConnected())
226
- this.#write(request)
227
- }
228
-
229
- setRuntimeConfig(cfg) {
230
- let request = ipsa.Request.create({runtimeConfig: cfg})
231
- this.runtimeConfigRequest = request
232
- if (this.isConnected())
233
- this.#write(request)
234
- }
235
-
236
- setAppConfig(cfg) {
237
- let request = ipsa.Request.create({appConfig: cfg})
238
- this.appConfigRequest = request
239
- if (this.isConnected())
240
- this.#write(request)
241
- }
242
- }
243
-
244
-
245
- export let IPSA = new IPSAClass()
246
-