@coherentglobal/spark-execute-sdk 0.4.12 → 0.4.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coherentglobal/spark-execute-sdk",
3
- "version": "0.4.12",
3
+ "version": "0.4.13",
4
4
  "description": "",
5
5
  "main": "src/node.js",
6
6
  "browser": "dist/browser.js",
@@ -11,7 +11,7 @@
11
11
  "bundle:full": "browserify src/browser.js --standalone Spark > dist/browser.js",
12
12
  "bundle:min": "browserify src/browser.js --standalone Spark | uglifyjs --compress --mangle --comments false > lib/sparkexecute.min.js",
13
13
  "test": "npx mocha --bail --exit --recursive --timeout 100000 --reporter nyan",
14
- "cover": "nyc --check-coverage --reporter=lcov --lines 60 mocha --bail --exit --recursive --timeout 100000"
14
+ "cover": "nyc --check-coverage --reporter=lcov --lines 65 mocha --bail --exit --recursive --timeout 100000"
15
15
  },
16
16
  "engines": {
17
17
  "node": ">=14.0.0"
@@ -23,21 +23,19 @@
23
23
  "author": "",
24
24
  "license": "ISC",
25
25
  "dependencies": {
26
- "@coherentglobal/wasm-runner": "^0.0.63",
26
+ "@coherentglobal/wasm-runner": "^0.0.78",
27
27
  "@types/node": "^18.7.18",
28
28
  "axios": "^0.27.2",
29
- "chai": "^4.3.6",
30
29
  "fs": "^0.0.1-security",
31
- "got": "^11.8.3",
30
+ "got": "^11.8.6",
32
31
  "http-status-codes": "^2.2.0",
33
32
  "joi": "^17.6.0",
34
- "jstify": "^0.14.0",
35
33
  "pino": "^8.5.0",
36
- "prettier": "^2.7.1",
37
34
  "serialize-anything": "^1.2.3",
38
35
  "uuid": "^9.0.0"
39
36
  },
40
37
  "devDependencies": {
38
+ "chai": "^4.3.6",
41
39
  "@babel/cli": "^7.18.10",
42
40
  "@babel/core": "^7.19.0",
43
41
  "@babel/plugin-transform-runtime": "^7.18.10",
@@ -53,7 +51,7 @@
53
51
  "eslint-plugin-prettier": "^4.0.0",
54
52
  "express": "^4.18.2",
55
53
  "jest": "^29.0.2",
56
- "jsdoc": "^3.6.11",
54
+ "jsdoc": "^4.0.0",
57
55
  "mocha": "^10.0.0",
58
56
  "nock": "^13.2.9",
59
57
  "nyc": "^15.1.0",
package/src/error.js CHANGED
@@ -1,3 +1,4 @@
1
+ /* istanbul ignore file */
1
2
  class WasmError extends Error {
2
3
  constructor(message) {
3
4
  super(message);
package/src/logger.js CHANGED
@@ -1,3 +1,3 @@
1
1
  const pino = require("pino");
2
2
 
3
- module.exports = pino({});
3
+ module.exports = pino({ level: process.env.LOG_LEVEL || 'info' });
package/src/node.js CHANGED
@@ -24,13 +24,14 @@ class Spark {
24
24
  this._registry = undefined;
25
25
 
26
26
  if (apmInstance) {
27
- this.apm = apmInstance
27
+ this.apm = apmInstance;
28
28
  }
29
29
 
30
30
  /**
31
- * @private
32
- */
33
- this.instanceid = option && option.instanceid ? option.instanceid : uuidv4()
31
+ * @private
32
+ */
33
+ this.instanceid =
34
+ option && option.instanceid ? option.instanceid : uuidv4();
34
35
 
35
36
  /**
36
37
  * @private
@@ -82,7 +83,7 @@ class Spark {
82
83
  /**
83
84
  * @private
84
85
  */
85
- this.priority = ["model", "onlineEndpoint"];
86
+ this.priority = ["offlineModel", "onlineEndpoint"];
86
87
  }
87
88
 
88
89
  /**
@@ -91,7 +92,9 @@ class Spark {
91
92
  * @returns {object}
92
93
  */
93
94
  _models(nodegen) {
94
- const models = nodegen.map((n, i) => processModels(n, i, undefined, this.instanceid));
95
+ const models = nodegen.map((n, i) =>
96
+ processModels(n, i, undefined, this.instanceid)
97
+ );
95
98
  return models;
96
99
  }
97
100
 
@@ -115,6 +118,17 @@ class Spark {
115
118
  }
116
119
  }
117
120
 
121
+ _isPriorityEnable(priority) {
122
+ switch (priority) {
123
+ case "offlineModel":
124
+ return this.model.length > 0;
125
+ case "onlineEndpoint":
126
+ return this.config?.sparkEndpoint !== undefined;
127
+ default:
128
+ return false;
129
+ }
130
+ }
131
+
118
132
  /**
119
133
  * Execute model
120
134
  *
@@ -129,15 +143,32 @@ class Spark {
129
143
  input.request_meta.version_uuid;
130
144
 
131
145
  let lookup = {
132
- model: this.offlineModel.bind(this),
146
+ offlineModel: this.offlineModel.bind(this),
133
147
  onlineEndpoint: this.onlineModelEndpoint.bind(this),
134
148
  };
135
149
 
136
150
  let response;
151
+ let error;
137
152
 
138
- response = await lookup[this.priority[0]](input, versionID);
139
- if (response instanceof Error && this.config.sparkEndpoint !== undefined && false) {
140
- response = await lookup[this.priority[1]](input, versionID);
153
+ for (let i = 0; i < this.priority.length; i++) {
154
+ try {
155
+ const priority = this.priority[i];
156
+ if (this._isPriorityEnable(priority)) {
157
+ response = await lookup[priority](input, versionID);
158
+ break;
159
+ }
160
+ } catch (err) {
161
+ logger.info({
162
+ EventType: "ExecuteModel.ERROR",
163
+ InstanceId: this.instanceid,
164
+ TextMessage: `Error while executing uuid: ${versionID} using priority:${this.priority[i]}`,
165
+ });
166
+ error = err;
167
+ }
168
+ }
169
+
170
+ if (!response && error !== undefined) {
171
+ throw error;
141
172
  }
142
173
 
143
174
  return response;
@@ -164,7 +195,6 @@ class Spark {
164
195
  return require.resolve(filePath);
165
196
  }
166
197
 
167
-
168
198
  let template = fs.readFileSync(
169
199
  require.resolve("./resolver/externalResolver.js"),
170
200
  {
@@ -172,53 +202,51 @@ class Spark {
172
202
  }
173
203
  );
174
204
 
175
-
176
-
177
- template = template.replace(
178
- "%%config_to_replace%%",
179
- configPath
180
- ).replace(
181
- "%%instanceid%%",
182
- this.instanceid
183
- );
205
+ template = template
206
+ .replace("%%config_to_replace%%", configPath)
207
+ .replace("%%instanceid%%", this.instanceid);
184
208
 
185
209
  fs.writeFileSync(filePath, template);
186
210
  if (!this.isSerializedConfig) {
187
- const config = { ...this.config }
211
+ const config = { ...this.config };
188
212
 
189
213
  if (config.nodeGenModels) {
190
- config.nodeGenModels.forEach(m => {
214
+ config.nodeGenModels.forEach((m) => {
191
215
  if (m.binary) {
192
216
  const filePath = path.join(
193
217
  __dirname,
194
- `resolver_temp/${this.instanceid}_model_${m.versionId || m.VersionId || uuidv4()}.binary`
218
+ `resolver_temp/${this.instanceid}_model_${
219
+ m.versionId || m.VersionId || uuidv4()
220
+ }.binary`
195
221
  );
196
222
 
197
- fs.writeFileSync(filePath, Buffer.from(m.binary, 'base64'));
223
+ fs.writeFileSync(filePath, Buffer.from(m.binary, "base64"));
198
224
  m.binaryPath = filePath;
199
225
  m.binary = undefined;
200
226
  }
201
227
  });
202
228
  }
203
229
  const data = serializeObject.serialize(config);
204
- fs.writeFileSync(configPath, Buffer.from(data))
230
+ fs.writeFileSync(configPath, Buffer.from(data));
205
231
  }
206
232
 
207
- process.once('SIGINT', () => {
233
+ process.once("SIGINT", () => {
208
234
  try {
209
- fs.rmSync(path.join(
210
- __dirname,
211
- `resolver_temp`), { recursive: true, force: true });
235
+ fs.rmSync(path.join(__dirname, `resolver_temp`), {
236
+ recursive: true,
237
+ force: true,
238
+ });
212
239
  } catch (err) {
213
240
  // Just ignore
214
241
  }
215
242
  });
216
243
 
217
- process.once('exit', () => {
244
+ process.once("exit", () => {
218
245
  try {
219
- fs.rmSync(path.join(
220
- __dirname,
221
- `resolver_temp`), { recursive: true, force: true });
246
+ fs.rmSync(path.join(__dirname, `resolver_temp`), {
247
+ recursive: true,
248
+ force: true,
249
+ });
222
250
  } catch (err) {
223
251
  // Just ignore
224
252
  }
@@ -234,7 +262,9 @@ class Spark {
234
262
  m?.metaData?.EngineInformation?.ServiceName === serviceName
235
263
  );
236
264
  if (!model) {
237
- throw new WasmRunnerErrors.MissingModelError(`folder ${folderName} service ${serviceName}`);
265
+ throw new WasmRunnerErrors.MissingModelError(
266
+ `folder ${folderName} service ${serviceName}`
267
+ );
238
268
  }
239
269
  return model?.metaData?.VersionId || model?.versionId;
240
270
  }
@@ -273,7 +303,7 @@ class Spark {
273
303
  url: model?.binary || model?.binaryPath || "",
274
304
  });
275
305
  }
276
-
306
+
277
307
  let result = await this._registry.execute(input, versionId);
278
308
 
279
309
  return result;
@@ -283,7 +313,7 @@ class Spark {
283
313
  InstanceId: this.instanceid,
284
314
  TextMessage: err.message,
285
315
  });
286
- return err;
316
+ throw err;
287
317
  }
288
318
  }
289
319
 
@@ -1,6 +1,6 @@
1
1
  // const tenant = "%%tenant_to_replace%%";
2
- const Spark = require('../node')
3
- const logger = require('../logger')
2
+ const Spark = require("../node");
3
+ const logger = require("../logger");
4
4
 
5
5
  const CALL_TYPE = {
6
6
  0: "SparkService",
@@ -40,14 +40,16 @@ const XcallResBuilder = {
40
40
  },
41
41
  };
42
42
 
43
- let instance
43
+ let instance;
44
44
 
45
45
  const sparkServiceVersionOne = async (requestData, context) => {
46
46
  const headers = context.headers;
47
47
  const folderName = requestData.folder_name;
48
48
  const serviceName = requestData.service_name;
49
49
  const upstreamVersionId = context.upstreamVersionId;
50
- let requestBodyFromEngine
50
+
51
+ let requestBodyFromEngine;
52
+
51
53
  try {
52
54
  requestBodyFromEngine = JSON.parse(requestData.request_body);
53
55
  } catch (err) {
@@ -57,32 +59,59 @@ const sparkServiceVersionOne = async (requestData, context) => {
57
59
  // });
58
60
  // throw new error(`Downstream Request body is malform JSON ${requestData.request_body}`)
59
61
  }
60
- const options = {}
62
+
63
+ const options = {};
61
64
 
62
65
  if (!instance) {
63
- instance = new Spark({}, { serialize: true, configPath: "%%config_to_replace%%", instanceid: "%%instanceid%%" })
66
+ instance = new Spark(
67
+ {},
68
+ {
69
+ serialize: true,
70
+ configPath: "%%config_to_replace%%",
71
+ instanceid: "%%instanceid%%",
72
+ }
73
+ );
64
74
  }
75
+ try {
76
+ const modelId = instance._getModelByMeta(folderName, serviceName);
77
+
78
+ if (!requestBodyFromEngine?.request_meta) {
79
+ requestBodyFromEngine.request_meta = {};
80
+ }
81
+ requestBodyFromEngine.request_meta.version_id = modelId;
82
+ const results = await instance.execute(requestBodyFromEngine, modelId);
83
+ const response = XcallResBuilder.Json(
84
+ CALL_TYPE[0],
85
+ serviceName,
86
+ 202,
87
+ "",
88
+ 0,
89
+ results
90
+ );
91
+ return response;
92
+ } catch (err) {
93
+ const response = XcallResBuilder.Json(
94
+ CALL_TYPE[0],
95
+ serviceName,
96
+ err.StatusCode
97
+ ? err.StatusCode
98
+ : err.response
99
+ ? err.response.status
100
+ : 500,
101
+ err.errorCode ? err.errorCode : err.code ? err.code : err.name,
102
+ err.response && err.response.timings
103
+ ? err.response.timings.end - err.response.timings.start
104
+ : 0,
105
+ {}
106
+ );
65
107
 
66
- const modelId = instance._getModelByMeta(folderName, serviceName)
67
- if (!requestBodyFromEngine?.request_meta) {
68
- requestBodyFromEngine.request_meta = {}
108
+ return response;
69
109
  }
70
- requestBodyFromEngine.request_meta.version_id = modelId
71
- const results = await instance.execute(requestBodyFromEngine, modelId)
72
- const response = XcallResBuilder.Json(
73
- CALL_TYPE[0],
74
- serviceName,
75
- 202,
76
- "",
77
- 0,
78
- results
79
- );
80
- return response;
81
- }
110
+ };
82
111
 
83
112
  module.exports = {
84
113
  sparkService: async (requestData, context) => {
85
- const results = await sparkServiceVersionOne(requestData, context)
86
- return results
87
- }
88
- };
114
+ const results = await sparkServiceVersionOne(requestData, context);
115
+ return results;
116
+ },
117
+ };
@@ -28,7 +28,7 @@ const request = got.extend({
28
28
  extendError = "MODEL_NOT_FOUND";
29
29
  }
30
30
 
31
- logger.info({
31
+ logger.error({
32
32
  EventType: "EntityStoreError",
33
33
  TextMessage: `EntityStoreError: ${JSON.stringify(response.body)}`,
34
34
  });
@@ -81,7 +81,8 @@ const getDocumentByVersionId = async (versionUuid, token) => {
81
81
  ).toString();
82
82
  logger.info({
83
83
  EventType: "GetVersionID",
84
- TextMessage: `getDocumentByVersionId , ${url}`,
84
+ TextMessage: `getDocumentByVersionId`,
85
+ url
85
86
  });
86
87
  const options = {
87
88
  headers: {
@@ -104,7 +105,8 @@ const getParameterSetById = async (versionUuid, token, tenant = "coherent") => {
104
105
  ).toString();
105
106
  logger.info({
106
107
  EventType: "ParameterSet",
107
- TextMessage: `getParameterSetById , ${url}`,
108
+ TextMessage: `getParameterSetById`,
109
+ url
108
110
  });
109
111
  const options = {
110
112
  headers: {
@@ -140,7 +142,9 @@ const downloadModelFile = async (url, versionUuid, headers) => {
140
142
 
141
143
  logger.info({
142
144
  EventType: "DownloadModelFile",
143
- TextMessage: `downloadModelFile url:${url}, versionUuid:${versionUuid}`,
145
+ TextMessage: `downloadModelFile`,
146
+ url,
147
+ versionUuid
144
148
  });
145
149
  const tmpWasm = tmp.fileSync({
146
150
  dir: TMP_DIR,
@@ -151,7 +155,9 @@ const downloadModelFile = async (url, versionUuid, headers) => {
151
155
  wasmDestination.write(getWasmDocument);
152
156
  logger.info({
153
157
  EventType: "DownloadComplete",
154
- TextMessage: `downloadModelFile complete url:${url}, versionUuid:${versionUuid}`,
158
+ TextMessage: `downloadModelFile complete`,
159
+ versionUuid,
160
+ url
155
161
  });
156
162
  return tmpWasm.name;
157
163
  };
@@ -164,7 +170,9 @@ const downloadJSON = async (url, versionUuid, headers) => {
164
170
  if (!fs.existsSync(filePath)) {
165
171
  logger.info({
166
172
  EventType: "DownloadJson",
167
- TextMessage: `downloadJSON url:${url}, versionUuid:${versionUuid}`,
173
+ TextMessage: `downloadJSON`,
174
+ versionUuid,
175
+ url
168
176
  });
169
177
  const tmpWasm = tmp.fileSync({
170
178
  dir: TMP_DIR,
@@ -174,7 +182,9 @@ const downloadJSON = async (url, versionUuid, headers) => {
174
182
  wasmDestination.write(getDocument);
175
183
  logger.info({
176
184
  EventType: "JsonDownloaded",
177
- TextMessage: `downloadJSON complete url:${url}, versionUuid:${versionUuid}`,
185
+ TextMessage: `downloadJSON complete`,
186
+ versionUuid,
187
+ url
178
188
  });
179
189
  }
180
190
 
@@ -194,7 +204,8 @@ const downloadModel = async (versionUuid, token) => {
194
204
  const modelFile = await downloadModelFile(downloadUrl, versionUuid);
195
205
  logger.info({
196
206
  EventType: "ModelDownloaded",
197
- TextMessage: `downloadModel complete versionUuid:${versionUuid}`,
207
+ TextMessage: `downloadModel complete`,
208
+ versionUuid
198
209
  });
199
210
  return modelFile;
200
211
  };
@@ -241,10 +252,10 @@ const getModelViaFolder = async (folder, model, headers) => {
241
252
  const output = await request.get(folderSparkUrl, options);
242
253
  const body = output.body ? JSON.parse(output.body) : {}
243
254
  let response = ""
244
- if(body) {
255
+ if (body) {
245
256
  const documents = body.data.documents
246
- const findModelFromDocuments = documents.find( name => name.name === `${model}.c1engine`)
247
- if(findModelFromDocuments) response = findModelFromDocuments.latestVersionId
257
+ const findModelFromDocuments = documents.find(name => name.name === `${model}.c1engine`)
258
+ if (findModelFromDocuments) response = findModelFromDocuments.latestVersionId
248
259
  }
249
260
  return response
250
261
  }
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.js"],"names":[],"mappings":"AAoDA;IAII,UAAgB;CAInB;AArCD;IAII,aAAiC;IACjC,iBAAqB;CAExB;AAED;IACE,qDAOC;IAFC,aAAgB;IAChB,UAAkB;CAErB;AAqBD;IACE,uCAKC;IAHC,YAA2B;IAE3B,aAAgC;CAEnC;AAED;IACE,uCAKC;IAHC,YAA2B;IAE3B,aAAqC;CAExC;AAnCD;IAII,aAA+B;IAC/B,iBAAqB;CAExB;AAlDD;IACE,0BAGC;IADC,eAAiB;IAGnB;;;;;MAOC;IAED;;;MAKC;CACF"}
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.js"],"names":[],"mappings":"AAqDA;IAII,UAAgB;CAInB;AArCD;IAII,aAAiC;IACjC,iBAAqB;CAExB;AAED;IACE,qDAOC;IAFC,aAAgB;IAChB,UAAkB;CAErB;AAqBD;IACE,uCAKC;IAHC,YAA2B;IAE3B,aAAgC;CAEnC;AAED;IACE,uCAKC;IAHC,YAA2B;IAE3B,aAAqC;CAExC;AAnCD;IAII,aAA+B;IAC/B,iBAAqB;CAExB;AAlDD;IACE,0BAGC;IADC,eAAiB;IAGnB;;;;;MAOC;IAED;;;MAKC;CACF"}
package/types/node.d.ts CHANGED
@@ -10,8 +10,8 @@ declare class Spark {
10
10
  private _registry;
11
11
  apm: any;
12
12
  /**
13
- * @private
14
- */
13
+ * @private
14
+ */
15
15
  private instanceid;
16
16
  config: object;
17
17
  /**
@@ -58,6 +58,7 @@ declare class Spark {
58
58
  * @returns {object}
59
59
  */
60
60
  validateConfig(config: object): object;
61
+ _isPriorityEnable(priority: any): boolean;
61
62
  /**
62
63
  * Execute model
63
64
  *
@@ -72,7 +73,7 @@ declare class Spark {
72
73
  /**
73
74
  * Remove Model
74
75
  */
75
- offlineModel(input: any, versionID: any): Promise<unknown>;
76
+ offlineModel(input: any, versionID: any): Promise<import("@coherentglobal/wasm-runner/dist/types.js").ResponseObject>;
76
77
  onlineModelEndpoint(input: any, versionID: any): Promise<any>;
77
78
  }
78
79
  //# sourceMappingURL=node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.js"],"names":[],"mappings":";AAeA;IACE;;OAEG;IACH,oBAFW,MAAM,+CAoEhB;IAjEC;;OAEG;IACH,kBAA0B;IAGxB,SAAsB;IAGxB;;MAEE;IACF,mBAA4E;IAU1E,eAAsB;IAMxB;;OAEG;IACH,eAAsD;IACtD;;OAEG;IACH,iBAA0D;IAC1D;;OAEG;IACH,cAGI;IACJ;;OAEG;IACH,YAAgD;IAChD;;OAEG;IACH,qBAA2C;IAC3C;;OAEG;IACH,cAAqD;IAErD;;OAEG;IACH,yBAAmD;IAEnD;;OAEG;IACH,iBAA2C;IAG7C;;;;OAIG;IACH,iBAHW,MAAM,GACJ,MAAM,CAKlB;IAED;;;;OAIG;IACH,uBAHW,MAAM,GACJ,MAAM,CAelB;IAED;;;;;;OAMG;IACH,eAJW,MAAM,oCAEJ,MAAM,CAqBlB;IAED,+BAkFC;IAED,wDAUC;IAED,uBAKC;IAED;;OAEG;IAGH,2DAkCC;IAED,8DA6CC;CACF"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.js"],"names":[],"mappings":";AAeA;IACE;;OAEG;IACH,oBAFW,MAAM,+CAqEhB;IAlEC;;OAEG;IACH,kBAA0B;IAGxB,SAAsB;IAGxB;;OAEG;IACH,mBAC4D;IAU1D,eAAsB;IAMxB;;OAEG;IACH,eAAsD;IACtD;;OAEG;IACH,iBAA0D;IAC1D;;OAEG;IACH,cAGI;IACJ;;OAEG;IACH,YAAgD;IAChD;;OAEG;IACH,qBAA2C;IAC3C;;OAEG;IACH,cAAqD;IAErD;;OAEG;IACH,yBAAmD;IAEnD;;OAEG;IACH,iBAAkD;IAGpD;;;;OAIG;IACH,iBAHW,MAAM,GACJ,MAAM,CAOlB;IAED;;;;OAIG;IACH,uBAHW,MAAM,GACJ,MAAM,CAelB;IAED,0CASC;IAED;;;;;;OAMG;IACH,eAJW,MAAM,oCAEJ,MAAM,CAsClB;IAED,+BA+EC;IAED,wDAYC;IAED,uBAKC;IAED;;OAEG;IAGH,sHAkCC;IAED,8DA6CC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"externalResolver.d.ts","sourceRoot":"","sources":["../../src/resolver/externalResolver.js"],"names":[],"mappings":"AAmFgB,8EAGb"}
1
+ {"version":3,"file":"externalResolver.d.ts","sourceRoot":"","sources":["../../src/resolver/externalResolver.js"],"names":[],"mappings":"AAgHgB,8EAGb"}
@@ -1 +1 @@
1
- {"version":3,"file":"entityStore.d.ts","sourceRoot":"","sources":["../../src/services/entityStore.js"],"names":[],"mappings":"AAgEA;;;;;;;;;;GAUG;AACH,yFAoBC;AAtDD;;;;;;;;;;GAUG;AACH,2DAFa,MAAM,CAYlB;AA6DD;;;;;;;;;;;;;GAaG;AACH,gGAmBC;AAiCD,6EAUC;AAMD,yFAeC;AA3HD,iGAsBC;AAuGD;;;;;;GAMG;AACH,0FAoBC"}
1
+ {"version":3,"file":"entityStore.d.ts","sourceRoot":"","sources":["../../src/services/entityStore.js"],"names":[],"mappings":"AAgEA;;;;;;;;;;GAUG;AACH,yFAqBC;AAvDD;;;;;;;;;;GAUG;AACH,2DAFa,MAAM,CAYlB;AA+DD;;;;;;;;;;;;;GAaG;AACH,gGAuBC;AAqCD,6EAWC;AAMD,yFAeC;AArID,iGAuBC;AAgHD;;;;;;GAMG;AACH,0FAoBC"}