chivox_jssdk_7.x 7.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chivoxaiengine.js","sources":["../../../src/ailog.ts","../../node_modules/tslib/tslib.es6.js","../../../src/result.ts","../../../src/audioWorkletHelper.ts","../../../src/opusEncoderHelper.ts","../../../src/utils.ts","../../../src/wavEncoderHelper.ts","../../../src/Recorder.ts","../../../src/audioHelper.ts","../../../src/consts.ts","../../../src/version.ts","../../../src/errid.ts","../../../src/AISession2.ts","../../../src/AIEngine2.ts"],"sourcesContent":["type LogLevelName = 'debug' | 'info' | 'warn' | 'error'; \r\n// 再加一级notice\r\n\r\nenum LogLevel {\r\n Debug = 0,\r\n Info = 1,\r\n Warn = 2,\r\n Error = 3,\r\n}\r\n\r\nlet logLevel: LogLevel = LogLevel.Info;\r\n\r\nexport const ailog = {\r\n getLevel(): LogLevelName | undefined {\r\n switch (logLevel) {\r\n case LogLevel.Debug:\r\n return 'debug';\r\n case LogLevel.Info:\r\n return 'info';\r\n case LogLevel.Warn:\r\n return 'warn';\r\n case LogLevel.Error:\r\n return 'error';\r\n default:\r\n return undefined;\r\n }\r\n },\r\n\r\n setLevel(name: LogLevelName) {\r\n if (name === 'debug') {\r\n logLevel = LogLevel.Debug;\r\n } else if (name === 'info') {\r\n logLevel = LogLevel.Info;\r\n } else if (name === 'warn') {\r\n logLevel = LogLevel.Warn;\r\n } else if (name === 'error') {\r\n logLevel = LogLevel.Error;\r\n }\r\n },\r\n\r\n debug(...data: any[]) {\r\n if (logLevel <= LogLevel.Debug) {\r\n console.debug(...data)\r\n }\r\n },\r\n\r\n info(...data: any[]) {\r\n if (logLevel <= LogLevel.Info) {\r\n console.info(...data)\r\n }\r\n },\r\n\r\n warn(...data: any[]) {\r\n if (logLevel <= LogLevel.Warn) {\r\n console.warn(...data)\r\n }\r\n },\r\n\r\n error(...data: any[]) {\r\n if (logLevel <= LogLevel.Error) {\r\n console.error(...data)\r\n }\r\n }\r\n};\r\n","/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n 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;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\r\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\r\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\r\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\r\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\r\n var _, done = false;\r\n for (var i = decorators.length - 1; i >= 0; i--) {\r\n var context = {};\r\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\r\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\r\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\r\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\r\n if (kind === \"accessor\") {\r\n if (result === void 0) continue;\r\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\r\n if (_ = accept(result.get)) descriptor.get = _;\r\n if (_ = accept(result.set)) descriptor.set = _;\r\n if (_ = accept(result.init)) initializers.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\r\n else descriptor[key] = _;\r\n }\r\n }\r\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\r\n done = true;\r\n};\r\n\r\nexport function __runInitializers(thisArg, initializers, value) {\r\n var useValue = arguments.length > 2;\r\n for (var i = 0; i < initializers.length; i++) {\r\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\r\n }\r\n return useValue ? value : void 0;\r\n};\r\n\r\nexport function __propKey(x) {\r\n return typeof x === \"symbol\" ? x : \"\".concat(x);\r\n};\r\n\r\nexport function __setFunctionName(f, name, prefix) {\r\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\r\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\r\n};\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\r\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\r\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nvar ownKeys = function(o) {\r\n ownKeys = Object.getOwnPropertyNames || function (o) {\r\n var ar = [];\r\n for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\r\n return ar;\r\n };\r\n return ownKeys(o);\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\nexport function __classPrivateFieldIn(state, receiver) {\r\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\r\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\r\n}\r\n\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose, inner;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n if (async) inner = dispose;\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n var r, s = 0;\r\n function next() {\r\n while (r = env.stack.pop()) {\r\n try {\r\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\r\n if (r.dispose) {\r\n var result = r.dispose.call(r.value);\r\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n else s |= 1;\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport function __rewriteRelativeImportExtension(path, preserveJsx) {\r\n if (typeof path === \"string\" && /^\\.\\.?\\//.test(path)) {\r\n return path.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {\r\n return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : (d + ext + \".\" + cm.toLowerCase() + \"js\");\r\n });\r\n }\r\n return path;\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __esDecorate: __esDecorate,\r\n __runInitializers: __runInitializers,\r\n __propKey: __propKey,\r\n __setFunctionName: __setFunctionName,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n __rewriteRelativeImportExtension: __rewriteRelativeImportExtension,\r\n};\r\n","export type ResultOk<T> = { ok: true, data: T };\r\nexport type ResultErr<E> = { ok: false, err: E }\r\n\r\nexport function isOk<T, E>(res: ResultOk<T> | ResultErr<E>): res is ResultOk<T> {\r\n return res.ok === true;\r\n}\r\n\r\nexport function isErr<T, E>(res: ResultOk<T> | ResultErr<E>): res is ResultErr<E> {\r\n return res.ok === false;\r\n}\r\n\r\nexport function makeOk(): ResultOk<void>;\r\n\r\nexport function makeOk<T>(data: T): ResultOk<T>;\r\n\r\nexport function makeOk<T = void>(data?: T): ResultOk<T> {\r\n return { ok: true, data: data as T }\r\n}\r\n\r\nexport function makeErr<E>(err: E): ResultErr<E> {\r\n return { ok: false, err: err };\r\n}\r\n\r\nexport function ifOk<T, E, U>(okhandler: (data: T) => ResultOk<U> | ResultErr<E> | Promise<ResultOk<U> | ResultErr<E>>) {\r\n return (res: ResultOk<T> | ResultErr<E>) => {\r\n if (isOk(res)) {\r\n return okhandler(res.data)\r\n }\r\n return res;\r\n }\r\n}\r\n","import { makeErr, makeOk, ResultErr, ResultOk } from \"./result\";\r\n\r\nconst code = `\r\nclass ChivoxAiRecorderAudioWorkletProcessor extends AudioWorkletProcessor {\r\n constructor() {\r\n super();\r\n\r\n this.recording = false;\r\n\r\n if (sampleRate <= 16000) {\r\n this.bufferSize = 1024;\r\n } else if (sampleRate <= 32000) {\r\n this.bufferSize = 2048;\r\n } else if (sampleRate <= 64000) {\r\n this.bufferSize = 4096;\r\n } else {\r\n this.bufferSize = 8192;\r\n }\r\n this.buffer = new Float32Array(this.bufferSize);\r\n this.bufferLength = 0;\r\n\r\n this.port.onmessage = (ev) => {\r\n const data = ev.data;\r\n if (typeof (data) !== 'object' || data === null) {\r\n return;\r\n }\r\n\r\n switch (data.command) {\r\n case 'init':\r\n if (this.recording) {\r\n console.warn(\"chivox-airecorder-audioworklet-processor: already recording\");\r\n return;\r\n }\r\n\r\n this.recording = true;\r\n // this.buffer.fill(0);\r\n this.bufferLength = 0;\r\n this.port.postMessage({ message: 'ready' }); // 必须保证发送ready消息前无异常抛出\r\n break;\r\n\r\n case 'done':\r\n if (!this.recording) {\r\n this.port.postMessage({ message: 'done' });\r\n return;\r\n }\r\n\r\n this.recording = false;\r\n if (this.bufferLength > 0) {\r\n this.postBufferData();\r\n // this.buffer.fill(0);\r\n this.bufferLength = 0;\r\n }\r\n this.port.postMessage({ message: 'done' }); // 必须保证发送done消息前无异常抛出\r\n break;\r\n\r\n default:\r\n console.warn(\"chivox-airecorder-audioworklet-processor: unknown command:\", data.command);\r\n }\r\n };\r\n }\r\n\r\n postBufferData() {\r\n try {\r\n const data = this.buffer.slice(0, this.bufferLength); // slice will copy data\r\n this.port.postMessage({ message: 'data', content: data }, [data.buffer]); // data: Float32Array\r\n } catch (err) {\r\n console.error('chivox-airecorder-audioworklet-processor: failed to postBufferData:', err);\r\n }\r\n }\r\n\r\n process(inputs, _outputs) {\r\n if (!this.recording) {\r\n return true;\r\n }\r\n\r\n // 仅处理第一个输入的第一个声道\r\n if (!inputs || inputs.length == 0 \r\n || !inputs[0] || inputs[0].length == 0 \r\n || !inputs[0][0] || inputs[0][0].length === 0) {\r\n return true;\r\n }\r\n\r\n try {\r\n const inputData = inputs[0][0]; \r\n let remaining = inputData.length;\r\n let offset = 0;\r\n\r\n while (remaining > 0) {\r\n const spaceAvail = this.bufferSize - this.bufferLength;\r\n const writeLen = Math.min(remaining, spaceAvail);\r\n\r\n this.buffer.set(inputData.subarray(offset, offset + writeLen), this.bufferLength);\r\n\r\n this.bufferLength += writeLen;\r\n offset += writeLen;\r\n remaining -= writeLen;\r\n\r\n if (this.bufferLength >= this.bufferSize) {\r\n this.postBufferData();\r\n // this.buffer.fill(0);\r\n this.bufferLength = 0;\r\n }\r\n }\r\n } catch (err) {\r\n console.error('audioworklet-processor: process error:', err);\r\n }\r\n\r\n return true;\r\n }\r\n}\r\n\r\nregisterProcessor('chivox-airecorder-audioworklet-processor', ChivoxAiRecorderAudioWorkletProcessor);\r\n`;\r\n\r\nlet codeBlob: Blob | null = null;\r\nlet codeUrl: string | null = null;\r\n\r\nexport function createAudioWorkletNode(audioContext: AudioContext): Promise<ResultOk<AudioWorkletNode> | ResultErr<Error>> {\r\n return (async () => { // 保证这段代码无异常抛出\r\n try {\r\n if (!codeBlob || !codeUrl) {\r\n codeBlob = new Blob([code], { type: 'application/javascript' });\r\n codeUrl = URL.createObjectURL(codeBlob);\r\n }\r\n } catch (err) {\r\n return makeErr(new Error(`create AudioWorklet Blob/URL fail: ${err instanceof Error ? err.message : String(err)}`));\r\n }\r\n\r\n try {\r\n await audioContext.audioWorklet.addModule(codeUrl);\r\n } catch (err) {\r\n return makeErr(new Error(`regist AudioWorklet fail: ${err instanceof Error ? err.message : String(err)}`));\r\n }\r\n\r\n let node: AudioWorkletNode;\r\n try {\r\n node = new AudioWorkletNode(audioContext, 'chivox-airecorder-audioworklet-processor')\r\n } catch (err) {\r\n return makeErr(new Error(`new AudioWorkletNode fail: ${err instanceof Error ? err.message : String(err)}`))\r\n }\r\n\r\n return makeOk(node);\r\n })();\r\n}\r\n\r\nexport function cleanupAudioWorkletResources() {\r\n if (codeUrl) {\r\n URL.revokeObjectURL(codeUrl);\r\n codeUrl = null;\r\n codeBlob = null;\r\n }\r\n}","import code from './opusEncoderCode.js'\r\nimport { makeErr, makeOk, ResultErr, ResultOk } from './result.js';\r\n\r\nlet codeBlob: Blob | null = null\r\nlet codeUrl: string | null = null\r\n\r\nexport function createOpusEncoderWorker(): ResultOk<Worker> | ResultErr<Error> { // 保证这段代码无异常抛出\r\n try {\r\n if (!codeBlob || !codeUrl) {\r\n codeBlob = new Blob([code], { type: 'application/javascript' });\r\n codeUrl = URL.createObjectURL(codeBlob);\r\n }\r\n } catch (err) {\r\n return makeErr(new Error(`createOpusEncoderWorker fail: create Blob/URL fail: ${err instanceof Error ? err.message : String(err)}`));\r\n }\r\n\r\n let worker: Worker;\r\n try {\r\n worker = new Worker(codeUrl);\r\n } catch (err) {\r\n return makeErr(new Error(`createOpusEncoderWorker fail: new Worker fail: ${err instanceof Error ? err.message : String(err)}`));\r\n }\r\n\r\n // TODO 如果在Worker启动时codeUrl中的代码发生错误,如何捕获\r\n\r\n return makeOk(worker);\r\n}\r\n\r\nexport function cleanupOpusEncoderWorkerResources() {\r\n if (codeUrl) {\r\n URL.revokeObjectURL(codeUrl)\r\n codeUrl = null;\r\n codeBlob = null;\r\n }\r\n}","export function uuid() {\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,\r\n (c) => {\r\n let r = Math.random() * 16 | 0,\r\n v = c == 'x' ? r : (r & 0x3 | 0x8);\r\n return v.toString(16);\r\n }\r\n );\r\n}\r\n\r\nexport function asyncall(handler: Function, ...args: any[]) {\r\n setTimeout(handler, 0, ...args);\r\n}\r\n\r\nexport function catchcall(handler: Function, ...args: any[]) {\r\n try {\r\n handler(...args);\r\n } catch (err) {\r\n console.error(err)\r\n }\r\n}","import { makeErr, makeOk, ResultErr, ResultOk } from \"./result\";\r\n\r\nconst code = `\r\nfunction Resampler(fromSampleRate, toSampleRate, channels, outputBufferSize, noReturn) {\r\n this.fromSampleRate = fromSampleRate;\r\n this.toSampleRate = toSampleRate;\r\n this.channels = channels | 0;\r\n this.outputBufferSize = outputBufferSize;\r\n this.noReturn = !!noReturn;\r\n this.initialize();\r\n}\r\n\r\nResampler.prototype.initialize = function () {\r\n //Perform some checks:\r\n if (this.fromSampleRate > 0 && this.toSampleRate > 0 && this.channels > 0) {\r\n if (this.fromSampleRate == this.toSampleRate) {\r\n //Setup a resampler bypass:\r\n this.resampler = this.bypassResampler;\t\t//Resampler just returns what was passed through.\r\n this.ratioWeight = 1;\r\n } else {\r\n if (this.fromSampleRate < this.toSampleRate) {\r\n /*\r\n Use generic linear interpolation if upsampling,\r\n as linear interpolation produces a gradient that we want\r\n and works fine with two input sample points per output in this case.\r\n */\r\n this.compileLinearInterpolationFunction();\r\n this.lastWeight = 1;\r\n } else {\r\n /*\r\n Custom resampler I wrote that doesn't skip samples\r\n like standard linear interpolation in high downsampling.\r\n This is more accurate than linear interpolation on downsampling.\r\n */\r\n this.compileMultiTapFunction();\r\n this.tailExists = false;\r\n this.lastWeight = 0;\r\n }\r\n this.ratioWeight = this.fromSampleRate / this.toSampleRate;\r\n this.initializeBuffers();\r\n }\r\n } else {\r\n throw (new Error(\"Invalid settings specified for the resampler.\"));\r\n }\r\n}\r\n\r\nResampler.prototype.compileLinearInterpolationFunction = function () {\r\n var toCompile = \"var bufferLength = buffer.length;var outLength = this.outputBufferSize;if ((bufferLength % \" + this.channels + \") == 0) {if (bufferLength > 0) {var ratioWeight = this.ratioWeight;\\\r\n var weight = this.lastWeight;\\\r\n var firstWeight = 0;\\\r\n var secondWeight = 0;\\\r\n var sourceOffset = 0;\\\r\n var outputOffset = 0;\\\r\n var outputBuffer = this.outputBuffer;\\\r\n for (; weight < 1; weight += ratioWeight) {\\\r\n secondWeight = weight % 1;\\\r\n firstWeight = 1 - secondWeight;\";\r\n for (var channel = 0; channel < this.channels; ++channel) {\r\n toCompile += \"outputBuffer[outputOffset++] = (this.lastOutput[\" + channel + \"] * firstWeight) + (buffer[\" + channel + \"] * secondWeight);\";\r\n }\r\n toCompile += \"}\\\r\n weight -= 1;\\\r\n for (bufferLength -= \" + this.channels + \", sourceOffset = Math.floor(weight) * \" + this.channels + \"; outputOffset < outLength && sourceOffset < bufferLength;) {\\\r\n secondWeight = weight % 1;\\\r\n firstWeight = 1 - secondWeight;\";\r\n for (var channel = 0; channel < this.channels; ++channel) {\r\n toCompile += \"outputBuffer[outputOffset++] = (buffer[sourceOffset\" + ((channel > 0) ? (\" + \" + channel) : \"\") + \"] * firstWeight) + (buffer[sourceOffset + \" + (this.channels + channel) + \"] * secondWeight);\";\r\n }\r\n toCompile += \"weight += ratioWeight;\\\r\n sourceOffset = Math.floor(weight) * \" + this.channels + \";\\\r\n}\";\r\n for (var channel = 0; channel < this.channels; ++channel) {\r\n toCompile += \"this.lastOutput[\" + channel + \"] = buffer[sourceOffset++];\";\r\n }\r\n toCompile += \"this.lastWeight = weight % 1;\\\r\n return this.bufferSlice(outputOffset);\\\r\n }\\\r\n else {\\\r\n return (this.noReturn) ? 0 : [];\\\r\n }\\\r\n }\\\r\n else {\\\r\n throw(new Error('Buffer was of incorrect sample length.'));\\\r\n }\";\r\n this.resampler = Function(\"buffer\", toCompile);\r\n}\r\n\r\nResampler.prototype.compileMultiTapFunction = function () {\r\n var toCompile = \"var bufferLength = buffer.length;\\\r\n var outLength = this.outputBufferSize;\\\r\n if ((bufferLength % \" + this.channels + \") == 0) {\\\r\n if (bufferLength > 0) {\\\r\n var ratioWeight = this.ratioWeight;\\\r\n var weight = 0;\";\r\n for (var channel = 0; channel < this.channels; ++channel) {\r\n toCompile += \"var output\" + channel + \" = 0;\"\r\n }\r\n toCompile += \"var actualPosition = 0;\\\r\n var amountToNext = 0;\\\r\n var alreadyProcessedTail = !this.tailExists;\\\r\n this.tailExists = false;\\\r\n var outputBuffer = this.outputBuffer;\\\r\n var outputOffset = 0;\\\r\n var currentPosition = 0;\\\r\n do {\\\r\n if (alreadyProcessedTail) {\\\r\n weight = ratioWeight;\";\r\n for (channel = 0; channel < this.channels; ++channel) {\r\n toCompile += \"output\" + channel + \" = 0;\"\r\n }\r\n toCompile += \"}\\\r\n else {\\\r\n weight = this.lastWeight;\";\r\n for (channel = 0; channel < this.channels; ++channel) {\r\n toCompile += \"output\" + channel + \" = this.lastOutput[\" + channel + \"];\"\r\n }\r\n toCompile += \"alreadyProcessedTail = true;\\\r\n}\\\r\nwhile (weight > 0 && actualPosition < bufferLength) {\\\r\n amountToNext = 1 + actualPosition - currentPosition;\\\r\n if (weight >= amountToNext) {\";\r\n for (channel = 0; channel < this.channels; ++channel) {\r\n toCompile += \"output\" + channel + \" += buffer[actualPosition++] * amountToNext;\"\r\n }\r\n toCompile += \"currentPosition = actualPosition;\\\r\n weight -= amountToNext;\\\r\n }\\\r\n else {\";\r\n for (channel = 0; channel < this.channels; ++channel) {\r\n toCompile += \"output\" + channel + \" += buffer[actualPosition\" + ((channel > 0) ? (\" + \" + channel) : \"\") + \"] * weight;\"\r\n }\r\n toCompile += \"currentPosition += weight;\\\r\n weight = 0;\\\r\n break;\\\r\n }\\\r\n }\\\r\n if (weight == 0) {\";\r\n for (channel = 0; channel < this.channels; ++channel) {\r\n toCompile += \"outputBuffer[outputOffset++] = output\" + channel + \" / ratioWeight;\"\r\n }\r\n toCompile += \"}\\\r\n else {\\\r\n this.lastWeight = weight;\";\r\n for (channel = 0; channel < this.channels; ++channel) {\r\n toCompile += \"this.lastOutput[\" + channel + \"] = output\" + channel + \";\"\r\n }\r\n toCompile += \"this.tailExists = true;\\\r\n break;\\\r\n }\\\r\n } while (actualPosition < bufferLength && outputOffset < outLength);\\\r\n return this.bufferSlice(outputOffset);\\\r\n }\\\r\n else {\\\r\n return (this.noReturn) ? 0 : [];\\\r\n }\\\r\n }\\\r\n else {\\\r\n throw(new Error('Buffer was of incorrect sample length.'));\\\r\n }\";\r\n this.resampler = Function(\"buffer\", toCompile);\r\n}\r\n\r\nResampler.prototype.bypassResampler = function (buffer) {\r\n if (this.noReturn) {\r\n //Set the buffer passed as our own, as we don't need to resample it:\r\n this.outputBuffer = buffer;\r\n return buffer.length;\r\n } else {\r\n //Just return the buffer passsed:\r\n return buffer;\r\n }\r\n}\r\n\r\nResampler.prototype.bufferSlice = function (sliceAmount) {\r\n if (this.noReturn) {\r\n //If we're going to access the properties directly from this object:\r\n return sliceAmount;\r\n } else {\r\n //Typed array and normal array buffer section referencing:\r\n try {\r\n return this.outputBuffer.subarray(0, sliceAmount);\r\n } catch (error) {\r\n try {\r\n //Regular array pass:\r\n this.outputBuffer.length = sliceAmount;\r\n return this.outputBuffer;\r\n } catch (error) {\r\n //Nightly Firefox 4 used to have the subarray function named as slice:\r\n return this.outputBuffer.slice(0, sliceAmount);\r\n }\r\n }\r\n }\r\n}\r\n\r\nResampler.prototype.initializeBuffers = function () {\r\n //Initialize the internal buffer:\r\n try {\r\n this.outputBuffer = new Float32Array(this.outputBufferSize);\r\n this.lastOutput = new Float32Array(this.channels);\r\n } catch (error) {\r\n this.outputBuffer = [];\r\n this.lastOutput = [];\r\n }\r\n}\r\n\r\n\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nfunction floatTo16BitPCM(input) {\r\n const output = new Int16Array(input.length);\r\n for (let i = 0; i < input.length; i++) {\r\n const clamped = Math.max(-1, Math.min(1, input[i]));\r\n output[i] = clamped < 0 ? clamped * 32768 : clamped * 32767;\r\n }\r\n return output;\r\n}\r\n\r\nfunction writeString(view, offset, string) {\r\n for (var i = 0; i < string.length; i++) {\r\n view.setUint8(offset + i, string.charCodeAt(i));\r\n }\r\n}\r\n\r\nfunction makeWavHeader(totalLen, sampleRate) {\r\n const header = new ArrayBuffer(44);\r\n const view = new DataView(header);\r\n /* RIFF identifier */\r\n writeString(view, 0, 'RIFF');\r\n /* RIFF chunk length */\r\n view.setUint32(4, 36 + totalLen, true);\r\n /* RIFF type */\r\n writeString(view, 8, 'WAVE');\r\n /* format chunk identifier */\r\n writeString(view, 12, 'fmt ');\r\n /* format chunk length */\r\n view.setUint32(16, 16, true);\r\n /* sample format (raw) */\r\n view.setUint16(20, 1, true);\r\n /* channel count */\r\n view.setUint16(22, 1, true);\r\n /* sample rate */\r\n view.setUint32(24, sampleRate, true);\r\n /* byte rate (sample rate * block align) */\r\n view.setUint32(28, sampleRate * 2, true);\r\n /* block align (channel count * bytes per sample) */\r\n view.setUint16(32, 2, true);\r\n /* bits per sample */\r\n view.setUint16(34, 16, true);\r\n /* data chunk identifier */\r\n writeString(view, 36, 'data');\r\n /* data chunk length */\r\n view.setUint32(40, totalLen, true);\r\n\r\n return header;\r\n}\r\n\r\n\r\nlet initialized = false\r\nlet resampler = null;\r\nlet cachePCM16 = []; // Int16Array[]\r\n\r\nself.onmessage = function (ev) {\r\n const data = ev.data;\r\n if (typeof (data) !== 'object' || data === null) {\r\n return\r\n }\r\n\r\n switch (data.command) {\r\n case 'init':\r\n if (initialized) {\r\n console.warn('chivox-wav-encoder-worker: already initialized!');\r\n return;\r\n }\r\n\r\n try {\r\n resampler = new Resampler(data.fromSampleRate, data.toSampleRate, 1, 2048, false); // 仅支持单声道\r\n } catch (err) {\r\n console.error(\"chivox-wav-encoder-worker: new Resampler error: \", err);\r\n resampler = null;\r\n }\r\n\r\n cachePCM16 = [];\r\n initialized = true;\r\n self.postMessage({ message: 'ready' }); // 必须保证发送ready消息前无异常抛出\r\n break;\r\n\r\n case 'encode':\r\n if (!initialized || !resampler) {\r\n return\r\n }\r\n\r\n const cont = data.content; // data.content is Float32Array\r\n if (!cont || !cont instanceof Float32Array) {\r\n return\r\n }\r\n\r\n try {\r\n const res = resampler.resampler(cont); // res is Float32Array\r\n if (res instanceof Float32Array && res.length > 0) {\r\n const pcm16 = floatTo16BitPCM(res);\r\n const cloned = new Int16Array(pcm16); // 确保这里会clone\r\n cachePCM16.push(cloned);\r\n self.postMessage({ message: 'data', content: pcm16 }, [pcm16.buffer]);\r\n }\r\n } catch (err) {\r\n console.error(\"chivox-wav-encoder-worker: encode error: \", err);\r\n }\r\n break;\r\n\r\n case 'done':\r\n if (!initialized || !resampler) {\r\n resampler = null;\r\n cachePCM16 = [];\r\n initialized = false;\r\n self.postMessage({ message: 'done', audioBlob: null }); // 必须保证发送done消息前无异常抛出\r\n return;\r\n }\r\n\r\n try {\r\n const res = resampler.resampler(new Float32Array(0)); // res is Float32Array\r\n if (res instanceof Float32Array && res.length > 0) {\r\n const pcm16 = floatTo16BitPCM(res);\r\n const cloned = new Int16Array(pcm16); // 确保这里会clone\r\n cachePCM16.push(cloned);\r\n self.postMessage({ message: 'data', content: pcm16 }, [pcm16.buffer]);\r\n }\r\n } catch (err) {\r\n console.error(\"chivox-wav-encoder-worker: encode remaining error: \", err);\r\n }\r\n\r\n let audioBlob = undefined;\r\n try {\r\n let totalLen = 0;\r\n for (const pcm16 of cachePCM16) { // pcm16 is Int16Array\r\n totalLen += pcm16.byteLength;\r\n }\r\n\r\n if (totalLen > 0) {\r\n const header = makeWavHeader(totalLen, resampler.toSampleRate);\r\n audioBlob = new Blob([header, ...cachePCM16], { type: \"audio/wav\" })\r\n }\r\n } catch (err) {\r\n console.error(\"chivox-wav-encoder-worker: makeWavFile error: \", err);\r\n }\r\n\r\n resampler = null;\r\n cachePCM16 = [];\r\n initialized = false;\r\n\r\n // 必须保证发送done消息前无异常抛出\r\n if (audioBlob) {\r\n self.postMessage({ message: 'done', audioBlob: audioBlob }); // blob类型不支持转移所有权\r\n } else {\r\n self.postMessage({ message: 'done', audioBlob: null });\r\n }\r\n break;\r\n\r\n case 'close':\r\n resampler = null;\r\n cachePCM16 = [];\r\n initialized = false;\r\n self.close();\r\n break;\r\n\r\n default:\r\n console.warn(\"chivox-wav-encoder-worker: unknown command:\", data.command);\r\n }\r\n}\r\n`;\r\n\r\nlet codeBlob: Blob | null = null\r\nlet codeUrl: string | null = null\r\n\r\nexport function createWavEncoderWorker(): ResultOk<Worker> | ResultErr<Error> { // 保证这段代码无异常抛出\r\n try {\r\n if (!codeBlob || !codeUrl) {\r\n codeBlob = new Blob([code], { type: 'application/javascript' });\r\n codeUrl = URL.createObjectURL(codeBlob);\r\n }\r\n } catch (err) {\r\n return makeErr(new Error(`createWavEncoderWorker fail: create Blob/URL fail: ${err instanceof Error ? err.message : String(err)}`));\r\n }\r\n\r\n let worker: Worker;\r\n try {\r\n worker = new Worker(codeUrl);\r\n } catch (err) {\r\n return makeErr(new Error(`createWavEncoderWorker fail: new Worker fail: ${err instanceof Error ? err.message : String(err)}`));\r\n }\r\n\r\n // TODO 如果在Worker启动时codeUrl中的代码发生错误,如何捕获\r\n\r\n return makeOk(worker);\r\n}\r\n\r\nexport function cleanupWavEncoderWorkerResources() {\r\n if (codeUrl) {\r\n URL.revokeObjectURL(codeUrl)\r\n codeUrl = null;\r\n codeBlob = null;\r\n }\r\n}","import { ailog } from \"./ailog\";\r\nimport { createAudioContext, getMediaStream } from \"./audioHelper\";\r\nimport { createAudioWorkletNode } from './audioWorkletHelper';\r\nimport { createOpusEncoderWorker } from './opusEncoderHelper';\r\nimport { ifOk, isErr, isOk, makeErr, makeOk, ResultErr, ResultOk } from \"./result\";\r\nimport { catchcall, asyncall } from \"./utils\";\r\nimport { createWavEncoderWorker } from \"./wavEncoderHelper\";\r\n\r\nexport interface RecorderInitOptions {\r\n onInited: () => void\r\n onError: (err: Error) => void\r\n}\r\n\r\nexport type AudioType = 'wav' | 'opus';\r\n\r\nexport interface RecorderStartOptions {\r\n audioType: AudioType\r\n sampleRate: number\r\n onSuccess: () => void\r\n onFail: (err: Error, recoverable: boolean) => void\r\n onDataFrame: (data: ArrayBufferLike) => void\r\n}\r\n\r\nexport interface RecorderStopOptions {\r\n onSuccess: (audioBlob: Blob | null) => void\r\n onFail: (err: Error, recoverable: boolean) => void\r\n}\r\n\r\nenum State {\r\n Initing = 'initing',\r\n Idle = 'idle',\r\n Starting = 'starting',\r\n Started = 'started',\r\n Stopping = 'stopping',\r\n Closed = 'closed',\r\n}\r\n\r\nexport class Recorder {\r\n private state: State\r\n private closing: boolean\r\n\r\n // init时创建的属性\r\n private audioContext: AudioContext | null\r\n private gainNode: GainNode | null\r\n private audioWorkletNode: AudioWorkletNode | null\r\n private opusEncoder: Worker | null\r\n private wavEncoder: Worker | null\r\n\r\n // start时设置或创建的属性\r\n private audioType: AudioType | undefined\r\n private stream: MediaStream | null\r\n private sourceNode: MediaStreamAudioSourceNode | null\r\n\r\n private audioWorkletStarted: boolean\r\n private opusEncoderStarted: boolean\r\n private wavEncoderStarted: boolean\r\n\r\n // starting过程中产生的录音数据-暂存\r\n private pendingRawPCM: Float32Array[]\r\n private pendingOpusData: Uint8Array[]\r\n private pendingWavData: Int16Array[]\r\n\r\n constructor(options: RecorderInitOptions) {\r\n const { onInited, onError } = options;\r\n this.logI(\"[chivox] recorder init\")\r\n\r\n this.state = State.Initing\r\n this.closing = false\r\n\r\n this.audioContext = null\r\n this.gainNode = null\r\n this.audioWorkletNode = null\r\n this.opusEncoder = null\r\n this.wavEncoder = null\r\n\r\n this.audioType = undefined\r\n\r\n this.stream = null\r\n this.sourceNode = null\r\n\r\n this.audioWorkletStarted = false\r\n this.opusEncoderStarted = false\r\n this.wavEncoderStarted = false\r\n\r\n this.pendingRawPCM = []\r\n this.pendingOpusData = []\r\n this.pendingWavData = []\r\n\r\n Promise.resolve()\r\n .then(() => createAudioContext())\r\n .then(ifOk((audioContext) => { // 保证这段代码无异常抛出\r\n this.audioContext = audioContext;\r\n try {\r\n this.gainNode = this.audioContext.createGain()\r\n } catch (err) {\r\n return makeErr(err instanceof Error ? err : new Error(String(err)))\r\n }\r\n return makeOk();\r\n }))\r\n .then(ifOk(() => createAudioWorkletNode(this.audioContext!)))\r\n .then(ifOk((node) => { // 保证这段代码无异常抛出\r\n this.audioWorkletNode = node;\r\n\r\n try {\r\n this.audioWorkletNode.connect(this.audioContext!.destination)\r\n } catch (err) {\r\n return makeErr(err instanceof Error ? err : new Error(String(err)));\r\n }\r\n\r\n const opusRes = createOpusEncoderWorker();\r\n if (isOk(opusRes)) {\r\n this.opusEncoder = opusRes.data;\r\n } else {\r\n return opusRes;\r\n }\r\n\r\n const wavRes = createWavEncoderWorker();\r\n if (isOk(wavRes)) {\r\n this.wavEncoder = wavRes.data;\r\n } else {\r\n return wavRes;\r\n }\r\n\r\n return makeOk();\r\n }))\r\n .then(res => {\r\n if (this.closing) {\r\n this.cleanupInit();\r\n this.state = State.Closed;\r\n this.closing = false;\r\n const err = new Error(`recorder init canceled: close`);\r\n catchcall(() => { onError(err) });\r\n return\r\n }\r\n\r\n if (isErr(res)) {\r\n this.logE(`[chivox] recorder init fail: ${res.err.message}`);\r\n this.cleanupInit()\r\n this.state = State.Closed;\r\n const err = new Error(`recorder init fail: ${res.err.message}`);\r\n catchcall(() => { onError(err) });\r\n return\r\n }\r\n\r\n this.state = State.Idle;\r\n this.logI(\"[chivox] recorder init ok\")\r\n catchcall(() => { onInited() });\r\n })\r\n }\r\n\r\n start(options: RecorderStartOptions): void {\r\n const { audioType, sampleRate, onSuccess, onFail, onDataFrame } = options\r\n this.logI(\"[chivox] recorder start\")\r\n\r\n if (this.state === State.Closed) {\r\n asyncall(() => { onFail(new Error(`recorder start fail: already closed`), true) });\r\n return\r\n }\r\n\r\n if (this.closing) {\r\n asyncall(() => { onFail(new Error(`recorder start fail: closing`), true) });\r\n return\r\n }\r\n\r\n if (this.state === State.Initing) {\r\n asyncall(() => { onFail(new Error(`recorder start fail: init not finished`), true) });\r\n return\r\n }\r\n\r\n if (this.state === State.Starting || this.state === State.Started) {\r\n asyncall(() => { onFail(new Error(`recorder start fail: already started`), true) });\r\n return\r\n }\r\n\r\n if (this.state === State.Stopping) {\r\n asyncall(() => { onFail(new Error(`recorder start fail: stop not finished`), true) });\r\n return\r\n }\r\n\r\n if (this.state !== State.Idle) {\r\n const err = new Error(`recorder start fail: undefined state: ${this.state}`);\r\n asyncall(() => { onFail(err, true) });\r\n return\r\n }\r\n\r\n const audioContext = this.audioContext!;\r\n const gainNode = this.gainNode!;\r\n const audioWorkletNode = this.audioWorkletNode!;\r\n\r\n this.state = State.Starting;\r\n this.audioType = audioType;\r\n\r\n // 这些都是在stop的时候重置的,这里不要重复重置\r\n // this.audioWorkletStarted = false\r\n // this.opusEncoderStarted = false\r\n // this.wavEncoderStarted = false\r\n\r\n this.pendingRawPCM = []\r\n this.pendingOpusData = []\r\n this.pendingWavData = []\r\n\r\n audioContext.resume()\r\n .then(\r\n () => makeOk(),\r\n err => makeErr(new Error(`resume AudioContext fail: ${err instanceof Error ? err.message : String(err)}`))\r\n )\r\n .then(ifOk(() => getMediaStream()))\r\n .then(ifOk((stream) => { // 保证这段代码无异常抛出\r\n this.stream = stream;\r\n try {\r\n this.sourceNode = audioContext.createMediaStreamSource(stream);\r\n } catch (err) {\r\n return makeErr(err instanceof Error ? err : new Error(`${String(err)}`))\r\n }\r\n return makeOk();\r\n }))\r\n .then(ifOk(() => this.startAudioWorklet(audioType)))\r\n .then(ifOk(() => this.startEncoder(audioType, audioContext.sampleRate, sampleRate, onDataFrame)))\r\n .then(ifOk(() => { // 保证这段代码无异常抛出\r\n try {\r\n this.sourceNode!.connect(gainNode);\r\n gainNode.connect(audioWorkletNode);\r\n } catch (err) {\r\n return makeErr(err instanceof Error ? err : new Error(`${String(err)}`))\r\n }\r\n return makeOk();\r\n }))\r\n .then((res) => {\r\n if (isErr(res)) {\r\n this.logE(`[chivox] recorder start fail: ${res.err.message}`);\r\n this.endRecording(audioType).then((endRes) => {\r\n if (this.closing) {\r\n this.cleanupInit();\r\n this.state = State.Closed;\r\n this.closing = false;\r\n const err = new Error(`recorder start fail: ${res.err.message}`)\r\n catchcall(() => { onFail(err, true) });\r\n return\r\n }\r\n\r\n if (isErr(endRes)) {\r\n this.cleanupInit();\r\n this.state = State.Closed;\r\n const err = new Error(`recorder start fail: ${endRes.err.message} : ${res.err.message}`)\r\n catchcall(() => { onFail(err, false) }); // 不可恢复错误\r\n return\r\n }\r\n\r\n this.state = State.Idle;\r\n const err = new Error(`recorder start fail: ${res.err.message}`)\r\n catchcall(() => { onFail(err, true) });\r\n })\r\n return\r\n }\r\n\r\n if (this.closing) {\r\n this.endRecording(audioType).then((_) => {\r\n this.cleanupInit();\r\n this.state = State.Closed;\r\n this.closing = false;\r\n const err = new Error(`recorder start canceled: close`);\r\n catchcall(() => { onFail(err, true) });\r\n })\r\n return\r\n }\r\n\r\n this.state = State.Started;\r\n this.logI(\"[chivox] recorder start ok\");\r\n catchcall(() => { onSuccess() });\r\n\r\n for (const data of this.pendingRawPCM) {\r\n this.feedEncoder(audioType, data); // 会移走 data.buffer 的所有权\r\n }\r\n this.pendingRawPCM = [];\r\n\r\n if (audioType === 'opus') {\r\n for (const data of this.pendingOpusData) {\r\n const buffer = data.buffer;\r\n catchcall(() => { onDataFrame(buffer) });\r\n }\r\n this.pendingOpusData = [];\r\n } else if (audioType === 'wav') {\r\n for (const data of this.pendingWavData) {\r\n const buffer = data.buffer;\r\n catchcall(() => { onDataFrame(buffer) });\r\n }\r\n this.pendingWavData = [];\r\n }\r\n });\r\n }\r\n\r\n stop(options: RecorderStopOptions): void {\r\n const { onSuccess, onFail } = options;\r\n this.logI(\"[chivox] recorder stop\")\r\n\r\n if (this.state === State.Closed) {\r\n const err = new Error(`recorder stop fail: already closed`);\r\n asyncall(() => onFail(err, true));\r\n return\r\n }\r\n\r\n if (this.closing) {\r\n const err = new Error(`recorder stop fail: closing`);\r\n asyncall(() => onFail(err, true));\r\n return\r\n }\r\n\r\n if (this.state === State.Initing) {\r\n const err = new Error(`recorder stop fail: init not finished`)\r\n asyncall(() => onFail(err, true));\r\n return\r\n }\r\n\r\n if (this.state === State.Idle) {\r\n const err = new Error(`recorder stop fail: not start`)\r\n asyncall(() => onFail(err, true));\r\n return\r\n }\r\n\r\n if (this.state === State.Starting) {\r\n const err = new Error(`recorder stop fail: start not finished`)\r\n asyncall(() => onFail(err, true));\r\n return\r\n }\r\n\r\n if (this.state === State.Stopping) {\r\n const err = new Error(`recorder stop fail: already stopping`)\r\n asyncall(() => onFail(err, true));\r\n return\r\n }\r\n\r\n if (this.state !== State.Started) {\r\n const err = new Error(`recorder stop fail: undefined state: ${this.state}`)\r\n asyncall(() => onFail(err, true));\r\n return\r\n }\r\n\r\n this.state = State.Stopping;\r\n this.endRecording(this.audioType!).then((res) => {\r\n if (isErr(res)) {\r\n this.logE(`[chivox] recorder stop fail: ${res.err.message}`);\r\n this.cleanupInit();\r\n this.state = State.Closed;\r\n this.closing = false;\r\n const err = new Error(`recorder stop fail: ${res.err.message}`)\r\n catchcall(() => { onFail(err, false) })\r\n return\r\n }\r\n\r\n this.logI(\"[chivox] recorder stop ok\");\r\n\r\n if (this.closing) {\r\n this.cleanupInit()\r\n this.state = State.Closed;\r\n this.closing = false;\r\n catchcall(() => { onSuccess(res.data) });\r\n return\r\n }\r\n\r\n this.state = State.Idle\r\n catchcall(() => { onSuccess(res.data) });\r\n })\r\n }\r\n\r\n close() {\r\n this.logI(`[chivox] recorder close`)\r\n\r\n if (this.state === State.Closed || this.closing) {\r\n return\r\n }\r\n\r\n this.closing = true;\r\n\r\n if (this.state === State.Initing) {\r\n return\r\n }\r\n\r\n if (this.state === State.Idle) {\r\n this.cleanupInit()\r\n this.state = State.Closed;\r\n this.closing = false;\r\n return\r\n }\r\n\r\n if (this.state === State.Starting) {\r\n return;\r\n }\r\n\r\n if (this.state === State.Started) {\r\n this.endRecording(this.audioType!).then((_) => {\r\n this.cleanupInit();\r\n this.state = State.Closed;\r\n this.closing = false;\r\n })\r\n return\r\n }\r\n\r\n if (this.state === State.Stopping) {\r\n return;\r\n }\r\n }\r\n\r\n getMicVolume(): number {\r\n if (this.gainNode) {\r\n try {\r\n return this.gainNode.gain.value;\r\n } catch (err) {\r\n return 0\r\n }\r\n } else {\r\n return 0\r\n }\r\n }\r\n\r\n setMicVolume(volume: number) {\r\n if (this.gainNode) {\r\n try {\r\n this.gainNode.gain.value = volume;\r\n } catch (err) {\r\n console.error(err)\r\n }\r\n }\r\n }\r\n\r\n private cleanupInit() {\r\n this.logI(\"[chivox] recorder cleanupInit\")\r\n\r\n if (this.opusEncoder) {\r\n this.opusEncoder.postMessage({ command: \"close\" });\r\n this.opusEncoder = null;\r\n }\r\n\r\n if (this.wavEncoder) {\r\n this.wavEncoder.postMessage({ command: \"close\" });\r\n this.wavEncoder = null\r\n }\r\n\r\n if (this.audioWorkletNode) {\r\n this.audioWorkletNode.disconnect();\r\n this.audioWorkletNode.port.close(); // 这步是必要的\r\n this.audioWorkletNode = null;\r\n }\r\n\r\n if (this.gainNode) {\r\n this.gainNode = null\r\n }\r\n\r\n if (this.audioContext) {\r\n this.audioContext.close().catch(err => {\r\n this.logW(`[chivox] recorder revertInit catched: close AudioContext fail: ${err instanceof Error ? err.message : String(err)}`)\r\n })\r\n this.audioContext = null\r\n }\r\n }\r\n\r\n private endRecording(audioType: AudioType): Promise<ResultOk<Blob | null> | ResultErr<Error>> {\r\n this.logI(`[chivox] recorder endRecording`)\r\n return Promise.resolve()\r\n .then(() => { // 保证这段代码无异常抛出\r\n try {\r\n if (this.sourceNode) {\r\n this.sourceNode.disconnect()\r\n this.sourceNode = null\r\n }\r\n } catch (err) { // 发生此异常后,录音机可以再次使用\r\n this.logW(\"[chivox] recorder endRecording catched: \", err)\r\n }\r\n\r\n try {\r\n if (this.gainNode) {\r\n this.gainNode.disconnect()\r\n }\r\n } catch (err) { // 发生此异常后,录音机可以再次使用\r\n this.logW(\"[chivox] recorder endRecording catched: \", err)\r\n }\r\n\r\n return makeOk()\r\n })\r\n .then((_: ResultOk<void>) => this.stopAudioWorklet())\r\n .then((_: ResultOk<void>) => this.stopEncoder(audioType))\r\n .then((res: ResultOk<Blob | null>) => { // 保证这段代码无异常抛出\r\n let streamErr: Error | null = null;\r\n try {\r\n if (this.stream) { // 这里如果异常,录音机不可再次使用\r\n this.stream.getTracks().forEach(track => track.stop()); // TODO 如果这里异常的话,后续强行对stream置null,会发生什么\r\n this.stream = null;\r\n }\r\n } catch (err) {\r\n this.logE(`[chivox] recorder endRecording error: ${err instanceof Error ? err.message : String(err)}`);\r\n streamErr = new Error(`endRecording error: ${err instanceof Error ? err.message : String(err)}`);\r\n }\r\n\r\n this.pendingRawPCM = [];\r\n this.pendingOpusData = [];\r\n this.pendingWavData = [];\r\n\r\n if (streamErr) {\r\n return makeErr(streamErr)\r\n }\r\n\r\n this.logI(`[chivox] recorder endRecording ok`)\r\n return makeOk(res.data);\r\n })\r\n }\r\n\r\n private startAudioWorklet(audioType: AudioType): Promise<ResultOk<void> | ResultErr<Error>> {\r\n if (this.audioWorkletStarted) {\r\n return Promise.resolve(makeErr(new Error(`startAudioWorklet fail: repeat start`)));\r\n }\r\n\r\n const audioWorkletNode = this.audioWorkletNode!;\r\n this.audioWorkletStarted = true;\r\n\r\n return new Promise<ResultOk<void> | ResultErr<Error>>(resolve => { // 保证这段代码无异常抛出\r\n const callback = ({ data }: MessageEvent) => {\r\n // TODO 这里发送init之后增加个超时等待ready\r\n if (typeof (data) !== 'object' || data === null) {\r\n return;\r\n }\r\n\r\n switch (data.message) {\r\n case 'ready':\r\n resolve(makeOk());\r\n break;\r\n\r\n case 'data':\r\n const cont = data.content; // data.content is Float32Array\r\n if (cont && cont instanceof Float32Array) {\r\n if (this.state === State.Starting) {\r\n this.pendingRawPCM.push(cont);\r\n } else if (this.state === State.Started || this.state === State.Stopping) {\r\n this.feedEncoder(audioType, cont); // 会移走 cont.buffer 的所有权\r\n }\r\n }\r\n break;\r\n\r\n case 'done':\r\n audioWorkletNode.port.removeEventListener(\"message\", callback);\r\n break;\r\n }\r\n };\r\n\r\n audioWorkletNode.port.addEventListener('message', callback);\r\n audioWorkletNode.port.start()\r\n audioWorkletNode.port.postMessage({ command: 'init' }) // audioWorkletNode保证在收到'init'消息之后一定发送'ready'消息\r\n })\r\n }\r\n\r\n private startEncoder(audioType: AudioType, fromSampleRate: number, toSampleRate: number, onDataFrame: (data: ArrayBufferLike) => void): Promise<ResultOk<void> | ResultErr<Error>> {\r\n if (audioType === 'opus') {\r\n return this.startOpusEncoder(fromSampleRate, toSampleRate, onDataFrame)\r\n } else if (audioType === 'wav') {\r\n return this.startWavEncoder(fromSampleRate, toSampleRate, onDataFrame)\r\n }\r\n return Promise.resolve(makeOk());\r\n }\r\n\r\n private startOpusEncoder(fromSampleRate: number, toSampleRate: number, onDataFrame: (data: ArrayBufferLike) => void): Promise<ResultOk<void> | ResultErr<Error>> {\r\n if (this.opusEncoderStarted) {\r\n return Promise.resolve(makeErr(new Error(`startOpusEncoder fail: repeat start`)));\r\n }\r\n\r\n const opusEncoder = this.opusEncoder!;\r\n this.opusEncoderStarted = true;\r\n\r\n return new Promise<ResultOk<void> | ResultErr<Error>>(resolve => { // 保证这段代码无抛出异常\r\n // TODO 这里发送init之后增加个超时等待ready\r\n const callback = ({ data }: MessageEvent) => {\r\n if (typeof (data) !== 'object' || data === null) {\r\n return;\r\n }\r\n\r\n switch (data.message) {\r\n case 'ready':\r\n resolve(makeOk());\r\n break;\r\n\r\n case 'page':\r\n const page = data['page'];\r\n if (page && page instanceof Uint8Array) {\r\n if (this.state === State.Starting) {\r\n this.pendingOpusData.push(page);\r\n } else if (this.state === State.Started || this.state === State.Stopping) {\r\n catchcall(() => { onDataFrame(page.buffer) });\r\n }\r\n }\r\n break;\r\n\r\n case 'done':\r\n opusEncoder.removeEventListener(\"message\", callback);\r\n break;\r\n }\r\n };\r\n\r\n opusEncoder.addEventListener('message', callback);\r\n opusEncoder.postMessage({ command: 'init', originalSampleRate: fromSampleRate, encoderSampleRate: toSampleRate, numberOfChannels: 1 }) // resampleQuality: 3, // Value between 0 and 10 inclusive. 10 being highest quality.\r\n });\r\n }\r\n\r\n private startWavEncoder(fromSampleRate: number, toSampleRate: number, onDataFrame: (data: ArrayBufferLike) => void): Promise<ResultOk<void> | ResultErr<Error>> {\r\n if (this.wavEncoderStarted) {\r\n return Promise.resolve(makeErr(new Error(`startWavEncoder fail: repeat start`)));\r\n }\r\n\r\n const wavEncoder = this.wavEncoder!;\r\n this.wavEncoderStarted = true;\r\n\r\n return new Promise<ResultOk<void> | ResultErr<Error>>(resolve => { // 保证这段代码无抛出异常\r\n // TODO 这里发送init之后增加个超时等待ready\r\n const callback = ({ data }: MessageEvent) => {\r\n if (typeof (data) !== 'object' || data === null) {\r\n return;\r\n }\r\n\r\n switch (data.message) {\r\n case 'ready':\r\n resolve(makeOk());\r\n break;\r\n\r\n case 'data':\r\n const cont = data.content; // data.content is Int16Array\r\n if (cont && cont instanceof Int16Array) {\r\n if (this.state === State.Starting) {\r\n this.pendingWavData.push(cont);\r\n } else if (this.state === State.Started || this.state === State.Stopping) {\r\n catchcall(() => { onDataFrame(cont.buffer) });\r\n }\r\n }\r\n break;\r\n\r\n case 'done':\r\n wavEncoder.removeEventListener(\"message\", callback);\r\n break;\r\n }\r\n };\r\n\r\n wavEncoder.addEventListener('message', callback);\r\n wavEncoder.postMessage({ command: 'init', fromSampleRate: fromSampleRate, toSampleRate: toSampleRate })\r\n })\r\n }\r\n\r\n private feedEncoder(audioType: AudioType, content: Float32Array) { // 会移走 content.buffer 的所有权\r\n if (audioType === 'opus') {\r\n if (this.opusEncoder && this.opusEncoderStarted) {\r\n this.opusEncoder.postMessage({ command: 'encode', buffers: [content] }, [content.buffer]);\r\n }\r\n } else if (audioType === 'wav') {\r\n if (this.wavEncoder && this.wavEncoderStarted) {\r\n this.wavEncoder.postMessage({ command: 'encode', content: content }, [content.buffer]);\r\n }\r\n }\r\n }\r\n\r\n private stopAudioWorklet(): Promise<ResultOk<void>> {\r\n if (this.audioWorkletStarted) {\r\n const audioWorkletNode = this.audioWorkletNode!;\r\n\r\n return new Promise<ResultOk<void>>(resolve => { // 保证这段代码无异常抛出\r\n const callback = ({ data }: MessageEvent) => {\r\n if (typeof (data) !== 'object' || data === null) {\r\n return\r\n }\r\n\r\n if (data.message === 'done') {\r\n audioWorkletNode.port.removeEventListener(\"message\", callback);\r\n resolve(makeOk());\r\n }\r\n };\r\n\r\n audioWorkletNode.port.addEventListener(\"message\", callback);\r\n audioWorkletNode.port.postMessage({ command: \"done\" });\r\n this.audioWorkletStarted = false;\r\n })\r\n }\r\n return Promise.resolve(makeOk())\r\n }\r\n\r\n private stopEncoder(audioType: AudioType): Promise<ResultOk<Blob | null>> {\r\n if (audioType === 'opus') {\r\n return this.stopOpusEncoder()\r\n } else if (audioType === 'wav') {\r\n return this.stopWavEncoder()\r\n }\r\n return Promise.resolve(makeOk(null))\r\n }\r\n\r\n private stopOpusEncoder(): Promise<ResultOk<Blob | null>> {\r\n if (this.opusEncoderStarted) {\r\n const opusEncoder = this.opusEncoder!;\r\n\r\n return new Promise<ResultOk<Blob | null>>(resolve => { // 保证这段代码无异常抛出\r\n const callback = ({ data }: MessageEvent) => {\r\n if (typeof (data) !== 'object' || data === null) {\r\n return\r\n }\r\n\r\n if (data.message === 'done') {\r\n opusEncoder.removeEventListener(\"message\", callback);\r\n const audioBlob = data.audioBlob ? (data.audioBlob as Blob) : null;\r\n resolve(makeOk(audioBlob));\r\n }\r\n };\r\n\r\n opusEncoder.addEventListener(\"message\", callback);\r\n opusEncoder.postMessage({ command: \"done\" });\r\n this.opusEncoderStarted = false;\r\n })\r\n }\r\n return Promise.resolve(makeOk(null))\r\n }\r\n\r\n private stopWavEncoder(): Promise<ResultOk<Blob | null>> {\r\n if (this.wavEncoderStarted) {\r\n const wavEncoder = this.wavEncoder!;\r\n\r\n return new Promise<ResultOk<Blob | null>>(resolve => { // 保证这段代码无异常抛出\r\n const callback = ({ data }: MessageEvent) => {\r\n if (typeof (data) !== 'object' || data === null) {\r\n return\r\n }\r\n\r\n if (data.message === 'done') {\r\n wavEncoder.removeEventListener(\"message\", callback);\r\n const audioBlob = data.audioBlob ? (data.audioBlob as Blob) : null;\r\n resolve(makeOk(audioBlob));\r\n }\r\n };\r\n\r\n wavEncoder.addEventListener('message', callback)\r\n wavEncoder.postMessage({ command: \"done\" });\r\n this.wavEncoderStarted = false;\r\n });\r\n }\r\n return Promise.resolve(makeOk(null))\r\n }\r\n\r\n private logE(...data: any[]) {\r\n ailog.error(...data)\r\n }\r\n\r\n private logW(...data: any[]) {\r\n ailog.warn(...data)\r\n }\r\n\r\n private logI(...data: any[]) {\r\n ailog.info(...data)\r\n }\r\n\r\n private logD(...data: any[]) {\r\n ailog.debug(...data);\r\n }\r\n}","import { makeErr, makeOk, ResultErr, ResultOk } from \"./result\";\n\nexport function createAudioContext(): Promise<ResultOk<AudioContext> | ResultErr<Error>> {\n return (async () => { // 保证这段代码无异常抛出\n const AudioContextConstructor = AudioContext ||\n (globalThis as any).webkitAudioContext ||\n (globalThis as any).mozAudioContext ||\n (globalThis as any).msAudioContext;\n\n if (!AudioContextConstructor) {\n return makeErr(new Error(\"Current browser does not support AudioContext\"));\n }\n\n let audioContext;\n try {\n audioContext = new AudioContextConstructor();\n } catch (err) {\n return makeErr(new Error(`Failed to create AudioContext: ${err instanceof Error ? err.message : String(err)}`));\n }\n\n if (audioContext.state === 'suspended') {\n try {\n await audioContext.resume();\n } catch (err) {\n return makeErr(new Error(\"Audio activation requires user interaction. Please click anywhere on the page first.\"));\n }\n }\n\n return makeOk(audioContext);\n })()\n}\n\nexport function getMediaStream(): Promise<ResultOk<MediaStream> | ResultErr<Error>> {\n return (async () => { // 保证这段代码无异常抛出\n let stream: MediaStream | null = null\n let lastErr: Error | null = null;\n\n try {\n stream = await globalThis.navigator.mediaDevices.getUserMedia({ audio: true, video: false });\n } catch (err) {\n if (err instanceof Error) {\n lastErr = err;\n } else {\n lastErr = new Error(`getUserMedia: unknown error: ${String(err)}`);\n }\n }\n\n if (stream) {\n return makeOk(stream);\n }\n\n if (!lastErr) {\n return makeErr(new Error(\"failed to obtain media stream, unknown error\"));\n }\n\n switch (lastErr.name) {\n case 'NotAllowedError':\n return makeErr(new Error(\"user denied microphone permission, please allow access in browser settings\"));\n case 'NotFoundError':\n return makeErr(new Error(\"no available microphone device detected\"));\n case 'AbortError':\n return makeErr(new Error(\"microphone access was interrupted, please check if the device is working properly\"));\n case 'NotReadableError':\n return makeErr(new Error(\"microphone device is not accessible, it may be occupied by another program\"));\n case 'OverconstrainedError':\n return makeErr(new Error(`unable to satisfy audio constraints: ${lastErr.message}`));\n default:\n return makeErr(new Error(`failed to obtain microphone: ${lastErr.message}`));\n }\n })()\n}\n","\r\nexport const DEFAULT_SERVER = \"wss://cloud.chivox.com\"\r\nexport const DEFAULT_SERVER_TIMEOUT = 60\r\n\r\n","export const VERSION_HEX_STR = \"0x07010000\"\r\nexport const VERSION_INT = parseInt(VERSION_HEX_STR, 16)\r\n\r\nexport function getVersionStr() {\r\n let verStr = \"\";\r\n let part = (VERSION_INT & 0xff000000) >> 24;\r\n verStr += part.toString();\r\n part = (VERSION_INT & 0x00ff0000) >> 16;\r\n verStr += \".\" + part.toString();\r\n part = (VERSION_INT & 0x0000ff00) >> 8;\r\n verStr += \".\" + part.toString();\r\n part = (VERSION_INT & 0x000000ff);\r\n if (part !== 0) {\r\n verStr += \".\" + part.toString();\r\n }\r\n return verStr;\r\n}","export const EID = {\r\n // 50003 - 没有音频输入设备录音机 (6.x, 5.x)\r\n SERVER_TIMEOUT: 50201, // 等待评分结果超时\r\n\r\n RECORDER_INIT_FAIL: 70001, // 录音机初始化失败\r\n BUSY_RECORDING: 70002, // 录音机正在进行上一次录音\r\n BUSY_INITING: 70003, // 引擎初始化正在进行中\r\n RECORDER_START_FAIL: 70004, // 录音机开始录音失败\r\n RECORDER_STOP_FAIL: 70005, // 录音机停止录音失败\r\n ENGINE_BROKEN: 70006, // 引擎运行异常\r\n ENGINE_DISPOSED: 70007, // 引擎已经销毁\r\n CALL_ORDER: 70008, // AISession接口调用顺序错误\r\n\r\n // 71001 - websocket连接数超过最大连接数四个 (6.x)\r\n\r\n // 72001 - 没有音频输入设备 (6.x)\r\n\r\n NETWORK: 73001, // websocket连接错误\r\n RESULT_NJ: 73002, // 服务器返回评测结果不是合法json\r\n EVAL_CANCELED: 73003, // 评测已取消\r\n INNER_ERR: 73004, // 内部错误\r\n\r\n // 75001 75002 75003 75004 75006 (6.x)\r\n PARAM_ERR: 75006, // 输入参数错误\r\n}\r\n","\r\nimport { DEFAULT_SERVER, DEFAULT_SERVER_TIMEOUT } from \"./consts\";\r\nimport { VERSION_HEX_STR } from \"./version\";\r\nimport { uuid } from \"./utils\";\r\nimport { EID } from \"./errid\";\r\n\r\nexport interface AISessionError {\r\n errId: number\r\n error: string\r\n [key: string]: any;\r\n}\r\n\r\nexport interface AISessionEvalScore {\r\n [key: string]: any\r\n}\r\n\r\nexport interface AISessionCfg {\r\n cloud?: AISessionCloudCfg;\r\n}\r\n\r\nexport interface AISessionCloudCfg {\r\n server?: string;\r\n serverTimeout?: number;\r\n}\r\n\r\nexport interface AISessionStartParam {\r\n app: AISessionStartParamApp;\r\n audio: AISessionStartParamAudio;\r\n request: AISessionStartParamRequest;\r\n}\r\n\r\nexport interface AISessionStartParamApp {\r\n applicationId: string\r\n sig: string\r\n alg: string\r\n timestamp: string\r\n userId?: string\r\n}\r\n\r\nexport interface AISessionStartParamAudio {\r\n audioType: string;\r\n channel: number;\r\n sampleBytes: number;\r\n sampleRate: number;\r\n}\r\n\r\nexport interface AISessionStartParamRequest {\r\n [key: string]: any\r\n}\r\n\r\nenum AISessionState {\r\n None = 'none',\r\n Connecting = 'connecting',\r\n FeedingBuf = 'feeding_buf',\r\n Feeding = 'feeding',\r\n End = 'end',\r\n}\r\n\r\nfunction makeError(errId: number, error: string): AISessionError {\r\n return { errId, error }\r\n}\r\n\r\nexport class AISession {\r\n private _server: string\r\n private _serverTimeout: number\r\n private _state: AISessionState\r\n private _isStarted: boolean\r\n private _isStopped: boolean\r\n private readonly _tokenId: string\r\n private _param?: AISessionStartParam\r\n private _datas: ArrayBufferLike[]\r\n private _websocket?: WebSocket\r\n private _waitTimerId?: number\r\n\r\n constructor(cfg: AISessionCfg) {\r\n const { cloud = {} } = cfg;\r\n\r\n let { server = DEFAULT_SERVER, serverTimeout = DEFAULT_SERVER_TIMEOUT } = cloud;\r\n server = server.replace(/\\/+$/g, '');\r\n if (serverTimeout <= 0) {\r\n serverTimeout = DEFAULT_SERVER_TIMEOUT;\r\n }\r\n\r\n this._server = server;\r\n this._serverTimeout = serverTimeout;\r\n this._state = AISessionState.None;\r\n this._isStarted = false;\r\n this._isStopped = false;\r\n this._tokenId = uuid();\r\n this._param = undefined;\r\n this._datas = [];\r\n this._websocket = undefined;\r\n this._waitTimerId = undefined;\r\n }\r\n\r\n getTokenId(): string {\r\n return this._tokenId;\r\n }\r\n\r\n resultCb?: (res: ArrayBuffer | AISessionEvalScore | AISessionError) => void = undefined\r\n\r\n start(param: AISessionStartParam) {\r\n // console.log(\"start\")\r\n if (this._state === AISessionState.End) {\r\n // console.log(\"start: state is end\")\r\n return\r\n }\r\n\r\n if (this._isStopped) {\r\n this._endWithCallback(makeError(EID.CALL_ORDER, \"don't call start again after stop\"))\r\n return\r\n }\r\n\r\n if (this._isStarted) {\r\n this._endWithCallback(makeError(EID.CALL_ORDER, \"don't call start twice\"))\r\n return\r\n }\r\n this._isStarted = true;\r\n\r\n // assert\r\n if (this._state !== AISessionState.None) {\r\n // console.log(\"start: assert\")\r\n this._endWithCallback(makeError(EID.INNER_ERR, `inner error: start at state: ${this._state}`))\r\n return\r\n }\r\n\r\n if (typeof (param) !== 'object' || param == null) {\r\n this._endWithCallback(makeError(EID.PARAM_ERR, \"invalid param\"))\r\n return\r\n }\r\n\r\n if (param.app == null) {\r\n this._endWithCallback(makeError(EID.PARAM_ERR, \"param error: no 'app'\"))\r\n return\r\n }\r\n if (typeof (param.app) !== 'object') {\r\n this._endWithCallback(makeError(EID.PARAM_ERR, \"param error: invalid 'app'\"))\r\n return\r\n }\r\n if (param.app.applicationId == null || param.app.applicationId === \"\") {\r\n this._endWithCallback(makeError(EID.PARAM_ERR, \"param error: no 'app.applicationId'\"))\r\n return\r\n }\r\n if (typeof (param.app.applicationId) !== 'string') {\r\n this._endWithCallback(makeError(EID.PARAM_ERR, \"param error: invalid 'app.applicationId'\"))\r\n return\r\n }\r\n\r\n if (param.audio == null) {\r\n this._endWithCallback(makeError(EID.PARAM_ERR, \"param error: no 'audio'\"))\r\n return\r\n }\r\n if (typeof (param.audio) !== 'object') {\r\n this._endWithCallback(makeError(EID.PARAM_ERR, \"param error: invalid 'audio'\"))\r\n return\r\n }\r\n\r\n if (param.request == null) {\r\n this._endWithCallback(makeError(EID.PARAM_ERR, \"param error: no 'request'\"))\r\n return\r\n }\r\n if (typeof (param.request) !== 'object') {\r\n this._endWithCallback(makeError(EID.PARAM_ERR, \"param error: invalid 'request'\"))\r\n return\r\n }\r\n if (param.request.coreType == null || param.request.coreType === \"\") {\r\n this._endWithCallback(makeError(EID.PARAM_ERR, \"param error: no 'request.coreType'\"))\r\n return\r\n }\r\n if (typeof (param.request.coreType) !== 'string') {\r\n this._endWithCallback(makeError(EID.PARAM_ERR, \"param error: invalid 'request.coreType'\"))\r\n return\r\n }\r\n\r\n const { applicationId } = param.app\r\n const { coreType, res } = param.request\r\n\r\n this._param = {\r\n app: Object.assign({}, param.app),\r\n audio: Object.assign({}, param.audio),\r\n request: Object.assign({}, param.request),\r\n }\r\n this._isStarted = true;\r\n\r\n // console.log(\"state -> connecting\")\r\n this._state = AISessionState.Connecting;\r\n\r\n let url;\r\n if (res) {\r\n url = `${this._server}/${coreType}/${res}?e=0&t=0&appKey=${applicationId}`\r\n } else {\r\n url = `${this._server}/${coreType}?e=0&t=0&appKey=${applicationId}`\r\n }\r\n this._websocket = new WebSocket(url);\r\n this._websocket.binaryType = \"arraybuffer\";\r\n this._websocket.onopen = () => { this._onWebsocketOpen() };\r\n this._websocket.onmessage = (ev) => { this._onWebsocketMessage(ev) };\r\n this._websocket.onerror = (ev) => { this._onWebsocketError(ev) };\r\n this._websocket.onclose = (ev) => { this._onWebsocketClose(ev) };\r\n }\r\n\r\n private _onWebsocketOpen() {\r\n // console.log(\"_onWebsocketOpen\")\r\n if (this._state === AISessionState.End) {\r\n // console.log(\"_onWebsocketOpen: state is end\")\r\n return\r\n }\r\n\r\n // assert\r\n if (this._state !== AISessionState.Connecting) {\r\n // console.log(\"_onWebsocketOpen: assert\")\r\n this._endWithCallback(makeError(EID.INNER_ERR, `inner error: _onWebsocketOpen at state: ${this._state}`))\r\n return\r\n }\r\n\r\n if (this._websocket?.readyState === WebSocket.OPEN) {\r\n // console.log(\"send connect\")\r\n this._websocket.send(JSON.stringify({\r\n cmd: \"connect\",\r\n param: {\r\n app: this._param?.app,\r\n sdk: {\r\n version: VERSION_HEX_STR,\r\n source: \"4\", // 4 for Html5\r\n protocol: \"1\", // 1 for websocket\r\n }\r\n }\r\n }))\r\n\r\n // console.log(\"send start\")\r\n this._websocket.send(JSON.stringify({\r\n cmd: \"start\",\r\n param: {\r\n tokenId: this._tokenId,\r\n audio: this._param?.audio,\r\n request: this._param?.request,\r\n app: this._param?.app,\r\n sdk: {\r\n version: VERSION_HEX_STR,\r\n source: \"4\", // 4 for Html5\r\n protocol: \"1\", // 1 for websocket\r\n }\r\n }\r\n }))\r\n }\r\n\r\n // console.log(\"state -> feeding_buf\")\r\n this._state = AISessionState.FeedingBuf\r\n this._feedBuf()\r\n }\r\n\r\n private _onWebsocketMessage(ev: MessageEvent) {\r\n // console.log(\"_onWebsocketMessage\")\r\n if (this._state === AISessionState.End) {\r\n // console.log(\"_onWebsocketMessage: state is end\")\r\n return\r\n }\r\n\r\n if (typeof (ev.data) === 'string') {\r\n // console.log(`string message: ${evt.data}`)\r\n let json: AISessionEvalScore | AISessionError;\r\n try {\r\n json = JSON.parse(ev.data);\r\n } catch (err) {\r\n // console.log(`json parse error: ${err}`)\r\n this._endWithCallback(makeError(EID.RESULT_NJ, \"server result not json\"));\r\n return\r\n }\r\n\r\n // console.log(`eof: ${json.eof}`)\r\n if (json.eof == null || json.eof == undefined) {\r\n // console.log(\"no eof\")\r\n json.eof = 1\r\n }\r\n\r\n if (json.errId || json.eof !== 0) {\r\n this._endWithCallback(json)\r\n } else { // TODO test\r\n this._doCallback(json)\r\n }\r\n return\r\n } else { // TODO test\r\n // console.log(\"bin message\")\r\n this._endWithCallback(ev.data)\r\n return\r\n }\r\n }\r\n\r\n private _onWebsocketClose(ev: CloseEvent) {\r\n const { wasClean, code, reason } = ev ?? {}\r\n // console.log(`_onWebsocketClose: wasClean=${wasClean}, code=${code}, reason=${reason}`)\r\n\r\n if (this._state === AISessionState.End) {\r\n // console.log(\"_onWebsocketClose: state is end\")\r\n return\r\n }\r\n\r\n if (this._state === AISessionState.Connecting) {\r\n // console.log(\"_onWebsocketClose: state is connecting\")\r\n this._endWithCallback(makeError(EID.NETWORK, `websocket connect fail, receive close: wasClean=${wasClean}, code=${code}, reason=${reason}`))\r\n return\r\n } else {\r\n // console.log(\"_onWebsocketClose: state is not connecting\")\r\n this._endWithCallback(makeError(EID.NETWORK, `network exception: receive close: wasClean=${wasClean}, code=${code}, reason=${reason}`))\r\n return\r\n }\r\n }\r\n\r\n private _onWebsocketError(ev: Event) {\r\n // 不处理,仅在close中处理\r\n }\r\n\r\n private _onWaitTimeout() {\r\n // console.log(\"_onWaitTimeout\")\r\n if (this._state === AISessionState.End) {\r\n // console.log(\"_onWaitTimeout: state is end\")\r\n return\r\n }\r\n\r\n this._waitTimerId = undefined\r\n this._endWithCallback(makeError(EID.SERVER_TIMEOUT, \"server timeout\"))\r\n }\r\n\r\n private _feedBuf() {\r\n // console.log(\"_feedBuf\")\r\n if (this._state === AISessionState.End) {\r\n // console.log(\"_feedBuf: state is end\")\r\n return\r\n }\r\n\r\n // assert\r\n if (this._state !== AISessionState.FeedingBuf) {\r\n // console.log(\"_feedBuf: assert\")\r\n this._endWithCallback(makeError(EID.INNER_ERR, `inner error: _feedBuf at state: ${this._state}`))\r\n return\r\n }\r\n\r\n if (this._datas.length > 0) {\r\n const data = this._datas.shift()\r\n if (data != null) {\r\n // console.log(\"send data\")\r\n if (this._websocket?.readyState === WebSocket.OPEN) {\r\n this._websocket.send(data)\r\n }\r\n }\r\n setTimeout(() => {\r\n this._feedBuf()\r\n }, 0)\r\n return\r\n }\r\n\r\n if (this._isStopped) {\r\n // console.log(\"send stop\")\r\n if (this._websocket?.readyState === WebSocket.OPEN) {\r\n this._websocket.send(JSON.stringify({\r\n cmd: \"stop\"\r\n }))\r\n }\r\n }\r\n\r\n // console.log(\"state -> feeding\");\r\n this._state = AISessionState.Feeding;\r\n return\r\n }\r\n\r\n feed(data: ArrayBufferLike) {\r\n // console.log(\"feed\")\r\n if (this._state === AISessionState.End) {\r\n // console.log(\"feed: state is end\")\r\n return\r\n }\r\n\r\n if (!this._isStarted) {\r\n this._endWithCallback(makeError(EID.CALL_ORDER, \"don't feed before start\"))\r\n return\r\n }\r\n\r\n if (this._isStopped) {\r\n this._endWithCallback(makeError(EID.CALL_ORDER, \"don't feed after stop\"))\r\n return\r\n }\r\n\r\n if (data == null || data.byteLength == null || data.byteLength == 0) {\r\n return\r\n }\r\n\r\n if (this._state === AISessionState.Connecting || this._state === AISessionState.FeedingBuf) {\r\n // console.log(\"buffer data\")\r\n this._datas.push(data)\r\n } else if (this._state === AISessionState.Feeding) {\r\n // console.log(\"send data\")\r\n if (this._websocket?.readyState === WebSocket.OPEN) {\r\n this._websocket.send(data)\r\n }\r\n }\r\n }\r\n\r\n stop() {\r\n // console.log(\"stop\")\r\n if (this._state === AISessionState.End) {\r\n // console.log(\"stop: state is end\")\r\n return\r\n }\r\n\r\n if (!this._isStarted) {\r\n this._endWithCallback(makeError(EID.CALL_ORDER, \"don't stop before start\"))\r\n return\r\n }\r\n\r\n if (this._isStopped) {\r\n this._endWithCallback(makeError(EID.CALL_ORDER, \"don't stop twice\"))\r\n return\r\n }\r\n this._isStopped = true\r\n\r\n if (this._state === AISessionState.Feeding) {\r\n // console.log(\"send stop\")\r\n if (this._websocket?.readyState === WebSocket.OPEN) {\r\n this._websocket.send(JSON.stringify({\r\n cmd: \"stop\"\r\n }))\r\n }\r\n }\r\n\r\n this._waitTimerId = setTimeout(() => {\r\n this._onWaitTimeout()\r\n }, this._serverTimeout * 1000)\r\n }\r\n\r\n /**\r\n * \r\n * @returns {void}\r\n */\r\n close() {\r\n // console.log(\"close\")\r\n if (this._state === AISessionState.End) {\r\n // console.log(\"close: state is end\")\r\n return\r\n }\r\n if (this._state === AISessionState.None) {\r\n // console.log(\"close: state is none\")\r\n this._state = AISessionState.End;\r\n return\r\n }\r\n\r\n this._doEnd()\r\n this._param = undefined;\r\n this._datas = [];\r\n }\r\n\r\n private _endWithCallback(msg: AISessionError | AISessionEvalScore | ArrayBuffer) {\r\n // console.log(\"_endWithCallback\")\r\n if (this._state === AISessionState.End) {\r\n // console.log(\"_endWithCallback: state is end\")\r\n return\r\n }\r\n this._doEnd()\r\n this._doCallback(msg)\r\n }\r\n\r\n private _doEnd() {\r\n // console.log(\"_doEnd\")\r\n if (this._websocket) {\r\n // console.log(\"websocket close\")\r\n this._websocket.close()\r\n this._websocket = undefined\r\n }\r\n\r\n if (this._waitTimerId !== undefined) {\r\n // console.log(\"waitTimer close\")\r\n clearTimeout(this._waitTimerId)\r\n this._waitTimerId = undefined\r\n }\r\n\r\n // console.log(\"state -> end\")\r\n this._state = AISessionState.End\r\n }\r\n\r\n private _doCallback(msg: AISessionError | AISessionEvalScore | ArrayBuffer) {\r\n // console.log(\"_doCallback\", msg)\r\n const cb = this.resultCb;\r\n if (cb) {\r\n setTimeout(() => { cb(msg) }, 0)\r\n }\r\n }\r\n}","import { ailog } from \"./ailog\";\r\nimport { Recorder } from \"./Recorder\"\r\nimport { AISessionError, AISessionEvalScore, AISession as ChivoxAISession } from './AISession2';\r\nimport { DEFAULT_SERVER, DEFAULT_SERVER_TIMEOUT } from \"./consts\";\r\nimport { asyncall, catchcall } from \"./utils\";\r\nimport type { AudioType } from './Recorder'\r\nimport { EID } from \"./errid\";\r\n\r\nconst CHANNEL = 1;\r\nconst SAMPLE_BYTES = 2;\r\nconst SAMPLE_RATE = 16000;\r\n\r\nexport interface AIEngineError {\r\n // 错误码\r\n errId: number\r\n // 错误描述\r\n error: string\r\n // 可能携带其他信息\r\n [key: string]: any;\r\n}\r\n\r\nexport interface AIEngineInitOptions {\r\n // 评测服务器地址, 缺省\"wss://cloud.chivox.com\"\r\n server?: string\r\n // 结束录音后等待评测结果的超时时间, 单位:秒, 缺省60\r\n serverTimeout?: number\r\n // 事件发生后AIEngine才能用于评测\r\n onInited: () => void\r\n // 事件发生后AIEngine不可继续使用\r\n onError: (err: AIEngineError) => void\r\n}\r\n\r\nexport interface AIEngineStartOptions {\r\n // 录音类型\r\n audioType: AudioType\r\n // 录音时长,单位:毫秒,达到时间后AIEngine会自动调用stop()结束录音。缺省不限时长\r\n duration?: number\r\n // 驰声身份验证信息\r\n app: AIEngineEvalApp\r\n // 评测内核参数\r\n serverParams: AIEngineEvalServerParams\r\n // 评测事件监听\r\n listener: AIEngineEvalListener\r\n}\r\n\r\nexport interface AIEngineEvalApp {\r\n // 由驰声提供的appKey\r\n applicationId: string\r\n // 签名字符串 通过签名算法alg(appkey + timestamp + secretKey)生成\r\n sig: string\r\n // 生成sig签名的算法 目前支持sha256, md5\r\n alg: string\r\n // 生成签名的时间戳,单位:毫秒(ms)\r\n timestamp: string\r\n // 业务应用的用户标识,请保证每个用户的userId唯一\r\n userId?: string\r\n}\r\n\r\nexport interface AIEngineEvalServerParams {\r\n [key: string]: any\r\n}\r\n\r\n/**\r\n * o --+-------> onStart --+-------> onStop --+--------> onScore\r\n * \\ \\ \\\r\n * \\ \\ \\\r\n * +-------------------+------------------+--------> onError\r\n */\r\nexport interface AIEngineEvalListener {\r\n // 录音开始\r\n onStart?: () => void\r\n // 录音结束, 当audioBlob非空时,表示录制的音频文件数据\r\n onStop: (audioBlob: Blob | null) => void\r\n // 评测结果\r\n onScore: (data: AIEngineEvalScore) => void\r\n // 评测错误\r\n onError: (err: AIEngineError) => void\r\n // 中间评测结果\r\n onInternalScore?: (data: AIEngineEvalScore) => void\r\n}\r\n\r\nexport interface AIEngineEvalScore {\r\n [key: string]: any\r\n}\r\n\r\nexport interface AIEngineStopOptions {\r\n cancel?: boolean\r\n}\r\n\r\nenum AIEngineState {\r\n Initing = 'initing', // [+disposeRequesting] \r\n Idle = 'idle', // [+disposeRequesting]\r\n Starting = 'starting', // [+stopRequesting] [+disposeRequesting] \r\n Started = 'started', // [+stopRequesting] [+disposeRequesting]\r\n Disposed = 'disposed',\r\n}\r\n\r\ninterface EvalContext {\r\n session: ChivoxAISession\r\n listener: AIEngineEvalListener\r\n emitEnd: boolean\r\n}\r\n\r\nexport class AIEngine {\r\n private _server: string\r\n private _serverTimeout: number\r\n private _onError: (err: AIEngineError) => void // 不可恢复的错误,事件发生后AIEngine不可继续使用\r\n\r\n private _state: AIEngineState\r\n private _stopRequesting: boolean\r\n private _stopWithCancel: boolean\r\n private _stopWithEvalFinalResult: ArrayBuffer | AIEngineEvalScore | AIEngineError | null\r\n private _disposeRequesting: boolean\r\n private _disposeForError: AIEngineError | null\r\n\r\n private _recorder: Recorder | null\r\n private _recordTimer: number | undefined\r\n private _fronteval: EvalContext | null\r\n private _backevalList: EvalContext[]\r\n\r\n constructor(options: AIEngineInitOptions) {\r\n ailog.info(\"[chivox] aiengine new()\");\r\n\r\n this._server = DEFAULT_SERVER\r\n this._serverTimeout = DEFAULT_SERVER_TIMEOUT\r\n this._onError = () => { }\r\n\r\n this._state = AIEngineState.Initing;\r\n this._stopRequesting = false;\r\n this._stopWithCancel = false;\r\n this._stopWithEvalFinalResult = null;\r\n this._disposeRequesting = false;\r\n this._disposeForError = null;\r\n\r\n this._recorder = null\r\n this._recordTimer = undefined\r\n this._fronteval = null\r\n this._backevalList = []\r\n\r\n if (typeof (options) !== 'object' || options === null) {\r\n ailog.error('[chivox] aiengine init fail: options is null or not object');\r\n this._state = AIEngineState.Disposed;\r\n return\r\n }\r\n\r\n let { server, serverTimeout, onInited, onError } = options;\r\n if (typeof (server) !== 'string') { server = DEFAULT_SERVER }\r\n if (typeof (serverTimeout) !== 'number') { serverTimeout = DEFAULT_SERVER_TIMEOUT }\r\n if (typeof (onInited) !== 'function') { onInited = () => { } }\r\n if (typeof (onError) !== 'function') { onError = () => { } }\r\n\r\n this._server = server;\r\n this._serverTimeout = serverTimeout > 0 ? serverTimeout : DEFAULT_SERVER_TIMEOUT;\r\n this._onError = onError;\r\n\r\n this._recorder = new Recorder({\r\n onInited: () => {\r\n if (this._disposeRequesting) {\r\n const disposeForErr = this._disposeForError;\r\n this._closeRecorder()\r\n this._state = AIEngineState.Disposed;\r\n this._disposeForError = null;\r\n this._disposeRequesting = false;\r\n const err = disposeForErr ?? { errId: EID.ENGINE_DISPOSED, error: `aiengine init canceled: disposed` };\r\n catchcall(() => { onError(err) })\r\n return\r\n }\r\n\r\n ailog.info(\"[chivox] aiengine init ok\");\r\n this._state = AIEngineState.Idle;\r\n catchcall(() => { onInited() });\r\n return\r\n },\r\n onError: (err) => {\r\n if (this._state === AIEngineState.Initing) {\r\n ailog.error(`[chivox] aiengine init fail: ${err.message}`);\r\n\r\n if (this._disposeRequesting) {\r\n const disposeForErr = this._disposeForError;\r\n this._closeRecorder()\r\n this._state = AIEngineState.Disposed;\r\n this._disposeForError = null;\r\n this._disposeRequesting = false;\r\n const initErr = disposeForErr ?? { errId: EID.RECORDER_INIT_FAIL, error: `aiengine init fail: ${err.message}` };\r\n catchcall(() => { onError(initErr) })\r\n return\r\n }\r\n\r\n this._closeRecorder()\r\n this._state = AIEngineState.Disposed;\r\n const initErr = { errId: EID.RECORDER_INIT_FAIL, error: `aiengine init fail: ${err.message}` };\r\n catchcall(() => { onError(initErr) })\r\n return\r\n }\r\n\r\n // 目前onError只会在`initing`状态可能触发\r\n ailog.warn(`[chivox] the recorder's 'onError' event occurs while aiengine is in state ${this._state}. recorder error: ${err.message}`);\r\n }\r\n });\r\n }\r\n\r\n start(options: AIEngineStartOptions): void {\r\n ailog.info('[chivox] aiengine start()')\r\n\r\n if (typeof (options) !== 'object' || options === null) {\r\n ailog.error('[chivox] aiengine start fail: options is null or not object');\r\n return\r\n }\r\n\r\n let listener: AIEngineEvalListener;\r\n if (typeof (options.listener) !== 'object' || options.listener === null) {\r\n listener = { onStop: () => { }, onScore: () => { }, onError: () => { } }\r\n } else {\r\n listener = Object.assign({ onStop: () => { }, onScore: () => { }, onError: () => { } }, options.listener)\r\n }\r\n\r\n if (this._state === AIEngineState.Disposed || this._disposeRequesting) {\r\n const err: AIEngineError = { errId: EID.ENGINE_DISPOSED, error: 'aiengine start fail: disposed' };\r\n asyncall(() => { listener.onError(err) });\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Initing) {\r\n const err: AIEngineError = { errId: EID.BUSY_INITING, error: 'aiengine start fail: init not finshed' };\r\n asyncall(() => { listener.onError(err) });\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Starting || this._state === AIEngineState.Started) {\r\n const err: AIEngineError = { errId: EID.BUSY_RECORDING, error: 'aiengine start fail: repeated start' };\r\n asyncall(() => { listener.onError(err) });\r\n return\r\n }\r\n\r\n if (this._state !== AIEngineState.Idle) {\r\n const err: AIEngineError = { errId: EID.INNER_ERR, error: `aiengine start fail: undefined state: ${this._state}` };\r\n asyncall(() => { listener.onError(err) });\r\n return\r\n }\r\n\r\n let { audioType, duration, app: userApp, serverParams: userServerParams } = options;\r\n\r\n if (typeof (audioType) !== 'string' || !(audioType === 'opus' || audioType === 'wav')) {\r\n const err: AIEngineError = { errId: EID.PARAM_ERR, error: \"aiengine start fail: invalid 'audioType'\" };\r\n asyncall(() => { listener.onError(err) });\r\n return\r\n }\r\n\r\n if (typeof (duration) !== 'number') {\r\n duration = undefined;\r\n }\r\n\r\n if (typeof (userApp) !== 'object' || userApp === null) {\r\n const err: AIEngineError = { errId: EID.PARAM_ERR, error: \"aiengine start fail: invalid 'app'\" }\r\n asyncall(() => { listener.onError(err) });\r\n return\r\n }\r\n\r\n if (typeof (userServerParams) !== 'object' || userServerParams === null) {\r\n const err: AIEngineError = { errId: EID.PARAM_ERR, error: \"aiengine start fail: invalid 'serverParams'\" }\r\n asyncall(() => { listener.onError(err) });\r\n return\r\n }\r\n\r\n let app: AIEngineEvalApp = Object.assign({ applicationId: \"\", sig: \"\", alg: \"\", timestamp: \"\" }, userApp)\r\n let request: AIEngineEvalServerParams = Object.assign({}, userServerParams)\r\n\r\n this._state = AIEngineState.Starting;\r\n\r\n const fronteval: EvalContext = {\r\n session: new ChivoxAISession({ cloud: { server: this._server, serverTimeout: this._serverTimeout } }),\r\n listener: listener,\r\n emitEnd: false,\r\n };\r\n\r\n this._fronteval = fronteval;\r\n this._fronteval.session.resultCb = (res) => { this._onEvalSessionResult(fronteval, res) }\r\n this._fronteval.session.start({\r\n audio: { audioType, channel: CHANNEL, sampleBytes: SAMPLE_BYTES, sampleRate: SAMPLE_RATE },\r\n app, request,\r\n })\r\n\r\n this._recorder!.start({\r\n audioType,\r\n sampleRate: SAMPLE_RATE,\r\n onSuccess: () => {\r\n if (this._disposeRequesting) {\r\n this._recorder!.stop({\r\n onSuccess: (_audioBlob) => {\r\n const disposeForErr = this._disposeForError;\r\n const callbacks: (() => void)[] = []\r\n this._endFrontEval(callbacks, { errId: EID.EVAL_CANCELED, error: `canceled: ${disposeForErr ? disposeForErr.error : \"aiengine disposed\"}` })\r\n this._disposeFromIdleLike(callbacks, disposeForErr);\r\n this._emitCallbacks(callbacks)\r\n return\r\n },\r\n onFail: (err, recoverable) => {\r\n const disposeForErr = this._disposeForError;\r\n const unrecoverableErr = recoverable ? null : { errId: EID.ENGINE_BROKEN, error: `aiengine broken: ${err.message}` };\r\n const callbacks: (() => void)[] = []\r\n this._endFrontEval(callbacks, { errId: EID.RECORDER_STOP_FAIL, error: `in disposing: ${err.message}. ${disposeForErr ? \"dispose reason: \" + disposeForErr.error : \"\"}` })\r\n this._disposeFromIdleLike(callbacks, disposeForErr ?? unrecoverableErr);\r\n this._emitCallbacks(callbacks)\r\n return\r\n }\r\n })\r\n return\r\n }\r\n\r\n if (this._stopRequesting) {\r\n this._state = AIEngineState.Started;\r\n if (!fronteval.emitEnd) {\r\n catchcall(() => { fronteval.listener.onStart?.() }) // 若用户在回调里调用`stop`或`dispose`,由于`_stopRequesting`已经为true,在`stop`和`dispose`中不会触发任何实际操作\r\n }\r\n this._stopFromStartedState();\r\n return\r\n }\r\n\r\n if (duration && duration > 0) {\r\n this._startRecordTimer(duration)\r\n }\r\n\r\n this._state = AIEngineState.Started;\r\n if (!fronteval.emitEnd) {\r\n catchcall(() => { fronteval.listener.onStart?.() })\r\n }\r\n return\r\n },\r\n onFail: (err, recoverable) => {\r\n ailog.error(`[chivox] aiengine start fail (recoverable=${recoverable}): ${err.message}`);\r\n const callbacks: (() => void)[] = []\r\n\r\n if (this._disposeRequesting) {\r\n const disposeForErr = this._disposeForError;\r\n const unrecoverableErr = recoverable ? null : { errId: EID.ENGINE_BROKEN, error: `aiengine broken: start fail: ${err.message}` };\r\n this._endFrontEval(callbacks, { errId: EID.RECORDER_START_FAIL, error: `aiengine start fail: ${err.message}` })\r\n this._disposeFromIdleLike(callbacks, disposeForErr ?? unrecoverableErr);\r\n this._emitCallbacks(callbacks)\r\n return\r\n }\r\n\r\n if (!recoverable) {\r\n const unrecoverableErr: AIEngineError = { errId: EID.ENGINE_BROKEN, error: `aiengine broken: start fail: ${err.message}` }\r\n this._endFrontEval(callbacks, { errId: EID.RECORDER_START_FAIL, error: `aiengine start fail: ${err.message}` })\r\n this._disposeFromIdleLike(callbacks, unrecoverableErr)\r\n this._emitCallbacks(callbacks)\r\n return\r\n }\r\n\r\n this._endFrontEval(callbacks, { errId: EID.RECORDER_START_FAIL, error: `aiengine start fail: ${err.message}` });\r\n this._state = AIEngineState.Idle;\r\n this._stopRequesting = false\r\n this._stopWithCancel = false;\r\n this._stopWithEvalFinalResult = null;\r\n this._emitCallbacks(callbacks)\r\n return\r\n },\r\n onDataFrame: (data) => {\r\n if (this._state === AIEngineState.Starting || this._state === AIEngineState.Started) {\r\n if (this._fronteval) {\r\n this._fronteval.session.feed(data)\r\n }\r\n }\r\n // 当在 Idle 状态时 this._fronteval 一定为 null,且其 session 已经 stop 或 close,因此不用feed(data)\r\n }\r\n })\r\n }\r\n\r\n stop(options?: AIEngineStopOptions): void {\r\n ailog.info('[chivox] aiengine stop()')\r\n if (typeof (options) !== 'object' || options === null) {\r\n options = undefined;\r\n }\r\n\r\n let cancel: boolean | undefined = undefined\r\n if (options && typeof (options.cancel) === 'boolean') {\r\n cancel = options.cancel\r\n }\r\n\r\n this._stopFunc(options ?? { cancel })\r\n }\r\n\r\n private _innerStop(options: AIEngineStopOptions) {\r\n ailog.info('[chivox] aiengine innerStop')\r\n this._stopFunc(options)\r\n }\r\n\r\n private _stopFunc(options: AIEngineStopOptions) {\r\n let { cancel: withCancel = false } = options;\r\n\r\n if (this._state === AIEngineState.Disposed) {\r\n return\r\n }\r\n\r\n if (this._disposeRequesting) {\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Initing) {\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Idle) {\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Starting) {\r\n if (!this._stopRequesting) {\r\n this._stopRequesting = true;\r\n this._stopWithCancel = withCancel;\r\n this._stopWithEvalFinalResult = null;\r\n }\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Started) {\r\n if (!this._stopRequesting) {\r\n this._stopRequesting = true;\r\n this._stopWithCancel = withCancel;\r\n this._stopWithEvalFinalResult = null;\r\n this._stopFromStartedState();\r\n }\r\n return\r\n }\r\n }\r\n\r\n dispose(): void {\r\n ailog.info('[chivox] aiengine dispose()')\r\n if (this._state === AIEngineState.Disposed) {\r\n return\r\n }\r\n\r\n if (this._disposeRequesting) {\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Initing) {\r\n this._disposeRequesting = true;\r\n this._disposeForError = null;\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Idle) {\r\n const callbacks: (() => void)[] = [];\r\n this._disposeFromIdleLike(callbacks, null);\r\n this._emitCallbacks(callbacks)\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Starting) {\r\n this._disposeRequesting = true;\r\n this._disposeForError = null;\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Started) {\r\n this._disposeRequesting = true;\r\n this._disposeForError = null;\r\n if (!this._stopRequesting) {\r\n this._stopRequesting = true;\r\n this._stopWithCancel = true;\r\n this._stopWithEvalFinalResult = null;\r\n this._stopFromStartedState();\r\n }\r\n return;\r\n }\r\n }\r\n\r\n // 音量 0 ~ 1\r\n getMicVolume(): number {\r\n if (this._recorder) {\r\n return this._recorder.getMicVolume()\r\n } else {\r\n return 0\r\n }\r\n }\r\n\r\n // 要设置的音量 0 ~ 1\r\n setMicVolume(volume: number) {\r\n if (this._recorder) {\r\n this._recorder.setMicVolume(volume)\r\n }\r\n }\r\n\r\n // 必须在`started`状态且`_stopRequesting === true`时调用\r\n private _stopFromStartedState(): void {\r\n ailog.info('[chivox] aiengine stopFromStartedState')\r\n\r\n this._clearRecordTimer()\r\n\r\n this._recorder!.stop({\r\n onSuccess: (audioBlob) => {\r\n const callbacks: (() => void)[] = []\r\n\r\n if (this._disposeRequesting) { // dispose请求中\r\n const disposeForErr = this._disposeForError;\r\n if (this._fronteval) {\r\n const fronteval = this._fronteval;\r\n if (!fronteval.emitEnd) {\r\n callbacks.push(() => { fronteval.listener.onStop(audioBlob) })\r\n }\r\n }\r\n this._endFrontEval(callbacks, { errId: EID.EVAL_CANCELED, error: `canceled: ${disposeForErr ? disposeForErr.error : \"aiengine disposed\"}` })\r\n this._disposeFromIdleLike(callbacks, disposeForErr)\r\n this._emitCallbacks(callbacks)\r\n return\r\n }\r\n\r\n if (this._stopWithCancel) {\r\n if (this._fronteval) {\r\n const fronteval = this._fronteval;\r\n if (!fronteval.emitEnd) {\r\n callbacks.push(() => { fronteval.listener.onStop(audioBlob) })\r\n }\r\n }\r\n this._endFrontEval(callbacks, { errId: EID.EVAL_CANCELED, error: \"canceled\" })\r\n this._state = AIEngineState.Idle;\r\n this._stopRequesting = false;\r\n this._stopWithCancel = false;\r\n this._stopWithEvalFinalResult = null;\r\n this._emitCallbacks(callbacks);\r\n return\r\n }\r\n\r\n if (this._fronteval) {\r\n const fronteval = this._fronteval;\r\n if (!fronteval.emitEnd) {\r\n callbacks.push(() => { fronteval.listener.onStop(audioBlob) })\r\n }\r\n\r\n const res = this._stopWithEvalFinalResult;\r\n if (res == null) {\r\n fronteval.session.stop();\r\n this._backevalList.push(fronteval);\r\n } else {\r\n if (!fronteval.emitEnd) {\r\n if (res instanceof ArrayBuffer) {\r\n // 暂时不支持二进制结果回调\r\n } else if (res.errId && res.errId !== 0) {\r\n callbacks.push(() => { fronteval.listener.onError(res as AIEngineError) })\r\n } else {\r\n callbacks.push(() => { fronteval.listener.onScore(res) })\r\n }\r\n }\r\n fronteval.session.close()\r\n }\r\n\r\n this._fronteval = null;\r\n }\r\n this._state = AIEngineState.Idle;\r\n this._stopRequesting = false;\r\n this._stopWithCancel = false;\r\n this._stopWithEvalFinalResult = null;\r\n this._emitCallbacks(callbacks);\r\n return\r\n },\r\n onFail: (err, recoverable) => {\r\n ailog.error(`[chivox] aiengine stop fail: ${err.message}`)\r\n const callbacks: (() => void)[] = []\r\n\r\n if (this._disposeRequesting) { // dispose请求中\r\n const disposeForErr = this._disposeForError;\r\n const unrecoverableErr = recoverable ? null : { errId: EID.ENGINE_BROKEN, error: `aiengine broken: ${err.message}` };\r\n this._endFrontEval(callbacks, { errId: EID.RECORDER_STOP_FAIL, error: `in disposing: ${err.message}. ${disposeForErr ? \"dispose reason: \" + disposeForErr.error : \"\"}` })\r\n this._disposeFromIdleLike(callbacks, disposeForErr ?? unrecoverableErr)\r\n this._emitCallbacks(callbacks)\r\n return\r\n }\r\n\r\n if (!recoverable) { // 不可恢复的错误\r\n this._endFrontEval(callbacks, { errId: EID.RECORDER_STOP_FAIL, error: `aiengine stop fail: ${err.message}` })\r\n this._disposeFromIdleLike(callbacks, { errId: EID.ENGINE_BROKEN, error: `aiengine broken: ${err.message}` })\r\n this._emitCallbacks(callbacks)\r\n return\r\n }\r\n\r\n this._endFrontEval(callbacks, { errId: EID.RECORDER_STOP_FAIL, error: `aiengine stop fail: ${err.message}` })\r\n this._state = AIEngineState.Idle;\r\n this._stopRequesting = false;\r\n this._stopWithCancel = false;\r\n this._stopWithEvalFinalResult = null;\r\n this._emitCallbacks(callbacks)\r\n }\r\n })\r\n }\r\n\r\n // 仅可以在`idle`、`starting`和`started`状态被调用\r\n private _disposeFromIdleLike(callbacks: (() => void)[], disposeForErr: AIEngineError | null): void {\r\n const cancelReason = \"canceled: \" + (disposeForErr ? disposeForErr.error : \"aiengine disposed\")\r\n this._cancelBackEvalList(callbacks, cancelReason)\r\n this._closeRecorder()\r\n this._state = AIEngineState.Disposed;\r\n this._disposeForError = null;\r\n this._disposeRequesting = false;\r\n this._stopRequesting = false;\r\n this._stopWithCancel = false;\r\n this._stopWithEvalFinalResult = null;\r\n\r\n if (disposeForErr) {\r\n callbacks.push(() => { this._onError(disposeForErr) })\r\n }\r\n }\r\n\r\n private _startRecordTimer(durationMs: number) {\r\n this._clearRecordTimer()\r\n this._recordTimer = setTimeout(() => {\r\n ailog.info('[chivox] aiengine recordTimer out')\r\n this._recordTimer = undefined;\r\n this._innerStop({ cancel: false })\r\n }, durationMs)\r\n }\r\n\r\n private _clearRecordTimer(): void {\r\n if (this._recordTimer !== undefined) {\r\n clearTimeout(this._recordTimer);\r\n this._recordTimer = undefined;\r\n }\r\n }\r\n\r\n private _endFrontEval(callbacks: (() => void)[], evalErr: AIEngineError): void {\r\n if (this._fronteval) {\r\n const fronteval = this._fronteval;\r\n if (!fronteval.emitEnd) {\r\n callbacks.push(() => { fronteval.listener.onError(evalErr) })\r\n }\r\n fronteval.emitEnd = true;\r\n fronteval.session.close();\r\n this._fronteval = null;\r\n }\r\n }\r\n\r\n private _cancelBackEvalList(callbacks: (() => void)[], reason: string): void {\r\n for (const backeval of this._backevalList) {\r\n if (!backeval.emitEnd) {\r\n callbacks.push(() => { backeval.listener.onError({ errId: EID.EVAL_CANCELED, error: reason }) })\r\n }\r\n backeval.emitEnd = true;\r\n backeval.session.close();\r\n }\r\n this._backevalList = [];\r\n }\r\n\r\n private _closeRecorder(): void {\r\n if (this._recorder) {\r\n this._recorder.close()\r\n this._recorder = null;\r\n }\r\n }\r\n\r\n private _emitCallbacks(callbacks: (() => void)[]): void {\r\n for (const cb of callbacks) {\r\n try {\r\n cb()\r\n } catch (err) {\r\n console.error(err)\r\n }\r\n }\r\n }\r\n\r\n private _onEvalSessionResult(someeval: EvalContext, res: ArrayBuffer | AISessionEvalScore | AISessionError) {\r\n if (res instanceof ArrayBuffer) {\r\n ailog.info('[chivox] aiengine onEvalSessionResult: ArrayBuffer ' + res.byteLength)\r\n } else {\r\n ailog.info('[chivox] aiengine onEvalSessionResult: ' + JSON.stringify(res))\r\n }\r\n \r\n if (this._state === AIEngineState.Disposed) {\r\n return\r\n }\r\n\r\n if (this._disposeRequesting) {\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Initing) {\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Idle) {\r\n // 在 Idle 状态 this._fronteval 一定为 null\r\n this._handleBackEvalResult(someeval, res);\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Starting || this._state === AIEngineState.Started) {\r\n if (someeval === this._fronteval) {\r\n this._handleFrontEvalResult(someeval, res)\r\n return;\r\n }\r\n\r\n this._handleBackEvalResult(someeval, res) // TODO 很难构造此种情况,测试过程未覆盖此情况\r\n return\r\n }\r\n }\r\n\r\n // 只能在`starting`和`started`状态调用\r\n private _handleFrontEvalResult(fronteval: EvalContext, res: ArrayBuffer | AISessionEvalScore | AISessionError): void {\r\n if (res instanceof ArrayBuffer) { // 二进制结果\r\n this._stopForFinalEvalResult(res)\r\n return;\r\n }\r\n\r\n if (res.errId && res.errId !== 0) { // errId为非0时表示评测错误\r\n this._stopForFinalEvalResult(res as AISessionError)\r\n return\r\n }\r\n\r\n if (res.eof === undefined || res.eof !== 0) { // 没有eof或者eof为非0时表示最终结果\r\n this._stopForFinalEvalResult(res as AISessionEvalScore)\r\n return\r\n }\r\n\r\n // 中间结果\r\n if (!fronteval.emitEnd) {\r\n fronteval.listener.onInternalScore?.(res)\r\n }\r\n return\r\n }\r\n\r\n // 只能在`starting`和`started`状态调用\r\n private _stopForFinalEvalResult(res: ArrayBuffer | AISessionEvalScore | AISessionError) {\r\n if (this._state === AIEngineState.Starting) {\r\n if (!this._stopRequesting) {\r\n this._stopRequesting = true;\r\n this._stopWithCancel = false;\r\n this._stopWithEvalFinalResult = res;\r\n } else if (!this._stopWithCancel) {\r\n if (!this._stopWithEvalFinalResult) {\r\n // 这里必然能在stop完成后,把结果回调给用户。为什么? 因为在 stop 的处理中 \"取出 _stopWithEvalFinalResult 并加入回调\" 和 \"设置 _stopRequesting 为 false\" 是同步执行的\r\n this._stopWithEvalFinalResult = res;\r\n }\r\n }\r\n return\r\n }\r\n\r\n if (this._state === AIEngineState.Started) {\r\n if (!this._stopRequesting) {\r\n this._stopRequesting = true;\r\n this._stopWithCancel = false;\r\n this._stopWithEvalFinalResult = res;\r\n this._stopFromStartedState();\r\n } else if (!this._stopWithCancel) {\r\n if (!this._stopWithEvalFinalResult) {\r\n // 这里必然能在stop完成后,把结果回调给用户。为什么? 因为在 stop 的处理中 \"取出 _stopWithEvalFinalResult 并加入回调\" 和 \"设置 _stopRequesting 为 false\" 是同步执行的\r\n this._stopWithEvalFinalResult = res;\r\n }\r\n }\r\n return\r\n }\r\n }\r\n\r\n private _handleBackEvalResult(backeval: EvalContext, res: ArrayBuffer | AISessionEvalScore | AISessionError): void {\r\n if (res instanceof ArrayBuffer) { // 二进制结果\r\n this._backevalList = this._backevalList.filter(item => item !== backeval)\r\n if (!backeval.emitEnd) {\r\n backeval.emitEnd = true;\r\n backeval.session.close();\r\n // 暂无二进制结果回调\r\n }\r\n return\r\n }\r\n\r\n if (res.errId && res.errId !== 0) { // errId为非0时表示评测错误\r\n this._backevalList = this._backevalList.filter(item => item !== backeval)\r\n if (!backeval.emitEnd) {\r\n backeval.emitEnd = true;\r\n backeval.session.close();\r\n backeval.listener.onError(res as AISessionError)\r\n }\r\n return\r\n }\r\n\r\n if (res.eof === undefined || res.eof !== 0) { // 没有eof或者eof为非0时表示最终结果\r\n this._backevalList = this._backevalList.filter(item => item !== backeval)\r\n if (!backeval.emitEnd) {\r\n backeval.emitEnd = true;\r\n backeval.session.close();\r\n backeval.listener.onScore(res as AISessionEvalScore)\r\n }\r\n return\r\n }\r\n\r\n // 中间结果\r\n if (!backeval.emitEnd) {\r\n backeval.listener.onInternalScore?.(res)\r\n }\r\n return\r\n }\r\n}\r\n"],"names":["LogLevel","logLevel","Info","ailog","getLevel","Debug","Warn","Error","setLevel","name","debug","data","console","info","warn","error","__awaiter","thisArg","_arguments","P","generator","Promise","resolve","reject","fulfilled","value","step","next","e","rejected","result","done","then","apply","isOk","res","ok","isErr","makeOk","makeErr","err","ifOk","okhandler","SuppressedError","codeBlob","codeUrl","asyncall","handler","args","setTimeout","catchcall","State","Recorder","constructor","options","onInited","onError","this","logI","state","Initing","closing","audioContext","gainNode","audioWorkletNode","opusEncoder","wavEncoder","audioType","undefined","stream","sourceNode","audioWorkletStarted","opusEncoderStarted","wavEncoderStarted","pendingRawPCM","pendingOpusData","pendingWavData","AudioContextConstructor","AudioContext","globalThis","webkitAudioContext","mozAudioContext","msAudioContext","message","String","resume","createAudioContext","createGain","Blob","type","URL","createObjectURL","audioWorklet","addModule","node","AudioWorkletNode","createAudioWorkletNode","connect","destination","opusRes","worker","Worker","createOpusEncoderWorker","wavRes","createWavEncoderWorker","cleanupInit","Closed","logE","Idle","start","sampleRate","onSuccess","onFail","onDataFrame","Starting","Started","Stopping","lastErr","navigator","mediaDevices","getUserMedia","audio","video","getMediaStream","createMediaStreamSource","startAudioWorklet","startEncoder","endRecording","endRes","_","feedEncoder","buffer","stop","close","getMicVolume","gain","setMicVolume","volume","postMessage","command","disconnect","port","catch","logW","stopAudioWorklet","stopEncoder","streamErr","getTracks","forEach","track","callback","cont","content","Float32Array","push","removeEventListener","addEventListener","fromSampleRate","toSampleRate","startOpusEncoder","startWavEncoder","page","Uint8Array","originalSampleRate","encoderSampleRate","numberOfChannels","Int16Array","buffers","stopOpusEncoder","stopWavEncoder","audioBlob","logD","DEFAULT_SERVER","DEFAULT_SERVER_TIMEOUT","VERSION_HEX_STR","EID","AISessionState","makeError","errId","AISession","cfg","resultCb","cloud","server","serverTimeout","replace","_server","_serverTimeout","_state","None","_isStarted","_isStopped","_tokenId","c","r","Math","random","toString","_param","_datas","_websocket","_waitTimerId","getTokenId","param","End","_endWithCallback","app","applicationId","request","coreType","url","Object","assign","Connecting","WebSocket","binaryType","onopen","_onWebsocketOpen","onmessage","ev","_onWebsocketMessage","onerror","_onWebsocketError","onclose","_onWebsocketClose","_a","readyState","OPEN","send","JSON","stringify","cmd","_b","sdk","version","source","protocol","tokenId","_c","_d","_e","FeedingBuf","_feedBuf","json","parse","eof","_doCallback","wasClean","code","reason","_onWaitTimeout","length","shift","Feeding","feed","byteLength","_doEnd","msg","clearTimeout","cb","AIEngineState","_onError","_stopRequesting","_stopWithCancel","_stopWithEvalFinalResult","_disposeRequesting","_disposeForError","_recorder","_recordTimer","_fronteval","_backevalList","Disposed","disposeForErr","_closeRecorder","initErr","listener","onStop","onScore","duration","userApp","serverParams","userServerParams","sig","alg","timestamp","fronteval","session","ChivoxAISession","emitEnd","_onEvalSessionResult","channel","sampleBytes","_audioBlob","callbacks","_endFrontEval","_disposeFromIdleLike","_emitCallbacks","recoverable","unrecoverableErr","onStart","_stopFromStartedState","_startRecordTimer","call","cancel","_stopFunc","_innerStop","withCancel","dispose","_clearRecordTimer","ArrayBuffer","cancelReason","_cancelBackEvalList","durationMs","evalErr","backeval","someeval","_handleFrontEvalResult","_handleBackEvalResult","_stopForFinalEvalResult","onInternalScore","filter","item"],"mappings":"4CAGA,IAAKA,GAAL,SAAKA,GACHA,EAAAA,EAAA,MAAA,GAAA,QACAA,EAAAA,EAAA,KAAA,GAAA,OACAA,EAAAA,EAAA,KAAA,GAAA,OACAA,EAAAA,EAAA,MAAA,GAAA,OACD,CALD,CAAKA,IAAAA,EAAQ,CAAA,IAOb,IAAIC,EAAqBD,EAASE,KAE3B,MAAMC,EAAQ,CACnB,QAAAC,GACE,OAAQH,GACN,KAAKD,EAASK,MACZ,MAAO,QACT,KAAKL,EAASE,KACZ,MAAO,OACT,KAAKF,EAASM,KACZ,MAAO,OACT,KAAKN,EAASO,MACZ,MAAO,QACT,QACE,OAEN,EAEA,QAAAC,CAASC,GACM,UAATA,EACFR,EAAWD,EAASK,MACF,SAATI,EACTR,EAAWD,EAASE,KACF,SAATO,EACTR,EAAWD,EAASM,KACF,UAATG,IACTR,EAAWD,EAASO,MAExB,EAEA,KAAAG,IAASC,GACHV,GAAYD,EAASK,OACvBO,QAAQF,SAASC,EAErB,EAEA,IAAAE,IAAQF,GACFV,GAAYD,EAASE,MACvBU,QAAQC,QAAQF,EAEpB,EAEA,IAAAG,IAAQH,GACFV,GAAYD,EAASM,MACvBM,QAAQE,QAAQH,EAEpB,EAEA,KAAAI,IAASJ,GACHV,GAAYD,EAASO,OACvBK,QAAQG,SAASJ,EAErB,GCoDK,SAASK,EAAUC,EAASC,EAAYC,EAAGC,GAE9C,OAAO,IAAKD,IAAMA,EAAIE,UAAU,SAAUC,EAASC,GAC/C,SAASC,EAAUC,GAAS,IAAMC,EAAKN,EAAUO,KAAKF,GAAS,CAAE,MAAOG,GAAKL,EAAOK,EAAI,CAAE,CAC1F,SAASC,EAASJ,GAAS,IAAMC,EAAKN,EAAiB,MAAEK,GAAS,CAAE,MAAOG,GAAKL,EAAOK,EAAI,CAAE,CAC7F,SAASF,EAAKI,GAJlB,IAAeL,EAIaK,EAAOC,KAAOT,EAAQQ,EAAOL,QAJ1CA,EAIyDK,EAAOL,MAJhDA,aAAiBN,EAAIM,EAAQ,IAAIN,EAAE,SAAUG,GAAWA,EAAQG,EAAQ,IAIjBO,KAAKR,EAAWK,EAAW,CAC7GH,GAAMN,EAAYA,EAAUa,MAAMhB,EAASC,GAAc,KAAKS,OAClE,EACJ,CCvHM,SAAUO,EAAWC,GACzB,OAAkB,IAAXA,EAAIC,EACb,CAEM,SAAUC,EAAYF,GAC1B,OAAkB,IAAXA,EAAIC,EACb,CAMM,SAAUE,EAAiB3B,GAC/B,MAAO,CAAEyB,IAAI,EAAMzB,KAAMA,EAC3B,CAEM,SAAU4B,EAAWC,GACzB,MAAO,CAAEJ,IAAI,EAAOI,IAAKA,EAC3B,CAEM,SAAUC,EAAcC,GAC5B,OAAQP,GACFD,EAAKC,GACAO,EAAUP,EAAIxB,MAEhBwB,CAEX,CD0SkD,mBAApBQ,iBAAiCA,gBEtN/D,IAAIC,EAAwB,KACxBC,EAAyB,KChH7B,IAAID,EAAwB,KACxBC,EAAyB,cCMbC,EAASC,KAAsBC,GAC7CC,WAAWF,EAAS,KAAMC,EAC5B,UAEgBE,EAAUH,KAAsBC,GAC9C,IACED,KAAWC,EACb,CAAE,MAAOR,GACP5B,QAAQG,MAAMyB,EAChB,CACF,CC8VA,IAAII,EAAwB,KACxBC,EAAyB,KCvV7B,IAAKM,GAAL,SAAKA,GACHA,EAAA,QAAA,UACAA,EAAA,KAAA,OACAA,EAAA,SAAA,WACAA,EAAA,QAAA,UACAA,EAAA,SAAA,WACAA,EAAA,OAAA,QACD,CAPD,CAAKA,IAAAA,EAAK,CAAA,UASGC,EAyBX,WAAAC,CAAYC,GACV,MAAMC,SAAEA,EAAQC,QAAEA,GAAYF,EAC9BG,KAAKC,KAAK,0BAEVD,KAAKE,MAAQR,EAAMS,QACnBH,KAAKI,SAAU,EAEfJ,KAAKK,aAAe,KACpBL,KAAKM,SAAW,KAChBN,KAAKO,iBAAmB,KACxBP,KAAKQ,YAAc,KACnBR,KAAKS,WAAa,KAElBT,KAAKU,eAAYC,EAEjBX,KAAKY,OAAS,KACdZ,KAAKa,WAAa,KAElBb,KAAKc,qBAAsB,EAC3Bd,KAAKe,oBAAqB,EAC1Bf,KAAKgB,mBAAoB,EAEzBhB,KAAKiB,cAAgB,GACrBjB,KAAKkB,gBAAkB,GACvBlB,KAAKmB,eAAiB,GAEtBvD,QAAQC,UACLU,KAAK,eCtFV,MAAO,KAAYhB,EAAAyC,UAAA,OAAA,EAAA,YACjB,MAAMoB,EAA0BC,cAC7BC,WAAmBC,oBACnBD,WAAmBE,iBACnBF,WAAmBG,eAEtB,IAAKL,EACH,OAAOtC,EAAQ,IAAIhC,MAAM,kDAG3B,IAAIuD,EACJ,IACEA,EAAe,IAAIe,CACrB,CAAE,MAAOrC,GACP,OAAOD,EAAQ,IAAIhC,MAAM,kCAAkCiC,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,MACzG,CAEA,GAA2B,cAAvBsB,EAAaH,MACf,UACQG,EAAauB,QACrB,CAAE,MAAO7C,GACP,OAAOD,EAAQ,IAAIhC,MAAM,wFAC3B,CAGF,OAAO+B,EAAOwB,EAChB,GA1BO,EA2BT,CD2DkBwB,IACXtD,KAAKS,EAAMqB,IACVL,KAAKK,aAAeA,EACpB,IACEL,KAAKM,SAAWN,KAAKK,aAAayB,YACpC,CAAE,MAAO/C,GACP,OAAOD,EAAQC,aAAejC,MAAQiC,EAAM,IAAIjC,MAAM6E,OAAO5C,IAC/D,CACA,OAAOF,OAERN,KAAKS,EAAK,IJkBX,SAAiCqB,GACrC,MAAO,KAAY9C,EAAAyC,UAAA,OAAA,EAAA,YACjB,IACOb,GAAaC,IAChBD,EAAW,IAAI4C,KAAK,CAvHf,slGAuHuB,CAAEC,KAAM,2BACpC5C,EAAU6C,IAAIC,gBAAgB/C,GAElC,CAAE,MAAOJ,GACP,OAAOD,EAAQ,IAAIhC,MAAM,sCAAsCiC,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,MAC7G,CAEA,UACQsB,EAAa8B,aAAaC,UAAUhD,EAC5C,CAAE,MAAOL,GACP,OAAOD,EAAQ,IAAIhC,MAAM,6BAA6BiC,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,MACpG,CAEA,IAAIsD,EACJ,IACEA,EAAO,IAAIC,iBAAiBjC,EAAc,2CAC5C,CAAE,MAAOtB,GACP,OAAOD,EAAQ,IAAIhC,MAAM,8BAA8BiC,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,MACrG,CAEA,OAAOF,EAAOwD,EAChB,GAxBO,EAyBT,CI5CuBE,CAAuBvC,KAAKK,gBAC5C9B,KAAKS,EAAMqD,IACVrC,KAAKO,iBAAmB8B,EAExB,IACErC,KAAKO,iBAAiBiC,QAAQxC,KAAKK,aAAcoC,YACnD,CAAE,MAAO1D,GACP,OAAOD,EAAQC,aAAejC,MAAQiC,EAAM,IAAIjC,MAAM6E,OAAO5C,IAC/D,CAEA,MAAM2D,aHtGZ,IACOvD,GAAaC,IAChBD,EAAW,IAAI4C,KAAK,qjudAAQ,CAAEC,KAAM,2BACpC5C,EAAU6C,IAAIC,gBAAgB/C,GAElC,CAAE,MAAOJ,GACP,OAAOD,EAAQ,IAAIhC,MAAM,uDAAuDiC,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,MAC9H,CAEA,IAAI4D,EACJ,IACEA,EAAS,IAAIC,OAAOxD,EACtB,CAAE,MAAOL,GACP,OAAOD,EAAQ,IAAIhC,MAAM,kDAAkDiC,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,MACzH,CAIA,OAAOF,EAAO8D,EAChB,CGmFwBE,GAChB,IAAIpE,EAAKiE,GAGP,OAAOA,EAFP1C,KAAKQ,YAAckC,EAAQxF,KAK7B,MAAM4F,aDkQZ,IACO3D,GAAaC,IAChBD,EAAW,IAAI4C,KAAK,CAtXb,siZAsXqB,CAAEC,KAAM,2BACpC5C,EAAU6C,IAAIC,gBAAgB/C,GAElC,CAAE,MAAOJ,GACP,OAAOD,EAAQ,IAAIhC,MAAM,sDAAsDiC,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,MAC7H,CAEA,IAAI4D,EACJ,IACEA,EAAS,IAAIC,OAAOxD,EACtB,CAAE,MAAOL,GACP,OAAOD,EAAQ,IAAIhC,MAAM,iDAAiDiC,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,MACxH,CAIA,OAAOF,EAAO8D,EAChB,CCrRuBI,GACf,OAAItE,EAAKqE,IACP9C,KAAKS,WAAaqC,EAAO5F,KAKpB2B,KAHEiE,KAKVvE,KAAKG,IACJ,GAAIsB,KAAKI,QAAS,CAChBJ,KAAKgD,cACLhD,KAAKE,MAAQR,EAAMuD,OACnBjD,KAAKI,SAAU,EACf,MAAMrB,EAAM,IAAIjC,MAAM,iCAEtB,YADA2C,EAAU,KAAQM,EAAQhB,IAE5B,CAEA,GAAIH,EAAMF,GAAM,CACdsB,KAAKkD,KAAK,gCAAgCxE,EAAIK,IAAI2C,WAClD1B,KAAKgD,cACLhD,KAAKE,MAAQR,EAAMuD,OACnB,MAAMlE,EAAM,IAAIjC,MAAM,uBAAuB4B,EAAIK,IAAI2C,WAErD,YADAjC,EAAU,KAAQM,EAAQhB,IAE5B,CAEAiB,KAAKE,MAAQR,EAAMyD,KACnBnD,KAAKC,KAAK,6BACVR,EAAU,KAAQK,OAExB,CAEA,KAAAsD,CAAMvD,GACJ,MAAMa,UAAEA,EAAS2C,WAAEA,EAAUC,UAAEA,EAASC,OAAEA,EAAMC,YAAEA,GAAgB3D,EAGlE,GAFAG,KAAKC,KAAK,2BAEND,KAAKE,QAAUR,EAAMuD,OAEvB,YADA5D,EAAS,KAAQkE,EAAO,IAAIzG,MAAM,wCAAwC,KAI5E,GAAIkD,KAAKI,QAEP,YADAf,EAAS,KAAQkE,EAAO,IAAIzG,MAAM,iCAAiC,KAIrE,GAAIkD,KAAKE,QAAUR,EAAMS,QAEvB,YADAd,EAAS,KAAQkE,EAAO,IAAIzG,MAAM,2CAA2C,KAI/E,GAAIkD,KAAKE,QAAUR,EAAM+D,UAAYzD,KAAKE,QAAUR,EAAMgE,QAExD,YADArE,EAAS,KAAQkE,EAAO,IAAIzG,MAAM,yCAAyC,KAI7E,GAAIkD,KAAKE,QAAUR,EAAMiE,SAEvB,YADAtE,EAAS,KAAQkE,EAAO,IAAIzG,MAAM,2CAA2C,KAI/E,GAAIkD,KAAKE,QAAUR,EAAMyD,KAAM,CAC7B,MAAMpE,EAAM,IAAIjC,MAAM,yCAAyCkD,KAAKE,SAEpE,YADAb,EAAS,KAAQkE,EAAOxE,GAAK,IAE/B,CAEA,MAAMsB,EAAeL,KAAKK,aACpBC,EAAWN,KAAKM,SAChBC,EAAmBP,KAAKO,iBAE9BP,KAAKE,MAAQR,EAAM+D,SACnBzD,KAAKU,UAAYA,EAOjBV,KAAKiB,cAAgB,GACrBjB,KAAKkB,gBAAkB,GACvBlB,KAAKmB,eAAiB,GAEtBd,EAAauB,SACVrD,KACC,IAAMM,IACNE,GAAOD,EAAQ,IAAIhC,MAAM,6BAA6BiC,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,QAEnGR,KAAKS,EAAK,eC7Kf,MAAO,KAAYzB,EAAAyC,UAAA,OAAA,EAAA,YACjB,IAAIY,EAA6B,KAC7BgD,EAAwB,KAE5B,IACEhD,QAAeU,WAAWuC,UAAUC,aAAaC,aAAa,CAAEC,OAAO,EAAMC,OAAO,GACtF,CAAE,MAAOlF,GAEL6E,EADE7E,aAAejC,MACPiC,EAEA,IAAIjC,MAAM,gCAAgC6E,OAAO5C,KAE/D,CAEA,GAAI6B,EACF,OAAO/B,EAAO+B,GAGhB,IAAKgD,EACH,OAAO9E,EAAQ,IAAIhC,MAAM,iDAG3B,OAAQ8G,EAAQ5G,MACd,IAAK,kBACH,OAAO8B,EAAQ,IAAIhC,MAAM,+EAC3B,IAAK,gBACH,OAAOgC,EAAQ,IAAIhC,MAAM,4CAC3B,IAAK,aACH,OAAOgC,EAAQ,IAAIhC,MAAM,sFAC3B,IAAK,mBACH,OAAOgC,EAAQ,IAAIhC,MAAM,+EAC3B,IAAK,uBACH,OAAOgC,EAAQ,IAAIhC,MAAM,wCAAwC8G,EAAQlC,YAC3E,QACE,OAAO5C,EAAQ,IAAIhC,MAAM,gCAAgC8G,EAAQlC,YAEvE,GApCO,EAqCT,CDwIuBwC,KAChB3F,KAAKS,EAAM4B,IACVZ,KAAKY,OAASA,EACd,IACEZ,KAAKa,WAAaR,EAAa8D,wBAAwBvD,EACzD,CAAE,MAAO7B,GACP,OAAOD,EAAQC,aAAejC,MAAQiC,EAAM,IAAIjC,MAAM,GAAG6E,OAAO5C,MAClE,CACA,OAAOF,OAERN,KAAKS,EAAK,IAAMgB,KAAKoE,kBAAkB1D,KACvCnC,KAAKS,EAAK,IAAMgB,KAAKqE,aAAa3D,EAAWL,EAAagD,WAAYA,EAAYG,KAClFjF,KAAKS,EAAK,KACT,IACEgB,KAAKa,WAAY2B,QAAQlC,GACzBA,EAASkC,QAAQjC,EACnB,CAAE,MAAOxB,GACP,OAAOD,EAAQC,aAAejC,MAAQiC,EAAM,IAAIjC,MAAM,GAAG6E,OAAO5C,MAClE,CACA,OAAOF,OAERN,KAAMG,IACL,GAAIE,EAAMF,GAwBR,OAvBAsB,KAAKkD,KAAK,iCAAiCxE,EAAIK,IAAI2C,gBACnD1B,KAAKsE,aAAa5D,GAAWnC,KAAMgG,IACjC,GAAIvE,KAAKI,QAAS,CAChBJ,KAAKgD,cACLhD,KAAKE,MAAQR,EAAMuD,OACnBjD,KAAKI,SAAU,EACf,MAAMrB,EAAM,IAAIjC,MAAM,wBAAwB4B,EAAIK,IAAI2C,WAEtD,YADAjC,EAAU,KAAQ8D,EAAOxE,GAAK,IAEhC,CAEA,GAAIH,EAAM2F,GAAS,CACjBvE,KAAKgD,cACLhD,KAAKE,MAAQR,EAAMuD,OACnB,MAAMlE,EAAM,IAAIjC,MAAM,wBAAwByH,EAAOxF,IAAI2C,aAAahD,EAAIK,IAAI2C,WAE9E,YADAjC,EAAU,KAAQ8D,EAAOxE,GAAK,IAEhC,CAEAiB,KAAKE,MAAQR,EAAMyD,KACnB,MAAMpE,EAAM,IAAIjC,MAAM,wBAAwB4B,EAAIK,IAAI2C,WACtDjC,EAAU,KAAQ8D,EAAOxE,GAAK,OAKlC,GAAIiB,KAAKI,QACPJ,KAAKsE,aAAa5D,GAAWnC,KAAMiG,IACjCxE,KAAKgD,cACLhD,KAAKE,MAAQR,EAAMuD,OACnBjD,KAAKI,SAAU,EACf,MAAMrB,EAAM,IAAIjC,MAAM,kCACtB2C,EAAU,KAAQ8D,EAAOxE,GAAK,WANlC,CAWAiB,KAAKE,MAAQR,EAAMgE,QACnB1D,KAAKC,KAAK,8BACVR,EAAU,KAAQ6D,MAElB,IAAK,MAAMpG,KAAQ8C,KAAKiB,cACtBjB,KAAKyE,YAAY/D,EAAWxD,GAI9B,GAFA8C,KAAKiB,cAAgB,GAEH,SAAdP,EAAsB,CACxB,IAAK,MAAMxD,KAAQ8C,KAAKkB,gBAAiB,CACvC,MAAMwD,EAASxH,EAAKwH,OACpBjF,EAAU,KAAQ+D,EAAYkB,IAChC,CACA1E,KAAKkB,gBAAkB,EACzB,MAAO,GAAkB,QAAdR,EAAqB,CAC9B,IAAK,MAAMxD,KAAQ8C,KAAKmB,eAAgB,CACtC,MAAMuD,EAASxH,EAAKwH,OACpBjF,EAAU,KAAQ+D,EAAYkB,IAChC,CACA1E,KAAKmB,eAAiB,EACxB,CAvBA,GAyBN,CAEA,IAAAwD,CAAK9E,GACH,MAAMyD,UAAEA,EAASC,OAAEA,GAAW1D,EAG9B,GAFAG,KAAKC,KAAK,0BAEND,KAAKE,QAAUR,EAAMuD,OAAQ,CAC/B,MAAMlE,EAAM,IAAIjC,MAAM,sCAEtB,YADAuC,EAAS,IAAMkE,EAAOxE,GAAK,GAE7B,CAEA,GAAIiB,KAAKI,QAAS,CAChB,MAAMrB,EAAM,IAAIjC,MAAM,+BAEtB,YADAuC,EAAS,IAAMkE,EAAOxE,GAAK,GAE7B,CAEA,GAAIiB,KAAKE,QAAUR,EAAMS,QAAS,CAChC,MAAMpB,EAAM,IAAIjC,MAAM,yCAEtB,YADAuC,EAAS,IAAMkE,EAAOxE,GAAK,GAE7B,CAEA,GAAIiB,KAAKE,QAAUR,EAAMyD,KAAM,CAC7B,MAAMpE,EAAM,IAAIjC,MAAM,iCAEtB,YADAuC,EAAS,IAAMkE,EAAOxE,GAAK,GAE7B,CAEA,GAAIiB,KAAKE,QAAUR,EAAM+D,SAAU,CACjC,MAAM1E,EAAM,IAAIjC,MAAM,0CAEtB,YADAuC,EAAS,IAAMkE,EAAOxE,GAAK,GAE7B,CAEA,GAAIiB,KAAKE,QAAUR,EAAMiE,SAAU,CACjC,MAAM5E,EAAM,IAAIjC,MAAM,wCAEtB,YADAuC,EAAS,IAAMkE,EAAOxE,GAAK,GAE7B,CAEA,GAAIiB,KAAKE,QAAUR,EAAMgE,QAAS,CAChC,MAAM3E,EAAM,IAAIjC,MAAM,wCAAwCkD,KAAKE,SAEnE,YADAb,EAAS,IAAMkE,EAAOxE,GAAK,GAE7B,CAEAiB,KAAKE,MAAQR,EAAMiE,SACnB3D,KAAKsE,aAAatE,KAAKU,WAAYnC,KAAMG,IACvC,GAAIE,EAAMF,GAAM,CACdsB,KAAKkD,KAAK,gCAAgCxE,EAAIK,IAAI2C,WAClD1B,KAAKgD,cACLhD,KAAKE,MAAQR,EAAMuD,OACnBjD,KAAKI,SAAU,EACf,MAAMrB,EAAM,IAAIjC,MAAM,uBAAuB4B,EAAIK,IAAI2C,WAErD,YADAjC,EAAU,KAAQ8D,EAAOxE,GAAK,IAEhC,CAIA,GAFAiB,KAAKC,KAAK,6BAEND,KAAKI,QAKP,OAJAJ,KAAKgD,cACLhD,KAAKE,MAAQR,EAAMuD,OACnBjD,KAAKI,SAAU,OACfX,EAAU,KAAQ6D,EAAU5E,EAAIxB,QAIlC8C,KAAKE,MAAQR,EAAMyD,KACnB1D,EAAU,KAAQ6D,EAAU5E,EAAIxB,SAEpC,CAEA,KAAA0H,GAGE,GAFA5E,KAAKC,KAAK,2BAEND,KAAKE,QAAUR,EAAMuD,SAAUjD,KAAKI,UAIxCJ,KAAKI,SAAU,EAEXJ,KAAKE,QAAUR,EAAMS,SAIzB,OAAIH,KAAKE,QAAUR,EAAMyD,MACvBnD,KAAKgD,cACLhD,KAAKE,MAAQR,EAAMuD,YACnBjD,KAAKI,SAAU,SAIbJ,KAAKE,QAAUR,EAAM+D,WAIrBzD,KAAKE,QAAUR,EAAMgE,SASrB1D,KAAKE,MAAUR,EAAMiE,UARvB3D,KAAKsE,aAAatE,KAAKU,WAAYnC,KAAMiG,IACvCxE,KAAKgD,cACLhD,KAAKE,MAAQR,EAAMuD,OACnBjD,KAAKI,SAAU,KAQrB,CAEA,YAAAyE,GACE,IAAI7E,KAAKM,SAOP,OAAO,EANP,IACE,OAAON,KAAKM,SAASwE,KAAK9G,KAC5B,CAAE,MAAOe,GACP,OAAO,CACT,CAIJ,CAEA,YAAAgG,CAAaC,GACX,GAAIhF,KAAKM,SACP,IACEN,KAAKM,SAASwE,KAAK9G,MAAQgH,CAC7B,CAAE,MAAOjG,GACP5B,QAAQG,MAAMyB,EAChB,CAEJ,CAEQ,WAAAiE,GACNhD,KAAKC,KAAK,iCAEND,KAAKQ,cACPR,KAAKQ,YAAYyE,YAAY,CAAEC,QAAS,UACxClF,KAAKQ,YAAc,MAGjBR,KAAKS,aACPT,KAAKS,WAAWwE,YAAY,CAAEC,QAAS,UACvClF,KAAKS,WAAa,MAGhBT,KAAKO,mBACPP,KAAKO,iBAAiB4E,aACtBnF,KAAKO,iBAAiB6E,KAAKR,QAC3B5E,KAAKO,iBAAmB,MAGtBP,KAAKM,WACPN,KAAKM,SAAW,MAGdN,KAAKK,eACPL,KAAKK,aAAauE,QAAQS,MAAMtG,IAC9BiB,KAAKsF,KAAK,kEAAkEvG,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,QAE1HiB,KAAKK,aAAe,KAExB,CAEQ,YAAAiE,CAAa5D,GAEnB,OADAV,KAAKC,KAAK,kCACHrC,QAAQC,UACZU,KAAK,KACJ,IACMyB,KAAKa,aACPb,KAAKa,WAAWsE,aAChBnF,KAAKa,WAAa,KAEtB,CAAE,MAAO9B,GACPiB,KAAKsF,KAAK,2CAA4CvG,EACxD,CAEA,IACMiB,KAAKM,UACPN,KAAKM,SAAS6E,YAElB,CAAE,MAAOpG,GACPiB,KAAKsF,KAAK,2CAA4CvG,EACxD,CAEA,OAAOF,MAERN,KAAMiG,GAAsBxE,KAAKuF,oBACjChH,KAAMiG,GAAsBxE,KAAKwF,YAAY9E,IAC7CnC,KAAMG,IACL,IAAI+G,EAA0B,KAC9B,IACMzF,KAAKY,SACPZ,KAAKY,OAAO8E,YAAYC,QAAQC,GAASA,EAAMjB,QAC/C3E,KAAKY,OAAS,KAElB,CAAE,MAAO7B,GACPiB,KAAKkD,KAAK,yCAAyCnE,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,MAC/F0G,EAAY,IAAI3I,MAAM,uBAAuBiC,aAAejC,MAAQiC,EAAI2C,QAAUC,OAAO5C,KAC3F,CAMA,OAJAiB,KAAKiB,cAAgB,GACrBjB,KAAKkB,gBAAkB,GACvBlB,KAAKmB,eAAiB,GAElBsE,EACK3G,EAAQ2G,IAGjBzF,KAAKC,KAAK,qCACHpB,EAAOH,EAAIxB,QAExB,CAEQ,iBAAAkH,CAAkB1D,GACxB,GAAIV,KAAKc,oBACP,OAAOlD,QAAQC,QAAQiB,EAAQ,IAAIhC,MAAM,0CAG3C,MAAMyD,EAAmBP,KAAKO,iBAG9B,OAFAP,KAAKc,qBAAsB,EAEpB,IAAIlD,QAA2CC,IACpD,MAAMgI,EAAW,EAAG3I,WAElB,GAAsB,iBAAlB,GAAuC,OAATA,EAIlC,OAAQA,EAAKwE,SACX,IAAK,QACH7D,EAAQgB,KACR,MAEF,IAAK,OACH,MAAMiH,EAAO5I,EAAK6I,QACdD,GAAQA,aAAgBE,eACtBhG,KAAKE,QAAUR,EAAM+D,SACvBzD,KAAKiB,cAAcgF,KAAKH,GACf9F,KAAKE,QAAUR,EAAMgE,SAAW1D,KAAKE,QAAUR,EAAMiE,UAC9D3D,KAAKyE,YAAY/D,EAAWoF,IAGhC,MAEF,IAAK,OACHvF,EAAiB6E,KAAKc,oBAAoB,UAAWL,KAK3DtF,EAAiB6E,KAAKe,iBAAiB,UAAWN,GAClDtF,EAAiB6E,KAAKhC,QACtB7C,EAAiB6E,KAAKH,YAAY,CAAEC,QAAS,UAEjD,CAEQ,YAAAb,CAAa3D,EAAsB0F,EAAwBC,EAAsB7C,GACvF,MAAkB,SAAd9C,EACKV,KAAKsG,iBAAiBF,EAAgBC,EAAc7C,GACpC,QAAd9C,EACFV,KAAKuG,gBAAgBH,EAAgBC,EAAc7C,GAErD5F,QAAQC,QAAQgB,IACzB,CAEQ,gBAAAyH,CAAiBF,EAAwBC,EAAsB7C,GACrE,GAAIxD,KAAKe,mBACP,OAAOnD,QAAQC,QAAQiB,EAAQ,IAAIhC,MAAM,yCAG3C,MAAM0D,EAAcR,KAAKQ,YAGzB,OAFAR,KAAKe,oBAAqB,EAEnB,IAAInD,QAA2CC,IAEpD,MAAMgI,EAAW,EAAG3I,WAClB,GAAsB,iBAAlB,GAAuC,OAATA,EAIlC,OAAQA,EAAKwE,SACX,IAAK,QACH7D,EAAQgB,KACR,MAEF,IAAK,OACH,MAAM2H,EAAOtJ,EAAW,KACpBsJ,GAAQA,aAAgBC,aACtBzG,KAAKE,QAAUR,EAAM+D,SACvBzD,KAAKkB,gBAAgB+E,KAAKO,GACjBxG,KAAKE,QAAUR,EAAMgE,SAAW1D,KAAKE,QAAUR,EAAMiE,UAC9DlE,EAAU,KAAQ+D,EAAYgD,EAAK9B,WAGvC,MAEF,IAAK,OACHlE,EAAY0F,oBAAoB,UAAWL,KAKjDrF,EAAY2F,iBAAiB,UAAWN,GACxCrF,EAAYyE,YAAY,CAAEC,QAAS,OAAQwB,mBAAoBN,EAAgBO,kBAAmBN,EAAcO,iBAAkB,KAEtI,CAEQ,eAAAL,CAAgBH,EAAwBC,EAAsB7C,GACpE,GAAIxD,KAAKgB,kBACP,OAAOpD,QAAQC,QAAQiB,EAAQ,IAAIhC,MAAM,wCAG3C,MAAM2D,EAAaT,KAAKS,WAGxB,OAFAT,KAAKgB,mBAAoB,EAElB,IAAIpD,QAA2CC,IAEpD,MAAMgI,EAAW,EAAG3I,WAClB,GAAsB,iBAAlB,GAAuC,OAATA,EAIlC,OAAQA,EAAKwE,SACX,IAAK,QACH7D,EAAQgB,KACR,MAEF,IAAK,OACH,MAAMiH,EAAO5I,EAAK6I,QACdD,GAAQA,aAAgBe,aACtB7G,KAAKE,QAAUR,EAAM+D,SACvBzD,KAAKmB,eAAe8E,KAAKH,GAChB9F,KAAKE,QAAUR,EAAMgE,SAAW1D,KAAKE,QAAUR,EAAMiE,UAC9DlE,EAAU,KAAQ+D,EAAYsC,EAAKpB,WAGvC,MAEF,IAAK,OACHjE,EAAWyF,oBAAoB,UAAWL,KAKhDpF,EAAW0F,iBAAiB,UAAWN,GACvCpF,EAAWwE,YAAY,CAAEC,QAAS,OAAQkB,eAAgBA,EAAgBC,aAAcA,KAE5F,CAEQ,WAAA5B,CAAY/D,EAAsBqF,GACtB,SAAdrF,EACEV,KAAKQ,aAAeR,KAAKe,oBAC3Bf,KAAKQ,YAAYyE,YAAY,CAAEC,QAAS,SAAU4B,QAAS,CAACf,IAAY,CAACA,EAAQrB,SAE5D,QAAdhE,GACLV,KAAKS,YAAcT,KAAKgB,mBAC1BhB,KAAKS,WAAWwE,YAAY,CAAEC,QAAS,SAAUa,QAASA,GAAW,CAACA,EAAQrB,QAGpF,CAEQ,gBAAAa,GACN,GAAIvF,KAAKc,oBAAqB,CAC5B,MAAMP,EAAmBP,KAAKO,iBAE9B,OAAO,IAAI3C,QAAwBC,IACjC,MAAMgI,EAAW,EAAG3I,WACI,iBAAlB,GAAuC,OAATA,GAIb,SAAjBA,EAAKwE,UACPnB,EAAiB6E,KAAKc,oBAAoB,UAAWL,GACrDhI,EAAQgB,OAIZ0B,EAAiB6E,KAAKe,iBAAiB,UAAWN,GAClDtF,EAAiB6E,KAAKH,YAAY,CAAEC,QAAS,SAC7ClF,KAAKc,qBAAsB,GAE/B,CACA,OAAOlD,QAAQC,QAAQgB,IACzB,CAEQ,WAAA2G,CAAY9E,GAClB,MAAkB,SAAdA,EACKV,KAAK+G,kBACW,QAAdrG,EACFV,KAAKgH,iBAEPpJ,QAAQC,QAAQgB,EAAO,MAChC,CAEQ,eAAAkI,GACN,GAAI/G,KAAKe,mBAAoB,CAC3B,MAAMP,EAAcR,KAAKQ,YAEzB,OAAO,IAAI5C,QAA+BC,IACxC,MAAMgI,EAAW,EAAG3I,WAClB,GAAsB,iBAAlB,GAAuC,OAATA,GAIb,SAAjBA,EAAKwE,QAAoB,CAC3BlB,EAAY0F,oBAAoB,UAAWL,GAC3C,MAAMoB,EAAY/J,EAAK+J,UAAa/J,EAAK+J,UAAqB,KAC9DpJ,EAAQgB,EAAOoI,GACjB,GAGFzG,EAAY2F,iBAAiB,UAAWN,GACxCrF,EAAYyE,YAAY,CAAEC,QAAS,SACnClF,KAAKe,oBAAqB,GAE9B,CACA,OAAOnD,QAAQC,QAAQgB,EAAO,MAChC,CAEQ,cAAAmI,GACN,GAAIhH,KAAKgB,kBAAmB,CAC1B,MAAMP,EAAaT,KAAKS,WAExB,OAAO,IAAI7C,QAA+BC,IACxC,MAAMgI,EAAW,EAAG3I,WAClB,GAAsB,iBAAlB,GAAuC,OAATA,GAIb,SAAjBA,EAAKwE,QAAoB,CAC3BjB,EAAWyF,oBAAoB,UAAWL,GAC1C,MAAMoB,EAAY/J,EAAK+J,UAAa/J,EAAK+J,UAAqB,KAC9DpJ,EAAQgB,EAAOoI,GACjB,GAGFxG,EAAW0F,iBAAiB,UAAWN,GACvCpF,EAAWwE,YAAY,CAAEC,QAAS,SAClClF,KAAKgB,mBAAoB,GAE7B,CACA,OAAOpD,QAAQC,QAAQgB,EAAO,MAChC,CAEQ,IAAAqE,IAAQhG,GACdR,EAAMY,SAASJ,EACjB,CAEQ,IAAAoI,IAAQpI,GACdR,EAAMW,QAAQH,EAChB,CAEQ,IAAA+C,IAAQ/C,GACdR,EAAMU,QAAQF,EAChB,CAEQ,IAAAgK,IAAQhK,GACdR,EAAMO,SAASC,EACjB,EE7uBK,MAAMiK,EAAiB,yBACjBC,EAAyB,GCFzBC,EAAkB,aCAlBC,EAEK,MAFLA,EAIS,MAJTA,EAKK,MALLA,EAMG,MANHA,EAOU,MAPVA,EAQS,MARTA,EASI,MATJA,EAUM,MAVNA,EAWC,MAXDA,EAiBF,MAjBEA,EAkBA,MAlBAA,EAmBI,MAnBJA,EAoBA,MApBAA,EAuBA,MC2Bb,IAAKC,EAQL,SAASC,EAAUC,EAAenK,GAChC,MAAO,CAAEmK,QAAOnK,QAClB,EAVA,SAAKiK,GACHA,EAAA,KAAA,OACAA,EAAA,WAAA,aACAA,EAAA,WAAA,cACAA,EAAA,QAAA,UACAA,EAAA,IAAA,KACD,CAND,CAAKA,IAAAA,EAAc,CAAA,UAYNG,EAYX,WAAA9H,CAAY+H,GAyBZ3H,KAAA4H,cAA8EjH,EAxB5E,MAAMkH,MAAEA,EAAQ,CAAA,GAAOF,EAEvB,IAAIG,OAAEA,EAASX,EAAcY,cAAEA,EAAgBX,GAA2BS,EAC1EC,EAASA,EAAOE,QAAQ,QAAS,IAC7BD,GAAiB,IACnBA,EAAgBX,GAGlBpH,KAAKiI,QAAUH,EACf9H,KAAKkI,eAAiBH,EACtB/H,KAAKmI,OAASZ,EAAea,KAC7BpI,KAAKqI,YAAa,EAClBrI,KAAKsI,YAAa,EAClBtI,KAAKuI,SPvFA,uCAAuCP,QAAQ,QACnDQ,IACC,IAAIC,EAAoB,GAAhBC,KAAKC,SAAgB,EAE7B,OADW,KAALH,EAAWC,EAAS,EAAJA,EAAU,GACvBG,SAAS,MOoFpB5I,KAAK6I,YAASlI,EACdX,KAAK8I,OAAS,GACd9I,KAAK+I,gBAAapI,EAClBX,KAAKgJ,kBAAerI,CACtB,CAEA,UAAAsI,GACE,OAAOjJ,KAAKuI,QACd,CAIA,KAAAnF,CAAM8F,GAEJ,GAAIlJ,KAAKmI,SAAWZ,EAAe4B,IAEjC,OAGF,GAAInJ,KAAKsI,WAEP,YADAtI,KAAKoJ,iBAAiB5B,EAAUF,EAAgB,sCAIlD,GAAItH,KAAKqI,WAEP,YADArI,KAAKoJ,iBAAiB5B,EAAUF,EAAgB,2BAMlD,GAHAtH,KAAKqI,YAAa,EAGdrI,KAAKmI,SAAWZ,EAAea,KAGjC,YADApI,KAAKoJ,iBAAiB5B,EAAUF,EAAe,gCAAgCtH,KAAKmI,WAItF,GAAuB,iBAAnB,GAAwC,MAATe,EAEjC,YADAlJ,KAAKoJ,iBAAiB5B,EAAUF,EAAe,kBAIjD,GAAiB,MAAb4B,EAAMG,IAER,YADArJ,KAAKoJ,iBAAiB5B,EAAUF,EAAe,0BAGjD,GAA2B,iBAAf4B,EAAS,IAEnB,YADAlJ,KAAKoJ,iBAAiB5B,EAAUF,EAAe,+BAGjD,GAA+B,MAA3B4B,EAAMG,IAAIC,eAAqD,KAA5BJ,EAAMG,IAAIC,cAE/C,YADAtJ,KAAKoJ,iBAAiB5B,EAAUF,EAAe,wCAGjD,GAAyC,iBAA7B4B,EAAMG,IAAiB,cAEjC,YADArJ,KAAKoJ,iBAAiB5B,EAAUF,EAAe,6CAIjD,GAAmB,MAAf4B,EAAMlF,MAER,YADAhE,KAAKoJ,iBAAiB5B,EAAUF,EAAe,4BAGjD,GAA6B,iBAAjB4B,EAAW,MAErB,YADAlJ,KAAKoJ,iBAAiB5B,EAAUF,EAAe,iCAIjD,GAAqB,MAAjB4B,EAAMK,QAER,YADAvJ,KAAKoJ,iBAAiB5B,EAAUF,EAAe,8BAGjD,GAA+B,iBAAnB4B,EAAa,QAEvB,YADAlJ,KAAKoJ,iBAAiB5B,EAAUF,EAAe,mCAGjD,GAA8B,MAA1B4B,EAAMK,QAAQC,UAA+C,KAA3BN,EAAMK,QAAQC,SAElD,YADAxJ,KAAKoJ,iBAAiB5B,EAAUF,EAAe,uCAGjD,GAAwC,iBAA5B4B,EAAMK,QAAgB,SAEhC,YADAvJ,KAAKoJ,iBAAiB5B,EAAUF,EAAe,4CAIjD,MAAMgC,cAAEA,GAAkBJ,EAAMG,KAC1BG,SAAEA,EAAQ9K,IAAEA,GAAQwK,EAAMK,QAYhC,IAAIE,EAVJzJ,KAAK6I,OAAS,CACZQ,IAAKK,OAAOC,OAAO,CAAA,EAAIT,EAAMG,KAC7BrF,MAAO0F,OAAOC,OAAO,CAAA,EAAIT,EAAMlF,OAC/BuF,QAASG,OAAOC,OAAO,CAAA,EAAIT,EAAMK,UAEnCvJ,KAAKqI,YAAa,EAGlBrI,KAAKmI,OAASZ,EAAeqC,WAI3BH,EADE/K,EACI,GAAGsB,KAAKiI,WAAWuB,KAAY9K,oBAAsB4K,IAErD,GAAGtJ,KAAKiI,WAAWuB,oBAA2BF,IAEtDtJ,KAAK+I,WAAa,IAAIc,UAAUJ,GAChCzJ,KAAK+I,WAAWe,WAAa,cAC7B9J,KAAK+I,WAAWgB,OAAS,KAAQ/J,KAAKgK,oBACtChK,KAAK+I,WAAWkB,UAAaC,IAASlK,KAAKmK,oBAAoBD,IAC/DlK,KAAK+I,WAAWqB,QAAWF,IAASlK,KAAKqK,kBAAkBH,IAC3DlK,KAAK+I,WAAWuB,QAAWJ,IAASlK,KAAKuK,kBAAkBL,GAC7D,CAEQ,gBAAAF,iBAEFhK,KAAKmI,SAAWZ,EAAe4B,MAM/BnJ,KAAKmI,SAAWZ,EAAeqC,aAMhB,QAAfY,EAAAxK,KAAK+I,kBAAU,IAAAyB,OAAA,EAAAA,EAAEC,cAAeZ,UAAUa,OAE5C1K,KAAK+I,WAAW4B,KAAKC,KAAKC,UAAU,CAClCC,IAAK,UACL5B,MAAO,CACLG,YAAK0B,EAAA/K,KAAK6I,6BAAQQ,IAClB2B,IAAK,CACHC,QAAS5D,EACT6D,OAAQ,IACRC,SAAU,SAMhBnL,KAAK+I,WAAW4B,KAAKC,KAAKC,UAAU,CAClCC,IAAK,QACL5B,MAAO,CACLkC,QAASpL,KAAKuI,SACdvE,cAAOqH,EAAArL,KAAK6I,6BAAQ7E,MACpBuF,gBAAS+B,EAAAtL,KAAK6I,6BAAQU,QACtBF,YAAKkC,EAAAvL,KAAK6I,6BAAQQ,IAClB2B,IAAK,CACHC,QAAS5D,EACT6D,OAAQ,IACRC,SAAU,UAOlBnL,KAAKmI,OAASZ,EAAeiE,WAC7BxL,KAAKyL,YArCHzL,KAAKoJ,iBAAiB5B,EAAUF,EAAe,2CAA2CtH,KAAKmI,WAsCnG,CAEQ,mBAAAgC,CAAoBD,GAE1B,GAAIlK,KAAKmI,SAAWZ,EAAe4B,IAAnC,CAKA,GAAyB,iBAAbe,EAAO,KAAgB,CAEjC,IAAIwB,EACJ,IACEA,EAAOd,KAAKe,MAAMzB,EAAGhN,KACvB,CAAE,MAAO6B,GAGP,YADAiB,KAAKoJ,iBAAiB5B,EAAUF,EAAe,0BAEjD,CAaA,OAVgB,MAAZoE,EAAKE,KAA2BjL,MAAZ+K,EAAKE,MAE3BF,EAAKE,IAAM,QAGTF,EAAKjE,OAAsB,IAAbiE,EAAKE,IACrB5L,KAAKoJ,iBAAiBsC,GAEtB1L,KAAK6L,YAAYH,GAGrB,CAEE1L,KAAKoJ,iBAAiBc,EAAGhN,KA3B3B,CA8BF,CAEQ,iBAAAqN,CAAkBL,GACxB,MAAM4B,SAAEA,EAAQC,KAAEA,EAAIC,OAAEA,GAAW9B,QAAAA,EAAM,CAAA,EAGzC,GAAIlK,KAAKmI,SAAWZ,EAAe4B,IAKnC,OAAInJ,KAAKmI,SAAWZ,EAAeqC,gBAEjC5J,KAAKoJ,iBAAiB5B,EAAUF,EAAa,mDAAmDwE,WAAkBC,aAAgBC,WAIlIhM,KAAKoJ,iBAAiB5B,EAAUF,EAAa,8CAA8CwE,WAAkBC,aAAgBC,KAGjI,CAEQ,iBAAA3B,CAAkBH,GAE1B,CAEQ,cAAA+B,GAEFjM,KAAKmI,SAAWZ,EAAe4B,MAKnCnJ,KAAKgJ,kBAAerI,EACpBX,KAAKoJ,iBAAiB5B,EAAUF,EAAoB,mBACtD,CAEQ,QAAAmE,WAEN,GAAIzL,KAAKmI,SAAWZ,EAAe4B,IAMnC,GAAInJ,KAAKmI,SAAWZ,EAAeiE,WAAnC,CAMA,GAAIxL,KAAK8I,OAAOoD,OAAS,EAAG,CAC1B,MAAMhP,EAAO8C,KAAK8I,OAAOqD,QAUzB,OATY,MAARjP,IAEiB,QAAfsN,EAAAxK,KAAK+I,kBAAU,IAAAyB,OAAA,EAAAA,EAAEC,cAAeZ,UAAUa,MAC5C1K,KAAK+I,WAAW4B,KAAKzN,QAGzBsC,WAAW,KACTQ,KAAKyL,YACJ,EAEL,CAEIzL,KAAKsI,aAEY,QAAfyC,EAAA/K,KAAK+I,kBAAU,IAAAgC,OAAA,EAAAA,EAAEN,cAAeZ,UAAUa,MAC5C1K,KAAK+I,WAAW4B,KAAKC,KAAKC,UAAU,CAClCC,IAAK,UAMX9K,KAAKmI,OAASZ,EAAe6E,OA1B7B,MAFEpM,KAAKoJ,iBAAiB5B,EAAUF,EAAe,mCAAmCtH,KAAKmI,UA8B3F,CAEA,IAAAkE,CAAKnP,SAEC8C,KAAKmI,SAAWZ,EAAe4B,MAK9BnJ,KAAKqI,WAKNrI,KAAKsI,WACPtI,KAAKoJ,iBAAiB5B,EAAUF,EAAgB,0BAItC,MAARpK,GAAmC,MAAnBA,EAAKoP,YAAyC,GAAnBpP,EAAKoP,aAIhDtM,KAAKmI,SAAWZ,EAAeqC,YAAc5J,KAAKmI,SAAWZ,EAAeiE,WAE9ExL,KAAK8I,OAAO7C,KAAK/I,GACR8C,KAAKmI,SAAWZ,EAAe6E,UAErB,QAAf5B,EAAAxK,KAAK+I,kBAAU,IAAAyB,OAAA,EAAAA,EAAEC,cAAeZ,UAAUa,MAC5C1K,KAAK+I,WAAW4B,KAAKzN,IAnBvB8C,KAAKoJ,iBAAiB5B,EAAUF,EAAgB,4BAsBpD,CAEA,IAAA3C,SAEM3E,KAAKmI,SAAWZ,EAAe4B,MAK9BnJ,KAAKqI,WAKNrI,KAAKsI,WACPtI,KAAKoJ,iBAAiB5B,EAAUF,EAAgB,sBAGlDtH,KAAKsI,YAAa,EAEdtI,KAAKmI,SAAWZ,EAAe6E,UAEd,QAAf5B,EAAAxK,KAAK+I,kBAAU,IAAAyB,OAAA,EAAAA,EAAEC,cAAeZ,UAAUa,MAC5C1K,KAAK+I,WAAW4B,KAAKC,KAAKC,UAAU,CAClCC,IAAK,UAKX9K,KAAKgJ,aAAexJ,WAAW,KAC7BQ,KAAKiM,kBACkB,IAAtBjM,KAAKkI,iBArBNlI,KAAKoJ,iBAAiB5B,EAAUF,EAAgB,4BAsBpD,CAMA,KAAA1C,GAEM5E,KAAKmI,SAAWZ,EAAe4B,MAI/BnJ,KAAKmI,SAAWZ,EAAea,MAMnCpI,KAAKuM,SACLvM,KAAK6I,YAASlI,EACdX,KAAK8I,OAAS,IANZ9I,KAAKmI,OAASZ,EAAe4B,IAOjC,CAEQ,gBAAAC,CAAiBoD,GAEnBxM,KAAKmI,SAAWZ,EAAe4B,MAInCnJ,KAAKuM,SACLvM,KAAK6L,YAAYW,GACnB,CAEQ,MAAAD,GAEFvM,KAAK+I,aAEP/I,KAAK+I,WAAWnE,QAChB5E,KAAK+I,gBAAapI,QAGMA,IAAtBX,KAAKgJ,eAEPyD,aAAazM,KAAKgJ,cAClBhJ,KAAKgJ,kBAAerI,GAItBX,KAAKmI,OAASZ,EAAe4B,GAC/B,CAEQ,WAAA0C,CAAYW,GAElB,MAAME,EAAK1M,KAAK4H,SACZ8E,GACFlN,WAAW,KAAQkN,EAAGF,IAAQ,EAElC,EC3YF,IAAKG,GAAL,SAAKA,GACHA,EAAA,QAAA,UACAA,EAAA,KAAA,OACAA,EAAA,SAAA,WACAA,EAAA,QAAA,UACAA,EAAA,SAAA,UACD,CAND,CAAKA,IAAAA,EAAa,CAAA,4BA+BhB,WAAA/M,CAAYC,GAmBV,GAlBAnD,EAAMU,KAAK,2BAEX4C,KAAKiI,QAAUd,EACfnH,KAAKkI,eAAiBd,EACtBpH,KAAK4M,SAAW,OAEhB5M,KAAKmI,OAASwE,EAAcxM,QAC5BH,KAAK6M,iBAAkB,EACvB7M,KAAK8M,iBAAkB,EACvB9M,KAAK+M,yBAA2B,KAChC/M,KAAKgN,oBAAqB,EAC1BhN,KAAKiN,iBAAmB,KAExBjN,KAAKkN,UAAY,KACjBlN,KAAKmN,kBAAexM,EACpBX,KAAKoN,WAAa,KAClBpN,KAAKqN,cAAgB,GAEI,iBAArB,GAA6C,OAAZxN,EAGnC,OAFAnD,EAAMY,MAAM,mEACZ0C,KAAKmI,OAASwE,EAAcW,UAI9B,IAAIxF,OAAEA,EAAMC,cAAEA,EAAajI,SAAEA,EAAQC,QAAEA,GAAYF,EAC3B,iBAApB,IAAgCiI,EAASX,GACd,iBAA3B,IAAuCY,EAAgBX,GACjC,mBAAtB,IAAoCtH,EAAW,QAC1B,mBAArB,IAAmCC,EAAU,QAEjDC,KAAKiI,QAAUH,EACf9H,KAAKkI,eAAiBH,EAAgB,EAAIA,EAAgBX,EAC1DpH,KAAK4M,SAAW7M,EAEhBC,KAAKkN,UAAY,IAAIvN,EAAS,CAC5BG,SAAU,KACR,GAAIE,KAAKgN,mBAAoB,CAC3B,MAAMO,EAAgBvN,KAAKiN,iBAC3BjN,KAAKwN,iBACLxN,KAAKmI,OAASwE,EAAcW,SAC5BtN,KAAKiN,iBAAmB,KACxBjN,KAAKgN,oBAAqB,EAC1B,MAAMjO,EAAMwO,QAAAA,EAAiB,CAAE9F,MAAOH,EAAqBhK,MAAO,oCAElE,YADAmC,EAAU,KAAQM,EAAQhB,IAE5B,CAEArC,EAAMU,KAAK,6BACX4C,KAAKmI,OAASwE,EAAcxJ,KAC5B1D,EAAU,KAAQK,OAGpBC,QAAUhB,IACR,GAAIiB,KAAKmI,SAAWwE,EAAcxM,QAAS,CAGzC,GAFAzD,EAAMY,MAAM,gCAAgCyB,EAAI2C,WAE5C1B,KAAKgN,mBAAoB,CAC3B,MAAMO,EAAgBvN,KAAKiN,iBAC3BjN,KAAKwN,iBACLxN,KAAKmI,OAASwE,EAAcW,SAC5BtN,KAAKiN,iBAAmB,KACxBjN,KAAKgN,oBAAqB,EAC1B,MAAMS,EAAUF,QAAAA,EAAiB,CAAE9F,MAAOH,EAAwBhK,MAAO,uBAAuByB,EAAI2C,WAEpG,YADAjC,EAAU,KAAQM,EAAQ0N,IAE5B,CAEAzN,KAAKwN,iBACLxN,KAAKmI,OAASwE,EAAcW,SAC5B,MAAMG,EAAU,CAAEhG,MAAOH,EAAwBhK,MAAO,uBAAuByB,EAAI2C,WAEnF,YADAjC,EAAU,KAAQM,EAAQ0N,IAE5B,CAGA/Q,EAAMW,KAAK,6EAA6E2C,KAAKmI,2BAA2BpJ,EAAI2C,aAGlI,CAEA,KAAA0B,CAAMvD,GAGJ,GAFAnD,EAAMU,KAAK,6BAEc,iBAArB,GAA6C,OAAZyC,EAEnC,YADAnD,EAAMY,MAAM,+DAId,IAAIoQ,EAOJ,GALEA,EADgC,iBAAtB7N,EAAgB,UAAuC,OAArBA,EAAQ6N,SACzC,CAAEC,OAAQ,OAAWC,QAAS,OAAW7N,QAAS,QAElD2J,OAAOC,OAAO,CAAEgE,OAAQ,OAAWC,QAAS,OAAW7N,QAAS,QAAaF,EAAQ6N,UAG9F1N,KAAKmI,SAAWwE,EAAcW,UAAYtN,KAAKgN,mBAAoB,CACrE,MAAMjO,EAAqB,CAAE0I,MAAOH,EAAqBhK,MAAO,iCAEhE,YADA+B,EAAS,KAAQqO,EAAS3N,QAAQhB,IAEpC,CAEA,GAAIiB,KAAKmI,SAAWwE,EAAcxM,QAAS,CACzC,MAAMpB,EAAqB,CAAE0I,MAAOH,EAAkBhK,MAAO,yCAE7D,YADA+B,EAAS,KAAQqO,EAAS3N,QAAQhB,IAEpC,CAEA,GAAIiB,KAAKmI,SAAWwE,EAAclJ,UAAYzD,KAAKmI,SAAWwE,EAAcjJ,QAAS,CACnF,MAAM3E,EAAqB,CAAE0I,MAAOH,EAAoBhK,MAAO,uCAE/D,YADA+B,EAAS,KAAQqO,EAAS3N,QAAQhB,IAEpC,CAEA,GAAIiB,KAAKmI,SAAWwE,EAAcxJ,KAAM,CACtC,MAAMpE,EAAqB,CAAE0I,MAAOH,EAAehK,MAAO,yCAAyC0C,KAAKmI,UAExG,YADA9I,EAAS,KAAQqO,EAAS3N,QAAQhB,IAEpC,CAEA,IAAI2B,UAAEA,EAASmN,SAAEA,EAAUxE,IAAKyE,EAASC,aAAcC,GAAqBnO,EAE5E,GAA2B,iBAAvB,GAAmD,SAAda,GAAsC,QAAdA,EAAsB,CACrF,MAAM3B,EAAqB,CAAE0I,MAAOH,EAAehK,MAAO,4CAE1D,YADA+B,EAAS,KAAQqO,EAAS3N,QAAQhB,IAEpC,CAMA,GAJ0B,iBAAtB,IACF8O,OAAWlN,GAGY,iBAArB,GAA6C,OAAZmN,EAAkB,CACrD,MAAM/O,EAAqB,CAAE0I,MAAOH,EAAehK,MAAO,sCAE1D,YADA+B,EAAS,KAAQqO,EAAS3N,QAAQhB,IAEpC,CAEA,GAAkC,iBAA9B,GAA+D,OAArBiP,EAA2B,CACvE,MAAMjP,EAAqB,CAAE0I,MAAOH,EAAehK,MAAO,+CAE1D,YADA+B,EAAS,KAAQqO,EAAS3N,QAAQhB,IAEpC,CAEA,IAAIsK,EAAuBK,OAAOC,OAAO,CAAEL,cAAe,GAAI2E,IAAK,GAAIC,IAAK,GAAIC,UAAW,IAAML,GAC7FvE,EAAoCG,OAAOC,OAAO,CAAA,EAAIqE,GAE1DhO,KAAKmI,OAASwE,EAAclJ,SAE5B,MAAM2K,EAAyB,CAC7BC,QAAS,IAAIC,EAAgB,CAAEzG,MAAO,CAAEC,OAAQ9H,KAAKiI,QAASF,cAAe/H,KAAKkI,kBAClFwF,SAAUA,EACVa,SAAS,GAGXvO,KAAKoN,WAAagB,EAClBpO,KAAKoN,WAAWiB,QAAQzG,SAAYlJ,IAAUsB,KAAKwO,qBAAqBJ,EAAW1P,IACnFsB,KAAKoN,WAAWiB,QAAQjL,MAAM,CAC5BY,MAAO,CAAEtD,YAAW+N,QA9QV,EA8Q4BC,YA7QvB,EA6QkDrL,WA5QnD,MA6QdgG,MAAKE,YAGPvJ,KAAKkN,UAAW9J,MAAM,CACpB1C,YACA2C,WAlRc,KAmRdC,UAAW,KACT,GAAItD,KAAKgN,mBACPhN,KAAKkN,UAAWvI,KAAK,CACnBrB,UAAYqL,IACV,MAAMpB,EAAgBvN,KAAKiN,iBACrB2B,EAA4B,GAClC5O,KAAK6O,cAAcD,EAAW,CAAEnH,MAAOH,EAAmBhK,MAAO,aAAaiQ,EAAgBA,EAAcjQ,MAAQ,wBACpH0C,KAAK8O,qBAAqBF,EAAWrB,GACrCvN,KAAK+O,eAAeH,IAGtBrL,OAAQ,CAACxE,EAAKiQ,KACZ,MAAMzB,EAAgBvN,KAAKiN,iBACrBgC,EAAmBD,EAAc,KAAO,CAAEvH,MAAOH,EAAmBhK,MAAO,oBAAoByB,EAAI2C,WACnGkN,EAA4B,GAClC5O,KAAK6O,cAAcD,EAAW,CAAEnH,MAAOH,EAAwBhK,MAAO,iBAAiByB,EAAI2C,YAAY6L,EAAgB,mBAAqBA,EAAcjQ,MAAQ,OAClK0C,KAAK8O,qBAAqBF,EAAWrB,QAAAA,EAAiB0B,GACtDjP,KAAK+O,eAAeH,UAhB1B,CAuBA,GAAI5O,KAAK6M,gBAMP,OALA7M,KAAKmI,OAASwE,EAAcjJ,QACvB0K,EAAUG,SACb9O,EAAU,qBAAQsL,GAAAP,EAAA4D,EAAUV,UAASwB,uCAEvClP,KAAKmP,wBAIHtB,GAAYA,EAAW,GACzB7N,KAAKoP,kBAAkBvB,GAGzB7N,KAAKmI,OAASwE,EAAcjJ,QACvB0K,EAAUG,SACb9O,EAAU,KAAK,IAAA+K,EAAAO,EAA6B,QAA1BA,KAAAqD,EAAUV,UAASwB,eAAO,IAAAnE,GAAAA,EAAAsE,KAAA7E,IAjB9C,GAqBFjH,OAAQ,CAACxE,EAAKiQ,KACZtS,EAAMY,MAAM,6CAA6C0R,OAAiBjQ,EAAI2C,WAC9E,MAAMkN,EAA4B,GAElC,GAAI5O,KAAKgN,mBAAoB,CAC3B,MAAMO,EAAgBvN,KAAKiN,iBACrBgC,EAAmBD,EAAc,KAAO,CAAEvH,MAAOH,EAAmBhK,MAAO,gCAAgCyB,EAAI2C,WAIrH,OAHA1B,KAAK6O,cAAcD,EAAW,CAAEnH,MAAOH,EAAyBhK,MAAO,wBAAwByB,EAAI2C,YACnG1B,KAAK8O,qBAAqBF,EAAWrB,QAAAA,EAAiB0B,QACtDjP,KAAK+O,eAAeH,EAEtB,CAEA,IAAKI,EAAa,CAChB,MAAMC,EAAkC,CAAExH,MAAOH,EAAmBhK,MAAO,gCAAgCyB,EAAI2C,WAI/G,OAHA1B,KAAK6O,cAAcD,EAAW,CAAEnH,MAAOH,EAAyBhK,MAAO,wBAAwByB,EAAI2C,YACnG1B,KAAK8O,qBAAqBF,EAAWK,QACrCjP,KAAK+O,eAAeH,EAEtB,CAEA5O,KAAK6O,cAAcD,EAAW,CAAEnH,MAAOH,EAAyBhK,MAAO,wBAAwByB,EAAI2C,YACnG1B,KAAKmI,OAASwE,EAAcxJ,KAC5BnD,KAAK6M,iBAAkB,EACvB7M,KAAK8M,iBAAkB,EACvB9M,KAAK+M,yBAA2B,KAChC/M,KAAK+O,eAAeH,IAGtBpL,YAActG,IACR8C,KAAKmI,SAAWwE,EAAclJ,UAAYzD,KAAKmI,SAAWwE,EAAcjJ,SACtE1D,KAAKoN,YACPpN,KAAKoN,WAAWiB,QAAQhC,KAAKnP,KAMvC,CAEA,IAAAyH,CAAK9E,GAMH,IAAIyP,EALJ5S,EAAMU,KAAK,4BACc,iBAArB,GAA6C,OAAZyC,IACnCA,OAAUc,GAIRd,GAAuC,kBAApBA,EAAc,SACnCyP,EAASzP,EAAQyP,QAGnBtP,KAAKuP,UAAU1P,QAAAA,EAAW,CAAEyP,UAC9B,CAEQ,UAAAE,CAAW3P,GACjBnD,EAAMU,KAAK,+BACX4C,KAAKuP,UAAU1P,EACjB,CAEQ,SAAA0P,CAAU1P,GAChB,IAAMyP,OAAQG,GAAa,GAAU5P,EAEjCG,KAAKmI,SAAWwE,EAAcW,WAI9BtN,KAAKgN,oBAILhN,KAAKmI,SAAWwE,EAAcxM,SAI9BH,KAAKmI,SAAWwE,EAAcxJ,OAI9BnD,KAAKmI,SAAWwE,EAAclJ,SAS9BzD,KAAKmI,SAAWwE,EAAcjJ,SAC3B1D,KAAK6M,kBACR7M,KAAK6M,iBAAkB,EACvB7M,KAAK8M,gBAAkB2C,EACvBzP,KAAK+M,yBAA2B,KAChC/M,KAAKmP,yBAbFnP,KAAK6M,kBACR7M,KAAK6M,iBAAkB,EACvB7M,KAAK8M,gBAAkB2C,EACvBzP,KAAK+M,yBAA2B,OActC,CAEA,OAAA2C,GAEE,GADAhT,EAAMU,KAAK,+BACP4C,KAAKmI,SAAWwE,EAAcW,WAI9BtN,KAAKgN,mBAAT,CAIA,GAAIhN,KAAKmI,SAAWwE,EAAcxM,QAGhC,OAFAH,KAAKgN,oBAAqB,OAC1BhN,KAAKiN,iBAAmB,MAI1B,GAAIjN,KAAKmI,SAAWwE,EAAcxJ,KAAM,CACtC,MAAMyL,EAA4B,GAGlC,OAFA5O,KAAK8O,qBAAqBF,EAAW,WACrC5O,KAAK+O,eAAeH,EAEtB,CAEA,OAAI5O,KAAKmI,SAAWwE,EAAclJ,UAChCzD,KAAKgN,oBAAqB,OAC1BhN,KAAKiN,iBAAmB,OAItBjN,KAAKmI,SAAWwE,EAAcjJ,SAChC1D,KAAKgN,oBAAqB,EAC1BhN,KAAKiN,iBAAmB,UACnBjN,KAAK6M,kBACR7M,KAAK6M,iBAAkB,EACvB7M,KAAK8M,iBAAkB,EACvB9M,KAAK+M,yBAA2B,KAChC/M,KAAKmP,gCAPT,CArBA,CAgCF,CAGA,YAAAtK,GACE,OAAI7E,KAAKkN,UACAlN,KAAKkN,UAAUrI,eAEf,CAEX,CAGA,YAAAE,CAAaC,GACPhF,KAAKkN,WACPlN,KAAKkN,UAAUnI,aAAaC,EAEhC,CAGQ,qBAAAmK,GACNzS,EAAMU,KAAK,0CAEX4C,KAAK2P,oBAEL3P,KAAKkN,UAAWvI,KAAK,CACnBrB,UAAY2D,IACV,MAAM2H,EAA4B,GAElC,GAAI5O,KAAKgN,mBAAoB,CAC3B,MAAMO,EAAgBvN,KAAKiN,iBAC3B,GAAIjN,KAAKoN,WAAY,CACnB,MAAMgB,EAAYpO,KAAKoN,WAClBgB,EAAUG,SACbK,EAAU3I,KAAK,KAAQmI,EAAUV,SAASC,OAAO1G,IAErD,CAIA,OAHAjH,KAAK6O,cAAcD,EAAW,CAAEnH,MAAOH,EAAmBhK,MAAO,aAAaiQ,EAAgBA,EAAcjQ,MAAQ,wBACpH0C,KAAK8O,qBAAqBF,EAAWrB,QACrCvN,KAAK+O,eAAeH,EAEtB,CAEA,GAAI5O,KAAK8M,gBAAiB,CACxB,GAAI9M,KAAKoN,WAAY,CACnB,MAAMgB,EAAYpO,KAAKoN,WAClBgB,EAAUG,SACbK,EAAU3I,KAAK,KAAQmI,EAAUV,SAASC,OAAO1G,IAErD,CAOA,OANAjH,KAAK6O,cAAcD,EAAW,CAAEnH,MAAOH,EAAmBhK,MAAO,aACjE0C,KAAKmI,OAASwE,EAAcxJ,KAC5BnD,KAAK6M,iBAAkB,EACvB7M,KAAK8M,iBAAkB,EACvB9M,KAAK+M,yBAA2B,UAChC/M,KAAK+O,eAAeH,EAEtB,CAEA,GAAI5O,KAAKoN,WAAY,CACnB,MAAMgB,EAAYpO,KAAKoN,WAClBgB,EAAUG,SACbK,EAAU3I,KAAK,KAAQmI,EAAUV,SAASC,OAAO1G,KAGnD,MAAMvI,EAAMsB,KAAK+M,yBACN,MAAPrO,GACF0P,EAAUC,QAAQ1J,OAClB3E,KAAKqN,cAAcpH,KAAKmI,KAEnBA,EAAUG,SACT7P,aAAekR,cAERlR,EAAI+I,OAAuB,IAAd/I,EAAI+I,MAC1BmH,EAAU3I,KAAK,KAAQmI,EAAUV,SAAS3N,QAAQrB,KAElDkQ,EAAU3I,KAAK,KAAQmI,EAAUV,SAASE,QAAQlP,MAGtD0P,EAAUC,QAAQzJ,SAGpB5E,KAAKoN,WAAa,IACpB,CACApN,KAAKmI,OAASwE,EAAcxJ,KAC5BnD,KAAK6M,iBAAkB,EACvB7M,KAAK8M,iBAAkB,EACvB9M,KAAK+M,yBAA2B,KAChC/M,KAAK+O,eAAeH,IAGtBrL,OAAQ,CAACxE,EAAKiQ,KACZtS,EAAMY,MAAM,gCAAgCyB,EAAI2C,WAChD,MAAMkN,EAA4B,GAElC,GAAI5O,KAAKgN,mBAAoB,CAC3B,MAAMO,EAAgBvN,KAAKiN,iBACrBgC,EAAmBD,EAAc,KAAO,CAAEvH,MAAOH,EAAmBhK,MAAO,oBAAoByB,EAAI2C,WAIzG,OAHA1B,KAAK6O,cAAcD,EAAW,CAAEnH,MAAOH,EAAwBhK,MAAO,iBAAiByB,EAAI2C,YAAY6L,EAAgB,mBAAqBA,EAAcjQ,MAAQ,OAClK0C,KAAK8O,qBAAqBF,EAAWrB,QAAAA,EAAiB0B,QACtDjP,KAAK+O,eAAeH,EAEtB,CAEA,IAAKI,EAIH,OAHAhP,KAAK6O,cAAcD,EAAW,CAAEnH,MAAOH,EAAwBhK,MAAO,uBAAuByB,EAAI2C,YACjG1B,KAAK8O,qBAAqBF,EAAW,CAAEnH,MAAOH,EAAmBhK,MAAO,oBAAoByB,EAAI2C,iBAChG1B,KAAK+O,eAAeH,GAItB5O,KAAK6O,cAAcD,EAAW,CAAEnH,MAAOH,EAAwBhK,MAAO,uBAAuByB,EAAI2C,YACjG1B,KAAKmI,OAASwE,EAAcxJ,KAC5BnD,KAAK6M,iBAAkB,EACvB7M,KAAK8M,iBAAkB,EACvB9M,KAAK+M,yBAA2B,KAChC/M,KAAK+O,eAAeH,KAG1B,CAGQ,oBAAAE,CAAqBF,EAA2BrB,GACtD,MAAMsC,EAAe,cAAgBtC,EAAgBA,EAAcjQ,MAAQ,qBAC3E0C,KAAK8P,oBAAoBlB,EAAWiB,GACpC7P,KAAKwN,iBACLxN,KAAKmI,OAASwE,EAAcW,SAC5BtN,KAAKiN,iBAAmB,KACxBjN,KAAKgN,oBAAqB,EAC1BhN,KAAK6M,iBAAkB,EACvB7M,KAAK8M,iBAAkB,EACvB9M,KAAK+M,yBAA2B,KAE5BQ,GACFqB,EAAU3I,KAAK,KAAQjG,KAAK4M,SAASW,IAEzC,CAEQ,iBAAA6B,CAAkBW,GACxB/P,KAAK2P,oBACL3P,KAAKmN,aAAe3N,WAAW,KAC7B9C,EAAMU,KAAK,qCACX4C,KAAKmN,kBAAexM,EACpBX,KAAKwP,WAAW,CAAEF,QAAQ,KACzBS,EACL,CAEQ,iBAAAJ,QACoBhP,IAAtBX,KAAKmN,eACPV,aAAazM,KAAKmN,cAClBnN,KAAKmN,kBAAexM,EAExB,CAEQ,aAAAkO,CAAcD,EAA2BoB,GAC/C,GAAIhQ,KAAKoN,WAAY,CACnB,MAAMgB,EAAYpO,KAAKoN,WAClBgB,EAAUG,SACbK,EAAU3I,KAAK,KAAQmI,EAAUV,SAAS3N,QAAQiQ,KAEpD5B,EAAUG,SAAU,EACpBH,EAAUC,QAAQzJ,QAClB5E,KAAKoN,WAAa,IACpB,CACF,CAEQ,mBAAA0C,CAAoBlB,EAA2B5C,GACrD,IAAK,MAAMiE,KAAYjQ,KAAKqN,cACrB4C,EAAS1B,SACZK,EAAU3I,KAAK,KAAQgK,EAASvC,SAAS3N,QAAQ,CAAE0H,MAAOH,EAAmBhK,MAAO0O,MAEtFiE,EAAS1B,SAAU,EACnB0B,EAAS5B,QAAQzJ,QAEnB5E,KAAKqN,cAAgB,EACvB,CAEQ,cAAAG,GACFxN,KAAKkN,YACPlN,KAAKkN,UAAUtI,QACf5E,KAAKkN,UAAY,KAErB,CAEQ,cAAA6B,CAAeH,GACrB,IAAK,MAAMlC,KAAMkC,EACf,IACElC,GACF,CAAE,MAAO3N,GACP5B,QAAQG,MAAMyB,EAChB,CAEJ,CAEQ,oBAAAyP,CAAqB0B,EAAuBxR,GAOlD,GANIA,aAAekR,YACjBlT,EAAMU,KAAK,sDAAwDsB,EAAI4N,YAEvE5P,EAAMU,KAAK,0CAA4CwN,KAAKC,UAAUnM,IAGpEsB,KAAKmI,SAAWwE,EAAcW,WAI9BtN,KAAKgN,oBAILhN,KAAKmI,SAAWwE,EAAcxM,QAAlC,CAIA,GAAIH,KAAKmI,SAAWwE,EAAcxJ,KAMlC,OAAInD,KAAKmI,SAAWwE,EAAclJ,UAAYzD,KAAKmI,SAAWwE,EAAcjJ,QACtEwM,IAAalQ,KAAKoN,gBACpBpN,KAAKmQ,uBAAuBD,EAAUxR,QAIxCsB,KAAKoQ,sBAAsBF,EAAUxR,QANvC,EAJEsB,KAAKoQ,sBAAsBF,EAAUxR,EAJvC,CAiBF,CAGQ,sBAAAyR,CAAuB/B,EAAwB1P,WACjDA,aAAekR,aAKflR,EAAI+I,OAAuB,IAAd/I,EAAI+I,MAJnBzH,KAAKqQ,wBAAwB3R,QASfiC,IAAZjC,EAAIkN,KAAiC,IAAZlN,EAAIkN,IAM5BwC,EAAUG,SACqB,QAAlCxD,GAAAP,EAAA4D,EAAUV,UAAS4C,uBAAe,IAAAvF,GAAAA,EAAAsE,KAAA7E,EAAG9L,GANrCsB,KAAKqQ,wBAAwB3R,EASjC,CAGQ,uBAAA2R,CAAwB3R,GAC1BsB,KAAKmI,SAAWwE,EAAclJ,SAc9BzD,KAAKmI,SAAWwE,EAAcjJ,UAC3B1D,KAAK6M,gBAKE7M,KAAK8M,iBACV9M,KAAK+M,2BAER/M,KAAK+M,yBAA2BrO,IAPlCsB,KAAK6M,iBAAkB,EACvB7M,KAAK8M,iBAAkB,EACvB9M,KAAK+M,yBAA2BrO,EAChCsB,KAAKmP,0BAlBFnP,KAAK6M,gBAIE7M,KAAK8M,iBACV9M,KAAK+M,2BAER/M,KAAK+M,yBAA2BrO,IANlCsB,KAAK6M,iBAAkB,EACvB7M,KAAK8M,iBAAkB,EACvB9M,KAAK+M,yBAA2BrO,EAwBtC,CAEQ,qBAAA0R,CAAsBH,EAAuBvR,WACnD,OAAIA,aAAekR,aACjB5P,KAAKqN,cAAgBrN,KAAKqN,cAAckD,OAAOC,GAAQA,IAASP,QAC3DA,EAAS1B,UACZ0B,EAAS1B,SAAU,EACnB0B,EAAS5B,QAAQzJ,WAMjBlG,EAAI+I,OAAuB,IAAd/I,EAAI+I,OACnBzH,KAAKqN,cAAgBrN,KAAKqN,cAAckD,OAAOC,GAAQA,IAASP,QAC3DA,EAAS1B,UACZ0B,EAAS1B,SAAU,EACnB0B,EAAS5B,QAAQzJ,QACjBqL,EAASvC,SAAS3N,QAAQrB,WAKdiC,IAAZjC,EAAIkN,KAAiC,IAAZlN,EAAIkN,KAC/B5L,KAAKqN,cAAgBrN,KAAKqN,cAAckD,OAAOC,GAAQA,IAASP,QAC3DA,EAAS1B,UACZ0B,EAAS1B,SAAU,EACnB0B,EAAS5B,QAAQzJ,QACjBqL,EAASvC,SAASE,QAAQlP,WAMzBuR,EAAS1B,SACqB,QAAjCxD,GAAAP,EAAAyF,EAASvC,UAAS4C,uBAAe,IAAAvF,GAAAA,EAAAsE,KAAA7E,EAAG9L,GAGxC","x_google_ignoreList":[1]}