@zwa73/utils 1.0.206 → 1.0.208
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/QuickExport.d.ts +1 -2
- package/dist/QuickExport.js +27 -22
- package/dist/UtilClass.d.ts +1 -98
- package/dist/UtilClass.js +7 -243
- package/dist/UtilDecorators.d.ts +1 -32
- package/dist/UtilDecorators.js +15 -225
- package/dist/UtilFunctions.d.ts +9 -267
- package/dist/UtilFunctions.js +38 -687
- package/dist/UtilI18n.js +1 -1
- package/dist/UtilInterfaces.d.ts +1 -180
- package/dist/UtilInterfaces.js +1 -0
- package/dist/UtilLogger.d.ts +19 -20
- package/dist/UtilLogger.js +1 -1
- package/dist/UtilSymbol.d.ts +1 -40
- package/dist/UtilSymbol.js +11 -27
- package/dist/index.js +3 -0
- package/dist/test/dist/bitcont.d.ts +1 -0
- package/dist/test/dist/bitcont.js +153 -0
- package/dist/test/dist/error.d.ts +1 -0
- package/dist/test/dist/error.js +11 -0
- package/dist/test/dist/fptest.d.ts +1 -0
- package/dist/test/dist/fptest.js +21 -0
- package/dist/test/dist/hbs.d.ts +1 -0
- package/dist/test/dist/hbs.js +14 -0
- package/dist/test/dist/ip.d.ts +1 -0
- package/dist/test/dist/ip.js +107 -0
- package/dist/test/dist/llonebot.d.ts +0 -0
- package/dist/test/dist/llonebot.js +1 -0
- package/dist/test/dist/log.d.ts +1 -0
- package/dist/test/dist/log.js +9 -0
- package/dist/test/dist/match.d.ts +1 -0
- package/dist/test/dist/match.js +19 -0
- package/dist/test/dist/pathe.d.ts +1 -0
- package/dist/test/dist/pathe.js +7 -0
- package/dist/test/dist/queuetest.d.ts +1 -0
- package/dist/test/dist/queuetest.js +139 -0
- package/dist/test/dist/regtest.d.ts +1 -0
- package/dist/test/dist/regtest.js +8 -0
- package/dist/test/dist/repeatTest.d.ts +1 -0
- package/dist/test/dist/repeatTest.js +120 -0
- package/dist/test/dist/stringifytest.d.ts +1 -0
- package/dist/test/dist/stringifytest.js +8 -0
- package/dist/test/dist/test2.d.ts +1 -0
- package/dist/test/dist/test2.js +35 -0
- package/dist/test/dist/testStream.d.ts +1 -0
- package/dist/test/dist/testStream.js +286 -0
- package/package.json +3 -1
package/dist/UtilFunctions.js
CHANGED
|
@@ -15,12 +15,6 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
-
};
|
|
24
18
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
25
19
|
if (mod && mod.__esModule) return mod;
|
|
26
20
|
var result = {};
|
|
@@ -28,9 +22,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
28
22
|
__setModuleDefault(result, mod);
|
|
29
23
|
return result;
|
|
30
24
|
};
|
|
31
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
32
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
33
|
-
};
|
|
34
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
27
|
};
|
|
@@ -38,57 +29,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
38
29
|
exports.UtilFunc = void 0;
|
|
39
30
|
const crypto = __importStar(require("crypto"));
|
|
40
31
|
const cp = __importStar(require("child_process"));
|
|
41
|
-
const UtilLogger_1 = require("./UtilLogger");
|
|
42
32
|
const UtilSymbol_1 = require("./UtilSymbol");
|
|
43
|
-
const UtilDecorators_1 = require("./UtilDecorators");
|
|
44
33
|
const path_1 = __importDefault(require("path"));
|
|
45
34
|
const UtilFileTools_1 = require("./UtilFileTools");
|
|
46
|
-
const
|
|
35
|
+
const UtilLogger_1 = require("./UtilLogger");
|
|
36
|
+
const js_utils_1 = require("@zwa73/js-utils");
|
|
37
|
+
const modular_mixer_1 = require("@zwa73/modular-mixer");
|
|
47
38
|
const HashMethodList = ["md5", "sha1", "sha256", "sha512", "sha3", "blake2", "blake3"];
|
|
48
|
-
/**永不完成的Promise单例 */
|
|
49
|
-
const NeverResolvedPromise = new Promise(() => { });
|
|
50
39
|
/**常用函数 */
|
|
51
|
-
class
|
|
52
|
-
//#region 杂项
|
|
53
|
-
/**获取当前时间戳
|
|
54
|
-
* @returns 时间戳
|
|
55
|
-
*/
|
|
56
|
-
static getTime() {
|
|
57
|
-
return new Date().getTime();
|
|
58
|
-
}
|
|
59
|
-
/**初始化对象的字段
|
|
60
|
-
* 会改变obj
|
|
61
|
-
* @param obj - 所要初始化的对象
|
|
62
|
-
* @param field - 所要初始化的字段
|
|
63
|
-
* @param defaultVal - 默认值
|
|
64
|
-
* @returns 最终值
|
|
65
|
-
*/
|
|
66
|
-
static initField(obj, field, defaultVal) {
|
|
67
|
-
if (!(field in obj))
|
|
68
|
-
obj[field] = defaultVal;
|
|
69
|
-
return obj[field];
|
|
70
|
-
}
|
|
71
|
-
/**初始化一个数据对象
|
|
72
|
-
* @param obj - 目标对象
|
|
73
|
-
* @param checkObj - 用于检测的对象 在对应key缺失时赋予对应值 如果值为函数, 则赋予执行结果 如果结果为 undefined 则不赋值
|
|
74
|
-
* @returns 完成初始化的对象
|
|
75
|
-
*/
|
|
76
|
-
static initObject(obj, checkObj) {
|
|
77
|
-
const fixobj = obj;
|
|
78
|
-
for (const key in checkObj) {
|
|
79
|
-
if (obj[key] !== undefined)
|
|
80
|
-
continue;
|
|
81
|
-
const checkVal = checkObj[key];
|
|
82
|
-
if (typeof checkVal === "function") {
|
|
83
|
-
const val = checkVal();
|
|
84
|
-
if (val !== undefined)
|
|
85
|
-
fixobj[key] = val;
|
|
86
|
-
}
|
|
87
|
-
else
|
|
88
|
-
fixobj[key] = checkVal;
|
|
89
|
-
}
|
|
90
|
-
return fixobj;
|
|
91
|
-
}
|
|
40
|
+
class _UtilFunc {
|
|
92
41
|
/**生成一串uuid
|
|
93
42
|
* @returns uuid
|
|
94
43
|
*/
|
|
@@ -103,13 +52,6 @@ class UtilFunc {
|
|
|
103
52
|
static calcHash(str, method = 'md5') {
|
|
104
53
|
return crypto.createHash(method).update(str).digest('hex');
|
|
105
54
|
}
|
|
106
|
-
static async sleep(timeMs, result) {
|
|
107
|
-
return new Promise((resolve, rejecte) => {
|
|
108
|
-
const timer = setTimeout(() => {
|
|
109
|
-
resolve(result);
|
|
110
|
-
}, timeMs);
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
55
|
/**是否需要检查环境 */
|
|
114
56
|
static checkEnv = true;
|
|
115
57
|
/**是否有正在运行的exec */
|
|
@@ -128,16 +70,16 @@ class UtilFunc {
|
|
|
128
70
|
const env = Object.create(process.env);
|
|
129
71
|
const penv = path_1.default.join(opt?.nodeModules
|
|
130
72
|
? UtilFileTools_1.UtilFT.currosizePath(opt.nodeModules)
|
|
131
|
-
: UtilFileTools_1.UtilFT.currosizePath(await UtilFunc.memoize(UtilFileTools_1.UtilFT.findNodeModulesDir)(process.cwd()) ?? ''), '.bin');
|
|
132
|
-
if (
|
|
73
|
+
: UtilFileTools_1.UtilFT.currosizePath(await exports.UtilFunc.memoize(UtilFileTools_1.UtilFT.findNodeModulesDir)(process.cwd()) ?? ''), '.bin');
|
|
74
|
+
if (_UtilFunc.checkEnv && !await UtilFileTools_1.UtilFT.pathExists(penv)) {
|
|
133
75
|
UtilLogger_1.SLogger.warn(`UtilFunc.exec 错误, 没有检测到 node_modules/.bin 环境 penv:${penv}`);
|
|
134
|
-
|
|
76
|
+
_UtilFunc.checkEnv = false;
|
|
135
77
|
}
|
|
136
78
|
env.PATH = penv + path_1.default.delimiter + env.PATH;
|
|
137
79
|
// 保存原来的标题
|
|
138
|
-
|
|
80
|
+
_UtilFunc.originalExecTitle = _UtilFunc.originalExecTitle == UtilSymbol_1.None
|
|
139
81
|
? process.title
|
|
140
|
-
:
|
|
82
|
+
: _UtilFunc.originalExecTitle;
|
|
141
83
|
const cwd = opt?.cwd ?? process.cwd();
|
|
142
84
|
const child = cp.spawn(command, { shell: true, env, cwd });
|
|
143
85
|
let stdout = '';
|
|
@@ -154,9 +96,9 @@ class UtilFunc {
|
|
|
154
96
|
});
|
|
155
97
|
child.on('error', reject);
|
|
156
98
|
child.on('close', (code) => {
|
|
157
|
-
if (
|
|
158
|
-
process.title =
|
|
159
|
-
|
|
99
|
+
if (_UtilFunc.originalExecTitle != UtilSymbol_1.None) {
|
|
100
|
+
process.title = _UtilFunc.originalExecTitle;
|
|
101
|
+
_UtilFunc.originalExecTitle = UtilSymbol_1.None;
|
|
160
102
|
}
|
|
161
103
|
if (code !== 0)
|
|
162
104
|
UtilLogger_1.SLogger.warn(`UtilFunc.exec 命令:"${command}" 结束 代码为:${code}`);
|
|
@@ -164,333 +106,12 @@ class UtilFunc {
|
|
|
164
106
|
});
|
|
165
107
|
});
|
|
166
108
|
}
|
|
167
|
-
/**获得一个永不完成的Promise单例 */
|
|
168
|
-
static async getNeverResolvedPromise() {
|
|
169
|
-
return NeverResolvedPromise;
|
|
170
|
-
}
|
|
171
|
-
/**重复尝试promise
|
|
172
|
-
* @async
|
|
173
|
-
* @param proc - 发起函数
|
|
174
|
-
* @param verify - 验证函数
|
|
175
|
-
* @param retries - 重试参数 默认 延迟:0ms 间隔:180_000ms 重试:3次
|
|
176
|
-
* @returns 重复结果
|
|
177
|
-
*/
|
|
178
|
-
static async retryPromise(proc, verify, retries = {}) {
|
|
179
|
-
retries.count = retries.count ?? 3;
|
|
180
|
-
retries.tryInterval = retries.tryInterval ?? 180_000;
|
|
181
|
-
const { count, tryInterval, tryDelay } = retries;
|
|
182
|
-
/**是否含有超时时间 */
|
|
183
|
-
const hasRepeatTime = (tryInterval >= 5000);
|
|
184
|
-
//验证处理函数
|
|
185
|
-
if (verify === undefined)
|
|
186
|
-
verify = () => UtilSymbol_1.Success;
|
|
187
|
-
//进行中的请求
|
|
188
|
-
const plist = [];
|
|
189
|
-
//开始处理
|
|
190
|
-
try {
|
|
191
|
-
//根据最大重试次数限制进行循环
|
|
192
|
-
for (let i = 0; i < count;) {
|
|
193
|
-
if (i > 0 && tryDelay) {
|
|
194
|
-
const delay = retries.expBackoff
|
|
195
|
-
? Math.min((Math.pow(2, i) - 1) * tryDelay, retries.expBackoffMax ?? Infinity)
|
|
196
|
-
: tryDelay;
|
|
197
|
-
await UtilFunc.sleep(delay);
|
|
198
|
-
}
|
|
199
|
-
UtilLogger_1.SLogger.info(`开始第 ${i + 1} 次 retryPromise`);
|
|
200
|
-
//如果 plist 中当前下标的任务还未创建 则 创建当前任务
|
|
201
|
-
if (plist.length < i + 1) {
|
|
202
|
-
plist.push(UtilFunc.timelimitPromise(async () => {
|
|
203
|
-
const index = i;
|
|
204
|
-
const result = await proc();
|
|
205
|
-
const stat = await verify(result);
|
|
206
|
-
return { result, stat, index };
|
|
207
|
-
}, hasRepeatTime ? tryInterval : undefined));
|
|
208
|
-
}
|
|
209
|
-
//等待任意任务 或当前计时器完成
|
|
210
|
-
const currObj = await Promise.race([...plist]);
|
|
211
|
-
//超时处理
|
|
212
|
-
if (currObj.status === UtilSymbol_1.Timeout) {
|
|
213
|
-
//解除timeout替换原参数
|
|
214
|
-
plist[i] = new Promise(async (rslove) => {
|
|
215
|
-
const res = await currObj.result;
|
|
216
|
-
rslove(UtilFunc.outcome(UtilSymbol_1.Success, res));
|
|
217
|
-
});
|
|
218
|
-
UtilLogger_1.SLogger.warn(`第 ${i + 1} 次 retryPromise 超时 ${tryInterval} ms 开始重试`);
|
|
219
|
-
i++;
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
//路由请求状态
|
|
223
|
-
const postresult = currObj.result;
|
|
224
|
-
const result = UtilFunc.matchProc(postresult.stat, {
|
|
225
|
-
[UtilSymbol_1.Success]() {
|
|
226
|
-
UtilLogger_1.SLogger.info(`第 ${postresult.index + 1} 次 retryPromise 成功`);
|
|
227
|
-
//非当前
|
|
228
|
-
if (postresult.index != i)
|
|
229
|
-
UtilLogger_1.SLogger.info(`成功的 promise 非当前 promise 考虑增大重试时间\n当前index: ${i}\n当前重试时间: ${tryInterval}`);
|
|
230
|
-
return postresult.result;
|
|
231
|
-
},
|
|
232
|
-
[UtilSymbol_1.Terminated]() {
|
|
233
|
-
UtilLogger_1.SLogger.warn(`第 ${postresult.index + 1} 次 retryPromise 终止 停止重试`);
|
|
234
|
-
return postresult.result;
|
|
235
|
-
},
|
|
236
|
-
[UtilSymbol_1.Failed]() {
|
|
237
|
-
//抛弃失败
|
|
238
|
-
plist[postresult.index] = UtilFunc.getNeverResolvedPromise();
|
|
239
|
-
//是当前
|
|
240
|
-
if (postresult.index == i) {
|
|
241
|
-
UtilLogger_1.SLogger.warn(`第 ${postresult.index + 1} 次 retryPromise 失败 开始重试`);
|
|
242
|
-
i++;
|
|
243
|
-
return UtilSymbol_1.None;
|
|
244
|
-
}
|
|
245
|
-
//非当前
|
|
246
|
-
UtilLogger_1.SLogger.warn(`第 ${postresult.index + 1} 次 retryPromise 失败`);
|
|
247
|
-
return UtilSymbol_1.None;
|
|
248
|
-
},
|
|
249
|
-
});
|
|
250
|
-
if (result !== UtilSymbol_1.None)
|
|
251
|
-
return {
|
|
252
|
-
completed: result,
|
|
253
|
-
pending: plist
|
|
254
|
-
.filter((p, i) => i != postresult.index)
|
|
255
|
-
.filter(p => p != UtilFunc.getNeverResolvedPromise())
|
|
256
|
-
.map(async (p) => {
|
|
257
|
-
const curObj = await p;
|
|
258
|
-
if (curObj.status == UtilSymbol_1.Success) {
|
|
259
|
-
const outres = curObj.result;
|
|
260
|
-
if (outres.stat == UtilSymbol_1.Success)
|
|
261
|
-
return outres.result;
|
|
262
|
-
}
|
|
263
|
-
if (curObj.status == UtilSymbol_1.Timeout) {
|
|
264
|
-
const outres = await curObj.result;
|
|
265
|
-
if (outres.stat == UtilSymbol_1.Success)
|
|
266
|
-
return outres.result;
|
|
267
|
-
}
|
|
268
|
-
return undefined;
|
|
269
|
-
}),
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
//全部失败或超时则返回 全pending
|
|
273
|
-
UtilLogger_1.SLogger.warn(`${count} 次 retryPromise 尝试均失败`);
|
|
274
|
-
return {
|
|
275
|
-
completed: undefined,
|
|
276
|
-
pending: plist
|
|
277
|
-
.filter(p => p != UtilFunc.getNeverResolvedPromise())
|
|
278
|
-
.map(async (p) => {
|
|
279
|
-
const curObj = await p;
|
|
280
|
-
if (curObj.status == UtilSymbol_1.Success) {
|
|
281
|
-
const outres = curObj.result;
|
|
282
|
-
if (outres.stat == UtilSymbol_1.Success)
|
|
283
|
-
return outres.result;
|
|
284
|
-
}
|
|
285
|
-
if (curObj.status == UtilSymbol_1.Timeout) {
|
|
286
|
-
const outres = await curObj.result;
|
|
287
|
-
if (outres.stat == UtilSymbol_1.Success)
|
|
288
|
-
return outres.result;
|
|
289
|
-
}
|
|
290
|
-
return undefined;
|
|
291
|
-
}),
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
catch (err) {
|
|
295
|
-
UtilLogger_1.SLogger.warn(`retryPromise 发生意外错误`, err);
|
|
296
|
-
return { completed: undefined, pending: [] };
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
/**创建一个限时的Promise
|
|
300
|
-
* @param func - 处理函数
|
|
301
|
-
* @param timeLimit - 毫秒限时
|
|
302
|
-
* @returns 超时则返回 处理函数委托 完成则返回结果
|
|
303
|
-
*/
|
|
304
|
-
static async timelimitPromise(func, timeLimit) {
|
|
305
|
-
return new Promise((reslove) => {
|
|
306
|
-
let clearTimer = null;
|
|
307
|
-
const procer = (async () => await func())();
|
|
308
|
-
const procerP = new Promise(async (resolve) => {
|
|
309
|
-
const res = await procer;
|
|
310
|
-
resolve(UtilFunc.outcome(UtilSymbol_1.Success, res));
|
|
311
|
-
if (clearTimer)
|
|
312
|
-
clearTimer();
|
|
313
|
-
});
|
|
314
|
-
if (timeLimit) {
|
|
315
|
-
const timerP = new Promise((timeResolve) => {
|
|
316
|
-
const timer = setTimeout(() => timeResolve(UtilFunc.outcome(UtilSymbol_1.Timeout, procer)), timeLimit);
|
|
317
|
-
clearTimer = () => {
|
|
318
|
-
timeResolve(UtilFunc.outcome(UtilSymbol_1.Timeout, procer));
|
|
319
|
-
clearInterval(timer);
|
|
320
|
-
};
|
|
321
|
-
});
|
|
322
|
-
reslove(Promise.race([procerP, timerP]));
|
|
323
|
-
}
|
|
324
|
-
else {
|
|
325
|
-
reslove(procerP);
|
|
326
|
-
}
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
/**对对象的每个属性应用映射函数,并返回一个新的对象。
|
|
330
|
-
* @template T - 对象的类型
|
|
331
|
-
* @param obj - 要处理的对象
|
|
332
|
-
* @param mapper - 映射函数,接受一个值和一个键,返回一个新的值
|
|
333
|
-
* @returns - 一个新的对象,它的属性是原对象的属性经过映射函数处理后的结果
|
|
334
|
-
*/
|
|
335
|
-
static mapEntries(obj, mapper) {
|
|
336
|
-
return Object.entries(obj).reduce((result, [key, value]) => {
|
|
337
|
-
result[key] = mapper(key, value);
|
|
338
|
-
return result;
|
|
339
|
-
}, {});
|
|
340
|
-
}
|
|
341
|
-
/**遍历对象的所有字段
|
|
342
|
-
* @param obj - 对象
|
|
343
|
-
* @param callback - 回调函数
|
|
344
|
-
*/
|
|
345
|
-
static eachField(obj, callback) {
|
|
346
|
-
if (obj == null)
|
|
347
|
-
return;
|
|
348
|
-
if (typeof obj === 'object' && 'toJSON' in obj && typeof obj.toJSON == 'function') {
|
|
349
|
-
UtilLogger_1.SLogger.warn('UtilFunc.eachField 错误 无法遍历IJData 已跳过');
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
if (Array.isArray(obj)) {
|
|
353
|
-
for (const item of obj)
|
|
354
|
-
UtilFunc.eachField(item, callback);
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
if (typeof obj === 'object') {
|
|
358
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
359
|
-
UtilFunc.eachField(v, callback);
|
|
360
|
-
callback(k, v, obj);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
/**将JToken转换为字符串
|
|
365
|
-
* @param token - 待转换的Token
|
|
366
|
-
* @param opt - 可选参数
|
|
367
|
-
* @param opt.space - 插入的空格 数字为空格数量 默认为制表符\t
|
|
368
|
-
* @param opt.compress - 使用紧凑风格 将会用/\uF121\uF122\uF123.+\uF121\uF122\uF123/作为特殊标记, 原始文本内若出现相同格式将会产生错误
|
|
369
|
-
* @param opt.compressThreshold - 紧凑风格 压缩阈值 默认100
|
|
370
|
-
* @returns 转换完成的字符串
|
|
371
|
-
*/
|
|
372
|
-
static stringifyJToken(token, opt) {
|
|
373
|
-
opt ??= {};
|
|
374
|
-
let { compress, space, compressThreshold } = opt;
|
|
375
|
-
space ??= "\t";
|
|
376
|
-
space = space === null ? undefined : space;
|
|
377
|
-
compressThreshold ??= 100;
|
|
378
|
-
if (!compress)
|
|
379
|
-
return JSON.stringify(token, null, space);
|
|
380
|
-
const ec = '\uF121\uF122\uF123';
|
|
381
|
-
const compressReplacer = (key, value) => {
|
|
382
|
-
if (Array.isArray(value) && value.every(item => typeof item === 'number' || typeof item === 'string' ||
|
|
383
|
-
typeof item === 'boolean' || item == null))
|
|
384
|
-
return `${ec}${JSON.stringify(value)}${ec}`;
|
|
385
|
-
const str = JSON.stringify(value);
|
|
386
|
-
if (typeof str != 'string')
|
|
387
|
-
return value;
|
|
388
|
-
if (str.length <= compressThreshold)
|
|
389
|
-
return `${ec}${str}${ec}`;
|
|
390
|
-
return value;
|
|
391
|
-
};
|
|
392
|
-
const result = JSON.stringify(token, compressReplacer, space);
|
|
393
|
-
if (typeof result != 'string')
|
|
394
|
-
return result;
|
|
395
|
-
return result.replace(new RegExp(`"${ec}(.*?)${ec}"`, 'g'), (match, p1) => p1.replace(/\\([\\"])/g, '$1'));
|
|
396
|
-
}
|
|
397
|
-
/**验证一个变量的类型是否为 T
|
|
398
|
-
* @template T - 验证类型
|
|
399
|
-
* @param t - 验证目标
|
|
400
|
-
*/
|
|
401
|
-
static assertType(t) { return t; }
|
|
402
|
-
/**验证一个变量的类型是否为字面量
|
|
403
|
-
* 仅限浅层
|
|
404
|
-
* @template T - 验证类型
|
|
405
|
-
* @param t - 验证目标
|
|
406
|
-
*/
|
|
407
|
-
static assertLiteral(t) { return t; }
|
|
408
|
-
/**深克隆 序列化并反序列化
|
|
409
|
-
* @template T - JToken类型的泛型
|
|
410
|
-
* @param obj - 克隆目标
|
|
411
|
-
* @returns 克隆结果
|
|
412
|
-
*/
|
|
413
|
-
static deepClone(obj) {
|
|
414
|
-
return JSON.parse(JSON.stringify(obj));
|
|
415
|
-
}
|
|
416
|
-
/**是否为安全的数字
|
|
417
|
-
* 非NaN 非null/undefined
|
|
418
|
-
* 且是数字
|
|
419
|
-
* @param num - 所要检测的数字
|
|
420
|
-
* @returns 是否安全
|
|
421
|
-
*/
|
|
422
|
-
static isSafeNumber(num) {
|
|
423
|
-
if (num == null)
|
|
424
|
-
return false;
|
|
425
|
-
if (typeof num === 'number') {
|
|
426
|
-
if (isNaN(num))
|
|
427
|
-
return false;
|
|
428
|
-
return true;
|
|
429
|
-
}
|
|
430
|
-
return false;
|
|
431
|
-
}
|
|
432
|
-
/**移除多行字符串中每行开始的最小空格数。
|
|
433
|
-
*
|
|
434
|
-
* @param input - 需要处理的多行 字符串模板 或 字符串。
|
|
435
|
-
* @param values - 插入模板字符串中的值。
|
|
436
|
-
* @returns 返回处理后的字符串,每行开始的空格数已被最小化。
|
|
437
|
-
*
|
|
438
|
-
* @example
|
|
439
|
-
* const name = 'World';
|
|
440
|
-
* const str = dedent`
|
|
441
|
-
* Hello,
|
|
442
|
-
* ${name}!
|
|
443
|
-
* `;
|
|
444
|
-
* console.log(str);
|
|
445
|
-
* // 输出:
|
|
446
|
-
* // Hello,
|
|
447
|
-
* // World!
|
|
448
|
-
*/
|
|
449
|
-
static dedent(input, ...values) {
|
|
450
|
-
const str = typeof input === 'string'
|
|
451
|
-
? input
|
|
452
|
-
: input.reduce((result, string, i) => result + string + (values[i] ?? ''), '');
|
|
453
|
-
const lines = str.split('\n');
|
|
454
|
-
const minIndent = Math.min(...lines.filter(line => line.trim() !== '').map(line => line.search(/\S/)));
|
|
455
|
-
return lines.map(line => line.slice(minIndent)).join('\n');
|
|
456
|
-
}
|
|
457
|
-
/**抛出错误
|
|
458
|
-
* @param message - 错误信息
|
|
459
|
-
* @param lvl - 日志等级
|
|
460
|
-
* @param opt - 额外参数
|
|
461
|
-
*/
|
|
462
|
-
static throwError(message, lvl, opt) {
|
|
463
|
-
const e = new Error(message);
|
|
464
|
-
const stackLines = e.stack.split('\n');
|
|
465
|
-
e.stack = [stackLines[0]].concat(stackLines.slice(2)).join('\n'); // 移除第一行的堆栈信息
|
|
466
|
-
Object.assign(e, opt);
|
|
467
|
-
if (lvl) {
|
|
468
|
-
//SLogger.log(lvl,message);
|
|
469
|
-
UtilLogger_1.SLogger.log(lvl, e.stack);
|
|
470
|
-
}
|
|
471
|
-
throw e;
|
|
472
|
-
}
|
|
473
|
-
/**获取函数调用位置 getFunctionLocation
|
|
474
|
-
* @param stack - 深度 默认1, 即getFuncLoc函数被调用的位置
|
|
475
|
-
*/
|
|
476
|
-
static getFuncLoc(stack = 1) {
|
|
477
|
-
const stackLines = new Error().stack.split('\n');
|
|
478
|
-
const regex = /([a-zA-Z]+?:.+?):(\d+?:\d+)/;
|
|
479
|
-
//console.log(stackLines)
|
|
480
|
-
const match = regex.exec(stackLines[stack + 1]);
|
|
481
|
-
if (match) {
|
|
482
|
-
const filePath = match[1];
|
|
483
|
-
const lineNumber = match[2];
|
|
484
|
-
return { filePath, lineNumber };
|
|
485
|
-
}
|
|
486
|
-
return undefined;
|
|
487
|
-
}
|
|
488
109
|
static publicIp;
|
|
489
110
|
/**获取当前公网ipv4 */
|
|
490
111
|
static async getPublicIpv4() {
|
|
491
|
-
if (
|
|
492
|
-
|
|
493
|
-
return
|
|
112
|
+
if (_UtilFunc.publicIp === undefined)
|
|
113
|
+
_UtilFunc.publicIp = await _UtilFunc.dynamicImport('public-ip');
|
|
114
|
+
return _UtilFunc.publicIp.publicIpv4();
|
|
494
115
|
}
|
|
495
116
|
/**动态导入模块的函数。这个函数是为了在TypeScript的模块系统配置为CommonJS时,防止动态import被转译为require而设计的。
|
|
496
117
|
* 使用这个函数,你可以在TypeScript中动态地导入模块,而不需要担心import()被转译为require()。
|
|
@@ -511,297 +132,27 @@ class UtilFunc {
|
|
|
511
132
|
static async dynamicImport(moduleName) {
|
|
512
133
|
return await eval(`import('${moduleName}')`);
|
|
513
134
|
}
|
|
514
|
-
/**缓存池 */
|
|
515
|
-
static cachePool = new WeakMap();
|
|
516
|
-
/**创建一个带有缓存有效期的memoize函数
|
|
517
|
-
* 只在传入值均为JToken时有效
|
|
518
|
-
* @param fn - 需要被memoize的函数
|
|
519
|
-
* @param expiry - 缓存的有效期 毫秒 默认为Infinity, 表示缓存永不过期。
|
|
520
|
-
* @returns 返回一个新的函数,这个函数在调用时会尝试从缓存中获取结果,如果缓存不存在或已过期,就会调用原函数并缓存其结果。
|
|
521
|
-
*/
|
|
522
|
-
static memoize(fn, expiry = Infinity) {
|
|
523
|
-
const cache = UtilFunc.cachePool.get(fn) ?? UtilFunc.ivk(() => {
|
|
524
|
-
const c = new Map();
|
|
525
|
-
UtilFunc.cachePool.set(fn, c);
|
|
526
|
-
return c;
|
|
527
|
-
});
|
|
528
|
-
return ((...args) => {
|
|
529
|
-
const key = JSON.stringify(args);
|
|
530
|
-
const now = Date.now();
|
|
531
|
-
const cached = cache.get(key);
|
|
532
|
-
if (cached && now - cached.timestamp < expiry)
|
|
533
|
-
return cached.result;
|
|
534
|
-
const result = fn(...args);
|
|
535
|
-
cache.set(key, { result, timestamp: now });
|
|
536
|
-
return result;
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
|
-
//#endregion
|
|
540
|
-
//#region 队列处理
|
|
541
|
-
/**代办表 用于队列处理等待 */
|
|
542
|
-
static pendingMap = {};
|
|
543
|
-
/**队列处理
|
|
544
|
-
* 等待标签为 flag 的队列
|
|
545
|
-
* 直到排在之前的任务全部完成再处理当前Promise
|
|
546
|
-
* @param flag - 队列标签
|
|
547
|
-
* @param task - 任务逻辑
|
|
548
|
-
* @returns 处理结果
|
|
549
|
-
*/
|
|
550
|
-
static async queueProc(flag, task) {
|
|
551
|
-
// 如果当前标签的队列不存在,则创建一个新的队列
|
|
552
|
-
if (!UtilFunc.pendingMap[flag])
|
|
553
|
-
UtilFunc.pendingMap[flag] = [];
|
|
554
|
-
// 创建一个新的Promise,并保存resolve函数以便后续调用
|
|
555
|
-
let resolveFunc;
|
|
556
|
-
let rejectFunc;
|
|
557
|
-
const promise = new Promise((resolve, reject) => {
|
|
558
|
-
resolveFunc = resolve;
|
|
559
|
-
rejectFunc = reject;
|
|
560
|
-
});
|
|
561
|
-
// 定义处理任务的函数
|
|
562
|
-
const processTask = async () => {
|
|
563
|
-
let result;
|
|
564
|
-
try {
|
|
565
|
-
// 执行任务并等待结果
|
|
566
|
-
result = await task();
|
|
567
|
-
// 使用保存的resolve函数来解决Promise
|
|
568
|
-
resolveFunc(result);
|
|
569
|
-
}
|
|
570
|
-
catch (error) {
|
|
571
|
-
// 如果任务执行出错,记录错误日志
|
|
572
|
-
UtilLogger_1.SLogger.warn(`queueProc 错误 flag: ${String(flag)} 已抛出`);
|
|
573
|
-
rejectFunc(error);
|
|
574
|
-
}
|
|
575
|
-
finally {
|
|
576
|
-
// 无论任务是否成功,都从队列中移除当前任务
|
|
577
|
-
UtilFunc.pendingMap[flag].shift();
|
|
578
|
-
// 如果队列中还有任务,执行下一个任务
|
|
579
|
-
if (UtilFunc.pendingMap[flag].length > 0) {
|
|
580
|
-
UtilFunc.pendingMap[flag][0]();
|
|
581
|
-
}
|
|
582
|
-
else {
|
|
583
|
-
// 如果队列中没有任务,删除队列
|
|
584
|
-
delete UtilFunc.pendingMap[flag];
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
};
|
|
588
|
-
// 将处理任务的函数添加到队列中
|
|
589
|
-
UtilFunc.pendingMap[flag].push(processTask);
|
|
590
|
-
// 如果队列中只有当前任务,立即执行
|
|
591
|
-
if (UtilFunc.pendingMap[flag].length === 1)
|
|
592
|
-
void processTask();
|
|
593
|
-
// 返回Promise,以便调用者可以等待任务完成
|
|
594
|
-
return promise;
|
|
595
|
-
}
|
|
596
|
-
/**队列获取目标的代办事件数
|
|
597
|
-
* @param flag - 队列标签
|
|
598
|
-
*/
|
|
599
|
-
static queueLength(flag) {
|
|
600
|
-
const pd = UtilFunc.pendingMap[flag];
|
|
601
|
-
return pd != null ? pd.length : 0;
|
|
602
|
-
}
|
|
603
|
-
//#endregion
|
|
604
|
-
//#region symbol化处理工具
|
|
605
|
-
/**创建一个Outcome */
|
|
606
|
-
static outcome(key, value) {
|
|
607
|
-
return {
|
|
608
|
-
status: key,
|
|
609
|
-
result: value
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
/**处理联合值
|
|
613
|
-
* @param t - 目标值
|
|
614
|
-
* @param procObj - 所有可能的id组成的处理函数映射 (status, result)=>any
|
|
615
|
-
* @returns 任意处理函数的返回值
|
|
616
|
-
*/
|
|
617
|
-
static matchProc(t, procObj) {
|
|
618
|
-
if (typeof t === 'string' || typeof t === 'number' || typeof t === 'symbol') {
|
|
619
|
-
if (procObj[t])
|
|
620
|
-
return procObj[t](t);
|
|
621
|
-
}
|
|
622
|
-
else if (procObj[t.status])
|
|
623
|
-
return procObj[t.status](t.status, t.result);
|
|
624
|
-
UtilFunc.throwError(`matchProc 传入了一个预料之外的值: ${String(t)}`, 'fatal');
|
|
625
|
-
}
|
|
626
|
-
/**处理部分联合值
|
|
627
|
-
* @param t - 目标值
|
|
628
|
-
* @param procObj - 所有可能的id组成的处理函数映射 (status, result)=>any
|
|
629
|
-
* @returns 任意处理函数的返回值
|
|
630
|
-
*/
|
|
631
|
-
static matchPartialProc(t, procObj) {
|
|
632
|
-
if (typeof t === 'string' || typeof t === 'number' || typeof t === 'symbol') {
|
|
633
|
-
if (procObj[t])
|
|
634
|
-
return procObj[t](t);
|
|
635
|
-
else
|
|
636
|
-
return undefined;
|
|
637
|
-
}
|
|
638
|
-
else if (procObj[t.status])
|
|
639
|
-
return procObj[t.status](t.status, t.result);
|
|
640
|
-
UtilLogger_1.SLogger.warn(`matchPartialProc 传入了一个预料之外的值, 已返回undefined: ${String(t)}`);
|
|
641
|
-
return undefined;
|
|
642
|
-
}
|
|
643
|
-
/**根据典型的成功或失败状态运行函数
|
|
644
|
-
* @param t - 目标值
|
|
645
|
-
* @param sucessFunc - 成功则运行的函数 (result)=>any
|
|
646
|
-
* @param failedFunc - 失败则运行的函数 (result)=>any
|
|
647
|
-
* @param noneFunc - 无结果或不匹配时运行的函数 ()=>any
|
|
648
|
-
* @returns 非成功或失败时返回 None
|
|
649
|
-
*/
|
|
650
|
-
static sucesProc(t, sucessFunc, failedFunc, noneFunc) {
|
|
651
|
-
failedFunc = failedFunc ?? (() => UtilSymbol_1.None);
|
|
652
|
-
noneFunc = noneFunc ?? (() => UtilSymbol_1.None);
|
|
653
|
-
const val = typeof t === 'symbol' ? undefined : t.result;
|
|
654
|
-
if (UtilFunc.isSuccess(t))
|
|
655
|
-
return sucessFunc(val);
|
|
656
|
-
if (UtilFunc.isFailed(t))
|
|
657
|
-
return failedFunc(val);
|
|
658
|
-
if (t !== UtilSymbol_1.None)
|
|
659
|
-
UtilLogger_1.SLogger.warn(`sucesProc 传入了一个不匹配的值, 将作为None运行: `, t);
|
|
660
|
-
return noneFunc();
|
|
661
|
-
}
|
|
662
|
-
/**是失败的 */
|
|
663
|
-
static isFailed(tg) {
|
|
664
|
-
const test = (t) => t === UtilSymbol_1.Failed || t === UtilSymbol_1.Terminated || t === UtilSymbol_1.Timeout;
|
|
665
|
-
if (tg != null && typeof tg === 'object' && 'status' in tg)
|
|
666
|
-
return test(tg.status);
|
|
667
|
-
return test(tg);
|
|
668
|
-
}
|
|
669
|
-
/**是成功的 */
|
|
670
|
-
static isSuccess(tg) {
|
|
671
|
-
const test = (t) => t === UtilSymbol_1.Success || t === UtilSymbol_1.Completed;
|
|
672
|
-
if (tg != null && typeof tg === 'object' && 'status' in tg)
|
|
673
|
-
return test(tg.status);
|
|
674
|
-
return test(tg);
|
|
675
|
-
}
|
|
676
|
-
/**类似空值 undefined null None
|
|
677
|
-
* @param t - 检测目标
|
|
678
|
-
* @param strictLog - 应该严格等于None 否则将输出警告 但任然返回true
|
|
679
|
-
*/
|
|
680
|
-
static likeNone(t, strictLog = true) {
|
|
681
|
-
if (t === UtilSymbol_1.None)
|
|
682
|
-
return true;
|
|
683
|
-
if (t === "null" || t === "undefined" || t === String(UtilSymbol_1.None)) {
|
|
684
|
-
UtilLogger_1.SLogger.warn(`输入值为字符串类型的空值, 已作为 None 处理`, `具体值: ${t}`);
|
|
685
|
-
return true;
|
|
686
|
-
}
|
|
687
|
-
if (strictLog && t == null)
|
|
688
|
-
UtilLogger_1.SLogger.warn(`输入值不严格等于 None , 已作为 None 处理`, `具体类型: ${t}`);
|
|
689
|
-
return t == null;
|
|
690
|
-
}
|
|
691
|
-
/**验证一个值是否为空
|
|
692
|
-
* 为空则抛异
|
|
693
|
-
* @param t - 验证目标
|
|
694
|
-
* @param errLog - 异常信息
|
|
695
|
-
* @returns 排除None的原值
|
|
696
|
-
*/
|
|
697
|
-
static expect(t, errLog) {
|
|
698
|
-
if (t === UtilSymbol_1.None)
|
|
699
|
-
UtilFunc.throwError(errLog ?? "expect验证了一个None值", "error");
|
|
700
|
-
return t;
|
|
701
|
-
}
|
|
702
|
-
//#endregion
|
|
703
|
-
//#region 显式处理错误工具
|
|
704
|
-
/**将传入函数包装为显式处理错误的函数
|
|
705
|
-
* @param func - 待转换函数
|
|
706
|
-
* @returns 转换完成的函数
|
|
707
|
-
*/
|
|
708
|
-
static eitherize(func) {
|
|
709
|
-
return (...args) => {
|
|
710
|
-
try {
|
|
711
|
-
const result = func(...args);
|
|
712
|
-
return UtilFunc.outcome(UtilSymbol_1.Success, result);
|
|
713
|
-
}
|
|
714
|
-
catch (error) {
|
|
715
|
-
if (error instanceof Error)
|
|
716
|
-
return UtilFunc.outcome(UtilSymbol_1.Failed, error);
|
|
717
|
-
return UtilFunc.outcome(UtilSymbol_1.Failed, new Error((0, util_1.inspect)(error)));
|
|
718
|
-
}
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
|
-
/**将传入的异步函数包装为显式处理错误的函数
|
|
722
|
-
* @param func - 待转换函数
|
|
723
|
-
* @returns 转换完成的函数
|
|
724
|
-
*/
|
|
725
|
-
static taskEitherize(func) {
|
|
726
|
-
return async (...args) => {
|
|
727
|
-
try {
|
|
728
|
-
const result = await func(...args);
|
|
729
|
-
return UtilFunc.outcome(UtilSymbol_1.Success, result);
|
|
730
|
-
}
|
|
731
|
-
catch (error) {
|
|
732
|
-
if (error instanceof Error)
|
|
733
|
-
return UtilFunc.outcome(UtilSymbol_1.Failed, error);
|
|
734
|
-
return UtilFunc.outcome(UtilSymbol_1.Failed, new Error((0, util_1.inspect)(error)));
|
|
735
|
-
}
|
|
736
|
-
};
|
|
737
|
-
}
|
|
738
|
-
//#endregion
|
|
739
|
-
//#region 解析srt
|
|
740
|
-
/**将hh:mm:ss,ms格式转换为毫秒 */
|
|
741
|
-
static parseSrtTime(time) {
|
|
742
|
-
const [hours, minutes, seconds] = time.split(':');
|
|
743
|
-
const [secs, milliseconds] = seconds.split(',');
|
|
744
|
-
return parseInt(hours) * 3600000 +
|
|
745
|
-
parseInt(minutes) * 60000 +
|
|
746
|
-
parseInt(secs) * 1000 +
|
|
747
|
-
parseInt(milliseconds);
|
|
748
|
-
}
|
|
749
|
-
/**将毫秒转换为hh:mm:ss,ms格式 */
|
|
750
|
-
static formatSrtTime(milliseconds) {
|
|
751
|
-
const hours = Math.floor(milliseconds / 3_600_000);
|
|
752
|
-
const minutes = Math.floor((milliseconds % 3_600_000) / 60_000);
|
|
753
|
-
const seconds = Math.floor((milliseconds % 60_000) / 1000);
|
|
754
|
-
const ms = Math.floor(milliseconds % 1000);
|
|
755
|
-
return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')},${String(ms).padStart(3, '0')}`;
|
|
756
|
-
}
|
|
757
|
-
/**解析srt文本为SrtSegment[] */
|
|
758
|
-
static parseSrt(srtText) {
|
|
759
|
-
const segments = [];
|
|
760
|
-
const srtLines = srtText.split('\n');
|
|
761
|
-
let index = 0;
|
|
762
|
-
while (index < srtLines.length) {
|
|
763
|
-
const id = srtLines[index++].trim();
|
|
764
|
-
if (!id)
|
|
765
|
-
continue;
|
|
766
|
-
const timeRange = srtLines[index++].trim();
|
|
767
|
-
const [start, end] = timeRange.split(' --> ')
|
|
768
|
-
.map(time => UtilFunc.parseSrtTime(time));
|
|
769
|
-
let text = '';
|
|
770
|
-
while (index < srtLines.length && srtLines[index].trim())
|
|
771
|
-
text += `${srtLines[index++]}\n`;
|
|
772
|
-
index++;
|
|
773
|
-
segments.push({ start, end, text: text.trim() });
|
|
774
|
-
}
|
|
775
|
-
return segments;
|
|
776
|
-
}
|
|
777
|
-
/**转换json为srt文本 */
|
|
778
|
-
static createSrt(segments) {
|
|
779
|
-
return segments.map((segment, index) => {
|
|
780
|
-
return `${index + 1}\n${UtilFunc.formatSrtTime(segment.start)} --> ${UtilFunc.formatSrtTime(segment.end)}\n${segment.text}\n`;
|
|
781
|
-
}).join('\n');
|
|
782
|
-
}
|
|
783
|
-
//#endregion
|
|
784
|
-
//#region 常用直传的快速调用函数
|
|
785
|
-
/**立即执行传入的函数
|
|
786
|
-
* @param fn - 需要立即执行的函数。
|
|
787
|
-
* @returns 返回 fn 函数的执行结果。
|
|
788
|
-
*/
|
|
789
|
-
static ivk(fn) {
|
|
790
|
-
return fn();
|
|
791
|
-
}
|
|
792
|
-
/**一个可供sort使用的从小到大排序的函数 */
|
|
793
|
-
static s2l(a, b) {
|
|
794
|
-
return a - b;
|
|
795
|
-
}
|
|
796
|
-
/**一个可供sort使用的从大到小排序的函数 */
|
|
797
|
-
static l2s(a, b) {
|
|
798
|
-
return b - a;
|
|
799
|
-
}
|
|
800
135
|
}
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
136
|
+
const mixkey = '__utilFunc';
|
|
137
|
+
const fields = Object.getOwnPropertyNames(_UtilFunc).filter(k => k !== 'length' && k !== 'prototype' && k !== 'name');
|
|
138
|
+
if (!(mixkey in js_utils_1.JsFunc)) {
|
|
139
|
+
(0, modular_mixer_1.composeClassPart)({
|
|
140
|
+
base: js_utils_1.JsFunc,
|
|
141
|
+
mixin: _UtilFunc,
|
|
142
|
+
key: mixkey,
|
|
143
|
+
fields: fields,
|
|
144
|
+
force: true
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
exports.UtilFunc = js_utils_1.JsFunc;
|
|
148
|
+
//void (async ()=>{
|
|
149
|
+
// const p1 = UtilFunc.getNeverResolvedPromise();
|
|
150
|
+
// const p2 = UtilFunc.getNeverResolvedPromise();
|
|
151
|
+
// const p3 = JsFunc.getNeverResolvedPromise();
|
|
152
|
+
// const p4 = JsFunc.getNeverResolvedPromise();
|
|
153
|
+
// console.log(p1==p2);
|
|
154
|
+
// console.log(p2==p3);
|
|
155
|
+
// console.log(p3==p4);
|
|
156
|
+
// console.log(p3);
|
|
157
|
+
// console.log(2345);
|
|
158
|
+
//})();
|