@ix-xs/node-comfort 1.0.56 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Utils.js ADDED
@@ -0,0 +1,325 @@
1
+ const logger = require("./Logger");
2
+
3
+ /**
4
+ * Miscellaneous async and process helpers.
5
+ */
6
+ module.exports = {
7
+ /**
8
+ * Waits for a given number of milliseconds.
9
+ *
10
+ * @example
11
+ * await nodeComfort.wait(500); // waits 500 ms
12
+ *
13
+ * @param {number} ms - Delay in milliseconds.
14
+ * @returns {Promise<void>} A promise that resolves after the delay.
15
+ */
16
+ wait(ms) {
17
+ return new Promise((resolve) => setTimeout(resolve, ms));
18
+ },
19
+
20
+ /**
21
+ * Polls a predicate at a given interval and emits events when it matches or times out.
22
+ *
23
+ * The predicate is evaluated every `options.interval` milliseconds (default: 50 ms).
24
+ * Be careful with the default interval: 50 ms is very frequent polling and can be
25
+ * unnecessarily CPU‑intensive if your predicate or trigger handlers are heavy.
26
+ * When `options.max` is `null`, the predicate can match indefinitely (infinite triggers),
27
+ * so you should choose an interval that makes sense for your use‑case.
28
+ *
29
+ * A `when(...)` task is one‑shot: once it has been stopped (manually or via `max`/`timeout`),
30
+ * calling `.start()` again on the same task will not restart it.
31
+ *
32
+ * @param {boolean|Promise<boolean>|(() => boolean|Promise<boolean>)} predicate
33
+ * Condition to evaluate at each tick, or a function returning it.
34
+ * @param {*} [payload={}]
35
+ * Value passed to listeners when events are emitted (e.g. an object or message).
36
+ * @param {object} [options]
37
+ * @param {number} [options.interval=50]
38
+ * Polling interval in milliseconds. Increase this value if your predicate is
39
+ * expensive or you expect many triggers without a `max` limit.
40
+ * @param {number|null} [options.timeout=null]
41
+ * Maximum time in milliseconds before emitting a "timeout" event and stopping.
42
+ * If `null`, no timeout is applied.
43
+ * @param {number|null} [options.max=null]
44
+ * Maximum number of successful predicate evaluations ("trigger" events) before
45
+ * automatically stopping. If `null`, triggers are infinite until `stop()` is called.
46
+ *
47
+ * @example
48
+ * // Basic usage: infinite triggers every 50 ms (default interval) – use with caution.
49
+ * const task = nodeComfort.when(() => true, { message: "Ok" });
50
+ *
51
+ * task
52
+ * .on("trigger", (payload) => {
53
+ * console.log(payload.message);
54
+ * // task.stop(); // stop when you’re done
55
+ * })
56
+ * .start();
57
+ *
58
+ * @example
59
+ * // Safer usage: limit triggers and/or lower polling frequency.
60
+ * nodeComfort.when(() => true, { message: "Ok" }, { max: 1, interval: 500 })
61
+ * .on("trigger", (payload) => {
62
+ * console.log(payload.message);
63
+ * })
64
+ * .on("timeout", (payload) => {
65
+ * console.log("Timed out", payload);
66
+ * })
67
+ * .start();
68
+ *
69
+ * @returns {{
70
+ * start: () => any,
71
+ * stop: () => any,
72
+ * on: <E extends "error"|"trigger"|"timeout">(event: E, handler: E extends "error"
73
+ * ? (error: unknown) => void|Promise<void>
74
+ * : (payload: any) => void|Promise<void>) => any
75
+ * }} A small task controller with `start`, `stop` and `on`.
76
+ */
77
+ when(predicate, payload = {}, options) {
78
+ const interval = options?.interval ?? 50;
79
+ const timeout = options?.timeout ?? null;
80
+ const max = options?.max ?? null;
81
+
82
+ /** @type {{ trigger: Set<Function>, error: Set<Function>, timeout: Set<Function> }} */
83
+ const listeners = {
84
+ trigger: new Set(),
85
+ error: new Set(),
86
+ timeout: new Set(),
87
+ };
88
+
89
+ let _timer = null;
90
+ let _timeoutTimer = null;
91
+ let _stopped = false;
92
+ let _count = 0;
93
+
94
+ /**
95
+ * Emits an event to all registered listeners.
96
+ * Errors in listeners are caught and ignored to avoid breaking the polling loop.
97
+ *
98
+ * @param {"trigger"|"error"|"timeout"} event
99
+ * @param {*} p
100
+ */
101
+ function emit(event, p) {
102
+ for (const fn of listeners[event]) {
103
+ try {
104
+ fn(p);
105
+ } catch {
106
+ // Best effort: we don't re-throw here to keep the task alive.
107
+ }
108
+ }
109
+ }
110
+
111
+ async function evalPredicate() {
112
+ if (typeof predicate === "function") {
113
+ return await predicate();
114
+ }
115
+ return Boolean(await predicate);
116
+ }
117
+
118
+ async function tick() {
119
+ if (_stopped) return;
120
+
121
+ try {
122
+ const ok = await evalPredicate();
123
+
124
+ if (ok) {
125
+ _count++;
126
+ emit("trigger", payload);
127
+
128
+ if (max != null && _count >= max) {
129
+ _stopInternal();
130
+ return;
131
+ }
132
+ }
133
+
134
+ if (!_stopped) {
135
+ _timer = setTimeout(tick, interval);
136
+ }
137
+ } catch (error) {
138
+ emit("error", error);
139
+ if (!_stopped) {
140
+ _timer = setTimeout(tick, interval);
141
+ }
142
+ }
143
+ }
144
+
145
+ function _stopInternal() {
146
+ _stopped = true;
147
+ if (_timer) {
148
+ clearTimeout(_timer);
149
+ _timer = null;
150
+ }
151
+ if (_timeoutTimer) {
152
+ clearTimeout(_timeoutTimer);
153
+ _timeoutTimer = null;
154
+ }
155
+ }
156
+
157
+ const controller = {
158
+ /**
159
+ * Starts the polling task (one-shot: no effect if it was already stopped).
160
+ * @returns {typeof controller}
161
+ */
162
+ start() {
163
+ if (_stopped) return controller;
164
+
165
+ if (!_timer) {
166
+ _timer = setTimeout(tick, 0);
167
+ }
168
+
169
+ if (timeout != null && !_timeoutTimer) {
170
+ _timeoutTimer = setTimeout(() => {
171
+ if (_stopped) return;
172
+ emit("timeout", payload);
173
+ _stopInternal();
174
+ }, timeout);
175
+ }
176
+
177
+ return controller;
178
+ },
179
+ /**
180
+ * Stops the polling task and clears all timers.
181
+ * @returns {typeof controller}
182
+ */
183
+ stop() {
184
+ _stopInternal();
185
+ return controller;
186
+ },
187
+ /**
188
+ * Registers an event handler.
189
+ *
190
+ * @typedef { "error" | "trigger" | "timeout" } EventNames
191
+ * @typedef {{
192
+ * error: (error: unknown) => void|Promise<void>,
193
+ * trigger: (payload: any) => void|Promise<void>,
194
+ * timeout: (payload: any) => void|Promise<void>,
195
+ * }} EventHandlers
196
+ *
197
+ * @template {EventNames} E
198
+ * @param {E} event - Event name.
199
+ * @param {EventHandlers[E]} handler - Handler function.
200
+ * @returns {typeof controller}
201
+ */
202
+ on(event, handler) {
203
+ listeners[event]?.add(handler);
204
+ return controller;
205
+ },
206
+ };
207
+
208
+ return controller;
209
+ },
210
+
211
+ /**
212
+ * Installs process-level safety nets for errors, exits and signals.
213
+ *
214
+ * By default, it:
215
+ * - logs uncaught exceptions and unhandled rejections,
216
+ * - logs process exit codes,
217
+ * - logs SIGINT/SIGTERM/SIGQUIT and exits with code 0.
218
+ *
219
+ * You can override each handler with `.on(event, handler)`.
220
+ *
221
+ * @example
222
+ * // Use defaults:
223
+ * nodeComfort.dontCrash();
224
+ *
225
+ * @example
226
+ * // Custom error handler:
227
+ * nodeComfort.dontCrash().on("error", (err) => {
228
+ * console.error("Global error:", err);
229
+ * process.exit(1);
230
+ * });
231
+ *
232
+ * @returns {{
233
+ * on: <E extends "error"|"exit"|"sig"|"beforeExit">(event: E, handler?: (
234
+ * E extends "error" ? (error: Error|unknown) => void|Promise<void> :
235
+ * E extends "exit" ? (code: number) => void|Promise<void> :
236
+ * E extends "sig" ? (signal: "SIGINT"|"SIGTERM"|"SIGQUIT") => void|Promise<void> :
237
+ * (code: number) => void|Promise<void>
238
+ * )) => any
239
+ * }} A small controller to configure global handlers.
240
+ */
241
+ dontCrash() {
242
+ const defaults = {
243
+ error: (error) => {
244
+ logger.log(
245
+ `<% red [@ix-xs/node-comfort] Process Error %>\n<% gray ${error.stack ?? error} %>`,
246
+ );
247
+ },
248
+ exit: (code) => {
249
+ logger.log(
250
+ `<% yellow [@ix-xs/node-comfort] Process Exit %>\n→ Code: <% gray ${code} %>`,
251
+ );
252
+ },
253
+ sig: (signal) => {
254
+ logger.log(
255
+ `<% yellow [@ix-xs/node-comfort] Process SIG* %>\n→ Signal: <% gray ${signal} %>`,
256
+ );
257
+ process.exit(0);
258
+ },
259
+ beforeExit: (code) => {},
260
+ };
261
+
262
+ const controller = {
263
+ /**
264
+ * Registers global process handlers.
265
+ *
266
+ * @template { "error" | "exit" | "sig" | "beforeExit" } E
267
+ * @param {E} event - Event name.
268
+ * @param {{
269
+ * error: (error: Error | unknown) => void | Promise<void>,
270
+ * exit: (code: number) => void | Promise<void>,
271
+ * sig: (signal: "SIGINT" | "SIGTERM" | "SIGQUIT") => void | Promise<void>,
272
+ * beforeExit: (code: number) => void|Promise<void>
273
+ * }[E]} [handler] - Custom handler, or use the default when omitted.
274
+ * @returns {typeof controller}
275
+ */
276
+ on(event, handler) {
277
+ if (event === "error") {
278
+ process.removeAllListeners("uncaughtException");
279
+ process.removeAllListeners("unhandledRejection");
280
+ const fn = handler ?? defaults.error;
281
+ process.on("uncaughtException", fn);
282
+ process.on("unhandledRejection", fn);
283
+ } else if (event === "exit") {
284
+ process.removeAllListeners("exit");
285
+ process.on("exit", handler ?? defaults.exit);
286
+ } else if (event === "sig") {
287
+ for (const signal of ["SIGINT", "SIGTERM", "SIGQUIT"]) {
288
+ process.removeAllListeners(signal);
289
+ process.on(signal, handler ?? defaults.sig);
290
+ }
291
+ } else if (event === "beforeExit") {
292
+ process.removeAllListeners("beforeExit");
293
+ process.on("beforeExit", handler ?? defaults.beforeExit);
294
+ }
295
+
296
+ return controller;
297
+ },
298
+ };
299
+
300
+ // Install default handlers for error, exit, sig
301
+ controller.on("error").on("exit").on("sig");
302
+
303
+ return controller;
304
+ },
305
+
306
+ /**
307
+ * Safely stringifies a value to pretty-printed JSON (4 spaces indent).
308
+ *
309
+ * @param {*} value - Value to stringify.
310
+ * @returns {string} JSON string representation.
311
+ */
312
+ JSONString(value) {
313
+ return JSON.stringify(value, null, 4);
314
+ },
315
+
316
+ /**
317
+ * Parses a JSON string.
318
+ *
319
+ * @param {string} value - JSON string to parse.
320
+ * @returns {*} Parsed value.
321
+ */
322
+ JSONParse(value) {
323
+ return JSON.parse(value);
324
+ },
325
+ };
@@ -0,0 +1,120 @@
1
+ declare const _exports: {
2
+ SQLite: {
3
+ new (path?: string): SQLite;
4
+ };
5
+ wait(ms: number): Promise<void>;
6
+ when(predicate: boolean | Promise<boolean> | (() => boolean | Promise<boolean>), payload?: any, options?: {
7
+ interval?: number | undefined;
8
+ timeout?: number | null | undefined;
9
+ max?: number | null | undefined;
10
+ }): {
11
+ start: () => any;
12
+ stop: () => any;
13
+ on: <E extends "error" | "trigger" | "timeout">(event: E, handler: E extends "error" ? (error: unknown) => void | Promise<void> : (payload: any) => void | Promise<void>) => any;
14
+ };
15
+ dontCrash(): {
16
+ on: <E extends "error" | "exit" | "sig" | "beforeExit">(event: E, handler?: (E extends "error" ? (error: Error | unknown) => void | Promise<void> : E extends "exit" ? (code: number) => void | Promise<void> : E extends "sig" ? (signal: "SIGINT" | "SIGTERM" | "SIGQUIT") => void | Promise<void> : (code: number) => void | Promise<void>)) => any;
17
+ };
18
+ JSONString(value: any): string;
19
+ JSONParse(value: string): any;
20
+ isArray(value: any): boolean;
21
+ isNumber(value: any): boolean;
22
+ isFunction(value: any): boolean;
23
+ isObject(value: any): boolean;
24
+ isBoolean(value: any): boolean;
25
+ isString(value: any): boolean;
26
+ isUndefined(value: any): boolean;
27
+ isNull(value: any): boolean;
28
+ isDate(value: any): boolean;
29
+ isMap(value: any): boolean;
30
+ isSet(value: any): boolean;
31
+ isError(value: any): boolean;
32
+ getEnv(value: string, envFilePath?: string): string | undefined;
33
+ createPath(path?: string): string;
34
+ getFoldersIn(path?: string, recursive?: boolean): string[] | undefined;
35
+ getFolder(path?: string): string | undefined;
36
+ getFilesIn(path?: string, recursive?: boolean): string[] | undefined;
37
+ getFile(path: string): string | undefined;
38
+ createFolder(path: string, force?: boolean): boolean | undefined;
39
+ createFile(path: string, force?: boolean, data?: string | object | null | undefined): boolean | undefined;
40
+ deleteFoldersIn(path?: string, filter?: (folder: string) => boolean): number | undefined;
41
+ deleteFolder(path: string): boolean | undefined;
42
+ deleteFilesIn(path?: string, recursive?: boolean, filter?: (file: string) => boolean): number | undefined;
43
+ deleteFile(path: string): boolean | undefined;
44
+ copyFoldersIn(options: {
45
+ dest: string;
46
+ path?: string | undefined;
47
+ recursive?: boolean | undefined;
48
+ withFiles?: boolean | undefined;
49
+ force?: boolean | undefined;
50
+ filter?: ((folder: string) => boolean) | undefined;
51
+ }): number | undefined;
52
+ copyFolder(options: {
53
+ dest: string;
54
+ path?: string | undefined;
55
+ recursive?: boolean | undefined;
56
+ withFiles?: boolean | undefined;
57
+ force?: boolean | undefined;
58
+ }): boolean | undefined;
59
+ copyFilesIn(options: {
60
+ dest: string;
61
+ path?: string | undefined;
62
+ recursive?: boolean | undefined;
63
+ force?: boolean | undefined;
64
+ filter?: ((file: string) => boolean) | undefined;
65
+ }): number | undefined;
66
+ copyFile(options: {
67
+ path: string;
68
+ dest: string;
69
+ force?: boolean | undefined;
70
+ }): boolean | undefined;
71
+ moveFoldersIn(options: {
72
+ dest: string;
73
+ path?: string | undefined;
74
+ recursive?: boolean | undefined;
75
+ withFiles?: boolean | undefined;
76
+ force?: boolean | undefined;
77
+ filter?: ((folder: string) => boolean) | undefined;
78
+ }): number | undefined;
79
+ moveFolder(options: {
80
+ path: string;
81
+ dest: string;
82
+ recursive?: boolean | undefined;
83
+ withFiles?: boolean | undefined;
84
+ force?: boolean | undefined;
85
+ }): boolean | undefined;
86
+ moveFilesIn(options: {
87
+ dest: string;
88
+ path?: string | undefined;
89
+ recursive?: boolean | undefined;
90
+ force?: boolean | undefined;
91
+ filter?: ((file: string) => boolean) | undefined;
92
+ }): number | undefined;
93
+ moveFile(options: {
94
+ path: string;
95
+ dest: string;
96
+ force?: boolean | undefined;
97
+ }): boolean | undefined;
98
+ readFile(path: string): string | undefined;
99
+ watch(options?: {
100
+ path?: string | undefined;
101
+ recursive?: boolean | undefined;
102
+ filter?: ((event: "rename" | "change", file: string) => boolean) | undefined;
103
+ }): {
104
+ on: <E extends "change" | "rename" | "all">(event: E, callback: E extends "all" ? (event: "change" | "rename", file: string) => void | Promise<void> : (file: string) => void | Promise<void>) => any;
105
+ stop: () => void;
106
+ pause: () => any;
107
+ resume: () => any;
108
+ } | undefined;
109
+ setTimestamp(value: boolean): Logger;
110
+ setDelimiter(options?: {
111
+ open?: string | undefined;
112
+ close?: string | undefined;
113
+ }): Logger;
114
+ log(content: any): Logger;
115
+ group(label: string): Logger;
116
+ groupEnd(): Logger;
117
+ };
118
+ export = _exports;
119
+ import SQLite = require("./src/SQLite");
120
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;iFAYi3N,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAAn0C,MAAM;;;;QAAuZ,MAAM;uBAAiX,MAAM;0BAAq/B,MAAM;gBAA0T,MAAM"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Checks if a value is a real Array.
3
+ *
4
+ * @example
5
+ * nodeComfort.Checker.isArray([1, 2, 3]); // true
6
+ * nodeComfort.Checker.isArray("not array"); // false
7
+ *
8
+ * @param {*} value - Value to check.
9
+ * @returns {boolean} True if the value is an Array.
10
+ */
11
+ export function isArray(value: any): boolean;
12
+ /**
13
+ * Checks if a value is a number (excluding NaN).
14
+ *
15
+ * @example
16
+ * nodeComfort.Checker.isNumber(42); // true
17
+ * nodeComfort.Checker.isNumber(NaN); // false
18
+ * nodeComfort.Checker.isNumber("42"); // false
19
+ *
20
+ * @param {*} value - Value to check.
21
+ * @returns {boolean} True if the value is a finite number or Infinity/-Infinity.
22
+ */
23
+ export function isNumber(value: any): boolean;
24
+ /**
25
+ * Checks if a value is a function.
26
+ *
27
+ * @example
28
+ * nodeComfort.Checker.isFunction(() => {}); // true
29
+ * nodeComfort.Checker.isFunction(class {}); // true
30
+ * nodeComfort.Checker.isFunction("fn"); // false
31
+ *
32
+ * @param {*} value - Value to check.
33
+ * @returns {boolean} True if the value is a function.
34
+ */
35
+ export function isFunction(value: any): boolean;
36
+ /**
37
+ * Checks if a value is a non-null object.
38
+ *
39
+ * Note: Arrays, Maps, Sets, Dates, etc. are also considered objects here.
40
+ *
41
+ * @example
42
+ * nodeComfort.Checker.isObject({}); // true
43
+ * nodeComfort.Checker.isObject([]); // true
44
+ * nodeComfort.Checker.isObject(null); // false
45
+ * nodeComfort.Checker.isObject("str"); // false
46
+ *
47
+ * @param {*} value - Value to check.
48
+ * @returns {boolean} True if the value is a non-null object.
49
+ */
50
+ export function isObject(value: any): boolean;
51
+ /**
52
+ * Checks if a value is a boolean.
53
+ *
54
+ * @example
55
+ * nodeComfort.Checker.isBoolean(true); // true
56
+ * nodeComfort.Checker.isBoolean(false); // true
57
+ * nodeComfort.Checker.isBoolean(0); // false
58
+ *
59
+ * @param {*} value - Value to check.
60
+ * @returns {boolean} True if the value is a boolean.
61
+ */
62
+ export function isBoolean(value: any): boolean;
63
+ /**
64
+ * Checks if a value is a string.
65
+ *
66
+ * @example
67
+ * nodeComfort.Checker.isString("hello"); // true
68
+ * nodeComfort.Checker.isString(123); // false
69
+ *
70
+ * @param {*} value - Value to check.
71
+ * @returns {boolean} True if the value is a string.
72
+ */
73
+ export function isString(value: any): boolean;
74
+ /**
75
+ * Checks if a value is exactly undefined.
76
+ *
77
+ * @example
78
+ * nodeComfort.Checker.isUndefined(undefined); // true
79
+ * nodeComfort.Checker.isUndefined(null); // false
80
+ *
81
+ * @param {*} value - Value to check.
82
+ * @returns {boolean} True if the value is undefined.
83
+ */
84
+ export function isUndefined(value: any): boolean;
85
+ /**
86
+ * Checks if a value is exactly null.
87
+ *
88
+ * @example
89
+ * nodeComfort.Checker.isNull(null); // true
90
+ * nodeComfort.Checker.isNull(undefined); // false
91
+ *
92
+ * @param {*} value - Value to check.
93
+ * @returns {boolean} True if the value is null.
94
+ */
95
+ export function isNull(value: any): boolean;
96
+ /**
97
+ * Checks if a value is a built-in Date instance.
98
+ *
99
+ * Uses `util.types.isDate` under the hood to handle cross-realm Dates.
100
+ *
101
+ * @example
102
+ * nodeComfort.Checker.isDate(new Date()); // true
103
+ * nodeComfort.Checker.isDate("2024-01-01"); // false
104
+ *
105
+ * @param {*} value - Value to check.
106
+ * @returns {boolean} True if the value is a Date instance.
107
+ */
108
+ export function isDate(value: any): boolean;
109
+ /**
110
+ * Checks if a value is a built-in Map instance.
111
+ *
112
+ * @example
113
+ * nodeComfort.Checker.isMap(new Map()); // true
114
+ * nodeComfort.Checker.isMap({}); // false
115
+ *
116
+ * @param {*} value - Value to check.
117
+ * @returns {boolean} True if the value is a Map.
118
+ */
119
+ export function isMap(value: any): boolean;
120
+ /**
121
+ * Checks if a value is a built-in Set instance.
122
+ *
123
+ * @example
124
+ * nodeComfort.Checker.isSet(new Set()); // true
125
+ * nodeComfort.Checker.isSet([]); // false
126
+ *
127
+ * @param {*} value - Value to check.
128
+ * @returns {boolean} True if the value is a Set.
129
+ */
130
+ export function isSet(value: any): boolean;
131
+ /**
132
+ * Checks if a value is a native Error instance.
133
+ *
134
+ * Uses `util.types.isNativeError` to correctly handle errors from other realms.
135
+ *
136
+ * @example
137
+ * nodeComfort.Checker.isError(new Error("x")); // true
138
+ * nodeComfort.Checker.isError(new TypeError("x")); // true
139
+ * nodeComfort.Checker.isError({ message: "x" }); // false
140
+ *
141
+ * @param {*} value - Value to check.
142
+ * @returns {boolean} True if the value is a native Error.
143
+ */
144
+ export function isError(value: any): boolean;
145
+ //# sourceMappingURL=Checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Checker.d.ts","sourceRoot":"","sources":["../../src/Checker.js"],"names":[],"mappings":"AAQE;;;;;;;;;GASG;AACH,+BAHW,GAAC,GACC,OAAO,CAInB;AAED;;;;;;;;;;GAUG;AACH,gCAHW,GAAC,GACC,OAAO,CAInB;AAED;;;;;;;;;;GAUG;AACH,kCAHW,GAAC,GACC,OAAO,CAInB;AAED;;;;;;;;;;;;;GAaG;AACH,gCAHW,GAAC,GACC,OAAO,CAInB;AAED;;;;;;;;;;GAUG;AACH,iCAHW,GAAC,GACC,OAAO,CAInB;AAED;;;;;;;;;GASG;AACH,gCAHW,GAAC,GACC,OAAO,CAInB;AAED;;;;;;;;;GASG;AACH,mCAHW,GAAC,GACC,OAAO,CAInB;AAED;;;;;;;;;GASG;AACH,8BAHW,GAAC,GACC,OAAO,CAInB;AAED;;;;;;;;;;;GAWG;AACH,8BAHW,GAAC,GACC,OAAO,CAInB;AAED;;;;;;;;;GASG;AACH,6BAHW,GAAC,GACC,OAAO,CAInB;AAED;;;;;;;;;GASG;AACH,6BAHW,GAAC,GACC,OAAO,CAInB;AAED;;;;;;;;;;;;GAYG;AACH,+BAHW,GAAC,GACC,OAAO,CAInB"}