/******/ (function() { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ "./node_modules/@firebase/util/dist/index.esm.js": /*!*******************************************************!*\ !*** ./node_modules/@firebase/util/dist/index.esm.js ***! \*******************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CONSTANTS: function() { return /* binding */ CONSTANTS; }, /* harmony export */ DecodeBase64StringError: function() { return /* binding */ DecodeBase64StringError; }, /* harmony export */ Deferred: function() { return /* binding */ Deferred; }, /* harmony export */ ErrorFactory: function() { return /* binding */ ErrorFactory; }, /* harmony export */ FirebaseError: function() { return /* binding */ FirebaseError; }, /* harmony export */ MAX_VALUE_MILLIS: function() { return /* binding */ MAX_VALUE_MILLIS; }, /* harmony export */ RANDOM_FACTOR: function() { return /* binding */ RANDOM_FACTOR; }, /* harmony export */ Sha1: function() { return /* binding */ Sha1; }, /* harmony export */ areCookiesEnabled: function() { return /* binding */ areCookiesEnabled; }, /* harmony export */ assert: function() { return /* binding */ assert; }, /* harmony export */ assertionError: function() { return /* binding */ assertionError; }, /* harmony export */ async: function() { return /* binding */ async; }, /* harmony export */ base64: function() { return /* binding */ base64; }, /* harmony export */ base64Decode: function() { return /* binding */ base64Decode; }, /* harmony export */ base64Encode: function() { return /* binding */ base64Encode; }, /* harmony export */ base64urlEncodeWithoutPadding: function() { return /* binding */ base64urlEncodeWithoutPadding; }, /* harmony export */ calculateBackoffMillis: function() { return /* binding */ calculateBackoffMillis; }, /* harmony export */ contains: function() { return /* binding */ contains; }, /* harmony export */ createMockUserToken: function() { return /* binding */ createMockUserToken; }, /* harmony export */ createSubscribe: function() { return /* binding */ createSubscribe; }, /* harmony export */ decode: function() { return /* binding */ decode; }, /* harmony export */ deepCopy: function() { return /* binding */ deepCopy; }, /* harmony export */ deepEqual: function() { return /* binding */ deepEqual; }, /* harmony export */ deepExtend: function() { return /* binding */ deepExtend; }, /* harmony export */ errorPrefix: function() { return /* binding */ errorPrefix; }, /* harmony export */ extractQuerystring: function() { return /* binding */ extractQuerystring; }, /* harmony export */ generateSHA256Hash: function() { return /* binding */ generateSHA256Hash; }, /* harmony export */ getDefaultAppConfig: function() { return /* binding */ getDefaultAppConfig; }, /* harmony export */ getDefaultEmulatorHost: function() { return /* binding */ getDefaultEmulatorHost; }, /* harmony export */ getDefaultEmulatorHostnameAndPort: function() { return /* binding */ getDefaultEmulatorHostnameAndPort; }, /* harmony export */ getDefaults: function() { return /* binding */ getDefaults; }, /* harmony export */ getExperimentalSetting: function() { return /* binding */ getExperimentalSetting; }, /* harmony export */ getGlobal: function() { return /* binding */ getGlobal; }, /* harmony export */ getModularInstance: function() { return /* binding */ getModularInstance; }, /* harmony export */ getUA: function() { return /* binding */ getUA; }, /* harmony export */ isAdmin: function() { return /* binding */ isAdmin; }, /* harmony export */ isBrowser: function() { return /* binding */ isBrowser; }, /* harmony export */ isBrowserExtension: function() { return /* binding */ isBrowserExtension; }, /* harmony export */ isCloudWorkstation: function() { return /* binding */ isCloudWorkstation; }, /* harmony export */ isCloudflareWorker: function() { return /* binding */ isCloudflareWorker; }, /* harmony export */ isElectron: function() { return /* binding */ isElectron; }, /* harmony export */ isEmpty: function() { return /* binding */ isEmpty; }, /* harmony export */ isIE: function() { return /* binding */ isIE; }, /* harmony export */ isIndexedDBAvailable: function() { return /* binding */ isIndexedDBAvailable; }, /* harmony export */ isMobileCordova: function() { return /* binding */ isMobileCordova; }, /* harmony export */ isNode: function() { return /* binding */ isNode; }, /* harmony export */ isNodeSdk: function() { return /* binding */ isNodeSdk; }, /* harmony export */ isReactNative: function() { return /* binding */ isReactNative; }, /* harmony export */ isSafari: function() { return /* binding */ isSafari; }, /* harmony export */ isSafariOrWebkit: function() { return /* binding */ isSafariOrWebkit; }, /* harmony export */ isUWP: function() { return /* binding */ isUWP; }, /* harmony export */ isValidFormat: function() { return /* binding */ isValidFormat; }, /* harmony export */ isValidTimestamp: function() { return /* binding */ isValidTimestamp; }, /* harmony export */ isWebWorker: function() { return /* binding */ isWebWorker; }, /* harmony export */ issuedAtTime: function() { return /* binding */ issuedAtTime; }, /* harmony export */ jsonEval: function() { return /* binding */ jsonEval; }, /* harmony export */ map: function() { return /* binding */ map; }, /* harmony export */ ordinal: function() { return /* binding */ ordinal; }, /* harmony export */ pingServer: function() { return /* binding */ pingServer; }, /* harmony export */ promiseWithTimeout: function() { return /* binding */ promiseWithTimeout; }, /* harmony export */ querystring: function() { return /* binding */ querystring; }, /* harmony export */ querystringDecode: function() { return /* binding */ querystringDecode; }, /* harmony export */ safeGet: function() { return /* binding */ safeGet; }, /* harmony export */ stringLength: function() { return /* binding */ stringLength; }, /* harmony export */ stringToByteArray: function() { return /* binding */ stringToByteArray; }, /* harmony export */ stringify: function() { return /* binding */ stringify; }, /* harmony export */ validateArgCount: function() { return /* binding */ validateArgCount; }, /* harmony export */ validateCallback: function() { return /* binding */ validateCallback; }, /* harmony export */ validateContextObject: function() { return /* binding */ validateContextObject; }, /* harmony export */ validateIndexedDBOpenable: function() { return /* binding */ validateIndexedDBOpenable; }, /* harmony export */ validateNamespace: function() { return /* binding */ validateNamespace; } /* harmony export */ }); /* harmony import */ var _postinstall_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./postinstall.mjs */ "./node_modules/@firebase/util/dist/postinstall.mjs"); /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Firebase constants. Some of these (@defines) can be overridden at compile-time. */ const CONSTANTS = { /** * @define {boolean} Whether this is the client Node.js SDK. */ NODE_CLIENT: false, /** * @define {boolean} Whether this is the Admin Node.js SDK. */ NODE_ADMIN: false, /** * Firebase SDK Version */ SDK_VERSION: '${JSCORE_VERSION}' }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Throws an error if the provided assertion is falsy */ const assert = function (assertion, message) { if (!assertion) { throw assertionError(message); } }; /** * Returns an Error object suitable for throwing. */ const assertionError = function (message) { return new Error('Firebase Database (' + CONSTANTS.SDK_VERSION + ') INTERNAL ASSERT FAILED: ' + message); }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const stringToByteArray$1 = function (str) { // TODO(user): Use native implementations if/when available const out = []; let p = 0; for (let i = 0; i < str.length; i++) { let c = str.charCodeAt(i); if (c < 128) { out[p++] = c; } else if (c < 2048) { out[p++] = (c >> 6) | 192; out[p++] = (c & 63) | 128; } else if ((c & 0xfc00) === 0xd800 && i + 1 < str.length && (str.charCodeAt(i + 1) & 0xfc00) === 0xdc00) { // Surrogate Pair c = 0x10000 + ((c & 0x03ff) << 10) + (str.charCodeAt(++i) & 0x03ff); out[p++] = (c >> 18) | 240; out[p++] = ((c >> 12) & 63) | 128; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } else { out[p++] = (c >> 12) | 224; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } } return out; }; /** * Turns an array of numbers into the string given by the concatenation of the * characters to which the numbers correspond. * @param bytes Array of numbers representing characters. * @return Stringification of the array. */ const byteArrayToString = function (bytes) { // TODO(user): Use native implementations if/when available const out = []; let pos = 0, c = 0; while (pos < bytes.length) { const c1 = bytes[pos++]; if (c1 < 128) { out[c++] = String.fromCharCode(c1); } else if (c1 > 191 && c1 < 224) { const c2 = bytes[pos++]; out[c++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); } else if (c1 > 239 && c1 < 365) { // Surrogate Pair const c2 = bytes[pos++]; const c3 = bytes[pos++]; const c4 = bytes[pos++]; const u = (((c1 & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63)) - 0x10000; out[c++] = String.fromCharCode(0xd800 + (u >> 10)); out[c++] = String.fromCharCode(0xdc00 + (u & 1023)); } else { const c2 = bytes[pos++]; const c3 = bytes[pos++]; out[c++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); } } return out.join(''); }; // We define it as an object literal instead of a class because a class compiled down to es5 can't // be treeshaked. https://github.com/rollup/rollup/issues/1691 // Static lookup maps, lazily populated by init_() // TODO(dlarocque): Define this as a class, since we no longer target ES5. const base64 = { /** * Maps bytes to characters. */ byteToCharMap_: null, /** * Maps characters to bytes. */ charToByteMap_: null, /** * Maps bytes to websafe characters. * @private */ byteToCharMapWebSafe_: null, /** * Maps websafe characters to bytes. * @private */ charToByteMapWebSafe_: null, /** * Our default alphabet, shared between * ENCODED_VALS and ENCODED_VALS_WEBSAFE */ ENCODED_VALS_BASE: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789', /** * Our default alphabet. Value 64 (=) is special; it means "nothing." */ get ENCODED_VALS() { return this.ENCODED_VALS_BASE + '+/='; }, /** * Our websafe alphabet. */ get ENCODED_VALS_WEBSAFE() { return this.ENCODED_VALS_BASE + '-_.'; }, /** * Whether this browser supports the atob and btoa functions. This extension * started at Mozilla but is now implemented by many browsers. We use the * ASSUME_* variables to avoid pulling in the full useragent detection library * but still allowing the standard per-browser compilations. * */ HAS_NATIVE_SUPPORT: typeof atob === 'function', /** * Base64-encode an array of bytes. * * @param input An array of bytes (numbers with * value in [0, 255]) to encode. * @param webSafe Boolean indicating we should use the * alternative alphabet. * @return The base64 encoded string. */ encodeByteArray(input, webSafe) { if (!Array.isArray(input)) { throw Error('encodeByteArray takes an array as a parameter'); } this.init_(); const byteToCharMap = webSafe ? this.byteToCharMapWebSafe_ : this.byteToCharMap_; const output = []; for (let i = 0; i < input.length; i += 3) { const byte1 = input[i]; const haveByte2 = i + 1 < input.length; const byte2 = haveByte2 ? input[i + 1] : 0; const haveByte3 = i + 2 < input.length; const byte3 = haveByte3 ? input[i + 2] : 0; const outByte1 = byte1 >> 2; const outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4); let outByte3 = ((byte2 & 0x0f) << 2) | (byte3 >> 6); let outByte4 = byte3 & 0x3f; if (!haveByte3) { outByte4 = 64; if (!haveByte2) { outByte3 = 64; } } output.push(byteToCharMap[outByte1], byteToCharMap[outByte2], byteToCharMap[outByte3], byteToCharMap[outByte4]); } return output.join(''); }, /** * Base64-encode a string. * * @param input A string to encode. * @param webSafe If true, we should use the * alternative alphabet. * @return The base64 encoded string. */ encodeString(input, webSafe) { // Shortcut for Mozilla browsers that implement // a native base64 encoder in the form of "btoa/atob" if (this.HAS_NATIVE_SUPPORT && !webSafe) { return btoa(input); } return this.encodeByteArray(stringToByteArray$1(input), webSafe); }, /** * Base64-decode a string. * * @param input to decode. * @param webSafe True if we should use the * alternative alphabet. * @return string representing the decoded value. */ decodeString(input, webSafe) { // Shortcut for Mozilla browsers that implement // a native base64 encoder in the form of "btoa/atob" if (this.HAS_NATIVE_SUPPORT && !webSafe) { return atob(input); } return byteArrayToString(this.decodeStringToByteArray(input, webSafe)); }, /** * Base64-decode a string. * * In base-64 decoding, groups of four characters are converted into three * bytes. If the encoder did not apply padding, the input length may not * be a multiple of 4. * * In this case, the last group will have fewer than 4 characters, and * padding will be inferred. If the group has one or two characters, it decodes * to one byte. If the group has three characters, it decodes to two bytes. * * @param input Input to decode. * @param webSafe True if we should use the web-safe alphabet. * @return bytes representing the decoded value. */ decodeStringToByteArray(input, webSafe) { this.init_(); const charToByteMap = webSafe ? this.charToByteMapWebSafe_ : this.charToByteMap_; const output = []; for (let i = 0; i < input.length;) { const byte1 = charToByteMap[input.charAt(i++)]; const haveByte2 = i < input.length; const byte2 = haveByte2 ? charToByteMap[input.charAt(i)] : 0; ++i; const haveByte3 = i < input.length; const byte3 = haveByte3 ? charToByteMap[input.charAt(i)] : 64; ++i; const haveByte4 = i < input.length; const byte4 = haveByte4 ? charToByteMap[input.charAt(i)] : 64; ++i; if (byte1 == null || byte2 == null || byte3 == null || byte4 == null) { throw new DecodeBase64StringError(); } const outByte1 = (byte1 << 2) | (byte2 >> 4); output.push(outByte1); if (byte3 !== 64) { const outByte2 = ((byte2 << 4) & 0xf0) | (byte3 >> 2); output.push(outByte2); if (byte4 !== 64) { const outByte3 = ((byte3 << 6) & 0xc0) | byte4; output.push(outByte3); } } } return output; }, /** * Lazy static initialization function. Called before * accessing any of the static map variables. * @private */ init_() { if (!this.byteToCharMap_) { this.byteToCharMap_ = {}; this.charToByteMap_ = {}; this.byteToCharMapWebSafe_ = {}; this.charToByteMapWebSafe_ = {}; // We want quick mappings back and forth, so we precompute two maps. for (let i = 0; i < this.ENCODED_VALS.length; i++) { this.byteToCharMap_[i] = this.ENCODED_VALS.charAt(i); this.charToByteMap_[this.byteToCharMap_[i]] = i; this.byteToCharMapWebSafe_[i] = this.ENCODED_VALS_WEBSAFE.charAt(i); this.charToByteMapWebSafe_[this.byteToCharMapWebSafe_[i]] = i; // Be forgiving when decoding and correctly decode both encodings. if (i >= this.ENCODED_VALS_BASE.length) { this.charToByteMap_[this.ENCODED_VALS_WEBSAFE.charAt(i)] = i; this.charToByteMapWebSafe_[this.ENCODED_VALS.charAt(i)] = i; } } } } }; /** * An error encountered while decoding base64 string. */ class DecodeBase64StringError extends Error { constructor() { super(...arguments); this.name = 'DecodeBase64StringError'; } } /** * URL-safe base64 encoding */ const base64Encode = function (str) { const utf8Bytes = stringToByteArray$1(str); return base64.encodeByteArray(utf8Bytes, true); }; /** * URL-safe base64 encoding (without "." padding in the end). * e.g. Used in JSON Web Token (JWT) parts. */ const base64urlEncodeWithoutPadding = function (str) { // Use base64url encoding and remove padding in the end (dot characters). return base64Encode(str).replace(/\./g, ''); }; /** * URL-safe base64 decoding * * NOTE: DO NOT use the global atob() function - it does NOT support the * base64Url variant encoding. * * @param str To be decoded * @return Decoded result, if possible */ const base64Decode = function (str) { try { return base64.decodeString(str, true); } catch (e) { console.error('base64Decode failed: ', e); } return null; }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Do a deep-copy of basic JavaScript Objects or Arrays. */ function deepCopy(value) { return deepExtend(undefined, value); } /** * Copy properties from source to target (recursively allows extension * of Objects and Arrays). Scalar values in the target are over-written. * If target is undefined, an object of the appropriate type will be created * (and returned). * * We recursively copy all child properties of plain Objects in the source- so * that namespace- like dictionaries are merged. * * Note that the target can be a function, in which case the properties in * the source Object are copied onto it as static properties of the Function. * * Note: we don't merge __proto__ to prevent prototype pollution */ function deepExtend(target, source) { if (!(source instanceof Object)) { return source; } switch (source.constructor) { case Date: // Treat Dates like scalars; if the target date object had any child // properties - they will be lost! const dateValue = source; return new Date(dateValue.getTime()); case Object: if (target === undefined) { target = {}; } break; case Array: // Always copy the array source and overwrite the target. target = []; break; default: // Not a plain Object - treat it as a scalar. return source; } for (const prop in source) { // use isValidKey to guard against prototype pollution. See https://snyk.io/vuln/SNYK-JS-LODASH-450202 if (!source.hasOwnProperty(prop) || !isValidKey(prop)) { continue; } target[prop] = deepExtend(target[prop], source[prop]); } return target; } function isValidKey(key) { return key !== '__proto__'; } /** * @license * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Polyfill for `globalThis` object. * @returns the `globalThis` object for the given environment. * @public */ function getGlobal() { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof __webpack_require__.g !== 'undefined') { return __webpack_require__.g; } throw new Error('Unable to locate global object.'); } /** * @license * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const getDefaultsFromGlobal = () => getGlobal().__FIREBASE_DEFAULTS__; /** * Attempt to read defaults from a JSON string provided to * process(.)env(.)__FIREBASE_DEFAULTS__ or a JSON file whose path is in * process(.)env(.)__FIREBASE_DEFAULTS_PATH__ * The dots are in parens because certain compilers (Vite?) cannot * handle seeing that variable in comments. * See https://github.com/firebase/firebase-js-sdk/issues/6838 */ const getDefaultsFromEnvVariable = () => { if (typeof process === 'undefined' || typeof process.env === 'undefined') { return; } const defaultsJsonString = process.env.__FIREBASE_DEFAULTS__; if (defaultsJsonString) { return JSON.parse(defaultsJsonString); } }; const getDefaultsFromCookie = () => { if (typeof document === 'undefined') { return; } let match; try { match = document.cookie.match(/__FIREBASE_DEFAULTS__=([^;]+)/); } catch (e) { // Some environments such as Angular Universal SSR have a // `document` object but error on accessing `document.cookie`. return; } const decoded = match && base64Decode(match[1]); return decoded && JSON.parse(decoded); }; /** * Get the __FIREBASE_DEFAULTS__ object. It checks in order: * (1) if such an object exists as a property of `globalThis` * (2) if such an object was provided on a shell environment variable * (3) if such an object exists in a cookie * @public */ const getDefaults = () => { try { return ((0,_postinstall_mjs__WEBPACK_IMPORTED_MODULE_0__.getDefaultsFromPostinstall)() || getDefaultsFromGlobal() || getDefaultsFromEnvVariable() || getDefaultsFromCookie()); } catch (e) { /** * Catch-all for being unable to get __FIREBASE_DEFAULTS__ due * to any environment case we have not accounted for. Log to * info instead of swallowing so we can find these unknown cases * and add paths for them if needed. */ console.info(`Unable to get __FIREBASE_DEFAULTS__ due to: ${e}`); return; } }; /** * Returns emulator host stored in the __FIREBASE_DEFAULTS__ object * for the given product. * @returns a URL host formatted like `127.0.0.1:9999` or `[::1]:4000` if available * @public */ const getDefaultEmulatorHost = (productName) => getDefaults()?.emulatorHosts?.[productName]; /** * Returns emulator hostname and port stored in the __FIREBASE_DEFAULTS__ object * for the given product. * @returns a pair of hostname and port like `["::1", 4000]` if available * @public */ const getDefaultEmulatorHostnameAndPort = (productName) => { const host = getDefaultEmulatorHost(productName); if (!host) { return undefined; } const separatorIndex = host.lastIndexOf(':'); // Finding the last since IPv6 addr also has colons. if (separatorIndex <= 0 || separatorIndex + 1 === host.length) { throw new Error(`Invalid host ${host} with no separate hostname and port!`); } // eslint-disable-next-line no-restricted-globals const port = parseInt(host.substring(separatorIndex + 1), 10); if (host[0] === '[') { // Bracket-quoted `[ipv6addr]:port` => return "ipv6addr" (without brackets). return [host.substring(1, separatorIndex - 1), port]; } else { return [host.substring(0, separatorIndex), port]; } }; /** * Returns Firebase app config stored in the __FIREBASE_DEFAULTS__ object. * @public */ const getDefaultAppConfig = () => getDefaults()?.config; /** * Returns an experimental setting on the __FIREBASE_DEFAULTS__ object (properties * prefixed by "_") * @public */ const getExperimentalSetting = (name) => getDefaults()?.[`_${name}`]; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class Deferred { constructor() { this.reject = () => { }; this.resolve = () => { }; this.promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); } /** * Our API internals are not promisified and cannot because our callback APIs have subtle expectations around * invoking promises inline, which Promises are forbidden to do. This method accepts an optional node-style callback * and returns a node-style callback which will resolve or reject the Deferred's promise. */ wrapCallback(callback) { return (error, value) => { if (error) { this.reject(error); } else { this.resolve(value); } if (typeof callback === 'function') { // Attaching noop handler just in case developer wasn't expecting // promises this.promise.catch(() => { }); // Some of our callbacks don't expect a value and our own tests // assert that the parameter length is 1 if (callback.length === 1) { callback(error); } else { callback(error, value); } } }; } } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function createMockUserToken(token, projectId) { if (token.uid) { throw new Error('The "uid" field is no longer supported by mockUserToken. Please use "sub" instead for Firebase Auth User ID.'); } // Unsecured JWTs use "none" as the algorithm. const header = { alg: 'none', type: 'JWT' }; const project = projectId || 'demo-project'; const iat = token.iat || 0; const sub = token.sub || token.user_id; if (!sub) { throw new Error("mockUserToken must contain 'sub' or 'user_id' field!"); } const payload = { // Set all required fields to decent defaults iss: `https://securetoken.google.com/${project}`, aud: project, iat, exp: iat + 3600, auth_time: iat, sub, user_id: sub, firebase: { sign_in_provider: 'custom', identities: {} }, // Override with user options ...token }; // Unsecured JWTs use the empty string as a signature. const signature = ''; return [ base64urlEncodeWithoutPadding(JSON.stringify(header)), base64urlEncodeWithoutPadding(JSON.stringify(payload)), signature ].join('.'); } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns navigator.userAgent string or '' if it's not defined. * @return user agent string */ function getUA() { if (typeof navigator !== 'undefined' && typeof navigator['userAgent'] === 'string') { return navigator['userAgent']; } else { return ''; } } /** * Detect Cordova / PhoneGap / Ionic frameworks on a mobile device. * * Deliberately does not rely on checking `file://` URLs (as this fails PhoneGap * in the Ripple emulator) nor Cordova `onDeviceReady`, which would normally * wait for a callback. */ function isMobileCordova() { return (typeof window !== 'undefined' && // @ts-ignore Setting up an broadly applicable index signature for Window // just to deal with this case would probably be a bad idea. !!(window['cordova'] || window['phonegap'] || window['PhoneGap']) && /ios|iphone|ipod|ipad|android|blackberry|iemobile/i.test(getUA())); } /** * Detect Node.js. * * @return true if Node.js environment is detected or specified. */ // Node detection logic from: https://github.com/iliakan/detect-node/ function isNode() { const forceEnvironment = getDefaults()?.forceEnvironment; if (forceEnvironment === 'node') { return true; } else if (forceEnvironment === 'browser') { return false; } try { return (Object.prototype.toString.call(__webpack_require__.g.process) === '[object process]'); } catch (e) { return false; } } /** * Detect Browser Environment. * Note: This will return true for certain test frameworks that are incompletely * mimicking a browser, and should not lead to assuming all browser APIs are * available. */ function isBrowser() { return typeof window !== 'undefined' || isWebWorker(); } /** * Detect Web Worker context. */ function isWebWorker() { return (typeof WorkerGlobalScope !== 'undefined' && typeof self !== 'undefined' && self instanceof WorkerGlobalScope); } /** * Detect Cloudflare Worker context. */ function isCloudflareWorker() { return (typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers'); } function isBrowserExtension() { const runtime = typeof chrome === 'object' ? chrome.runtime : typeof browser === 'object' ? browser.runtime : undefined; return typeof runtime === 'object' && runtime.id !== undefined; } /** * Detect React Native. * * @return true if ReactNative environment is detected. */ function isReactNative() { return (typeof navigator === 'object' && navigator['product'] === 'ReactNative'); } /** Detects Electron apps. */ function isElectron() { return getUA().indexOf('Electron/') >= 0; } /** Detects Internet Explorer. */ function isIE() { const ua = getUA(); return ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0; } /** Detects Universal Windows Platform apps. */ function isUWP() { return getUA().indexOf('MSAppHost/') >= 0; } /** * Detect whether the current SDK build is the Node version. * * @return true if it's the Node SDK build. */ function isNodeSdk() { return CONSTANTS.NODE_CLIENT === true || CONSTANTS.NODE_ADMIN === true; } /** Returns true if we are running in Safari. */ function isSafari() { return (!isNode() && !!navigator.userAgent && navigator.userAgent.includes('Safari') && !navigator.userAgent.includes('Chrome')); } /** Returns true if we are running in Safari or WebKit */ function isSafariOrWebkit() { return (!isNode() && !!navigator.userAgent && (navigator.userAgent.includes('Safari') || navigator.userAgent.includes('WebKit')) && !navigator.userAgent.includes('Chrome')); } /** * This method checks if indexedDB is supported by current browser/service worker context * @return true if indexedDB is supported by current browser/service worker context */ function isIndexedDBAvailable() { try { return typeof indexedDB === 'object'; } catch (e) { return false; } } /** * This method validates browser/sw context for indexedDB by opening a dummy indexedDB database and reject * if errors occur during the database open operation. * * @throws exception if current browser/sw context can't run idb.open (ex: Safari iframe, Firefox * private browsing) */ function validateIndexedDBOpenable() { return new Promise((resolve, reject) => { try { let preExist = true; const DB_CHECK_NAME = 'validate-browser-context-for-indexeddb-analytics-module'; const request = self.indexedDB.open(DB_CHECK_NAME); request.onsuccess = () => { request.result.close(); // delete database only when it doesn't pre-exist if (!preExist) { self.indexedDB.deleteDatabase(DB_CHECK_NAME); } resolve(true); }; request.onupgradeneeded = () => { preExist = false; }; request.onerror = () => { reject(request.error?.message || ''); }; } catch (error) { reject(error); } }); } /** * * This method checks whether cookie is enabled within current browser * @return true if cookie is enabled within current browser */ function areCookiesEnabled() { if (typeof navigator === 'undefined' || !navigator.cookieEnabled) { return false; } return true; } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Standardized Firebase Error. * * Usage: * * // TypeScript string literals for type-safe codes * type Err = * 'unknown' | * 'object-not-found' * ; * * // Closure enum for type-safe error codes * // at-enum {string} * var Err = { * UNKNOWN: 'unknown', * OBJECT_NOT_FOUND: 'object-not-found', * } * * let errors: Map = { * 'generic-error': "Unknown error", * 'file-not-found': "Could not find file: {$file}", * }; * * // Type-safe function - must pass a valid error code as param. * let error = new ErrorFactory('service', 'Service', errors); * * ... * throw error.create(Err.GENERIC); * ... * throw error.create(Err.FILE_NOT_FOUND, {'file': fileName}); * ... * // Service: Could not file file: foo.txt (service/file-not-found). * * catch (e) { * assert(e.message === "Could not find file: foo.txt."); * if ((e as FirebaseError)?.code === 'service/file-not-found') { * console.log("Could not read file: " + e['file']); * } * } */ const ERROR_NAME = 'FirebaseError'; // Based on code from: // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types class FirebaseError extends Error { constructor( /** The error code for this error. */ code, message, /** Custom data for this error. */ customData) { super(message); this.code = code; this.customData = customData; /** The custom name for all FirebaseErrors. */ this.name = ERROR_NAME; // Fix For ES5 // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work // TODO(dlarocque): Replace this with `new.target`: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget // which we can now use since we no longer target ES5. Object.setPrototypeOf(this, FirebaseError.prototype); // Maintains proper stack trace for where our error was thrown. // Only available on V8. if (Error.captureStackTrace) { Error.captureStackTrace(this, ErrorFactory.prototype.create); } } } class ErrorFactory { constructor(service, serviceName, errors) { this.service = service; this.serviceName = serviceName; this.errors = errors; } create(code, ...data) { const customData = data[0] || {}; const fullCode = `${this.service}/${code}`; const template = this.errors[code]; const message = template ? replaceTemplate(template, customData) : 'Error'; // Service Name: Error message (service/code). const fullMessage = `${this.serviceName}: ${message} (${fullCode}).`; const error = new FirebaseError(fullCode, fullMessage, customData); return error; } } function replaceTemplate(template, data) { return template.replace(PATTERN, (_, key) => { const value = data[key]; return value != null ? String(value) : `<${key}?>`; }); } const PATTERN = /\{\$([^}]+)}/g; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Evaluates a JSON string into a javascript object. * * @param {string} str A string containing JSON. * @return {*} The javascript object representing the specified JSON. */ function jsonEval(str) { return JSON.parse(str); } /** * Returns JSON representing a javascript object. * @param {*} data JavaScript object to be stringified. * @return {string} The JSON contents of the object. */ function stringify(data) { return JSON.stringify(data); } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Decodes a Firebase auth. token into constituent parts. * * Notes: * - May return with invalid / incomplete claims if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const decode = function (token) { let header = {}, claims = {}, data = {}, signature = ''; try { const parts = token.split('.'); header = jsonEval(base64Decode(parts[0]) || ''); claims = jsonEval(base64Decode(parts[1]) || ''); signature = parts[2]; data = claims['d'] || {}; delete claims['d']; } catch (e) { } return { header, claims, data, signature }; }; /** * Decodes a Firebase auth. token and checks the validity of its time-based claims. Will return true if the * token is within the time window authorized by the 'nbf' (not-before) and 'iat' (issued-at) claims. * * Notes: * - May return a false negative if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const isValidTimestamp = function (token) { const claims = decode(token).claims; const now = Math.floor(new Date().getTime() / 1000); let validSince = 0, validUntil = 0; if (typeof claims === 'object') { if (claims.hasOwnProperty('nbf')) { validSince = claims['nbf']; } else if (claims.hasOwnProperty('iat')) { validSince = claims['iat']; } if (claims.hasOwnProperty('exp')) { validUntil = claims['exp']; } else { // token will expire after 24h by default validUntil = validSince + 86400; } } return (!!now && !!validSince && !!validUntil && now >= validSince && now <= validUntil); }; /** * Decodes a Firebase auth. token and returns its issued at time if valid, null otherwise. * * Notes: * - May return null if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const issuedAtTime = function (token) { const claims = decode(token).claims; if (typeof claims === 'object' && claims.hasOwnProperty('iat')) { return claims['iat']; } return null; }; /** * Decodes a Firebase auth. token and checks the validity of its format. Expects a valid issued-at time. * * Notes: * - May return a false negative if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const isValidFormat = function (token) { const decoded = decode(token), claims = decoded.claims; return !!claims && typeof claims === 'object' && claims.hasOwnProperty('iat'); }; /** * Attempts to peer into an auth token and determine if it's an admin auth token by looking at the claims portion. * * Notes: * - May return a false negative if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const isAdmin = function (token) { const claims = decode(token).claims; return typeof claims === 'object' && claims['admin'] === true; }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function contains(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } function safeGet(obj, key) { if (Object.prototype.hasOwnProperty.call(obj, key)) { return obj[key]; } else { return undefined; } } function isEmpty(obj) { for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { return false; } } return true; } function map(obj, fn, contextObj) { const res = {}; for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { res[key] = fn.call(contextObj, obj[key], key, obj); } } return res; } /** * Deep equal two objects. Support Arrays and Objects. */ function deepEqual(a, b) { if (a === b) { return true; } const aKeys = Object.keys(a); const bKeys = Object.keys(b); for (const k of aKeys) { if (!bKeys.includes(k)) { return false; } const aProp = a[k]; const bProp = b[k]; if (isObject(aProp) && isObject(bProp)) { if (!deepEqual(aProp, bProp)) { return false; } } else if (aProp !== bProp) { return false; } } for (const k of bKeys) { if (!aKeys.includes(k)) { return false; } } return true; } function isObject(thing) { return thing !== null && typeof thing === 'object'; } /** * @license * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Rejects if the given promise doesn't resolve in timeInMS milliseconds. * @internal */ function promiseWithTimeout(promise, timeInMS = 2000) { const deferredPromise = new Deferred(); setTimeout(() => deferredPromise.reject('timeout!'), timeInMS); promise.then(deferredPromise.resolve, deferredPromise.reject); return deferredPromise.promise; } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns a querystring-formatted string (e.g. &arg=val&arg2=val2) from a * params object (e.g. {arg: 'val', arg2: 'val2'}) * Note: You must prepend it with ? when adding it to a URL. */ function querystring(querystringParams) { const params = []; for (const [key, value] of Object.entries(querystringParams)) { if (Array.isArray(value)) { value.forEach(arrayVal => { params.push(encodeURIComponent(key) + '=' + encodeURIComponent(arrayVal)); }); } else { params.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); } } return params.length ? '&' + params.join('&') : ''; } /** * Decodes a querystring (e.g. ?arg=val&arg2=val2) into a params object * (e.g. {arg: 'val', arg2: 'val2'}) */ function querystringDecode(querystring) { const obj = {}; const tokens = querystring.replace(/^\?/, '').split('&'); tokens.forEach(token => { if (token) { const [key, value] = token.split('='); obj[decodeURIComponent(key)] = decodeURIComponent(value); } }); return obj; } /** * Extract the query string part of a URL, including the leading question mark (if present). */ function extractQuerystring(url) { const queryStart = url.indexOf('?'); if (!queryStart) { return ''; } const fragmentStart = url.indexOf('#', queryStart); return url.substring(queryStart, fragmentStart > 0 ? fragmentStart : undefined); } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview SHA-1 cryptographic hash. * Variable names follow the notation in FIPS PUB 180-3: * http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf. * * Usage: * var sha1 = new sha1(); * sha1.update(bytes); * var hash = sha1.digest(); * * Performance: * Chrome 23: ~400 Mbit/s * Firefox 16: ~250 Mbit/s * */ /** * SHA-1 cryptographic hash constructor. * * The properties declared here are discussed in the above algorithm document. * @constructor * @final * @struct */ class Sha1 { constructor() { /** * Holds the previous values of accumulated variables a-e in the compress_ * function. * @private */ this.chain_ = []; /** * A buffer holding the partially computed hash result. * @private */ this.buf_ = []; /** * An array of 80 bytes, each a part of the message to be hashed. Referred to * as the message schedule in the docs. * @private */ this.W_ = []; /** * Contains data needed to pad messages less than 64 bytes. * @private */ this.pad_ = []; /** * @private {number} */ this.inbuf_ = 0; /** * @private {number} */ this.total_ = 0; this.blockSize = 512 / 8; this.pad_[0] = 128; for (let i = 1; i < this.blockSize; ++i) { this.pad_[i] = 0; } this.reset(); } reset() { this.chain_[0] = 0x67452301; this.chain_[1] = 0xefcdab89; this.chain_[2] = 0x98badcfe; this.chain_[3] = 0x10325476; this.chain_[4] = 0xc3d2e1f0; this.inbuf_ = 0; this.total_ = 0; } /** * Internal compress helper function. * @param buf Block to compress. * @param offset Offset of the block in the buffer. * @private */ compress_(buf, offset) { if (!offset) { offset = 0; } const W = this.W_; // get 16 big endian words if (typeof buf === 'string') { for (let i = 0; i < 16; i++) { // TODO(user): [bug 8140122] Recent versions of Safari for Mac OS and iOS // have a bug that turns the post-increment ++ operator into pre-increment // during JIT compilation. We have code that depends heavily on SHA-1 for // correctness and which is affected by this bug, so I've removed all uses // of post-increment ++ in which the result value is used. We can revert // this change once the Safari bug // (https://bugs.webkit.org/show_bug.cgi?id=109036) has been fixed and // most clients have been updated. W[i] = (buf.charCodeAt(offset) << 24) | (buf.charCodeAt(offset + 1) << 16) | (buf.charCodeAt(offset + 2) << 8) | buf.charCodeAt(offset + 3); offset += 4; } } else { for (let i = 0; i < 16; i++) { W[i] = (buf[offset] << 24) | (buf[offset + 1] << 16) | (buf[offset + 2] << 8) | buf[offset + 3]; offset += 4; } } // expand to 80 words for (let i = 16; i < 80; i++) { const t = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; W[i] = ((t << 1) | (t >>> 31)) & 0xffffffff; } let a = this.chain_[0]; let b = this.chain_[1]; let c = this.chain_[2]; let d = this.chain_[3]; let e = this.chain_[4]; let f, k; // TODO(user): Try to unroll this loop to speed up the computation. for (let i = 0; i < 80; i++) { if (i < 40) { if (i < 20) { f = d ^ (b & (c ^ d)); k = 0x5a827999; } else { f = b ^ c ^ d; k = 0x6ed9eba1; } } else { if (i < 60) { f = (b & c) | (d & (b | c)); k = 0x8f1bbcdc; } else { f = b ^ c ^ d; k = 0xca62c1d6; } } const t = (((a << 5) | (a >>> 27)) + f + e + k + W[i]) & 0xffffffff; e = d; d = c; c = ((b << 30) | (b >>> 2)) & 0xffffffff; b = a; a = t; } this.chain_[0] = (this.chain_[0] + a) & 0xffffffff; this.chain_[1] = (this.chain_[1] + b) & 0xffffffff; this.chain_[2] = (this.chain_[2] + c) & 0xffffffff; this.chain_[3] = (this.chain_[3] + d) & 0xffffffff; this.chain_[4] = (this.chain_[4] + e) & 0xffffffff; } update(bytes, length) { // TODO(johnlenz): tighten the function signature and remove this check if (bytes == null) { return; } if (length === undefined) { length = bytes.length; } const lengthMinusBlock = length - this.blockSize; let n = 0; // Using local instead of member variables gives ~5% speedup on Firefox 16. const buf = this.buf_; let inbuf = this.inbuf_; // The outer while loop should execute at most twice. while (n < length) { // When we have no data in the block to top up, we can directly process the // input buffer (assuming it contains sufficient data). This gives ~25% // speedup on Chrome 23 and ~15% speedup on Firefox 16, but requires that // the data is provided in large chunks (or in multiples of 64 bytes). if (inbuf === 0) { while (n <= lengthMinusBlock) { this.compress_(bytes, n); n += this.blockSize; } } if (typeof bytes === 'string') { while (n < length) { buf[inbuf] = bytes.charCodeAt(n); ++inbuf; ++n; if (inbuf === this.blockSize) { this.compress_(buf); inbuf = 0; // Jump to the outer loop so we use the full-block optimization. break; } } } else { while (n < length) { buf[inbuf] = bytes[n]; ++inbuf; ++n; if (inbuf === this.blockSize) { this.compress_(buf); inbuf = 0; // Jump to the outer loop so we use the full-block optimization. break; } } } } this.inbuf_ = inbuf; this.total_ += length; } /** @override */ digest() { const digest = []; let totalBits = this.total_ * 8; // Add pad 0x80 0x00*. if (this.inbuf_ < 56) { this.update(this.pad_, 56 - this.inbuf_); } else { this.update(this.pad_, this.blockSize - (this.inbuf_ - 56)); } // Add # bits. for (let i = this.blockSize - 1; i >= 56; i--) { this.buf_[i] = totalBits & 255; totalBits /= 256; // Don't use bit-shifting here! } this.compress_(this.buf_); let n = 0; for (let i = 0; i < 5; i++) { for (let j = 24; j >= 0; j -= 8) { digest[n] = (this.chain_[i] >> j) & 255; ++n; } } return digest; } } /** * Helper to make a Subscribe function (just like Promise helps make a * Thenable). * * @param executor Function which can make calls to a single Observer * as a proxy. * @param onNoObservers Callback when count of Observers goes to zero. */ function createSubscribe(executor, onNoObservers) { const proxy = new ObserverProxy(executor, onNoObservers); return proxy.subscribe.bind(proxy); } /** * Implement fan-out for any number of Observers attached via a subscribe * function. */ class ObserverProxy { /** * @param executor Function which can make calls to a single Observer * as a proxy. * @param onNoObservers Callback when count of Observers goes to zero. */ constructor(executor, onNoObservers) { this.observers = []; this.unsubscribes = []; this.observerCount = 0; // Micro-task scheduling by calling task.then(). this.task = Promise.resolve(); this.finalized = false; this.onNoObservers = onNoObservers; // Call the executor asynchronously so subscribers that are called // synchronously after the creation of the subscribe function // can still receive the very first value generated in the executor. this.task .then(() => { executor(this); }) .catch(e => { this.error(e); }); } next(value) { this.forEachObserver((observer) => { observer.next(value); }); } error(error) { this.forEachObserver((observer) => { observer.error(error); }); this.close(error); } complete() { this.forEachObserver((observer) => { observer.complete(); }); this.close(); } /** * Subscribe function that can be used to add an Observer to the fan-out list. * * - We require that no event is sent to a subscriber synchronously to their * call to subscribe(). */ subscribe(nextOrObserver, error, complete) { let observer; if (nextOrObserver === undefined && error === undefined && complete === undefined) { throw new Error('Missing Observer.'); } // Assemble an Observer object when passed as callback functions. if (implementsAnyMethods(nextOrObserver, [ 'next', 'error', 'complete' ])) { observer = nextOrObserver; } else { observer = { next: nextOrObserver, error, complete }; } if (observer.next === undefined) { observer.next = noop; } if (observer.error === undefined) { observer.error = noop; } if (observer.complete === undefined) { observer.complete = noop; } const unsub = this.unsubscribeOne.bind(this, this.observers.length); // Attempt to subscribe to a terminated Observable - we // just respond to the Observer with the final error or complete // event. if (this.finalized) { // eslint-disable-next-line @typescript-eslint/no-floating-promises this.task.then(() => { try { if (this.finalError) { observer.error(this.finalError); } else { observer.complete(); } } catch (e) { // nothing } return; }); } this.observers.push(observer); return unsub; } // Unsubscribe is synchronous - we guarantee that no events are sent to // any unsubscribed Observer. unsubscribeOne(i) { if (this.observers === undefined || this.observers[i] === undefined) { return; } delete this.observers[i]; this.observerCount -= 1; if (this.observerCount === 0 && this.onNoObservers !== undefined) { this.onNoObservers(this); } } forEachObserver(fn) { if (this.finalized) { // Already closed by previous event....just eat the additional values. return; } // Since sendOne calls asynchronously - there is no chance that // this.observers will become undefined. for (let i = 0; i < this.observers.length; i++) { this.sendOne(i, fn); } } // Call the Observer via one of it's callback function. We are careful to // confirm that the observe has not been unsubscribed since this asynchronous // function had been queued. sendOne(i, fn) { // Execute the callback asynchronously // eslint-disable-next-line @typescript-eslint/no-floating-promises this.task.then(() => { if (this.observers !== undefined && this.observers[i] !== undefined) { try { fn(this.observers[i]); } catch (e) { // Ignore exceptions raised in Observers or missing methods of an // Observer. // Log error to console. b/31404806 if (typeof console !== 'undefined' && console.error) { console.error(e); } } } }); } close(err) { if (this.finalized) { return; } this.finalized = true; if (err !== undefined) { this.finalError = err; } // Proxy is no longer needed - garbage collect references // eslint-disable-next-line @typescript-eslint/no-floating-promises this.task.then(() => { this.observers = undefined; this.onNoObservers = undefined; }); } } /** Turn synchronous function into one called asynchronously. */ // eslint-disable-next-line @typescript-eslint/ban-types function async(fn, onError) { return (...args) => { Promise.resolve(true) .then(() => { fn(...args); }) .catch((error) => { if (onError) { onError(error); } }); }; } /** * Return true if the object passed in implements any of the named methods. */ function implementsAnyMethods(obj, methods) { if (typeof obj !== 'object' || obj === null) { return false; } for (const method of methods) { if (method in obj && typeof obj[method] === 'function') { return true; } } return false; } function noop() { // do nothing } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Check to make sure the appropriate number of arguments are provided for a public function. * Throws an error if it fails. * * @param fnName The function name * @param minCount The minimum number of arguments to allow for the function call * @param maxCount The maximum number of argument to allow for the function call * @param argCount The actual number of arguments provided. */ const validateArgCount = function (fnName, minCount, maxCount, argCount) { let argError; if (argCount < minCount) { argError = 'at least ' + minCount; } else if (argCount > maxCount) { argError = maxCount === 0 ? 'none' : 'no more than ' + maxCount; } if (argError) { const error = fnName + ' failed: Was called with ' + argCount + (argCount === 1 ? ' argument.' : ' arguments.') + ' Expects ' + argError + '.'; throw new Error(error); } }; /** * Generates a string to prefix an error message about failed argument validation * * @param fnName The function name * @param argName The name of the argument * @return The prefix to add to the error thrown for validation. */ function errorPrefix(fnName, argName) { return `${fnName} failed: ${argName} argument `; } /** * @param fnName * @param argumentNumber * @param namespace * @param optional */ function validateNamespace(fnName, namespace, optional) { if (optional && !namespace) { return; } if (typeof namespace !== 'string') { //TODO: I should do more validation here. We only allow certain chars in namespaces. throw new Error(errorPrefix(fnName, 'namespace') + 'must be a valid firebase namespace.'); } } function validateCallback(fnName, argumentName, // eslint-disable-next-line @typescript-eslint/ban-types callback, optional) { if (optional && !callback) { return; } if (typeof callback !== 'function') { throw new Error(errorPrefix(fnName, argumentName) + 'must be a valid function.'); } } function validateContextObject(fnName, argumentName, context, optional) { if (optional && !context) { return; } if (typeof context !== 'object' || context === null) { throw new Error(errorPrefix(fnName, argumentName) + 'must be a valid context object.'); } } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Code originally came from goog.crypt.stringToUtf8ByteArray, but for some reason they // automatically replaced '\r\n' with '\n', and they didn't handle surrogate pairs, // so it's been modified. // Note that not all Unicode characters appear as single characters in JavaScript strings. // fromCharCode returns the UTF-16 encoding of a character - so some Unicode characters // use 2 characters in JavaScript. All 4-byte UTF-8 characters begin with a first // character in the range 0xD800 - 0xDBFF (the first character of a so-called surrogate // pair). // See http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3 /** * @param {string} str * @return {Array} */ const stringToByteArray = function (str) { const out = []; let p = 0; for (let i = 0; i < str.length; i++) { let c = str.charCodeAt(i); // Is this the lead surrogate in a surrogate pair? if (c >= 0xd800 && c <= 0xdbff) { const high = c - 0xd800; // the high 10 bits. i++; assert(i < str.length, 'Surrogate pair missing trail surrogate.'); const low = str.charCodeAt(i) - 0xdc00; // the low 10 bits. c = 0x10000 + (high << 10) + low; } if (c < 128) { out[p++] = c; } else if (c < 2048) { out[p++] = (c >> 6) | 192; out[p++] = (c & 63) | 128; } else if (c < 65536) { out[p++] = (c >> 12) | 224; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } else { out[p++] = (c >> 18) | 240; out[p++] = ((c >> 12) & 63) | 128; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } } return out; }; /** * Calculate length without actually converting; useful for doing cheaper validation. * @param {string} str * @return {number} */ const stringLength = function (str) { let p = 0; for (let i = 0; i < str.length; i++) { const c = str.charCodeAt(i); if (c < 128) { p++; } else if (c < 2048) { p += 2; } else if (c >= 0xd800 && c <= 0xdbff) { // Lead surrogate of a surrogate pair. The pair together will take 4 bytes to represent. p += 4; i++; // skip trail surrogate. } else { p += 3; } } return p; }; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * The amount of milliseconds to exponentially increase. */ const DEFAULT_INTERVAL_MILLIS = 1000; /** * The factor to backoff by. * Should be a number greater than 1. */ const DEFAULT_BACKOFF_FACTOR = 2; /** * The maximum milliseconds to increase to. * *

Visible for testing */ const MAX_VALUE_MILLIS = 4 * 60 * 60 * 1000; // Four hours, like iOS and Android. /** * The percentage of backoff time to randomize by. * See * http://go/safe-client-behavior#step-1-determine-the-appropriate-retry-interval-to-handle-spike-traffic * for context. * *

Visible for testing */ const RANDOM_FACTOR = 0.5; /** * Based on the backoff method from * https://github.com/google/closure-library/blob/master/closure/goog/math/exponentialbackoff.js. * Extracted here so we don't need to pass metadata and a stateful ExponentialBackoff object around. */ function calculateBackoffMillis(backoffCount, intervalMillis = DEFAULT_INTERVAL_MILLIS, backoffFactor = DEFAULT_BACKOFF_FACTOR) { // Calculates an exponentially increasing value. // Deviation: calculates value from count and a constant interval, so we only need to save value // and count to restore state. const currBaseValue = intervalMillis * Math.pow(backoffFactor, backoffCount); // A random "fuzz" to avoid waves of retries. // Deviation: randomFactor is required. const randomWait = Math.round( // A fraction of the backoff value to add/subtract. // Deviation: changes multiplication order to improve readability. RANDOM_FACTOR * currBaseValue * // A random float (rounded to int by Math.round above) in the range [-1, 1]. Determines // if we add or subtract. (Math.random() - 0.5) * 2); // Limits backoff to max to avoid effectively permanent backoff. return Math.min(MAX_VALUE_MILLIS, currBaseValue + randomWait); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Provide English ordinal letters after a number */ function ordinal(i) { if (!Number.isFinite(i)) { return `${i}`; } return i + indicator(i); } function indicator(i) { i = Math.abs(i); const cent = i % 100; if (cent >= 10 && cent <= 20) { return 'th'; } const dec = i % 10; if (dec === 1) { return 'st'; } if (dec === 2) { return 'nd'; } if (dec === 3) { return 'rd'; } return 'th'; } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function getModularInstance(service) { if (service && service._delegate) { return service._delegate; } else { return service; } } /** * @license * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Checks whether host is a cloud workstation or not. * @public */ function isCloudWorkstation(url) { // `isCloudWorkstation` is called without protocol in certain connect*Emulator functions // In HTTP request builders, it's called with the protocol. // If called with protocol prefix, it's a valid URL, so we extract the hostname // If called without, we assume the string is the hostname. try { const host = url.startsWith('http://') || url.startsWith('https://') ? new URL(url).hostname : url; return host.endsWith('.cloudworkstations.dev'); } catch { return false; } } /** * Makes a fetch request to the given server. * Mostly used for forwarding cookies in Firebase Studio. * @public */ async function pingServer(endpoint) { const result = await fetch(endpoint, { credentials: 'include' }); return result.ok; } /** * @license * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @public * Generates a SHA-256 hash for the given input string. * * @param input The string to hash. * @returns A promise that resolves to the SHA-256 hash as a hex string. */ async function generateSHA256Hash(input) { const textEncoder = new TextEncoder(); const data = textEncoder.encode(input); const hashBuffer = await crypto.subtle.digest('SHA-256', data); // Convert ArrayBuffer to hex string const hashArray = Array.from(new Uint8Array(hashBuffer)); const hexHash = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); return hexHash; } //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./src/config.js": /*!***********************!*\ !*** ./src/config.js ***! \***********************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ API_KEY: function() { return /* binding */ API_KEY; }, /* harmony export */ APP_NAME: function() { return /* binding */ APP_NAME; }, /* harmony export */ AVATAR_SIZE: function() { return /* binding */ AVATAR_SIZE; }, /* harmony export */ BASE_APP_NAME: function() { return /* binding */ BASE_APP_NAME; }, /* harmony export */ BROKEN_IMAGE_SIZE: function() { return /* binding */ BROKEN_IMAGE_SIZE; }, /* harmony export */ CHANNEL_ACCESS_MODE: function() { return /* binding */ CHANNEL_ACCESS_MODE; }, /* harmony export */ CLICKABLE_URL_SCHEMES: function() { return /* binding */ CLICKABLE_URL_SCHEMES; }, /* harmony export */ DEFAULT_COLOR_SCHEME: function() { return /* binding */ DEFAULT_COLOR_SCHEME; }, /* harmony export */ DEFAULT_HOST: function() { return /* binding */ DEFAULT_HOST; }, /* harmony export */ DEFAULT_P2P_ACCESS_MODE: function() { return /* binding */ DEFAULT_P2P_ACCESS_MODE; }, /* harmony export */ DEFAULT_TEXT_SIZE: function() { return /* binding */ DEFAULT_TEXT_SIZE; }, /* harmony export */ DRAFTY_FR_MIME_TYPE_LEGACY: function() { return /* binding */ DRAFTY_FR_MIME_TYPE_LEGACY; }, /* harmony export */ EDIT_PREVIEW_LENGTH: function() { return /* binding */ EDIT_PREVIEW_LENGTH; }, /* harmony export */ FORWARDED_PREVIEW_LENGTH: function() { return /* binding */ FORWARDED_PREVIEW_LENGTH; }, /* harmony export */ IMAGE_PREVIEW_DIM: function() { return /* binding */ IMAGE_PREVIEW_DIM; }, /* harmony export */ IMAGE_THUMBNAIL_DIM: function() { return /* binding */ IMAGE_THUMBNAIL_DIM; }, /* harmony export */ IMMEDIATE_P2P_SUBSCRIPTION: function() { return /* binding */ IMMEDIATE_P2P_SUBSCRIPTION; }, /* harmony export */ KEYPRESS_DELAY: function() { return /* binding */ KEYPRESS_DELAY; }, /* harmony export */ KNOWN_HOSTS: function() { return /* binding */ KNOWN_HOSTS; }, /* harmony export */ LINK_CONTACT_US: function() { return /* binding */ LINK_CONTACT_US; }, /* harmony export */ LINK_PRIVACY_POLICY: function() { return /* binding */ LINK_PRIVACY_POLICY; }, /* harmony export */ LINK_TERMS_OF_SERVICE: function() { return /* binding */ LINK_TERMS_OF_SERVICE; }, /* harmony export */ LOGGING_ENABLED: function() { return /* binding */ LOGGING_ENABLED; }, /* harmony export */ MAX_AVATAR_BYTES: function() { return /* binding */ MAX_AVATAR_BYTES; }, /* harmony export */ MAX_DURATION: function() { return /* binding */ MAX_DURATION; }, /* harmony export */ MAX_EXTERN_ATTACHMENT_SIZE: function() { return /* binding */ MAX_EXTERN_ATTACHMENT_SIZE; }, /* harmony export */ MAX_IMAGE_DIM: function() { return /* binding */ MAX_IMAGE_DIM; }, /* harmony export */ MAX_INBAND_ATTACHMENT_SIZE: function() { return /* binding */ MAX_INBAND_ATTACHMENT_SIZE; }, /* harmony export */ MAX_ONLINE_IN_TOPIC: function() { return /* binding */ MAX_ONLINE_IN_TOPIC; }, /* harmony export */ MAX_PEER_TITLE_LENGTH: function() { return /* binding */ MAX_PEER_TITLE_LENGTH; }, /* harmony export */ MAX_TAG_COUNT: function() { return /* binding */ MAX_TAG_COUNT; }, /* harmony export */ MAX_TAG_LENGTH: function() { return /* binding */ MAX_TAG_LENGTH; }, /* harmony export */ MAX_TITLE_LENGTH: function() { return /* binding */ MAX_TITLE_LENGTH; }, /* harmony export */ MAX_TOPIC_DESCRIPTION_LENGTH: function() { return /* binding */ MAX_TOPIC_DESCRIPTION_LENGTH; }, /* harmony export */ MEDIA_BREAKPOINT: function() { return /* binding */ MEDIA_BREAKPOINT; }, /* harmony export */ MESSAGES_PAGE: function() { return /* binding */ MESSAGES_PAGE; }, /* harmony export */ MESSAGE_PREVIEW_LENGTH: function() { return /* binding */ MESSAGE_PREVIEW_LENGTH; }, /* harmony export */ MIN_DURATION: function() { return /* binding */ MIN_DURATION; }, /* harmony export */ MIN_SWIPE_DISTANCE: function() { return /* binding */ MIN_SWIPE_DISTANCE; }, /* harmony export */ MIN_TAG_LENGTH: function() { return /* binding */ MIN_TAG_LENGTH; }, /* harmony export */ NEW_GRP_ACCESS_MODE: function() { return /* binding */ NEW_GRP_ACCESS_MODE; }, /* harmony export */ NO_ACCESS_MODE: function() { return /* binding */ NO_ACCESS_MODE; }, /* harmony export */ NO_DIMENSIONS_VIDEO: function() { return /* binding */ NO_DIMENSIONS_VIDEO; }, /* harmony export */ QRCODE_SIZE: function() { return /* binding */ QRCODE_SIZE; }, /* harmony export */ QUOTED_REPLY_LENGTH: function() { return /* binding */ QUOTED_REPLY_LENGTH; }, /* harmony export */ READ_DELAY: function() { return /* binding */ READ_DELAY; }, /* harmony export */ REM_SIZE: function() { return /* binding */ REM_SIZE; }, /* harmony export */ SELF_AVATAR_URI: function() { return /* binding */ SELF_AVATAR_URI; }, /* harmony export */ TOAST_DURATION: function() { return /* binding */ TOAST_DURATION; }, /* harmony export */ VIDEO_PREVIEW_DIM: function() { return /* binding */ VIDEO_PREVIEW_DIM; }, /* harmony export */ VIDEO_THUMBNAIL_WIDTH: function() { return /* binding */ VIDEO_THUMBNAIL_WIDTH; }, /* harmony export */ WAKE_UP_TICK: function() { return /* binding */ WAKE_UP_TICK; }, /* harmony export */ WAKE_UP_TIMEOUT: function() { return /* binding */ WAKE_UP_TIMEOUT; }, /* harmony export */ WALLPAPER_DEFAULTS: function() { return /* binding */ WALLPAPER_DEFAULTS; } /* harmony export */ }); /* harmony import */ var _version_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./version.js */ "./src/version.js"); const BASE_APP_NAME = 'TinodeWeb'; const APP_NAME = BASE_APP_NAME + '/' + (_version_js__WEBPACK_IMPORTED_MODULE_0__.PACKAGE_VERSION || '0.25'); const API_KEY = "AQAAAAABAAAoeOI7tA3HsYvdzDhYhZJy" || 0; const KNOWN_HOSTS = { hosted: 'web.tinode.co', local: 'localhost:6060' }; const DEFAULT_HOST = KNOWN_HOSTS.hosted; const LOGGING_ENABLED = true; const KEYPRESS_DELAY = 3_000; const READ_DELAY = 1_500; const MIN_TAG_LENGTH = 2; const MAX_TAG_LENGTH = 96; const MAX_TAG_COUNT = 16; const DEFAULT_P2P_ACCESS_MODE = 'JRWPS'; const NEW_GRP_ACCESS_MODE = 'JRWPSAO'; const CHANNEL_ACCESS_MODE = 'JR'; const NO_ACCESS_MODE = 'N'; const MEDIA_BREAKPOINT = 640; const REM_SIZE = 13; const AVATAR_SIZE = 384; const MAX_AVATAR_BYTES = 4096; const BROKEN_IMAGE_SIZE = 32; const NO_DIMENSIONS_VIDEO = 128; const MESSAGES_PAGE = 24; const MAX_INBAND_ATTACHMENT_SIZE = 262_144; const MAX_EXTERN_ATTACHMENT_SIZE = 1 << 23; const MAX_IMAGE_DIM = 1024; const IMAGE_PREVIEW_DIM = 64; const VIDEO_PREVIEW_DIM = 96; const IMAGE_THUMBNAIL_DIM = 36; const VIDEO_THUMBNAIL_WIDTH = 48; const MAX_ONLINE_IN_TOPIC = 4; const MAX_TITLE_LENGTH = 60; const MAX_TOPIC_DESCRIPTION_LENGTH = 360; const MAX_PEER_TITLE_LENGTH = 24; const MESSAGE_PREVIEW_LENGTH = 80; const QUOTED_REPLY_LENGTH = 30; const FORWARDED_PREVIEW_LENGTH = 84; const EDIT_PREVIEW_LENGTH = 48; const MIN_DURATION = 2_000; const MAX_DURATION = 600_000; const LINK_CONTACT_US = 'mailto:support@tinode.co'; const LINK_PRIVACY_POLICY = 'https://tinode.co/privacy.html'; const LINK_TERMS_OF_SERVICE = 'https://tinode.co/terms.html'; const IMMEDIATE_P2P_SUBSCRIPTION = false; const CLICKABLE_URL_SCHEMES = ['http', 'https', 'ftp', 'ftps']; const QRCODE_SIZE = 128; const WAKE_UP_TIMEOUT = 80000; const WAKE_UP_TICK = 1000; const MIN_SWIPE_DISTANCE = REM_SIZE * 3; const SELF_AVATAR_URI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZpZXdCb3g9IjAgMCAxNyAxNyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMy41NjIgMXYxNS40NTlsNC42ODYtMy4yNyA0Ljc1MiAzLjI2di0xNS40NDloLTkuNDM4ek0xMiAxNC41NTFsLTMuNzU2LTIuNTc4LTMuNjgxIDIuNTY4di0xMi41NDFoNy40Mzd2MTIuNTUxeiIgZmlsbD0iIzU1NTU1NSIgLz48L3N2Zz4='; const TOAST_DURATION = 3_000; const DEFAULT_COLOR_SCHEME = 'auto'; const DEFAULT_TEXT_SIZE = 10; const DRAFTY_FR_MIME_TYPE_LEGACY = 'application/json'; const WALLPAPER_DEFAULTS = { type: 'patt', index: 0, path: 'img/bkg/' }; /***/ }), /***/ "./src/constants.js": /*!**************************!*\ !*** ./src/constants.js ***! \**************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CALL_HEAD_STARTED: function() { return /* binding */ CALL_HEAD_STARTED; }, /* harmony export */ CALL_STATE_INCOMING_RECEIVED: function() { return /* binding */ CALL_STATE_INCOMING_RECEIVED; }, /* harmony export */ CALL_STATE_IN_PROGRESS: function() { return /* binding */ CALL_STATE_IN_PROGRESS; }, /* harmony export */ CALL_STATE_NONE: function() { return /* binding */ CALL_STATE_NONE; }, /* harmony export */ CALL_STATE_OUTGOING_INITATED: function() { return /* binding */ CALL_STATE_OUTGOING_INITATED; } /* harmony export */ }); const CALL_STATE_NONE = 0; const CALL_STATE_OUTGOING_INITATED = 1; const CALL_STATE_INCOMING_RECEIVED = 2; const CALL_STATE_IN_PROGRESS = 3; const CALL_HEAD_STARTED = 'started'; /***/ }), /***/ "./src/lib/blob-helpers.js": /*!*********************************!*\ !*** ./src/lib/blob-helpers.js ***! \*********************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ MIME_EXTENSIONS: function() { return /* binding */ MIME_EXTENSIONS; }, /* harmony export */ SUPPORTED_IMAGE_FORMATS: function() { return /* binding */ SUPPORTED_IMAGE_FORMATS; }, /* harmony export */ base64DecodedLen: function() { return /* binding */ base64DecodedLen; }, /* harmony export */ base64EncodedLen: function() { return /* binding */ base64EncodedLen; }, /* harmony export */ base64ReEncode: function() { return /* binding */ base64ReEncode; }, /* harmony export */ base64ToBlob: function() { return /* binding */ base64ToBlob; }, /* harmony export */ base64ToIntArray: function() { return /* binding */ base64ToIntArray; }, /* harmony export */ blobToBase64: function() { return /* binding */ blobToBase64; }, /* harmony export */ fileNameForMime: function() { return /* binding */ fileNameForMime; }, /* harmony export */ filePasted: function() { return /* binding */ filePasted; }, /* harmony export */ fileToBase64: function() { return /* binding */ fileToBase64; }, /* harmony export */ fitImageSize: function() { return /* binding */ fitImageSize; }, /* harmony export */ getMimeType: function() { return /* binding */ getMimeType; }, /* harmony export */ imageCrop: function() { return /* binding */ imageCrop; }, /* harmony export */ imageScaled: function() { return /* binding */ imageScaled; }, /* harmony export */ importVCard: function() { return /* binding */ importVCard; }, /* harmony export */ intArrayToBase64: function() { return /* binding */ intArrayToBase64; }, /* harmony export */ makeImageUrl: function() { return /* binding */ makeImageUrl; } /* harmony export */ }); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_0__); const SUPPORTED_IMAGE_FORMATS = ['image/jpeg', 'image/gif', 'image/png', 'image/svg', 'image/svg+xml']; const MIME_EXTENSIONS = ['jpg', 'gif', 'png', 'svg', 'svg']; function makeImageUrl(photo) { if (photo && typeof photo == 'object') { if (photo.ref) { return photo.ref; } if (photo.data && photo.type) { const mime = photo.type.startsWith('image/') ? photo.type : 'image/' + photo.type; return 'data:' + mime + ';base64,' + photo.data; } } return null; } function fitImageSize(width, height, maxWidth, maxHeight, forceSquare) { width = width | 0; height = height | 0; maxWidth = maxWidth | 0; maxHeight = maxHeight | 0; if (width <= 0 || height <= 0 || maxWidth <= 0 || maxHeight <= 0) { return null; } if (forceSquare) { maxWidth = maxHeight = Math.min(maxWidth, maxHeight); } const scale = Math.min(Math.min(width, maxWidth) / width, Math.min(height, maxHeight) / height); const size = { dstWidth: width * scale | 0, dstHeight: height * scale | 0 }; if (forceSquare) { size.dstWidth = size.dstHeight = Math.min(size.dstWidth, size.dstHeight); size.srcWidth = size.srcHeight = Math.min(width, height); size.xoffset = (width - size.srcWidth) / 2 | 0; size.yoffset = (height - size.srcWidth) / 2 | 0; } else { size.xoffset = size.yoffset = 0; size.srcWidth = width; size.srcHeight = height; } return size; } function fileNameForMime(fname, mime) { const idx = SUPPORTED_IMAGE_FORMATS.indexOf(mime); if (idx < 0 || !fname) { return fname; } const ext = MIME_EXTENSIONS[idx]; const at = fname.lastIndexOf('.'); if (at >= 0) { fname = fname.substring(0, at); } return fname + '.' + ext; } function imageScaled(fileOrBlob, maxWidth, maxHeight, maxSize, forceSquare) { return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = 'Anonymous'; img.onerror = function (err) { reject(new Error("Image format unrecognized")); }; img.onload = async function () { URL.revokeObjectURL(img.src); const dim = fitImageSize(img.width, img.height, maxWidth, maxHeight, forceSquare); if (!dim) { reject(new Error("Invalid image")); return; } let canvas = document.createElement('canvas'); canvas.width = dim.dstWidth; canvas.height = dim.dstHeight; let ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; ctx.drawImage(img, dim.xoffset, dim.yoffset, dim.srcWidth, dim.srcHeight, 0, 0, dim.dstWidth, dim.dstHeight); const mime = SUPPORTED_IMAGE_FORMATS.includes(fileOrBlob.type) ? fileOrBlob.type : 'image/jpeg'; let blob = await new Promise(resolve => canvas.toBlob(resolve, mime)); if (!blob) { reject(new Error("Unsupported image format")); return; } while (maxSize > 0 && blob.length > maxSize) { dim.dstWidth = dim.dstWidth * 0.70710678118 | 0; dim.dstHeight = dim.dstHeight * 0.70710678118 | 0; canvas.width = dim.dstWidth; canvas.height = dim.dstHeight; ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, dim.xoffset, dim.yoffset, dim.srcWidth, dim.srcHeight, 0, 0, dim.dstWidth, dim.dstHeight); blob = await new Promise(resolve => canvas.toBlob(resolve, mime)); } canvas = null; resolve({ mime: mime, blob: blob, width: dim.dstWidth, height: dim.dstHeight, name: fileNameForMime(fileOrBlob.name, mime) }); }; img.src = URL.createObjectURL(fileOrBlob); }); } function imageCrop(mime, objURL, left, top, width, height, scale) { return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = 'Anonymous'; img.onerror = _ => { reject(new Error("Image format unrecognized")); }; img.onload = _ => { URL.revokeObjectURL(img.src); let canvas = document.createElement('canvas'); canvas.width = width * scale; canvas.height = height * scale; let ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; ctx.drawImage(img, left, top, width, height, 0, 0, canvas.width, canvas.height); mime = SUPPORTED_IMAGE_FORMATS.includes(mime) ? mime : 'image/jpeg'; canvas.toBlob(blob => { canvas = null; if (blob) { resolve({ mime: mime, blob: blob, width: width, height: height }); } else { reject(new Error("Unsupported image format")); } }, mime); }; img.src = objURL; }); } function fileToBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = _ => { reject(reader.error); }; reader.onload = _ => { resolve({ mime: file.type, bits: reader.result.split(',')[1], name: file.name }); }; reader.readAsDataURL(file); }); } function blobToBase64(blob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = _ => { reject(reader.error); }; reader.onload = _ => { resolve({ mime: blob.type, bits: reader.result.split(',')[1] }); }; reader.readAsDataURL(blob); }); } function filePasted(event, onImageSuccess, onAttachmentSuccess, onError) { const items = (event.clipboardData || event.originalEvent.clipboardData || {}).items; if (!items || !items.length) { return false; } for (let i in items) { const item = items[i]; if (item.kind === 'file') { const file = item.getAsFile(); if (!file) { console.error("Failed to get file object from pasted file item", item.kind, item.type); onError("Failed to get file object from pasted file item"); continue; } if (file.type && file.type.split('/')[0] == 'image') { onImageSuccess(file); } else { onAttachmentSuccess(file); } return true; } } return false; } function getMimeType(header) { const mime = /^data:(image\/[-+a-z0-9.]+);base64/.exec(header); return mime && mime.length > 1 ? mime[1] : null; } function base64EncodedLen(n) { return Math.floor((n + 2) / 3) * 4; } function base64DecodedLen(n) { return Math.floor(n / 4) * 3; } function base64ReEncode(str) { if (str) { str = str.replace(/-/g, '+').replace(/_/g, '/'); try { str = btoa(atob(str)); } catch (err) { console.error("Failed to base64 re-encode string.", err); str = null; } } return str; } function base64ToBlob(str, mime) { if (!str) { return null; } try { const bin = atob(str); const length = bin.length; const buf = new ArrayBuffer(length); const arr = new Uint8Array(buf); for (let i = 0; i < length; i++) { arr[i] = bin.charCodeAt(i); } return new Blob([buf], { type: mime }); } catch (err) { console.error("Failed to convert base64 to blob: ", err); } return null; } function intArrayToBase64(arr) { if (!Array.isArray(arr)) { return null; } try { let bin = ''; new Uint8Array(arr).forEach(b => bin += String.fromCharCode(b)); return window.btoa(bin); } catch (err) {} return null; } function base64ToIntArray(b64) { const arr = []; try { const bin = window.atob(b64); [...bin].forEach(c => { arr.push(c.charCodeAt(0)); }); return arr; } catch (err) {} return null; } function importVCard(fileOrBlob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = _ => { reject(reader.error); }; reader.onload = _ => { const card = tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.TheCard.importVCard(reader.result); if (!card) { reject(new Error("Failed to parse vCard")); return; } resolve(card); }; reader.readAsText(fileOrBlob); }); } /***/ }), /***/ "./src/lib/formatters.js": /*!*******************************!*\ !*** ./src/lib/formatters.js ***! \*******************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ fullFormatter: function() { return /* binding */ fullFormatter; }, /* harmony export */ previewFormatter: function() { return /* binding */ previewFormatter; }, /* harmony export */ replyFormatter: function() { return /* binding */ replyFormatter; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _widgets_audio_player_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/audio-player.jsx */ "./src/widgets/audio-player.jsx"); /* harmony import */ var _widgets_call_message_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/call-message.jsx */ "./src/widgets/call-message.jsx"); /* harmony import */ var _widgets_call_status_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/call-status.jsx */ "./src/widgets/call-status.jsx"); /* harmony import */ var _widgets_inline_video_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/inline-video.jsx */ "./src/widgets/inline-video.jsx"); /* harmony import */ var _widgets_lazy_image_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../widgets/lazy-image.jsx */ "./src/widgets/lazy-image.jsx"); /* harmony import */ var _widgets_the_card_mini_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../widgets/the-card-mini.jsx */ "./src/widgets/the-card-mini.jsx"); /* harmony import */ var _widgets_uploading_image_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../widgets/uploading-image.jsx */ "./src/widgets/uploading-image.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _blob_helpers_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _strformat_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ drafty_form: { id: 'drafty_form', defaultMessage: 'Form: ', description: 'Comment for form in Drafty' }, drafty_attachment: { id: 'drafty_attachment', defaultMessage: 'Attachment', description: 'Comment for attachment in Drafty' }, drafty_image: { id: 'drafty_image', defaultMessage: 'Picture', description: 'Comment for embedded images in Drafty' }, drafty_video: { id: 'drafty_video', defaultMessage: 'Video recording', description: 'Comment for videos embedded in Drafty' }, drafty_unknown: { id: 'drafty_unknown', defaultMessage: 'Unsupported', description: 'Unsupported entity in drafty' } }); function fullFormatter(style, data, values, key, stack) { if (stack.includes('QQ')) { return quoteFormatter.call(this, style, data, values, key); } if (!style) { return values; } let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName(style); let attr = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attrValue(style, data) || {}; attr.key = key; switch (style) { case 'AU': if (attr.src) { attr.src = this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_13__.sanitizeUrlForMime)(attr.src, 'audio')); attr.duration = data.duration > 0 ? data.duration | 0 : undefined; attr.preview = data.preview; attr.loading = 'lazy'; } el = _widgets_audio_player_jsx__WEBPACK_IMPORTED_MODULE_3__["default"]; values = null; break; case 'BR': values = null; break; case 'EX': break; case 'HL': attr.className = 'highlight'; break; case 'HD': el = null; values = null; break; case 'IM': el = handleImageData.call(this, el, data, attr); values = null; break; case 'BN': attr.onClick = e => this.onHandleClick(e, 'form_button'); let inner = react__WEBPACK_IMPORTED_MODULE_0___default().Children.map(values, child => { return typeof child == 'string' ? child : undefined; }); if (!inner || inner.length == 0) { inner = [attr.name]; } attr['data-title'] = inner.join(''); break; case 'LN': if (attr) { attr.href = typeof attr.href == 'string' ? (0,_utils_js__WEBPACK_IMPORTED_MODULE_13__.sanitizeUrl)(attr.href, _config_js__WEBPACK_IMPORTED_MODULE_10__.CLICKABLE_URL_SCHEMES) : ''; } break; case 'MN': attr.className = 'mention'; if (data) { attr.className += ' ' + (0,_strformat_js__WEBPACK_IMPORTED_MODULE_12__.idToColorClass)(data.val, false, true); } break; case 'FM': attr.className = 'bot-form'; break; case 'RW': break; case 'QQ': attr.className = 'reply-quote'; attr.onClick = e => this.onHandleClick(e, 'quote'); break; case 'TC': el = _widgets_the_card_mini_jsx__WEBPACK_IMPORTED_MODULE_8__["default"]; attr.content = data; attr.authorizeURL = this.authorizeURL; attr.onChatClick = e => this.onHandleClick(e, 'contact_chat'); attr.onFindClick = e => this.onHandleClick(e, 'contact_find'); values = null; break; case 'VC': el = _widgets_call_message_jsx__WEBPACK_IMPORTED_MODULE_4__["default"]; values = null; if (data) { attr.callState = data.state; attr.incoming = data.incoming; attr.duration = data.duration; } break; case 'VD': el = handleVideoData.call(this, el, data, attr); values = null; break; default: if (!el) { el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); attr = { key: key }; let body = values; if (!Array.isArray(values) || !values.join('').trim()) { body = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('span', { key: 'x1', className: 'gray' }, this.formatMessage(messages.drafty_unknown))]; } values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', { key: 'x0', className: 'material-icons gray' }, 'extension'), ' '].concat(body); } break; } if (!el) { return values; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values); } function handleImageData(el, data, attr) { if (!data) { attr.src = 'img/broken_image.png'; attr.style = { width: _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM + 'px', height: _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM + 'px' }; return el; } attr.className = 'inline-image'; const dim = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_11__.fitImageSize)(data.width, data.height, this.viewportWidth > 0 ? Math.min(this.viewportWidth - _config_js__WEBPACK_IMPORTED_MODULE_10__.REM_SIZE * 6.5, _config_js__WEBPACK_IMPORTED_MODULE_10__.REM_SIZE * 34.5) : _config_js__WEBPACK_IMPORTED_MODULE_10__.REM_SIZE * 34.5, _config_js__WEBPACK_IMPORTED_MODULE_10__.REM_SIZE * 24, false) || { dstWidth: _config_js__WEBPACK_IMPORTED_MODULE_10__.BROKEN_IMAGE_SIZE, dstHeight: _config_js__WEBPACK_IMPORTED_MODULE_10__.BROKEN_IMAGE_SIZE }; attr.style = { width: dim.dstWidth + 'px', height: dim.dstHeight + 'px', minWidth: dim.dstWidth + 'px', minHeight: dim.dstHeight + 'px' }; if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isProcessing(data)) { attr.src = this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_13__.sanitizeUrlForMime)(attr.src, 'image')); attr.alt = data.name; if (attr.src) { if (Math.max(data.width || 0, data.height || 0) > _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM) { attr.onClick = e => this.onHandleClick(e, 'image'); attr.className += ' image-clickable'; } attr.loading = 'lazy'; } else { attr.src = null; } } else { el = _widgets_uploading_image_jsx__WEBPACK_IMPORTED_MODULE_9__["default"]; } return el; } function handleVideoData(el, data, attr) { if (!data) { attr.src = 'img/broken_video.png'; attr.style = { width: _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM + 'px', height: _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM + 'px' }; return el; } attr.className = 'inline-image'; const dim = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_11__.fitImageSize)(data.width, data.height, this.viewportWidth > 0 ? Math.min(this.viewportWidth - _config_js__WEBPACK_IMPORTED_MODULE_10__.REM_SIZE * 6.5, _config_js__WEBPACK_IMPORTED_MODULE_10__.REM_SIZE * 34.5) : _config_js__WEBPACK_IMPORTED_MODULE_10__.REM_SIZE * 34.5, _config_js__WEBPACK_IMPORTED_MODULE_10__.REM_SIZE * 24, false) || { dstWidth: _config_js__WEBPACK_IMPORTED_MODULE_10__.NO_DIMENSIONS_VIDEO, dstHeight: _config_js__WEBPACK_IMPORTED_MODULE_10__.NO_DIMENSIONS_VIDEO }; attr.style = { width: dim.dstWidth + 'px', height: dim.dstHeight + 'px', minWidth: dim.dstWidth + 'px', minHeight: dim.dstHeight + 'px' }; if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isProcessing(data)) { attr.src = this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_13__.sanitizeUrlForMime)(attr.src, 'image')); attr.alt = data.name; if (data.ref || data.val) { attr.onClick = e => this.onHandleClick(e, 'video'); attr.loading = 'lazy'; } el = _widgets_inline_video_jsx__WEBPACK_IMPORTED_MODULE_6__["default"]; } else { el = _widgets_uploading_image_jsx__WEBPACK_IMPORTED_MODULE_9__["default"]; } return el; } function previewFormatter(style, data, values, key) { if (!style) { return values; } let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName(style); const attr = { key: key }; switch (style) { case 'AU': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', { key: 'au', className: 'material-icons' }, 'mic'), ' ', (0,_strformat_js__WEBPACK_IMPORTED_MODULE_12__.secondsToTime)(data.duration / 1000)]; break; case 'BR': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [' ']; break; case 'HL': attr.className = 'highlight preview'; break; case 'LN': case 'MN': el = 'span'; break; case 'IM': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', { key: 'im', className: 'material-icons' }, 'photo'), ' ', this.formatMessage(messages.drafty_image)]; break; case 'BN': el = 'span'; attr.className = 'flat-button faux'; break; case 'FM': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', { key: 'fm', className: 'material-icons' }, 'dashboard'), this.formatMessage(messages.drafty_form)].concat(' ', values || []); break; case 'RW': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); break; case 'EX': if (data) { if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isFormResponseType(data.mime)) { return null; } delete data.val; delete data.ref; } el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', { key: 'ex', className: 'material-icons' }, 'attachment'), ' ', this.formatMessage(messages.drafty_attachment)]; break; case 'VC': el = _widgets_call_status_jsx__WEBPACK_IMPORTED_MODULE_5__["default"]; if (data) { attr.callState = data.state; attr.incoming = data.incoming; attr.duration = data.duration; } values = null; break; case 'QQ': case 'HD': el = null; values = null; break; case 'TC': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', { key: 'tc', className: 'material-icons' }, 'contact_mail'), ' ', tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.getFn(data) || this.formatMessage(messages.drafty_unknown)]; break; case 'VD': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', { key: 'im', className: 'material-icons' }, 'play_circle_outline'), ' ', this.formatMessage(messages.drafty_video)]; break; default: if (!el) { el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', { key: 'x0', className: 'material-icons gray' }, 'extension'), ' ', this.formatMessage(messages.drafty_unknown)]; } break; } if (!el) { return values; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values); } ; function inlineImageAttr(attr, data) { attr.style = { width: _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM + 'px', height: _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM + 'px', maxWidth: _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM + 'px', maxHeight: _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM + 'px' }; attr.className = 'inline-image'; attr.alt = this.formatMessage(messages.drafty_image); if (!data) { attr.src = 'img/broken_image.png'; } else { attr.src = attr.src || 'img/broken_image.png'; } attr.title = attr.alt; return attr; } function inlineVideoAttr(attr, data) { const dim = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_11__.fitImageSize)(data.width, data.height, _config_js__WEBPACK_IMPORTED_MODULE_10__.VIDEO_THUMBNAIL_WIDTH, _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM); attr.style = { width: dim.width + 'px', height: dim.height + 'px', maxWidth: _config_js__WEBPACK_IMPORTED_MODULE_10__.VIDEO_THUMBNAIL_WIDTH + 'px', maxHeight: _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM + 'px' }; attr.className = 'inline-image'; attr.alt = this.formatMessage(messages.drafty_video); attr.title = attr.alt; if (!data) { attr.src = 'img/broken_video.png'; } else { attr.src = attr.src || 'img/broken_video.png'; } return attr; } function quoteFormatter(style, data, values, key) { if (['BR', 'EX', 'IM', 'MN', 'VD'].includes(style)) { let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName(style); let attr = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attrValue(style, data) || {}; attr.key = key; switch (style) { case 'BR': values = null; break; case 'IM': attr = inlineImageAttr.call(this, attr, data); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', attr, null), ' ', attr.alt]; el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); attr = { key: key }; break; case 'VD': attr = inlineVideoAttr.call(this, attr, data); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', attr, null), ' ', attr.alt]; el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); attr = { key: key }; break; case 'MN': el = 'span'; attr.className = 'mention'; if (data) { attr.className += ' ' + (0,_strformat_js__WEBPACK_IMPORTED_MODULE_12__.idToColorClass)(data.val, false, true); } break; case 'EX': let fname; if (data) { if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isFormResponseType(data.mime)) { return null; } fname = data.name; delete data.val; delete data.ref; } el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', { key: 'ex', className: 'material-icons' }, 'attachment'), (0,_strformat_js__WEBPACK_IMPORTED_MODULE_12__.shortenFileName)(fname, 16) || this.formatMessage(messages.drafty_attachment)]; break; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values); } return previewFormatter.call(this, style, data, values, key); } function quoteImageOrVideo(data, isVideo) { let promise; let bits, ref, mime; if (isVideo) { bits = data.preview; mime = data.premime || 'image/jpeg'; ref = data.preref; } else { bits = data.val; mime = data.mime; ref = data.ref; } if (bits) { const blob = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_11__.base64ToBlob)(bits, mime); if (!blob) { throw new Error("Invalid image"); } promise = Promise.resolve(blob); } else if (ref) { promise = fetch(this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_13__.sanitizeUrlForMime)(ref, 'image'))).then(evt => { if (evt.ok) { return evt.blob(); } else { throw new Error(`Image fetch unsuccessful: ${evt.status} ${evt.statusText}`); } }); } else { throw new Error("Missing image data"); } return promise.then(blob => { return (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_11__.imageScaled)(blob, isVideo ? _config_js__WEBPACK_IMPORTED_MODULE_10__.VIDEO_THUMBNAIL_WIDTH : _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM, _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM, -1, !isVideo); }).then(scaled => { if (isVideo) { data.premime = scaled.mime; } else { data.mime = scaled.mime; } data.size = scaled.blob.size; data.width = scaled.width; data.height = scaled.height; delete data.ref; delete data.preref; data.src = URL.createObjectURL(scaled.blob); return (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_11__.blobToBase64)(scaled.blob); }).then(b64 => { if (isVideo) { data.preview = b64.bits; } else { data.val = b64.bits; } return data; }).catch(err => { delete data.val; delete data.preview; delete data.src; data.width = _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM; data.height = _config_js__WEBPACK_IMPORTED_MODULE_10__.IMAGE_THUMBNAIL_DIM; throw err; }); } function replyFormatter(style, data, values, key, stack) { if (style == 'IM' || style == 'VD') { const isImage = style == 'IM'; const attr = isImage ? inlineImageAttr.call(this, { key: key }, data) : inlineVideoAttr.call(this, { key: key }, data); let loadedPromise; try { loadedPromise = (0,_utils_js__WEBPACK_IMPORTED_MODULE_13__.cancelablePromise)(quoteImageOrVideo.call(this, data, style == 'VD')); } catch (error) { console.warn("Failed to quote image:", error.message); loadedPromise = (0,_utils_js__WEBPACK_IMPORTED_MODULE_13__.cancelablePromise)(error); } attr.whenDone = loadedPromise; values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_lazy_image_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], attr, null), ' ', attr.alt]; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), { key: key }, values); } else if (style == 'QQ') { if (stack.includes('QQ')) { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement('span', { key: key }, [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', { key: 'qq', className: 'material-icons' }, 'format_quote'), ' ']); } const attr = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attrValue('QQ', data) || {}; attr.key = key; attr.className = 'reply-quote'; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName('QQ'), attr, values); } return quoteFormatter.call(this, style, data, values, key); } /***/ }), /***/ "./src/lib/host-name.js": /*!******************************!*\ !*** ./src/lib/host-name.js ***! \******************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ detectServerAddress: function() { return /* binding */ detectServerAddress; }, /* harmony export */ isLocalHost: function() { return /* binding */ isLocalHost; }, /* harmony export */ isSecureConnection: function() { return /* binding */ isSecureConnection; } /* harmony export */ }); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); function detectServerAddress() { let host = _config_js__WEBPACK_IMPORTED_MODULE_0__.DEFAULT_HOST; if (typeof window.location == 'object') { if (window.location.protocol == 'file:' || window.location.hostname == 'localhost') { host = _config_js__WEBPACK_IMPORTED_MODULE_0__.KNOWN_HOSTS.local; } else if (window.location.hostname) { host = window.location.hostname + (window.location.port ? ':' + window.location.port : ''); } } return host; } function isSecureConnection() { if (typeof window.location == 'object') { return window.location.protocol == 'https:'; } return false; } function isLocalHost() { if (typeof window.location == 'object') { return window.location.hostname == 'localhost'; } return false; } /***/ }), /***/ "./src/lib/im-api.js": /*!***************************!*\ !*** ./src/lib/im-api.js ***! \***************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ImApiError: function() { return /* binding */ ImApiError; }, /* harmony export */ acceptFriendRequest: function() { return /* binding */ acceptFriendRequest; }, /* harmony export */ acceptGroupInvitation: function() { return /* binding */ acceptGroupInvitation; }, /* harmony export */ acceptGroupJoinRequest: function() { return /* binding */ acceptGroupJoinRequest; }, /* harmony export */ addGroupAdmins: function() { return /* binding */ addGroupAdmins; }, /* harmony export */ addGroupFile: function() { return /* binding */ addGroupFile; }, /* harmony export */ batchDeleteFavorites: function() { return /* binding */ batchDeleteFavorites; }, /* harmony export */ batchUnblockUsers: function() { return /* binding */ batchUnblockUsers; }, /* harmony export */ blockUser: function() { return /* binding */ blockUser; }, /* harmony export */ cancelMeeting: function() { return /* binding */ cancelMeeting; }, /* harmony export */ checkURL: function() { return /* binding */ checkURL; }, /* harmony export */ confirmPasswordReset: function() { return /* binding */ confirmPasswordReset; }, /* harmony export */ confirmRiskChallenge: function() { return /* binding */ confirmRiskChallenge; }, /* harmony export */ createChatUploader: function() { return /* binding */ createChatUploader; }, /* harmony export */ createDailyReport: function() { return /* binding */ createDailyReport; }, /* harmony export */ createFileDownloader: function() { return /* binding */ createFileDownloader; }, /* harmony export */ createFriendRequest: function() { return /* binding */ createFriendRequest; }, /* harmony export */ createGroup: function() { return /* binding */ createGroup; }, /* harmony export */ createGroupJoinRequest: function() { return /* binding */ createGroupJoinRequest; }, /* harmony export */ createGroupQRCode: function() { return /* binding */ createGroupQRCode; }, /* harmony export */ createMeeting: function() { return /* binding */ createMeeting; }, /* harmony export */ createMonthlyReport: function() { return /* binding */ createMonthlyReport; }, /* harmony export */ createMyQRCode: function() { return /* binding */ createMyQRCode; }, /* harmony export */ createP2PConversation: function() { return /* binding */ createP2PConversation; }, /* harmony export */ createSecurityChallenge: function() { return /* binding */ createSecurityChallenge; }, /* harmony export */ createUserQRCode: function() { return /* binding */ createUserQRCode; }, /* harmony export */ currentTenantCode: function() { return /* binding */ currentTenantCode; }, /* harmony export */ deleteFavorite: function() { return /* binding */ deleteFavorite; }, /* harmony export */ deleteFriend: function() { return /* binding */ deleteFriend; }, /* harmony export */ deleteGroupAdmin: function() { return /* binding */ deleteGroupAdmin; }, /* harmony export */ deleteGroupFile: function() { return /* binding */ deleteGroupFile; }, /* harmony export */ disableYouthMode: function() { return /* binding */ disableYouthMode; }, /* harmony export */ enableYouthMode: function() { return /* binding */ enableYouthMode; }, /* harmony export */ favoriteMessages: function() { return /* binding */ favoriteMessages; }, /* harmony export */ fetchFileState: function() { return /* binding */ fetchFileState; }, /* harmony export */ forwardFavorites: function() { return /* binding */ forwardFavorites; }, /* harmony export */ forwardMessages: function() { return /* binding */ forwardMessages; }, /* harmony export */ getAbuseReasons: function() { return /* binding */ getAbuseReasons; }, /* harmony export */ getBlocks: function() { return /* binding */ getBlocks; }, /* harmony export */ getBootstrap: function() { return /* binding */ getBootstrap; }, /* harmony export */ getConversationContext: function() { return /* binding */ getConversationContext; }, /* harmony export */ getConversationSettings: function() { return /* binding */ getConversationSettings; }, /* harmony export */ getDailyReport: function() { return /* binding */ getDailyReport; }, /* harmony export */ getDailyReports: function() { return /* binding */ getDailyReports; }, /* harmony export */ getDailyStatistics: function() { return /* binding */ getDailyStatistics; }, /* harmony export */ getExecutiveMailboxConfig: function() { return /* binding */ getExecutiveMailboxConfig; }, /* harmony export */ getFavorite: function() { return /* binding */ getFavorite; }, /* harmony export */ getFavorites: function() { return /* binding */ getFavorites; }, /* harmony export */ getFeedbackConfig: function() { return /* binding */ getFeedbackConfig; }, /* harmony export */ getFileUrl: function() { return /* binding */ getFileUrl; }, /* harmony export */ getForwardBundle: function() { return /* binding */ getForwardBundle; }, /* harmony export */ getForwardTargets: function() { return /* binding */ getForwardTargets; }, /* harmony export */ getFriendRequests: function() { return /* binding */ getFriendRequests; }, /* harmony export */ getFriends: function() { return /* binding */ getFriends; }, /* harmony export */ getGroup: function() { return /* binding */ getGroup; }, /* harmony export */ getGroupAnnouncement: function() { return /* binding */ getGroupAnnouncement; }, /* harmony export */ getGroupFiles: function() { return /* binding */ getGroupFiles; }, /* harmony export */ getGroupGovernance: function() { return /* binding */ getGroupGovernance; }, /* harmony export */ getGroupJoinRequests: function() { return /* binding */ getGroupJoinRequests; }, /* harmony export */ getGroupMemberProfile: function() { return /* binding */ getGroupMemberProfile; }, /* harmony export */ getGroupMembers: function() { return /* binding */ getGroupMembers; }, /* harmony export */ getGroupMutes: function() { return /* binding */ getGroupMutes; }, /* harmony export */ getGroupRoleLimits: function() { return /* binding */ getGroupRoleLimits; }, /* harmony export */ getGroupSettings: function() { return /* binding */ getGroupSettings; }, /* harmony export */ getGroupSummary: function() { return /* binding */ getGroupSummary; }, /* harmony export */ getGroups: function() { return /* binding */ getGroups; }, /* harmony export */ getLatestAppRelease: function() { return /* binding */ getLatestAppRelease; }, /* harmony export */ getLatestGroupAnnouncement: function() { return /* binding */ getLatestGroupAnnouncement; }, /* harmony export */ getMe: function() { return /* binding */ getMe; }, /* harmony export */ getMePrivacy: function() { return /* binding */ getMePrivacy; }, /* harmony export */ getMeProfile: function() { return /* binding */ getMeProfile; }, /* harmony export */ getMeeting: function() { return /* binding */ getMeeting; }, /* harmony export */ getMeetings: function() { return /* binding */ getMeetings; }, /* harmony export */ getMentionableGroupMembers: function() { return /* binding */ getMentionableGroupMembers; }, /* harmony export */ getMessageContext: function() { return /* binding */ getMessageContext; }, /* harmony export */ getMessageReceipts: function() { return /* binding */ getMessageReceipts; }, /* harmony export */ getMonthlyReport: function() { return /* binding */ getMonthlyReport; }, /* harmony export */ getMonthlyReports: function() { return /* binding */ getMonthlyReports; }, /* harmony export */ getMonthlyStatistics: function() { return /* binding */ getMonthlyStatistics; }, /* harmony export */ getMyGroupProfile: function() { return /* binding */ getMyGroupProfile; }, /* harmony export */ getOrganizationDepartmentMembers: function() { return /* binding */ getOrganizationDepartmentMembers; }, /* harmony export */ getOrganizationDepartments: function() { return /* binding */ getOrganizationDepartments; }, /* harmony export */ getOrganizationMembers: function() { return /* binding */ getOrganizationMembers; }, /* harmony export */ getRealnameStatus: function() { return /* binding */ getRealnameStatus; }, /* harmony export */ getSystemNotifications: function() { return /* binding */ getSystemNotifications; }, /* harmony export */ getTenantContext: function() { return /* binding */ getTenantContext; }, /* harmony export */ getTopicMedia: function() { return /* binding */ getTopicMedia; }, /* harmony export */ getUserProfile: function() { return /* binding */ getUserProfile; }, /* harmony export */ getWorkbench: function() { return /* binding */ getWorkbench; }, /* harmony export */ getYouthMode: function() { return /* binding */ getYouthMode; }, /* harmony export */ imDelete: function() { return /* binding */ imDelete; }, /* harmony export */ imGet: function() { return /* binding */ imGet; }, /* harmony export */ imPatch: function() { return /* binding */ imPatch; }, /* harmony export */ imPost: function() { return /* binding */ imPost; }, /* harmony export */ imPut: function() { return /* binding */ imPut; }, /* harmony export */ imRequest: function() { return /* binding */ imRequest; }, /* harmony export */ inviteGroupMembers: function() { return /* binding */ inviteGroupMembers; }, /* harmony export */ leaveGroup: function() { return /* binding */ leaveGroup; }, /* harmony export */ markSystemNotificationRead: function() { return /* binding */ markSystemNotificationRead; }, /* harmony export */ muteGroupMembers: function() { return /* binding */ muteGroupMembers; }, /* harmony export */ publicFileBase: function() { return /* binding */ publicFileBase; }, /* harmony export */ readGroupAnnouncement: function() { return /* binding */ readGroupAnnouncement; }, /* harmony export */ recallMessage: function() { return /* binding */ recallMessage; }, /* harmony export */ rejectFriendRequest: function() { return /* binding */ rejectFriendRequest; }, /* harmony export */ rejectGroupJoinRequest: function() { return /* binding */ rejectGroupJoinRequest; }, /* harmony export */ reopenMonthlyReport: function() { return /* binding */ reopenMonthlyReport; }, /* harmony export */ requestVerificationCode: function() { return /* binding */ requestVerificationCode; }, /* harmony export */ resolveQRCode: function() { return /* binding */ resolveQRCode; }, /* harmony export */ resolveTenant: function() { return /* binding */ resolveTenant; }, /* harmony export */ respondMeeting: function() { return /* binding */ respondMeeting; }, /* harmony export */ reviseMessage: function() { return /* binding */ reviseMessage; }, /* harmony export */ searchConversations: function() { return /* binding */ searchConversations; }, /* harmony export */ searchOrganization: function() { return /* binding */ searchOrganization; }, /* harmony export */ searchTopicMessages: function() { return /* binding */ searchTopicMessages; }, /* harmony export */ searchUsers: function() { return /* binding */ searchUsers; }, /* harmony export */ sendDailyReminders: function() { return /* binding */ sendDailyReminders; }, /* harmony export */ sendMeetingReminders: function() { return /* binding */ sendMeetingReminders; }, /* harmony export */ setIndependentPassword: function() { return /* binding */ setIndependentPassword; }, /* harmony export */ submitAbuseReport: function() { return /* binding */ submitAbuseReport; }, /* harmony export */ submitDailyReport: function() { return /* binding */ submitDailyReport; }, /* harmony export */ submitExecutiveMailboxMessage: function() { return /* binding */ submitExecutiveMailboxMessage; }, /* harmony export */ submitFeedback: function() { return /* binding */ submitFeedback; }, /* harmony export */ submitMonthlyReport: function() { return /* binding */ submitMonthlyReport; }, /* harmony export */ submitRealname: function() { return /* binding */ submitRealname; }, /* harmony export */ submitTenantApplication: function() { return /* binding */ submitTenantApplication; }, /* harmony export */ submitTenantEntryFeedback: function() { return /* binding */ submitTenantEntryFeedback; }, /* harmony export */ transferGroupOwner: function() { return /* binding */ transferGroupOwner; }, /* harmony export */ unblockUser: function() { return /* binding */ unblockUser; }, /* harmony export */ unmuteGroupMember: function() { return /* binding */ unmuteGroupMember; }, /* harmony export */ updateConversationSettings: function() { return /* binding */ updateConversationSettings; }, /* harmony export */ updateCurrentGroupAnnouncement: function() { return /* binding */ updateCurrentGroupAnnouncement; }, /* harmony export */ updateDailyDraft: function() { return /* binding */ updateDailyDraft; }, /* harmony export */ updateDevicePushToken: function() { return /* binding */ updateDevicePushToken; }, /* harmony export */ updateFriendRemark: function() { return /* binding */ updateFriendRemark; }, /* harmony export */ updateGroup: function() { return /* binding */ updateGroup; }, /* harmony export */ updateGroupGovernance: function() { return /* binding */ updateGroupGovernance; }, /* harmony export */ updateGroupMemberSettings: function() { return /* binding */ updateGroupMemberSettings; }, /* harmony export */ updateMePrivacy: function() { return /* binding */ updateMePrivacy; }, /* harmony export */ updateMeProfile: function() { return /* binding */ updateMeProfile; }, /* harmony export */ updateMeeting: function() { return /* binding */ updateMeeting; }, /* harmony export */ updateMonthlyDraft: function() { return /* binding */ updateMonthlyDraft; }, /* harmony export */ updateMyGroupProfile: function() { return /* binding */ updateMyGroupProfile; }, /* harmony export */ uploadLargeFile: function() { return /* binding */ uploadLargeFile; }, /* harmony export */ uploadPublicFile: function() { return /* binding */ uploadPublicFile; }, /* harmony export */ verifyIndependentPassword: function() { return /* binding */ verifyIndependentPassword; }, /* harmony export */ verifyPasswordResetCode: function() { return /* binding */ verifyPasswordResetCode; }, /* harmony export */ verifyRegisterCode: function() { return /* binding */ verifyRegisterCode; }, /* harmony export */ verifySecurityChallenge: function() { return /* binding */ verifySecurityChallenge; } /* harmony export */ }); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _version_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../version.js */ "./src/version.js"); /* harmony import */ var _local_storage_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./local-storage.js */ "./src/lib/local-storage.js"); const DEFAULT_API_BASE = '/v1/im'; const DEFAULT_FILE_BASE = '/v0/file'; class ImApiError extends Error { constructor(message, reason, status, details) { super(message); this.reason = reason; this.status = status; this.details = details; } } const REASON_MESSAGES = { TENANT_UNAVAILABLE: '企业码不存在或已停用', TENANT_MISMATCH: '登录状态异常,请重新进入企业码', AUTH_FAILED: '账号或密码错误', TOKEN_EXPIRED: '登录已过期,请重新登录', ACCOUNT_DISABLED: '账号已被禁用', RATE_LIMITED: '操作过于频繁,请稍后再试', VALIDATION_FAILED: '提交的内容不符合要求', IDEMPOTENCY_CONFLICT: '内容已发生变化,请刷新后重试', RESOURCE_NOT_FOUND: '内容不存在或已被删除', FORBIDDEN: '没有权限执行此操作', FRIEND_RELATION_REQUIRED: '需要先添加对方为好友', MESSAGE_NOT_ALLOWED: '当前状态无法发送消息', GROUP_MUTED: '你已被禁言,无法发言', GROUP_MEMBER_LIMIT_EXCEEDED: '群成员数量已达上限', TENANT_USER_QUOTA_EXCEEDED: '企业账号数已达上限', TENANT_GROUP_QUOTA_EXCEEDED: '企业群组数已达上限', FILE_TOO_LARGE: '文件大小超出限制', FILE_FORBIDDEN: '没有权限访问此文件', FILE_UNAVAILABLE: '文件暂不可用', STORAGE_QUOTA_EXCEEDED: '存储空间已达上限', REALNAME_REQUIRED: '需要先完成实名认证', YOUTH_MODE_RESTRICTED: '青少年模式下无法使用此功能', RISK_CONFIRMATION_REQUIRED: '需要先完成安全确认', RISK_ACTION_BLOCKED: '该操作已被安全策略拦截' }; function requestId() { return typeof crypto != 'undefined' && crypto.randomUUID ? crypto.randomUUID() : 'web_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2); } function getTenantContext() { return _local_storage_js__WEBPACK_IMPORTED_MODULE_2__["default"].getObject('im-tenant'); } function currentTenantCode() { const tenant = getTenantContext(); return tenant && tenant.code || 'default'; } function apiBase() { const tenant = getTenantContext(); return (tenant && tenant.endpoints && tenant.endpoints.api || DEFAULT_API_BASE).replace(/\/$/, ''); } function fileBase() { const tenant = getTenantContext(); return (tenant && tenant.endpoints && tenant.endpoints.file || DEFAULT_FILE_BASE).replace(/\/$/, ''); } function authToken() { return sessionStorage.getItem('im-session-token') || ''; } function normalizeResponse(payload) { return payload && payload.code === 0 && payload.data !== undefined ? payload.data : payload; } async function imRequest(path, { method = 'GET', body, headers, auth = true, tenantCodeOverride } = {}) { const finalHeaders = { 'Content-Type': 'application/json', 'X-MeetingIM-APIKey': _config_js__WEBPACK_IMPORTED_MODULE_0__.API_KEY, 'X-IM-Schema': '1', 'X-Tenant-Code': tenantCodeOverride || currentTenantCode(), 'X-Request-ID': requestId(), ...headers }; if (auth) { const token = authToken(); if (token) { finalHeaders.Authorization = 'Bearer ' + token; } } const response = await fetch(apiBase() + path, { method, headers: finalHeaders, body: body !== undefined ? JSON.stringify(body) : undefined }); const text = await response.text(); let payload = {}; if (text) { try { payload = JSON.parse(text); } catch (e) { throw new ImApiError(response.ok ? '接口返回非 JSON 数据' : response.statusText || '接口请求失败', 'NON_JSON_RESPONSE', response.status, text.slice(0, 160)); } } if (!response.ok || payload && payload.code && payload.code !== 0) { const known = payload.reason && REASON_MESSAGES[payload.reason]; throw new ImApiError(known || payload.message || payload.reason || response.statusText || '请求失败', payload.reason, response.status, payload.details); } return normalizeResponse(payload); } const idem = () => ({ 'Idempotency-Key': requestId() }); const imGet = (path, opts) => imRequest(path, opts); const imPost = (path, body, opts = {}) => imRequest(path, { method: 'POST', body, headers: idem(), ...opts }); const imPatch = (path, body, opts = {}) => imRequest(path, { method: 'PATCH', body, headers: idem(), ...opts }); const imPut = (path, body, opts = {}) => imRequest(path, { method: 'PUT', body, headers: idem(), ...opts }); const imDelete = (path, opts = {}) => imRequest(path, { method: 'DELETE', headers: idem(), ...opts }); function qs(params) { const usp = new URLSearchParams(); Object.entries(params || {}).forEach(([k, v]) => { if (v !== undefined && v !== null && v !== '') { usp.set(k, v); } }); const s = usp.toString(); return s ? '?' + s : ''; } async function uploadPublicFile(file, purpose, onProgress) { const form = new FormData(); form.append('purpose', purpose); form.append('file', file); return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('POST', apiBase() + '/public/uploads'); xhr.setRequestHeader('X-MeetingIM-APIKey', _config_js__WEBPACK_IMPORTED_MODULE_0__.API_KEY); xhr.setRequestHeader('X-IM-Schema', '1'); xhr.setRequestHeader('X-Tenant-Code', currentTenantCode()); xhr.setRequestHeader('X-Request-ID', requestId()); if (onProgress) { xhr.upload.onprogress = e => onProgress(e.lengthComputable ? e.loaded / e.total : 0); } xhr.onload = () => { let payload = {}; try { payload = JSON.parse(xhr.responseText); } catch (e) {} if (xhr.status >= 200 && xhr.status < 300 && payload.code === 0) { resolve(normalizeResponse(payload)); } else { reject(new ImApiError(payload.message || payload.reason || '上传失败', payload.reason, xhr.status, payload.details)); } }; xhr.onerror = () => reject(new ImApiError('网络错误,上传失败', 'NETWORK_ERROR', 0)); xhr.send(form); }); } function uploadLargeFile(tinode, file, onProgress) { const authToken = tinode && tinode.getAuthToken && tinode.getAuthToken(); if (!authToken) { return Promise.reject(new ImApiError('尚未登录,无法上传文件', 'AUTH_REQUIRED', 401)); } const form = new FormData(); form.append('file', file); form.set('id', tinode.getNextUniqueId()); return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('POST', fileBase() + '/u/'); xhr.setRequestHeader('X-MeetingIM-APIKey', _config_js__WEBPACK_IMPORTED_MODULE_0__.API_KEY); xhr.setRequestHeader('Authorization', 'Token ' + authToken.token); if (onProgress) { xhr.upload.onprogress = e => onProgress(e.lengthComputable ? e.loaded / e.total : 0); } xhr.onload = () => { let payload = {}; try { payload = JSON.parse(xhr.responseText); } catch (e) {} const ctrl = payload.ctrl || {}; if (xhr.status >= 200 && xhr.status < 300 && ctrl.params && ctrl.params.url) { const url = ctrl.params.url; resolve({ fileId: url.slice(url.lastIndexOf('/') + 1), url, expires: ctrl.params.expires }); } else { reject(new ImApiError(ctrl.text || '上传失败', 'UPLOAD_FAILED', xhr.status)); } }; xhr.onerror = () => reject(new ImApiError('网络错误,上传失败', 'NETWORK_ERROR', 0)); xhr.send(form); }); } function createChatUploader(tinode) { const xhrs = []; return { onProgress: null, upload(file) { const self = this; const authToken = tinode && tinode.getAuthToken && tinode.getAuthToken(); if (!authToken) { return Promise.reject(new ImApiError('尚未登录,无法上传文件', 'AUTH_REQUIRED', 401)); } return new Promise((resolve, reject) => { const form = new FormData(); form.append('file', file); form.set('id', tinode.getNextUniqueId()); const xhr = new XMLHttpRequest(); xhrs.push(xhr); xhr.open('POST', fileBase() + '/u/'); xhr.setRequestHeader('X-MeetingIM-APIKey', _config_js__WEBPACK_IMPORTED_MODULE_0__.API_KEY); xhr.setRequestHeader('Authorization', 'Token ' + authToken.token); xhr.upload.onprogress = e => { if (e.lengthComputable && self.onProgress) { self.onProgress(e.loaded / e.total); } }; xhr.onload = () => { let payload = {}; try { payload = JSON.parse(xhr.responseText); } catch (e) {} const ctrl = payload.ctrl || {}; if (xhr.status >= 200 && xhr.status < 300 && ctrl.params && ctrl.params.url) { resolve(ctrl.params.url); } else { reject(new ImApiError(ctrl.text || '上传失败', 'UPLOAD_FAILED', xhr.status)); } }; xhr.onerror = () => reject(new ImApiError('网络错误,上传失败', 'NETWORK_ERROR', 0)); xhr.send(form); }); }, cancel() { xhrs.forEach(req => { if (req.readyState < 4) { req.abort(); } }); } }; } function createFileDownloader(tinode) { const xhrs = []; return { download(relativeUrl, filename, mimetype, onProgress, onError) { const authToken = tinode && tinode.getAuthToken && tinode.getAuthToken(); if (!authToken) { const err = new ImApiError('尚未登录,无法下载文件', 'AUTH_REQUIRED', 401); if (onError) { onError(err); } return Promise.reject(err); } return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhrs.push(xhr); xhr.open('GET', relativeUrl, true); xhr.setRequestHeader('X-MeetingIM-APIKey', _config_js__WEBPACK_IMPORTED_MODULE_0__.API_KEY); xhr.setRequestHeader('Authorization', 'Token ' + authToken.token); xhr.responseType = 'blob'; xhr.onprogress = e => { if (onProgress) { onProgress(e.loaded); } }; xhr.onload = () => { if (xhr.status === 200) { const link = document.createElement('a'); link.href = window.URL.createObjectURL(new Blob([xhr.response], { type: mimetype })); link.style.display = 'none'; link.setAttribute('download', filename); document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(link.href); resolve(); } else { const reader = new FileReader(); reader.onload = function () { let err; try { const pkt = JSON.parse(this.result); err = new ImApiError(pkt.ctrl && pkt.ctrl.text || '下载失败', 'DOWNLOAD_FAILED', xhr.status); } catch (e) { err = new ImApiError('下载失败', 'DOWNLOAD_FAILED', xhr.status); } if (onError) { onError(err); } reject(err); }; reader.readAsText(xhr.response); } }; xhr.onerror = () => { const err = new ImApiError('网络错误,下载失败', 'NETWORK_ERROR', 0); if (onError) { onError(err); } reject(err); }; xhr.send(); }); }, cancel() { xhrs.forEach(req => { if (req.readyState < 4) { req.abort(); } }); } }; } function resolveTenant(tenantCode) { return imRequest('/tenants/resolve', { method: 'POST', auth: false, tenantCodeOverride: tenantCode, body: { tenant_code: tenantCode, platform: 'web', app_version: _version_js__WEBPACK_IMPORTED_MODULE_1__.PACKAGE_VERSION || '0.25.3' } }); } function submitTenantApplication(body) { return imRequest('/tenant-applications', { method: 'POST', auth: false, headers: idem(), body }); } function submitTenantEntryFeedback(body) { return imRequest('/tenant-entry-feedback', { method: 'POST', auth: false, headers: idem(), body }); } function requestVerificationCode(scene, phone) { return imRequest('/auth/verification-codes', { method: 'POST', auth: false, headers: idem(), body: { scene, phone } }); } function verifyRegisterCode(challengeId, code) { return imRequest('/auth/verification-codes/' + encodeURIComponent(challengeId) + '/verify', { method: 'POST', auth: false, body: { code } }); } function verifyPasswordResetCode(challengeId, code) { return imRequest('/auth/password-reset/challenges/' + encodeURIComponent(challengeId) + '/verify', { method: 'POST', auth: false, body: { code } }); } function confirmPasswordReset(resetToken, newPassword) { return imRequest('/auth/password-reset/confirm', { method: 'POST', auth: false, headers: idem(), body: { reset_token: resetToken, new_password: newPassword } }); } function getBootstrap() { return imRequest('/bootstrap'); } function getMe() { return imRequest('/me'); } function getRealnameStatus() { return imRequest('/security/realname'); } function submitRealname(body) { return imPost('/security/realname/submissions', body); } function createSecurityChallenge(scene) { return imPost('/security/challenges', { scene, channel: 'sms' }); } function verifySecurityChallenge(challengeId, code) { return imPost('/security/challenges/' + encodeURIComponent(challengeId) + '/verify', { code }); } function setIndependentPassword(password, purpose, actionToken) { return imPost('/settings/independent-password', { password, purpose, action_token: actionToken }); } function verifyIndependentPassword(password, purpose, action) { return imPost('/settings/independent-password/verify', { password, purpose, action }); } const getFriends = (query = '', cursor = '', initial = '') => imGet('/friends' + qs({ query, cursor, initial })); const getFriendRequests = (direction = 'inbound', status = 'all', cursor = '') => imGet('/friend-requests' + qs({ direction, status, cursor })); const createFriendRequest = (targetUserId, message = '', source = 'search', sourceTopic = '') => imPost('/friend-requests', { target_user_id: targetUserId, message, source, source_topic: sourceTopic }); const acceptFriendRequest = (requestId_, version) => imPost('/friend-requests/' + encodeURIComponent(requestId_) + '/accept', version ? { version } : {}); const rejectFriendRequest = (requestId_, version) => imPost('/friend-requests/' + encodeURIComponent(requestId_) + '/reject', version ? { version } : {}); const deleteFriend = userId => imDelete('/friends/' + encodeURIComponent(userId)); const updateFriendRemark = (userId, remark) => imPatch('/friends/' + encodeURIComponent(userId), { remark }); const searchUsers = (query, type = 'account', cursor = '') => imGet('/users/search' + qs({ q: query, type, cursor })); const getUserProfile = identifier => imGet('/users/' + encodeURIComponent(identifier) + '/profile'); const createMyQRCode = (expiresInSeconds = 86400) => imPost('/me/qrcodes', { purpose: 'add_friend', expires_in_seconds: expiresInSeconds }); const createUserQRCode = (identifier, expiresInSeconds = 86400) => imPost('/users/' + encodeURIComponent(identifier) + '/qrcodes', { purpose: 'add_friend', expires_in_seconds: expiresInSeconds }); const resolveQRCode = (token, purpose = 'add_friend') => imPost('/qrcodes/resolve', { token, purpose }); const getBlocks = (cursor = '') => imGet('/blocks' + qs({ cursor })); const blockUser = userId => imPut('/blocks/' + encodeURIComponent(userId), {}); const unblockUser = userId => imDelete('/blocks/' + encodeURIComponent(userId)); const batchUnblockUsers = userIds => imPost('/blocks/batch-delete', { user_ids: userIds }); const searchConversations = (query = '', cursor = '') => imGet('/search/conversations' + qs({ q: query, cursor })); const getSystemNotifications = (cursor = '', limit = 20) => imGet('/system-notifications' + qs({ cursor, limit })); const markSystemNotificationRead = id => imPost('/system-notifications/' + encodeURIComponent(id) + '/read', { read_at: new Date().toISOString() }); const getConversationContext = topic => imGet('/conversations/' + encodeURIComponent(topic) + '/context'); const createP2PConversation = peerUserId => imPost('/conversations/p2p', { peer_user_id: peerUserId }); const getConversationSettings = topic => imGet('/conversations/' + encodeURIComponent(topic) + '/settings'); const updateConversationSettings = (topic, body) => imPatch('/conversations/' + encodeURIComponent(topic) + '/settings', body); const recallMessage = (topic, seq, version = 1, reason = 'mistake') => imPost('/topics/' + encodeURIComponent(topic) + '/messages/' + encodeURIComponent(seq) + '/recall', { version, reason }); const reviseMessage = (topic, seq, content, version = 1) => imPost('/topics/' + encodeURIComponent(topic) + '/messages/' + encodeURIComponent(seq) + '/revisions', { content, client_mid: requestId(), version }); const getMessageReceipts = (topic, seq, cursor = '') => imGet('/topics/' + encodeURIComponent(topic) + '/messages/' + encodeURIComponent(seq) + '/receipts' + qs({ cursor })); const searchTopicMessages = (topic, { query = '', type = 'all', cursor = '' } = {}) => imGet('/topics/' + encodeURIComponent(topic) + '/messages/search' + qs({ q: query, type, cursor })); const getMessageContext = (topic, seq, before = 20, after = 20) => imGet('/topics/' + encodeURIComponent(topic) + '/messages/' + encodeURIComponent(seq) + '/context' + qs({ before, after })); const getTopicMedia = (topic, type = 'image', cursor = '') => imGet('/topics/' + encodeURIComponent(topic) + '/media' + qs({ type, cursor })); const getForwardTargets = (query = '', cursor = '') => imGet('/forward-targets' + qs({ query, cursor })); const forwardMessages = (mode, sources, targetTopics, comment = '') => imPost('/messages/forward', { mode, sources, target_topics: targetTopics, comment }); const getForwardBundle = (bundleId, cursor = '') => imGet('/forward-bundles/' + encodeURIComponent(bundleId) + qs({ cursor })); const favoriteMessages = messages => imPost('/favorites/batch', { messages: messages.map(m => ({ ...m, seq: String(m.seq) })) }); const getFavorites = ({ type = 'all', query = '', cursor = '' } = {}) => imGet('/favorites' + qs({ type, q: query, cursor })); const getFavorite = favoriteId => imGet('/favorites/' + encodeURIComponent(favoriteId)); const deleteFavorite = favoriteId => imDelete('/favorites/' + encodeURIComponent(favoriteId)); const batchDeleteFavorites = favoriteIds => imPost('/favorites/batch-delete', { favorite_ids: favoriteIds }); const forwardFavorites = (favoriteIds, targetTopics, comment = '') => imPost('/favorites/forward', { favorite_ids: favoriteIds, target_topics: targetTopics, comment }); const checkURL = (url, source = 'favorite') => imPost('/security/urls/check', { url, source }); const confirmRiskChallenge = (riskChallengeId, decision = 'continue') => imPost('/security/risk-challenges/' + encodeURIComponent(riskChallengeId) + '/confirm', { decision }); const getMentionableGroupMembers = (topic, query = '', cursor = '') => imGet('/groups/' + encodeURIComponent(topic) + '/members' + qs({ mentionable: true, query, cursor })); async function fetchFileState(fileId, range = '') { const headers = { 'X-MeetingIM-APIKey': _config_js__WEBPACK_IMPORTED_MODULE_0__.API_KEY, 'X-IM-Schema': '1', 'X-Tenant-Code': currentTenantCode(), 'X-Request-ID': requestId() }; const token = authToken(); if (token) { headers.Authorization = 'Token ' + token; } if (range) { headers.Range = range; } const response = await fetch(fileBase() + '/s/' + encodeURIComponent(fileId), { headers }); return { ok: response.ok, status: response.status, contentType: response.headers.get('content-type') || '', contentLength: response.headers.get('content-length') || '', acceptRanges: response.headers.get('accept-ranges') || '', etag: response.headers.get('etag') || '' }; } function publicFileBase() { return fileBase(); } const fileUrlCache = new Map(); function getFileUrl(fileId) { if (!fileId) { return Promise.resolve(null); } if (fileUrlCache.has(fileId)) { return fileUrlCache.get(fileId); } const headers = { 'X-MeetingIM-APIKey': _config_js__WEBPACK_IMPORTED_MODULE_0__.API_KEY, 'X-IM-Schema': '1', 'X-Tenant-Code': currentTenantCode(), 'X-Request-ID': requestId() }; const token = authToken(); if (token) { headers.Authorization = 'Token ' + token; } const promise = fetch(fileBase() + '/s/' + encodeURIComponent(fileId), { headers }).then(res => { if (!res.ok) { throw new ImApiError('文件加载失败', 'FILE_FETCH_FAILED', res.status); } return res.blob(); }).then(blob => URL.createObjectURL(blob)).catch(err => { fileUrlCache.delete(fileId); throw err; }); fileUrlCache.set(fileId, promise); return promise; } const getGroups = ({ category = 'joined', query = '', cursor = '' } = {}) => imGet('/groups' + qs({ category, query, cursor })); const createGroup = ({ name, description = '', memberUserIds = [], avatarFileId = '' }) => imPost('/groups', { name, description, member_user_ids: memberUserIds, avatar_file_id: avatarFileId }); const getGroup = topic => imGet('/groups/' + encodeURIComponent(topic)); const updateGroup = (topic, body) => imPatch('/groups/' + encodeURIComponent(topic), body); const getGroupSettings = topic => imGet('/groups/' + encodeURIComponent(topic) + '/settings'); const updateGroupMemberSettings = (topic, { pinned, mute_notifications }) => imPatch('/groups/' + encodeURIComponent(topic) + '/member-settings', { pinned, mute_notifications }); const updateMyGroupProfile = (topic, nickname, version) => imPut('/groups/' + encodeURIComponent(topic) + '/members/me/profile', { nickname, version }); const getMyGroupProfile = topic => imGet('/groups/' + encodeURIComponent(topic) + '/members/me/profile'); const leaveGroup = topic => imPost('/groups/' + encodeURIComponent(topic) + '/leave', {}); const getGroupMembers = (topic, { query = '', cursor = '', role = '', eligibleRole = '', mentionable, muteEligible } = {}) => imGet('/groups/' + encodeURIComponent(topic) + '/members' + qs({ query, cursor, role, eligible_role: eligibleRole, mentionable: mentionable ? 'true' : '', mute_eligible: muteEligible ? 'true' : '' })); const createGroupQRCode = (topic, expiresInSeconds = 86400) => imPost('/groups/' + encodeURIComponent(topic) + '/qrcodes', { expires_in_seconds: expiresInSeconds }); const inviteGroupMembers = (topic, userIds, message = '') => imPost('/groups/' + encodeURIComponent(topic) + '/invitations', { user_ids: userIds, message }); const acceptGroupInvitation = invitationId => imPost('/group-invitations/' + encodeURIComponent(invitationId) + '/accept', {}); const createGroupJoinRequest = (topic, { message = '', source = 'qr', qrToken = '' } = {}) => imPost('/groups/' + encodeURIComponent(topic) + '/join-requests', { message, source, qr_token: qrToken }); const getGroupJoinRequests = (topic, status = 'pending', cursor = '') => imGet('/groups/' + encodeURIComponent(topic) + '/join-requests' + qs({ status, cursor })); const acceptGroupJoinRequest = (topic, requestId_, version) => imPost('/groups/' + encodeURIComponent(topic) + '/join-requests/' + encodeURIComponent(requestId_) + '/accept', version ? { version } : {}); const rejectGroupJoinRequest = (topic, requestId_, version) => imPost('/groups/' + encodeURIComponent(topic) + '/join-requests/' + encodeURIComponent(requestId_) + '/reject', version ? { version } : {}); const getGroupSummary = topic => imGet('/groups/' + encodeURIComponent(topic) + '/summary'); const getLatestGroupAnnouncement = topic => imGet('/groups/' + encodeURIComponent(topic) + '/announcements/latest'); const updateCurrentGroupAnnouncement = (topic, content, version) => imPut('/groups/' + encodeURIComponent(topic) + '/announcements/current', { content, version }); const getGroupAnnouncement = (topic, announcementId) => imGet('/groups/' + encodeURIComponent(topic) + '/announcements/' + encodeURIComponent(announcementId)); const readGroupAnnouncement = (topic, announcementId) => imPost('/groups/' + encodeURIComponent(topic) + '/announcements/' + encodeURIComponent(announcementId) + '/read', {}); const getGroupGovernance = topic => imGet('/groups/' + encodeURIComponent(topic) + '/governance'); const updateGroupGovernance = (topic, body) => imPatch('/groups/' + encodeURIComponent(topic) + '/governance', body); const getGroupRoleLimits = topic => imGet('/groups/' + encodeURIComponent(topic) + '/role-limits'); const addGroupAdmins = (topic, userIds, version) => imPost('/groups/' + encodeURIComponent(topic) + '/admins/batch', { user_ids: userIds, version }); const deleteGroupAdmin = (topic, userId, version) => imDelete('/groups/' + encodeURIComponent(topic) + '/admins/' + encodeURIComponent(userId), version ? { headers: { ...idem(), 'If-Match': String(version) } } : {}); const muteGroupMembers = (topic, members, reason = '') => imPost('/groups/' + encodeURIComponent(topic) + '/mutes', { members, reason }); const getGroupMutes = (topic, cursor = '') => imGet('/groups/' + encodeURIComponent(topic) + '/mutes' + qs({ cursor })); const unmuteGroupMember = (topic, userId) => imDelete('/groups/' + encodeURIComponent(topic) + '/mutes/' + encodeURIComponent(userId)); const transferGroupOwner = (topic, targetUserId, version, actionToken = '') => imPost('/groups/' + encodeURIComponent(topic) + '/owner-transfer', { target_user_id: targetUserId, version }, actionToken ? { headers: { ...idem(), 'X-Action-Token': actionToken } } : {}); const getGroupFiles = (topic, { query = '', type = '', cursor = '' } = {}) => imGet('/groups/' + encodeURIComponent(topic) + '/files' + qs({ q: query, type, cursor })); const addGroupFile = (topic, { fileId, fileName = '', mimeType = '', fileType = '', fileSize = 0, sourceTopic = '', sourceSeq } = {}) => imPost('/groups/' + encodeURIComponent(topic) + '/files', { file_id: fileId, file_name: fileName, mime_type: mimeType, file_type: fileType, file_size: fileSize, source_topic: sourceTopic, source_seq: sourceSeq }); const deleteGroupFile = (topic, groupFileId) => imDelete('/groups/' + encodeURIComponent(topic) + '/files/' + encodeURIComponent(groupFileId)); const getGroupMemberProfile = (topic, userId) => imGet('/groups/' + encodeURIComponent(topic) + '/members/' + encodeURIComponent(userId) + '/profile'); const getWorkbench = () => imGet('/workbench'); const getOrganizationDepartments = (parentId = 'root', cursor = '') => imGet('/organization/departments' + qs({ parent_id: parentId, cursor })); const getOrganizationDepartmentMembers = (departmentId, cursor = '') => imGet('/organization/departments/' + encodeURIComponent(departmentId) + '/members' + qs({ cursor })); const getOrganizationMembers = ({ query = '', departmentId = '', cursor = '' } = {}) => imGet('/organization/members' + qs({ q: query, department_id: departmentId, cursor })); const searchOrganization = (query = '', types = 'department,user', cursor = '') => imGet('/organization/search' + qs({ q: query, types, cursor })); const getMeetings = (cursor = '', limit = 20) => imGet('/meetings' + qs({ limit, cursor })); const createMeeting = body => imPost('/meetings', body); const getMeeting = meetingId => imGet('/meetings/' + encodeURIComponent(meetingId)); const updateMeeting = (meetingId, body) => imPatch('/meetings/' + encodeURIComponent(meetingId), body); const cancelMeeting = (meetingId, version, reason = '时间冲突') => imPost('/meetings/' + encodeURIComponent(meetingId) + '/cancel', { version, reason }); const sendMeetingReminders = meetingId => imPost('/meetings/' + encodeURIComponent(meetingId) + '/reminders', {}); const respondMeeting = (meetingId, response, version) => imPut('/meetings/' + encodeURIComponent(meetingId) + '/my-response', { response, version }); const getDailyReports = ({ scope = 'mine', from = '', to = '', status = '', cursor = '' } = {}) => imGet('/reports/daily' + qs({ scope, from, to, status, cursor })); const createDailyReport = reportDate => imPost('/reports/daily', { report_date: reportDate }); const getDailyReport = reportId => imGet('/reports/daily/' + encodeURIComponent(reportId)); const updateDailyDraft = (reportId, content, version, attachments = []) => imPut('/reports/daily/' + encodeURIComponent(reportId) + '/draft', { content, attachments, version }); const submitDailyReport = (reportId, version) => imPost('/reports/daily/' + encodeURIComponent(reportId) + '/submit', { version }); const getDailyStatistics = date => imGet('/reports/daily/statistics' + qs({ date })); const sendDailyReminders = (date, userIds = []) => imPost('/reports/daily/reminders', { date, user_ids: userIds }); const getMonthlyReports = ({ scope = 'mine', fromMonth = '', toMonth = '', status = '', cursor = '' } = {}) => imGet('/reports/monthly' + qs({ scope, from_month: fromMonth, to_month: toMonth, status, cursor })); const createMonthlyReport = month => imPost('/reports/monthly', { month }); const getMonthlyReport = reportId => imGet('/reports/monthly/' + encodeURIComponent(reportId)); const updateMonthlyDraft = (reportId, workSummary, nextPlan, version, attachments = []) => imPut('/reports/monthly/' + encodeURIComponent(reportId) + '/draft', { work_summary: workSummary, next_plan: nextPlan, attachments, version }); const submitMonthlyReport = (reportId, version) => imPost('/reports/monthly/' + encodeURIComponent(reportId) + '/submit', { version }); const reopenMonthlyReport = (reportId, version, reason = '补充内容') => imPost('/reports/monthly/' + encodeURIComponent(reportId) + '/reopen', { version, reason }); const getMonthlyStatistics = month => imGet('/reports/monthly/statistics' + qs({ month })); const getExecutiveMailboxConfig = () => imGet('/executive-mailbox/config'); const submitExecutiveMailboxMessage = body => imPost('/executive-mailbox/submissions', body); const getMeProfile = () => imGet('/me/profile'); const updateMeProfile = body => imPatch('/me/profile', body); const getMePrivacy = () => imGet('/me/privacy'); const updateMePrivacy = body => imPatch('/me/privacy', body); const getYouthMode = () => imGet('/settings/youth-mode'); const enableYouthMode = (policyVersion, actionToken) => imPost('/settings/youth-mode/enable', { policy_version: policyVersion, action_token: actionToken }); const disableYouthMode = actionToken => imPost('/settings/youth-mode/disable', {}, { headers: { ...idem(), 'X-Action-Token': actionToken } }); const getLatestAppRelease = ({ platform = 'android', currentVersion = '1.0.0', channel = 'stable' } = {}) => imGet('/app/releases/latest' + qs({ platform, current_version: currentVersion, channel })); const updateDevicePushToken = (deviceId, body) => imPut('/devices/' + encodeURIComponent(deviceId) + '/push-token', body); const getAbuseReasons = (targetType = 'user') => imGet('/reports/abuse/reasons' + qs({ target_type: targetType })); const submitAbuseReport = body => imPost('/reports/abuse', body); const getFeedbackConfig = () => imGet('/feedback/config'); const submitFeedback = body => imPost('/feedback', body); /***/ }), /***/ "./src/lib/local-storage.js": /*!**********************************!*\ !*** ./src/lib/local-storage.js ***! \**********************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ LocalStorageUtil; } /* harmony export */ }); class LocalStorageUtil { static setObject(key, value) { localStorage.setItem(key, JSON.stringify(value)); } static getObject(key) { const value = localStorage.getItem(key); return value && JSON.parse(value); } static updateObject(key, value) { const oldVal = this.getObject(key); this.setObject(key, Object.assign(oldVal || {}, value)); } static removeItem(key) { localStorage.removeItem(key); } } /***/ }), /***/ "./src/lib/navigation.js": /*!*******************************!*\ !*** ./src/lib/navigation.js ***! \*******************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ HashNavigation; } /* harmony export */ }); let navigationCount = 0; class HashNavigation { static parseUrlHash(hash) { const parts = hash.split('?', 2); const params = {}; let path = []; if (parts[0]) { path = parts[0].replace('#', '').split('/'); } if (parts[1]) { parts[1].split('&').forEach(arg => { const eq = arg.indexOf('='); if (eq > 0) { params[arg.slice(0, eq)] = decodeURIComponent(arg.slice(eq + 1)); } }); } return { path: path, params: params }; } static navigateTo(url) { navigationCount++; window.location.hash = url; } static goBack() { if (navigationCount > 0) { navigationCount--; window.history.back(); return true; } return false; } static composeUrlHash(path, params) { let url = path.join('/'); const args = []; for (const key in params) { if (params.hasOwnProperty(key)) { if (params[key] !== undefined) { args.push(key + '=' + encodeURIComponent(params[key])); } } } if (args.length > 0) { url += '?' + args.join('&'); } return url; } static addUrlParam(hash, key, value) { const parsed = HashNavigation.parseUrlHash(hash); parsed.params[key] = value; return HashNavigation.composeUrlHash(parsed.path, parsed.params); } static removeUrlParam(hash, key) { const parsed = HashNavigation.parseUrlHash(hash); delete parsed.params[key]; return HashNavigation.composeUrlHash(parsed.path, parsed.params); } static removeUrlParams(hash, keys) { if (!Array.isArray(keys)) { keys = [keys]; } const parsed = HashNavigation.parseUrlHash(hash); for (const key of keys) { delete parsed.params[key]; } return HashNavigation.composeUrlHash(parsed.path, parsed.params); } static setUrlSidePanel(hash, sidepanel) { const parsed = HashNavigation.parseUrlHash(hash); parsed.path[0] = sidepanel; return HashNavigation.composeUrlHash(parsed.path, parsed.params); } static setUrlInfoPanel(hash, infopanel) { const parsed = HashNavigation.parseUrlHash(hash); if (infopanel) { parsed.params.info = infopanel; } else { delete parsed.params.info; } return HashNavigation.composeUrlHash(parsed.path, parsed.params); } static setUrlTopic(hash, topic) { const parsed = HashNavigation.parseUrlHash(hash); parsed.path[1] = topic; delete parsed.params.info; return HashNavigation.composeUrlHash(parsed.path, parsed.params); } } /***/ }), /***/ "./src/lib/strformat.js": /*!******************************!*\ !*** ./src/lib/strformat.js ***! \******************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ bytesToHumanSize: function() { return /* binding */ bytesToHumanSize; }, /* harmony export */ flagEmoji: function() { return /* binding */ flagEmoji; }, /* harmony export */ idToColorClass: function() { return /* binding */ idToColorClass; }, /* harmony export */ letterTileColorId: function() { return /* binding */ letterTileColorId; }, /* harmony export */ relativeDateFormat: function() { return /* binding */ relativeDateFormat; }, /* harmony export */ secondsToTime: function() { return /* binding */ secondsToTime; }, /* harmony export */ shortDateFormat: function() { return /* binding */ shortDateFormat; }, /* harmony export */ shortenFileName: function() { return /* binding */ shortenFileName; }, /* harmony export */ truncateString: function() { return /* binding */ truncateString; } /* harmony export */ }); function shortDateFormat(then, locale) { locale = locale || window.navigator.userLanguage || window.navigator.language; const now = new Date(); if (then.getFullYear() == now.getFullYear()) { if (then.getMonth() == now.getMonth() && then.getDate() == now.getDate()) { return then.toLocaleTimeString(locale, { hour12: false, hour: '2-digit', minute: '2-digit' }); } return then.toLocaleDateString(locale, { hour12: false, month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); } return then.toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' }); } function relativeDateFormat(then, locale) { locale = locale || window.navigator.userLanguage || window.navigator.language; const now = new Date(); const thenDays = Math.floor((then.getTime() - then.getTimezoneOffset() * 60_000) / 86_400_000); const nowDays = Math.floor((now.getTime() - now.getTimezoneOffset() * 60_000) / 86_400_000); const diff = thenDays - nowDays; if (Math.abs(diff) < 2) { return new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }).format(diff, 'day'); } return new Intl.DateTimeFormat(locale).format(then); } function secondsToTime(seconds, fixedMin) { if (typeof seconds != 'number') { return ''; } let min = (Math.floor(seconds / 60) | 0) % 60; let hours = Math.floor(seconds / 3600) | 0; if (fixedMin || hours > 0) { min = min < 10 ? `0${min}` : min; } let sec = (seconds | 0) % 60; sec = sec < 10 ? `0${sec}` : sec; if (hours == 0) { return `${min}:${sec}`; } return `${hours}:${min}:${sec}`; } function bytesToHumanSize(bytes) { if (!bytes || bytes == 0) { return '0 Bytes'; } const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB']; const bucket = Math.min(Math.floor(Math.log2(bytes) / 10) | 0, sizes.length - 1); const count = bytes / Math.pow(1024, bucket); const round = bucket > 0 ? count < 3 ? 2 : count < 30 ? 1 : 0 : 0; return count.toFixed(round) + ' ' + sizes[bucket]; } function shortenFileName(filename, maxLength) { if (typeof filename != 'string') { return filename; } return filename.length > maxLength ? filename.slice(0, maxLength / 2 - 1) + '…' + filename.slice(1 - maxLength / 2) : filename; } function stringToColorHash(value) { let hash = 0; value = '' + value; for (let i = 0; i < value.length; i++) { hash = (hash << 5) - hash + value.charCodeAt(i); hash = hash & hash; } return hash; } function letterTileColorId(userId) { return Math.abs(stringToColorHash(userId)) % 16; } function idToColorClass(id, light, fg) { return (light ? 'lt-' : 'dk-') + (fg ? 'fg-' : 'bg-') + letterTileColorId(id); } function flagEmoji(countryCode) { const codePoints = countryCode.toUpperCase().split('').map(char => 0x1F1A5 + char.charCodeAt()); return String.fromCodePoint(...codePoints); } function truncateString(str, maxLength) { if (typeof str !== 'string') { return str; } if (str.length <= maxLength) { return str; } const isRTL = /[\u0590-\u05FF\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]/.test(str); return isRTL ? '…' + str.slice(0, maxLength - 1) : str.slice(0, maxLength - 1) + '…'; } /***/ }), /***/ "./src/lib/use-cached-data.js": /*!************************************!*\ !*** ./src/lib/use-cached-data.js ***! \************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ readCachedData: function() { return /* binding */ readCachedData; }, /* harmony export */ useCachedData: function() { return /* binding */ useCachedData; }, /* harmony export */ writeCachedData: function() { return /* binding */ writeCachedData; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); const cache = new Map(); function useCachedData(key, fetcher, deps) { const [data, setData] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => key ? cache.get(key) : undefined); const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => !!key && !cache.has(key)); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!key) return; let live = true; setLoading(!cache.has(key)); fetcher().then(result => { if (!live) return; cache.set(key, result); setData(result); setLoading(false); }).catch(() => { if (live) setLoading(false); }); return () => { live = false; }; }, [key, ...(deps || [])]); return [data, loading]; } function readCachedData(key) { return key ? cache.get(key) : undefined; } function writeCachedData(key, value) { if (key) cache.set(key, value); } /***/ }), /***/ "./src/lib/utils.js": /*!**************************!*\ !*** ./src/lib/utils.js ***! \**************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ arrayEqual: function() { return /* binding */ arrayEqual; }, /* harmony export */ asEmail: function() { return /* binding */ asEmail; }, /* harmony export */ asPhone: function() { return /* binding */ asPhone; }, /* harmony export */ cancelablePromise: function() { return /* binding */ cancelablePromise; }, /* harmony export */ defaultWallpaper: function() { return /* binding */ defaultWallpaper; }, /* harmony export */ deliveryMarker: function() { return /* binding */ deliveryMarker; }, /* harmony export */ isUrlRelative: function() { return /* binding */ isUrlRelative; }, /* harmony export */ sanitizeUrl: function() { return /* binding */ sanitizeUrl; }, /* harmony export */ sanitizeUrlForMime: function() { return /* binding */ sanitizeUrlForMime; }, /* harmony export */ theCard: function() { return /* binding */ theCard; }, /* harmony export */ topicDisplayName: function() { return /* binding */ topicDisplayName; }, /* harmony export */ updateFavicon: function() { return /* binding */ updateFavicon; }, /* harmony export */ urlAsAttachment: function() { return /* binding */ urlAsAttachment; }, /* harmony export */ wallpaperNameFromUrl: function() { return /* binding */ wallpaperNameFromUrl; }, /* harmony export */ wallpaperTypeFromUrl: function() { return /* binding */ wallpaperTypeFromUrl; } /* harmony export */ }); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); function topicDisplayName(topicName, publicData, fallback) { const fn = publicData && publicData.fn; if (fn) return fn; if (publicData && tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.isGroupTopicName(topicName) && publicData.name) return publicData.name; return fallback; } function updateFavicon(count) { const oldIcon = document.getElementById('shortcut-icon'); const head = document.head || document.getElementsByTagName('head')[0]; const newIcon = document.createElement('link'); newIcon.type = 'image/png'; newIcon.id = 'shortcut-icon'; newIcon.rel = 'shortcut icon'; newIcon.href = 'img/logo32x32' + (count > 0 ? 'a' : '') + '.png'; if (oldIcon) { head.removeChild(oldIcon); } head.appendChild(newIcon); document.title = (count > 0 ? '(' + count + ') ' : '') + 'Tinode'; } function theCard(fn, imageUrl, imageMimeType, note) { let card = null; fn = fn && fn.trim(); note = note && note.trim(); if (fn) { card = { fn: fn }; } if (typeof note == 'string') { card = card || {}; card.note = note ? note : tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.DEL_CHAR; } if (imageUrl) { card = card || {}; let mimeType = imageMimeType; const matches = /^data:(image\/[-a-z0-9+.]+)?(;base64)?,/i.exec(imageUrl); if (matches) { mimeType = matches[1]; card.photo = { data: imageUrl.substring(imageUrl.indexOf(',') + 1), ref: tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.DEL_CHAR }; } else { card.photo = { data: tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.DEL_CHAR, ref: imageUrl }; } card.photo.type = (mimeType || 'image/jpeg').substring('image/'.length); } return card; } function arrayEqual(a, b) { if (a === b) { return true; } if (!Array.isArray(a) || !Array.isArray(b)) { return false; } if (a.length != b.length) { return false; } a.sort(); b.sort(); for (let i = 0, l = a.length; i < l; i++) { if (a[i] !== b[i]) { return false; } } return true; } function asPhone(val) { val = val.trim(); if (/^(?:\+?(\d{1,3}))?[- (.]*(\d{3})[- ).]*(\d{3})[- .]*(\d{2})[- .]*(\d{2})?$/.test(val)) { return val.replaceAll(/[- ().]*/g, ''); } return null; } function asEmail(val) { val = val.trim(); if (/^[a-z0-9_.+-]+@[a-z0-9-]+(\.[a-z0-9-]+)+$/i.test(val)) { return val; } return null; } function isUrlRelative(url) { return url && !/^\s*([a-z][a-z0-9+.-]*:|\/\/)/im.test(url.replace(/\\/g, '/')); } function sanitizeUrl(url, allowedSchemes) { if (typeof url != 'string') { return url; } url = url.replace(/[^\x21-\x7E]/gmi, '').trim(); url = url.replace(/\\/g, '/'); if (!/^([a-z][a-z0-9+.-]*:|\/\/)/i.test(url)) { return url; } if (/^blob:http/.test(url)) { return url; } const schemes = Array.isArray(allowedSchemes) ? allowedSchemes.join('|') : 'http|https'; const re = new RegExp('^((' + schemes + '):|//)', 'i'); if (!re.test(url)) { return null; } return url; } function sanitizeUrlForMime(url, mimeMajor) { if (!url) { return null; } const sanitizedUrl = sanitizeUrl(url); if (sanitizedUrl) { return sanitizedUrl; } const re = new RegExp(`data:${mimeMajor}\/[-+.a-z0-9]+;base64,`, 'i'); if (re.test(url.trim())) { return url; } return null; } function urlAsAttachment(url) { if (url.startsWith('data:') || url.startsWith('blob:')) { return url; } let query = '', fragment = ''; const idxF = url.indexOf('#'); if (idxF > 0) { fragment = url.substring(idxF + 1); url = url.substring(0, idxF); } const idxQ = url.indexOf('?'); if (idxQ > 0) { query = url.substring(idxQ + 1); url = url.substring(0, idxQ); } const params = new URLSearchParams(query); params.append('asatt', '1'); return `${url}?${params.toString()}` + (fragment ? `#${fragment}` : ''); } function deliveryMarker(received) { switch (received) { case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_SENDING: return { name: 'access_time' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_FAILED: case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_FATAL: return { name: 'warning', color: 'red' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_SENT: return { name: 'done' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_RECEIVED: return { name: 'done_all' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_READ: return { name: 'done_all', color: 'blue' }; } return null; } function cancelablePromise(promise) { let hasCanceled = false; const wrappedPromise = promise instanceof Error ? Promise.reject(promise) : new Promise((resolve, reject) => { promise.then(result => hasCanceled ? reject({ isCanceled: true }) : resolve(result), error => hasCanceled ? reject({ isCanceled: true }) : reject(error)); }); return { promise: wrappedPromise, cancel() { hasCanceled = true; } }; } ; function defaultWallpaper() { const wallpaperIndex = __webpack_require__(/*! ../../img/bkg/index.json */ "./img/bkg/index.json"); const wp = wallpaperIndex[_config_js__WEBPACK_IMPORTED_MODULE_1__.WALLPAPER_DEFAULTS.type][_config_js__WEBPACK_IMPORTED_MODULE_1__.WALLPAPER_DEFAULTS.index]; return { name: `../${_config_js__WEBPACK_IMPORTED_MODULE_1__.WALLPAPER_DEFAULTS.path}${wp.name}`, size: wp.size }; } function wallpaperNameFromUrl(wallpaperUrl) { const parts = wallpaperUrl.split('/'); return parts[parts.length - 1]; } function wallpaperTypeFromUrl(wallpaperUrl) { const fname = wallpaperNameFromUrl(wallpaperUrl); const wallpaperIndex = __webpack_require__(/*! ../../img/bkg/index.json */ "./img/bkg/index.json"); for (const type in wallpaperIndex) { for (let i = 0; i < wallpaperIndex[type].length; i++) { if (wallpaperIndex[type][i].name == fname) { return type; } } } return null; } /***/ }), /***/ "./src/version.js": /*!************************!*\ !*** ./src/version.js ***! \************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PACKAGE_VERSION: function() { return /* binding */ PACKAGE_VERSION; } /* harmony export */ }); const PACKAGE_VERSION = "0.25.3"; /***/ }), /***/ "./src/views/acc-general-view.jsx": /*!****************************************!*\ !*** ./src/views/acc-general-view.jsx ***! \****************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ AccGeneralView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class AccGeneralView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { colorSchema: props.colorSchema || 'auto', textSize: props.textSize * 10 || '100', sendOnEnter: props.sendOnEnter || 'plain' }; this.isMac = (navigator.userAgentData && navigator.userAgentData.platform || navigator.platform).toLowerCase().startsWith('mac'); this.handleColorSchemaSelected = this.handleColorSchemaSelected.bind(this); this.handleTextSizeChanged = this.handleTextSizeChanged.bind(this); this.handleSendOnEnterSelected = this.handleSendOnEnterSelected.bind(this); } handleColorSchemaSelected(e) { this.setState({ colorSchema: e.currentTarget.value }); this.props.onChangeColorSchema(e.currentTarget.value); } handleTextSizeChanged(e) { this.setState({ textSize: e.currentTarget.value }); this.props.onTextSizeChanged(e.currentTarget.value / 10 | 0); } handleSendOnEnterSelected(e) { this.setState({ sendOnEnter: e.currentTarget.value }); this.props.onSendOnEnterChanged(e.currentTarget.value); } render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { id: "settings-form", className: "scrollable-panel", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-column", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_color_schema", defaultMessage: "Theme:", description: "Label for selecting color scheme (dark, light) in Settings" }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("ul", { className: "quoted", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { type: "radio", id: "system", name: "color-scheme-select", value: "auto", checked: this.state.colorSchema == 'auto', onChange: this.handleColorSchemaSelected }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { htmlFor: "system", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "color_schema_system", defaultMessage: "System default", description: "Name of the color schema" }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { src: "img/routine.svg", style: { verticalAlign: 'top', width: '1.6rem', height: '1.6rem' } }, void 0, false)] }, void 0, true)] }, "system", true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { type: "radio", id: "light", name: "color-scheme-select", value: "light", checked: this.state.colorSchema == 'light', onChange: this.handleColorSchemaSelected }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { htmlFor: "light", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "color_schema_light", defaultMessage: "Light", description: "Name of the color schema" }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons orange large", children: "light_mode" }, void 0, false)] }, void 0, true)] }, "light", true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { type: "radio", id: "dark", name: "color-scheme-select", value: "dark", checked: this.state.colorSchema == 'dark', onChange: this.handleColorSchemaSelected }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { htmlFor: "dark", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "color_schema_dark", defaultMessage: "Dark", description: "Name of the color schema" }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons blue large", children: "dark_mode" }, void 0, false)] }, void 0, true)] }, "dark", true)] }, void 0, true) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "hr" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row clean-clickable", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("a", { onClick: this.props.onSelectWallpapers, className: "flat-button", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons", children: "wallpaper" }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "wallpapers", defaultMessage: "Wallpapers", description: "Link or title for working with wallpapers." }, void 0, false)] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "hr" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-column", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_text_size", defaultMessage: "Text size:", description: "Label adjusting text size" }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { type: "range", id: "text_size", name: "text_size", min: "80", max: "120", step: "10", list: "text_size_options", value: this.state.textSize, onChange: this.handleTextSizeChanged }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("datalist", { id: "text_size_options", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("option", { value: "80", label: "80%" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("option", { value: "90", label: "90%" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("option", { value: "100", label: "100%" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("option", { value: "110", label: "110%" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("option", { value: "120", label: "120%" }, void 0, false)] }, void 0, true) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "hr" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_keyboard", defaultMessage: "Keyboard:", description: "Label for send on enter settings" }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("ul", { className: "quoted", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { type: "radio", id: "plain", name: "send-select", value: "plain", checked: this.state.sendOnEnter == 'plain', onChange: this.handleSendOnEnterSelected }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { htmlFor: "send_plain", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "send_plain", defaultMessage: "Send on Enter", description: "Config option to send message on hitting Enter" }, void 0, false), "\xA0"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: "small gray", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "send_plain_explained", defaultMessage: "Press Shift + Enter for new line", description: "Explanation how to enter newline when [Send on Enter] is enabled" }, void 0, false) }, void 0, false) }, void 0, false)] }, "plain", true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { type: "radio", id: "command", name: "send-select", value: "command", checked: this.state.sendOnEnter == 'command', onChange: this.handleSendOnEnterSelected }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { htmlFor: "send_command", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "send_command", defaultMessage: "Send on {key}", values: { key: this.isMac ? '⌘ + Enter' : 'Ctrl + Enter' }, description: "Config option to send message on hitting CTRL(or Cmd)-Enter" }, void 0, false), "\xA0"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: "small gray", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "send_command_explained", defaultMessage: "Press Enter for new line", description: "Explanation how to enter newline when [Send on CTRL-Enter] is enabled" }, void 0, false) }, void 0, false) }, void 0, false)] }, "command", true)] }, void 0, true) }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/views/acc-notifications-view.jsx": /*!**********************************************!*\ !*** ./src/views/acc-notifications-view.jsx ***! \**********************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ AccNotificationsView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class AccNotificationsView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleCheckboxClick = this.handleCheckboxClick.bind(this); } handleCheckboxClick(what, checked) { if (what == 'sound') { this.props.onToggleMessageSounds(checked); } else if (what == 'alert') { this.props.onTogglePushNotifications(checked); } } render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "scrollable-panel", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { htmlFor: "message-sound", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_message_sound", defaultMessage: "Message sound:", description: "Label for message sounds toggle" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: "sound", id: "message-sound", checked: this.props.messageSounds, onChange: this.handleCheckboxClick }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { htmlFor: "desktop-alerts", children: this.props.desktopAlertsEnabled ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_push_notifications", defaultMessage: "Notification alerts:", description: "Label for push notifications switch" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_push_notifications_disabled", defaultMessage: "Notification alerts (requires HTTPS):", description: "Label for push notifications switch" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: "alert", id: "desktop-alerts", checked: this.props.desktopAlerts, onChange: this.props.desktopAlertsEnabled ? this.handleCheckboxClick : null }, void 0, false)] }, void 0, true)] }, void 0, true); } } ; /***/ }), /***/ "./src/views/acc-support-view.jsx": /*!****************************************!*\ !*** ./src/views/acc-support-view.jsx ***! \****************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ AccSupportView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class AccSupportView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "scrollable-panel", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-column", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("a", { href: _config_js__WEBPACK_IMPORTED_MODULE_3__.LINK_CONTACT_US, className: "flat-button", target: "_blank", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("i", { className: "material-icons", children: "email" }, void 0, false), " \xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "link_contact_us", defaultMessage: "Contact Us", description: "Ancor text for contacting us by email" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("a", { href: _config_js__WEBPACK_IMPORTED_MODULE_3__.LINK_TERMS_OF_SERVICE, className: "flat-button", target: "_blank", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("i", { className: "material-icons", children: "description" }, void 0, false), " \xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "link_terms_of_service", defaultMessage: "Terms of Service", description: "Ancor text for terms of service link" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("a", { href: _config_js__WEBPACK_IMPORTED_MODULE_3__.LINK_PRIVACY_POLICY, className: "flat-button", target: "_blank", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("i", { className: "material-icons", children: "policy" }, void 0, false), " \xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "link_privacy_policy", defaultMessage: "Privacy Policy", description: "Ancor text for privacy policy link" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "hr" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-column", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_client", defaultMessage: "Client:", description: "Label for a client version" }, void 0, false) }, void 0, false), _config_js__WEBPACK_IMPORTED_MODULE_3__.APP_NAME] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_sdk", defaultMessage: "SDK:" }, void 0, false) }, void 0, false), tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.getLibrary()] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_server", defaultMessage: "Server:", description: "Label for a server version" }, void 0, false) }, void 0, false), this.props.serverVersion] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_server_address", defaultMessage: "Server address:" }, void 0, false) }, void 0, false), this.props.serverAddress] }, void 0, true)] }, void 0, true)] }, void 0, true); } } ; /***/ }), /***/ "./src/views/auth-onboarding-view.jsx": /*!********************************************!*\ !*** ./src/views/auth-onboarding-view.jsx ***! \********************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ AuthOnboardingView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const USERNAME_RE = /^[a-z0-9]{1,10}$/; const PHONE_RE = /^\d{11}$/; const INVITE_RE = /^[A-Za-z]{5}$/; const CREDIT_CODE_RE = /^[0-9A-Z]{18}$/; const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const navigate = view => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__["default"].navigateTo(view); function Icon({ children, className = '' }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("i", { className: 'material-icons ' + className, "aria-hidden": "true", children: children }, void 0, false); } function AppMark({ tenantName }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-brand", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-logo", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "J" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("h1", { children: tenantName || '即时通讯' }, void 0, false)] }, void 0, true); } function Header({ title, back = 'tenant' }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("header", { className: "auth-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", className: "auth-icon-button", onClick: () => { if (!_lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__["default"].goBack()) navigate(back); }, "aria-label": "返回", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("h1", { children: title }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { className: "auth-header-spacer" }, void 0, false)] }, void 0, true); } function Field({ icon, action, error, className = '', ...props }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: 'auth-field-wrap ' + className, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: 'auth-field' + (error ? ' invalid' : ''), children: [icon ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { className: "auth-field-icon", children: icon }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { ...props }, void 0, false), action] }, void 0, true), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-field-error", children: error }, void 0, false) : null] }, void 0, true); } function PasswordField(props) { const [visible, setVisible] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Field, { ...props, type: visible ? 'text' : 'password', action: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", className: "auth-inline-icon", onClick: () => setVisible(!visible), "aria-label": visible ? '隐藏密码' : '显示密码', children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: visible ? 'visibility' : 'visibility_off' }, void 0, false) }, void 0, false) }, void 0, false); } function Agreement({ checked, onChange, prefix = '同意捷信密使' }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { className: "auth-agreement", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { type: "checkbox", checked: checked, onChange: e => onChange(e.target.checked) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: [prefix, " ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("a", { href: "#agreement", onClick: e => e.preventDefault(), children: "《用户协议》" }, void 0, false), " 和 ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("a", { href: "#privacy", onClick: e => e.preventDefault(), children: "《隐私政策》" }, void 0, false)] }, void 0, true)] }, void 0, true); } function Toast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 2800); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-toast", role: "status", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "check_circle" }, void 0, false), message] }, void 0, true) : null; } function FormAlert({ text }) { return text ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-form-alert", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "error_outline" }, void 0, false), text] }, void 0, true) : null; } function TenantEntry({ onTenantResolved }) { const [code, setCode] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(sessionStorage.getItem('im-tenant-code') || ''); const [error, setError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const submit = async e => { e.preventDefault(); const value = code.trim(); if (!value || value.length > 64) { setError(value ? '企业码不能超过 64 个字符' : '请输入企业码'); return; } setBusy(true); setError(''); try { const data = await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.resolveTenant)(value); sessionStorage.setItem('im-tenant-code', data.tenant.code || value); sessionStorage.setItem('im-tenant-name', data.tenant.name || data.tenant.code || value); onTenantResolved(data, value); navigate('login'); } catch (err) { setError('企业码不存在或已停用,请核实后重试'); } finally { setBusy(false); } }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-landing", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-top-link", type: "button", onClick: () => navigate('enterprise-register'), children: "企业注册" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("form", { className: "auth-landing-form", onSubmit: submit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(AppMark, {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Field, { value: code, onChange: e => { setCode(e.target.value); setError(''); }, placeholder: "请输入企业码", autoComplete: "organization", maxLength: "64", error: error, autoFocus: true }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-primary", type: "submit", disabled: !code.trim() || busy, children: busy ? '进入中…' : '进入企业' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-bottom-link", type: "button", onClick: () => navigate('enterprise-feedback'), children: "遇到问题?" }, void 0, false)] }, void 0, true); } function Login({ tenantName, login, loginDisabled, persist, errorText, errorLevel, onLoginRequest, onPersistenceChange, onError }) { const [account, setAccount] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(login || ''); const [password, setPassword] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [agreed, setAgreed] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!persist) { onPersistenceChange(true); } }, []); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (errorLevel === 'err' && errorText) { setPassword(''); } }, [errorText, errorLevel]); const submit = e => { e.preventDefault(); if (!account.trim() || !password || !agreed || loginDisabled) return; onLoginRequest(account.trim(), password); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-landing auth-login-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", className: "auth-back-link", onClick: () => { onError && onError(); navigate('tenant'); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false), "切换企业"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("form", { className: "auth-landing-form", onSubmit: submit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(AppMark, { tenantName: tenantName }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(FormAlert, { text: errorLevel === 'err' ? errorText : '' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Field, { value: account, onChange: e => setAccount(e.target.value), placeholder: "请输入用户名/手机号", autoComplete: "username" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(PasswordField, { value: password, onChange: e => setPassword(e.target.value), placeholder: "请输入密码", autoComplete: "current-password" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-row auth-row-end", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", className: "auth-text-button", onClick: () => navigate('reset'), children: "忘记密码" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-primary", type: "submit", disabled: !account.trim() || !password || !agreed || loginDisabled, children: loginDisabled ? '登录中…' : '登录' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { className: "auth-switch", children: ["没有账户? ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", onClick: () => navigate('register'), children: "马上注册" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Agreement, { checked: agreed, onChange: setAgreed }, void 0, false)] }, void 0, true); } function EnterpriseRegister() { const [creditCode, setCreditCode] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [email, setEmail] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [file, setFile] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [errors, setErrors] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({}); const [submitting, setSubmitting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [submitted, setSubmitted] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [reviewDays, setReviewDays] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(1); const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => () => file && URL.revokeObjectURL(file.url), [file]); const chooseFile = e => { const selected = e.target.files[0]; if (!selected) return; if (selected.size > 10 * 1024 * 1024 || !['image/jpeg', 'image/png', 'image/webp', 'application/pdf'].includes(selected.type)) { setErrors({ ...errors, file: '支持 JPG、PNG、WebP、PDF,文件不超过 10MB' }); return; } if (file) URL.revokeObjectURL(file.url); setFile({ name: selected.name, type: selected.type, url: URL.createObjectURL(selected), blob: selected }); setErrors({ ...errors, file: '' }); }; const submit = async e => { e.preventDefault(); const next = {}; if (!CREDIT_CODE_RE.test(creditCode)) next.creditCode = '请输入 18 位统一社会信用代码'; if (email && !EMAIL_RE.test(email)) next.email = '请输入有效的企业邮箱'; setErrors(next); if (Object.keys(next).length) return; setSubmitting(true); try { let licenseFileId = ''; if (file) { const uploaded = await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.uploadPublicFile)(file.blob, 'enterprise_license'); licenseFileId = uploaded.file_id; } const data = await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.submitTenantApplication)({ credit_code: creditCode, enterprise_email: email, license_file_id: licenseFileId, tenant_code_hint: sessionStorage.getItem('im-tenant-code') || '' }); setReviewDays(Math.max(1, Math.round((data.estimated_review_hours || 24) / 24))); setSubmitted(true); setToast('提交成功,我们会尽快联系你'); } catch (err) { setErrors({ ...next, form: err.message || '提交失败,请稍后重试' }); } finally { setSubmitting(false); } }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Header, { title: "企业注册" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("main", { className: "auth-content auth-content-narrow", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("ol", { className: "auth-steps", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("li", { className: submitted ? '' : 'active', children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "1" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("b", { children: "填写企业信息" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "2" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("b", { children: "确定信息" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("li", { className: submitted ? 'active' : '', children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "3" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("b", { children: "提交审核" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("form", { className: "auth-form", onSubmit: submit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(FormAlert, { text: errors.form }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { className: "auth-label", children: "统一社会信用代码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Field, { value: creditCode, onChange: e => setCreditCode(e.target.value.trim().toUpperCase().replace(/[^0-9A-Z]/g, '')), placeholder: "请输入18位统一社会信用代码", maxLength: "18", icon: "qr_code_scanner", error: errors.creditCode }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { className: "auth-help", children: "请填写营业执照上的统一社会信用代码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { className: "auth-label", children: ["上传营业执照 ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "选填" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { className: 'auth-upload' + (errors.file ? ' invalid' : ''), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { type: "file", accept: "image/jpeg,image/png,image/webp,application/pdf", onChange: chooseFile }, void 0, false), file && file.type !== 'application/pdf' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("img", { src: file.url, alt: "营业执照预览" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "add_photo_alternate" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("strong", { children: file ? file.name : '点击上传营业执照' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("small", { children: "支持 JPG、PNG、WebP、PDF,不超过 10MB" }, void 0, false)] }, void 0, true), file ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", className: "auth-remove-file", onClick: () => { URL.revokeObjectURL(file.url); setFile(null); }, children: "移除文件" }, void 0, false) : null, errors.file ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-field-error", children: errors.file }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { className: "auth-label", children: ["企业邮箱 ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "选填" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Field, { icon: "mail_outline", value: email, onChange: e => setEmail(e.target.value), placeholder: "请输入企业邮箱", type: "email", error: errors.email }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { className: "auth-help", children: "用于接收审核结果及企业通知" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-primary", type: "submit", disabled: submitted || submitting || creditCode.length !== 18, children: submitted ? '已提交' : submitting ? '提交中…' : '提交资料' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { className: "auth-review-time", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "schedule" }, void 0, false), "资料提交后,预计 ", reviewDays, " 个工作日完成审核"] }, void 0, true)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } function EnterpriseFeedback() { const [description, setDescription] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [files, setFiles] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [error, setError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [submitting, setSubmitting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const addFiles = e => { const selected = Array.from(e.target.files || []).slice(0, 9 - files.length); const valid = selected.filter(file => file.size <= 10 * 1024 * 1024 && ['image/jpeg', 'image/png', 'image/webp'].includes(file.type)); setFiles(files.concat(valid.map(file => ({ name: file.name, url: URL.createObjectURL(file), blob: file })))); }; const submit = async e => { e.preventDefault(); const length = description.trim().length; if (length < 10 || length > 300) { setError('问题描述需为 10 至 300 个字符'); return; } setSubmitting(true); try { const screenshotFileIds = []; for (const item of files) { const uploaded = await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.uploadPublicFile)(item.blob, 'tenant_entry_feedback'); screenshotFileIds.push(uploaded.file_id); } await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.submitTenantEntryFeedback)({ description: description.trim(), tenant_code_hint: sessionStorage.getItem('im-tenant-code') || '', screenshot_file_ids: screenshotFileIds }); setToast('已收到反馈,我们会尽快处理'); files.forEach(item => URL.revokeObjectURL(item.url)); setDescription(''); setFiles([]); setError(''); } catch (err) { setError(err.message || '提交失败,请稍后重试'); } finally { setSubmitting(false); } }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-page auth-soft-bg", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Header, { title: "意见反馈" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("main", { className: "auth-content auth-content-narrow", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("form", { className: "auth-form", onSubmit: submit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { className: "auth-label", children: "问题反馈" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("textarea", { value: description, maxLength: "300", onChange: e => { setDescription(e.target.value); setError(''); }, placeholder: "为了更好的帮您解决问题,请在提交问题时上传截图信息,方便我们更快速的帮助您解决问题。", className: error ? 'invalid' : '' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-counter", children: [description.length, "/300"] }, void 0, true), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-field-error", children: error }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { className: "auth-label", children: ["图片(", files.length, "/9)"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-screenshot-grid", children: [files.map((file, index) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-screenshot", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("img", { src: file.url, alt: file.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", onClick: () => { URL.revokeObjectURL(file.url); setFiles(files.filter((_, i) => i !== index)); }, "aria-label": "删除截图", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "close" }, void 0, false) }, void 0, false)] }, file.url, true)), files.length < 9 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { className: "auth-add-screenshot", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { type: "file", multiple: true, accept: "image/jpeg,image/png,image/webp", onChange: addFiles }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "photo_camera" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "点击上传" }, void 0, false)] }, void 0, true) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-primary", type: "submit", disabled: description.trim().length < 10 || submitting, children: submitting ? '提交中…' : '提交' }, void 0, false)] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } function VerificationButton({ phone, scene = 'register', onChallenge, onError }) { const [seconds, setSeconds] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(0); const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!seconds) return undefined; const timer = window.setTimeout(() => setSeconds(s => s - 1), 1000); return () => window.clearTimeout(timer); }, [seconds]); const click = async () => { if (busy || seconds > 0 || !PHONE_RE.test(phone)) return; setBusy(true); try { const data = await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.requestVerificationCode)(scene, phone); onChallenge(data.challenge_id); setSeconds(data.resend_after_seconds || 60); } catch (err) { onError && onError(err.message || '获取验证码失败'); if (err.details && err.details.retry_after_seconds) { setSeconds(err.details.retry_after_seconds); } if (err.details && err.details.challenge_id) { onChallenge(err.details.challenge_id); } } finally { setBusy(false); } }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", className: "auth-code-button", disabled: busy || seconds > 0 || !PHONE_RE.test(phone), onClick: click, children: seconds > 0 ? `${seconds}s` : busy ? '发送中…' : '获取验证码' }, void 0, false); } function Register({ errorText, errorLevel, onImRegisterRequest }) { const [form, setForm] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({ username: '', phone: '', code: '', password: '', invite: '' }); const [challengeId, setChallengeId] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [agreed, setAgreed] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [errors, setErrors] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({}); const [submitting, setSubmitting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const change = key => e => setForm({ ...form, [key]: e.target.value }); const usingPhone = !!form.phone; react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (errorLevel === 'err' && errorText) setSubmitting(false); }, [errorText, errorLevel]); const submit = async e => { e.preventDefault(); const next = {}; if (!form.username && !form.phone) next.username = '用户名和手机号至少填写一项'; if (form.username && !USERNAME_RE.test(form.username)) next.username = '用户名仅支持 1-10 位小写字母或数字'; if (usingPhone) { if (!PHONE_RE.test(form.phone)) next.phone = '请输入 11 位手机号'; if (!challengeId) next.code = '请先获取验证码';else if (!/^\d{6}$/.test(form.code)) next.code = '请输入 6 位验证码'; } else if (!INVITE_RE.test(form.invite)) { next.invite = '用户名注册需填写 5 位字母邀请码'; } if (form.password.length < 8) next.password = '密码至少 8 位'; setErrors(next); if (Object.keys(next).length) return; setSubmitting(true); try { if (usingPhone) { const verified = await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.verifyRegisterCode)(challengeId, form.code); const secretAccount = form.username || '+86' + form.phone; onImRegisterRequest(secretAccount, form.password, form.username || '', { username: form.username || '', phone: form.phone, invite_code: '' }, { meth: 'tel', val: form.phone, resp: verified.verification_token, params: { challenge_id: challengeId } }); } else { onImRegisterRequest(form.username, form.password, form.username, { username: form.username, phone: '', invite_code: form.invite }, null); } } catch (err) { setErrors({ ...next, code: err.message || '验证码错误或已过期' }); setSubmitting(false); } }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-landing auth-register-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("form", { className: "auth-landing-form auth-register-form", onSubmit: submit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(AppMark, { tenantName: sessionStorage.getItem('im-tenant-name') || '讯工捷迅' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(FormAlert, { text: errorLevel === 'err' ? errorText : '' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Field, { value: form.username, onChange: e => setForm({ ...form, username: e.target.value.replace(/[^a-z0-9]/g, '').slice(0, 10) }), placeholder: "请输入用户名", error: errors.username, autoComplete: "username" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Field, { value: form.phone, onChange: e => setForm({ ...form, phone: e.target.value.replace(/\D/g, '').slice(0, 11) }), placeholder: "请输入手机号", error: errors.phone, inputMode: "numeric" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Field, { value: form.code, onChange: e => setForm({ ...form, code: e.target.value.replace(/\D/g, '').slice(0, 6) }), placeholder: "请输入短信验证码", inputMode: "numeric", error: errors.code, action: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(VerificationButton, { phone: form.phone, scene: "register", onChallenge: setChallengeId, onError: msg => setErrors(e => ({ ...e, code: msg })) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(PasswordField, { value: form.password, onChange: change('password'), placeholder: "请输入密码", autoComplete: "new-password", error: errors.password }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Field, { value: form.invite, onChange: e => setForm({ ...form, invite: e.target.value.replace(/[^A-Za-z]/g, '').slice(0, 5) }), placeholder: "请输入邀请码(非必填)", error: errors.invite }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-primary", type: "submit", disabled: !form.username && !form.phone || !form.password || !agreed || submitting, children: submitting ? '注册中…' : '注册' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { className: "auth-switch", children: ["已有讯工捷迅账号? ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", onClick: () => navigate('login'), children: "登录" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Agreement, { checked: agreed, onChange: setAgreed, prefix: "注册即认同捷讯" }, void 0, false)] }, void 0, true); } function PasswordReset() { const [form, setForm] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({ phone: '', code: '', password: '', confirm: '' }); const [challengeId, setChallengeId] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [error, setError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [submitting, setSubmitting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const change = key => e => setForm({ ...form, [key]: e.target.value }); const submit = async e => { e.preventDefault(); if (!PHONE_RE.test(form.phone)) return setError('请输入 11 位手机号'); if (!challengeId || !/^\d{6}$/.test(form.code)) return setError('请先获取并输入 6 位验证码'); if (form.password.length < 8) return setError('密码至少 8 位'); if (form.password !== form.confirm) return setError('两次输入的密码不一致'); setSubmitting(true); setError(''); try { const verified = await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.verifyPasswordResetCode)(challengeId, form.code); await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.confirmPasswordReset)(verified.reset_token, form.password); setToast('密码修改成功,请重新登录'); window.setTimeout(() => navigate('login'), 1200); } catch (err) { setError(err.message || '验证码错误或已过期'); setSubmitting(false); } }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-page auth-soft-bg", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Header, { title: "忘记密码", back: "login" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("main", { className: "auth-content auth-content-narrow auth-reset-content", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("form", { className: "auth-list-form", onSubmit: submit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "手机号" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { value: form.phone, onChange: e => setForm({ ...form, phone: e.target.value.replace(/\D/g, '').slice(0, 11) }), placeholder: "请输入手机号", inputMode: "numeric" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "验证码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { value: form.code, onChange: e => setForm({ ...form, code: e.target.value.replace(/\D/g, '').slice(0, 6) }), placeholder: "请输入验证码", inputMode: "numeric" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(VerificationButton, { phone: form.phone, scene: "reset_password", onChallenge: setChallengeId, onError: setError }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-list-gap" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "设置密码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { type: "password", value: form.password, onChange: change('password'), placeholder: "至少 8 位" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "再次输入" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { type: "password", value: form.confirm, onChange: change('confirm'), placeholder: "请再次确定密码" }, void 0, false)] }, void 0, true), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-form-alert", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "error_outline" }, void 0, false), error] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-primary auth-sticky-action", type: "submit", disabled: !form.phone || !form.code || !form.password || !form.confirm || submitting, children: submitting ? '提交中…' : '修改密码' }, void 0, false)] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } const IDENTITY_CHECK_SCENE = 'set_independent_password'; function IdentityCheck({ authenticated }) { const [phoneMask, setPhoneMask] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [challengeId, setChallengeId] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [code, setCode] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [seconds, setSeconds] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(0); const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [error, setError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!seconds) return undefined; const timer = window.setTimeout(() => setSeconds(s => s - 1), 1000); return () => window.clearTimeout(timer); }, [seconds]); const requestCode = react__WEBPACK_IMPORTED_MODULE_0___default().useCallback(async () => { setBusy(true); setError(''); try { const data = await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.createSecurityChallenge)(IDENTITY_CHECK_SCENE); setChallengeId(data.challenge_id); setPhoneMask(data.phone_mask); setSeconds(data.resend_after_seconds || 60); } catch (err) { setError(err.reason === 'REALNAME_REQUIRED' ? '需要先完成实名认证并绑定手机号' : err.message || '获取验证码失败'); } finally { setBusy(false); } }, []); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { requestCode(); }, [requestCode]); const submit = async e => { e.preventDefault(); if (!challengeId || code.length !== 6 || busy) return; setBusy(true); try { const data = await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.verifySecurityChallenge)(challengeId, code); sessionStorage.setItem('im-action-token:' + IDENTITY_CHECK_SCENE, JSON.stringify(data)); navigate('independent-password'); } catch (err) { setError(err.message || '验证码错误'); } finally { setBusy(false); } }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-page auth-soft-bg auth-identity-check-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Header, { title: "身份验证", back: authenticated ? 'security' : 'login' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("main", { className: "auth-content auth-content-narrow auth-reset-content", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("form", { className: "auth-list-form", onSubmit: submit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "手机号" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { value: phoneMask, readOnly: true, placeholder: "获取中…" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "验证码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { value: code, onChange: e => setCode(e.target.value.replace(/\D/g, '').slice(0, 6)), placeholder: "请输入验证码", inputMode: "numeric" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", className: "auth-code-button", disabled: busy || seconds > 0, onClick: requestCode, children: seconds > 0 ? `${seconds}s` : '获取验证码' }, void 0, false)] }, void 0, true), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-field-error", children: error }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-primary auth-sticky-action", type: "submit", disabled: code.length !== 6 || busy, children: "确定" }, void 0, false)] }, void 0, true) }, void 0, false)] }, void 0, true); } function Realname({ authenticated = false }) { const [status, setStatus] = react__WEBPACK_IMPORTED_MODULE_0___default().useState('loading'); const [maskedName, setMaskedName] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [maskedIdNumber, setMaskedIdNumber] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [name, setName] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [idNumber, setIdNumber] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [error, setError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.getRealnameStatus)().then(data => { setStatus(data.status); setMaskedName(data.masked_name || ''); setMaskedIdNumber(data.masked_id_number || ''); }).catch(err => { setError(err.message || '加载实名状态失败'); setStatus('load_error'); }); }, []); const editable = status === 'unverified' || status === 'rejected'; const submit = async e => { e.preventDefault(); if (name.trim().length < 2 || !/^\d{17}[\dXx]$/.test(idNumber)) { setError('请输入有效姓名和 18 位身份证号码'); return; } setBusy(true); try { const data = await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.submitRealname)({ name: name.trim(), id_type: 'cn_id', id_number: idNumber.toUpperCase() }); setStatus(data.status || 'pending'); setError(''); } catch (err) { setError(err.message || '提交失败,请稍后重试'); } finally { setBusy(false); } }; if (status === 'loading' || status === 'load_error') { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-page auth-realname-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Header, { title: "实名认证", back: authenticated ? 'security' : 'login' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { className: "auth-privacy-note", style: { margin: '2rem 1rem' }, children: status === 'load_error' ? error || '加载失败,请重试' : '加载中…' }, void 0, false)] }, void 0, true); } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-page auth-realname-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Header, { title: "实名认证", back: authenticated ? 'security' : 'login' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-realname-hero", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("strong", { children: "实名认证" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "更加真实,更受欢迎" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "verified_user" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("main", { className: "auth-realname-content", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("h2", { children: status === 'verified' ? '认证信息' : '请您使用有效身份证信息认证' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("form", { onSubmit: submit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "姓名" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { value: editable ? name : maskedName, onChange: e => setName(e.target.value), readOnly: !editable, placeholder: "请输入真实姓名" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: "证件号码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { value: editable ? idNumber : maskedIdNumber, onChange: e => setIdNumber(e.target.value), readOnly: !editable, placeholder: "请输入证件号码" }, void 0, false)] }, void 0, true), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-field-error", children: error }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-primary", type: "submit", disabled: !editable || busy, children: status === 'verified' ? '已实名' : status === 'pending' ? '审核中' : busy ? '提交中…' : '提交' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { className: "auth-privacy-note", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "info" }, void 0, false), "我们将获取您的姓名、证件号用于认证,信息会被严格保护"] }, void 0, true)] }, void 0, true)] }, void 0, true); } function RealnameReminder() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-page auth-reminder-demo", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-demo-chat", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("h1", { children: "消息" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-demo-search", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "search" }, void 0, false), "搜索"] }, void 0, true), ['系统消息', '文件助手', '项目协作群', '陈经理'].map((item, i) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-demo-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: item[0] }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("b", { children: item }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("small", { children: i ? '最近一条消息内容' : '安全通知与账号动态' }, void 0, false)] }, void 0, true)] }, item, true))] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-modal-backdrop", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-modal", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("h2", { children: "实名认证提醒" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { children: "根据国家法律法规要求,您需先进行实名认证才能使用该项 APP" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-primary", onClick: () => navigate('realname'), children: "去实名认证" }, void 0, false)] }, void 0, true) }, void 0, false)] }, void 0, true); } function IndependentPassword({ authenticated }) { const [pin, setPin] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [error, setError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const invalid = ['0000', '1111', '2222', '3333', '4444', '5555', '6666', '7777', '8888', '9999', '0123', '1234', '2345', '3456', '4567', '5678', '6789', '9876', '8765', '7654', '6543', '5432', '4321', '3210']; const submit = async e => { e.preventDefault(); if (invalid.includes(pin)) { setError('请勿使用连续或重复数字'); return; } const stored = sessionStorage.getItem('im-action-token:' + IDENTITY_CHECK_SCENE); const actionToken = stored && JSON.parse(stored).action_token; if (!actionToken) { setError('身份验证已过期,请返回重新验证'); return; } setBusy(true); try { await (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.setIndependentPassword)(pin, 'youth_mode', actionToken); sessionStorage.removeItem('im-action-token:' + IDENTITY_CHECK_SCENE); setError(''); setToast('独立密码设置成功'); setPin(''); } catch (err) { setError(err.message || '设置失败,请返回重新验证身份'); } finally { setBusy(false); } }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Header, { title: "", back: authenticated ? 'security' : 'login' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("main", { className: "auth-pin-content", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("h1", { children: "设置独立密码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-pin-boxes", "aria-hidden": "true", children: [0, 1, 2, 3].map(i => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: pin[i] ? '●' : '' }, i, false)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { className: "auth-pin-input", type: "text", value: pin, onChange: e => setPin(e.target.value.replace(/\D/g, '').slice(0, 4)), inputMode: "numeric", autoComplete: "off", "aria-label": "四位独立密码", autoFocus: true }, void 0, false), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "auth-field-error", children: error }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { className: "auth-primary", disabled: pin.length !== 4 || busy, onClick: submit, children: busy ? '提交中…' : '确定' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } function AuthOnboardingView({ view, onTenantResolved, authenticated = false, login, loginDisabled, persist, errorText, errorLevel, onLoginRequest, onPersistenceChange, onImRegisterRequest, onError }) { const tenantName = sessionStorage.getItem('im-tenant-name') || ''; switch (view) { case 'tenant': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(TenantEntry, { onTenantResolved: onTenantResolved || (() => {}) }, void 0, false); case 'login': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Login, { tenantName: tenantName, login: login, loginDisabled: loginDisabled, persist: persist, errorText: errorText, errorLevel: errorLevel, onLoginRequest: onLoginRequest, onPersistenceChange: onPersistenceChange, onError: onError }, void 0, false); case 'enterprise-register': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(EnterpriseRegister, {}, void 0, false); case 'enterprise-feedback': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(EnterpriseFeedback, {}, void 0, false); case 'register': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Register, { errorText: errorText, errorLevel: errorLevel, onImRegisterRequest: onImRegisterRequest }, void 0, false); case 'reset': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(PasswordReset, {}, void 0, false); case 'identity-check': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(IdentityCheck, { authenticated: authenticated }, void 0, false); case 'realname': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Realname, { authenticated: authenticated }, void 0, false); case 'realname-verified': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Realname, { authenticated: authenticated }, void 0, false); case 'realname-reminder': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(RealnameReminder, {}, void 0, false); case 'independent-password': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(IndependentPassword, { authenticated: authenticated }, void 0, false); default: return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(TenantEntry, { onTenantResolved: onTenantResolved || (() => {}) }, void 0, false); } } /***/ }), /***/ "./src/views/call-experience-view.jsx": /*!********************************************!*\ !*** ./src/views/call-experience-view.jsx ***! \********************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CALL_EXPERIENCE_VIEWS: function() { return /* binding */ CALL_EXPERIENCE_VIEWS; }, /* harmony export */ "default": function() { return /* binding */ CallExperienceView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const navigate = view => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__["default"].navigateTo(view); const CALL_EXPERIENCE_VIEWS = ['call-history', 'call-incoming', 'audio-call-ringing', 'audio-call-active', 'audio-call-muted', 'audio-call-speaker', 'video-call-ringing', 'video-call-camera-off', 'video-call-active', 'video-call-peer-camera-off', 'call-minimized']; const PEER = { name: '安妮', avatar: 'img/bkg/p09.jpg' }; const CALL_RECORDS = [{ id: 1, type: 'video', direction: 'outgoing', state: 'cancelled', label: '已取消', time: '今天 10:24' }, { id: 2, type: 'audio', direction: 'incoming', state: 'declined', label: '已拒绝', time: '昨天 21:03' }, { id: 3, type: 'video', direction: 'incoming', state: 'missed', label: '未接听', time: '昨天 18:42' }, { id: 4, type: 'audio', direction: 'outgoing', state: 'busy', label: '对方忙线', time: '星期一 15:10' }, { id: 5, type: 'audio', direction: 'outgoing', state: 'finished', label: '通话时长 12:36', time: '8月20日' }]; function Icon({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons", "aria-hidden": "true", children: children }, void 0, false); } function Toast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 1800); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-toast", role: "status", children: message }, void 0, false) : null; } function CallAvatar({ small = false }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: 'call-product-avatar' + (small ? ' small' : ''), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { src: PEER.avatar, alt: "" }, void 0, false) }, void 0, false); } function CallHeader({ onMinimize, light = false }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("header", { className: 'call-product-header' + (light ? ' light' : ''), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: onMinimize, "aria-label": "最小化通话", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "keyboard_arrow_down" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: "端到端加密通话" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", "aria-label": "更多通话设置", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "more_vert" }, void 0, false) }, void 0, false)] }, void 0, true); } function Control({ icon, label, active, danger, onClick }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: 'call-control' + (active ? ' active' : '') + (danger ? ' danger' : ''), onClick: onClick, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: icon }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: label }, void 0, false)] }, void 0, true); } function CallHistory() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-history-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("header", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('chat-standard'), "aria-label": "返回会话", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("h1", { children: "安妮" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('friend-profile'), "aria-label": "个人资料", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "person_outline" }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "最近通话" }, void 0, false), CALL_RECORDS.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: 'call-record ' + item.state, onClick: () => navigate(item.type === 'audio' ? 'audio-call-ringing' : 'video-call-ringing'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: item.type === 'audio' ? 'call' : 'videocam' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: item.type === 'audio' ? '语音通话' : '视频通话' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: item.label }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("time", { children: item.time }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: item.direction === 'incoming' ? 'call_received' : 'call_made' }, void 0, false)] }, item.id, true))] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("footer", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('audio-call-ringing'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "call" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: "语音通话" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('video-call-ringing'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "videocam" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: "视频通话" }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true); } function IncomingCall({ onToast }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-fullscreen call-audio-surface incoming", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-ambient" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(CallHeader, { onMinimize: () => navigate('call-minimized') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("main", { className: "call-peer-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(CallAvatar, {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("h1", { children: PEER.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { children: "邀请你进行视频通话" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: "call-ringing-dots", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", {}, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("footer", { className: "call-incoming-actions", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Control, { icon: "call_end", label: "拒绝", danger: true, onClick: () => { onToast('已拒绝视频通话'); window.setTimeout(() => navigate('call-history'), 600); } }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Control, { icon: "videocam", label: "接听", active: true, onClick: () => navigate('video-call-active') }, void 0, false)] }, void 0, true)] }, void 0, true); } function formatDuration(seconds) { const mins = Math.floor(seconds / 60).toString().padStart(2, '0'); return `${mins}:${(seconds % 60).toString().padStart(2, '0')}`; } function AudioCall({ view, onToast }) { const ringing = view === 'audio-call-ringing'; const [seconds, setSeconds] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(ringing ? 0 : 68); const [mic, setMic] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(view !== 'audio-call-muted'); const [speaker, setSpeaker] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(view === 'audio-call-speaker'); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (ringing) return undefined; const timer = window.setInterval(() => setSeconds(value => value + 1), 1000); return () => window.clearInterval(timer); }, [ringing]); const hangup = () => { onToast(ringing ? '已取消呼叫' : `通话结束 ${formatDuration(seconds)}`); window.setTimeout(() => navigate('call-history'), 650); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-fullscreen call-audio-surface", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-ambient" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(CallHeader, { onMinimize: () => navigate('call-minimized') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("main", { className: "call-peer-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(CallAvatar, {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("h1", { children: PEER.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { children: ringing ? '正在等待对方接听…' : formatDuration(seconds) }, void 0, false), !ringing ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { className: "call-network", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", {}, void 0, false), "网络良好"] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: "call-ringing-dots", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", {}, void 0, false)] }, void 0, true)] }, void 0, true), ringing ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("footer", { className: "call-single-action", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Control, { icon: "call_end", label: "取消", danger: true, onClick: hangup }, void 0, false) }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("footer", { className: "call-active-controls", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Control, { icon: mic ? 'mic' : 'mic_off', label: mic ? '麦克风' : '麦克风已关', active: mic, onClick: () => { setMic(!mic); onToast(mic ? '麦克风已关闭' : '麦克风已开启'); } }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Control, { icon: speaker ? 'volume_up' : 'hearing', label: speaker ? '扬声器' : '听筒', active: speaker, onClick: () => { setSpeaker(!speaker); onToast(speaker ? '已切换到听筒' : '扬声器已开启'); } }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Control, { icon: "call_end", label: "挂断", danger: true, onClick: hangup }, void 0, false)] }, void 0, true)] }, void 0, true); } function VideoBackdrop({ cameraOff, peerOff }) { if (peerOff) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-video-off", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(CallAvatar, {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: "对方摄像头已关闭" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: "语音通话仍在继续" }, void 0, false)] }, void 0, true); if (cameraOff) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-video-off local", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(CallAvatar, {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: "摄像头已关闭" }, void 0, false)] }, void 0, true); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { className: "call-video-backdrop", src: "img/bkg/w06.jpg", alt: "视频通话画面" }, void 0, false); } function VideoCall({ view, onToast }) { const ringing = view === 'video-call-ringing' || view === 'video-call-camera-off'; const [camera, setCamera] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(view !== 'video-call-camera-off'); const [mic, setMic] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(true); const [seconds, setSeconds] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(ringing ? 0 : 128); const peerOff = view === 'video-call-peer-camera-off'; react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (ringing) return undefined; const timer = window.setInterval(() => setSeconds(value => value + 1), 1000); return () => window.clearInterval(timer); }, [ringing]); const hangup = () => { onToast(ringing ? '已取消视频呼叫' : `视频通话结束 ${formatDuration(seconds)}`); window.setTimeout(() => navigate('call-history'), 650); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-fullscreen call-video-surface", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(VideoBackdrop, { cameraOff: ringing && !camera, peerOff: peerOff }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-video-shade" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(CallHeader, { light: true, onMinimize: () => navigate('call-minimized') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-video-status", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("h1", { children: PEER.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { children: ringing ? '正在等待对方接听…' : formatDuration(seconds) }, void 0, false)] }, void 0, true), !ringing ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "call-local-preview", "aria-label": "本地视频预览", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { src: camera ? 'img/bkg/p05.jpg' : PEER.avatar, alt: "" }, void 0, false), !camera ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "videocam_off" }, void 0, false) : null] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("footer", { className: "call-video-controls", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Control, { icon: "flip_camera_android", label: "翻转", onClick: () => onToast('已切换摄像头') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Control, { icon: camera ? 'videocam' : 'videocam_off', label: camera ? '摄像头' : '摄像头已关', active: camera, onClick: () => { setCamera(!camera); onToast(camera ? '摄像头已关闭' : '摄像头已开启'); } }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Control, { icon: "call_end", label: ringing ? '取消' : '挂断', danger: true, onClick: hangup }, void 0, false), !ringing ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Control, { icon: mic ? 'mic' : 'mic_off', label: mic ? '麦克风' : '麦克风已关', active: mic, onClick: () => setMic(!mic) }, void 0, false) : null] }, void 0, true)] }, void 0, true); } function MinimizedCall({ onToast }) { const [position, setPosition] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => ({ x: Math.max(16, window.innerWidth - 134), y: 168 })); const drag = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); const onPointerDown = event => { drag.current = { x: event.clientX - position.x, y: event.clientY - position.y }; event.currentTarget.setPointerCapture(event.pointerId); }; const onPointerMove = event => { if (!drag.current) return; setPosition({ x: Math.max(8, Math.min(window.innerWidth - 132, event.clientX - drag.current.x)), y: Math.max(70, Math.min(window.innerHeight - 190, event.clientY - drag.current.y)) }); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-minimized-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("header", { className: "call-chat-preview-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('messages-home'), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: "安妮" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: "在线" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "more_vert" }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "今天 10:24" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "call-chat-preview-message", children: "下午的评审材料我已经发到群里了。" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "call-floating-window", style: { transform: `translate(${position.x}px, ${position.y}px)` }, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: () => { drag.current = null; }, onClick: () => navigate('video-call-active'), "aria-label": "返回全屏通话", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { src: "img/bkg/w06.jpg", alt: "视频通话悬浮画面" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", {}, void 0, false), "02:18"] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("footer", { className: "call-chat-composer", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { placeholder: "输入消息" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "add_circle_outline" }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "call-mini-hangup", onClick: () => { onToast('通话已结束'); window.setTimeout(() => navigate('call-history'), 600); }, "aria-label": "挂断通话", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "call_end" }, void 0, false) }, void 0, false)] }, void 0, true); } function CallExperienceView({ view }) { const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); let content; if (view === 'call-history') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(CallHistory, {}, void 0, false);else if (view === 'call-incoming') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(IncomingCall, { onToast: setToast }, void 0, false);else if (view.startsWith('audio-call')) content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(AudioCall, { view: view, onToast: setToast }, void 0, false);else if (view === 'call-minimized') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(MinimizedCall, { onToast: setToast }, void 0, false);else content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(VideoCall, { view: view, onToast: setToast }, void 0, false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [content, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } /***/ }), /***/ "./src/views/contact-management-view.jsx": /*!***********************************************!*\ !*** ./src/views/contact-management-view.jsx ***! \***********************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CONTACT_MANAGEMENT_VIEWS: function() { return /* binding */ CONTACT_MANAGEMENT_VIEWS; }, /* harmony export */ "default": function() { return /* binding */ ContactManagementView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var qrcodejs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! qrcodejs */ "qrcodejs"); /* harmony import */ var qrcodejs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(qrcodejs__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var pinyin_pro__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! pinyin-pro */ "./node_modules/pinyin-pro/dist/esm/core/pinyin/index.mjs"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var _lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/use-cached-data.js */ "./src/lib/use-cached-data.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const navigate = (view, uid) => { let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].setUrlSidePanel(window.location.hash, view); hash = uid ? _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].addUrlParam(hash, 'uid', uid) : _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].removeUrlParam(hash, 'uid'); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].navigateTo(hash); }; const CONTACT_MANAGEMENT_VIEWS = ['address-book', 'friend-requests', 'add-friend', 'my-friend-qr', 'friend-search-result', 'friend-verification', 'friend-profile', 'group-member-profile', 'friend-settings', 'friend-settings-blocked', 'friend-delete-confirm', 'block-list', 'block-confirm', 'clear-chat-confirm']; function alphaInitial(name) { const ch = (name || '').trim()[0] || '#'; if (/[A-Za-z]/.test(ch)) { return ch.toUpperCase(); } if (/[一-龥]/.test(ch)) { const letter = (0,pinyin_pro__WEBPACK_IMPORTED_MODULE_2__.pinyin)(ch, { pattern: 'first', toneType: 'none' }); return /[a-z]/i.test(letter) ? letter.toUpperCase() : '#'; } return '#'; } function Icon({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", { className: "material-icons", "aria-hidden": "true", children: children }, void 0, false); } function Header({ title, back = 'messages-home', backUid, right, onRight }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("header", { className: "people-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => { if (!_lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].goBack()) navigate(back, backUid); }, "aria-label": "返回", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h1", { children: title }, void 0, false), right ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "text", onClick: onRight, children: right }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", {}, void 0, false)] }, void 0, true); } function Avatar({ person, icon }) { const fileId = person && person.avatar_file_id; const [url, setUrl] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!fileId) { setUrl(null); return undefined; } let live = true; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getFileUrl)(fileId).then(u => { if (live) setUrl(u); }).catch(() => {}); return () => { live = false; }; }, [fileId]); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { className: "people-avatar", children: url ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("img", { src: url, alt: "" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: icon || 'person' }, void 0, false) }, void 0, false); } function Toast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 2000); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "chat-toast", role: "status", children: message }, void 0, false) : null; } function Search({ value, onChange, placeholder, onSubmit }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("label", { className: "people-search", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "search" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("input", { value: value, onChange: event => onChange(event.target.value), onKeyDown: event => { if (event.key === 'Enter' && onSubmit) onSubmit(); }, placeholder: placeholder }, void 0, false)] }, void 0, true); } function QrCard({ payload, profile, loading }) { const ref = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!ref.current || !payload) return; ref.current.innerHTML = ''; new (qrcodejs__WEBPACK_IMPORTED_MODULE_1___default())(ref.current, { text: payload, width: 190, height: 190, correctLevel: (qrcodejs__WEBPACK_IMPORTED_MODULE_1___default().CorrectLevel).M }); }, [payload]); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "people-qr-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-qr-profile", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { person: profile }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: profile && profile.display_name || '' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: profile && profile.public_account ? '账号 ' + profile.public_account : '' }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-qrcode", ref: ref }, void 0, false), loading ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: "正在生成二维码…" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: "扫一扫上面的二维码,加我为好友" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "二维码 24 小时内有效" }, void 0, false)] }, void 0, true); } function AddressBook({ myUserId, onTopicSelected }) { const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const friendsCacheKey = myUserId ? 'friends:' + myUserId : null; const [friends, setFriends] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => friendsCacheKey && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)(friendsCacheKey) || []); const [pendingCount, setPendingCount] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(0); const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => !(friendsCacheKey && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)(friendsCacheKey))); const [bootstrap] = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.useCachedData)(myUserId ? 'bootstrap:' + myUserId : null, _lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getBootstrap, [myUserId]); const fileAssistantTopic = bootstrap && bootstrap.entries && bootstrap.entries.file_assistant && bootstrap.entries.file_assistant.topic; react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getFriends)().then(data => { const list = data.items || []; if (friendsCacheKey) { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)(friendsCacheKey, list); } setFriends(list); }).catch(() => {}).finally(() => setLoading(false)); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getFriendRequests)('inbound', 'pending').then(data => setPendingCount((data.items || []).length)).catch(() => {}); }, []); const visible = friends.filter(item => `${item.display_name}${item.remark || ''}`.includes(query)); const groups = visible.reduce((result, item) => { const key = alphaInitial(item.remark || item.display_name); return { ...result, [key]: (result[key] || []).concat(item) }; }, {}); const sortedKeys = Object.keys(groups).sort(); const entries = [{ icon: 'person_add_alt', label: '新朋友', route: 'friend-requests', badge: pendingCount || null, tone: 'blue' }, { icon: 'group', label: '群组', route: 'group-list', tone: 'green' }, { icon: 'folder_special', label: '文件助手', route: 'chat-standard', tone: 'orange', fileAssistant: true }, { icon: 'notifications', label: '系统消息', route: 'system-messages', tone: 'red' }]; const scrollTo = key => { const el = document.getElementById('people-group-' + key); if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' }); }; const openEntry = item => { if (item.fileAssistant && fileAssistantTopic && onTopicSelected) onTopicSelected(fileAssistantTopic);else navigate(item.route); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "通讯录", right: "添加", onRight: () => navigate('add-friend') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Search, { value: query, onChange: setQuery, placeholder: "搜索联系人" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "people-scroll", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "people-entry-list", children: entries.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => openEntry(item), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { icon: item.icon }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: item.label }, void 0, false), item.badge ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("em", { children: item.badge }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, item.label, true)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h3", { className: "people-section-title", children: "好友通讯录" }, void 0, false), loading ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "people-empty-hint", children: "加载中…" }, void 0, false) : sortedKeys.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "people-empty-hint", children: "暂无好友" }, void 0, false) : null, sortedKeys.map(initial => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "people-group", id: 'people-group-' + initial, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h2", { children: initial }, void 0, false), groups[initial].map(person => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => { seedProfile(person); navigate('friend-profile', person.user_id); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { person: person }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: person.remark || person.display_name }, void 0, false), person.remark ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: person.display_name }, void 0, false) : null] }, void 0, true)] }, person.user_id, true))] }, initial, true))] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("nav", { className: "people-index", children: sortedKeys.map(value => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("a", { href: "#", onClick: e => { e.preventDefault(); scrollTo(value); }, children: value }, value, false)) }, void 0, false)] }, void 0, true); } function requestStatusLabel(item) { if (item.status === 'pending') return item.direction === 'outbound' ? '已发送' : null; if (item.status === 'accepted') return '已添加'; if (item.status === 'rejected') return '已拒绝'; if (item.status === 'expired') return '已过期'; return null; } function FriendRequests({ onToast }) { const [items, setItems] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(true); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getFriendRequests)('all', 'all').then(data => setItems(data.items || [])).catch(() => {}).finally(() => setLoading(false)); }, []); const handle = (item, accept) => { const nextStatus = accept ? 'accepted' : 'rejected'; setItems(values => values.map(v => v.request_id === item.request_id ? { ...v, status: nextStatus } : v)); const call = accept ? (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.acceptFriendRequest)(item.request_id) : (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.rejectFriendRequest)(item.request_id); call.then(() => onToast(accept ? '已通过好友申请' : '已拒绝好友申请')).catch(err => { setItems(values => values.map(v => v.request_id === item.request_id ? { ...v, status: item.status } : v)); onToast(err.message || '操作失败'); }); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "新朋友", back: "address-book" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "people-request-list", children: [loading ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "people-empty-hint", children: "加载中…" }, void 0, false) : items.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "people-empty-hint", children: "暂无新朋友申请" }, void 0, false) : null, items.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { person: item.peer }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: item.peer && item.peer.display_name || item.applicant_id }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: item.message || '请求添加您为好友' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: new Date(item.created_at).toLocaleString() }, void 0, false)] }, void 0, true), item.status === 'pending' && item.direction === 'inbound' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => handle(item, false), children: "拒绝" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "primary", onClick: () => handle(item, true), children: "通过验证" }, void 0, false)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("em", { children: requestStatusLabel(item) }, void 0, false)] }, item.request_id, true))] }, void 0, true)] }, void 0, true); } function seedProfile(item) { if (!item || !item.user_id) return; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('profile-seed:' + item.user_id, { ...item, capabilities: { can_add_friend: !!item.can_add } }); } function AddFriend({ result = false, onToast, onOpenScanner }) { const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [searching, setSearching] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [searched, setSearched] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(result); const [results, setResults] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const runSearch = q => { if (!q.trim()) { setSearched(false); setResults([]); return; } setSearching(true); setSearched(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.searchUsers)(q.trim(), 'exact_account').then(data => setResults(data.items || [])).catch(() => setResults([])).finally(() => setSearching(false)); }; const shareCard = () => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.createMyQRCode)().then(data => { const text = `加我为好友:${data.qr_payload}`; if (navigator.share) { navigator.share({ title: '添加好友', text }).catch(() => {}); } else if (navigator.clipboard) { navigator.clipboard.writeText(text); } }).catch(() => {}); }; const actionLabel = item => item.relationship === 'friend' ? '已是好友' : item.relationship === 'pending_outbound' ? '已申请' : item.relationship === 'pending_inbound' ? '待通过' : '添加'; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "添加好友", back: "address-book" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Search, { value: query, onChange: v => { setQuery(v); if (!v.trim()) { setSearched(false); setResults([]); } }, placeholder: "查找账号", onSubmit: () => runSearch(query) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { children: searched ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "people-search-result", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h2", { children: "查找人" }, void 0, false), searching ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "people-empty-hint", children: "搜索中…" }, void 0, false) : results.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "people-empty-hint", children: "未找到相关用户" }, void 0, false) : results.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => { seedProfile(item); item.relationship === 'friend' ? navigate('friend-profile', item.user_id) : navigate('group-member-profile', item.user_id); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { person: item }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: item.display_name }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("em", { className: item.relationship === 'none' ? 'people-add-cta' : '', children: actionLabel(item) }, void 0, false)] }, item.user_id, true))] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "people-add-actions", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('my-friend-qr'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "qr_code" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: "我的二维码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "让朋友扫一扫添加我" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => onOpenScanner ? onOpenScanner() : onToast('暂不支持扫码,请使用账号搜索添加好友'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "qr_code_scanner" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: "扫一扫" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "扫描好友或群二维码" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: shareCard, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "share" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: "分享给好友" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "分享链接给好友,一起来玩吧" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true)] }, void 0, true) }, void 0, false)] }, void 0, true); } function QrPage({ onToast }) { const [payload, setPayload] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [profile, setProfile] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.createMyQRCode)().then(data => { setPayload(data.qr_payload); setProfile(data.display_profile); }).catch(() => onToast('二维码生成失败')); }, []); const share = () => { if (navigator.share && payload) { navigator.share({ title: '添加好友', text: payload }).then(() => onToast('二维码名片已分享')).catch(() => {}); } else if (navigator.clipboard && payload) { navigator.clipboard.writeText(payload); onToast('链接已复制'); } }; const save = () => { const canvas = document.querySelector('.people-qrcode canvas'); if (!canvas) { onToast('二维码尚未生成'); return; } const a = document.createElement('a'); a.href = canvas.toDataURL('image/png'); a.download = '我的二维码.png'; a.click(); onToast('二维码已保存到相册'); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-page people-qr-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "我的二维码", back: "add-friend" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(QrCard, { payload: payload, profile: profile, loading: !payload }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-qr-actions", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: share, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "share" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "分享好友" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: save, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "download" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "保存到相册" }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true)] }, void 0, true); } function Verification({ uid, onToast }) { const [profile, setProfile] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => uid ? (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('profile-seed:' + uid) : null); const [message, setMessage] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [sending, setSending] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [sent, setSent] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!uid) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getUserProfile)(uid).then(data => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('profile-seed:' + uid, data); setProfile(data); }).catch(() => {}); }, [uid]); const alreadyPending = profile && (profile.relationship === 'pending_outbound' || profile.relationship === 'pending_inbound'); const alreadyFriend = profile && profile.relationship === 'friend'; const send = () => { setSending(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.createFriendRequest)(uid, message.trim(), 'search').then(() => { onToast('好友申请已发送'); setSent(true); (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('profile-seed:' + uid, { ...((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('profile-seed:' + uid) || {}), relationship: 'pending_outbound' }); window.setTimeout(() => navigate('group-member-profile', uid), 800); }).catch(err => onToast(err.message || '发送失败')).finally(() => setSending(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "好友验证", back: "group-member-profile", backUid: uid }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "people-verify", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { person: profile }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h2", { children: profile && profile.display_name || '' }, void 0, false), alreadyFriend ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "people-empty-hint", children: "你们已经是好友了" }, void 0, false) : alreadyPending || sent ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "people-empty-hint", children: "好友申请正在等待验证" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "验证留言" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("textarea", { value: message, maxLength: "50", placeholder: "我是祈万事安好", onChange: event => setMessage(event.target.value) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: [message.length, "/50"] }, void 0, true)] }, void 0, true), alreadyFriend || alreadyPending || sent ? null : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-verify-actions", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-member-profile', uid), children: "取消" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "people-primary", disabled: sending, onClick: send, children: sending ? '发送中…' : '发送' }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true); } function Profile({ uid, friend, onTopicSelected, onToast }) { const [profile, setProfile] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => uid ? (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('profile-seed:' + uid) : null); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!uid) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getUserProfile)(uid).then(data => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('profile-seed:' + uid, data); setProfile(data); }).catch(() => { setProfile(current => { if (!current) { onToast('资料加载失败'); setLoadError(true); } return current; }); }); }, [uid]); if (!profile) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "个人资料", back: friend ? 'address-book' : 'chat-standard' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "people-profile", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "people-empty-hint", children: loadError ? '资料加载失败,请重试' : '加载中…' }, void 0, false) }, void 0, false)] }, void 0, true); const canAdd = profile.capabilities && profile.capabilities.can_add_friend; const isFriend = profile.relationship === 'friend'; const cannotAddReason = profile.relationship === 'blocked_by_peer' ? '对方已将你拉黑,无法添加为好友' : profile.relationship === 'blocked_by_me' ? '你已拉黑对方,需先取消拉黑才能添加为好友' : profile.relationship === 'pending_inbound' ? '对方已向你发送好友申请,请前往"新朋友"处理' : '好友申请正在等待验证'; const openChat = () => onTopicSelected(uid); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "个人资料", back: friend ? 'address-book' : 'chat-standard', right: isFriend ? '设置' : null, onRight: () => navigate('friend-settings', uid) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "people-profile", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { person: profile }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h2", { children: profile.display_name }, void 0, false), profile.public_account ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: ["用户名:", profile.public_account] }, void 0, true) : null, profile.region ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: ["地区:", profile.region] }, void 0, true) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "qr_code" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("dl", { children: [profile.gender ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("dt", { children: "性别" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("dd", { children: profile.gender }, void 0, false)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("dt", { children: "个性签名" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("dd", { className: profile.signature ? '' : 'muted', children: profile.signature || '此人很懒什么都没留下~' }, void 0, false)] }, void 0, true)] }, void 0, true), isFriend ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-profile-actions", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "people-primary", onClick: openChat, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chat_bubble_outline" }, void 0, false), "发消息"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: openChat, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "call" }, void 0, false), "音视频通话"] }, void 0, true)] }, void 0, true) : canAdd ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "people-primary", onClick: () => navigate('friend-verification', uid), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "person_add_alt" }, void 0, false), "添加好友"] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "people-empty-hint", children: cannotAddReason }, void 0, false)] }, void 0, true)] }, void 0, true); } function Toggle({ checked, onChange }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", role: "switch", "aria-checked": checked, className: 'people-switch' + (checked ? ' checked' : ''), onClick: () => onChange(!checked), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", {}, void 0, false) }, void 0, false); } function Settings({ uid, initialBlocked, onToast }) { const [profile, setProfile] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => uid ? (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('profile-seed:' + uid) : null); const [blocked, setBlocked] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(initialBlocked); const [pinned, setPinned] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [muted, setMuted] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [editingRemark, setEditingRemark] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [remark, setRemark] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [remarkDraft, setRemarkDraft] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!uid) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getUserProfile)(uid).then(p => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('profile-seed:' + uid, p); setProfile(p); setBlocked(p.relationship === 'blocked_by_me'); }).catch(() => {}); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getFriends)().then(data => { const entry = (data.items || []).find(item => item.user_id === uid); if (entry) setRemark(entry.remark || ''); }).catch(() => {}); }, [uid]); const saveRemark = () => { const value = remarkDraft.trim(); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.updateFriendRemark)(uid, value).then(() => { setRemark(value); setEditingRemark(false); onToast('备注已更新'); }).catch(err => onToast(err.message || '备注更新失败')); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "聊天设置", back: "friend-profile", backUid: uid }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "people-settings", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "people-settings-profile", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { person: profile }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: profile && profile.display_name || '' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].addUrlParam(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].setUrlSidePanel(window.location.hash, 'history-search'), 'topic', uid)), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "查看聊天记录" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "消息传输方式" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "已启动加密传输" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "置顶聊天" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Toggle, { checked: pinned, onChange: setPinned }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "消息免打扰" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Toggle, { checked: muted, onChange: setMuted }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('clear-chat-confirm', uid), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "清空聊天记录" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), editingRemark ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-remark-edit", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("input", { value: remarkDraft, maxLength: "20", onChange: e => setRemarkDraft(e.target.value), autoFocus: true }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: saveRemark, children: "保存" }, void 0, false)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => { setRemarkDraft(remark); setEditingRemark(true); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "备注" }, void 0, false), remark ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: remark }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: blocked ? '取消拉黑' : '拉黑' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Toggle, { checked: !!blocked, onChange: value => { if (value) { navigate('block-confirm', uid); return; } (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.unblockUser)(uid).then(() => { setBlocked(false); onToast('已移出黑名单'); }).catch(err => onToast(err.message || '操作失败')); } }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => { let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].setUrlSidePanel(window.location.hash, 'abuse-report-reasons'); hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].addUrlParam(hash, 'target_type', 'user'); hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].addUrlParam(hash, 'target_id', uid); hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].addUrlParam(hash, 'target_name', profile && profile.display_name || uid); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].navigateTo(hash); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "投诉与举报" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true)] }, void 0, true), blocked ? null : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "people-danger", onClick: () => navigate('friend-delete-confirm', uid), children: "删除好友" }, void 0, false)] }, void 0, true)] }, void 0, true); } function BlockList({ onToast }) { const [people, setPeople] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(true); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getBlocks)().then(data => setPeople(data.items || [])).catch(() => {}).finally(() => setLoading(false)); }, []); const remove = userId => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.unblockUser)(userId).then(() => { setPeople(items => items.filter(item => item.user_id !== userId)); onToast('已移出黑名单'); }).catch(err => onToast(err.message || '操作失败')); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "黑名单", back: "android-settings" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "people-block-list", children: loading ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "people-empty-hint", children: "加载中…" }, void 0, false) : people.length ? people.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { person: item.user }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: item.user && item.user.display_name || item.user_id }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "已阻止消息和通话" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => remove(item.user_id), children: "移出" }, void 0, false)] }, item.user_id, true)) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-empty", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "person_off" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: "黑名单为空" }, void 0, false)] }, void 0, true) }, void 0, false)] }, void 0, true); } function ConfirmSheet({ type, uid, tinode, onToast }) { const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const config = { delete: { title: '删除好友', text: '删除后将解除好友关系,对方将无法继续向你发送消息。聊天记录仍会保留。', action: '确认删除', route: 'address-book', toast: '好友已删除', keepUid: false }, block: { title: '黑名单', text: '拉黑后将不会收到对方的消息,可在"设置"—"黑名单"查看人员名单', action: '确定', route: 'friend-settings-blocked', toast: '已加入黑名单', keepUid: true }, clear: { title: '清除聊天记录', text: '清空后不可找回,确定要清空当前会话的历史记录吗?', action: '确定', route: 'friend-settings', toast: '聊天记录已清除', keepUid: true } }[type]; const confirm = () => { setBusy(true); let call; if (type === 'delete') call = (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.deleteFriend)(uid);else if (type === 'block') call = (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.blockUser)(uid);else { const topic = tinode ? tinode.getTopic(uid) : null; call = topic ? topic.delMessagesAll(false) : Promise.resolve(); } call.then(() => { onToast(config.toast); navigate(config.route, config.keepUid ? uid : undefined); }).catch(err => onToast(err.message || '操作失败')).finally(() => setBusy(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Settings, { uid: uid, initialBlocked: type === 'block', onToast: onToast }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "people-sheet-backdrop", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "people-confirm-sheet", role: "dialog", "aria-modal": "true", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h2", { children: config.title }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: config.text }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "danger", disabled: busy, onClick: confirm, children: config.action }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('friend-settings', uid), children: "取消" }, void 0, false)] }, void 0, true) }, void 0, false)] }, void 0, true); } function ContactManagementView({ view, hashParams, myUserId, tinode, onTopicSelected, onOpenScanner }) { const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const uid = hashParams && hashParams.uid; let content; if (view === 'address-book') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(AddressBook, { myUserId: myUserId, onTopicSelected: onTopicSelected }, void 0, false);else if (view === 'friend-requests') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(FriendRequests, { onToast: setToast }, void 0, false);else if (view === 'add-friend' || view === 'friend-search-result') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(AddFriend, { result: view === 'friend-search-result', onToast: setToast, onOpenScanner: onOpenScanner }, void 0, false);else if (view === 'my-friend-qr') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(QrPage, { onToast: setToast }, void 0, false);else if (view === 'friend-verification') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Verification, { uid: uid, onToast: setToast }, void 0, false);else if (view === 'friend-profile' || view === 'group-member-profile') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Profile, { uid: uid, friend: view === 'friend-profile', onTopicSelected: onTopicSelected, onToast: setToast }, void 0, false);else if (view === 'friend-settings' || view === 'friend-settings-blocked') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Settings, { uid: uid, initialBlocked: view === 'friend-settings-blocked', onToast: setToast }, void 0, false);else if (view === 'block-list') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(BlockList, { onToast: setToast }, void 0, false);else if (view === 'friend-delete-confirm') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(ConfirmSheet, { type: "delete", uid: uid, tinode: tinode, onToast: setToast }, void 0, false);else if (view === 'block-confirm') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(ConfirmSheet, { type: "block", uid: uid, tinode: tinode, onToast: setToast }, void 0, false);else content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(ConfirmSheet, { type: "clear", uid: uid, tinode: tinode, onToast: setToast }, void 0, false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.Fragment, { children: [content, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } /***/ }), /***/ "./src/views/contacts-view.jsx": /*!*************************************!*\ !*** ./src/views/contacts-view.jsx ***! \*************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ ContactsView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ archived_contacts_title: { id: "archived_contacts", defaultMessage: "Archived contacts ({count})", description: "Label for archived chats" } }); class ContactsView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.handleAction = this.handleAction.bind(this); this.state = ContactsView.deriveStateFromProps(props); } static deriveStateFromProps(props) { const contacts = []; let unreadThreads = 0; let archivedCount = 0; const me = props.tinode.getMeTopic(); props.chatList.forEach(c => { const blocked = c.acs && !c.acs.isJoiner(); c.pinned = me.pinnedTopicRank(c.topic); if (blocked && props.blocked) { contacts.push(c); } if (blocked || props.blocked) { return; } if (c.private && c.private.arch) { if (props.archive) { contacts.push(c); } else { archivedCount++; } } else if (!props.archive) { contacts.push(c); unreadThreads += c.unread > 0 ? 1 : 0; } }); contacts.sort((a, b) => { const pin = b.pinned - a.pinned; return pin != 0 ? pin : (b.touched || 0) - (a.touched || 0); }); if (archivedCount > 0) { contacts.push({ action: 'archive', title: messages.archived_contacts_title, values: { count: archivedCount } }); } return { contactList: contacts, unreadThreads: unreadThreads }; } componentDidUpdate(prevProps, prevState) { if (prevProps.chatList != this.props.chatList || prevProps.archive != this.props.archive || prevProps.blocked != this.props.blocked) { const newState = ContactsView.deriveStateFromProps(this.props); this.setState(newState); if (newState.unreadThreads != prevState.unreadThreads) { (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.updateFavicon)(newState.unreadThreads); } } } handleAction(action_ignored) { this.props.onShowArchive(); } render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "contacts_not_found", defaultMessage: "You have no chats\\n¯∖_(ツ)_/¯", description: "HTML message shown in ContactList when no contacts are found", children: no_contacts => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(_widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, connected: this.props.connected, contacts: this.state.contactList, emptyListMessage: no_contacts, topicSelected: this.props.topicSelected, myUserId: this.props.myUserId, showOnline: true, showUnread: true, onTopicSelected: this.props.onTopicSelected, showContextMenu: this.props.showContextMenu, onAction: this.handleAction }, void 0, false) }, void 0, false); } } ; /***/ }), /***/ "./src/views/content-library-view.jsx": /*!********************************************!*\ !*** ./src/views/content-library-view.jsx ***! \********************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CONTENT_LIBRARY_VIEWS: function() { return /* binding */ CONTENT_LIBRARY_VIEWS; }, /* harmony export */ "default": function() { return /* binding */ ContentLibraryView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_audio_player_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/audio-player.jsx */ "./src/widgets/audio-player.jsx"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var _lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/use-cached-data.js */ "./src/lib/use-cached-data.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const sourceNameCache = new Map(); function resolveSourceName(topic, onDone) { if (!topic) return; if (sourceNameCache.has(topic)) { onDone(sourceNameCache.get(topic)); return; } if (tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.isSelfTopicName(topic)) { sourceNameCache.set(topic, '已保存的消息'); onDone('已保存的消息'); return; } const call = topic.startsWith('grp') ? (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.getGroup)(topic).then(g => g.name) : (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.getUserProfile)(topic).then(p => p.display_name); call.then(name => { sourceNameCache.set(topic, name); onDone(name); }).catch(() => {}); } const navigate = (view, params) => { let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].setUrlSidePanel(window.location.hash, view); Object.entries(params || {}).forEach(([key, value]) => { hash = value ? _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].addUrlParam(hash, key, value) : _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].removeUrlParam(hash, key); }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].navigateTo(hash); }; const CONTENT_LIBRARY_VIEWS = ['favorites', 'favorites-mixed', 'favorites-files', 'favorites-text', 'favorites-voice', 'favorites-links', 'favorites-select', 'favorite-share', 'file-download', 'file-downloading', 'file-downloaded', 'history-search', 'history-files', 'history-links', 'history-images', 'history-videos']; function Icon({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("i", { className: "material-icons", "aria-hidden": "true", children: children }, void 0, false); } function Header({ title, back = 'messages-home', backParams, right, onRight }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("header", { className: "library-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", onClick: () => { if (!_lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].goBack()) navigate(back, backParams); }, "aria-label": "返回", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("h1", { children: title }, void 0, false), right ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", className: "text", onClick: onRight, children: right }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", {}, void 0, false)] }, void 0, true); } function Avatar({ item }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { className: "library-avatar", children: item && item.image ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("img", { src: item.image, alt: "" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: item && item.icon || 'person' }, void 0, false) }, void 0, false); } function Toast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 2000); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "chat-toast", role: "status", children: message }, void 0, false) : null; } function Search({ value, onChange, placeholder = '搜索' }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("label", { className: "library-search", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "search" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("input", { value: value, onChange: event => onChange(event.target.value), placeholder: placeholder }, void 0, false)] }, void 0, true); } function draftyContentOf(content) { return tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Drafty.isValid(content) ? content : null; } function firstAttachment(content) { const drafty = draftyContentOf(content); if (!drafty) return null; let found = null; tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Drafty.attachments(drafty, att => { if (!found) found = att; }); return found; } function resolveAttachmentUrl(att) { if (!att) return Promise.resolve(null); const direct = tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Drafty.getDownloadUrl(att); if (!direct) return Promise.resolve(null); if (direct.startsWith('blob:') || direct.startsWith('data:')) return Promise.resolve(direct); return (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.getFileUrl)(direct.slice(direct.lastIndexOf('/') + 1)).catch(() => null); } function attachmentFromFlat(item) { if (item && (item.ent || item.fmt || item.txt !== undefined)) { return firstAttachment({ txt: item.txt, fmt: item.fmt, ent: item.ent }); } return null; } function plainTextOf(content, fallbackText) { if (typeof content === 'string') return content; const drafty = draftyContentOf(content); if (drafty) return tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Drafty.toPlainText(drafty); return fallbackText || ''; } const FILE_TYPE_META = { image: ['image', '#3ba55c'], video: ['videocam', '#3b82c4'], audio: ['audiotrack', '#8b5cf6'], document: ['description', '#e05d44'], file: ['insert_drive_file', '#8a8f98'] }; function extFromName(name) { const m = /\.([a-zA-Z0-9]+)$/.exec(name || ''); return m ? m[1].toUpperCase() : ''; } function FileCard({ name, size, mime, sender, removed, onOpen }) { const ext = extFromName(name); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", className: 'library-file-card' + (removed ? ' removed' : ''), onClick: removed ? undefined : onOpen, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { children: ext || (mime || '').split('/')[0].toUpperCase() || '?' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("strong", { children: name || '未命名文件' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("small", { children: [typeof size === 'number' ? (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__.bytesToHumanSize)(size) : size || '未知大小', sender ? ` · ${sender}` : ''] }, void 0, true)] }, void 0, true), removed ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("em", { children: "文件已失效" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true); } function VoiceCard({ att, head }) { const [src, setSrc] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { resolveAttachmentUrl(att).then(setSrc); }, [att]); const duration = att && att.duration || head && head.duration || 0; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-voice-card", children: src ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(_widgets_audio_player_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { short: true, src: src, duration: duration, preview: att && att.preview }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "hourglass_empty" }, void 0, false) }, void 0, false); } function LinkText({ url, onOpen }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", className: "library-link-text", onClick: () => onOpen && onOpen(url), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "link" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { children: url }, void 0, false)] }, void 0, true); } function MediaThumb({ url, video, duration, onOpen }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", className: "library-media-thumb", onClick: onOpen, children: [url ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("img", { src: url, alt: video ? '视频缩略图' : '图片缩略图' }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: video ? 'videocam' : 'image' }, void 0, false), video ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "play_circle" }, void 0, false), duration ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("small", { children: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__.secondsToTime)(duration) }, void 0, false) : null] }, void 0, true) : null] }, void 0, true); } function FavoriteItem({ item, onOpen, selecting, selected, onSelect }) { const att = firstAttachment(item.snapshot && item.snapshot.content); const source = item.source_display || item.source && item.source.topic || ''; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("article", { className: 'library-favorite-item' + (selecting ? ' selecting' : ''), children: [selecting ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", className: 'library-check' + (selected ? ' checked' : ''), onClick: onSelect, "aria-label": "选择收藏", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: selected ? 'check' : '' }, void 0, false) }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-favorite-content", children: [item.type === 'text' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("p", { className: "library-text-content", children: plainTextOf(item.snapshot && item.snapshot.content, item.snapshot && item.snapshot.text) }, void 0, false) : null, item.type === 'file' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(FileCard, { name: att && att.name, size: att && tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Drafty.getEntitySize(att), mime: att && att.mime, onOpen: onOpen }, void 0, false) : null, item.type === 'voice' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(VoiceCard, { att: att, head: item.snapshot && item.snapshot.head }, void 0, false) : null, item.type === 'link' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(LinkText, { url: item.snapshot && item.snapshot.content && item.snapshot.content.url || plainTextOf(item.snapshot && item.snapshot.content, item.snapshot && item.snapshot.text), onOpen: onOpen }, void 0, false) : null, item.type === 'image' || item.type === 'video' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(MediaThumb, { url: item._thumbUrl, video: item.type === 'video', onOpen: onOpen }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("footer", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { children: ["来自 ", source] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("time", { children: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__.shortDateFormat)(new Date(item.collected_at)) }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true); } const TYPE_ROUTE = { all: 'favorites-mixed', file: 'favorites-files', text: 'favorites-text', voice: 'favorites-voice', link: 'favorites-links' }; const TYPE_LABELS = [['all', '全部'], ['image', '图片'], ['video', '视频'], ['file', '文件'], ['voice', '语音'], ['text', '文本'], ['link', '链接']]; function Favorites({ view, tinode, onToast }) { const initialType = view === 'favorites-files' ? 'file' : view === 'favorites-text' ? 'text' : view === 'favorites-voice' ? 'voice' : view === 'favorites-links' ? 'link' : 'all'; const selecting = view === 'favorites-select'; const [type, setType] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(selecting ? 'file' : initialType); const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [selected, setSelected] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [items, setItems] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_6__.readCachedData)('favorites:' + type) || null); const [cursor, setCursor] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [hasMore, setHasMore] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [fileUrls, setFileUrls] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({}); const [sourceNames, setSourceNames] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({}); const load = react__WEBPACK_IMPORTED_MODULE_0___default().useCallback(append => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.getFavorites)({ type, query, cursor: append ? cursor : '' }).then(data => { setItems(prev => { const list = append ? (prev || []).concat(data.items || []) : data.items || []; if (!query) (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_6__.writeCachedData)('favorites:' + type, list); return list; }); setCursor(data.next_cursor || ''); setHasMore(!!data.next_cursor); }).catch(err => onToast(err.message || '加载失败')); }, [type, query, cursor]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { setItems(!query && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_6__.readCachedData)('favorites:' + type) || null); load(false); }, [type, query]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (items || []).forEach(item => { if (item.type !== 'image' && item.type !== 'video' || fileUrls[item.favorite_id]) return; const att = firstAttachment(item.snapshot && item.snapshot.content); resolveAttachmentUrl(att).then(url => { if (url) setFileUrls(v => ({ ...v, [item.favorite_id]: url })); }); }); }, [items]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (items || []).forEach(item => { const topic = item.source && item.source.topic; if (!topic || sourceNames[topic]) return; resolveSourceName(topic, name => name && setSourceNames(v => ({ ...v, [topic]: name }))); }); }, [items]); const toggle = id => setSelected(values => values.includes(id) ? values.filter(v => v !== id) : values.concat(id)); const deleteSelected = () => { if (!window.confirm(`确定删除已选择的 ${selected.length} 项收藏吗?`)) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.batchDeleteFavorites)(selected).then(result => { const okIds = new Set((result && result.items || []).filter(r => r.ok).map(r => r.favorite_id)); setItems(values => { const next = values.filter(item => !okIds.has(item.favorite_id)); if (!query) (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_6__.writeCachedData)('favorites:' + type, next); return next; }); setSelected(values => values.filter(id => !okIds.has(id))); onToast(okIds.size === selected.length ? '已删除所选收藏' : `已删除 ${okIds.size}/${selected.length} 项,部分删除失败`); }).catch(err => onToast(err.message || '删除失败')); }; const openItem = item => { if (item.type === 'file') { navigate('file-download', { favoriteId: item.favorite_id }); return; } if (item.type === 'link') { const url = item.snapshot && item.snapshot.content && item.snapshot.content.url || plainTextOf(item.snapshot && item.snapshot.content, item.snapshot && item.snapshot.text); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.checkURL)(url, 'favorite').then(res => { if (res.decision === 'allow') window.open(url, '_blank', 'noopener,noreferrer');else onToast(res.decision === 'block' ? '该链接存在风险,已被拦截' : '该链接可能存在风险,请谨慎访问'); }).catch(() => onToast('链接安全校验失败')); return; } onToast('暂不支持预览此类收藏'); }; const list = items || []; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Header, { title: selecting ? `已选择 ${selected.length} 项` : '我的收藏', back: selecting ? 'favorites-files' : 'messages-home', right: selecting ? '取消' : '多选', onRight: () => navigate(selecting ? 'favorites-files' : 'favorites-select') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Search, { value: query, onChange: setQuery, placeholder: "搜索收藏内容" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("nav", { className: "library-type-tabs", children: TYPE_LABELS.map(([id, label]) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", className: type === id ? 'active' : '', onClick: () => { setType(id); if (TYPE_ROUTE[id] && !selecting) navigate(TYPE_ROUTE[id]); }, children: label }, id, false)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("main", { className: "library-favorite-list", children: items === null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("p", { className: "library-empty-hint", children: "加载中…" }, void 0, false) : list.length ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.Fragment, { children: [list.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(FavoriteItem, { item: { ...item, _thumbUrl: fileUrls[item.favorite_id], source_display: sourceNames[item.source && item.source.topic] }, selecting: selecting, selected: selected.includes(item.favorite_id), onSelect: () => toggle(item.favorite_id), onOpen: () => openItem(item) }, item.favorite_id, false)), hasMore ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", className: "library-load-more", onClick: () => load(true), children: "加载更多" }, void 0, false) : null] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-empty", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "bookmark_border" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("strong", { children: "暂无此类收藏" }, void 0, false)] }, void 0, true) }, void 0, false), selecting ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("nav", { className: "library-batch-bar", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", disabled: !selected.length, onClick: () => navigate('favorite-share', { ids: selected.join(',') }), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "share" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { children: "转发" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", disabled: !selected.length, onClick: deleteSelected, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "delete_outline" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { children: "删除" }, void 0, false)] }, void 0, true)] }, void 0, true) : null] }, void 0, true); } function FavoriteShare({ hashParams, myUserId, chatList, onToast }) { const ids = (hashParams && hashParams.ids ? hashParams.ids.split(',') : []).filter(Boolean); const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [selected, setSelected] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [confirming, setConfirming] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [comment, setComment] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [sending, setSending] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [preview, setPreview] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (ids[0]) (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.getFavorite)(ids[0]).then(setPreview).catch(() => {}); }, []); const toggle = id => setSelected(values => values.includes(id) ? values.filter(v => v !== id) : values.concat(id).slice(0, 9)); const send = () => { if (sending) return; setSending(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.forwardFavorites)(ids, selected, comment.trim()).then(result => { const items = result && result.items || []; const failedCount = items.filter(r => r.status !== 'sent').length; onToast(failedCount ? `${selected.length - failedCount}/${selected.length} 个会话分享成功` : `已分享给 ${selected.length} 个会话`); window.setTimeout(() => navigate('favorites-files'), 700); }).catch(err => onToast(err.message || '分享失败')).finally(() => setSending(false)); }; const previewAtt = preview && firstAttachment(preview.snapshot && preview.snapshot.content); const contacts = (chatList || []).filter(c => c.acs && c.acs.isJoiner() && c.acs.isWriter() && (!query || (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__.topicDisplayName)(c.name, c.public, c.name || '').toLowerCase().includes(query.toLowerCase()))); const nameOf = uid => { const t = contacts.find(c => c.name === uid); return t && (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__.topicDisplayName)(t.name, t.public, uid) || uid; }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Header, { title: "分享", back: "favorites-select" }, void 0, false), !confirming ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Search, { value: query, onChange: setQuery, placeholder: "搜索联系人或群聊" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("p", { className: "library-section-title", children: "最近聊天" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("main", { className: "library-target-list", children: contacts.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", onClick: () => toggle(item.name), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Avatar, { item: {} }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("strong", { children: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__.topicDisplayName)(item.name, item.public, item.name) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("i", { className: 'library-check' + (selected.includes(item.name) ? ' checked' : ''), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: selected.includes(item.name) ? 'check' : '' }, void 0, false) }, void 0, false)] }, item.name, true)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("footer", { className: "library-next-bar", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { children: ["已选择 ", selected.length, "/9"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", disabled: !selected.length, onClick: () => setConfirming(true), children: "确定" }, void 0, false)] }, void 0, true)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("main", { className: "library-share-confirm", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("h2", { children: "发送给" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-target-summary", children: selected.map(uid => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Avatar, { item: {} }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("small", { children: nameOf(uid) }, void 0, false)] }, uid, true)) }, void 0, false), preview ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("section", { children: [previewAtt ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(FileCard, { name: previewAtt.name, size: tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Drafty.getEntitySize(previewAtt), onOpen: () => {} }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("p", { className: "library-text-content", children: plainTextOf(preview.snapshot && preview.snapshot.content, preview.snapshot && preview.snapshot.text) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("p", { children: "收藏原件会继续保留,并在目标会话中生成一条新消息。" }, void 0, false)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("textarea", { value: comment, onChange: event => setComment(event.target.value), placeholder: "给朋友留言" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", disabled: sending, onClick: send, children: "发送" }, void 0, false)] }, void 0, true)] }, void 0, true); } function DownloadPage({ hashParams, tinode, onToast }) { const [meta, setMeta] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [state, setState] = react__WEBPACK_IMPORTED_MODULE_0___default().useState('ready'); const [progress, setProgress] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(0); const downloaderRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); const { favoriteId, topic, seq } = hashParams || {}; const backView = favoriteId ? 'favorites-files' : 'history-files'; const backParams = favoriteId ? undefined : { topic }; react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { const apply = content => { const att = firstAttachment(content); if (!att) { onToast('文件信息加载失败'); setLoadError(true); return; } setMeta({ name: att.name, mime: att.mime, size: tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Drafty.getEntitySize(att), url: tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Drafty.getDownloadUrl(att) }); }; if (favoriteId) { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.getFavorite)(favoriteId).then(fav => apply(fav.snapshot && fav.snapshot.content)).catch(err => { onToast(err.message || '加载失败'); setLoadError(true); }); } else if (topic && seq) { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.getMessageContext)(topic, seq, 0, 0).then(data => { const item = (data.items || []).find(m => String(m.seq) === String(seq)) || data.items[0]; apply(item && item.content); }).catch(err => { onToast(err.message || '加载失败'); setLoadError(true); }); } }, [hashParams]); const start = () => { if (!meta || !tinode) return; if (meta.url && (meta.url.startsWith('blob:') || meta.url.startsWith('data:'))) { const link = document.createElement('a'); link.href = meta.url; link.download = meta.name || 'file'; document.body.appendChild(link); link.click(); document.body.removeChild(link); setState('done'); return; } const downloader = (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.createFileDownloader)(tinode); if (!downloader) { onToast('当前环境不支持下载'); return; } downloaderRef.current = downloader; setState('loading'); setProgress(0); const result = downloader.download(meta.url, meta.name, meta.mime, loaded => setProgress(meta.size ? Math.min(100, Math.round(loaded / meta.size * 100)) : 0), err => { setState('ready'); onToast(err && err.message || '下载失败'); }); if (result && result.then) { result.then(() => setState('done')).catch(() => {}); } }; const cancel = () => { if (downloaderRef.current) downloaderRef.current.cancel(); setState('ready'); setProgress(0); }; if (!meta) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Header, { title: "文件", back: backView, backParams: backParams }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("main", { className: "library-download", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("p", { className: "library-empty-hint", children: loadError ? '文件不存在或已被删除' : '加载中…' }, void 0, false) }, void 0, false)] }, void 0, true); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Header, { title: "文件", back: backView, backParams: backParams }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("main", { className: "library-download", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { className: "library-download-icon", children: extFromName(meta.name) || '?' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("h2", { children: meta.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("p", { children: "该文件不支持在线预览" }, void 0, false), state === 'loading' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("section", { className: "library-download-progress", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { children: "下载中..." }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("strong", { children: [progress, "%"] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("progress", { value: progress, max: "100" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("small", { children: [(0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__.bytesToHumanSize)(meta.size * progress / 100), " / ", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__.bytesToHumanSize)(meta.size)] }, void 0, true)] }, void 0, true) : null, state === 'ready' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", className: "library-primary", onClick: start, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "download" }, void 0, false), "立即下载(", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__.bytesToHumanSize)(meta.size), ")"] }, void 0, true) : state === 'loading' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-download-actions", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", onClick: cancel, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "close" }, void 0, false), "取消"] }, void 0, true) }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-download-actions", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", className: "primary", onClick: () => onToast('已保存,可在浏览器下载列表中查看'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "open_in_new" }, void 0, false), "用其他应用打开"] }, void 0, true) }, void 0, false)] }, void 0, true)] }, void 0, true); } function Highlight({ text, ranges }) { if (!ranges || !ranges.length) return text; const parts = []; let last = 0; ranges.forEach(([start, len], i) => { parts.push(text.slice(last, start), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("mark", { children: text.slice(start, start + len) }, i, false)); last = start + len; }); parts.push(text.slice(last)); return parts; } function HistoryNav({ active }) { const tabs = [['history-search', '聊天记录'], ['history-images', '图片'], ['history-videos', '视频'], ['history-files', '文件'], ['history-links', '链接']]; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("nav", { className: "library-history-tabs", children: tabs.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", className: active === item[0] ? 'active' : '', onClick: () => navigate(item[0]), children: item[1] }, item[0], false)) }, void 0, false); } const HISTORY_TITLES = { 'history-search': '查找聊天记录', 'history-files': '文件', 'history-links': '链接', 'history-images': '图片', 'history-videos': '视频' }; const HISTORY_TYPE = { 'history-search': 'all', 'history-files': 'file', 'history-links': 'link', 'history-images': 'image', 'history-videos': 'video' }; const TYPE_LABEL = { image: '[图片]', video: '[视频]', voice: '[语音]', file: '[文件]', link: '[链接]' }; function History({ view, hashParams, myUserId, onToast }) { const topic = hashParams && hashParams.topic; const cacheKey = topic ? `history:${topic}:${view}` : null; const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [items, setItems] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => cacheKey && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_6__.readCachedData)(cacheKey) || null); const [cursor, setCursor] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [hasMore, setHasMore] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [mediaUrls, setMediaUrls] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({}); const [senderNames, setSenderNames] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({}); const load = react__WEBPACK_IMPORTED_MODULE_0___default().useCallback(append => { if (!topic) return; const type = HISTORY_TYPE[view]; const call = view === 'history-search' ? (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.searchTopicMessages)(topic, { query, type, cursor: append ? cursor : '' }) : (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.getTopicMedia)(topic, type, append ? cursor : ''); call.then(data => { setItems(prev => { const list = append ? (prev || []).concat(data.items || []) : data.items || []; if (!query && cacheKey) (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_6__.writeCachedData)(cacheKey, list); return list; }); setCursor(data.next_cursor || ''); setHasMore(!!data.next_cursor); }).catch(err => onToast(err.message || '加载失败')); }, [topic, view, query, cursor]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { setItems(!query && cacheKey && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_6__.readCachedData)(cacheKey) || null); load(false); }, [topic, view, query]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (view !== 'history-images' && view !== 'history-videos') return; (items || []).forEach(item => { if (mediaUrls[item.seq]) return; resolveAttachmentUrl(attachmentFromFlat(item)).then(url => { if (url) setMediaUrls(v => ({ ...v, [item.seq]: url })); }); }); }, [items, view]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (items || []).forEach(item => { const from = item.from; if (!from || senderNames[from] || from === myUserId || 'usr' + from === myUserId) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.getUserProfile)(from.startsWith('usr') ? from : 'usr' + from).then(p => { setSenderNames(v => ({ ...v, [from]: p.display_name })); }).catch(() => {}); }); }, [items]); const jump = seq => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].addUrlParam(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].setUrlTopic('', topic), 'jumpseq', seq)); const nameOf = from => { if (!from) return ''; if (from === myUserId || 'usr' + from === myUserId) return '我'; return senderNames[from] || from; }; const openLink = url => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_5__.checkURL)(url, 'message').then(res => { if (res.decision === 'allow') window.open(url, '_blank', 'noopener,noreferrer');else onToast(res.decision === 'block' ? '该链接存在风险,已被拦截' : '该链接可能存在风险,请谨慎访问'); }).catch(() => onToast('链接安全校验失败')); }; const list = items || []; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Header, { title: HISTORY_TITLES[view], back: topic && topic.startsWith('grp') ? 'group-settings' : 'friend-settings', backParams: topic && topic.startsWith('grp') ? { topic } : { uid: topic } }, void 0, false), view === 'history-search' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Search, { value: query, onChange: setQuery, placeholder: "搜索当前会话" }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(HistoryNav, { active: view }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("main", { className: "library-history-content", children: [items === null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("p", { className: "library-empty-hint", children: "加载中…" }, void 0, false) : !list.length ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-empty", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: view === 'history-search' ? 'search_off' : 'inbox' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("strong", { children: "暂无内容" }, void 0, false)] }, void 0, true) : view === 'history-search' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("section", { className: "library-message-results", children: list.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", onClick: () => jump(item.seq), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Avatar, { item: {} }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("strong", { children: nameOf(item.from) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("p", { children: item.type === 'text' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Highlight, { text: item.snippet || '', ranges: item.matches }, void 0, false) : TYPE_LABEL[item.type] || item.snippet || '' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("small", { children: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__.shortDateFormat)(new Date(item.ts)) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, item.seq, true)) }, void 0, false) : view === 'history-files' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("section", { className: "library-record-files", children: list.map(item => { const att = attachmentFromFlat(item); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-record-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("strong", { children: nameOf(item.from) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("small", { children: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__.shortDateFormat)(new Date(item.ts)) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(FileCard, { name: att ? att.name : item.name, size: att ? tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Drafty.getEntitySize(att) : item.size, mime: att && att.mime, removed: item.availability === 'removed', onOpen: () => navigate('file-download', { topic, seq: item.seq }) }, void 0, false)] }, item.seq, true); }) }, void 0, false) : view === 'history-links' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("section", { className: "library-record-links", children: list.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "library-record-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("strong", { children: nameOf(item.from) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("small", { children: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__.shortDateFormat)(new Date(item.ts)) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(LinkText, { url: item.url || plainTextOf(item.txt !== undefined ? { txt: item.txt, fmt: item.fmt, ent: item.ent } : undefined, item.text), onOpen: openLink }, void 0, false)] }, item.seq, true)) }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("section", { className: "library-media-grid", children: list.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(MediaThumb, { url: mediaUrls[item.seq], video: view === 'history-videos', duration: item.duration, onOpen: () => jump(item.seq) }, item.seq, false)) }, void 0, false), hasMore ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("button", { type: "button", className: "library-load-more", onClick: () => load(true), children: "加载更多" }, void 0, false) : null] }, void 0, true)] }, void 0, true); } function ContentLibraryView({ view, hashParams, tinode, myUserId, onTopicSelected, chatList }) { const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); let content; if (view.startsWith('favorites')) content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Favorites, { view: view, tinode: tinode, onToast: setToast }, void 0, false);else if (view === 'favorite-share') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(FavoriteShare, { hashParams: hashParams, myUserId: myUserId, chatList: chatList, onToast: setToast }, void 0, false);else if (view.startsWith('file-download')) content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(DownloadPage, { hashParams: hashParams, tinode: tinode, onToast: setToast }, void 0, false);else content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(History, { view: view, hashParams: hashParams, myUserId: myUserId, onToast: setToast }, void 0, false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.Fragment, { children: [content, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } /***/ }), /***/ "./src/views/direct-message-view.jsx": /*!*******************************************!*\ !*** ./src/views/direct-message-view.jsx ***! \*******************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ DirectMessageView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const navigate = view => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__["default"].navigateTo(view); const VIEW_CONFIG = { 'chat-inbound-request': { relationship: 'pending_inbound', variant: 'inbound-request' }, 'chat-inbound-message': { relationship: 'pending_inbound', variant: 'inbound-message' }, 'chat-outbound-request': { relationship: 'pending_outbound', variant: 'outbound-request' }, 'chat-status': { relationship: 'friend', variant: 'status' }, 'chat-friend': { relationship: 'friend', variant: 'friend' }, 'chat-media': { relationship: 'friend', variant: 'media' }, 'chat-blocked': { relationship: 'blocked_by_peer', variant: 'blocked' }, 'chat-deleted': { relationship: 'none', variant: 'deleted' }, 'chat-standard': { relationship: 'friend', variant: 'standard' }, 'chat-attachments': { relationship: 'friend', variant: 'attachments' }, 'chat-mixed': { relationship: 'friend', variant: 'mixed' }, 'chat-contact-card': { relationship: 'friend', variant: 'contact-card' } }; const ATTACHMENTS = [{ id: 'photo', icon: 'image', label: '照片' }, { id: 'camera', icon: 'photo_camera', label: '拍摄' }, { id: 'call', icon: 'call', label: '视频语音' }, { id: 'card', icon: 'contact_page', label: '名片' }, { id: 'file', icon: 'folder', label: '文件' }, { id: 'favorite', icon: 'bookmark', label: '收藏' }, { id: 'video', icon: 'videocam', label: '视频通话' }]; function Icon({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons", "aria-hidden": "true", children: children }, void 0, false); } function Toast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 2200); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-toast", role: "status", children: message }, void 0, false) : null; } function ChatAvatar({ mine = false, peer = false }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-avatar", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { src: mine ? 'img/bkg/p05.jpg' : peer ? 'img/bkg/p09.jpg' : 'img/bkg/p14.jpg', alt: "" }, void 0, false) }, void 0, false); } function Status({ value, failedReason }) { if (!value && !failedReason) return null; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: 'chat-message-status' + (failedReason ? ' failed' : ''), children: [failedReason ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "error" }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: failedReason || value }, void 0, false)] }, void 0, true); } function FileCard() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-file-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: "365天艾宾浩斯记忆曲线复习计划.pdf" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: "115KB" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: "chat-file-icon", children: "P" }, void 0, false)] }, void 0, true); } function ContactCard({ onOpen }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "chat-contact-card", onClick: onOpen, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { src: "img/bkg/p15.jpg", alt: "" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: "栗子来了" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: "个人名片 · 账号 QL1024" }, void 0, false)] }, void 0, true); } function VoiceMessage({ duration = 6, playing = false }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-voice-message", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: playing ? 'graphic_eq' : 'volume_up' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: [duration, "″"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", {}, void 0, false)] }, void 0, true); } function ImageMessage({ progress }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-image-message", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { src: "img/bkg/p22.jpg", alt: "会话图片" }, void 0, false), progress < 100 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-upload-progress", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("progress", { value: progress, max: "100" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: [progress, "%"] }, void 0, true)] }, void 0, true) : null] }, void 0, true); } function Bubble({ mine = false, children, status, failedReason, type = 'text', onOpenCard }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: 'chat-message-row' + (mine ? ' mine' : ''), children: [!mine ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(ChatAvatar, { peer: true }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-message-stack", children: [type === 'file' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(FileCard, {}, void 0, false) : type === 'card' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(ContactCard, { onOpen: onOpenCard }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: 'chat-bubble ' + type + (mine ? ' mine' : ''), children: children }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Status, { value: status, failedReason: failedReason }, void 0, false)] }, void 0, true), mine ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(ChatAvatar, { mine: true }, void 0, false) : null] }, void 0, true); } function RelationNotice({ children, action, onAction }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-relation-notice", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: children }, void 0, false), action ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: onAction, children: action }, void 0, false) : null] }, void 0, true); } function ChatTimeline({ variant, uploadProgress, sendStatus, onRetry, onOpenCard, onFriendAction }) { if (variant === 'inbound-request' || variant === 'inbound-message') { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "7月30日 11:40" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { children: variant === 'inbound-request' ? '请求添加你为好友' : '我是祈万事安好' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(RelationNotice, { children: "以上是打招呼的消息" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-request-actions", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => onFriendAction('declined'), children: "拒绝" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "primary", onClick: () => onFriendAction('accepted'), children: "通过申请" }, void 0, false)] }, void 0, true)] }, void 0, true); } if (variant === 'outbound-request') { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "7月30日 11:40" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "已发送", children: "请求添加你为好友" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(RelationNotice, { children: "好友申请已发送,等待对方处理" }, void 0, false)] }, void 0, true); } if (variant === 'status') { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "7月30日 11:40" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: sendStatus, children: "我是祈万事安好" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(RelationNotice, { children: "你已添加安妮,现在可以开始聊天。" }, void 0, false)] }, void 0, true); } if (variant === 'friend') { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "8月27日 11:11" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(RelationNotice, { children: "你们已成为好友,现在可以开始聊天" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { children: "我们已成为好友,现在我们可以开始聊天" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "已读", children: "你还好吗?" }, void 0, false)] }, void 0, true); } if (variant === 'media') { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "8月27日 11:11" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(RelationNotice, { children: "接雨彤创建群聊" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "已读", children: "你还好吗?" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, type: "image", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(ImageMessage, { progress: uploadProgress }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, type: "voice", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(VoiceMessage, { duration: 6, playing: true }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { type: "voice", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(VoiceMessage, { duration: 6 }, void 0, false) }, void 0, false)] }, void 0, true); } if (variant === 'blocked') { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "7月30日 11:40" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "已读", children: "请求添加你为好友" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(RelationNotice, { children: "你已添加了安妮,现在可以开始聊天。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "7月30日 13:00" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "已读", children: "这边在网上看见你的留言,你想了解什么课程了" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { children: "有课程辅导的老师?对新手友好吗?" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, failedReason: "消息已发送,但被对方拒收了", children: "这个不用担心特别好上手,学起来特别简单" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, failedReason: "消息已发送,但被对方拒收了", children: "拉黑我这么速度,真的牛" }, void 0, false)] }, void 0, true); } if (variant === 'deleted') { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "7月30日 13:00" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "已读", children: "你好我是XXX推荐过来的,这边想了解课程是吗" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { children: "这边目前找到更好的课程,不考虑你们家,谢谢" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "已读", children: "这是我们导师名片,你可以加一下,对比一下价格" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(RelationNotice, { action: "发送朋友验证", onAction: () => onFriendAction('resent'), children: "你还不是他(她)朋友。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, failedReason: "发送失败,需重新添加好友", children: "这么突然把我删了,真心累了" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(RelationNotice, { action: "发送朋友验证", onAction: () => onFriendAction('resent'), children: "你还不是他(她)朋友。" }, void 0, false)] }, void 0, true); } const base = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "7月30日 11:40" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "已读", children: "请求添加你为好友" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(RelationNotice, { children: "你已添加了安妮,现在可以开始聊天。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "7月30日 13:00" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "已读", children: "你好,我是王珊珊,很高兴认识你,你怎么称呼" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { children: "你好,我是安妮,想跟你咨询一下设计课程,方便?" }, void 0, false)] }, void 0, true); if (variant === 'standard') { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [base, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "未读", children: "非常方便,这是我们的课程目录,你可以看看了解一下" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, type: "file", status: "未读" }, void 0, false)] }, void 0, true); } if (variant === 'mixed') { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [base, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, type: "file", status: "已送达" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { type: "card", onOpenCard: onOpenCard }, void 0, false)] }, void 0, true); } if (variant === 'contact-card') { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [base, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "已读", children: "这是我们导师名片,你可以加一下,有问题随时联系他" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, type: "card", status: "已送达", onOpenCard: onOpenCard }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { children: "好的,非常感谢,那我这边就直接联系他吧" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: "已读", children: "没问题的,有疑问随时沟通" }, void 0, false)] }, void 0, true); } return base; } function AttachmentPanel({ onChoose }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-attachment-panel", children: ATTACHMENTS.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => onChoose(item), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: item.icon }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: item.label }, void 0, false)] }, item.id, true)) }, void 0, false); } function Composer({ relationship, attachmentOpen, setAttachmentOpen, onSend }) { const [draft, setDraft] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(sessionStorage.getItem('im-chat-draft') || ''); const canSend = relationship === 'friend'; const updateDraft = value => { setDraft(value); sessionStorage.setItem('im-chat-draft', value); }; const submit = e => { e.preventDefault(); if (!canSend || !draft.trim()) return; onSend(draft.trim()); updateDraft(''); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("form", { className: 'chat-composer' + (!canSend ? ' locked' : ''), onSubmit: submit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", "aria-label": "语音", disabled: !canSend, onClick: () => navigate('voice-ready'), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "record_voice_over" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { value: draft, onChange: e => updateDraft(e.target.value), placeholder: canSend ? '输入消息' : relationship === 'pending_inbound' ? '请先处理好友申请' : relationship === 'pending_outbound' ? '等待对方通过好友申请' : '当前无法发送消息', disabled: !canSend }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", "aria-label": "表情", disabled: !canSend, onClick: () => navigate('emoji-panel'), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "sentiment_satisfied_alt" }, void 0, false) }, void 0, false), draft.trim() ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "submit", className: "chat-send-button", children: "发送" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", "aria-label": "更多", disabled: !canSend, onClick: () => setAttachmentOpen(!attachmentOpen), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: attachmentOpen ? 'keyboard' : 'add_circle_outline' }, void 0, false) }, void 0, false)] }, void 0, true); } function DirectMessageView({ view }) { const config = VIEW_CONFIG[view] || VIEW_CONFIG['chat-standard']; const [relationship, setRelationship] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(config.relationship); const [variant, setVariant] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(config.variant); const [attachmentOpen, setAttachmentOpen] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(config.variant === 'attachments'); const [uploadProgress, setUploadProgress] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(config.variant === 'media' ? 76 : 100); const [sendStatus, setSendStatus] = react__WEBPACK_IMPORTED_MODULE_0___default().useState('发送中'); const [extraMessages, setExtraMessages] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (variant !== 'status') return undefined; const stages = ['已发送', '已送达', '已读']; const timers = stages.map((status, index) => window.setTimeout(() => setSendStatus(status), 600 * (index + 1))); return () => timers.forEach(timer => window.clearTimeout(timer)); }, [variant]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (variant !== 'media' || uploadProgress >= 100) return undefined; const timer = window.setTimeout(() => setUploadProgress(value => Math.min(value + 4, 100)), 350); return () => window.clearTimeout(timer); }, [variant, uploadProgress]); const friendAction = action => { if (action === 'declined') { setRelationship('none'); setToast('已拒绝好友申请'); } else { setRelationship(action === 'accepted' ? 'friend' : 'pending_outbound'); if (action === 'accepted') setVariant('friend'); setToast(action === 'accepted' ? '好友申请已通过' : '好友验证已发送'); } }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-product-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("header", { className: "chat-product-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('messages-home'), "aria-label": "返回消息", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("h1", { children: "接语彤" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", {}, void 0, false), "在线"] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('friend-settings'), "aria-label": "会话设置", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "more_vert" }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("main", { className: "chat-product-timeline", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(ChatTimeline, { variant: variant, uploadProgress: uploadProgress, sendStatus: sendStatus, onRetry: () => setToast('正在重试发送'), onOpenCard: () => navigate('friend-profile'), onFriendAction: friendAction }, void 0, false), extraMessages.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Bubble, { mine: true, status: item.status, children: item.text }, item.id, false))] }, void 0, true), relationship === 'friend' ? null : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-permission-banner", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "info_outline" }, void 0, false), relationship === 'pending_inbound' ? '通过好友申请后即可发送消息' : relationship === 'pending_outbound' ? '好友申请正在等待处理' : relationship === 'none' ? '对方已不是你的好友,发送消息前需重新验证' : '当前关系状态下无法发送消息'] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Composer, { relationship: relationship, attachmentOpen: attachmentOpen, setAttachmentOpen: setAttachmentOpen, onSend: text => { const id = Date.now(); setExtraMessages(items => items.concat({ id, text, status: '发送中' })); window.setTimeout(() => setExtraMessages(items => items.map(item => item.id === id ? { ...item, status: '已发送' } : item)), 600); } }, void 0, false), attachmentOpen && relationship === 'friend' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(AttachmentPanel, { onChoose: item => { setToast(`已选择${item.label},上传接口将在联调阶段接入`); if (item.id === 'card') navigate('chat-contact-card'); if (item.id === 'photo' || item.id === 'camera') navigate('media-uploading'); if (item.id === 'call' || item.id === 'video') navigate('call-history'); if (item.id === 'file') navigate('upload-file'); if (item.id === 'favorite') navigate('favorites'); } }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } /***/ }), /***/ "./src/views/group-management-view.jsx": /*!*********************************************!*\ !*** ./src/views/group-management-view.jsx ***! \*********************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ GROUP_MANAGEMENT_VIEWS: function() { return /* binding */ GROUP_MANAGEMENT_VIEWS; }, /* harmony export */ "default": function() { return /* binding */ GroupManagementView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var qrcodejs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! qrcodejs */ "qrcodejs"); /* harmony import */ var qrcodejs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(qrcodejs__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var pinyin_pro__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! pinyin-pro */ "./node_modules/pinyin-pro/dist/esm/core/pinyin/index.mjs"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var _lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/use-cached-data.js */ "./src/lib/use-cached-data.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const navigate = (view, topic) => { let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].setUrlSidePanel(window.location.hash, view); hash = topic ? _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].addUrlParam(hash, 'topic', topic) : _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].removeUrlParam(hash, 'topic'); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].navigateTo(hash); }; const navigateToProfile = userId => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].addUrlParam(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].setUrlSidePanel(window.location.hash, 'group-member-profile'), 'uid', userId)); const GROUP_MANAGEMENT_VIEWS = ['group-list', 'group-empty', 'group-invite', 'group-events', 'group-join-requests', 'group-new-request', 'group-announcement', 'group-summary', 'group-announcement-detail', 'group-settings', 'group-profile', 'group-avatar', 'group-nickname', 'group-description', 'group-my-nickname', 'group-role-message', 'group-qr', 'group-governance', 'group-admins', 'group-admin-add', 'group-admin-success', 'group-admin-partial', 'group-admin-removed', 'group-mute-add', 'group-muted', 'group-owner-select', 'group-owner-confirm', 'group-files', 'group-file-upload']; function alphaInitial(name) { const ch = (name || '').trim()[0] || '#'; if (/[A-Za-z]/.test(ch)) { return ch.toUpperCase(); } if (/[一-龥]/.test(ch)) { const letter = (0,pinyin_pro__WEBPACK_IMPORTED_MODULE_2__.pinyin)(ch, { pattern: 'first', toneType: 'none' }); return /[a-z]/i.test(letter) ? letter.toUpperCase() : '#'; } return '#'; } function groupBy(list, keyFn) { const groups = {}; list.forEach(item => { const key = keyFn(item); (groups[key] || (groups[key] = [])).push(item); }); return Object.keys(groups).sort().map(key => [key, groups[key]]); } function shortDate(iso) { if (!iso) return ''; const d = new Date(iso); return `${d.getMonth() + 1}-${String(d.getDate()).padStart(2, '0')}`; } const MEMBERS = [{ id: 'annie', name: '安妮', role: '管理员', avatar: 'img/bkg/p09.jpg' }, { id: 'lizi', name: '栗子来了', role: '成员', avatar: 'img/bkg/p15.jpg' }, { id: 'wang', name: '王珊珊', role: '成员', avatar: 'img/bkg/p14.jpg' }, { id: 'sun', name: '孙光洪', role: '成员', avatar: 'img/bkg/p03.jpg' }, { id: 'lin', name: '林间风', role: '成员', avatar: 'img/bkg/p18.jpg' }]; const GROUPS_DEMO = { owned: [{ id: 'product', name: '产品研发群', count: 18, avatar: 'img/bkg/p22.jpg' }] }; function Icon({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", { className: "material-icons", "aria-hidden": "true", children: children }, void 0, false); } function Header({ title, back = 'group-list', backTopic, right, onRight }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("header", { className: "group-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => { if (!_lib_navigation_js__WEBPACK_IMPORTED_MODULE_3__["default"].goBack()) navigate(back, backTopic); }, "aria-label": "返回", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h1", { children: title }, void 0, false), right ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "text", onClick: onRight, children: right }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", {}, void 0, false)] }, void 0, true); } function Avatar({ item, icon }) { const fileId = item && item.avatar_file_id; const [url, setUrl] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!fileId) { setUrl(null); return undefined; } let live = true; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getFileUrl)(fileId).then(u => { if (live) setUrl(u); }).catch(() => {}); return () => { live = false; }; }, [fileId]); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { className: "group-avatar", children: url ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("img", { src: url, alt: "" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: icon || 'group' }, void 0, false) }, void 0, false); } function Toast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 2000); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "chat-toast", role: "status", children: message }, void 0, false) : null; } function CenterToast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 1400); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-toast-center", role: "status", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "check_circle" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: message }, void 0, false)] }, void 0, true) : null; } function Search({ value, onChange, placeholder = '搜索' }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("label", { className: "group-search", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "search" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("input", { value: value, onChange: event => onChange(event.target.value), placeholder: placeholder }, void 0, false)] }, void 0, true); } function Toggle({ checked, onChange, disabled }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", role: "switch", "aria-checked": checked, disabled: disabled, className: 'group-switch' + (checked ? ' checked' : ''), onClick: () => !disabled && onChange(!checked), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", {}, void 0, false) }, void 0, false); } function GroupList({ onToast }) { const [lists, setLists] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('groups') || { owned: null, managed: null, joined: null }); const [loadErrors, setLoadErrors] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({ owned: false, managed: false, joined: false }); const [category, setCategory] = react__WEBPACK_IMPORTED_MODULE_0___default().useState('owned'); const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [creating, setCreating] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [name, setName] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [submitting, setSubmitting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const reload = react__WEBPACK_IMPORTED_MODULE_0___default().useCallback(() => { ['owned', 'managed', 'joined'].forEach(cat => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroups)({ category: cat, query }).then(data => { const items = data.items || []; setLists(v => { const next = { ...v, [cat]: items }; if (!query) (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('groups', next); return next; }); }).catch(() => { onToast('加载失败'); setLoadErrors(v => ({ ...v, [cat]: true })); }); }); }, [query]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { reload(); }, [reload]); const current = lists[category]; const submit = () => { if (!name.trim() || submitting) return; setSubmitting(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.createGroup)({ name: name.trim() }).then(() => { setCreating(false); setName(''); onToast('群聊创建成功'); reload(); }).catch(err => onToast(err.message || '创建失败')).finally(() => setSubmitting(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群聊", back: "address-book", right: "创建", onRight: () => setCreating(true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Search, { value: query, onChange: setQuery, placeholder: "搜索群聊" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("nav", { className: "group-tabs", children: [['owned', '我创建的'], ['managed', '我管理的'], ['joined', '我加入的']].map(([key, label]) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: category === key ? 'active' : '', onClick: () => setCategory(key), children: [label, "(", (lists[key] || []).length, ")"] }, key, true)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-list", children: current === null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-empty", children: loadErrors[category] ? '群列表加载失败' : '加载中…' }, void 0, false) : current.length ? current.map(group => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-settings', group.topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: group }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: group.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: [group.member_count, " 位成员"] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, group.topic, true)) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-empty", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "groups" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: "这里还没有群聊" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: category === 'owned' ? '创建一个群聊,邀请成员一起沟通' : '加入或被设置为管理员后会显示在这里' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => setCreating(true), children: "创建群聊" }, void 0, false)] }, void 0, true) }, void 0, false), creating ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-modal-backdrop", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "group-modal", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h2", { children: "创建群聊" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("label", { children: ["群名称", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("input", { autoFocus: true, value: name, maxLength: "30", onChange: event => setName(event.target.value), placeholder: "输入群名称" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: "创建后可继续邀请成员和设置群资料。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("footer", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => setCreating(false), children: "取消" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "primary", disabled: !name.trim() || submitting, onClick: submit, children: "创建" }, void 0, false)] }, void 0, true)] }, void 0, true) }, void 0, false) : null] }, void 0, true); } function ChatHeader() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("header", { className: "group-chat-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-list'), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h1", { children: "产品研发群" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "18人" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-settings'), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "more_vert" }, void 0, false) }, void 0, false)] }, void 0, true); } function SystemEvent({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-system-event", children: children }, void 0, false); } function GroupChat({ mode, onToast }) { const [joined, setJoined] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(ChatHeader, {}, void 0, false), ['group-new-request', 'group-summary'].includes(mode) ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "group-top-notice", onClick: () => navigate('group-join-requests'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "person_add_alt" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: "新的进群申请" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "2 条申请等待处理" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true) : null, ['group-announcement', 'group-summary'].includes(mode) ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "group-top-notice announcement", onClick: () => navigate('group-announcement-detail'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "campaign" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: "群公告" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "下午三点进行版本评审,请准时参加" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-chat-timeline", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "chat-time", children: "今天 10:24" }, void 0, false), mode === 'group-invite' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", { className: "group-invite-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: GROUPS_DEMO.owned[0] }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: "产品研发群" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "安妮邀请你加入群聊" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: "一起参与新版产品的设计与研发讨论" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", disabled: joined, onClick: () => { setJoined(true); onToast('已加入产品研发群'); }, children: joined ? '已加入' : '立即加入' }, void 0, false)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(SystemEvent, { children: "安妮邀请栗子来了加入群聊" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(SystemEvent, { children: "管理员通过了王珊珊的进群申请" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-chat-message", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: MEMBERS[0] }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: ["安妮 ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("em", { children: "管理员" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: "下午评审前请大家把问题同步到文档里。" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-chat-message owner", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: { ...MEMBERS[3], avatar: 'img/bkg/p05.jpg' } }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: ["陈晨 ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("em", { children: "群主" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: "收到,我会在两点前整理一版。" }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-chat-composer", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "record_voice_over" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("input", { placeholder: "输入消息" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "sentiment_satisfied_alt" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "add_circle_outline" }, void 0, false) }, void 0, false)] }, void 0, true)] }, void 0, true); } function JoinRequests({ topic, onToast }) { const [items, setItems] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-join-requests:' + topic) || null); const [profiles, setProfiles] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({}); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const fetchedIds = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(new Set()); const load = react__WEBPACK_IMPORTED_MODULE_0___default().useCallback(() => { if (!topic) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupJoinRequests)(topic, 'all').then(data => { const list = data.items || []; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-join-requests:' + topic, list); setItems(list); const ids = new Set(); list.forEach(r => { ids.add(r.user_id); if (r.inviter_id) ids.add(r.inviter_id); }); ids.forEach(id => { if (fetchedIds.current.has(id)) return; fetchedIds.current.add(id); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getUserProfile)(id).then(p => setProfiles(v => ({ ...v, [id]: p }))).catch(() => { fetchedIds.current.delete(id); }); }); }).catch(() => { onToast('加载失败'); setLoadError(true); }); }, [topic]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { setItems(topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-join-requests:' + topic) || null); load(); }, [topic, load]); const handle = (req, accept) => { const call = accept ? (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.acceptGroupJoinRequest)(topic, req.request_id, req.version) : (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.rejectGroupJoinRequest)(topic, req.request_id, req.version); call.then(() => { onToast(accept ? '已同意进群申请' : '已拒绝进群申请'); load(); }).catch(err => onToast(err.message || '操作失败')); }; const nameOf = id => profiles[id] && profiles[id].display_name || id; const describe = req => req.source === 'qr' ? `${nameOf(req.user_id)}通过二维码分享进群` : req.inviter_id ? `${nameOf(req.inviter_id)}邀请${nameOf(req.user_id)}进群` : `${nameOf(req.user_id)}申请加入群聊`; const statusLabel = { accepted: '已确定', approved: '已确定', rejected: '已拒绝', expired: '已过期' }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "邀请进群申请", back: "group-settings", backTopic: topic }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-request-list", children: items === null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-empty", children: loadError ? '申请列表加载失败' : '加载中…' }, void 0, false) : items.length ? items.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: profiles[item.user_id] || {} }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: describe(item) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: shortDate(item.created_at) }, void 0, false)] }, void 0, true), item.status === 'pending' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => handle(item, false), children: "拒绝" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "primary", onClick: () => handle(item, true), children: "确定" }, void 0, false)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("em", { children: statusLabel[item.status] || item.status }, void 0, false)] }, item.request_id, true)) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-inline-empty", children: "暂无进群申请" }, void 0, false) }, void 0, false)] }, void 0, true); } function Announcement({ topic, myRole, fromChat, onToast }) { const cachedAnnouncement = topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-announcement:' + topic); const [data, setData] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => cachedAnnouncement || null); const [draft, setDraft] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => cachedAnnouncement && cachedAnnouncement.content || ''); const [editing, setEditing] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [saving, setSaving] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const canEdit = myRole === 'owner' || myRole === 'admin'; const backView = fromChat ? '' : 'group-settings'; react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!topic) return; const cached = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-announcement:' + topic); if (cached) { setData(cached); setDraft(cached.content || ''); } (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getLatestGroupAnnouncement)(topic).then(d => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-announcement:' + topic, d); setData(d); setDraft(d.content || ''); }).catch(() => { onToast('加载失败'); setLoadError(true); }); }, [topic]); const publish = () => { if (!draft.trim() || saving) return; setSaving(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.updateCurrentGroupAnnouncement)(topic, draft.trim(), data ? data.version : 0).then(d => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-announcement:' + topic, d); setData(d); setEditing(false); onToast('群公告已发布'); }).catch(err => onToast(err.message || '发布失败')).finally(() => setSaving(false)); }; if (!data) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群公告", back: backView, backTopic: topic }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-announcement-detail", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-empty", children: loadError ? '群公告加载失败' : '加载中…' }, void 0, false) }, void 0, false)] }, void 0, true); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群公告", back: backView, backTopic: topic, right: canEdit ? '发布' : null, onRight: canEdit ? publish : undefined }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-announcement-detail", children: [canEdit ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("textarea", { autoFocus: editing, value: draft, maxLength: 2000, onChange: e => setDraft(e.target.value), onFocus: () => setEditing(true), placeholder: "请输入群公告内容" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "campaign" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: data.content || '暂无群公告' }, void 0, false)] }, void 0, true), !canEdit ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { className: "group-inline-hint", children: "仅群主及群管理员可编辑" }, void 0, false) : null] }, void 0, true)] }, void 0, true); } function GroupSettings({ topic, myUserId, tinode, onToast }) { const [group, setGroup] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-settings:' + topic) || null); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [members, setMembers] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => { const cached = topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-members:' + topic); return cached ? cached.slice(0, 9) : []; }); const [announcement, setAnnouncement] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => { const cached = topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-announcement:' + topic); return cached && cached.content ? cached : null; }); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!topic) return; setGroup((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-settings:' + topic) || null); setMembers(((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-members:' + topic) || []).slice(0, 9)); const cachedAnn = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-announcement:' + topic); setAnnouncement(cachedAnn && cachedAnn.content ? cachedAnn : null); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupSettings)(topic).then(g => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-settings:' + topic, g); setGroup(g); }).catch(() => { onToast('加载失败'); setLoadError(true); }); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupMembers)(topic).then(data => { const items = data.items || []; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-members:' + topic, items); setMembers(items.slice(0, 9)); }).catch(() => {}); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getLatestGroupAnnouncement)(topic).then(d => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-announcement:' + topic, d); setAnnouncement(d && d.content ? d : null); }).catch(() => {}); }, [topic]); const setPref = patch => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.updateGroupMemberSettings)(topic, { pinned: group.pinned, mute_notifications: group.mute_notifications, ...patch }).then(() => setGroup(g => { const next = { ...g, ...patch }; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-settings:' + topic, next); return next; })).catch(err => onToast(err.message || '设置失败')); }; const leave = () => { if (group && group.my_role === 'owner') { onToast('群主需先转让群主或解散群聊'); return; } (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.leaveGroup)(topic).then(() => { onToast('已退出群聊'); navigate('group-list'); }).catch(err => onToast(err.message || '操作失败')); }; if (!group) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群聊设置", back: "group-list" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-settings", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-empty", children: loadError ? '群组信息加载失败' : '加载中…' }, void 0, false) }, void 0, false)] }, void 0, true); const canManage = group.permissions && group.permissions.can_manage_settings; const links = [['group-profile', '群资料', group.name], ['group-announcement-detail', '群公告', announcement ? announcement.content : '暂无群公告'], ['group-files', '群文件', ''], ['group-my-nickname', '我在本群的昵称', '']]; if (canManage) links.splice(3, 0, ['group-governance', '群组管理', '']); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群聊设置", back: "group-list", right: canManage ? '管理' : null, onRight: canManage ? () => navigate('group-governance', topic) : undefined }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-settings", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "group-settings-header", onClick: () => navigate('group-profile', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: group }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: group.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: group.description || '群主很懒,还没有群简介' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "group-member-strip", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: members.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigateToProfile(item.user_id), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: item }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: item.group_nickname || item.display_name }, void 0, false)] }, item.user_id, true)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", "aria-label": "邀请成员", onClick: () => onToast('请通过转发/分享群二维码邀请成员'), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "person_add_alt" }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-hint", children: ["共 ", group.member_count, " 位成员"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { children: links.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate(item[0], topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: item[1] }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: item[2] }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, item[0], true)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "置顶聊天" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Toggle, { checked: !!group.pinned, onChange: v => setPref({ pinned: v }) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "消息免打扰" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Toggle, { checked: !!group.mute_notifications, onChange: v => setPref({ mute_notifications: v }) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('history-search', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "查看聊天记录" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => { const t = tinode ? tinode.getTopic(topic) : null; (t ? t.delMessagesAll(false) : Promise.resolve()).then(() => onToast('聊天记录已清除')).catch(err => onToast(err.message || '操作失败')); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "清空聊天记录" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => onToast('举报入口暂未开放'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "投诉/举报" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "group-danger", onClick: leave, children: "退出群组" }, void 0, false)] }, void 0, true)] }, void 0, true); } function GroupProfile({ topic, myUserId, onToast }) { const [group, setGroup] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group:' + topic) || null); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [myNickname, setMyNickname] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!topic) return; setGroup((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group:' + topic) || null); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroup)(topic).then(g => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group:' + topic, g); setGroup(g); }).catch(() => { onToast('加载失败'); setLoadError(true); }); }, [topic]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!topic) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getMyGroupProfile)(topic).then(data => { setMyNickname(data.nickname || ''); }).catch(() => {}); }, [topic]); if (!group) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群资料", back: "group-settings", backTopic: topic }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-profile", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-empty", children: loadError ? '群组信息加载失败' : '加载中…' }, void 0, false) }, void 0, false)] }, void 0, true); const canEdit = group.permissions && group.permissions.can_edit_profile; const nicknameLabel = myNickname || '未设置'; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群资料", back: "group-settings", backTopic: topic }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-profile", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "group-profile-avatar", disabled: !canEdit, onClick: () => canEdit && navigate('group-avatar', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: group }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "群头像" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-my-nickname', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "群昵称" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: nicknameLabel }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), canEdit ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-nickname', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "群名称" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: group.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "群名称" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: group.name }, void 0, false)] }, void 0, true), canEdit ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-description', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "群简介" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: group.description || '群主很懒,还没有群简介' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "群简介" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: group.description || '群主很懒,还没有群简介' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-qr', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "群二维码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "qr_code" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: [group.member_count, " 位成员"] }, void 0, true)] }, void 0, true)] }, void 0, true); } function AvatarSheet({ topic, myUserId, tinode, onToast }) { const inputRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); const [uploading, setUploading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const pick = () => inputRef.current && inputRef.current.click(); const onFile = e => { const file = e.target.files && e.target.files[0]; e.target.value = ''; if (!file || !tinode) return; setUploading(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.uploadLargeFile)(tinode, file).then(({ fileId }) => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroup)(topic).then(group => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.updateGroup)(topic, { avatar_file_id: fileId, version: group.version }))).then(() => { onToast('群头像已更新'); navigate('group-profile', topic); }).catch(err => onToast(err.message || '上传失败')).finally(() => setUploading(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupProfile, { topic: topic, onToast: onToast }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("input", { ref: inputRef, type: "file", accept: "image/*", style: { display: 'none' }, onChange: onFile }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-sheet-backdrop", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "group-source-sheet", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h2", { children: "设置群头像" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", disabled: uploading, onClick: pick, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "photo_library" }, void 0, false), uploading ? '正在上传…' : '从相册选择'] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-profile', topic), children: "取消" }, void 0, false)] }, void 0, true) }, void 0, false)] }, void 0, true); } function GroupQr({ topic, onToast }) { const ref = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); const [data, setData] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!topic) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.createGroupQRCode)(topic).then(setData).catch(() => onToast('二维码生成失败')); }, [topic]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!ref.current || !data) return; ref.current.innerHTML = ''; new (qrcodejs__WEBPACK_IMPORTED_MODULE_1___default())(ref.current, { text: data.qr_payload, width: 190, height: 190, correctLevel: (qrcodejs__WEBPACK_IMPORTED_MODULE_1___default().CorrectLevel).M }); }, [data]); const group = data && data.group_snapshot; const share = () => { if (navigator.share && data) { navigator.share({ title: group && group.name, text: '扫码加入群聊', url: data.qr_payload }).catch(() => {}); } else if (data) { navigator.clipboard.writeText(data.qr_payload).then(() => onToast('链接已复制')).catch(() => onToast('分享失败')); } }; const save = () => { const canvas = ref.current && ref.current.querySelector('canvas'); if (!canvas) { onToast('保存失败'); return; } const a = document.createElement('a'); a.href = canvas.toDataURL('image/png'); a.download = (group ? group.name : 'group') + '-qrcode.png'; a.click(); onToast('群二维码已保存'); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page group-qr-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群二维码", back: "group-profile", backTopic: topic }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "group-qr-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: group || {} }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: group ? group.name : '' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: [group ? group.member_count : 0, " 位成员"] }, void 0, true)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-qrcode", ref: ref }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: "使用APP扫码二维码,加入群聊" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-qr-actions", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: share, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "share" }, void 0, false), "分享好友"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: save, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "download" }, void 0, false), "保存至相册"] }, void 0, true)] }, void 0, true)] }, void 0, true)] }, void 0, true); } const GOVERNANCE_FIELDS = [['join_approval', '进群验证', '开启后,他人申请加入群聊需群主或管理员同意'], ['mute_all', '全体禁言', '开启后,仅群主和管理员可以发言'], ['member_upload_files', '群成员文件上传', '关闭后,普通成员将无法上传群文件'], ['member_invite', '群成员邀请', '关闭后,仅群主和管理员可以邀请新成员进群'], ['member_private_chat', '群成员私信权限', '关闭后,不允许发送名片消息,且普通成员在群聊界面、群组信息内点击头像无反应。']]; function Governance({ topic, tinode, onToast }) { const [gov, setGov] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-governance:' + topic) || null); const [dissolving, setDissolving] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!topic) return; setGov((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-governance:' + topic) || null); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupGovernance)(topic).then(d => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-governance:' + topic, d); setGov(d); }).catch(() => { onToast('加载失败'); setLoadError(true); }); }, [topic]); const setField = (key, value) => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.updateGroupGovernance)(topic, { [key]: value }).then(data => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-governance:' + topic, data); setGov(data); }).catch(err => onToast(err.message || '设置失败')); }; const dissolve = () => { if (!window.confirm('解散后群聊将无法恢复,确定要解散该群聊吗?')) return; const t = tinode ? tinode.getTopic(topic) : null; if (!t) return; setDissolving(true); t.delTopic(true).then(() => { onToast('群聊已解散'); navigate('group-list'); }).catch(err => onToast(err.message || '解散失败')).finally(() => setDissolving(false)); }; if (!gov) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群组管理", back: "group-settings", backTopic: topic }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-governance", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-empty", children: loadError ? '群组管理加载失败' : '加载中…' }, void 0, false) }, void 0, false)] }, void 0, true); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群组管理", back: "group-settings", backTopic: topic }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-governance", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-avatar', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "设置群头像" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-join-requests', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "邀请进群申请" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-muted', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "禁言的群成员" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-admins', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "设置管理员" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => navigate('group-owner-select', topic), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: "群主管理权转让" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { children: GOVERNANCE_FIELDS.map(([key, label, desc]) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: label }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: desc }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Toggle, { checked: !!gov[key], disabled: gov[key + '_editable'] === false, onChange: v => setField(key, v) }, void 0, false)] }, key, true)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "group-danger", disabled: dissolving, onClick: dissolve, children: "解散群组" }, void 0, false)] }, void 0, true)] }, void 0, true); } function deriveOwnerAndAdmins(items) { return { owner: items.find(m => m.role === 'owner') || null, admins: items.filter(m => m.role === 'admin') }; } function AdminList({ topic, onToast }) { const cachedMembers = topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-members:' + topic); const seed = cachedMembers ? deriveOwnerAndAdmins(cachedMembers) : { owner: null, admins: null }; const [owner, setOwner] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => seed.owner); const [admins, setAdmins] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => seed.admins); const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const load = react__WEBPACK_IMPORTED_MODULE_0___default().useCallback(() => { if (!topic) return; const cached = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-members:' + topic); if (cached) { const d = deriveOwnerAndAdmins(cached); setOwner(d.owner); setAdmins(d.admins); } (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupMembers)(topic).then(data => { const items = data.items || []; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-members:' + topic, items); const d = deriveOwnerAndAdmins(items); setOwner(d.owner); setAdmins(d.admins); }).catch(() => { onToast('加载失败'); setLoadError(true); }); }, [topic]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { load(); }, [load]); const remove = userId => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.deleteGroupAdmin)(topic, userId).then(() => { setToast('管理员已移除'); load(); }).catch(err => onToast(err.message || '操作失败')); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "设置群管理员", back: "group-governance", backTopic: topic, right: "添加", onRight: () => navigate('group-admin-add', topic) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-admin-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("aside", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "info_outline" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: "管理员可协助审批进群申请、管理公告和群成员。最多设置 10 名管理员。" }, void 0, false)] }, void 0, true), owner ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h2", { children: "群主" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: owner }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: owner.display_name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "群主" }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h2", { children: ["管理员 ", admins ? admins.length : 0, "/10"] }, void 0, true), admins === null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-empty", children: loadError ? '成员列表加载失败' : '加载中…' }, void 0, false) : admins.length ? admins.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: item }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: item.display_name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "管理员" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => remove(item.user_id), children: "移除" }, void 0, false)] }, item.user_id, true)) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-inline-empty", children: "暂无管理员" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(CenterToast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } function MemberPicker({ type, topic, onToast }) { const mute = type === 'mute-add'; const back = mute ? 'group-muted' : 'group-admins'; const [members, setMembers] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [selected, setSelected] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!topic) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupMembers)(topic, mute ? { muteEligible: true } : { eligibleRole: 'admin' }).then(data => setMembers((data.items || []).filter(m => m.eligible !== false))).catch(() => { onToast('加载失败'); setLoadError(true); }); }, [topic, mute]); const visible = (members || []).filter(m => (m.group_nickname || m.display_name || '').includes(query)); const groups = groupBy(visible, m => alphaInitial(m.group_nickname || m.display_name)); const toggle = id => setSelected(v => v.includes(id) ? v.filter(x => x != id) : v.concat(id)); const done = () => { if (!selected.length || busy) return; setBusy(true); const call = mute ? (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.muteGroupMembers)(topic, selected.map(user_id => ({ user_id }))) : (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.addGroupAdmins)(topic, selected); call.then(result => { const failed = result && result.succeeded ? result.succeeded.filter(s => !s.ok) : []; setToast(failed.length ? `成功设置 ${selected.length - failed.length} 人,${failed.length} 人设置失败` : '设置成功'); window.setTimeout(() => navigate(back, topic), 900); }).catch(err => onToast(err.message || '设置失败')).finally(() => setBusy(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: mute ? '添加禁言成员' : '添加管理员', back: back, backTopic: topic, right: `完成${selected.length ? `(${selected.length})` : ''}`, onRight: selected.length ? done : undefined }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Search, { value: query, onChange: setQuery, placeholder: "搜索群成员" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-member-picker", children: members === null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-empty", children: loadError ? '成员列表加载失败' : '加载中…' }, void 0, false) : groups.map(([letter, list]) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-section-title", children: letter }, void 0, false), list.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => toggle(item.user_id), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: item }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: item.group_nickname || item.display_name }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", { className: 'group-check' + (selected.includes(item.user_id) ? ' checked' : ''), children: selected.includes(item.user_id) ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "check" }, void 0, false) : null }, void 0, false)] }, item.user_id, true))] }, letter, true)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(CenterToast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } function Muted({ topic, onToast }) { const [items, setItems] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-muted:' + topic) || null); const [names, setNames] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({}); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const load = react__WEBPACK_IMPORTED_MODULE_0___default().useCallback(() => { if (!topic) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupMutes)(topic).then(data => { const list = data.items || []; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-muted:' + topic, list); setItems(list); }).catch(() => { onToast('加载失败'); setLoadError(true); }); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupMembers)(topic).then(data => { const map = {}; (data.items || []).forEach(m => { map[m.user_id] = m.group_nickname || m.display_name || m.user_id; }); setNames(map); }).catch(() => {}); }, [topic]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { setItems(topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-muted:' + topic) || null); load(); }, [topic, load]); const unmute = userId => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.unmuteGroupMember)(topic, userId).then(() => { onToast('已解除禁言'); load(); }).catch(err => onToast(err.message || '操作失败')); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "禁言的群成员", back: "group-governance", backTopic: topic, right: "添加", onRight: () => navigate('group-mute-add', topic) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-muted-list", children: items === null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-empty", children: loadError ? '成员列表加载失败' : '加载中…' }, void 0, false) : items.length ? items.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: {} }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: names[item.user_id] || item.user_id }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: item.expires_at ? `禁言至 ${shortDate(item.expires_at)}` : '永久禁言' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => unmute(item.user_id), children: "解除" }, void 0, false)] }, item.user_id, true)) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-inline-empty", children: "以上成员不允许发言" }, void 0, false) }, void 0, false)] }, void 0, true); } function OwnerSelect({ topic, onToast }) { const [members, setMembers] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [target, setTarget] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!topic) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupMembers)(topic, { eligibleRole: 'owner' }).then(data => setMembers((data.items || []).filter(m => m.eligible !== false))).catch(() => { onToast('加载失败'); setLoadError(true); }); }, [topic]); const visible = (members || []).filter(m => (m.group_nickname || m.display_name || '').includes(query)); const admins = visible.filter(m => m.role === 'admin'); const others = visible.filter(m => m.role !== 'admin'); const confirm = () => { if (busy || !target) return; setBusy(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.transferGroupOwner)(topic, target.user_id).then(() => { onToast('群主已转让'); navigate('group-governance', topic); }).catch(err => onToast(err.message || '转让失败')).finally(() => setBusy(false)); }; const row = item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", { role: "button", tabIndex: 0, onClick: () => setTarget(item), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, { item: item }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: item.group_nickname || item.display_name }, void 0, false) }, void 0, false)] }, item.user_id, true); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "选择新群主", back: "group-governance", backTopic: topic }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Search, { value: query, onChange: setQuery, placeholder: "搜索" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-request-list", children: members === null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-empty", children: loadError ? '成员列表加载失败' : '加载中…' }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.Fragment, { children: [admins.length ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-section-title", children: "管理员" }, void 0, false), admins.map(row)] }, void 0, true) : null, others.length ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-section-title", children: "群成员" }, void 0, false), others.map(row)] }, void 0, true) : null] }, void 0, true) }, void 0, false), target ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-sheet-backdrop", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", { className: "group-confirm-sheet", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("h2", { children: "选择新群主" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { children: [target.group_nickname || target.display_name, "成为新群主,确定后你将立即失去群主身份"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "danger", disabled: busy, onClick: confirm, children: "确定" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => setTarget(null), children: "取消" }, void 0, false)] }, void 0, true) }, void 0, false) : null] }, void 0, true); } const FILE_TYPE_META = { image: ['image', '#3ba55c'], video: ['videocam', '#3b82c4'], audio: ['audiotrack', '#8b5cf6'], document: ['description', '#e05d44'], file: ['insert_drive_file', '#8a8f98'] }; function GroupFiles({ topic, tinode, onToast }) { const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [files, setFiles] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group-files:' + topic) || null); const [menuOpen, setMenuOpen] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [uploading, setUploading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const inputRefs = { file: react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null), image: react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null), video: react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null) }; const load = react__WEBPACK_IMPORTED_MODULE_0___default().useCallback(() => { if (!topic) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupFiles)(topic, { query }).then(data => { const items = data.items || []; if (!query) (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-files:' + topic, items); setFiles(items); }).catch(() => { onToast('加载失败'); setLoadError(true); }); }, [topic, query]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { load(); }, [load]); const usedBytes = (files || []).reduce((sum, f) => sum + (f.file_size || 0), 0); const pick = kind => { setMenuOpen(false); inputRefs[kind].current && inputRefs[kind].current.click(); }; const onFile = e => { const file = e.target.files && e.target.files[0]; e.target.value = ''; if (!file || !tinode) return; setUploading({ name: file.name, progress: 0 }); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.uploadLargeFile)(tinode, file, frac => setUploading(u => u ? { ...u, progress: Math.round(frac * 100) } : u)).then(({ fileId }) => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.addGroupFile)(topic, { fileId, fileName: file.name, mimeType: file.type, fileSize: file.size })).then(() => { setUploading(null); load(); }).catch(err => { setUploading(null); onToast(err.message || '上传失败'); }); }; const remove = fileId => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.deleteGroupFile)(topic, fileId).then(() => load()).catch(err => onToast(err.message || '删除失败')); }; const gb = n => (n / 1024 ** 3).toFixed(2); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群文件", back: "group-settings", backTopic: topic, right: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "add" }, void 0, false), onRight: () => setMenuOpen(v => !v) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("input", { ref: inputRefs.file, type: "file", style: { display: 'none' }, onChange: onFile }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("input", { ref: inputRefs.image, type: "file", accept: "image/*", style: { display: 'none' }, onChange: onFile }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("input", { ref: inputRefs.video, type: "file", accept: "video/*", style: { display: 'none' }, onChange: onFile }, void 0, false), menuOpen ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-upload-menu", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => pick('file'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "upload_file" }, void 0, false), "上传文件"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => pick('image'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "image" }, void 0, false), "上传照片"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => pick('video'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "play_circle_outline" }, void 0, false), "上传视频"] }, void 0, true)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Search, { value: query, onChange: setQuery, placeholder: "搜索文件名或者上传者" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-hint", children: ["共", (files || []).length, "个文件(已使用", gb(usedBytes), "GB/10GB)"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-file-list", children: [uploading ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", { className: "uploading", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { className: "group-file-type", style: { backgroundColor: '#8a8f98' }, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "upload_file" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: uploading.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: ["上传中 ", uploading.progress, "%"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("progress", { value: uploading.progress, max: "100" }, void 0, false)] }, void 0, true)] }, void 0, true) : null, files === null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", { className: "group-inline-empty", children: loadError ? '文件列表加载失败' : '加载中…' }, void 0, false) : files.map(file => { const [icon, color] = FILE_TYPE_META[file.file_type] || FILE_TYPE_META.file; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { className: "group-file-type", style: { backgroundColor: color }, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: icon }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", { children: file.file_name || '未命名文件' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: [bytesToGB(file.file_size), " · ", file.uploader_id] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: () => remove(file.group_file_id), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, { children: "delete_outline" }, void 0, false) }, void 0, false)] }, file.group_file_id, true); })] }, void 0, true)] }, void 0, true); } function bytesToGB(bytes) { if (!bytes) return '0 KB'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; } function GroupNameEditor({ topic, onToast }) { const [group, setGroup] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [value, setValue] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (topic) (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroup)(topic).then(g => { setGroup(g); setValue(g.name); }).catch(() => onToast('加载失败')); }, [topic]); const save = () => { if (!value.trim()) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.updateGroup)(topic, { name: value.trim(), version: group ? group.version : 0 }).then(() => { onToast('保存成功'); window.setTimeout(() => navigate('group-profile', topic), 600); }).catch(err => onToast(err.message || '保存失败')); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群昵称", back: "group-profile", backTopic: topic, right: "完成", onRight: save }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-edit-text", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("input", { autoFocus: true, value: value, maxLength: 11, onChange: e => setValue(e.target.value) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: [value.length, "/11"] }, void 0, true)] }, void 0, true)] }, void 0, true); } function GroupDescriptionEditor({ topic, onToast }) { const [group, setGroup] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [value, setValue] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (topic) (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroup)(topic).then(g => { setGroup(g); setValue(g.description || ''); }).catch(() => onToast('加载失败')); }, [topic]); const publish = () => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.updateGroup)(topic, { description: value.trim(), version: group ? group.version : 0 }).then(() => { onToast('保存成功'); window.setTimeout(() => navigate('group-profile', topic), 600); }).catch(err => onToast(err.message || '保存失败')); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "群简介", back: "group-profile", backTopic: topic, right: "发布", onRight: publish }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-edit-text", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("textarea", { autoFocus: true, value: value, maxLength: 225, placeholder: "请输入群简介内容", onChange: e => setValue(e.target.value) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: [value.length, "/225"] }, void 0, true)] }, void 0, true)] }, void 0, true); } function MyNicknameEditor({ topic, onToast }) { const [value, setValue] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!topic) return; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getMyGroupProfile)(topic).then(data => setValue(data.nickname || '')).catch(() => {}); }, [topic]); const save = () => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.updateMyGroupProfile)(topic, value.trim(), 0).then(() => { onToast('保存成功'); window.setTimeout(() => navigate('group-settings', topic), 600); }).catch(err => onToast(err.message || '保存失败')); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "group-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, { title: "我在本群的昵称", back: "group-settings", backTopic: topic, right: "完成", onRight: save }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("main", { className: "group-edit-text", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("input", { autoFocus: true, value: value, maxLength: 32, onChange: e => setValue(e.target.value) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", { children: "群昵称仅在当前群内显示。" }, void 0, false)] }, void 0, true)] }, void 0, true); } function GroupManagementView({ view, hashParams, myUserId, tinode, onTopicSelected }) { const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const topic = hashParams && hashParams.topic; const roleCacheKey = topic && myUserId ? `group-my-role:${topic}:${myUserId}` : null; const [myRole, setMyRole] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => roleCacheKey && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)(roleCacheKey) || null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!topic || !myUserId) { setMyRole(null); return; } const key = `group-my-role:${topic}:${myUserId}`; setMyRole((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)(key) || null); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupMembers)(topic).then(data => { const items = data.items || []; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)('group-members:' + topic, items); const me = items.find(m => m.user_id === myUserId); const role = me ? me.role : null; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)(key, role); setMyRole(role); }).catch(() => {}); }, [topic, myUserId]); let content; if (view === 'group-list' || view === 'group-empty') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupList, { onToast: setToast }, void 0, false);else if (['group-invite', 'group-events', 'group-new-request', 'group-announcement', 'group-summary', 'group-role-message'].includes(view)) content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupChat, { mode: view, onToast: setToast }, void 0, false);else if (view === 'group-join-requests') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(JoinRequests, { topic: topic, onToast: setToast }, void 0, false);else if (view === 'group-announcement-detail') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Announcement, { topic: topic, myRole: myRole, fromChat: hashParams && hashParams.from === 'chat', onToast: setToast }, void 0, false);else if (view === 'group-settings') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupSettings, { topic: topic, myUserId: myUserId, tinode: tinode, onToast: setToast }, void 0, false);else if (view === 'group-profile') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupProfile, { topic: topic, myUserId: myUserId, onToast: setToast }, void 0, false);else if (view === 'group-avatar') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(AvatarSheet, { topic: topic, myUserId: myUserId, tinode: tinode, onToast: setToast }, void 0, false);else if (view === 'group-nickname') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupNameEditor, { topic: topic, onToast: setToast }, void 0, false);else if (view === 'group-description') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupDescriptionEditor, { topic: topic, onToast: setToast }, void 0, false);else if (view === 'group-my-nickname') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(MyNicknameEditor, { topic: topic, myUserId: myUserId, onToast: setToast }, void 0, false);else if (view === 'group-qr') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupQr, { topic: topic, onToast: setToast }, void 0, false);else if (view === 'group-governance') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Governance, { topic: topic, tinode: tinode, onToast: setToast }, void 0, false);else if (['group-admins', 'group-admin-success', 'group-admin-partial', 'group-admin-removed'].includes(view)) content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(AdminList, { topic: topic, onToast: setToast }, void 0, false);else if (view === 'group-admin-add') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(MemberPicker, { type: "admin-add", topic: topic, onToast: setToast }, void 0, false);else if (view === 'group-mute-add') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(MemberPicker, { type: "mute-add", topic: topic, onToast: setToast }, void 0, false);else if (view === 'group-muted') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Muted, { topic: topic, onToast: setToast }, void 0, false);else if (['group-owner-select', 'group-owner-confirm'].includes(view)) content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(OwnerSelect, { topic: topic, onToast: setToast }, void 0, false);else content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupFiles, { topic: topic, tinode: tinode, onToast: setToast }, void 0, false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.Fragment, { children: [content, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } /***/ }), /***/ "./src/views/login-view.jsx": /*!**********************************!*\ !*** ./src/views/login-view.jsx ***! \**********************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ LoginView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _widgets_visible_password_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/visible-password.jsx */ "./src/widgets/visible-password.jsx"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class LoginView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { login: props.login, password: '', hostName: props.serverAddress, saveToken: props.persist }; this.handleLoginChange = this.handleLoginChange.bind(this); this.handlePasswordChange = this.handlePasswordChange.bind(this); this.handleToggleSaveToken = this.handleToggleSaveToken.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleLoginChange(e) { this.setState({ login: e.target.value }); } handlePasswordChange(e) { this.setState({ password: e.target.value }); } handleToggleSaveToken() { this.props.onPersistenceChange(!this.state.saveToken); this.setState({ saveToken: !this.state.saveToken }); } handleSubmit(e) { e.preventDefault(); this.props.onLogin(this.state.login.trim(), this.state.password.trim()); } render() { let submitClasses = 'primary'; if (this.props.disabled) { submitClasses += ' disabled'; } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("form", { id: "login-form", onSubmit: this.handleSubmit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "login_prompt", defaultMessage: "Login", description: "Placeholer for username/login", children: login_prompt => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", { type: "text", id: "inputLogin", placeholder: login_prompt, autoComplete: "username", autoCorrect: "off", autoCapitalize: "none", value: this.state.login, onChange: this.handleLoginChange, required: true, autoFocus: true }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "password_prompt", defaultMessage: "Password", description: "Placeholder/prompt for entering password", children: password_prompt => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(_widgets_visible_password_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { type: "password", id: "inputPassword", placeholder: password_prompt, autoComplete: "current-password", value: this.state.password, onChange: this.handlePasswordChange, required: true }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { id: "save-token", name: "save-token", checked: this.state.saveToken, onChange: this.handleToggleSaveToken }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { htmlFor: "save-token", children: ["\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "stay_logged_in", defaultMessage: "Stay logged in", description: "Label for a checkbox" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("a", { href: "#reset", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "forgot_password_link", defaultMessage: "Forgot password?", description: "Link to Reset password form" }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "dialog-buttons", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { className: submitClasses, type: "submit", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_sign_in", defaultMessage: "Sign in", description: "Button [Sign In]" }, void 0, false) }, void 0, false) }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/views/message-center-view.jsx": /*!*******************************************!*\ !*** ./src/views/message-center-view.jsx ***! \*******************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ MessageCenterView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/use-cached-data.js */ "./src/lib/use-cached-data.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const navigate = view => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].setUrlSidePanel(window.location.hash, view)); function frequentContacts(chatList) { if (!chatList || chatList.length === 0) return []; return chatList.filter(item => item.topic && tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.isP2PTopicName(item.topic)).slice().sort((a, b) => new Date(b.touched || 0).getTime() - new Date(a.touched || 0).getTime()).slice(0, 8).map(item => ({ id: item.topic, name: item.public && item.public.fn || '未命名', avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__.makeImageUrl)(item.public && item.public.photo), online: !!item.online })); } const MESSAGE_ACTIONS = [{ id: 'quote', icon: 'format_quote', label: '引用' }, { id: 'copy', icon: 'content_copy', label: '复制' }, { id: 'favorite', icon: 'inventory_2', label: '收藏' }, { id: 'translate', icon: 'translate', label: '翻译' }, { id: 'forward', icon: 'reply', label: '转发' }, { id: 'recall', icon: 'undo', label: '撤回', gated: true }, { id: 'delete', icon: 'delete_outline', label: '删除', gated: true }, { id: 'select', icon: 'select_all', label: '多选' }, { id: 'group_recall', icon: 'restart_alt', label: '群撤回' }]; function Icon({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", { className: "material-icons", "aria-hidden": "true", children: children }, void 0, false); } function Toast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 2200); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "messages-toast", role: "status", children: message }, void 0, false) : null; } function Avatar({ item, small = false }) { const className = 'messages-avatar ' + (small ? 'small ' : '') + 'tone-' + (item.tone || 'blue'); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: className, children: [item.avatar ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("img", { src: item.avatar, alt: "" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: item.icon || 'person' }, void 0, false), item.online !== undefined ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { className: item.online ? 'online' : 'offline' }, void 0, false) : null] }, void 0, true); } function draftyPreview(content) { if (typeof content === 'string' || content == null) return content || ''; if (Array.isArray(content.ent) && content.ent.length) { const label = { IM: '[图片]', VD: '[视频]', AU: '[语音]', EX: '[文件]', TC: '[名片]', VC: '[通话]' }[content.ent[0].tp]; if (label) return label; } return content.txt || '[消息]'; } function formatConversationTime(ts) { if (!ts) return ''; const date = new Date(ts); const now = new Date(); const startOfDay = d => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime(); const days = Math.round((startOfDay(now) - startOfDay(date)) / 86400000); if (days === 0) return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }); if (days === 1) return '昨天'; if (days < 7) return ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][date.getDay()]; return date.toLocaleDateString('zh-CN', { month: 'numeric', day: 'numeric' }); } function entryConversations(bootstrap) { if (!bootstrap || !bootstrap.entries) return []; const list = []; const sys = bootstrap.entries.system_messages; if (sys && sys.enabled) { list.push({ id: 'system', title: '系统消息', summary: '最新公告', icon: 'notifications', tone: 'orange', system: true, unread: sys.unread_count || 0 }); } const files = bootstrap.entries.file_assistant; if (files && files.enabled) { list.push({ id: 'files', title: '文件助手', summary: '你上传1份文件', icon: 'folder', tone: 'green', fileAssistant: true, topic: files.topic, unread: files.unread_count || 0 }); } return list; } function normalizeConversations(chatList, myUserId) { if (!chatList || chatList.length === 0) return []; return chatList.map((item, index) => { const latest = typeof item.latestMessage === 'function' ? item.latestMessage() : null; let summary = item.private && item.private.comment ? item.private.comment : '暂无消息'; if (latest) summary = draftyPreview(latest.content); if (latest && latest.from === myUserId) summary = '我:' + summary; return { id: item.topic || item.user || String(index), title: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_6__.topicDisplayName)(item.topic, item.public, '未命名会话'), summary, time: formatConversationTime(item.touched), unread: Math.max(Number(item.unread) || 0, 0), online: !!item.online, muted: !!(item.acs && item.acs.isMuted && item.acs.isMuted()), pinned: !!item.pinned }; }); } function BottomNavigation() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("nav", { className: "messages-bottom-nav", "aria-label": "主导航", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", onClick: () => navigate('workbench'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "dashboard" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: "工作台" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: "active", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "person" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: "消息" }, void 0, false)] }, void 0, true)] }, void 0, true); } function QuickMenu({ onClose, onAction, permissions }) { const actions = [{ id: 'friends', icon: 'group', label: '朋友' }, { id: 'profile', icon: 'person_outline', label: '我的' }, { id: 'create-group', icon: 'add_comment', label: '创建群组', permission: 'create_group' }, { id: 'add-friend', icon: 'person_add_alt', label: '添加好友', permission: 'user_search' }, { id: 'scan', icon: 'qr_code_scanner', label: '扫一扫', permission: 'scan_qr' }].filter(item => !item.permission || !permissions || permissions[item.permission] !== false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "messages-menu-backdrop", onMouseDown: onClose, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "messages-quick-menu", onMouseDown: e => e.stopPropagation(), role: "menu", children: actions.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", role: "menuitem", onClick: () => onAction(item), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: item.icon }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: item.label }, void 0, false)] }, item.id, true)) }, void 0, false) }, void 0, false); } function MessageHome({ view, connected, chatList, myUserId, onTopicSelected, onOpenScanner }) { const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [menuOpen, setMenuOpen] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(view === 'messages-menu'); const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [bootstrap] = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.useCachedData)(myUserId ? 'bootstrap:' + myUserId : null, _lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getBootstrap, [myUserId]); const offline = view === 'messages-offline' || !!myUserId && connected === false; const conversations = entryConversations(bootstrap).concat(normalizeConversations(chatList, myUserId)); const filtered = conversations.filter(item => `${item.title}${item.summary}`.toLowerCase().includes(query.trim().toLowerCase())); const frequent = frequentContacts(chatList); const selectConversation = item => { if (item.system) { navigate('system-messages'); } else if (item.fileAssistant && item.topic && onTopicSelected) { onTopicSelected(item.topic); } else if (chatList && chatList.length && onTopicSelected) { onTopicSelected(item.id); } else { navigate('chat-standard'); } }; const runQuickAction = item => { setMenuOpen(false); if (item.id === 'friends') return navigate('address-book'); if (item.id === 'profile') return navigate('personal-center'); if (item.id === 'create-group') return navigate('group-list'); if (item.id === 'add-friend') return navigate('add-friend'); if (item.id === 'scan' && onOpenScanner) return onOpenScanner(); setToast(item.id === 'scan' ? '扫码功能暂不可用' : `${item.label}页面将在对应章节中提供`); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "messages-product-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("header", { className: "messages-home-header", children: [offline ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "messages-connection", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { className: "messages-spinner" }, void 0, false), "加载中"] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h1", { children: "消息" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: "messages-menu-button", onClick: () => setMenuOpen(true), "aria-label": "更多功能", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "menu" }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { className: "messages-home-content", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("label", { className: "messages-search", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "search" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", { value: query, onChange: e => setQuery(e.target.value), placeholder: "搜索" }, void 0, false)] }, void 0, true), frequent.length > 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { className: "messages-frequent", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h2", { children: "常联系的人" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "messages-frequent-scroll", children: frequent.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", onClick: () => onTopicSelected && onTopicSelected(item.id), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Avatar, { item: item, small: true }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: item.name }, void 0, false)] }, item.id, true)) }, void 0, false)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { className: "messages-conversations", "aria-label": "会话列表", children: [filtered.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: 'messages-conversation' + (item.pinned ? ' pinned' : ''), onClick: () => selectConversation(item), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Avatar, { item: item }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { className: "messages-conversation-copy", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("strong", { children: item.title }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: item.summary }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { className: "messages-conversation-meta", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("time", { children: item.time }, void 0, false), item.unread ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("b", { children: item.unread > 99 ? '99+' : item.unread }, void 0, false) : item.muted ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "notifications_off" }, void 0, false) : null] }, void 0, true)] }, item.id, true)), filtered.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "messages-empty", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "search_off" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { children: "未找到相关会话" }, void 0, false)] }, void 0, true) : null] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(BottomNavigation, {}, void 0, false), menuOpen ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(QuickMenu, { onClose: () => setMenuOpen(false), onAction: runQuickAction, permissions: bootstrap && bootstrap.permissions }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } function MessageActions() { const [visible, setVisible] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(true); const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [selected, setSelected] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [supportedActions, setSupportedActions] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getBootstrap)().then(data => setSupportedActions(data.message_policy && data.message_policy.supported_actions)).catch(() => {}); }, []); const actions = MESSAGE_ACTIONS.filter(item => !item.gated || !supportedActions || supportedActions.includes(item.id)); const runAction = item => { setSelected(item.id); if (item.id === 'copy' && navigator.clipboard) { navigator.clipboard.writeText('明天上午十点开项目会,请准时参加。').catch(() => {}); } setToast(`${item.label}操作已选择`); setVisible(false); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "message-actions-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("header", { className: "messages-sub-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { onClick: () => navigate('messages-home'), "aria-label": "返回", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h1", { children: "项目协作群" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {}, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { className: "message-actions-chat", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { className: "message-time", children: "今天 10:24" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "message-demo-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Avatar, { item: { avatar: 'img/bkg/p09.jpg' } }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: "message-demo-bubble", onContextMenu: e => { e.preventDefault(); setVisible(true); }, children: "明天上午十点开项目会,请准时参加。" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "message-demo-row mine", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: "message-demo-bubble mine", onContextMenu: e => { e.preventDefault(); setVisible(true); }, children: "收到,我会提前准备材料。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Avatar, { item: { avatar: 'img/bkg/p05.jpg' } }, void 0, false)] }, void 0, true), selected ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { className: "message-operation-result", children: ["已选择:", MESSAGE_ACTIONS.find(item => item.id === selected).label] }, void 0, true) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("footer", { className: "message-demo-composer", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "mic_none" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: "输入消息" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "sentiment_satisfied_alt" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "add_circle_outline" }, void 0, false)] }, void 0, true), visible ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "message-action-backdrop", onMouseDown: () => setVisible(false), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "message-action-menu", onMouseDown: e => e.stopPropagation(), role: "menu", children: actions.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", role: "menuitem", onClick: () => runAction(item), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: item.label }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: item.icon }, void 0, false)] }, item.id, true)) }, void 0, false) }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } function SystemMessages({ authenticated }) { const [items, setItems] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(true); const [error, setError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getSystemNotifications)().then(data => setItems(data.items || [])).catch(err => setError(err.message || '加载失败')).finally(() => setLoading(false)); }, []); const markRead = item => { if (item.read_at) return; setItems(list => list.map(i => i.id === item.id ? { ...i, read_at: new Date().toISOString() } : i)); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.markSystemNotificationRead)(item.id).catch(() => { setItems(list => list.map(i => i.id === item.id ? { ...i, read_at: null } : i)); }); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "system-messages-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("header", { className: "messages-sub-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { onClick: () => { if (!_lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].goBack()) navigate('messages-home'); }, "aria-label": "返回", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h1", { children: "系统消息" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {}, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { className: "system-notification-list", children: [loading ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { className: "messages-empty", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "hourglass_empty" }, void 0, false), "加载中…"] }, void 0, true) : null, error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { className: "messages-empty", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "error_outline" }, void 0, false), error] }, void 0, true) : null, !loading && !error && items.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { className: "messages-empty", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "notifications_none" }, void 0, false), "暂无系统消息"] }, void 0, true) : null, items.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("article", { className: item.read_at ? 'read' : '', onClick: () => markRead(item), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("time", { children: new Date(item.created_at).toLocaleString('zh-CN') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "system-notification-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("header", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h2", { children: item.title }, void 0, false), !item.read_at ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: "新" }, void 0, false) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { children: item.summary }, void 0, false), item.action && item.action.device ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("dl", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("dt", { children: "设备:" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("dd", { children: item.action.device }, void 0, false)] }, void 0, true), item.action.ip ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("dt", { children: "IP地址:" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("dd", { children: item.action.ip }, void 0, false)] }, void 0, true) : null] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: "system-security-link", onClick: e => { e.stopPropagation(); navigate(authenticated ? 'security' : 'identity-check'); }, children: ["前往安全设置 ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("footer", { children: ["保持警惕", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("br", {}, void 0, false), "即时通讯安全团队"] }, void 0, true)] }, void 0, true)] }, item.id, true))] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } function MessageCenterView(props) { switch (props.view) { case 'system-messages': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(SystemMessages, { authenticated: !!props.myUserId }, void 0, false); case 'message-actions': return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MessageActions, {}, void 0, false); case 'messages-offline': case 'messages-menu': case 'messages-home': default: return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MessageHome, { ...props }, void 0, false); } } /***/ }), /***/ "./src/views/message-composer-view.jsx": /*!*********************************************!*\ !*** ./src/views/message-composer-view.jsx ***! \*********************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ MESSAGE_COMPOSER_VIEWS: function() { return /* binding */ MESSAGE_COMPOSER_VIEWS; }, /* harmony export */ "default": function() { return /* binding */ MessageComposerView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const navigate = view => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__["default"].navigateTo(view); const MESSAGE_COMPOSER_VIEWS = ['compose-keyboard', 'mentions-select', 'mentions-complete', 'mentions-message', 'emoji-panel', 'emoji-message', 'voice-ready', 'voice-hold', 'voice-recording', 'media-uploading', 'media-gallery', 'media-retry', 'upload-file', 'file-message', 'message-multiselect', 'favorite-success', 'forward-select', 'forward-multiple', 'forward-individual', 'forward-bundle']; const MEMBERS = [{ id: 'all', name: '所有人', note: '提醒群内所有成员', avatar: 'campaign' }, { id: 'annie', name: '安妮', note: '产品设计组', image: 'img/bkg/p09.jpg' }, { id: 'lizi', name: '栗子来了', note: '前端开发组', image: 'img/bkg/p15.jpg' }, { id: 'wang', name: '王珊珊', note: '市场运营组', image: 'img/bkg/p14.jpg' }, { id: 'chen', name: '陈晨', note: '项目管理组', image: 'img/bkg/p05.jpg' }]; const TARGETS = [{ id: 'file', name: '文件助手', note: '仅自己可见', icon: 'folder_special' }, { id: 'team', name: '产品研发群', note: '18人', image: 'img/bkg/p22.jpg' }, { id: 'annie', name: '安妮', note: '在线', image: 'img/bkg/p09.jpg' }, { id: 'lizi', name: '栗子来了', note: '刚刚活跃', image: 'img/bkg/p15.jpg' }, { id: 'wang', name: '王珊珊', note: '市场运营组', image: 'img/bkg/p14.jpg' }]; const EMOJIS = ['😀', '😄', '😂', '🥰', '😎', '🤔', '👍', '👏', '🎉', '❤️', '🔥', '💡', '✅', '🙏', '💪', '🌟', '📌', '🚀']; function Icon({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons", "aria-hidden": "true", children: children }, void 0, false); } function Avatar({ item }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: "compose-avatar", children: item.image ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { src: item.image, alt: "" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: item.icon || item.avatar || 'person' }, void 0, false) }, void 0, false); } function Header({ title = '产品研发群', subtitle = '18人', onMore }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("header", { className: "chat-product-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('messages-home'), "aria-label": "返回消息", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("h1", { children: title }, void 0, false), subtitle ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: subtitle }, void 0, false) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: onMore, "aria-label": "会话设置", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "more_vert" }, void 0, false) }, void 0, false)] }, void 0, true); } function Toast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 2000); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-toast", role: "status", children: message }, void 0, false) : null; } function VoiceBubble({ mine = false, duration = 8, unread = false }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: 'compose-message-row' + (mine ? ' mine' : ''), children: [!mine ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Avatar, { item: MEMBERS[1] }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: 'compose-voice-bubble' + (mine ? ' mine' : ''), "aria-label": `播放${duration}秒语音`, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "graphic_eq" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: "compose-wave" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: [duration, "″"] }, void 0, true), unread ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", {}, void 0, false) : null] }, void 0, true), mine ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Avatar, { item: { image: 'img/bkg/p05.jpg' } }, void 0, false) : null] }, void 0, true); } function TextBubble({ mine = false, children, selected, onSelect }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: 'compose-select-row' + (selected !== undefined ? ' selectable' : ''), children: [selected !== undefined ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: 'compose-check' + (selected ? ' checked' : ''), onClick: onSelect, "aria-label": selected ? '取消选择' : '选择消息', children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: selected ? 'check' : '' }, void 0, false) }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: 'compose-message-row' + (mine ? ' mine' : ''), children: [!mine ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Avatar, { item: MEMBERS[2] }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: 'compose-text-bubble' + (mine ? ' mine' : ''), children: children }, void 0, false), mine ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Avatar, { item: { image: 'img/bkg/p05.jpg' } }, void 0, false) : null] }, void 0, true)] }, void 0, true); } function ImageBubble({ progress, failed = false, selected, onSelect }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: 'compose-select-row' + (selected !== undefined ? ' selectable' : ''), children: [selected !== undefined ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: 'compose-check' + (selected ? ' checked' : ''), onClick: onSelect, "aria-label": "选择图片", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: selected ? 'check' : '' }, void 0, false) }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-message-row mine", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-media-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { src: "img/bkg/p22.jpg", alt: "会议白板照片" }, void 0, false), progress < 100 || failed ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-media-state", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: failed ? 'refresh' : 'cloud_upload' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: failed ? '上传失败,点击重试' : `${progress}%` }, void 0, false), !failed ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("progress", { value: progress, max: "100" }, void 0, false) : null] }, void 0, true) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Avatar, { item: { image: 'img/bkg/p05.jpg' } }, void 0, false)] }, void 0, true)] }, void 0, true); } function VideoBubble() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-message-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Avatar, { item: MEMBERS[3] }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "compose-video-card", "aria-label": "播放视频", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { src: "img/bkg/p23.jpg", alt: "项目讨论视频封面" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "play_circle" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: "00:24" }, void 0, false)] }, void 0, true)] }, void 0, true); } function FileBubble({ progress = 100, name = '产品需求说明书.pdf', selected, onSelect }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: 'compose-select-row' + (selected !== undefined ? ' selectable' : ''), children: [selected !== undefined ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: 'compose-check' + (selected ? ' checked' : ''), onClick: onSelect, "aria-label": "选择文件", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: selected ? 'check' : '' }, void 0, false) }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-message-row mine", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-file-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: "compose-file-type", children: "PDF" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: ["2.4 MB · ", progress < 100 ? `上传中 ${progress}%` : '已发送'] }, void 0, true), progress < 100 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("progress", { value: progress, max: "100" }, void 0, false) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: progress < 100 ? 'close' : 'download' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Avatar, { item: { image: 'img/bkg/p05.jpg' } }, void 0, false)] }, void 0, true)] }, void 0, true); } function BaseTimeline({ mode, uploadProgress, selected, toggleSelected }) { const selectable = mode === 'message-multiselect' || mode === 'favorite-success'; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("main", { className: "chat-product-timeline compose-timeline", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "chat-time", children: "今天 10:24" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(TextBubble, { children: "上午的评审结论已经整理好了,大家有空看一下。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(TextBubble, { mine: true, selected: selectable ? selected.includes('text') : undefined, onSelect: () => toggleSelected('text'), children: "好的,我补充一下交互细节。" }, void 0, false), mode === 'mentions-message' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(TextBubble, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { className: "compose-mention", children: "@安妮 @栗子来了" }, void 0, false), " 下午三点一起确认新版流程。"] }, void 0, true) : null, ['media-uploading', 'media-gallery', 'media-retry'].includes(mode) ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(VoiceBubble, { duration: 6 }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(ImageBubble, { progress: mode === 'media-retry' ? 48 : uploadProgress, failed: mode === 'media-retry' }, void 0, false), mode === 'media-gallery' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(VoiceBubble, { mine: true, duration: 12, unread: true }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(VideoBubble, {}, void 0, false)] }, void 0, true) : null] }, void 0, true) : null, ['file-message', 'message-multiselect', 'favorite-success'].includes(mode) ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(FileBubble, { selected: selectable ? selected.includes('file') : undefined, onSelect: () => toggleSelected('file') }, void 0, false) : null, selectable ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(ImageBubble, { progress: 100, selected: selected.includes('image'), onSelect: () => toggleSelected('image') }, void 0, false) : null] }, void 0, true); } function EmojiPanel({ onEmoji, onDelete }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("section", { className: "compose-emoji-panel", "aria-label": "表情面板", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("nav", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "active", "aria-label": "最近使用", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "schedule" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", "aria-label": "笑脸", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "sentiment_satisfied_alt" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", "aria-label": "收藏表情", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "favorite_border" }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { children: EMOJIS.map(emoji => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => onEmoji(emoji), children: emoji }, emoji, false)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "compose-emoji-delete", onClick: onDelete, "aria-label": "删除字符", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "backspace" }, void 0, false) }, void 0, false)] }, void 0, true); } function Composer({ mode, draft, setDraft, onSend, setMode }) { const voice = ['voice-ready', 'voice-hold', 'voice-recording'].includes(mode); const emoji = ['emoji-panel', 'emoji-message'].includes(mode); const keyDown = event => { if (event.key === '@' && mode !== 'mentions-message') window.setTimeout(() => navigate('mentions-select'), 0); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("form", { className: "compose-toolbar", onSubmit: event => { event.preventDefault(); onSend(); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => setMode(voice ? 'compose-keyboard' : 'voice-ready'), "aria-label": voice ? '切换键盘' : '切换语音', children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: voice ? 'keyboard' : 'record_voice_over' }, void 0, false) }, void 0, false), voice ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "compose-hold-button", onPointerDown: () => setMode('voice-hold'), onPointerUp: () => setMode('media-uploading'), children: "按住说话" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { autoFocus: mode === 'compose-keyboard', value: draft, onChange: event => setDraft(event.target.value), onKeyDown: keyDown, placeholder: "输入消息" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => setMode(emoji ? 'compose-keyboard' : 'emoji-panel'), "aria-label": "表情", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "sentiment_satisfied_alt" }, void 0, false) }, void 0, false), draft.trim() && !voice ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "submit", className: "compose-send", children: "发送" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('upload-file'), "aria-label": "更多", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "add_circle_outline" }, void 0, false) }, void 0, false)] }, void 0, true), emoji ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(EmojiPanel, { onEmoji: value => setDraft(draft + value), onDelete: () => setDraft(draft.slice(0, -1)) }, void 0, false) : null] }, void 0, true); } function VoiceOverlay({ cancel = false }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: 'compose-record-overlay' + (cancel ? ' cancel' : ''), role: "status", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: cancel ? 'delete_outline' : 'mic' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-meter", children: [2, 5, 8, 12, 9, 6, 11, 4].map((height, index) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { style: { height: `${height * 2}px` } }, index, false)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: cancel ? '松开手指,取消发送' : '手指上滑,取消发送' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: "00:08" }, void 0, false)] }, void 0, true); } function MemberPicker({ complete }) { const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [selected, setSelected] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(complete ? ['annie', 'lizi'] : []); const visible = MEMBERS.filter(item => item.name.includes(query) || item.note.includes(query)); const toggle = id => setSelected(values => values.includes(id) ? values.filter(value => value !== id) : values.concat(id)); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-picker-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("header", { className: "compose-picker-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('compose-keyboard'), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("h1", { children: "选择提醒人" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "text", disabled: !selected.length, onClick: () => { sessionStorage.setItem('im-mentions', JSON.stringify(selected)); navigate('mentions-message'); }, children: ["完成", selected.length ? `(${selected.length})` : ''] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { className: "compose-search", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "search" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { value: query, onChange: event => setQuery(event.target.value), placeholder: "搜索群成员" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "compose-section-title", children: "群成员" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-picker-list", children: visible.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => toggle(item.id), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Avatar, { item: item }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: item.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: item.note }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: 'compose-checkbox' + (selected.includes(item.id) ? ' checked' : ''), children: selected.includes(item.id) ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "check" }, void 0, false) : null }, void 0, false)] }, item.id, true)) }, void 0, false)] }, void 0, true); } function UploadFilePage({ onToast }) { const [files, setFiles] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([{ name: '产品需求说明书.pdf', size: '2.4 MB', progress: 64 }]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (files.every(file => file.progress >= 100)) return undefined; const timer = window.setTimeout(() => setFiles(items => items.map(file => ({ ...file, progress: Math.min(100, file.progress + 6) }))), 300); return () => window.clearTimeout(timer); }, [files]); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-upload-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Header, { title: "上传文件", subtitle: "最多选择 9 个文件", onMore: () => onToast('单个文件最大 100 MB') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { className: "compose-upload-drop", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { type: "file", multiple: true, onChange: event => setFiles(Array.from(event.target.files).map(file => ({ name: file.name, size: `${Math.max(1, file.size / 1024 / 1024).toFixed(1)} MB`, progress: 1 }))) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "cloud_upload" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: "选择文件" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: "支持文档、压缩包及常用媒体格式" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("section", { className: "compose-upload-list", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("h2", { children: "待发送文件" }, void 0, false), files.map(file => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: "compose-file-type", children: file.name.split('.').pop().slice(0, 4).toUpperCase() }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: file.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: [file.size, " · ", file.progress < 100 ? `上传中 ${file.progress}%` : '上传完成'] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("progress", { value: file.progress, max: "100" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", "aria-label": "移除文件", onClick: () => setFiles(items => items.filter(item => item.name !== file.name)), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "close" }, void 0, false) }, void 0, false)] }, file.name, true))] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("footer", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", disabled: !files.length, onClick: () => navigate('file-message'), children: ["发送", files.length ? ` (${files.length})` : ''] }, void 0, true) }, void 0, false)] }, void 0, true); } function ForwardPage({ mode, onToast }) { const multi = mode !== 'forward-select'; const confirm = mode === 'forward-individual' || mode === 'forward-bundle'; const [selected, setSelected] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => { if (!confirm) return []; try { return JSON.parse(sessionStorage.getItem('im-forward-targets')) || ['team', 'annie']; } catch (_) { return ['team', 'annie']; } }); const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [comment, setComment] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const toggle = id => setSelected(values => values.includes(id) ? values.filter(value => value !== id) : multi ? values.concat(id).slice(0, 9) : [id]); const visible = TARGETS.filter(item => item.name.includes(query) || item.note.includes(query)); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-forward-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("header", { className: "compose-picker-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('message-multiselect'), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "close" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("h1", { children: confirm ? mode === 'forward-bundle' ? '合并转发' : '逐条转发' : '选择转发对象' }, void 0, false), !confirm ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "text", onClick: () => navigate(multi ? 'forward-select' : 'forward-multiple'), children: multi ? '单选' : '多选' }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", {}, void 0, false)] }, void 0, true), !confirm ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { className: "compose-search", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "search" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { value: query, onChange: event => setQuery(event.target.value), placeholder: "搜索会话或联系人" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { className: "compose-section-title", children: "最近会话" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-picker-list", children: visible.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => { toggle(item.id); if (!multi) { sessionStorage.setItem('im-forward-targets', JSON.stringify([item.id])); window.setTimeout(() => navigate('forward-individual'), 0); } }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Avatar, { item: item }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: item.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: item.note }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: 'compose-checkbox' + (selected.includes(item.id) ? ' checked' : ''), children: selected.includes(item.id) ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "check" }, void 0, false) : null }, void 0, false)] }, item.id, true)) }, void 0, false), multi ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("footer", { className: "compose-target-footer", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: ["已选择 ", selected.length, "/9 个会话"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", disabled: !selected.length, onClick: () => { sessionStorage.setItem('im-forward-targets', JSON.stringify(selected)); navigate('forward-individual'); }, children: "下一步" }, void 0, false)] }, void 0, true) : null] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("main", { className: "compose-forward-confirm", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("h2", { children: "发送给" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-target-summary", children: TARGETS.filter(item => selected.includes(item.id)).map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Avatar, { item: item }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("small", { children: item.name }, void 0, false)] }, item.id, true)) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("section", { className: "compose-forward-preview", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("h2", { children: mode === 'forward-bundle' ? '产品研发群的聊天记录' : '将逐条发送 3 条消息' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { children: "栗子来了:上午的评审结论已经整理好了" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { children: "我:好的,我补充一下交互细节。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("p", { children: "我:[图片]" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("textarea", { value: comment, onChange: event => setComment(event.target.value), placeholder: "给朋友留言" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-forward-mode", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: mode === 'forward-individual' ? 'active' : '', onClick: () => navigate('forward-individual'), children: "逐条转发" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: mode === 'forward-bundle' ? 'active' : '', onClick: () => navigate('forward-bundle'), children: "合并转发" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", className: "compose-confirm-send", onClick: () => { onToast(`已发送给 ${selected.length} 个会话`); window.setTimeout(() => navigate('chat-standard'), 900); }, children: "发送" }, void 0, false)] }, void 0, true)] }, void 0, true); } function MessageComposerView({ view }) { const [mode, setMode] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(view); const [draft, setDraftState] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => sessionStorage.getItem('im-message-composer-draft') || (view === 'emoji-message' ? '收到啦 ' : '')); const [uploadProgress, setUploadProgress] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(view === 'media-uploading' ? 22 : 100); const [selected, setSelected] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(view === 'favorite-success' ? ['text', 'file', 'image'] : ['text', 'image']); const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(view === 'favorite-success' ? '已收藏 3 条消息' : ''); const setDraft = value => { setDraftState(value); sessionStorage.setItem('im-message-composer-draft', value); }; react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (mode !== 'media-uploading' || uploadProgress >= 100) return undefined; const timer = window.setTimeout(() => setUploadProgress(value => Math.min(100, value + 5)), 350); return () => window.clearTimeout(timer); }, [mode, uploadProgress]); if (view === 'mentions-select' || view === 'mentions-complete') return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(MemberPicker, { complete: view === 'mentions-complete' }, void 0, false); if (view === 'upload-file') return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(UploadFilePage, { onToast: setToast }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); if (['forward-select', 'forward-multiple', 'forward-individual', 'forward-bundle'].includes(view)) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(ForwardPage, { mode: view, onToast: setToast }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); const toggleSelected = id => setSelected(values => values.includes(id) ? values.filter(value => value !== id) : values.concat(id)); const recording = mode === 'voice-hold' || mode === 'voice-recording'; const multiselect = mode === 'message-multiselect' || mode === 'favorite-success'; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "chat-product-page message-composer-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Header, { onMore: () => setToast('会话设置') }, void 0, false), multiselect ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "compose-selection-bar", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => navigate('chat-standard'), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "close" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("strong", { children: ["已选择 ", selected.length, " 条"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", onClick: () => setSelected(selected.length ? [] : ['text', 'file', 'image']), children: selected.length ? '取消全选' : '全选' }, void 0, false)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(BaseTimeline, { mode: mode, uploadProgress: uploadProgress, selected: selected, toggleSelected: toggleSelected }, void 0, false), multiselect ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("nav", { className: "compose-batch-actions", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", disabled: !selected.length, onClick: () => navigate('forward-select'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "forward" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: "转发" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", disabled: !selected.length, onClick: () => { setMode('favorite-success'); setToast(`已收藏 ${selected.length} 条消息`); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "bookmark_border" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: "收藏" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { type: "button", disabled: !selected.length, onClick: () => { setSelected([]); setToast('已删除所选消息'); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Icon, { children: "delete_outline" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: "删除" }, void 0, false)] }, void 0, true)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Composer, { mode: mode, draft: draft, setDraft: setDraft, setMode: setMode, onSend: () => { if (!draft.trim()) return; setToast('消息已发送'); setDraft(''); } }, void 0, false), recording ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(VoiceOverlay, { cancel: false }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } /***/ }), /***/ "./src/views/new-topic-view.jsx": /*!**************************************!*\ !*** ./src/views/new-topic-view.jsx ***! \**************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _widgets_new_topic_by_id_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/new-topic-by-id.jsx */ "./src/widgets/new-topic-by-id.jsx"); /* harmony import */ var _widgets_new_topic_group_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/new-topic-group.jsx */ "./src/widgets/new-topic-group.jsx"); /* harmony import */ var _widgets_search_contacts_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/search-contacts.jsx */ "./src/widgets/search-contacts.jsx"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ search_for_contacts: { id: "search_for_contacts", defaultMessage: "Use search to find contacts", description: "Text shown in contacts view when user entered no search query." }, search_no_results: { id: "search_no_results", defaultMessage: "Search returned no results", description: "Text shown in contacts view when query returned no results." }, search_placeholder: { id: "search_placeholder", defaultMessage: "List like alice@example.com, +17025550003...", description: "Placeholder in contacts search field" } }); class NewTopicView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); const urlParams = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].parseUrlHash(window.location.hash).params; const initialTab = urlParams['tab'] || 'find'; const initialQuery = initialTab == 'find' ? urlParams['q'] || null : null; this.state = { tabSelected: initialTab, searchQuery: initialQuery }; this.handleTabClick = this.handleTabClick.bind(this); this.handleSearchContacts = this.handleSearchContacts.bind(this); this.handleSearchResultSelected = this.handleSearchResultSelected.bind(this); this.handleNewGroupSubmit = this.handleNewGroupSubmit.bind(this); this.handleGroupByID = this.handleGroupByID.bind(this); } componentDidMount() { this.props.onInitFind(); } handleTabClick(e) { e.preventDefault(); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].addUrlParam(window.location.hash, 'tab', e.currentTarget.dataset.id)); this.setState({ tabSelected: e.currentTarget.dataset.id }); } handleSearchContacts(query) { query = query.trim() || tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.DEL_CHAR; if (!/[\s,:]/.test(query) && query != tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.DEL_CHAR) { const email = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_8__.asEmail)(query); if (email) { query = `${tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.TAG_EMAIL}${email}`; } else { const tel = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_8__.asPhone)(query); if (tel) { query = `${tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.TAG_PHONE}${tel}`; } else { if (query[0] == '@') { query = query.substring(1); } query = `${tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.TAG_ALIAS}${query},${query}`; } } } this.props.onSearchContacts(query); this.setState({ searchQuery: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNullValue(query) ? null : query }); } handleSearchResultSelected(topicName) { if (this.state.tabSelected == 'find') { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].removeUrlParams(window.location.hash, ['tab', 'q'])); this.props.onCreateTopic(topicName); } } handleNewGroupSubmit(name, description, dataUrl, priv, tags, isChannel) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].removeUrlParams(window.location.hash, ['tab', 'q'])); this.props.onCreateTopic(undefined, { public: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_8__.theCard)(name, dataUrl, null, description), private: priv, tags: tags }, isChannel); } handleGroupByID(topicName) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].removeUrlParams(window.location.hash, ['tab', 'q'])); this.props.onCreateTopic(topicName); } render() { const { formatMessage } = this.props.intl; const no_contacts_placeholder = formatMessage(this.state.searchQuery ? messages.search_no_results : messages.search_for_contacts); const search_placeholder = formatMessage(messages.search_placeholder); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("div", { className: "flex-column", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("ul", { className: "tabbar", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("li", { className: this.state.tabSelected === 'find' ? 'active' : null, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("a", { href: "#", "data-id": "find", onClick: this.handleTabClick, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tabtitle_find_user", defaultMessage: "find", description: "Tab title Find" }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("li", { className: this.state.tabSelected === 'grp' ? 'active' : null, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("a", { href: "#", "data-id": "grp", onClick: this.handleTabClick, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tabtitle_new_group", defaultMessage: "new group", description: "Tab title New Group" }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("li", { className: this.state.tabSelected === 'byid' ? 'active' : null, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("a", { href: "#", "data-id": "byid", onClick: this.handleTabClick, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tabtitle_group_by_id", defaultMessage: "by id", description: "Tab title Find topic by ID" }, void 0, false) }, void 0, false) }, void 0, false)] }, void 0, true), this.state.tabSelected === 'grp' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(_widgets_new_topic_group_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { tinode: this.props.tinode, onSubmit: this.handleNewGroupSubmit, onError: this.props.onError }, void 0, false) : this.state.tabSelected === 'byid' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(_widgets_new_topic_by_id_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { myURI: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.URI_TOPIC_ID_PREFIX + this.props.tinode.getCurrentUserID(), onSubmit: this.handleGroupByID, onError: this.props.onError }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("div", { className: "flex-column", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(_widgets_search_contacts_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { placeholder: search_placeholder, initialQuery: this.state.searchQuery || '', onSearchContacts: this.handleSearchContacts }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(_widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, contacts: this.props.searchResults, myUserId: this.props.myUserId, emptyListMessage: no_contacts_placeholder, showSelfTopic: !this.state.searchQuery, showOnline: false, showUnread: false, showContextMenu: false, onTopicSelected: this.handleSearchResultSelected }, void 0, false)] }, void 0, true)] }, void 0, true); } } ; /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(NewTopicView)); /***/ }), /***/ "./src/views/personal-settings-view.jsx": /*!**********************************************!*\ !*** ./src/views/personal-settings-view.jsx ***! \**********************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PERSONAL_SETTINGS_VIEWS: function() { return /* binding */ PERSONAL_SETTINGS_VIEWS; }, /* harmony export */ "default": function() { return /* binding */ PersonalSettingsView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var qrcodejs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! qrcodejs */ "qrcodejs"); /* harmony import */ var qrcodejs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(qrcodejs__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/use-cached-data.js */ "./src/lib/use-cached-data.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _version_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../version.js */ "./src/version.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const navigate = (view, params) => { let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].setUrlSidePanel(window.location.hash, view); Object.entries(params || {}).forEach(([key, value]) => { hash = value ? _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].addUrlParam(hash, key, value) : _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].removeUrlParam(hash, key); }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].navigateTo(hash); }; const PERSONAL_SETTINGS_VIEWS = ['personal-center', 'personal-profile', 'profile-nickname', 'profile-birth-date', 'profile-signature', 'profile-gender', 'profile-region', 'personal-qrcode', 'android-settings', 'cache-clear-confirm', 'clear-history-confirm', 'change-password', 'delete-account-confirm', 'app-version', 'privacy-settings', 'friend-discovery-settings', 'youth-mode-off', 'youth-mode-on', 'youth-mode-verify', 'notification-permission', 'permission-settings-reminder', 'camera-permission-info', 'microphone-permission-info']; function Icon({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", { className: "material-icons", "aria-hidden": "true", children: children }, void 0, false); } function Header({ title, back = 'personal-center', action, actionLabel, onAction, actionDisabled }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("header", { className: "personal-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", onClick: () => { if (!_lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].goBack()) navigate(back); }, "aria-label": "返回", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h1", { children: title }, void 0, false), action ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: "text", onClick: onAction, disabled: actionDisabled, children: actionLabel || action }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {}, void 0, false)] }, void 0, true); } function Toast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 2100); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-toast", role: "status", children: message }, void 0, false) : null; } function Toggle({ checked, disabled, onChange }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", role: "switch", "aria-checked": checked, disabled: disabled, className: 'personal-switch' + (checked ? ' checked' : ''), onClick: () => onChange(!checked), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {}, void 0, false) }, void 0, false); } function MenuRow({ icon, title, value, route, onClick, danger }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: 'personal-menu-row' + (danger ? ' danger' : ''), onClick: onClick || (() => route && navigate(route)), children: [icon ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: icon }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("strong", { children: title }, void 0, false), value ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: value }, void 0, false) : null] }, void 0, true), route || onClick ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false) : null] }, void 0, true); } function tenantName() { try { return JSON.parse(window.localStorage.getItem('im-tenant') || '{}').name || ''; } catch (_) { return ''; } } function ImgFromFile({ fileId, className }) { const [url, setUrl] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { let live = true; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getFileUrl)(fileId).then(u => live && setUrl(u)).catch(() => {}); return () => { live = false; }; }, [fileId]); return url ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("img", { className: className, src: url, alt: "" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { className: className }, void 0, false); } function PersonalCenter() { const [profile] = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.useCachedData)('me-profile', _lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getMeProfile, []); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page personal-center-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "我的", back: "messages-home" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: "personal-identity", onClick: () => navigate('personal-profile'), children: [profile && profile.avatar_file_id ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(ImgFromFile, { fileId: profile.avatar_file_id }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { className: "personal-avatar-fallback", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "person" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("strong", { children: profile && (profile.nickname || profile.public_account) || '…' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: ["企业名称:", tenantName() || '…'] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: ["ID: ", profile && profile.public_account || '…'] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "qr_code", title: "我的二维码", route: "personal-qrcode" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "bookmark_border", title: "我的收藏", route: "favorites" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "report_problem", title: "关于我们", route: "app-version" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "feedback", title: "意见反馈", route: "user-feedback" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "settings", title: "设置", route: "android-settings" }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true); } function PersonalProfile({ onToast, tinode }) { const [profile, setProfile] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.readCachedData)('me-profile') || null); const fileInputRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); const [uploading, setUploading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const load = () => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getMeProfile)().then(p => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('me-profile', p); setProfile(p); }).catch(() => {}); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { load(); }, []); const pickAvatar = () => fileInputRef.current && fileInputRef.current.click(); const handleAvatarFile = event => { const file = event.target.files && event.target.files[0]; event.target.value = ''; if (!file || !tinode) return; setUploading(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.uploadLargeFile)(tinode, file).then(({ fileId }) => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.updateMeProfile)({ avatar_file_id: fileId, version: profile.version })).then(load).then(() => onToast('头像已更新')).catch(err => onToast(err.message || '头像上传失败')).finally(() => setUploading(false)); }; const genderLabel = { male: '男', female: '女', other: '其他' }[profile && profile.gender] || '未设置'; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "个人信息" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { className: "personal-profile-list", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", onClick: pickAvatar, disabled: uploading, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("strong", { children: "头像" }, void 0, false), profile && profile.avatar_file_id ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(ImgFromFile, { fileId: profile.avatar_file_id }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "person" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", { ref: fileInputRef, type: "file", accept: "image/*", style: { display: 'none' }, onChange: handleAvatarFile }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { title: "昵称", value: profile && (profile.nickname || '未设置'), route: "profile-nickname" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { title: "性别", value: genderLabel, route: "profile-gender" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { title: "出生日期", value: profile && profile.birth_date || '未设置', route: "profile-birth-date" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { title: "二维码名片", route: "personal-qrcode" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { title: "地区", value: profile && profile.region || '未设置', route: "profile-region" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { title: "个性签名", value: profile && profile.signature || '此人很懒什么都没留下~', route: "profile-signature" }, void 0, false)] }, void 0, true)] }, void 0, true); } const FIELD_LIMITS = { nickname: 32, signature: 120 }; function TextEditor({ field, multiline, title, onToast }) { const [profile, setProfile] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [value, setValue] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [saving, setSaving] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getMeProfile)().then(p => { setProfile(p); setValue(p[field] || ''); }).catch(() => {}); }, [field]); const save = () => { const normalized = value.trim(); if (field === 'nickname' && !normalized) { onToast('昵称不能为空'); return; } setSaving(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.updateMeProfile)({ [field]: normalized, version: profile.version }).then(_ => { onToast('资料已保存'); window.setTimeout(() => navigate('personal-profile'), 500); }).catch(err => onToast(err.message || '保存失败')).finally(() => setSaving(false)); }; const maxLength = FIELD_LIMITS[field]; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page profile-editor-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: title, back: "personal-profile", action: "完成", onAction: save, actionDisabled: !profile || saving }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("label", { children: [multiline ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("textarea", { value: value, maxLength: maxLength, autoFocus: true, placeholder: "请输入……", onChange: event => setValue(event.target.value) }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", { value: value, maxLength: maxLength, autoFocus: true, onChange: event => setValue(event.target.value) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: [value.length, "/", maxLength] }, void 0, true), value ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", onClick: () => setValue(''), "aria-label": "清空", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "cancel" }, void 0, false) }, void 0, false) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { children: field === 'nickname' ? '昵称将展示在联系人资料和聊天页面中' : '签名将展示在你的个人资料页' }, void 0, false)] }, void 0, true)] }, void 0, true); } function BirthDateEditor({ onToast }) { const [profile, setProfile] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [value, setValue] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getMeProfile)().then(p => { setProfile(p); setValue(p.birth_date || ''); }).catch(() => {}); }, []); const save = () => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.updateMeProfile)({ birth_date: value, version: profile.version }).then(_ => { onToast('出生日期已保存'); window.setTimeout(() => navigate('personal-profile'), 500); }).catch(err => onToast(err.message || '保存失败')); }; const today = new Date().toISOString().slice(0, 10); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page profile-editor-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "出生日期", back: "personal-profile", action: "完成", onAction: save, actionDisabled: !profile }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { className: "birth-date-editor", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "cake" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: "选择出生日期" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", { type: "date", value: value, max: today, min: "1900-01-01", onChange: event => setValue(event.target.value) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { children: "出生日期的可见范围由隐私设置决定" }, void 0, false)] }, void 0, true)] }, void 0, true); } const GENDER_OPTIONS = [{ value: 'male', label: '男' }, { value: 'female', label: '女' }, { value: 'other', label: '其他' }]; function GenderEditor({ onToast }) { const [profile, setProfile] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getMeProfile)().then(setProfile).catch(() => {}); }, []); const choose = value => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.updateMeProfile)({ gender: value, version: profile.version }).then(_ => { onToast('性别已更新'); window.setTimeout(() => navigate('personal-profile'), 400); }).catch(err => onToast(err.message || '保存失败')); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "性别", back: "personal-profile" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { className: "gender-option-list", children: GENDER_OPTIONS.map(opt => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", onClick: () => choose(opt.value), disabled: !profile, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("strong", { children: opt.label }, void 0, false), profile && profile.gender === opt.value ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "check" }, void 0, false) : null] }, opt.value, true)) }, void 0, false)] }, void 0, true); } function RegionEditor({ onToast }) { const [profile, setProfile] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [value, setValue] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getMeProfile)().then(p => { setProfile(p); setValue(p.region || ''); }).catch(() => {}); }, []); const save = () => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.updateMeProfile)({ region: value.trim(), version: profile.version }).then(_ => { onToast('地区已保存'); window.setTimeout(() => navigate('personal-profile'), 500); }).catch(err => onToast(err.message || '保存失败')); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page profile-editor-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "地区", back: "personal-profile", action: "完成", onAction: save, actionDisabled: !profile }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("label", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", { value: value, maxLength: 60, autoFocus: true, placeholder: "省份/城市", onChange: event => setValue(event.target.value) }, void 0, false) }, void 0, false) }, void 0, false)] }, void 0, true); } function PersonalQr({ onToast }) { const [profile, setProfile] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.readCachedData)('me-profile') || null); const [qr, setQr] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const qrRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); const load = () => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.createMyQRCode)().then(setQr).catch(err => onToast(err.message || '二维码生成失败')); }; react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getMeProfile)().then(p => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('me-profile', p); setProfile(p); }).catch(() => {}); load(); }, []); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!qr || !qrRef.current) return; qrRef.current.innerHTML = ''; new (qrcodejs__WEBPACK_IMPORTED_MODULE_1___default())(qrRef.current, { text: qr.qr_payload || qr.qr_token, width: 210, height: 210, correctLevel: (qrcodejs__WEBPACK_IMPORTED_MODULE_1___default().CorrectLevel).M }); }, [qr]); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page personal-qr-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "我的二维码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-qr-profile", children: [profile && profile.avatar_file_id ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(ImgFromFile, { fileId: profile.avatar_file_id }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "person" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("strong", { children: profile && profile.nickname || profile && profile.public_account }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: tenantName() }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-qrcode", ref: qrRef }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { children: "扫一扫上面的二维码,加我为好友" }, void 0, false), qr && qr.expires_at ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: ["二维码将于 ", new Date(qr.expires_at).toLocaleString(), " 失效"] }, void 0, true) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-qr-actions", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", onClick: () => { load(); onToast('二维码已刷新'); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "refresh" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: "刷新" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", onClick: () => { if (navigator.share && qr) { navigator.share({ title: '我的名片', text: qr.qr_payload || qr.qr_token }).catch(() => {}); } else { onToast('当前环境不支持分享'); } }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "share" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: "分享" }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true)] }, void 0, true); } function SettingsList({ onToast, onLogout }) { const [youthSettings, setYouthSettings] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.readCachedData)('youth-mode') || null); const [realname, setRealname] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.readCachedData)('me-realname') || null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getYouthMode)().then(d => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('youth-mode', d); setYouthSettings(d); }).catch(() => {}); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getRealnameStatus)().then(d => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('me-realname', d); setRealname(d); }).catch(() => {}); }, []); const youthEnabled = youthSettings ? youthSettings.enabled : null; const realnameStatus = realname ? realname.status : null; const realnameLabel = { verified: '已认证', pending: '审核中', rejected: '未通过' }[realnameStatus] || '未认证'; const logout = () => { if (window.confirm('确定要退出当前登录吗?')) { onLogout ? onLogout() : onToast('当前环境不支持退出登录'); } }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "设置" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { className: "android-settings-list", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "delete_sweep", title: "清除缓存", route: "cache-clear-confirm" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "mark_chat_read", title: "清除所有聊天记录", route: "clear-history-confirm" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "password", title: "修改密码", route: "change-password" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "lock_outline", title: "隐私设置", route: "privacy-settings" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "block", title: "黑名单", route: "block-list" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "child_care", title: "青少年模式", value: youthEnabled == null ? '…' : youthEnabled ? '已开启' : '未开启', route: youthEnabled ? 'youth-mode-on' : 'youth-mode-off' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "verified_user", title: "实名认证", value: realnameLabel, route: "realname" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { icon: "no_accounts", title: "注销账号", route: "delete-account-confirm", danger: true }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: "personal-logout", onClick: logout, children: "退出当前登录" }, void 0, false)] }, void 0, true)] }, void 0, true); } function ConfirmSheet({ icon, title, body, confirmLabel = '确认', confirmDanger = true, busy, onConfirm, onCancel, children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-sheet-backdrop", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { className: "personal-confirm-sheet", role: "dialog", "aria-modal": "true", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: icon }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h2", { children: title }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { children: body }, void 0, false), children, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: confirmDanger ? 'danger' : 'primary', disabled: busy, onClick: onConfirm, children: busy ? '处理中…' : confirmLabel }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", onClick: onCancel, disabled: busy, children: "取消" }, void 0, false)] }, void 0, true) }, void 0, false); } function CacheClear({ onToast }) { const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [done, setDone] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [freed, setFreed] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(0); const confirm = async () => { setBusy(true); try { const before = (await navigator.storage.estimate().catch(() => ({ usage: 0 }))).usage || 0; const keys = await caches.keys(); await Promise.all(keys.map(k => caches.delete(k))); const after = (await navigator.storage.estimate().catch(() => ({ usage: 0 }))).usage || 0; setFreed(Math.max(0, before - after)); setDone(true); } finally { setBusy(false); } }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(ConfirmSheet, { icon: done ? 'check_circle' : 'delete_sweep', title: done ? '缓存已清理' : '清空缓存', body: done ? `已释放约 ${(freed / (1024 * 1024)).toFixed(1)} MB 存储空间。` : '确定清空本地的缓存数据?将清除缩略图、临时文件和可重新下载的数据,不会删除聊天记录、收藏或登录信息。', confirmLabel: done ? '完成' : '确定', confirmDanger: !done, busy: busy, onConfirm: done ? () => navigate('android-settings') : confirm, onCancel: () => navigate('android-settings') }, void 0, false); } function ClearHistoryConfirm({ tinode, chatList, onToast }) { const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const confirm = () => { if (!tinode || !chatList || !chatList.length) { onToast('没有可清除的会话'); navigate('android-settings'); return; } setBusy(true); Promise.all(chatList.map(c => { const topic = tinode.getTopic(c.name); return topic ? topic.delMessagesAll(false).catch(() => {}) : Promise.resolve(); })).then(() => { onToast('聊天记录已清空'); navigate('android-settings'); }).finally(() => setBusy(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(ConfirmSheet, { icon: "mark_chat_read", title: "清除所有聊天记录", body: "确定清除所有聊天记录?此操作不可恢复,但不会影响好友/群聊关系和收藏内容。", busy: busy, onConfirm: confirm, onCancel: () => navigate('android-settings') }, void 0, false); } function ChangePassword({ onUpdatePassword, onToast }) { const [oldPwd, setOldPwd] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [newPwd, setNewPwd] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [confirmPwd, setConfirmPwd] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const submit = () => { if (!oldPwd || newPwd.length < 6) { onToast('请输入原密码,新密码至少6位'); return; } if (newPwd !== confirmPwd) { onToast('两次输入的新密码不一致'); return; } if (!onUpdatePassword) { onToast('当前环境不支持修改密码'); return; } onUpdatePassword(newPwd); onToast('密码已更新'); window.setTimeout(() => navigate('android-settings'), 500); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page profile-editor-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "修改密码", back: "android-settings", action: "完成", onAction: submit }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: "原密码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", { type: "password", value: oldPwd, onChange: e => setOldPwd(e.target.value), placeholder: "请输入当前密码" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: "新密码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", { type: "password", value: newPwd, onChange: e => setNewPwd(e.target.value), placeholder: "至少6位" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: "确认新密码" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", { type: "password", value: confirmPwd, onChange: e => setConfirmPwd(e.target.value), placeholder: "再次输入新密码" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { children: "Tinode 协议本身不会在服务端校验\"原密码\",这里的原密码输入是前端自己加的一道二次确认,防止误触。" }, void 0, false)] }, void 0, true)] }, void 0, true); } function DeleteAccountConfirm({ onDeleteAccount, onToast }) { const [step, setStep] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(1); const [password, setPassword] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const proceed = () => { if (!password) { onToast('请输入密码以确认'); return; } if (!onDeleteAccount) { onToast('当前环境不支持注销账号'); return; } setBusy(true); Promise.resolve(onDeleteAccount()).catch(err => { onToast(err.message || '注销失败'); setBusy(false); }); }; if (step === 1) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(ConfirmSheet, { icon: "warning", title: "注销账号", body: "注销后账号数据将被永久删除且无法恢复,包括聊天记录、好友关系和收藏内容。确定要继续吗?", confirmLabel: "继续", onConfirm: () => setStep(2), onCancel: () => navigate('android-settings') }, void 0, false); } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(ConfirmSheet, { icon: "no_accounts", title: "输入密码确认注销", body: "请输入登录密码以确认注销账号(该操作立即生效,不可撤销)。", busy: busy, onConfirm: proceed, onCancel: () => navigate('android-settings'), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", { type: "password", autoFocus: true, value: password, onChange: e => setPassword(e.target.value), placeholder: "登录密码" }, void 0, false) }, void 0, false); } function AppVersion({ onToast }) { const currentVersion = _version_js__WEBPACK_IMPORTED_MODULE_5__.PACKAGE_VERSION; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page app-version-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "关于我们", back: "android-settings" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { className: "app-brand", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "forum" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h2", { children: _config_js__WEBPACK_IMPORTED_MODULE_4__.BASE_APP_NAME }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { children: ["版本 ", currentVersion] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { className: "personal-menu-section", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { title: "用户条款", onClick: () => onToast('用户条款') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { title: "隐私协议", onClick: () => onToast('隐私协议') }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true); } function PrivacySettings({ onToast }) { const [privacy, setPrivacy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.readCachedData)('me-privacy') || null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getMePrivacy)().then(p => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('me-privacy', p); setPrivacy(p); }).catch(() => {}); }, []); const update = (key, value) => { const prev = privacy; setPrivacy({ ...privacy, [key]: value }); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.updateMePrivacy)({ [key]: value, version: privacy.version }).then(p => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('me-privacy', p); setPrivacy(p); }).catch(err => { onToast(err.message || '保存失败'); setPrivacy(prev); (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('me-privacy', prev); }); }; const methodSummary = () => { if (!privacy) return ''; const labels = { account: '账号', phone: '手机号', qr: '二维码', group: '群聊' }; const on = Object.entries(privacy.add_me_methods || {}).filter(([, v]) => v).map(([k]) => labels[k] || k); if (on.length === 4) return '全部允许'; return on.length ? on.join('、') : '全部关闭'; }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "隐私设置", back: "android-settings" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { className: "privacy-list", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(MenuRow, { title: "添加我的方式", value: methodSummary(), route: "friend-discovery-settings" }, void 0, false) }, void 0, false), privacy ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("strong", { children: "显示消息已读状态" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: "关闭后你也无法查看对方的已读状态" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Toggle, { checked: !!privacy.read_receipts, onChange: v => update('read_receipts', v) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("strong", { children: "展示最后在线时间" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: "仅向联系人显示" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Toggle, { checked: privacy.last_seen_visibility !== 'nobody', onChange: v => update('last_seen_visibility', v ? 'friends' : 'nobody') }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("strong", { children: "允许好友查看我的资料" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: "关闭后仅你自己可见" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Toggle, { checked: privacy.profile_visibility !== 'nobody', onChange: v => update('profile_visibility', v ? 'friends' : 'nobody') }, void 0, false)] }, void 0, true)] }, void 0, true) : null] }, void 0, true)] }, void 0, true); } function FriendDiscoverySettings({ onToast }) { const [privacy, setPrivacy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.readCachedData)('me-privacy') || null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getMePrivacy)().then(p => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('me-privacy', p); setPrivacy(p); }).catch(() => {}); }, []); const update = (key, value) => { const prev = privacy; const nextMethods = { ...(privacy.add_me_methods || {}), [key]: value }; setPrivacy({ ...privacy, add_me_methods: nextMethods }); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.updateMePrivacy)({ add_me_methods: nextMethods, version: privacy.version }).then(p => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('me-privacy', p); setPrivacy(p); }).catch(err => { onToast(err.message || '保存失败'); setPrivacy(prev); (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('me-privacy', prev); }); }; const rows = [{ key: 'account', title: '账号' }, { key: 'phone', title: '手机号' }, { key: 'qr', title: '二维码' }, { key: 'group', title: '群聊' }]; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "添加我的方式", back: "privacy-settings" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { className: "privacy-list", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { className: "privacy-note", children: "关闭某种方式后,其他人将无法通过该渠道搜索或添加你。" }, void 0, false), privacy ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { children: rows.map(row => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("strong", { children: ["可通过", row.title, "添加我"] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Toggle, { checked: !!(privacy.add_me_methods || {})[row.key], onChange: v => update(row.key, v) }, void 0, false)] }, row.key, true)) }, void 0, false) : null] }, void 0, true)] }, void 0, true); } const YOUTH_RULES = [`为呵护未成年人健康成长,${_config_js__WEBPACK_IMPORTED_MODULE_4__.BASE_APP_NAME}推出青少年模式。该模式下部分功能将受限制使用`, '每天开启后使用时长不超过 40 分钟', '限制加好友/群聊次数(主动/被动加好友或群聊每日最多各 4 次)']; const YOUTH_USAGE_KEY = 'im-youth-mode-usage'; function useYouthUsageSeconds(active) { const [seconds, setSeconds] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(0); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { const today = new Date().toISOString().slice(0, 10); let stored = {}; try { stored = JSON.parse(window.localStorage.getItem(YOUTH_USAGE_KEY) || '{}'); } catch (_) {} if (stored.date !== today) stored = { date: today, seconds: 0 }; setSeconds(stored.seconds || 0); if (!active) return undefined; const timer = window.setInterval(() => { setSeconds(s => { const next = s + 1; window.localStorage.setItem(YOUTH_USAGE_KEY, JSON.stringify({ date: today, seconds: next })); return next; }); }, 1000); return () => window.clearInterval(timer); }, [active]); return seconds; } function formatHMS(totalSeconds) { const h = Math.floor(totalSeconds / 3600); const m = Math.floor(totalSeconds % 3600 / 60); const s = totalSeconds % 60; const pad = n => String(n).padStart(2, '0'); return `${pad(h)}:${pad(m)}:${pad(s)}`; } function YouthMode({ onToast }) { const [settings, setSettings] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.readCachedData)('youth-mode') || null); const usage = useYouthUsageSeconds(settings && settings.enabled); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { setSettings((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.readCachedData)('youth-mode') || null); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getYouthMode)().then(d => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('youth-mode', d); setSettings(d); }).catch(err => onToast(err.message || '加载失败')); }, []); const startEnable = () => { if (!settings) return; if (!settings.password_set) { onToast('请先设置独立密码'); window.setTimeout(() => navigate('identity-check'), 400); return; } navigate('youth-mode-verify', { ym: 'enable' }); }; if (!settings) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page youth-mode-page", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "青少年模式", back: "android-settings" }, void 0, false) }, void 0, false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page youth-mode-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: "青少年模式", back: "android-settings" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: settings.enabled ? 'verified_user' : 'child_care' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h2", { children: settings.enabled ? '青少年模式已开启' : '青少年模式未开启' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("ul", { children: YOUTH_RULES.map(rule => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("li", { children: rule }, rule, false)) }, void 0, false), settings.enabled ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { className: "youth-usage", children: ["今日已使用:", formatHMS(usage)] }, void 0, true) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("footer", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: settings.enabled ? 'outline' : '', onClick: () => settings.enabled ? navigate('youth-mode-verify', { ym: 'disable' }) : startEnable(), children: settings.enabled ? '关闭青少年模式' : '开启青少年模式' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: "可在设置中查看青少年模式状态" }, void 0, false)] }, void 0, true)] }, void 0, true); } function YouthModeVerify({ hashParams, onToast }) { const mode = hashParams && hashParams.ym || 'disable'; const [settings, setSettings] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [password, setPassword] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [error, setError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getYouthMode)().then(setSettings).catch(() => {}); }, []); const submit = () => { if (password.length !== 4) { setError('请输入4位独立密码'); return; } setBusy(true); setError(''); const action = mode === 'enable' ? 'enable_youth_mode' : 'close_youth_mode'; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.verifyIndependentPassword)(password, 'youth_mode', action).then(({ action_token }) => { const call = mode === 'enable' ? (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.enableYouthMode)(settings.policy_version, action_token) : (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.disableYouthMode)(action_token); return call; }).then(_ => { if (settings) (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('youth-mode', { ...settings, enabled: mode === 'enable' }); onToast(mode === 'enable' ? '青少年模式已开启' : '青少年模式已关闭'); window.setTimeout(() => navigate(mode === 'enable' ? 'youth-mode-on' : 'youth-mode-off'), 400); }).catch(err => setError(err.message || '验证失败')).finally(() => setBusy(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page youth-mode-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Header, { title: mode === 'enable' ? '开启青少年模式' : '关闭青少年模式', back: mode === 'enable' ? 'youth-mode-off' : 'youth-mode-on' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("main", { className: "youth-password-gate", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "auth-pin-boxes", "aria-hidden": "true", children: [0, 1, 2, 3].map(i => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: password[i] ? '●' : '' }, i, false)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", { className: "auth-pin-input", type: "text", inputMode: "numeric", autoComplete: "off", autoFocus: true, value: password, onChange: e => setPassword(e.target.value.replace(/\D/g, '').slice(0, 4)), "aria-label": "独立密码" }, void 0, false), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "auth-field-error", children: error }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: "auth-primary", disabled: password.length !== 4 || busy, onClick: submit, children: busy ? '验证中…' : '确定' }, void 0, false)] }, void 0, true)] }, void 0, true); } const PERMISSIONS = { notification: { icon: 'notifications_active', title: '获取推送权限', text: '向您及时送达重要通知、活动提醒、个性化内容更新等信息。', action: '开启通知', route: 'permission-settings-reminder' }, reminder: { icon: 'settings', title: '消息推送暂未开启', text: `前往【设置 - 通知管理】一键开启吧!`, action: '好的', secondaryAction: '暂不开启', route: 'android-settings' }, camera: { icon: 'photo_camera', title: '相机权限使用说明', text: '调用相机拍摄/扫码,为您提供拍照、扫码识别等服务。', action: '继续授权', route: 'messages-home' }, microphone: { icon: 'mic', title: '麦克风权限使用说明', text: '用于语音消息、语音输入和音视频通话,未授权时不会创建录音文件。', action: '继续授权', route: 'messages-home' } }; function PermissionGuide({ type, onToast }) { const config = PERMISSIONS[type]; const proceed = () => { if (type === 'notification' && 'Notification' in window) { Notification.requestPermission().then(() => navigate(config.route)); return; } onToast(type === 'reminder' ? '请前往系统设置开启通知' : '等待系统授权结果'); window.setTimeout(() => navigate(config.route), 500); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "personal-page permission-guide-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "permission-preview", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("header", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h1", { children: "消息" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: "menu" }, void 0, false)] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "permission-overlay", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", { role: "dialog", "aria-modal": "true", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, { children: config.icon }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h2", { children: config.title }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { children: config.text }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", onClick: proceed, children: config.action }, void 0, false), config.secondaryAction ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", onClick: () => navigate('messages-home'), children: config.secondaryAction }, void 0, false) : null] }, void 0, true) }, void 0, false)] }, void 0, true); } function PersonalSettingsView({ view, hashParams, myUserId, tinode, chatList, onUpdatePassword, onDeleteAccount, onLogout }) { const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); let content; if (view === 'personal-center') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(PersonalCenter, {}, void 0, false);else if (view === 'personal-profile') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(PersonalProfile, { onToast: setToast, tinode: tinode }, void 0, false);else if (view === 'profile-nickname') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(TextEditor, { field: "nickname", title: "设置昵称", onToast: setToast }, void 0, false);else if (view === 'profile-signature') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(TextEditor, { field: "signature", title: "个性签名", multiline: true, onToast: setToast }, void 0, false);else if (view === 'profile-birth-date') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(BirthDateEditor, { onToast: setToast }, void 0, false);else if (view === 'profile-gender') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(GenderEditor, { onToast: setToast }, void 0, false);else if (view === 'profile-region') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(RegionEditor, { onToast: setToast }, void 0, false);else if (view === 'personal-qrcode') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(PersonalQr, { onToast: setToast }, void 0, false);else if (view === 'android-settings') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(SettingsList, { onToast: setToast, onLogout: onLogout }, void 0, false);else if (view === 'cache-clear-confirm') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(CacheClear, { onToast: setToast }, void 0, false);else if (view === 'clear-history-confirm') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(ClearHistoryConfirm, { onToast: setToast, tinode: tinode, chatList: chatList }, void 0, false);else if (view === 'change-password') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(ChangePassword, { onToast: setToast, onUpdatePassword: onUpdatePassword }, void 0, false);else if (view === 'delete-account-confirm') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(DeleteAccountConfirm, { onToast: setToast, onDeleteAccount: onDeleteAccount }, void 0, false);else if (view === 'app-version') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(AppVersion, { onToast: setToast }, void 0, false);else if (view === 'privacy-settings') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(PrivacySettings, { onToast: setToast }, void 0, false);else if (view === 'friend-discovery-settings') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(FriendDiscoverySettings, { onToast: setToast }, void 0, false);else if (view === 'youth-mode-off' || view === 'youth-mode-on') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(YouthMode, { onToast: setToast }, void 0, false);else if (view === 'youth-mode-verify') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(YouthModeVerify, { hashParams: hashParams, onToast: setToast }, void 0, false);else content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(PermissionGuide, { type: view === 'notification-permission' ? 'notification' : view === 'permission-settings-reminder' ? 'reminder' : view === 'camera-permission-info' ? 'camera' : 'microphone', onToast: setToast }, void 0, false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.Fragment, { children: [content, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } /***/ }), /***/ "./src/views/security-support-view.jsx": /*!*********************************************!*\ !*** ./src/views/security-support-view.jsx ***! \*********************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ RiskConfirmDialog: function() { return /* binding */ RiskConfirmDialog; }, /* harmony export */ SECURITY_SUPPORT_VIEWS: function() { return /* binding */ SECURITY_SUPPORT_VIEWS; }, /* harmony export */ "default": function() { return /* binding */ SecuritySupportView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var _lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/use-cached-data.js */ "./src/lib/use-cached-data.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const navigate = (view, params) => { let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__["default"].setUrlSidePanel(window.location.hash, view); Object.entries(params || {}).forEach(([key, value]) => { hash = value ? _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__["default"].addUrlParam(hash, key, value) : _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__["default"].removeUrlParam(hash, key); }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__["default"].navigateTo(hash); }; const SECURITY_SUPPORT_VIEWS = ['fraud-risk-warning', 'fraud-risk-confirmation', 'abuse-report-reasons', 'abuse-report-details', 'user-feedback']; function Icon({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("i", { className: "material-icons", "aria-hidden": "true", children: children }, void 0, false); } function Header({ title, back }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("header", { className: "support-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", onClick: () => { if (!_lib_navigation_js__WEBPACK_IMPORTED_MODULE_1__["default"].goBack()) navigate(back); }, "aria-label": "返回", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h1", { children: title }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", {}, void 0, false)] }, void 0, true); } function Toast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 2200); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "support-toast", role: "status", children: message }, void 0, false) : null; } function FraudAwareness({ secondary }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "support-page risk-warning-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Header, { title: "安全提醒", back: secondary ? 'fraud-risk-warning' : 'personal-center' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("main", { className: "risk-info-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { className: "risk-symbol", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: secondary ? 'warning_amber' : 'shield_lock' }, void 0, false) }, void 0, false), secondary ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", { className: "risk-emphasis", children: "您发送的内容可能涉及诈骗风险,请注意甄别。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", { children: "切勿轻信陌生人的投资理财、兼职刷单、网络贷款等信息,谨防上当受骗。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("aside", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "phone_in_talk" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: "如遇诈骗请立即拨打 110 报警。" }, void 0, false)] }, void 0, true)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", { children: "为保障您的账号及资金安全,请您注意:" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("ul", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "receipt_long" }, void 0, false), "不参与刷单返利活动"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "currency_yuan" }, void 0, false), "不轻信高收益投资、理财信息"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "person_off" }, void 0, false), "不出租、出借、出售账号及实名信息"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "lock" }, void 0, false), "不向任何人泄露验证码、密码等敏感信息"] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", { className: "risk-emphasis", children: "请提高安全防范意识,谨防电信网络诈骗。" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", className: "primary", onClick: () => navigate(secondary ? 'fraud-risk-warning' : 'personal-center'), children: secondary ? '我已知晓' : '我已阅读并知晓' }, void 0, false)] }, void 0, true)] }, void 0, true); } function RiskConfirmDialog({ level, blocked, onConfirm, onCancel }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "risk-overlay", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("section", { className: "risk-dialog secondary", role: "alertdialog", "aria-modal": "true", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { className: "risk-symbol", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: blocked ? 'block' : 'warning_amber' }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h2", { children: "安全提醒" }, void 0, false), blocked ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", { className: "risk-emphasis", children: "检测到该内容存在较高安全风险,暂无法发送。" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", { className: "risk-emphasis", children: "您发送的内容可能涉及诈骗风险,请注意甄别。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", { children: "切勿轻信陌生人的投资理财、兼职刷单、网络贷款等信息,谨防上当受骗。如遇诈骗请立即拨打 110 报警。" }, void 0, false)] }, void 0, true), blocked ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", onClick: onCancel, children: "我已知晓" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", className: "danger", onClick: onConfirm, children: "我已知晓,继续发送" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", onClick: onCancel, children: "取消发送" }, void 0, false)] }, void 0, true)] }, void 0, true) }, void 0, false); } function ReportReasons({ hashParams, onToast }) { const targetType = hashParams && hashParams.target_type || 'user'; const targetName = hashParams && hashParams.target_name || ''; const [reasons, setReasons] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.getAbuseReasons)(targetType).then(data => setReasons(Array.isArray(data) ? data : data && (data.reasons || data.items) || [])).catch(err => { onToast(err.message || '加载失败'); setReasons([]); }); }, [targetType]); const select = reason => navigate('abuse-report-details', { ...hashParams, reason_code: reason.reason_code || reason.code, reason_label: reason.label, requires_description: reason.requires_description ? '1' : '' }); {} return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "support-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Header, { title: "举报", back: "messages-home" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("main", { className: "report-reasons", children: [targetName ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("section", { className: "report-target", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "account_circle" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", { children: ["举报", targetName] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("small", { children: "举报人身份不会向对方公开" }, void 0, false)] }, void 0, true)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h2", { children: "请选择举报原因" }, void 0, false), reasons === null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", { className: "report-loading", children: "加载中…" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("section", { className: "report-reason-list", children: reasons.map(reason => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", onClick: () => select(reason), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", { children: reason.label }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, reason.reason_code || reason.code, true)) }, void 0, false)] }, void 0, true)] }, void 0, true); } function ReportDetails({ hashParams, tinode, onToast }) { const reasonLabel = hashParams && hashParams.reason_label || ''; const reasonCode = hashParams && hashParams.reason_code || ''; const requiresDescription = (hashParams && hashParams.requires_description) === '1'; const [description, setDescription] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [evidence, setEvidence] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [uploading, setUploading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [submitting, setSubmitting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [submitted, setSubmitted] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const fileInputRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); const addEvidence = event => { const file = event.target.files && event.target.files[0]; event.target.value = ''; if (!file || !tinode) return; if (evidence.length >= 9) { onToast('最多上传 9 个证据文件'); return; } setUploading(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.uploadLargeFile)(tinode, file).then(({ fileId }) => setEvidence(items => items.concat({ id: fileId, name: file.name }))).catch(err => onToast(err.message || '上传失败')).finally(() => setUploading(false)); }; const submit = () => { if (requiresDescription && !description.trim()) { onToast('请补充问题描述'); return; } const target = { type: hashParams.target_type || 'user' }; if (hashParams.target_type === 'message') { target.topic = hashParams.topic; target.seq = String(hashParams.seq); } else if (hashParams.target_type === 'group') { target.topic = hashParams.topic || hashParams.target_id; } else { target.user_id = hashParams.target_id; } setSubmitting(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.submitAbuseReport)({ target, reason_code: reasonCode, description: description.trim(), evidence_file_ids: evidence.map(e => e.id) }).then(result => setSubmitted(result)).catch(err => onToast(err.message || '提交失败')).finally(() => setSubmitting(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "support-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Header, { title: "举报", back: "abuse-report-reasons" }, void 0, false), submitted ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("main", { className: "support-success", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "task_alt" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h2", { children: "举报已受理" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", { children: "我们会依据平台规则核实处理,举报人身份不会向被举报方公开。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("dl", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("dt", { children: "受理编号" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("dd", { children: submitted.report_id }, void 0, false)] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", onClick: () => navigate('messages-home'), children: "完成" }, void 0, false)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("main", { className: "report-details", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("section", { className: "report-selected-reason", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("small", { children: "举报原因" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", { children: reasonLabel }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", onClick: () => navigate('abuse-report-reasons', hashParams), children: "修改" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { className: "support-textarea", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: ["问题描述", requiresDescription ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("b", { children: "*" }, void 0, false) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("textarea", { value: description, maxLength: "500", onChange: event => setDescription(event.target.value), placeholder: "请描述具体情况、发生时间和相关行为" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("small", { children: [description.length, "/500"] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("section", { className: "evidence-section", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("header", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", { children: "证据材料" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("small", { children: "图片或文件,最多 9 个" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("em", { children: [evidence.length, "/9"] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { children: [evidence.map(file => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("article", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "image" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: file.name }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", onClick: () => setEvidence(items => items.filter(item => item.id !== file.id)), "aria-label": "删除证据", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "close" }, void 0, false) }, void 0, false)] }, file.id, true)), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", className: "evidence-upload", disabled: uploading, onClick: () => fileInputRef.current && fileInputRef.current.click(), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "add_photo_alternate" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: uploading ? '上传中…' : '添加证据' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", { ref: fileInputRef, type: "file", accept: "image/*", style: { display: 'none' }, onChange: addEvidence }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("aside", { className: "report-privacy-note", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "lock" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: "证据仅用于平台审核,将按照安全策略保存和访问。" }, void 0, false)] }, void 0, true)] }, void 0, true), !submitted ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("footer", { className: "support-submit-bar", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", disabled: submitting, onClick: submit, children: submitting ? '提交中…' : '提交举报' }, void 0, false) }, void 0, false) : null] }, void 0, true); } function UserFeedback({ tinode, onToast }) { const cachedFeedbackConfig = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.readCachedData)('feedback-config'); const [config, setConfig] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => cachedFeedbackConfig || null); const [category, setCategory] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => cachedFeedbackConfig && cachedFeedbackConfig.categories && cachedFeedbackConfig.categories[0] || ''); const [content, setContent] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [images, setImages] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [uploading, setUploading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [diagnostics, setDiagnostics] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [submitting, setSubmitting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [submitted, setSubmitted] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const fileInputRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); const maxFiles = config && config.attachment_policy && config.attachment_policy.max_files || 5; const maxLength = config && config.max_length || 300; react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.getFeedbackConfig)().then(data => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_3__.writeCachedData)('feedback-config', data); setConfig(data); setCategory(data.categories && data.categories[0] || 'other'); }).catch(() => {}); }, []); const CATEGORY_LABELS = { bug: '功能异常', suggestion: '产品建议', complaint: '服务投诉', other: '其他' }; const addImage = event => { const file = event.target.files && event.target.files[0]; event.target.value = ''; if (!file || !tinode) return; if (images.length >= maxFiles) { onToast(`最多上传 ${maxFiles} 张图片`); return; } setUploading(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.uploadLargeFile)(tinode, file).then(({ fileId }) => setImages(items => items.concat({ id: fileId }))).catch(err => onToast(err.message || '上传失败')).finally(() => setUploading(false)); }; const submit = () => { if (!content.trim()) { onToast('请填写反馈内容'); return; } setSubmitting(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.submitFeedback)({ category, content: content.trim(), attachment_file_ids: images.map(i => i.id), include_diagnostics: diagnostics }).then(result => setSubmitted(result)).catch(err => onToast(err.message || '提交失败')).finally(() => setSubmitting(false)); }; if (submitted) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "support-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Header, { title: "意见反馈", back: "personal-center" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("main", { className: "support-success", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "mark_email_read" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h2", { children: "反馈已受理" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", { children: "感谢你的反馈,我们会尽快查看并用于改进产品。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("dl", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("dt", { children: "反馈编号" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("dd", { children: submitted.feedback_id }, void 0, false)] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", onClick: () => navigate('personal-center'), children: "返回我的" }, void 0, false)] }, void 0, true)] }, void 0, true); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "support-page feedback-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Header, { title: "意见反馈", back: "personal-center" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("main", { children: [config && config.categories && config.categories.length > 1 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("section", { className: "feedback-categories", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h2", { children: "反馈类型" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { children: config.categories.map(id => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", className: category === id ? 'active' : '', onClick: () => setCategory(id), children: CATEGORY_LABELS[id] || id }, id, false)) }, void 0, false)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { className: "support-textarea", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: ["问题反馈", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("b", { children: "*" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("textarea", { value: content, maxLength: maxLength, onChange: event => setContent(event.target.value), placeholder: "为了更好的帮您解决问题,请在提交问题时上传截图信息,方便我们更快速的帮助您解决问题。" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("small", { children: [content.length, "/", maxLength] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("section", { className: "feedback-upload", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("header", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", { children: "图片" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("em", { children: [images.length, "/", maxFiles] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", disabled: uploading, onClick: () => fileInputRef.current && fileInputRef.current.click(), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Icon, { children: "add_a_photo" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: uploading ? '上传中…' : '点击上传' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", { ref: fileInputRef, type: "file", accept: "image/*", style: { display: 'none' }, onChange: addImage }, void 0, false)] }, void 0, true), config && config.diagnostics_notice ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { className: "diagnostics-consent", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", { type: "checkbox", checked: diagnostics, onChange: event => setDiagnostics(event.target.checked) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("strong", { children: "同意上传脱敏诊断信息" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("small", { children: config.diagnostics_notice }, void 0, false)] }, void 0, true)] }, void 0, true) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("footer", { className: "support-submit-bar", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "button", disabled: submitting, onClick: submit, children: submitting ? '提交中…' : '提交' }, void 0, false) }, void 0, false)] }, void 0, true); } function SecuritySupportView({ view, hashParams, tinode }) { const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); let content; if (view === 'fraud-risk-warning' || view === 'fraud-risk-confirmation') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(FraudAwareness, { secondary: view === 'fraud-risk-confirmation' }, void 0, false);else if (view === 'abuse-report-reasons') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(ReportReasons, { hashParams: hashParams, onToast: setToast }, void 0, false);else if (view === 'abuse-report-details') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(ReportDetails, { hashParams: hashParams, tinode: tinode, onToast: setToast }, void 0, false);else content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(UserFeedback, { tinode: tinode, onToast: setToast }, void 0, false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.Fragment, { children: [content, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } /***/ }), /***/ "./src/views/settings-view.jsx": /*!*************************************!*\ !*** ./src/views/settings-view.jsx ***! \*************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ SettingsView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _widgets_host_selector_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/host-selector.jsx */ "./src/widgets/host-selector.jsx"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class SettingsView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { transport: props.transport || 'def', serverAddress: props.serverAddress, secureConnection: props.secureConnection }; this.handleSubmit = this.handleSubmit.bind(this); this.handleTransportSelected = this.handleTransportSelected.bind(this); this.handleServerAddressChange = this.handleServerAddressChange.bind(this); this.handleToggleSecure = this.handleToggleSecure.bind(this); } handleSubmit(e) { e.preventDefault(); this.props.onUpdate({ transport: this.state.transport, serverAddress: this.state.serverAddress, secureConnection: this.state.secureConnection }); } handleTransportSelected(e) { this.setState({ transport: e.currentTarget.value }); } handleServerAddressChange(name) { this.setState({ serverAddress: name }); } handleToggleSecure(e) { this.setState({ secureConnection: !this.state.secureConnection }); } render() { const names = { def: "default", ws: "websocket", lp: "long polling" }; const transportOptions = []; ['def', 'ws', 'lp'].forEach(item => { const id = 'transport-' + item; const name = names[item]; transportOptions.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", { type: "radio", id: id, name: "transport-select", value: item, checked: this.state.transport === item, onChange: this.handleTransportSelected }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { htmlFor: id, children: name }, void 0, false)] }, item, true)); }); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("form", { id: "settings-form", className: "panel-form", onSubmit: this.handleSubmit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_server_to_use", defaultMessage: "Server to use:", description: "Label for server selector in SettingsView" }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(_widgets_host_selector_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { serverAddress: this.state.serverAddress, onServerAddressChange: this.handleServerAddressChange }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { id: "secure-connection", name: "secure-connection", checked: this.state.secureConnection, className: "quoted", onChange: this.handleToggleSecure }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { htmlFor: "secure-connection", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_use_secure_connection", defaultMessage: "Use secure connection", description: "Label for WS/WSS connection type in SettingsView" }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_wire_transport", defaultMessage: "Wire transport:", description: "Label for wire transport selection in SettingsView" }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("ul", { className: "quoted", children: transportOptions }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "dialog-buttons", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { type: "submit", className: "primary", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_update", defaultMessage: "Update", description: "Button [Update]" }, void 0, false) }, void 0, false) }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/views/sidepanel-view.jsx": /*!**************************************!*\ !*** ./src/views/sidepanel-view.jsx ***! \**************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/error-panel.jsx */ "./src/widgets/error-panel.jsx"); /* harmony import */ var _widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/load-spinner.jsx */ "./src/widgets/load-spinner.jsx"); /* harmony import */ var _widgets_side_navbar_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/side-navbar.jsx */ "./src/widgets/side-navbar.jsx"); /* harmony import */ var _topic_common_view_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./topic-common-view.jsx */ "./src/views/topic-common-view.jsx"); /* harmony import */ var _auth_onboarding_view_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./auth-onboarding-view.jsx */ "./src/views/auth-onboarding-view.jsx"); /* harmony import */ var _message_center_view_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./message-center-view.jsx */ "./src/views/message-center-view.jsx"); /* harmony import */ var _direct_message_view_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./direct-message-view.jsx */ "./src/views/direct-message-view.jsx"); /* harmony import */ var _message_composer_view_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./message-composer-view.jsx */ "./src/views/message-composer-view.jsx"); /* harmony import */ var _contact_management_view_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./contact-management-view.jsx */ "./src/views/contact-management-view.jsx"); /* harmony import */ var _group_management_view_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./group-management-view.jsx */ "./src/views/group-management-view.jsx"); /* harmony import */ var _content_library_view_jsx__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./content-library-view.jsx */ "./src/views/content-library-view.jsx"); /* harmony import */ var _call_experience_view_jsx__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./call-experience-view.jsx */ "./src/views/call-experience-view.jsx"); /* harmony import */ var _workplace_collaboration_view_jsx__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./workplace-collaboration-view.jsx */ "./src/views/workplace-collaboration-view.jsx"); /* harmony import */ var _personal_settings_view_jsx__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./personal-settings-view.jsx */ "./src/views/personal-settings-view.jsx"); /* harmony import */ var _security_support_view_jsx__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./security-support-view.jsx */ "./src/views/security-support-view.jsx"); /* harmony import */ var _contacts_view_jsx__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./contacts-view.jsx */ "./src/views/contacts-view.jsx"); /* harmony import */ var _acc_general_view_jsx__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./acc-general-view.jsx */ "./src/views/acc-general-view.jsx"); /* harmony import */ var _acc_notifications_view_jsx__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./acc-notifications-view.jsx */ "./src/views/acc-notifications-view.jsx"); /* harmony import */ var _acc_support_view_jsx__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./acc-support-view.jsx */ "./src/views/acc-support-view.jsx"); /* harmony import */ var _login_view_jsx__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./login-view.jsx */ "./src/views/login-view.jsx"); /* harmony import */ var _new_topic_view_jsx__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./new-topic-view.jsx */ "./src/views/new-topic-view.jsx"); /* harmony import */ var _settings_view_jsx__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ./settings-view.jsx */ "./src/views/settings-view.jsx"); /* harmony import */ var _validation_view_jsx__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ./validation-view.jsx */ "./src/views/validation-view.jsx"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const AccountSettingsView = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => Promise.all(/*! import() */[__webpack_require__.e("vendors-node_modules_libphonenumber-js_mobile_exports_parsePhoneNumberWithError_js"), __webpack_require__.e("vendors-node_modules_libphonenumber-js_examples_mobile_json_js-node_modules_libphonenumber-js-883e54"), __webpack_require__.e("src_widgets_phone-edit_jsx"), __webpack_require__.e("src_views_account-settings-view_jsx")]).then(__webpack_require__.bind(__webpack_require__, /*! ./account-settings-view.jsx */ "./src/views/account-settings-view.jsx"))); const CreateAccountView = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => Promise.all(/*! import() */[__webpack_require__.e("vendors-node_modules_libphonenumber-js_mobile_exports_parsePhoneNumberWithError_js"), __webpack_require__.e("vendors-node_modules_libphonenumber-js_examples_mobile_json_js-node_modules_libphonenumber-js-883e54"), __webpack_require__.e("src_widgets_phone-edit_jsx"), __webpack_require__.e("src_views_create-account-view_jsx")]).then(__webpack_require__.bind(__webpack_require__, /*! ./create-account-view.jsx */ "./src/views/create-account-view.jsx"))); const AccSecurityView = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => __webpack_require__.e(/*! import() */ "src_views_acc-security-view_jsx").then(__webpack_require__.bind(__webpack_require__, /*! ./acc-security-view.jsx */ "./src/views/acc-security-view.jsx"))); const PasswordResetView = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => Promise.all(/*! import() */[__webpack_require__.e("vendors-node_modules_libphonenumber-js_mobile_exports_parsePhoneNumberWithError_js"), __webpack_require__.e("vendors-node_modules_libphonenumber-js_examples_mobile_json_js-node_modules_libphonenumber-js-883e54"), __webpack_require__.e("src_widgets_phone-edit_jsx"), __webpack_require__.e("src_views_password-reset-view_jsx")]).then(__webpack_require__.bind(__webpack_require__, /*! ./password-reset-view.jsx */ "./src/views/password-reset-view.jsx"))); const WallpapersView = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => __webpack_require__.e(/*! import() */ "src_views_wallpapers_jsx").then(__webpack_require__.bind(__webpack_require__, /*! ./wallpapers.jsx */ "./src/views/wallpapers.jsx"))); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ login: { id: 'sidepanel_title_login', description: 'Sidepanel title for LoginView.', defaultMessage: 'Sign In' }, register: { id: 'sidepanel_title_register', description: 'Sidepanel title for CreateAccountView.', defaultMessage: 'Create Account' }, settings: { id: 'sidepanel_title_settings', description: 'Sidepanel title for SettingsView.', defaultMessage: 'Settings' }, edit: { id: 'sidepanel_title_account_settings', description: 'Sidepanel title for AccountSettingsView.', defaultMessage: 'Account Settings' }, general: { id: 'panel_title_general', description: 'Title for TopicCommon.', defaultMessage: 'General' }, security: { id: 'panel_title_security', description: 'Title for TopicSecirity and AccSecurity.', defaultMessage: 'Security' }, crop: { id: 'panel_title_crop', description: 'Title for AvatarCropView.', defaultMessage: 'Drag to Adjust' }, notif: { id: 'sidepanel_title_acc_notifications', description: 'Sidepanel title for AccNotificationsView.', defaultMessage: 'Notifications' }, acc_general: { id: 'sidepanel_title_acc_general', description: 'Sidepanel title for AccGeneralView.', defaultMessage: 'General' }, support: { id: 'sidepanel_title_acc_support', description: 'Sidepanel title for AccSupportView.', defaultMessage: 'Support' }, newtpk: { id: 'sidepanel_title_newtpk', description: 'Sidepanel title for NewTopicView.', defaultMessage: 'Start New Chat' }, cred: { id: 'sidepanel_title_cred', description: 'Sidepanel title for ValidationView.', defaultMessage: 'Confirm Credentials' }, reset: { id: 'sidepanel_title_reset', description: 'Sidepanel title for PasswordResetView.', defaultMessage: 'Reset Password' }, archive: { id: 'sidepanel_title_archive', description: 'Sidepanel title for ContactsView-Archive.', defaultMessage: 'Archived Chats' }, blocked: { id: 'sidepanel_title_blocked', description: 'Sidepanel title for ContactsView-Blocked.', defaultMessage: 'Blocked Chats' }, wallpapers: { id: 'wallpapers', description: 'Link or title for working with wallpapers.', defaultMessage: 'Wallpapers' } }); class SidepanelView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleNewTopic = this.handleNewTopic.bind(this); } handleNewTopic() { this.props.onNavigate('newtpk'); } render() { const { formatMessage } = this.props.intl; const view = this.props.state || (this.props.myUserId ? 'messages-home' : 'tenant'); const chapterOneViews = ['tenant', 'login', 'enterprise-register', 'enterprise-feedback', 'register', 'reset', 'identity-check', 'realname', 'realname-verified', 'realname-reminder', 'independent-password']; if (chapterOneViews.includes(view)) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", className: "auth-onboarding-panel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_auth_onboarding_view_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { view: view, authenticated: !!this.props.myUserId, login: this.props.login, loginDisabled: this.props.loginDisabled, persist: this.props.persist, errorText: this.props.errorText, errorLevel: this.props.errorLevel, onLoginRequest: this.props.onLoginRequest, onPersistenceChange: this.props.onPersistenceChange, onCreateAccount: this.props.onCreateAccount, onImRegisterRequest: this.props.onImRegisterRequest, onTenantResolved: this.props.onTenantResolved, onError: this.props.onError }, void 0, false) }, void 0, false); } const chapterTwoViews = ['messages-home', 'messages-offline', 'messages-menu', 'message-actions', 'system-messages']; if (chapterTwoViews.includes(view)) { const fullPage = !this.props.myUserId || view !== 'messages-home'; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", className: 'message-center-panel' + (fullPage ? ' full-page' : ''), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_message_center_view_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], { view: view, connected: this.props.connected, chatList: this.props.chatList, myUserId: this.props.myUserId, onTopicSelected: this.props.onTopicSelected, onOpenScanner: this.props.onOpenScanner }, void 0, false) }, void 0, false); } const chapterThreeViews = ['chat-inbound-request', 'chat-inbound-message', 'chat-outbound-request', 'chat-status', 'chat-friend', 'chat-media', 'chat-blocked', 'chat-deleted', 'chat-standard', 'chat-attachments', 'chat-mixed', 'chat-contact-card']; if (chapterThreeViews.includes(view)) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", className: "direct-message-panel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_direct_message_view_jsx__WEBPACK_IMPORTED_MODULE_8__["default"], { view: view }, view, false) }, void 0, false); } if (_message_composer_view_jsx__WEBPACK_IMPORTED_MODULE_9__.MESSAGE_COMPOSER_VIEWS.includes(view)) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", className: "message-composer-panel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_message_composer_view_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { view: view }, view, false) }, void 0, false); } if (_contact_management_view_jsx__WEBPACK_IMPORTED_MODULE_10__.CONTACT_MANAGEMENT_VIEWS.includes(view)) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", className: "contact-management-panel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_contact_management_view_jsx__WEBPACK_IMPORTED_MODULE_10__["default"], { view: view, hashParams: this.props.hashParams, myUserId: this.props.myUserId, tinode: this.props.tinode, onTopicSelected: this.props.onTopicSelected, onOpenScanner: this.props.onOpenScanner }, view, false) }, void 0, false); } if (_group_management_view_jsx__WEBPACK_IMPORTED_MODULE_11__.GROUP_MANAGEMENT_VIEWS.includes(view)) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", className: "group-management-panel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_group_management_view_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], { view: view, hashParams: this.props.hashParams, myUserId: this.props.myUserId, tinode: this.props.tinode, onTopicSelected: this.props.onTopicSelected }, view, false) }, void 0, false); } if (_content_library_view_jsx__WEBPACK_IMPORTED_MODULE_12__.CONTENT_LIBRARY_VIEWS.includes(view)) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", className: "content-library-panel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_content_library_view_jsx__WEBPACK_IMPORTED_MODULE_12__["default"], { view: view, hashParams: this.props.hashParams, myUserId: this.props.myUserId, tinode: this.props.tinode, onTopicSelected: this.props.onTopicSelected, chatList: this.props.chatList }, view, false) }, void 0, false); } if (_call_experience_view_jsx__WEBPACK_IMPORTED_MODULE_13__.CALL_EXPERIENCE_VIEWS.includes(view)) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", className: "call-experience-panel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_call_experience_view_jsx__WEBPACK_IMPORTED_MODULE_13__["default"], { view: view }, view, false) }, void 0, false); } if (_workplace_collaboration_view_jsx__WEBPACK_IMPORTED_MODULE_14__.WORKPLACE_COLLABORATION_VIEWS.includes(view)) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", className: "workplace-collaboration-panel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_workplace_collaboration_view_jsx__WEBPACK_IMPORTED_MODULE_14__["default"], { view: view, hashParams: this.props.hashParams, myUserId: this.props.myUserId, tinode: this.props.tinode, onTopicSelected: this.props.onTopicSelected }, view, false) }, void 0, false); } if (_personal_settings_view_jsx__WEBPACK_IMPORTED_MODULE_15__.PERSONAL_SETTINGS_VIEWS.includes(view)) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", className: "personal-settings-panel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_personal_settings_view_jsx__WEBPACK_IMPORTED_MODULE_15__["default"], { view: view, hashParams: this.props.hashParams, myUserId: this.props.myUserId, tinode: this.props.tinode, chatList: this.props.chatList, onUpdatePassword: this.props.onUpdatePassword, onDeleteAccount: this.props.onDeleteAccount, onLogout: this.props.onLogout }, view, false) }, void 0, false); } if (_security_support_view_jsx__WEBPACK_IMPORTED_MODULE_16__.SECURITY_SUPPORT_VIEWS.includes(view)) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", className: "security-support-panel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_security_support_view_jsx__WEBPACK_IMPORTED_MODULE_16__["default"], { view: view, hashParams: this.props.hashParams, tinode: this.props.tinode }, view, false) }, void 0, false); } let title, avatar, badges; if (view == 'contacts') { title = this.props.title; avatar = this.props.avatar ? this.props.avatar : true; badges = this.props.trustedBadges; } else { title = formatMessage(messages[view]); avatar = false; badges = null; } let onCancel; if (['login', 'contacts'].indexOf(view) == -1) { onCancel = this.props.onCancel; } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { id: "sidepanel", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_widgets_side_navbar_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { state: view, title: title, avatar: avatar, tinode: this.props.tinode, trustedBadges: badges, myUserId: this.props.myUserId, onSignUp: this.props.onSignUp, onSettings: this.props.onSettings, onNewTopic: this.handleNewTopic, onCancel: onCancel }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { level: this.props.errorLevel, text: this.props.errorText, action: this.props.errorAction, actionText: this.props.errorActionText, onClearError: this.props.onError }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { show: this.props.loadSpinnerVisible }, void 0, false), view === 'login' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_login_view_jsx__WEBPACK_IMPORTED_MODULE_21__["default"], { login: this.props.login, disabled: this.props.loginDisabled, persist: this.props.persist, onLogin: this.props.onLoginRequest, onPersistenceChange: this.props.onPersistenceChange }, void 0, false) : view === 'register' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: "Loading...", description: "Message shown when component is loading" }, void 0, false) }, void 0, false), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(CreateAccountView, { tinode: this.props.tinode, reqCredMethod: this.props.reqCredMethod, onShowCountrySelector: this.props.onShowCountrySelector, onCreateAccount: this.props.onCreateAccount, onCancel: this.props.onCancel, onError: this.props.onError }, void 0, false) }, void 0, false) : view === 'settings' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_settings_view_jsx__WEBPACK_IMPORTED_MODULE_23__["default"], { transport: this.props.transport, serverAddress: this.props.serverAddress, secureConnection: this.props.secureConnection, onCancel: this.props.onCancel, onUpdate: this.props.onGlobalSettings }, void 0, false) : view === 'edit' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: "Loading...", description: "Message shown when component is loading" }, void 0, false) }, void 0, false), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(AccountSettingsView, { tinode: this.props.tinode, myUserId: this.props.myUserId, trustedBadges: this.props.trustedBadges, reqCredMethod: this.props.reqCredMethod, onShowCountrySelector: this.props.onShowCountrySelector, onNavigate: this.props.onNavigate, onCredAdd: this.props.onCredAdd, onCredDelete: this.props.onCredDelete, onCredConfirm: this.props.onCredConfirm, onError: this.props.onError }, void 0, false) }, void 0, false) : view === 'general' || view === 'crop' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_topic_common_view_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { topic: "me", tinode: this.props.tinode, myUserId: this.props.myUserId, reqCredMethod: this.props.reqCredMethod, onUpdateTopicDesc: this.props.onUpdateAccountDesc, onUpdateTagsRequest: this.props.onUpdateAccountTags, onError: this.props.onError }, void 0, false) : view === 'acc_general' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_acc_general_view_jsx__WEBPACK_IMPORTED_MODULE_18__["default"], { colorSchema: this.props.colorSchema, onSelectWallpapers: this.props.onSelectWallpapers, textSize: this.props.textSize, sendOnEnter: this.props.sendOnEnter, onChangeColorSchema: this.props.onChangeColorSchema, onTextSizeChanged: this.props.onTextSizeChanged, onSendOnEnterChanged: this.props.onSendOnEnterChanged }, void 0, false) : view === 'notif' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_acc_notifications_view_jsx__WEBPACK_IMPORTED_MODULE_19__["default"], { messageSounds: this.props.messageSounds, desktopAlerts: this.props.desktopAlerts, desktopAlertsEnabled: this.props.desktopAlertsEnabled, onTogglePushNotifications: this.props.onTogglePushNotifications, onToggleMessageSounds: this.props.onToggleMessageSounds }, void 0, false) : view === 'security' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: "Loading...", description: "Message shown when component is loading" }, void 0, false) }, void 0, false), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(AccSecurityView, { tinode: this.props.tinode, incognitoMode: this.props.incognitoMode, onNavigate: this.props.onNavigate, onUpdateAccountDesc: this.props.onUpdateAccountDesc, onUpdatePassword: this.props.onUpdatePassword, onLogout: this.props.onLogout, onDeleteAccount: this.props.onDeleteAccount, onShowAlert: this.props.onShowAlert, onShowBlocked: this.props.onShowBlocked, onToggleIncognitoMode: this.props.onToggleIncognitoMode }, void 0, false) }, void 0, false) : view === 'support' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_acc_support_view_jsx__WEBPACK_IMPORTED_MODULE_20__["default"], { serverAddress: this.props.serverAddress, serverVersion: this.props.serverVersion }, void 0, false) : view === 'wallpapers' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: "Loading...", description: "Message shown when component is loading" }, void 0, false) }, void 0, false), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(WallpapersView, { wallpaper: this.props.wallpaper, wallpaperSize: this.props.wallpaperSize, wallpaperBlur: this.props.wallpaperBlur, colorSchema: this.props.colorSchema !== 'auto' ? this.props.colorSchema : this.props.systemColorSchema, onWallpaperSelected: this.props.onWallpaperSelected }, void 0, false) }, void 0, false) : view === 'contacts' || view == 'archive' || view == 'blocked' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_contacts_view_jsx__WEBPACK_IMPORTED_MODULE_17__["default"], { tinode: this.props.tinode, myUserId: this.props.myUserId, connected: this.props.connected, topicSelected: this.props.topicSelected, archive: view == 'archive', blocked: view == 'blocked', chatList: this.props.chatList, showContextMenu: this.props.showContextMenu, onTopicSelected: this.props.onTopicSelected, onShowArchive: this.props.onShowArchive }, void 0, false) : view === 'newtpk' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_new_topic_view_jsx__WEBPACK_IMPORTED_MODULE_22__["default"], { tinode: this.props.tinode, searchResults: this.props.searchResults, onInitFind: this.props.onInitFind, onSearchContacts: this.props.onSearchContacts, onCreateTopic: this.props.onCreateTopic, onError: this.props.onError }, void 0, false) : view === 'cred' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_validation_view_jsx__WEBPACK_IMPORTED_MODULE_24__["default"], { credCode: this.props.credCode, credMethod: this.props.credMethod, credToken: this.props.credToken, onSubmit: this.props.onValidateCredentials, onCancel: this.props.onCancel }, void 0, false) : view === 'reset' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: "Loading...", description: "Message shown when component is loading" }, void 0, false) }, void 0, false), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(PasswordResetView, { tinode: this.props.tinode, reqCredMethod: this.props.reqCredMethod, onShowCountrySelector: this.props.onShowCountrySelector, onRequest: this.props.onPasswordResetRequest, onReset: this.props.onResetPassword, onCancel: this.props.onCancel, onError: this.props.onError }, void 0, false) }, void 0, false) : null] }, void 0, true); } } ; /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(SidepanelView)); /***/ }), /***/ "./src/views/tinode-web.jsx": /*!**********************************!*\ !*** ./src/views/tinode-web.jsx ***! \**********************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var firebase_app__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! firebase/app */ "./node_modules/firebase/app/dist/esm/index.esm.js"); /* harmony import */ var firebase_messaging__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! firebase/messaging */ "./node_modules/firebase/messaging/dist/esm/index.esm.js"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_4__); /* harmony import */ var _widgets_alert_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/alert.jsx */ "./src/widgets/alert.jsx"); /* harmony import */ var _widgets_context_menu_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/context-menu.jsx */ "./src/widgets/context-menu.jsx"); /* harmony import */ var _widgets_forward_dialog_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../widgets/forward-dialog.jsx */ "./src/widgets/forward-dialog.jsx"); /* harmony import */ var _widgets_batch_forward_dialog_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../widgets/batch-forward-dialog.jsx */ "./src/widgets/batch-forward-dialog.jsx"); /* harmony import */ var _widgets_call_incoming_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../widgets/call-incoming.jsx */ "./src/widgets/call-incoming.jsx"); /* harmony import */ var _widgets_qr_scanner_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../widgets/qr-scanner.jsx */ "./src/widgets/qr-scanner.jsx"); /* harmony import */ var _sidepanel_view_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./sidepanel-view.jsx */ "./src/views/sidepanel-view.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); /* harmony import */ var _version_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../version.js */ "./src/version.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../lib/host-name.js */ "./src/lib/host-name.js"); /* harmony import */ var _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../lib/local-storage.js */ "./src/lib/local-storage.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var _lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../lib/use-cached-data.js */ "./src/lib/use-cached-data.js"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const PhoneCountrySelector = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => __webpack_require__.e(/*! import() */ "src_widgets_phone-country-selector_jsx").then(__webpack_require__.bind(__webpack_require__, /*! ../widgets/phone-country-selector.jsx */ "./src/widgets/phone-country-selector.jsx"))); const InfoView = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => __webpack_require__.e(/*! import() */ "src_views_info-view_jsx").then(__webpack_require__.bind(__webpack_require__, /*! ./info-view.jsx */ "./src/views/info-view.jsx"))); const MessagesView = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => __webpack_require__.e(/*! import() */ "src_views_messages-view_jsx").then(__webpack_require__.bind(__webpack_require__, /*! ./messages-view.jsx */ "./src/views/messages-view.jsx"))); const POP_SOUND = new Audio('audio/msg.m4a'); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ reconnect_countdown: { id: 'reconnect_countdown', defaultMessage: 'Disconnected. Reconnecting in {seconds}…', description: 'Message shown when an app update is available.' }, reconnect_now: { id: 'reconnect_now', defaultMessage: 'Try now', description: 'Prompt for reconnecting now' }, push_init_failed: { id: 'push_init_failed', defaultMessage: 'Failed to initialize push notifications', description: 'Error message when push notifications have failed to initialize.' }, invalid_security_token: { id: 'invalid_security_token', defaultMessage: 'Invalid security token', description: 'Error message when resetting password.' }, no_connection: { id: 'no_connection', defaultMessage: 'No connection', description: 'Warning that the user is offline.' }, code_doesnot_match: { id: 'code_doesnot_match', defaultMessage: 'Code does not match', description: 'Error message when the credential validation code is incorrect.' }, menu_item_info: { id: 'menu_item_info', defaultMessage: 'Info', description: 'Show extended topic information' }, menu_item_audio_call: { id: 'menu_item_audio_call', defaultMessage: 'Call', description: 'Start audio call' }, menu_item_video_call: { id: 'menu_item_video_call', defaultMessage: 'Video call', description: 'Start video call' }, cred_confirmed_successfully: { id: 'cred_confirmed_successfully', defaultMessage: 'Confirmed successfully', description: 'Notification message that the credential was successfully validated.' }, password_reset_success: { id: 'password_reset_success', defaultMessage: 'Password reset successfully', description: 'Notification message that the password was successfully reset.' }, select_country: { id: 'select_country', defaultMessage: 'Select country', description: 'Placeholder for the country selector' } }); class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.selfRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.state = this.getBlankState(); this.handleResize = this.handleResize.bind(this); this.handleHashRoute = this.handleHashRoute.bind(this); this.handleOnline = this.handleOnline.bind(this); this.handleEscapeKey = this.handleEscapeKey.bind(this); this.handleColorSchemeChange = this.handleColorSchemeChange.bind(this); this.checkForAppUpdate = this.checkForAppUpdate.bind(this); this.handleVisibilityEvent = this.handleVisibilityEvent.bind(this); this.handleError = this.handleError.bind(this); this.handleLoginRequest = this.handleLoginRequest.bind(this); this.handlePersistenceChange = this.handlePersistenceChange.bind(this); this.handleConnected = this.handleConnected.bind(this); this.handleAutoreconnectIteration = this.handleAutoreconnectIteration.bind(this); this.doLogin = this.doLogin.bind(this); this.handleLoginSuccessful = this.handleLoginSuccessful.bind(this); this.handleTenantResolved = this.handleTenantResolved.bind(this); this.handleDisconnect = this.handleDisconnect.bind(this); this.tnMeMetaDesc = this.tnMeMetaDesc.bind(this); this.tnMeContactUpdate = this.tnMeContactUpdate.bind(this); this.tnMeSubsUpdated = this.tnMeSubsUpdated.bind(this); this.resetContactList = this.resetContactList.bind(this); this.tnInitFind = this.tnInitFind.bind(this); this.tnFndSubsUpdated = this.tnFndSubsUpdated.bind(this); this.handleSearchContacts = this.handleSearchContacts.bind(this); this.handleTopicSelected = this.handleTopicSelected.bind(this); this.handleHideMessagesView = this.handleHideMessagesView.bind(this); this.handleSendMessage = this.handleSendMessage.bind(this); this.handleNewChatInvitation = this.handleNewChatInvitation.bind(this); this.handleNewAccount = this.handleNewAccount.bind(this); this.handleNewAccountRequest = this.handleNewAccountRequest.bind(this); this.handleImRegisterRequest = this.handleImRegisterRequest.bind(this); this.handleUpdatePasswordRequest = this.handleUpdatePasswordRequest.bind(this); this.handleUpdateAccountTagsRequest = this.handleUpdateAccountTagsRequest.bind(this); this.handleToggleIncognitoMode = this.handleToggleIncognitoMode.bind(this); this.handleChangeColorSchema = this.handleChangeColorSchema.bind(this); this.handleChangeTextSize = this.handleChangeTextSize.bind(this); this.handleSendOnEnter = this.handleSendOnEnter.bind(this); this.handleSelectWallpapers = this.handleSelectWallpapers.bind(this); this.handleWallpaperSelected = this.handleWallpaperSelected.bind(this); this.handleSettings = this.handleSettings.bind(this); this.handleGlobalSettings = this.handleGlobalSettings.bind(this); this.handleShowArchive = this.handleShowArchive.bind(this); this.handleShowBlocked = this.handleShowBlocked.bind(this); this.handleToggleMessageSounds = this.handleToggleMessageSounds.bind(this); this.handleCredAdd = this.handleCredAdd.bind(this); this.handleCredDelete = this.handleCredDelete.bind(this); this.handleCredConfirm = this.handleCredConfirm.bind(this); this.initFCMessaging = this.initFCMessaging.bind(this); this.toggleFCMToken = this.toggleFCMToken.bind(this); this.handlePushMessage = this.handlePushMessage.bind(this); this.handleSidepanelCancel = this.handleSidepanelCancel.bind(this); this.handleStartTopicRequest = this.handleStartTopicRequest.bind(this); this.handleNewTopicCreated = this.handleNewTopicCreated.bind(this); this.handleTopicUpdateRequest = this.handleTopicUpdateRequest.bind(this); this.handleUnarchive = this.handleUnarchive.bind(this); this.handleChangePermissions = this.handleChangePermissions.bind(this); this.handleTagsUpdateRequest = this.handleTagsUpdateRequest.bind(this); this.handleLogout = this.handleLogout.bind(this); this.handleDeleteAccount = this.handleDeleteAccount.bind(this); this.handleDeleteTopicRequest = this.handleDeleteTopicRequest.bind(this); this.handleDeleteMessagesRequest = this.handleDeleteMessagesRequest.bind(this); this.handleLeaveUnsubRequest = this.handleLeaveUnsubRequest.bind(this); this.handleBlockTopicRequest = this.handleBlockTopicRequest.bind(this); this.handleReportTopic = this.handleReportTopic.bind(this); this.handleShareTheCard = this.handleShareTheCard.bind(this); this.handleShowContextMenu = this.handleShowContextMenu.bind(this); this.defaultTopicContextMenu = this.defaultTopicContextMenu.bind(this); this.handleHideContextMenu = this.handleHideContextMenu.bind(this); this.handleShowAlert = this.handleShowAlert.bind(this); this.handleShowInfoView = this.handleShowInfoView.bind(this); this.handleMemberUpdateRequest = this.handleMemberUpdateRequest.bind(this); this.handleValidateCredentialsRequest = this.handleValidateCredentialsRequest.bind(this); this.handlePasswordResetRequest = this.handlePasswordResetRequest.bind(this); this.handleResetPassword = this.handleResetPassword.bind(this); this.handleContextMenuAction = this.handleContextMenuAction.bind(this); this.handleShowCountrySelector = this.handleShowCountrySelector.bind(this); this.handleShowForwardDialog = this.handleShowForwardDialog.bind(this); this.handleHideForwardDialog = this.handleHideForwardDialog.bind(this); this.handleEnterSelectMode = this.handleEnterSelectMode.bind(this); this.handleToggleMessageSelect = this.handleToggleMessageSelect.bind(this); this.handleExitSelectMode = this.handleExitSelectMode.bind(this); this.handleShowBatchForward = this.handleShowBatchForward.bind(this); this.handleHideBatchForward = this.handleHideBatchForward.bind(this); this.handleOpenScanner = this.handleOpenScanner.bind(this); this.handleCloseScanner = this.handleCloseScanner.bind(this); this.handleQrDetected = this.handleQrDetected.bind(this); this.handleSubmitGroupJoinRequest = this.handleSubmitGroupJoinRequest.bind(this); this.handleCancelGroupJoinPreview = this.handleCancelGroupJoinPreview.bind(this); this.handleStartVideoCall = this.handleStartVideoCall.bind(this); this.handleStartAudioCall = this.handleStartAudioCall.bind(this); this.handleInfoMessage = this.handleInfoMessage.bind(this); this.handleDataMessage = this.handleDataMessage.bind(this); this.handleCallClose = this.handleCallClose.bind(this); this.handleCallInvite = this.handleCallInvite.bind(this); this.handleCallRinging = this.handleCallRinging.bind(this); this.handleCallHangup = this.handleCallHangup.bind(this); this.handleCallSendOffer = this.handleCallSendOffer.bind(this); this.handleCallIceCandidate = this.handleCallIceCandidate.bind(this); this.handleCallSendAnswer = this.handleCallSendAnswer.bind(this); this.handleCallAccept = this.handleCallAccept.bind(this); this.sendMessageToTopic = this.sendMessageToTopic.bind(this); this.callTimeoutTimer = null; } getBlankState() { const settings = _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('settings') || {}; const persist = !!_lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in'); if (!settings.wallpaper) { const wallpaper = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_22__.defaultWallpaper)(); settings.wallpaper = wallpaper.name || ''; settings.wallpaperSize = wallpaper.size || 0; settings.wallpaperBlur = 0; } return { connected: false, ready: false, autoLogin: false, transport: settings.transport || null, serverAddress: settings.serverAddress || (0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.detectServerAddress)(), secureConnection: settings.secureConnection === undefined ? (0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.isSecureConnection)() : settings.secureConnection, serverVersion: "no connection", messageSounds: !settings.messageSoundsOff, incognitoMode: false, colorSchema: settings.colorSchema || _config_js__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_COLOR_SCHEME, systemColorSchema: window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light', wallpaper: settings.wallpaper, wallpaperSize: settings.wallpaperSize, wallpaperBlur: 0, textSize: settings.textSize || _config_js__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_TEXT_SIZE, sendOnEnter: settings.sendOnEnter || 'plain', desktopAlerts: persist && !!settings.desktopAlerts, desktopAlertsEnabled: ((0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.isSecureConnection)() || (0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.isLocalHost)()) && typeof firebase_app__WEBPACK_IMPORTED_MODULE_2__.initializeApp != 'undefined' && typeof navigator != 'undefined' && typeof FIREBASE_INIT != 'undefined', firebaseToken: persist ? _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('firebase-token') : null, applicationVisible: !document.hidden, errorText: '', errorLevel: null, errorAction: undefined, errorActionText: null, sidePanelSelected: 'tenant', sidePanelParams: {}, sidePanelTitle: null, sidePanelAvatar: null, myTrustedBadges: [], loadSpinnerVisible: false, login: '', password: '', persist: persist, myUserId: null, liveConnection: navigator.onLine, topicSelected: '', topicSelectedOnline: false, topicSelectedAcs: null, newTopicParams: null, loginDisabled: false, displayMobile: window.innerWidth <= _config_js__WEBPACK_IMPORTED_MODULE_12__.MEDIA_BREAKPOINT, infoPanel: undefined, mobilePanel: 'sidepanel', callTopic: undefined, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_NONE, callAudioOnly: undefined, callShouldStart: false, contextMenuVisible: false, contextMenuBounds: null, contextMenuClickAt: null, contextMenuParams: null, contextMenuItems: [], forwardDialogVisible: false, forwardMessage: null, selectMode: false, selectModeTopic: null, selectedSeqs: [], batchForwardVisible: false, scannerOpen: false, groupJoinPreview: null, alertVisible: false, alertParams: {}, chatList: [], searchResults: [], searchableContacts: [], reqCredMethod: undefined, credMethod: undefined, credCode: undefined, credToken: undefined, requestedTopic: undefined }; } componentDidMount() { window.addEventListener('resize', this.handleResize); this.handleOnlineOn = _ => { this.handleOnline(true); }; window.addEventListener('online', this.handleOnlineOn); this.handleOnlineOff = _ => { this.handleOnline(false); }; window.addEventListener('offline', this.handleOnlineOff); window.addEventListener('hashchange', this.handleHashRoute); window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', this.handleColorSchemeChange); document.addEventListener('visibilitychange', this.handleVisibilityEvent); document.addEventListener('keydown', this.handleEscapeKey); document.documentElement.style.colorScheme = this.state.colorSchema == 'auto' ? 'light dark' : this.state.colorSchema; document.documentElement.style.setProperty('--message-text-size', `${this.state.textSize}pt`); this.applyWallpaperSettings(this.state.wallpaper, this.state.wallpaperSize, this.state.wallpaperBlur, this.state.colorSchema == 'auto' ? this.state.systemColorSchema : this.state.colorSchema); if (typeof BroadcastChannel == 'function') { const serviceWorkerChannel = new BroadcastChannel('tinode-sw'); serviceWorkerChannel.addEventListener('message', this.handlePushMessage); } else { console.warn("Your browser does not support BroadcastChannel. Some features will not be available"); } this.lastWakeUpCheck = new Date().getTime(); this.wakeUpTicker = setInterval(_ => { const now = new Date().getTime(); if (now - this.lastWakeUpCheck > _config_js__WEBPACK_IMPORTED_MODULE_12__.WAKE_UP_TIMEOUT) { this.handleOnlineOn(); } this.lastWakeUpCheck = now; }, _config_js__WEBPACK_IMPORTED_MODULE_12__.WAKE_UP_TICK); this.setState({ viewportWidth: document.documentElement.clientWidth, viewportHeight: document.documentElement.clientHeight }); new Promise((resolve, reject) => { this.tinode = TinodeWeb.tnSetup(this.state.serverAddress, this.state.secureConnection, this.state.transport, this.props.intl.locale, this.state.persist, resolve); this.tinode.onConnect = this.handleConnected; this.tinode.onDisconnect = this.handleDisconnect; this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration; this.tinode.onInfoMessage = this.handleInfoMessage; this.tinode.onDataMessage = this.handleDataMessage; }).then(_ => { if (this.state.desktopAlertsEnabled) { this.initFCMessaging().catch(_ => {}); } this.resetContactList(); const token = this.state.persist ? _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('auth-token') : undefined; if (token) { this.setState({ autoLogin: true }); token.expires = new Date(token.expires); this.tinode.setAuthToken(token); this.tinode.connect().catch(err => { this.handleError(err.message, 'err'); }); } const parsedNav = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].parseUrlHash(window.location.hash); if (!['cred', 'reset', 'register'].includes(parsedNav.path[0])) { this.setState({ requestedTopic: parsedNav.path[1] }); const path = parsedNav.params && parsedNav.params.cred_done ? _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam('', 'cred_done', parsedNav.params.cred_done) : ''; _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(path); } else { this.handleHashRoute(); } }); } componentWillUnmount() { window.removeEventListener('resize', this.handleResize); window.removeEventListener('hashchange', this.handleHashRoute); window.removeEventListener('online', this.handleOnlineOn); window.removeEventListener('offline', this.handleOnlineOff); window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', this.handleColorSchemeChange); document.removeEventListener('visibilitychange', this.handleVisibilityEvent); document.removeEventListener('keydown', this.handleEscapeKey); clearInterval(this.wakeUpTicker); } static tnSetup(serverAddress, secureConnection, transport, locale, persistentCache, onSetupCompleted) { const tinode = new tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode({ appName: _config_js__WEBPACK_IMPORTED_MODULE_12__.APP_NAME, host: serverAddress, apiKey: _config_js__WEBPACK_IMPORTED_MODULE_12__.API_KEY, transport: transport, secure: secureConnection, persist: persistentCache }, onSetupCompleted); tinode.setHumanLanguage(locale); tinode.enableLogging(_config_js__WEBPACK_IMPORTED_MODULE_12__.LOGGING_ENABLED, true); TinodeWeb.installTenantHiPatch(tinode); return tinode; } static installTenantHiPatch(tinode) { const conn = tinode && tinode._connection; if (!conn || conn.__tenantPatched) { return; } const original = conn.sendText.bind(conn); conn.sendText = msg => { if (typeof msg == 'string' && (msg.indexOf('"hi":') >= 0 || msg.indexOf('"acc":') >= 0)) { try { const parsed = JSON.parse(msg); if (parsed.hi) { const tenant = (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_18__.getTenantContext)(); if (tenant && tenant.code) { parsed.hi.tenant = tenant.code; msg = JSON.stringify(parsed); } } else if (parsed.acc && tinode.__pendingAccExtra) { Object.assign(parsed.acc, tinode.__pendingAccExtra); tinode.__pendingAccExtra = null; msg = JSON.stringify(parsed); } } catch (e) {} } return original(msg); }; conn.__tenantPatched = true; } handlePushMessage(payload) { this.tinode.oobNotification(payload.data || {}); } initFCMessaging() { const { formatMessage, locale } = this.props.intl; const onError = (msg, err) => { console.error(msg, err); this.handleError(formatMessage(messages.push_init_failed), 'err'); this.setState({ firebaseToken: null }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: false }); }; try { this.fcm = (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.getMessaging)((0,firebase_app__WEBPACK_IMPORTED_MODULE_2__.initializeApp)(FIREBASE_INIT, _config_js__WEBPACK_IMPORTED_MODULE_12__.BASE_APP_NAME)); return navigator.serviceWorker.getRegistration('/service-worker.js').then(reg => { return reg || navigator.serviceWorker.register('/service-worker.js').then(reg => { this.checkForAppUpdate(reg); return reg; }); }).then(reg => { (reg.active || reg.installing).postMessage(JSON.stringify({ locale: locale, version: _version_js__WEBPACK_IMPORTED_MODULE_14__.PACKAGE_VERSION })); return TinodeWeb.requestFCMToken(this.fcm, reg); }).then(token => { const persist = _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in'); if (token != this.state.firebaseToken) { this.tinode.setDeviceToken(token); if (persist) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('firebase-token', token); } } this.setState({ firebaseToken: token, desktopAlerts: true }); if (persist) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: true }); } (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.onMessage)(this.fcm, payload => { this.handlePushMessage(payload); }); }).catch(err => { onError(err); throw err; }); } catch (err) { onError(err); return Promise.reject(err); } } static requestFCMToken(fcm, sw) { return (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.getToken)(fcm, { serviceWorkerRegistration: sw, vapidKey: FIREBASE_INIT.messagingVapidKey }).then(token => { if (token) { return token; } else if (typeof Notification != 'undefined') { return Notification.requestPermission().then(permission => { if (permission === 'granted') { return (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.getToken)(fcm, { serviceWorkerRegistration: sw, vapidKey: FIREBASE_INIT.messagingVapidKey }).then(token => { if (token) { return token; } else { throw new Error("Failed to initialize notifications"); } }); } else { throw new Error("No permission to send notifications: " + permission); } }); } throw new Error("Notifications are not supported"); }); } handleResize() { const mobile = document.documentElement.clientWidth <= _config_js__WEBPACK_IMPORTED_MODULE_12__.MEDIA_BREAKPOINT; this.setState({ viewportWidth: document.documentElement.clientWidth, viewportHeight: document.documentElement.clientHeight }); if (this.state.displayMobile != mobile) { this.setState({ displayMobile: mobile }); } } handleEscapeKey(e) { if (e.key === 'Escape' || e.keyCode === 27) { this.setState({ topicSelected: null, errorText: '', errorLevel: null, mobilePanel: 'sidepanel', topicSelectedOnline: false, topicSelectedAcs: null, infoPanel: undefined, forwardMessage: null, contextMenuVisible: false, forwardDialogVisible: false, alertVisible: false }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic('', null)); } } checkForAppUpdate(reg) { reg.onupdatefound = _ => { const installingWorker = reg.installing; installingWorker.onstatechange = _ => { if (installingWorker.state == 'installed' && navigator.serviceWorker.controller) { const msg = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "update_available", defaultMessage: "Update available.", description: "Message shown when an app update is available." }, void 0, false), " ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)("a", { href: "", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "reload_update", defaultMessage: "Reload", description: "Call to action to reload application when update is available." }, void 0, false) }, void 0, false), "."] }, void 0, true); this.handleError(msg, 'info'); } }; }; } handleHashRoute() { const hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].parseUrlHash(window.location.hash); const newState = { infoPanel: hash.params.info, newTopicTabSelected: hash.params.tab }; if (hash.path && hash.path.length > 0) { if (['acc_general', 'archive', 'blocked', 'contacts', 'cred', 'crop', 'edit', 'general', 'newtpk', 'notif', 'register', 'reset', 'security', 'settings', 'support', 'wallpapers', 'tenant', 'login', 'enterprise-register', 'enterprise-feedback', 'identity-check', 'realname', 'realname-verified', 'realname-reminder', 'independent-password', 'messages-home', 'messages-offline', 'messages-menu', 'message-actions', 'system-messages', 'chat-inbound-request', 'chat-inbound-message', 'chat-outbound-request', 'chat-status', 'chat-friend', 'chat-media', 'chat-blocked', 'chat-deleted', 'chat-standard', 'chat-attachments', 'chat-mixed', 'chat-contact-card', 'compose-keyboard', 'mentions-select', 'mentions-complete', 'mentions-message', 'emoji-panel', 'emoji-message', 'voice-ready', 'voice-hold', 'voice-recording', 'media-uploading', 'media-gallery', 'media-retry', 'upload-file', 'file-message', 'message-multiselect', 'favorite-success', 'forward-select', 'forward-multiple', 'forward-individual', 'forward-bundle', 'address-book', 'friend-requests', 'add-friend', 'my-friend-qr', 'friend-search-result', 'friend-verification', 'friend-profile', 'group-member-profile', 'friend-settings', 'friend-settings-blocked', 'friend-delete-confirm', 'block-list', 'block-confirm', 'clear-chat-confirm', 'group-list', 'group-empty', 'group-invite', 'group-events', 'group-join-requests', 'group-new-request', 'group-announcement', 'group-summary', 'group-announcement-detail', 'group-settings', 'group-profile', 'group-avatar', 'group-nickname', 'group-description', 'group-my-nickname', 'group-role-message', 'group-qr', 'group-governance', 'group-admins', 'group-admin-add', 'group-admin-success', 'group-admin-partial', 'group-admin-removed', 'group-mute-add', 'group-muted', 'group-owner-select', 'group-owner-confirm', 'group-files', 'group-file-upload', 'favorites', 'favorites-mixed', 'favorites-files', 'favorites-text', 'favorites-voice', 'favorites-links', 'favorites-select', 'favorite-share', 'file-download', 'file-downloading', 'file-downloaded', 'history-search', 'history-files', 'history-links', 'history-images', 'history-videos', 'call-history', 'call-incoming', 'audio-call-ringing', 'audio-call-active', 'audio-call-muted', 'audio-call-speaker', 'video-call-ringing', 'video-call-camera-off', 'video-call-active', 'video-call-peer-camera-off', 'call-minimized', 'workbench', 'organization-directory', 'meeting-organizer', 'meeting-attendee', 'meeting-create', 'meeting-detail', 'daily-report-editor', 'daily-report-mine', 'daily-report-team', 'daily-report-detail', 'monthly-report-editor', 'monthly-report-list', 'monthly-report-detail', 'executive-mailbox', 'executive-mailbox-notice', 'personal-center', 'personal-profile', 'profile-nickname', 'profile-birth-date', 'profile-signature', 'profile-gender', 'profile-region', 'personal-qrcode', 'android-settings', 'cache-clear-confirm', 'clear-history-confirm', 'change-password', 'delete-account-confirm', 'app-version', 'privacy-settings', 'friend-discovery-settings', 'youth-mode-off', 'youth-mode-on', 'youth-mode-verify', 'notification-permission', 'permission-settings-reminder', 'camera-permission-info', 'microphone-permission-info', 'fraud-risk-warning', 'fraud-risk-confirmation', 'abuse-report-reasons', 'abuse-report-details', 'user-feedback', ''].includes(hash.path[0])) { newState.sidePanelSelected = hash.path[0]; newState.sidePanelParams = hash.params; } else { console.warn("Unknown sidepanel view", hash.path[0]); } let topicName = hash.path[1] || null; if (topicName != this.state.topicSelected) { if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.topicType(topicName)) { topicName = null; newState.mobilePanel = 'sidepanel'; } else { newState.mobilePanel = 'topic-view'; } Object.assign(newState, { topicSelected: topicName, topicSelectedAcs: this.tinode.getTopicAccessMode(topicName) }); } } else { Object.assign(newState, { sidePanelSelected: '', sidePanelParams: {}, topicSelected: null }); } if (hash.params.method) { newState.credMethod = hash.params.method; } if (hash.params.code) { newState.credCode = hash.params.code; } if (hash.params.token) { newState.credToken = hash.params.token; } if (hash.params.cred_done) { Object.assign(newState, TinodeWeb.stateForError(this.props.intl.formatMessage(messages.cred_confirmed_successfully), 'info')); } this.setState(newState); } handleOnline(online) { if (online) { this.handleError(); clearInterval(this.reconnectCountdown); this.tinode.reconnect(); } else { this.handleError(this.props.intl.formatMessage(messages.no_connection), 'warn'); } this.setState({ liveConnection: online }); } handleVisibilityEvent() { this.setState({ applicationVisible: !document.hidden }); } static stateForError(err, level, action, actionText) { return { errorText: err, errorLevel: level, errorAction: action, errorActionText: actionText, callShouldStart: false }; } handleError(err, level, action, actionText) { this.setState(TinodeWeb.stateForError(err, level, action, actionText)); } handleLoginRequest(login, password) { this.setState({ loginDisabled: true, login: login, password: password, loadSpinnerVisible: true, autoLogin: true }); this.handleError('', null); if (this.tinode.isConnected()) { this.doLogin(login, password, null, { meth: this.state.credMethod, resp: this.state.credCode }); } else { this.tinode.connect().catch(err => { this.setState({ loginDisabled: false, autoLogin: false, loadSpinnerVisible: false }); this.handleError(err.message, 'err'); }); } if (this.state.desktopAlertsEnabled && !this.state.firebaseToken) { this.initFCMessaging(); } } handlePersistenceChange(persist) { if (persist) { this.tinode.initStorage().then(_ => { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('keep-logged-in', true); this.setState({ persist: true }); }); } else { this.tinode.clearStorage().then(_ => { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('keep-logged-in', false); this.setState({ persist: false }); }); } } handleConnected() { clearInterval(this.reconnectCountdown); this.handleError(); const params = this.tinode.getServerInfo(); this.setState({ serverVersion: params.ver + ' ' + (params.build ? params.build : 'none'), reqCredMethod: ((params.reqCred || {}).auth || [])[0] || 'email' }); if (this.state.autoLogin) { this.doLogin(this.state.login, this.state.password, null, { meth: this.state.credMethod, resp: this.state.credCode }); } } handleAutoreconnectIteration(sec, prom) { clearInterval(this.reconnectCountdown); if (sec < 0) { this.handleError(); return; } if (prom) { prom.then(_ => { this.handleError(); }).catch(err => { this.handleError(err.message, 'err'); }); return; } const { formatMessage } = this.props.intl; let count = sec / 1000; count = count | count; this.reconnectCountdown = setInterval(_ => { if (count < -10) { clearInterval(this.reconnectCountdown); this.tinode.reconnect(); return; } const fmtTime = count > 99 ? (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_21__.secondsToTime)(count) : count; this.handleError(formatMessage(messages.reconnect_countdown, { seconds: fmtTime }), 'warn', _ => { clearInterval(this.reconnectCountdown); this.tinode.reconnect(); }, formatMessage(messages.reconnect_now)); count -= 1; }, 1000); } handleDisconnect(err) { this.setState({ connected: false, ready: false, topicSelectedOnline: false, errorText: err && err.message ? err.message : "Disconnected", errorLevel: err && err.message ? 'err' : 'warn', loginDisabled: false, contextMenuVisible: false, forwardDialogVisible: false, serverVersion: "no connection" }); } doLogin(login, password, tmpToken, cred) { if (this.tinode.isAuthenticated()) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(''); return; } let token = tmpToken || (this.tinode.getAuthToken() || {}).token; if (!(login && password) && !token) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(''); this.setState({ loginDisabled: false }); return; } cred = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.credential(cred); let connectionPromise = this.tinode.isConnected() ? Promise.resolve() : this.tinode.connect(); let loginPromise; if (login && password) { token = null; this.setState({ password: null }); loginPromise = connectionPromise.then(_ => this.tinode.loginBasic(login, password, cred)); } else { loginPromise = connectionPromise.then(_ => this.tinode.loginToken(token, cred)); } loginPromise.then(ctrl => { if (ctrl.code >= 300 && ctrl.text === 'validate credentials') { this.setState({ loadSpinnerVisible: false }); if (cred) { this.handleError(this.props.intl.formatMessage(messages.code_doesnot_match), 'warn'); } TinodeWeb.navigateToCredentialsView(ctrl.params); } else { this.handleLoginSuccessful(); } }).catch(err => { const autoLogin = err.code >= 500; this.setState({ loginDisabled: false, credMethod: undefined, credCode: undefined, loadSpinnerVisible: false, autoLogin: autoLogin }); this.handleError(err.message, 'err'); console.warn("Login failed", err); if (!autoLogin) { if (token) { this.handleLogout(); } _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(''); } }); } static navigateToCredentialsView(params) { const parsed = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].parseUrlHash(window.location.hash); parsed.path[0] = 'cred'; parsed.params['method'] = params.cred[0]; parsed.params['token'] = params.token; parsed.params['code'] = params.code; _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].composeUrlHash(parsed.path, parsed.params)); } handleLoginSuccessful() { this.handleError(); if (_lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in')) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('auth-token', this.tinode.getAuthToken()); } const authToken = this.tinode.getAuthToken(); sessionStorage.setItem('im-session-token', authToken ? authToken.token : ''); const goToTopic = this.state.requestedTopic || this.state.topicSelected; const me = this.tinode.getMeTopic(); me.onMetaDesc = this.tnMeMetaDesc; me.onContactUpdate = this.tnMeContactUpdate; me.onSubsUpdated = this.tnMeSubsUpdated; this.setState({ connected: true, credMethod: undefined, credCode: undefined, credToken: undefined, myUserId: this.tinode.getCurrentUserID(), autoLogin: true, requestedTopic: undefined }); me.subscribe(me.startMetaQuery().withLaterSub().withDesc().withTags().withCred().build()).catch(err => { this.tinode.disconnect(); localStorage.removeItem('auth-token'); this.handleError(err.message, 'err'); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(''); }).finally(_ => { this.setState({ loadSpinnerVisible: false }); }); let urlHash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel(window.location.hash, 'workbench'); if (goToTopic) { urlHash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic(urlHash, goToTopic); } _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(urlHash); } tnMeMetaDesc(desc) { if (!desc) { return; } if (desc.public) { this.setState({ sidePanelTitle: desc.public.fn, sidePanelAvatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.makeImageUrl)(desc.public.photo) }); } if (desc.trusted) { const badges = []; for (const [key, val] of Object.entries(desc.trusted)) { if (val) { badges.push(key); } } this.setState({ myTrustedBadges: badges }); } if (desc.acs) { this.setState({ incognitoMode: !desc.acs.isPresencer() }); } if (TinodeWeb.checkIfPinsUpdated(desc, this.state.chatList)) { this.resetContactList(); } } tnMeContactUpdate(what, cont) { if (what == 'on' || what == 'off') { this.resetContactList(); if (this.state.topicSelected == cont.topic) { this.setState({ topicSelectedOnline: what == 'on' }); } } else if (what == 'read') { this.resetContactList(); } else if (what == 'msg' && cont) { const topic = this.tinode.getTopic(cont.topic); const archived = topic && topic.isArchived(); if (cont.unread > 0 && this.state.messageSounds && !archived) { if (document.hidden || this.state.topicSelected != cont.topic) { POP_SOUND.play().catch(_ => {}); } } this.resetContactList(); } else if (what == 'recv') {} else if (what == 'gone' || what == 'unsub') { if (this.state.topicSelected == cont.topic) { this.handleTopicSelected(null); } this.resetContactList(); } else if (what == 'acs') { if (this.state.topicSelected == cont.topic) { this.setState({ topicSelectedAcs: cont.acs }); } } else if (what == 'del') {} else if (what == 'upd' || what == 'call') {} else { console.info("Unsupported (yet) presence update:", what, "in", (cont || {}).topic); } } tnMeSubsUpdated(unused) { this.resetContactList(); } static prepareSearchableContacts(chatList, foundContacts) { const merged = {}; for (const c of chatList) { if (tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(c.topic)) { merged[c.topic] = { user: c.topic, updated: c.updated, public: c.public, private: c.private, acs: c.acs }; } } for (const c of foundContacts) { if (!merged[c.user]) { merged[c.user] = c; } } return Object.values(merged); } resetContactList() { const newState = { chatList: [] }; if (!this.state.ready) { newState.ready = true; } const me = this.tinode.getMeTopic(); me.contacts(c => { if (!c.topic && !c.user) { c.topic = c.name; } newState.chatList.push(c); if (this.state.topicSelected == c.topic) { newState.topicSelectedOnline = c.online; newState.topicSelectedAcs = c.acs; } }); const past = new Date(0); newState.chatList.sort((a, b) => { const pins = me.pinnedTopicRank(b.topic) - me.pinnedTopicRank(a.topic); return pins != 0 ? pins : (b.touched || past).getTime() - (a.touched || past).getTime(); }); newState.searchableContacts = TinodeWeb.prepareSearchableContacts(newState.chatList, this.state.searchResults); this.setState(newState); } static checkIfPinsUpdated(me, chatList) { for (let i = 0; i < chatList.length; i++) { const c = chatList[i]; if (!!me.pinnedTopicRank(c.topic) != c.pinned) { return true; } } return false; } tnInitFind() { const fnd = this.tinode.getFndTopic(); fnd.onSubsUpdated = this.tnFndSubsUpdated; if (fnd.isSubscribed()) { this.tnFndSubsUpdated(); } else { fnd.subscribe(fnd.startMetaQuery().withSub().build()).catch(err => { this.handleError(err.message, 'err'); }); } } tnFndSubsUpdated() { const foundContacts = []; this.tinode.getFndTopic().contacts(s => { foundContacts.push(s); }); this.setState({ searchResults: foundContacts, searchableContacts: TinodeWeb.prepareSearchableContacts(this.state.chatList, foundContacts) }); } handleSearchContacts(query) { const fnd = this.tinode.getFndTopic(); fnd.setMeta({ desc: { public: query } }).then(_ => fnd.getMeta(fnd.startMetaQuery().withSub().build())).catch(err => this.handleError(err.message, 'err')); } handleTopicSelected(topicName) { if (this.state.newTopicParams && this.state.newTopicParams._topicName != topicName) { this.setState({ newTopicParams: null }); } if (topicName) { this.setState({ errorText: '', errorLevel: null, mobilePanel: 'topic-view', infoPanel: undefined }); if (this.state.topicSelected != topicName) { this.setState({ topicSelectedOnline: this.tinode.isTopicOnline(topicName), topicSelectedAcs: this.tinode.getTopicAccessMode(topicName), forwardMessage: null }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic('', topicName)); } } else { this.setState({ topicSelected: null, errorText: '', errorLevel: null, mobilePanel: 'sidepanel', topicSelectedOnline: false, topicSelectedAcs: null, infoPanel: undefined, forwardMessage: null }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic('', null)); } } handleHideMessagesView() { this.setState({ mobilePanel: 'sidepanel' }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic(window.location.hash, null)); } handleSendMessage(msg, uploadCompletionPromise, uploader, head) { const topic = this.tinode.getTopic(this.state.topicSelected); return this.sendMessageToTopic(topic, msg, uploadCompletionPromise, uploader, head); } sendMessageToTopic(topic, msg, uploadCompletionPromise, uploader, head) { msg = topic.createMessage(msg, false); msg._uploader = uploader; if (head) { msg.head = Object.assign(msg.head || {}, head); } const completion = []; if (uploadCompletionPromise) { completion.push(uploadCompletionPromise); } if (!topic.isSubscribed()) { const subscribePromise = topic.subscribe().then(_ => { let calls = []; topic.queuedMessages(pub => { if (pub._sending || pub.seq == msg.seq) { return; } if (pub.head && pub.head.webrtc) { calls.push(pub.seq); return; } if (topic.isSubscribed()) { topic.publishMessage(pub); } }); if (calls.length > 0) { topic.delMessagesList(calls, true); } }); completion.push(subscribePromise); } return topic.publishDraft(msg, Promise.all(completion)).then(ctrl => { if (topic.isArchived()) { topic.archive(false); } return ctrl; }).catch(err => this.handleError(err.message, 'err')); } handleNewChatInvitation(topicName, action) { const topic = this.tinode.getTopic(topicName); let response = null; switch (action) { case 'accept': const mode = topic.getAccessMode().getGiven(); response = topic.setMeta({ sub: { mode: mode } }); if (topic.isP2PType()) { response = response.then(_ => topic.setMeta({ sub: { user: topicName, mode: mode } })); } break; case 'delete': response = topic.delTopic(true); break; case 'block': const am = topic.getAccessMode().updateWant('-JP').getWant(); response = topic.setMeta({ sub: { mode: am } }).then(_ => this.handleTopicSelected(null)); break; default: console.warn("Unknown invitation action", '"' + action + '""'); } if (response != null) { response.catch(err => this.handleError(err.message, 'err')); } } handleNewAccount() { this.handleError(); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel(window.location.hash, 'register')); } handleNewAccountRequest(login_, password_, public_, cred_, tags_) { this.handleError(); this.tinode.connect(this.state.serverAddress).then(_ => { let attachments; if (public_ && public_.photo && public_.photo.ref) { attachments = [public_.photo.ref]; } return this.tinode.createAccountBasic(login_, password_, { public: public_, tags: tags_, cred: tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.credential(cred_), attachments: attachments }); }).then(ctrl => { if (ctrl.code >= 300 && ctrl.text == 'validate credentials') { TinodeWeb.navigateToCredentialsView(ctrl.params); } else { this.handleLoginSuccessful(this); } }).catch(err => { this.handleError(err.message, 'err'); }); } handleImRegisterRequest(login_, password_, displayName, extra, cred_) { this.tinode.__pendingAccExtra = extra; this.handleNewAccountRequest(login_, password_, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_22__.theCard)(displayName, null), cred_); } handleToggleIncognitoMode(on) { this.setState({ incognitoMode: null }); const me = this.tinode.getMeTopic(); const am = me.getAccessMode().updateWant(on ? '-P' : '+P').getWant(); me.setMeta({ sub: { mode: am } }).catch(err => { this.setState({ incognitoMode: !on }); this.handleError(err.message, 'err'); }); } handleChangeColorSchema(schema) { this.setState({ colorSchema: schema }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { colorSchema: schema }); document.documentElement.style.colorScheme = schema == 'auto' ? 'light dark' : schema; this.applyColorSchema(schema, this.state.systemColorSchema, this.state.wallpaperSize); } handleColorSchemeChange(event) { const systemSchema = event.matches ? 'dark' : 'light'; this.setState({ systemColorSchema: systemSchema }); this.applyColorSchema(this.state.colorSchema, systemSchema, this.state.wallpaperSize); } applyColorSchema(schema, systemSchema, size) { const effectiveSchema = schema == 'auto' ? systemSchema : schema; document.documentElement.style.setProperty('--wallpaper-invert', effectiveSchema == 'dark' && size ? '1' : '0'); document.documentElement.style.setProperty('--wallpaper-brightness', effectiveSchema == 'dark' && !size ? '0.5' : '1'); } handleSelectWallpapers() { this.handleError(); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel(window.location.hash, 'wallpapers')); } applyWallpaperSettings(wallpaper, size, blur, effectiveSchema) { document.documentElement.style.setProperty('--wallpaper-url', `url('${wallpaper}')`); document.documentElement.style.setProperty('--wallpaper-repeat', size ? 'repeat' : 'no-repeat'); document.documentElement.style.setProperty('--wallpaper-blur', size ? '0px' : `${blur}px`); document.documentElement.style.setProperty('--wallpaper-size', size ? `${size}px` : 'cover'); document.documentElement.style.setProperty('--wallpaper-position', size ? 'unset' : 'center'); document.documentElement.style.setProperty('--wallpaper-invert', effectiveSchema == 'dark' && size ? '1' : '0'); document.documentElement.style.setProperty('--wallpaper-brightness', effectiveSchema == 'dark' && !size ? '0.5' : '1'); } handleWallpaperSelected(wallpaper, size, blur) { this.handleError(); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { wallpaper: wallpaper, wallpaperSize: size, wallpaperBlur: blur }); this.setState({ wallpaper: wallpaper, wallpaperSize: size, wallpaperBlur: blur }); this.applyWallpaperSettings(wallpaper, size, blur, this.state.colorSchema == 'auto' ? this.state.systemColorSchema : this.state.colorSchema); } handleChangeTextSize(size) { this.setState({ textSize: size | 0 }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { textSize: size }); document.documentElement.style.setProperty('--message-text-size', `${size}pt`); } handleSendOnEnter(option) { this.setState({ sendOnEnter: option }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { sendOnEnter: option }); } handleUpdateAccountTagsRequest(_, tags) { this.tinode.getMeTopic().setMeta({ tags: tags }).catch(err => this.handleError(err.message, 'err')); } handleSettings() { this.handleError(); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel(window.location.hash, this.state.myUserId ? 'edit' : 'settings')); } handleGlobalSettings(settings) { const serverAddress = settings.serverAddress || this.state.serverAddress; const transport = settings.transport || this.state.transport; const secureConnection = settings.secureConnection === undefined ? this.state.secureConnection : settings.secureConnection; if (this.tinode) { this.tinode.clearStorage(); this.tinode.onDisconnect = undefined; this.tinode.disconnect(); } this.tinode = TinodeWeb.tnSetup(serverAddress, secureConnection, transport, this.props.intl.locale, _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in')); this.tinode.onConnect = this.handleConnected; this.tinode.onDisconnect = this.handleDisconnect; this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration; this.tinode.onInfoMessage = this.handleInfoMessage; this.tinode.onDataMessage = this.handleDataMessage; this.setState({ serverAddress: serverAddress, transport: transport, secureConnection: secureConnection }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('settings', { serverAddress: serverAddress, transport: transport, secureConnection: secureConnection }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel(window.location.hash, '')); } handleTenantResolved(data, requestedCode) { const tenant = data.tenant || {}; const endpoints = data.endpoints || {}; _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('im-tenant', { code: tenant.code || requestedCode, name: tenant.name || tenant.code || requestedCode, endpoints }); let host = this.state.serverAddress; let secureConnection = this.state.secureConnection; if (endpoints.websocket) { try { const wsUrl = new URL(endpoints.websocket); host = wsUrl.host; secureConnection = wsUrl.protocol === 'wss:'; } catch (e) {} } if (host && (host !== this.state.serverAddress || secureConnection !== this.state.secureConnection)) { this.handleGlobalSettings({ serverAddress: host, secureConnection }); } } handleShowArchive() { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel(window.location.hash, this.state.myUserId ? 'archive' : '')); } handleShowBlocked() { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel(window.location.hash, this.state.myUserId ? 'blocked' : '')); } toggleFCMToken(enabled) { if (enabled) { this.setState({ desktopAlerts: null }); if (!this.state.firebaseToken) { this.initFCMessaging(); } else { this.setState({ desktopAlerts: true }); if (_lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in')) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: true }); } } } else if (this.state.firebaseToken && this.fcm) { (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.deleteToken)(this.fcm).catch(err => { console.error("Unable to delete token.", err); }).finally(_ => { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: false }); localStorage.removeItem('firebase-token'); this.setState({ desktopAlerts: false, firebaseToken: null }); this.tinode.setDeviceToken(null); }); } else { this.setState({ desktopAlerts: false, firebaseToken: null }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: false }); } } handleToggleMessageSounds(enabled) { this.setState({ messageSounds: enabled }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { messageSoundsOff: !enabled }); } handleCredAdd(method, value) { const me = this.tinode.getMeTopic(); me.setMeta({ cred: { meth: method, val: value } }).catch(err => this.handleError(err.message, 'err')); } handleCredDelete(method, value) { const me = this.tinode.getMeTopic(); me.delCredential(method, value).catch(err => this.handleError(err.message, 'err')); } handleCredConfirm(method, response) { TinodeWeb.navigateToCredentialsView({ cred: [method], code: response }); } handleSidepanelCancel() { const parsed = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].parseUrlHash(window.location.hash); let path = ''; if (['security', 'support', 'general', 'notif', 'acc_general'].includes(parsed.path[0])) { path = 'edit'; } else if ('crop' == parsed.path[0]) { path = 'general'; } else if ('blocked' == parsed.path[0]) { path = 'security'; } else if ('wallpapers' == parsed.path[0]) { path = 'acc_general'; } else if (this.state.myUserId) { path = 'contacts'; } parsed.path[0] = path; if (parsed.params) { delete parsed.params.code; delete parsed.params.method; delete parsed.params.tab; delete parsed.params.scheme; delete parsed.params.token; } _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].composeUrlHash(parsed.path, parsed.params)); this.setState({ errorText: '', errorLevel: null }); } basicNavigator(hash) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel(window.location.hash, hash)); } infoNavigator(hash) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlInfoPanel(window.location.hash, hash)); } handleStartTopicRequest(topicName, newTopicParams, isChannel) { if (topicName && this.tinode.isTopicCached(topicName)) { this.handleTopicSelected(topicName); return; } const params = {}; if (tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(topicName)) { params.sub = { mode: _config_js__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_P2P_ACCESS_MODE }; params.desc = { defacs: { auth: _config_js__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_P2P_ACCESS_MODE } }; } else { topicName = topicName || this.tinode.newGroupTopicName(isChannel); if (newTopicParams) { params.desc = { public: newTopicParams.public, private: { comment: newTopicParams.private } }; params.tags = newTopicParams.tags; } } params._topicName = topicName; this.setState({ newTopicParams: params }, _ => { this.handleTopicSelected(topicName); }); } handleNewTopicCreated(oldName, newName) { let nextState = {}; if (this.state.callShouldStart) { nextState = { callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS, callShouldStart: false }; } if (this.state.topicSelected == oldName && oldName != newName) { nextState.topicSelected = newName; } this.setState(nextState, _ => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic('', newName)); }); } handleTopicUpdateRequest(topicName, pub, priv, defacs) { this.handleError(); const topic = this.tinode.getTopic(topicName); if (topic) { const params = {}; let attachments; if (pub) { if (pub.photo) { if (pub.photo.ref && pub.photo.ref != tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR) { attachments = [pub.photo.ref]; } else if (!pub.photo.data || pub.photo.data == tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR) { pub.photo = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR; } } params.public = pub; } if (typeof priv == 'string') { params.private = priv === tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR ? tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR : { comment: priv }; } if (defacs) { params.defacs = defacs; } topic.setMeta({ desc: params, attachments: attachments }).catch(err => this.handleError(err.message, 'err')); } } handleUnarchive(topicName) { const topic = this.tinode.getTopic(topicName); if (topic) { topic.archive(false).catch(err => this.handleError(err.message, 'err')); } } handleUpdatePasswordRequest(password) { this.handleError(); if (password) { this.tinode.updateAccountBasic(null, this.tinode.getCurrentLogin(), password).catch(err => this.handleError(err.message, 'err')); } } handleChangePermissions(topicName, mode, uid) { const topic = this.tinode.getTopic(topicName); if (topic) { const am = topic.getAccessMode(); if (uid) { am.updateGiven(mode); mode = am.getGiven(); } else { am.updateWant(mode); mode = am.getWant(); } topic.setMeta({ sub: { user: uid, mode: mode } }).catch(err => this.handleError(err.message, 'err')); } } handleTagsUpdateRequest(topicName, tags) { const topic = this.tinode.getTopic(topicName); if (topic) { topic.setMeta({ tags: tags }).catch(err => this.handleError(err.message, 'err')); } } handleLogout() { (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_22__.updateFavicon)(0); localStorage.removeItem('auth-token'); localStorage.removeItem('firebase-token'); localStorage.removeItem('settings'); sessionStorage.removeItem('im-session-token'); if (this.state.firebaseToken && this.fcm) { (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.deleteToken)(this.fcm).catch(err => { console.warn('Failed to delete FCM token on logout', err); }); } document.documentElement.style.colorScheme = _config_js__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_COLOR_SCHEME == 'auto' ? 'light dark' : _config_js__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_COLOR_SCHEME; document.documentElement.style.setProperty('--message-text-size', `${_config_js__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_TEXT_SIZE}pt`); clearInterval(this.reconnectCountdown); let cleared; if (this.tinode) { cleared = this.tinode.clearStorage(); this.tinode.onDisconnect = undefined; this.tinode.disconnect(); } else { cleared = Promise.resolve(); } this.setState(this.getBlankState()); cleared.then(_ => { this.tinode = TinodeWeb.tnSetup(this.state.serverAddress, this.state.secureConnection, this.state.transport, this.props.intl.locale, _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in'), _ => { this.tinode.onConnect = this.handleConnected; this.tinode.onDisconnect = this.handleDisconnect; this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration; this.tinode.onInfoMessage = this.handleInfoMessage; this.tinode.onDataMessage = this.handleDataMessage; _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(''); }); }); } handleDeleteAccount() { return this.tinode.delCurrentUser(true).then(_ => { this.handleLogout(); }); } handleDeleteTopicRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.delTopic(true).then(_ => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic(window.location.hash, '')); }).catch(err => { this.handleError(err.message, 'err'); }); } handleDeleteMessagesRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.delMessagesAll(true).catch(err => this.handleError(err.message, 'err')); } handleLeaveUnsubRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.leave(true).then(_ => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic(window.location.hash, '')); }).catch(err => { this.handleError(err.message, 'err'); }); } handleBlockTopicRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.updateMode(null, '-JP').then(_ => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic(window.location.hash, '')); }).catch(err => this.handleError(err.message, 'err')); } handleReportTopic(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } const isP2P = topic.isP2PType(); const targetName = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_22__.topicDisplayName)(topicName, topic.public, topicName); const params = isP2P ? { target_type: 'user', target_id: topicName, target_name: targetName } : { target_type: 'group', target_id: topicName, topic: topicName, target_name: targetName }; topic.updateMode(null, '-JP').then(_ => { let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic(window.location.hash, ''); hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel(hash, 'abuse-report-reasons'); Object.entries(params).forEach(([key, value]) => { hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam(hash, key, value); }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(hash); }).catch(err => this.handleError(err.message, 'err')); } handleShowContextMenu(params, menuItems) { this.setState({ contextMenuVisible: true, contextMenuClickAt: { x: params.x, y: params.y }, contextMenuParams: params, contextMenuItems: menuItems || this.defaultTopicContextMenu(params.topicName), contextMenuBounds: this.selfRef.current.getBoundingClientRect() }); } handleShowForwardDialog(params) { if (this.state.sidePanelSelected == 'newtpk') { this.handleSidepanelCancel(); } const header = params.userName ? '➦ ' + params.userName : ''; const content = typeof params.content == 'string' ? tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.init(params.content) : tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.forwardedContent(params.content); const preview = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.preview(content, _config_js__WEBPACK_IMPORTED_MODULE_12__.FORWARDED_PREVIEW_LENGTH, true); const msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.append(tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.appendLineBreak(tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.mention(header, params.userFrom)), content); const msgPreview = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.quote(header, params.userFrom, preview); const head = { forwarded: params.topicName + ':' + params.seq }; this.setState({ forwardDialogVisible: true, forwardMessage: { head: head, msg: msg, preview: msgPreview } }); } handleShareTheCard(card) { this.setState({ forwardDialogVisible: true, forwardMessage: { content: card, type: card.contentType } }); } defaultTopicContextMenu(topicName) { const topic = this.tinode.getTopic(topicName); if (topic._deleted) { return ['topic_delete']; } const me = this.tinode.getMeTopic(); let muted = false, blocked = false, self_blocked = false, subscribed = false, deleter = false, archived = false, pinned = false, webrtc = false, writer = false, p2p = false, self = false; if (topic) { subscribed = topic.isSubscribed(); archived = topic.isArchived(); pinned = me.pinnedTopicRank(topicName) > 0; const acs = topic.getAccessMode(); if (acs) { muted = acs.isMuted(); blocked = !acs.isJoiner(); self_blocked = !acs.isJoiner('want'); deleter = acs.isDeleter(); writer = acs.isWriter(); } } webrtc = writer && !!this.tinode.getServerParam('iceServers'); p2p = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(topicName); self = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isSelfTopicName(topicName); return [subscribed ? { title: this.props.intl.formatMessage(messages.menu_item_info), handler: this.handleShowInfoView } : null, subscribed && p2p && webrtc ? { title: this.props.intl.formatMessage(messages.menu_item_audio_call), handler: this.handleStartAudioCall } : null, subscribed && p2p && webrtc ? { title: this.props.intl.formatMessage(messages.menu_item_video_call), handler: this.handleStartVideoCall } : null, subscribed ? 'messages_clear' : null, subscribed && deleter && !self ? 'messages_clear_hard' : null, self ? null : muted ? blocked ? null : 'topic_unmute' : 'topic_mute', self ? null : self_blocked ? 'topic_unblock' : 'topic_block', pinned ? 'topic_unpin' : 'topic_pin', archived ? 'topic_restore' : 'topic_archive', 'topic_delete']; } handleHideContextMenu() { this.setState({ contextMenuVisible: false, contextMenuClickAt: null, contextMenuParams: null, contextMenuBounds: null }); } handleHideForwardDialog(keepForwardedMessage) { this.setState({ forwardDialogVisible: false, forwardMessage: keepForwardedMessage ? this.state.forwardMessage : null }); } handleContextMenuAction(action, promise, params) { if (action == 'topic_archive') { if (promise && params.topicName && params.topicName == this.state.topicSelected) { promise.then(_ => { this.handleTopicSelected(null); }); } } else if (action == 'menu_item_forward') { this.handleShowForwardDialog(params); } else if (action == 'menu_item_select') { this.handleEnterSelectMode(params); } } handleEnterSelectMode(params) { this.setState({ selectMode: true, selectModeTopic: params.topicName, selectedSeqs: [params.seq] }); } handleToggleMessageSelect(seq) { const selectedSeqs = this.state.selectedSeqs.includes(seq) ? this.state.selectedSeqs.filter(s => s != seq) : this.state.selectedSeqs.concat(seq); this.setState({ selectedSeqs }); } handleExitSelectMode() { this.setState({ selectMode: false, selectModeTopic: null, selectedSeqs: [], batchForwardVisible: false }); } handleShowBatchForward() { this.setState({ batchForwardVisible: true }); } handleHideBatchForward() { this.setState({ batchForwardVisible: false }); } handleOpenScanner() { this.setState({ scannerOpen: true }); } handleCloseScanner() { this.setState({ scannerOpen: false }); } handleQrDetected(text) { const hasScheme = typeof text === 'string' && text.indexOf('im://qr') === 0; const params = hasScheme ? new URLSearchParams(text.slice(text.indexOf('?') + 1)) : null; const token = params ? params.get('token') : null; const purpose = params ? params.get('purpose') : null; if (!token) { this.setState({ scannerOpen: false }); this.handleError('无法识别的二维码', 'err'); return; } (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_18__.resolveQRCode)(token, purpose).then(data => { if (data.purpose === 'join_group' && data.group) { if (data.status === 'joined') { this.setState({ scannerOpen: false }); this.handleTopicSelected(data.group.topic); } else { this.setState({ scannerOpen: false, groupJoinPreview: { ...data.group, qrToken: token } }); } return; } if (data.user) { this.setState({ scannerOpen: false }); (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_19__.writeCachedData)('profile-seed:' + data.user.user_id, { ...data.user, capabilities: { can_add_friend: !!data.user.can_add } }); let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic(window.location.hash, ''); hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel(hash, data.user.relationship === 'friend' ? 'friend-profile' : 'group-member-profile'); hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam(hash, 'uid', data.user.user_id); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(hash); return; } this.setState({ scannerOpen: false }); this.handleError('无法识别的二维码', 'err'); }).catch(err => { this.setState({ scannerOpen: false }); this.handleError(err.message || '二维码已失效', 'err'); }); } handleSubmitGroupJoinRequest(message) { const preview = this.state.groupJoinPreview; if (!preview) { return Promise.resolve(); } return (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_18__.createGroupJoinRequest)(preview.topic, { message, source: 'qr', qrToken: preview.qrToken }).then(() => { this.setState({ groupJoinPreview: null }); this.handleError('申请已提交,等待管理员通过', 'info'); }).catch(err => { this.handleError(err.message || '申请提交失败', 'err'); }); } handleCancelGroupJoinPreview() { this.setState({ groupJoinPreview: null }); } handleShowAlert(title, content, onConfirm, confirmText, onReject, rejectText) { this.setState({ alertVisible: true, alertParams: { title: title, content: content, onConfirm: onConfirm, confirm: confirmText, onReject: onReject, reject: rejectText } }); } handleShowInfoView() { const topicName = this.state.topicSelected; if (tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(topicName)) { let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel('', 'friend-settings'); hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam(hash, 'uid', topicName); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(hash); return; } if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isSelfTopicName(topicName)) { let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel('', 'group-settings'); hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam(hash, 'topic', topicName); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(hash); return; } _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam(window.location.hash, 'info', 'info')); this.setState({ infoPanel: 'info' }); } handleMemberUpdateRequest(topicName, added, removed) { if (!topicName) { return; } const topic = this.tinode.getTopic(topicName); if (!topic) { return; } if (added && added.length > 0) { added.forEach(uid => { topic.invite(uid, null).catch(err => this.handleError(err.message, 'err')); }); } if (removed && removed.length > 0) { removed.forEach(uid => { topic.delSubscription(uid).catch(err => this.handleError(err.message, 'err')); }); } } handleValidateCredentialsRequest(cred, code, token) { if (this.tinode.isAuthenticated()) { this.tinode.getMeTopic().setMeta({ cred: { meth: cred, resp: code } }).then(_ => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel(window.location.hash, 'contacts'))).catch(err => this.handleError(err.message, 'err')); } else { this.setState({ credMethod: cred, credCode: code, credToken: token }); this.doLogin(null, null, token, { meth: cred, resp: code }); } } handlePasswordResetRequest(method, value) { return this.tinode.connect().then(_ => this.tinode.requestResetAuthSecret('basic', method, value)).catch(err => { this.handleError(err.message, 'err'); }); } handleResetPassword(newPassword, tempAuth) { const secret = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.base64ReEncode)(tempAuth.secret); if (!secret || !tempAuth.scheme) { this.handleError(this.props.intl.formatMessage(messages.invalid_security_token), 'err'); } else { this.tinode.connect().then(_ => this.tinode.updateAccountBasic(null, null, newPassword, { scheme: tempAuth.scheme, secret: secret })).then(_ => { this.handleError(this.props.intl.formatMessage(messages.password_reset_success), 'info'); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(''); }).catch(err => { this.handleError(err.message, 'err'); }); } } handleShowCountrySelector(code, dial, selectedCallback) { this.handleShowAlert(this.props.intl.formatMessage(messages.select_country), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: "Loading...", description: "Message shown when component is loading" }, void 0, false) }, void 0, false), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(PhoneCountrySelector, { selected: code, onSubmit: (c, d) => { this.setState({ alertVisible: false }); selectedCallback(c, d); } }, void 0, false) }, void 0, false), null, null, _ => {}, null); } handleStartVideoCall() { this.setState({ callTopic: this.state.topicSelected, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_OUTGOING_INITATED, callAudioOnly: false }); } handleStartAudioCall() { this.setState({ callTopic: this.state.topicSelected, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_OUTGOING_INITATED, callAudioOnly: true }); } handleCallInvite(callTopic, callSeq, callState, audioOnly) { switch (callState) { case _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_OUTGOING_INITATED: const head = { webrtc: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_HEAD_STARTED, aonly: !!audioOnly }; return this.handleSendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.videoCall(audioOnly), undefined, undefined, head).then(ctrl => { if (ctrl.code < 200 || ctrl.code >= 300 || !ctrl.params || !ctrl.params.seq) { this.handleCallClose(); return ctrl; } this.setState({ callSeq: ctrl.params['seq'] }); return ctrl; }); case _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS: const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('accept', callSeq); break; } } handleCallRinging(callTopic, callSeq) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('ringing', callSeq); } handleCallHangup(callTopic, callSeq) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('hang-up', callSeq); } handleCallSendOffer(callTopic, callSeq, sdp) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('offer', callSeq, sdp); } handleCallIceCandidate(callTopic, callSeq, candidate) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('ice-candidate', callSeq, candidate); } handleCallSendAnswer(callTopic, callSeq, sdp) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('answer', callSeq, sdp); } handleCallClose() { if (this.callTimeoutTimer) { clearTimeout(this.callTimeoutTimer); } this.setState({ callTopic: undefined, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_NONE, callAudioOnly: undefined }); } handleCallAccept(topicName, setCallTopic, callSeq) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } if (topic.isSubscribed()) { this.handleTopicSelected(setCallTopic ? topicName : this.state.callTopic); const upd = { callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS }; if (setCallTopic) { upd.callTopic = topicName; upd.callSeq = callSeq; } this.setState(upd); } else { this.setState({ callShouldStart: true }, _ => this.handleTopicSelected(this.state.callTopic)); } } handleInfoMessage(info) { if (info.what != 'call') { return; } switch (info.event) { case 'accept': if (tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isMeTopicName(info.topic) && this.tinode.isMe(info.from)) { this.setState({ callTopic: null, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_NONE, callSeq: null, callAudioOnly: undefined }); return; } if (info.topic == this.state.callTopic) { this.setState({ callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS }); } break; case 'hang-up': this.handleCallClose(); break; } } handleDataMessage(data) { if (data.head && data.head.webrtc && data.head.webrtc == _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_HEAD_STARTED && tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(data.topic)) { const topic = this.tinode.getTopic(data.topic); if (topic) { const msg = topic.latestMsgVersion(data.seq) || data; if (msg.head && msg.head.webrtc && msg.head.webrtc == _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_HEAD_STARTED) { if (data.from != this.state.myUserId) { if (this.state.callState == _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_NONE) { this.setState({ callTopic: data.topic, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_INCOMING_RECEIVED, callSeq: data.seq, callAudioOnly: !!msg.head.aonly }); } else { this.handleCallHangup(data.topic, data.seq); } } } } else { console.warn("Received vc data message from unknown topic", data.topic); } } } render() { const colorSchema = this.state.colorSchema !== 'auto' ? this.state.colorSchema : this.state.systemColorSchema; const activeProductView = this.state.sidePanelSelected || (this.state.myUserId ? 'messages-home' : 'tenant'); const chapterOneViews = ['tenant', 'login', 'enterprise-register', 'enterprise-feedback', 'register', 'reset', 'identity-check', 'realname', 'realname-verified', 'realname-reminder', 'independent-password']; const chapterOneActive = chapterOneViews.includes(activeProductView); const chapterTwoFullPage = ['messages-offline', 'messages-menu', 'message-actions', 'system-messages'].includes(activeProductView) || !this.state.myUserId && activeProductView === 'messages-home'; const chapterThreeActive = ['chat-inbound-request', 'chat-inbound-message', 'chat-outbound-request', 'chat-status', 'chat-friend', 'chat-media', 'chat-blocked', 'chat-deleted', 'chat-standard', 'chat-attachments', 'chat-mixed', 'chat-contact-card'].includes(activeProductView); const chapterFourActive = ['compose-keyboard', 'mentions-select', 'mentions-complete', 'mentions-message', 'emoji-panel', 'emoji-message', 'voice-ready', 'voice-hold', 'voice-recording', 'media-uploading', 'media-gallery', 'media-retry', 'upload-file', 'file-message', 'message-multiselect', 'favorite-success', 'forward-select', 'forward-multiple', 'forward-individual', 'forward-bundle'].includes(activeProductView); const chapterFiveActive = ['address-book', 'friend-requests', 'add-friend', 'my-friend-qr', 'friend-search-result', 'friend-verification', 'friend-profile', 'group-member-profile', 'friend-settings', 'friend-settings-blocked', 'friend-delete-confirm', 'block-list', 'block-confirm', 'clear-chat-confirm'].includes(activeProductView); const chapterSixActive = ['group-list', 'group-empty', 'group-invite', 'group-events', 'group-join-requests', 'group-new-request', 'group-announcement', 'group-summary', 'group-announcement-detail', 'group-settings', 'group-profile', 'group-avatar', 'group-nickname', 'group-description', 'group-my-nickname', 'group-role-message', 'group-qr', 'group-governance', 'group-admins', 'group-admin-add', 'group-admin-success', 'group-admin-partial', 'group-admin-removed', 'group-mute-add', 'group-muted', 'group-owner-select', 'group-owner-confirm', 'group-files', 'group-file-upload'].includes(activeProductView); const chapterSevenActive = ['favorites', 'favorites-mixed', 'favorites-files', 'favorites-text', 'favorites-voice', 'favorites-links', 'favorites-select', 'favorite-share', 'file-download', 'file-downloading', 'file-downloaded', 'history-search', 'history-files', 'history-links', 'history-images', 'history-videos'].includes(activeProductView); const callExperienceActive = ['call-history', 'call-incoming', 'audio-call-ringing', 'audio-call-active', 'audio-call-muted', 'audio-call-speaker', 'video-call-ringing', 'video-call-camera-off', 'video-call-active', 'video-call-peer-camera-off', 'call-minimized'].includes(activeProductView); const workplaceCollaborationActive = ['workbench', 'organization-directory', 'meeting-organizer', 'meeting-attendee', 'meeting-create', 'meeting-detail', 'daily-report-editor', 'daily-report-mine', 'daily-report-team', 'daily-report-detail', 'monthly-report-editor', 'monthly-report-list', 'monthly-report-detail', 'executive-mailbox', 'executive-mailbox-notice'].includes(activeProductView); const personalSettingsActive = ['personal-center', 'personal-profile', 'profile-nickname', 'profile-birth-date', 'profile-signature', 'profile-gender', 'profile-region', 'personal-qrcode', 'android-settings', 'cache-clear-confirm', 'clear-history-confirm', 'change-password', 'delete-account-confirm', 'app-version', 'privacy-settings', 'friend-discovery-settings', 'youth-mode-off', 'youth-mode-on', 'youth-mode-verify', 'notification-permission', 'permission-settings-reminder', 'camera-permission-info', 'microphone-permission-info'].includes(activeProductView); const securitySupportActive = ['fraud-risk-warning', 'fraud-risk-confirmation', 'abuse-report-reasons', 'abuse-report-details', 'user-feedback'].includes(activeProductView); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)("div", { id: "app-container", ref: this.selfRef, children: [this.state.contextMenuVisible ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(_widgets_context_menu_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { tinode: this.tinode, bounds: this.state.contextMenuBounds, clickAt: this.state.contextMenuClickAt, params: this.state.contextMenuParams, items: this.state.contextMenuItems, hide: this.handleHideContextMenu, onShowAlert: this.handleShowAlert, onAction: this.handleContextMenuAction, onTopicRemoved: topicName => { if (topicName == this.state.topicSelected) { this.handleTopicSelected(null); } }, onError: this.handleError }, void 0, false) : null, this.state.forwardDialogVisible ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(_widgets_forward_dialog_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], { tinode: this.tinode, contacts: this.state.chatList, topicSelected: this.state.topicSelected, myUserId: this.state.myUserId, hide: this.handleHideForwardDialog, onInitFind: this.tnInitFind, searchResults: this.state.searchResults, onSearchContacts: this.handleSearchContacts, onTopicSelected: this.handleStartTopicRequest }, void 0, false) : null, this.state.batchForwardVisible ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(_widgets_batch_forward_dialog_jsx__WEBPACK_IMPORTED_MODULE_8__["default"], { tinode: this.tinode, contacts: this.state.chatList, topicSelected: this.state.topicSelected, myUserId: this.state.myUserId, topicName: this.state.selectModeTopic, seqs: this.state.selectedSeqs, hide: sent => { this.handleHideBatchForward(); if (sent) { this.handleExitSelectMode(); } }, onInitFind: this.tnInitFind, searchResults: this.state.searchResults, onSearchContacts: this.handleSearchContacts }, void 0, false) : null, this.state.callTopic && this.state.callState == _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_INCOMING_RECEIVED ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(_widgets_call_incoming_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { tinode: this.tinode, topic: this.state.callTopic, seq: this.state.callSeq, callState: this.state.callState, audioOnly: this.state.callAudioOnly, onClose: this.handleCallClose, onRinging: this.handleCallRinging, onAcceptCall: this.handleCallAccept, onReject: this.handleCallHangup }, void 0, false) : null, this.state.scannerOpen ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(_widgets_qr_scanner_jsx__WEBPACK_IMPORTED_MODULE_10__["default"], { onDetect: this.handleQrDetected, onClose: this.handleCloseScanner }, void 0, false) : null, this.state.groupJoinPreview ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(_widgets_qr_scanner_jsx__WEBPACK_IMPORTED_MODULE_10__.GroupJoinPreview, { group: this.state.groupJoinPreview, onSubmit: this.handleSubmitGroupJoinRequest, onCancel: this.handleCancelGroupJoinPreview }, void 0, false) : null, this.state.alertVisible ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(_widgets_alert_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { title: this.state.alertParams.title, content: this.state.alertParams.content, onReject: this.state.alertParams.onReject ? _ => this.setState({ alertVisible: false }) : null, reject: this.state.alertParams.reject, onConfirm: this.state.alertParams.onConfirm ? _ => { this.setState({ alertVisible: false }); this.state.alertParams.onConfirm(); } : null, confirm: this.state.alertParams.confirm }, void 0, false) : null, !this.state.displayMobile || this.state.mobilePanel == 'sidepanel' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(_sidepanel_view_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], { tinode: this.tinode, connected: this.state.connected, displayMobile: this.state.displayMobile, state: this.state.sidePanelSelected, hashParams: this.state.sidePanelParams, title: this.state.sidePanelTitle, avatar: this.state.sidePanelAvatar, trustedBadges: this.state.myTrustedBadges, login: this.state.login, persist: this.state.persist, myUserId: this.state.myUserId, loginDisabled: this.state.loginDisabled, loadSpinnerVisible: this.state.loadSpinnerVisible, errorText: this.state.errorText, errorLevel: this.state.errorLevel, errorAction: this.state.errorAction, errorActionText: this.state.errorActionText, topicSelected: this.state.topicSelected, chatList: this.state.chatList, credMethod: this.state.credMethod, credCode: this.state.credCode, credToken: this.state.credToken, transport: this.state.transport, messageSounds: this.state.messageSounds, desktopAlerts: this.state.desktopAlerts, desktopAlertsEnabled: this.state.desktopAlertsEnabled, incognitoMode: this.state.incognitoMode, serverAddress: this.state.serverAddress, secureConnection: this.state.secureConnection, serverVersion: this.state.serverVersion, reqCredMethod: this.state.reqCredMethod, textSize: this.state.textSize, colorSchema: this.state.colorSchema, wallpaper: this.state.wallpaper, wallpaperSize: this.state.wallpaperSize, wallpaperBlur: this.state.wallpaperBlur, systemColorSchema: this.state.systemColorSchema, sendOnEnter: this.state.sendOnEnter, onGlobalSettings: this.handleGlobalSettings, onSignUp: this.handleNewAccount, onSettings: this.handleSettings, onNavigate: this.basicNavigator, onLoginRequest: this.handleLoginRequest, onTenantResolved: this.handleTenantResolved, onPersistenceChange: this.handlePersistenceChange, onCreateAccount: this.handleNewAccountRequest, onImRegisterRequest: this.handleImRegisterRequest, onUpdateAccountDesc: this.handleTopicUpdateRequest, onUpdatePassword: this.handleUpdatePasswordRequest, onUpdateAccountTags: this.handleUpdateAccountTagsRequest, onTogglePushNotifications: this.toggleFCMToken, onToggleMessageSounds: this.handleToggleMessageSounds, onToggleIncognitoMode: this.handleToggleIncognitoMode, onChangeColorSchema: this.handleChangeColorSchema, onTextSizeChanged: this.handleChangeTextSize, onSendOnEnterChanged: this.handleSendOnEnter, onSelectWallpapers: this.handleSelectWallpapers, onWallpaperSelected: this.handleWallpaperSelected, onCredAdd: this.handleCredAdd, onCredDelete: this.handleCredDelete, onCredConfirm: this.handleCredConfirm, onTopicSelected: this.handleTopicSelected, onOpenScanner: this.handleOpenScanner, onCreateTopic: this.handleStartTopicRequest, onLogout: this.handleLogout, onDeleteAccount: this.handleDeleteAccount, onShowAlert: this.handleShowAlert, onCancel: this.handleSidepanelCancel, onError: this.handleError, onValidateCredentials: this.handleValidateCredentialsRequest, onPasswordResetRequest: this.handlePasswordResetRequest, onResetPassword: this.handleResetPassword, onShowArchive: this.handleShowArchive, onShowBlocked: this.handleShowBlocked, onShowCountrySelector: this.handleShowCountrySelector, onInitFind: this.tnInitFind, searchResults: this.state.searchResults, onSearchContacts: this.handleSearchContacts, showContextMenu: this.handleShowContextMenu }, void 0, false) : null, !chapterOneActive && !chapterTwoFullPage && !chapterThreeActive && !chapterFourActive && !chapterFiveActive && !chapterSixActive && !chapterSevenActive && !callExperienceActive && !workplaceCollaborationActive && !personalSettingsActive && !securitySupportActive && (!this.state.displayMobile || this.state.mobilePanel == 'topic-view' && !this.state.infoPanel) ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: "Loading...", description: "Message shown when component is loading" }, void 0, false) }, void 0, false), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(MessagesView, { tinode: this.tinode, connected: this.state.connected, ready: this.state.ready, online: this.state.topicSelectedOnline, acs: this.state.topicSelectedAcs, displayMobile: this.state.displayMobile, viewportWidth: this.state.viewportWidth, viewportHeight: this.state.viewportHeight, topic: this.state.topicSelected, jumpToSeq: this.state.sidePanelParams && this.state.sidePanelParams.jumpseq, myUserId: this.state.myUserId, myUserName: this.state.sidePanelTitle, serverVersion: this.state.serverVersion, serverAddress: this.state.serverAddress, applicationVisible: this.state.applicationVisible, colorSchema: colorSchema, sendOnEnter: this.state.sendOnEnter, wallpaper: this.state.wallpaper, forwardMessage: this.state.forwardMessage, onCancelForwardMessage: this.handleHideForwardDialog, selectMode: this.state.selectMode && this.state.selectModeTopic == this.state.topicSelected, selectedSeqs: this.state.selectedSeqs, onToggleMessageSelect: this.handleToggleMessageSelect, onExitSelectMode: this.handleExitSelectMode, onShowBatchForward: this.handleShowBatchForward, callTopic: this.state.callTopic, callSeq: this.state.callSeq, callState: this.state.callState, callAudioOnly: this.state.callAudioOnly, onCallHangup: this.handleCallHangup, onAcceptCall: this.handleCallAccept, onCallInvite: this.handleCallInvite, onCallSendOffer: this.handleCallSendOffer, onCallIceCandidate: this.handleCallIceCandidate, onCallSendAnswer: this.handleCallSendAnswer, errorText: this.state.errorText, errorLevel: this.state.errorLevel, errorAction: this.state.errorAction, errorActionText: this.state.errorActionText, newTopicParams: this.state.newTopicParams, onHideMessagesView: this.handleHideMessagesView, onError: this.handleError, onNewTopicCreated: this.handleNewTopicCreated, showContextMenu: this.handleShowContextMenu, onChangePermissions: this.handleChangePermissions, onNewChat: this.handleNewChatInvitation, sendMessage: this.handleSendMessage, onVideoCallClosed: this.handleCallClose }, void 0, false) }, void 0, false) : null, this.state.infoPanel ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: "Loading...", description: "Message shown when component is loading" }, void 0, false) }, void 0, false), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_23__.jsxDEV)(InfoView, { tinode: this.tinode, connected: this.state.connected, displayMobile: this.state.displayMobile, topic: this.state.topicSelected, searchableContacts: this.state.searchableContacts, myUserId: this.state.myUserId, panel: this.state.infoPanel, errorText: this.state.errorText, errorLevel: this.state.errorLevel, errorAction: this.state.errorAction, errorActionText: this.state.errorActionText, onNavigate: this.infoNavigator, onTopicDescUpdateRequest: this.handleTopicUpdateRequest, onShowAlert: this.handleShowAlert, onChangePermissions: this.handleChangePermissions, onMemberUpdateRequest: this.handleMemberUpdateRequest, onDeleteTopic: this.handleDeleteTopicRequest, onDeleteMessages: this.handleDeleteMessagesRequest, onLeaveTopic: this.handleLeaveUnsubRequest, onBlockTopic: this.handleBlockTopicRequest, onReportTopic: this.handleReportTopic, onShareTheCard: this.handleShareTheCard, onTopicTagsUpdateRequest: this.handleTagsUpdateRequest, onTopicUnArchive: this.handleUnarchive, onInitFind: this.tnInitFind, onError: this.handleError, showContextMenu: this.handleShowContextMenu }, void 0, false) }, void 0, false) : null] }, void 0, true); } } ; /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(TinodeWeb)); /***/ }), /***/ "./src/views/topic-common-view.jsx": /*!*****************************************!*\ !*** ./src/views/topic-common-view.jsx ***! \*****************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ TopicCommonView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _widgets_topic_desc_edit_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../widgets/topic-desc-edit.jsx */ "./src/widgets/topic-desc-edit.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class TopicCommonView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); const topic = this.props.tinode.getTopic(this.props.topic); const acs = topic.getAccessMode(); this.state = { tags: [] }; this.previousTagsUpdated = undefined; this.onTagsUpdated = this.onTagsUpdated.bind(this); this.handleTagsUpdated = this.handleTagsUpdated.bind(this); } componentDidUpdate(props) { const topic = this.props.tinode.getTopic(props.topic); if (!topic) { return; } if (topic.onTagsUpdated != this.onTagsUpdated) { if (topic.getType() == 'grp') { this.previousTagsUpdated = topic.onTagsUpdated; topic.onTagsUpdated = this.onTagsUpdated; } else { this.previousTagsUpdated = undefined; } } if (this.state.topic != props.topic) { this.setState({ topic: props.topic }); } } componentWillUnmount() { const topic = this.props.tinode.getTopic(this.props.topic); topic.onTagsUpdated = this.previousTagsUpdated; } onTagsUpdated(tags) { this.setState({ tags: tags }); if (this.previousTagsUpdated && this.previousTagsUpdated != this.onTagsUpdated) { this.previousTagsUpdated(tags); } } handleTagsUpdated(tags) { if (!(0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_2__.arrayEqual)(this.state.tags.slice(0), tags.slice(0))) { this.props.onUpdateTagsRequest(this.props.topic, tags); } } render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "scrollable-panel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(_widgets_topic_desc_edit_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: this.props.tinode, topic: this.props.topic, onUpdateTopicDesc: this.props.onUpdateTopicDesc, onUpdateTags: this.handleTagsUpdated, onError: this.props.onError }, void 0, false) }, void 0, false); } } ; /***/ }), /***/ "./src/views/validation-view.jsx": /*!***************************************!*\ !*** ./src/views/validation-view.jsx ***! \***************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ phone: { id: 'phone_dative', defaultMessage: 'phone', description: "Dative case of 'phone', i.e. 'phone' in 'by phone'" }, email: { id: 'email_dative', defaultMessage: 'email', description: "Dative case of 'email', i.e. 'email' in 'by email'" } }); class ValidationView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { code: props.credCode || '', codeReceived: props.credCode }; this.handleCodeChange = this.handleCodeChange.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); } static getDerivedStateFromProps(nextProps, prevState) { if (nextProps.credCode != prevState.codeReceived) { return { code: nextProps.credCode || '', codeReceived: nextProps.credCode }; } return prevState; } componentDidMount() { if (this.props.credCode) { this.props.onSubmit(this.props.credMethod, this.props.credCode, this.props.credToken); } } componentDidUpdate(prevProps, prevState) { if (this.state.codeReceived && this.state.code && this.state.code != prevState.code) { this.props.onSubmit(this.props.credMethod, this.state.code, this.props.credToken); } } handleCodeChange(e) { this.setState({ code: e.target.value.replace(/[^\d]/g, '') }); } handleKeyPress(e) { if (e.key === 'Enter') { this.handleSubmit(e); } else if (e.key == 'Escape') { this.handleCancel(e); } } handleSubmit(e) { e.preventDefault(); if (this.state.code && this.state.code.trim()) { this.props.onSubmit(this.props.credMethod, this.state.code.trim(), this.props.credToken); } } handleCancel(e) { e.preventDefault(); this.props.onCancel(); } render() { const { formatMessage } = this.props.intl; const methods = { 'email': formatMessage(messages.email), 'tel': formatMessage(messages.phone) }; const method = methods[this.props.credMethod] || this.props.credMethod; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("label", { className: "small gray", htmlFor: "enter-confirmation-code", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "enter_confirmation_code_prompt", defaultMessage: "Confirmation code", description: "Request to enter confirmation code", values: { method: method } }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "numeric_confirmation_code_prompt", defaultMessage: "Numbers only", description: "Prompt for numeric conformation code", children: numbers_only => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { type: "text", id: "enter-confirmation-code", placeholder: numbers_only, value: this.state.code, onChange: this.handleCodeChange, onKeyDown: this.handleKeyPress, required: true }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "dialog-buttons", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { className: "secondary", onClick: this.handleCancel, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: "Cancel", description: "Button [Cancel]" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { className: "primary", onClick: this.handleSubmit, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_confirm", defaultMessage: "Confirm", description: "Button [Confirm]" }, void 0, false) }, void 0, false)] }, void 0, true)] }, void 0, true); } } ; /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ValidationView)); /***/ }), /***/ "./src/views/workplace-collaboration-view.jsx": /*!****************************************************!*\ !*** ./src/views/workplace-collaboration-view.jsx ***! \****************************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WORKPLACE_COLLABORATION_VIEWS: function() { return /* binding */ WORKPLACE_COLLABORATION_VIEWS; }, /* harmony export */ "default": function() { return /* binding */ WorkplaceCollaborationView; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../widgets/contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var _lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/use-cached-data.js */ "./src/lib/use-cached-data.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const navigate = (view, params) => { let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].setUrlSidePanel(window.location.hash, view); Object.entries(params || {}).forEach(([key, value]) => { hash = value ? _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].addUrlParam(hash, key, value) : _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].removeUrlParam(hash, key); }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].navigateTo(hash); }; const WORKPLACE_COLLABORATION_VIEWS = ['workbench', 'organization-directory', 'meeting-organizer', 'meeting-attendee', 'meeting-create', 'meeting-detail', 'daily-report-editor', 'daily-report-mine', 'daily-report-team', 'daily-report-detail', 'monthly-report-editor', 'monthly-report-list', 'monthly-report-detail', 'executive-mailbox', 'executive-mailbox-notice']; function Icon({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", { className: "material-icons", "aria-hidden": "true", children: children }, void 0, false); } function Header({ title, back = 'workbench', action, actionLabel, onAction, actionDisabled }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("header", { className: "workplace-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", onClick: () => { if (!_lib_navigation_js__WEBPACK_IMPORTED_MODULE_2__["default"].goBack()) navigate(back); }, "aria-label": "返回", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("h1", { children: title }, void 0, false), action ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", onClick: onAction, "aria-label": actionLabel || '操作', disabled: actionDisabled, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: action }, void 0, false) }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", {}, void 0, false)] }, void 0, true); } function Toast({ message, onDone }) { react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!message) return undefined; const timer = window.setTimeout(onDone, 2100); return () => window.clearTimeout(timer); }, [message, onDone]); return message ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-toast", role: "status", children: message }, void 0, false) : null; } const WEEKDAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']; function formatMeetingDate(d) { const now = new Date(); const dayDiff = Math.round((new Date(d.getFullYear(), d.getMonth(), d.getDate()) - new Date(now.getFullYear(), now.getMonth(), now.getDate())) / 86_400_000); const suffix = dayDiff === 0 ? '(今天)' : dayDiff === 1 ? '(明天)' : dayDiff === -1 ? '(昨天)' : ''; return `${d.getMonth() + 1}月${d.getDate()}日 ${WEEKDAYS[d.getDay()]}${suffix}`; } function formatTime(d) { return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`; } function toDateInputValue(d) { return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; } const nameCache = new Map(); function resolveUserName(id, onDone) { if (!id) return; if (nameCache.has(id)) { onDone(nameCache.get(id)); return; } const withPrefix = id.startsWith('usr') ? id : 'usr' + id; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getUserProfile)(id).catch(() => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getUserProfile)(withPrefix)).then(p => { const name = p && (p.display_name || p.nickname || p.public_account) || id; nameCache.set(id, name); onDone(name); }).catch(() => { nameCache.set(id, id); onDone(id); }); } function useUserNames(ids, myUserId) { const [names, setNames] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({}); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (ids || []).forEach(id => { if (!id || names[id] !== undefined) return; const prefixed = id.startsWith('usr') ? id : 'usr' + id; if (myUserId && prefixed === myUserId) { setNames(v => ({ ...v, [id]: '我' })); return; } resolveUserName(id, name => setNames(v => ({ ...v, [id]: name }))); }); }, [JSON.stringify(ids), myUserId]); return names; } const APP_TONES = { organization: 'red', attendance: 'orange', meetings: 'blue', daily_reports: 'orange', monthly_reports: 'violet', executive_mailbox: 'green' }; const APP_ICONS = { organization: 'account_tree', attendance: 'schedule', meetings: 'notifications_active', daily_reports: 'task_alt', monthly_reports: 'event_note', executive_mailbox: 'mail_outline' }; const APP_ROUTES = { organization: 'organization-directory', meetings: 'meeting-attendee', daily_reports: 'daily-report-mine', monthly_reports: 'monthly-report-list', executive_mailbox: 'executive-mailbox' }; function Workbench({ onToast }) { const [me] = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.useCachedData)('me', _lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getMe, []); const [modules, setModules] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)('workbench-modules') || []); const [icons, setIcons] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({}); const [error, setError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getWorkbench)().then(data => { const list = data && data.modules || []; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)('workbench-modules', list); setModules(list); list.forEach(m => { if (m.icon_file_id) { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getFileUrl)(m.icon_file_id).then(url => url && setIcons(v => ({ ...v, [m.code]: url }))).catch(() => {}); } }); }).catch(err => setError(err.message || '工作台加载失败')); }, []); const openApp = app => { if (APP_ROUTES[app.code]) { navigate(APP_ROUTES[app.code]); return; } onToast && onToast('该功能暂未开放'); }; const profile = me && me.profile; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page workbench-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "workbench-profile", children: [profile && profile.avatar_file_id ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(ImgFromFile, { fileId: profile.avatar_file_id }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { className: "workbench-avatar-fallback", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "person" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: profile && (profile.nickname || profile.public_account) || '…' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: "员工" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", "aria-label": "工作台设置", onClick: () => navigate('personal-center'), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "tune" }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "workbench-banner", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: "提高效率,从工作台开始" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: "Business applications start from the workbench" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "business_center" }, void 0, false)] }, void 0, true), error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "workplace-error", children: error }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "workbench-apps", "aria-label": "办公应用", children: modules.filter(m => m.enabled).map(app => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", onClick: () => openApp(app), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { className: 'tone-' + (APP_TONES[app.code] || 'blue'), children: [icons[app.code] ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("img", { src: icons[app.code], alt: "" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: APP_ICONS[app.code] || 'apps' }, void 0, false), app.unread_count ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("em", { children: app.unread_count > 99 ? '99+' : app.unread_count }, void 0, false) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: app.name }, void 0, false)] }, app.code, true)) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("nav", { className: "workplace-bottom-nav", "aria-label": "主导航", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: "active", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "dashboard" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: "工作台" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", onClick: () => navigate('messages-home'), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "chat_bubble_outline" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: "消息" }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true); } function ImgFromFile({ fileId, className }) { const [url, setUrl] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { let live = true; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getFileUrl)(fileId).then(u => live && setUrl(u)).catch(() => {}); return () => { live = false; }; }, [fileId]); return url ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("img", { className: className, src: url, alt: "" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { className: className }, void 0, false); } function DeptRow({ dept, depth, expanded, onToggle }) { const icon = depth === 0 ? 'business' : 'diamond'; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: `organization-department depth-${depth}${expanded ? ' expanded' : ''}`, style: { paddingLeft: `${1 + depth * 1.1}rem` }, onClick: onToggle, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: icon }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: [dept.name, typeof dept.member_count === 'number' ? `${dept.member_count}人` : '', "(", depth === 0 ? '一级' : depth === 1 ? '二级' : `${depth + 1}级`, ")"] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: expanded ? 'expand_more' : 'chevron_right' }, void 0, false)] }, void 0, true); } function SearchDeptRow({ dept }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "organization-department depth-0", style: { paddingLeft: '1rem' }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "business" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: [dept.name, typeof dept.member_count === 'number' ? `(${dept.member_count}人)` : ''] }, void 0, true) }, void 0, false)] }, void 0, true); } function PersonRow({ person, depth, isMe, level }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: `organization-person${isMe ? ' me' : ''}`, style: { paddingLeft: `${1 + depth * 1.1}rem` }, onClick: () => navigate('group-member-profile', { uid: person.user_id }), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "radio_button_unchecked" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: [person.display_name, "(", level, "级)"] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true); } function DeptNode({ dept, depth, myUserId }) { const [expanded, setExpanded] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(depth === 0); const [children, setChildren] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [members, setMembers] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const load = () => { if (children != null) return; setLoading(true); Promise.all([(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getOrganizationDepartments)(dept.department_id).then(d => d.departments || d.items || []), dept.member_count ? (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getOrganizationDepartmentMembers)(dept.department_id).then(d => d.members || d.items || []) : Promise.resolve([])]).then(([depts, mems]) => { setChildren(depts); setMembers(mems); }).finally(() => setLoading(false)); }; const toggle = () => { const next = !expanded; setExpanded(next); if (next) load(); }; react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (expanded) load(); }, []); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(DeptRow, { dept: dept, depth: depth, expanded: expanded, onToggle: toggle }, void 0, false), expanded && loading ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: "加载中…" }, void 0, false) : null, expanded && !loading ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.Fragment, { children: [(children || []).map(child => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(DeptNode, { dept: child, depth: depth + 1, myUserId: myUserId }, child.department_id, false)), (members || []).map(person => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(PersonRow, { person: person, depth: depth + 1, level: depth + 2, isMe: person.user_id === myUserId || 'usr' + person.user_id === myUserId }, person.user_id, false))] }, void 0, true) : null] }, void 0, true); } function durationLabel(startAt, endAt) { const mins = Math.round((new Date(endAt) - new Date(startAt)) / 60_000); if (mins <= 0) return ''; if (mins % 60 === 0) return `${mins / 60}小时`; if (mins < 60) return `${mins}分钟`; return `${Math.floor(mins / 60)}小时${mins % 60}分钟`; } const RESPONSE_LABEL = { accepted: '已接受', declined: '已拒绝', tentative: '待定' }; function MeetingCard({ meeting, myUserId, onRespond, onToast }) { const organizerName = meeting.organizer && meeting.organizer.display_name || meeting.organizer_display_name || meeting.organizer_id; const attendeeNames = (meeting.participants || []).map(p => p.display_name || p.user_id).join('、'); const isOrganizer = meeting.organizer_id === myUserId; const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const respond = response => { setBusy(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getMeeting)(meeting.meeting_id).then(fresh => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.respondMeeting)(fresh.meeting_id, response, fresh.version)).then(_ => { onRespond(); onToast(response === 'accepted' ? '已接受会议邀请' : response === 'declined' ? '已拒绝会议邀请' : '已标记为待定'); }).catch(err => onToast(err.message || '操作失败')).finally(() => setBusy(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("article", { className: "meeting-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("header", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: [formatMeetingDate(new Date(meeting.start_at)), " ", formatTime(new Date(meeting.start_at))] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: ["会议主题:", meeting.title] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: "meeting-more", onClick: () => navigate('meeting-detail', { meeting_id: meeting.meeting_id }), children: ["查看更多", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dl", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", { children: "发起人" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dd", { children: organizerName }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", { children: "时间" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dd", { children: formatMeetingDate(new Date(meeting.start_at)) }, void 0, false)] }, void 0, true), meeting.location ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", { children: "地点" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dd", { children: meeting.location }, void 0, false)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", { children: "参会人" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dd", { className: "meeting-attendees", children: attendeeNames || '无' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", { children: "会议时间" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dd", { children: durationLabel(meeting.start_at, meeting.end_at) }, void 0, false)] }, void 0, true)] }, void 0, true), !isOrganizer ? meeting.my_response && meeting.my_response !== 'pending' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("footer", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: "meeting-responded", disabled: true, children: RESPONSE_LABEL[meeting.my_response] || meeting.my_response }, void 0, false) }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("footer", { className: "meeting-response", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", disabled: busy, onClick: () => respond('declined'), children: "拒绝" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: "primary", disabled: busy, onClick: () => respond('accepted'), children: "接受" }, void 0, false)] }, void 0, true) : null] }, void 0, true); } function Meetings({ onToast }) { const [meetings, setMeetings] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)('meetings') || null); const [me] = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.useCachedData)('me', _lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getMe, []); const myUserId = me && me.user_id; const load = () => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getMeetings)().then(d => { const list = d.meetings || d.items || []; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)('meetings', list); setMeetings(list); }).catch(() => setMeetings(prev => prev || [])); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { load(); }, []); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "会议通知", action: "add", actionLabel: "发起会议", onAction: () => navigate('meeting-create') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { className: "meeting-list", children: meetings == null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: "加载中…" }, void 0, false) : meetings.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: "暂无会议通知" }, void 0, false) : meetings.map(m => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(MeetingCard, { meeting: m, myUserId: myUserId, onRespond: load, onToast: onToast }, m.meeting_id, false)) }, void 0, false)] }, void 0, true); } function MeetingDetail({ hashParams, onToast }) { const meetingId = hashParams && hashParams.meeting_id; const [meeting, setMeeting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => meetingId && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)('meeting:' + meetingId) || null); const [me] = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.useCachedData)('me', _lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getMe, []); const myUserId = me && me.user_id; const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const load = () => meetingId && (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getMeeting)(meetingId).then(m => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)('meeting:' + meetingId, m); setMeeting(m); }).catch(err => { onToast(err.message || '加载失败'); setLoadError(true); }); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (meetingId) setMeeting((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)('meeting:' + meetingId) || null); load(); }, [meetingId]); if (!meeting) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "会议详情", back: "meeting-attendee" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: loadError ? '会议信息加载失败' : '加载中…' }, void 0, false) }, void 0, false)] }, void 0, true); const counts = { accepted: 0, pending: 0, declined: 0, tentative: 0 }; (meeting.participants || []).forEach(p => { counts[p.response] = (counts[p.response] || 0) + 1; }); const isOrganizer = meeting.organizer_id === myUserId; const remind = () => { setBusy(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.sendMeetingReminders)(meeting.meeting_id).then(_ => onToast('已提醒未响应成员')).catch(err => onToast(err.message || '提醒失败')).finally(() => setBusy(false)); }; const cancel = () => { setBusy(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getMeeting)(meeting.meeting_id).then(fresh => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.cancelMeeting)(fresh.meeting_id, fresh.version)).then(_ => { onToast('会议已取消'); load(); }).catch(err => onToast(err.message || '取消失败')).finally(() => setBusy(false)); }; const respond = response => { setBusy(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getMeeting)(meeting.meeting_id).then(fresh => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.respondMeeting)(fresh.meeting_id, response, fresh.version)).then(_ => { onToast(RESPONSE_LABEL[response] ? `已${RESPONSE_LABEL[response]}` : '已回应'); load(); }).catch(err => onToast(err.message || '操作失败')).finally(() => setBusy(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "会议详情", back: "meeting-attendee" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { className: "meeting-list", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("article", { className: "meeting-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("header", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: [formatMeetingDate(new Date(meeting.start_at)), " ", formatTime(new Date(meeting.start_at))] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: ["会议主题:", meeting.title] }, void 0, true)] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dl", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", { children: "发起人" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dd", { children: meeting.organizer && meeting.organizer.display_name || meeting.organizer_display_name || meeting.organizer_id }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", { children: "时间" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dd", { children: [formatMeetingDate(new Date(meeting.start_at)), " ", formatTime(new Date(meeting.start_at)), " - ", formatTime(new Date(meeting.end_at))] }, void 0, true)] }, void 0, true), meeting.location ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", { children: "地点" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dd", { children: meeting.location }, void 0, false)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", { children: "会议时间" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dd", { children: durationLabel(meeting.start_at, meeting.end_at) }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("ul", { className: "meeting-participant-list", children: (meeting.participants || []).map(p => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("li", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: p.display_name || p.user_id }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("em", { className: p.response, children: RESPONSE_LABEL[p.response] || '待确认' }, void 0, false)] }, p.user_id, true)) }, void 0, false), !isOrganizer && meeting.permissions && meeting.permissions.can_respond && (!meeting.my_response || meeting.my_response === 'pending') ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("footer", { className: "meeting-response", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", disabled: busy, onClick: () => respond('declined'), children: "无法参加" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", disabled: busy, onClick: () => respond('tentative'), children: "待定" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: "primary", disabled: busy, onClick: () => respond('accepted'), children: "接受" }, void 0, false)] }, void 0, true) : null] }, void 0, true), isOrganizer ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "meeting-status", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("h2", { children: "参会确认" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: counts.accepted }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: "已接受" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: counts.pending }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: "待响应" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: counts.declined }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: "已拒绝" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("footer", { children: [meeting.permissions && meeting.permissions.can_remind ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", disabled: busy, onClick: remind, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "notifications" }, void 0, false), "提醒未响应"] }, void 0, true) : null, meeting.permissions && meeting.permissions.can_cancel && meeting.state !== 'cancelled' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: "danger", disabled: busy, onClick: cancel, children: "取消会议" }, void 0, false) : null] }, void 0, true)] }, void 0, true) : null] }, void 0, true)] }, void 0, true); } function MeetingCreate({ myUserId, tinode, onToast }) { const [title, setTitle] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [date, setDate] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(toDateInputValue(new Date())); const [startTime, setStartTime] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [endTime, setEndTime] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [location, setLocation] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [candidates, setCandidates] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [selected, setSelected] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [names, setNames] = react__WEBPACK_IMPORTED_MODULE_0___default().useState({}); const [submitting, setSubmitting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { const handle = window.setTimeout(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getOrganizationMembers)({ query }).then(d => setCandidates(d.members || d.items || [])).catch(() => setCandidates([])); }, 300); return () => window.clearTimeout(handle); }, [query]); const toggle = uid => { setSelected(v => v.includes(uid) ? v.filter(x => x != uid) : v.concat(uid)); const cand = candidates.find(c => c.user_id === uid); if (cand) setNames(v => ({ ...v, [uid]: cand.display_name })); }; const contacts = candidates.map(c => ({ user: c.user_id, public: { fn: c.display_name } })); const submit = () => { if (!title.trim() || !date || !startTime || !endTime || selected.length === 0) { onToast('请完善会议主题、时间与参会人'); return; } const startAt = new Date(`${date}T${startTime}:00`).toISOString(); const endAt = new Date(`${date}T${endTime}:00`).toISOString(); setSubmitting(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.createMeeting)({ title: title.trim(), start_at: startAt, end_at: endAt, location: location.trim(), attendee_user_ids: selected }).then(_ => { onToast('会议已发起'); navigate('meeting-attendee'); }).catch(err => onToast(err.message || '发起会议失败')).finally(() => setSubmitting(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page report-editor-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "发起会议", back: "meeting-attendee" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "report-field", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: "*" }, void 0, false), "会议主题"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { type: "text", value: title, maxLength: "80", onChange: e => setTitle(e.target.value), placeholder: "请输入会议主题" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "report-field", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: "*" }, void 0, false), "日期"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { type: "date", value: date, onChange: e => setDate(e.target.value) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "meeting-time-range", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "report-field", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: "*" }, void 0, false), "开始时间"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { type: "time", value: startTime, onChange: e => setStartTime(e.target.value) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "report-field", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: "*" }, void 0, false), "结束时间"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { type: "time", value: endTime, onChange: e => setEndTime(e.target.value) }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "report-field", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: "地点" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { type: "text", value: location, maxLength: "60", onChange: e => setLocation(e.target.value), placeholder: "请输入会议地点(可选)" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "report-field", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: "*" }, void 0, false), "参会人"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { type: "text", value: query, onChange: e => setQuery(e.target.value), placeholder: "搜索姓名添加参会人" }, void 0, false)] }, void 0, true), selected.length ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "meeting-selected-attendees", children: selected.map(uid => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [names[uid] || uid, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", { className: "material-icons", onClick: () => toggle(uid), children: "close" }, void 0, false)] }, uid, true)) }, void 0, false) : null, tinode ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(_widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: tinode, contacts: contacts, myUserId: myUserId, emptyListMessage: "搜索同事姓名", showOnline: false, showUnread: false, showContextMenu: false, topicSelected: selected, onTopicSelected: toggle }, void 0, false) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("footer", { className: "workplace-submit-bar", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", disabled: submitting, onClick: submit, children: submitting ? '发起中…' : '发起会议' }, void 0, false) }, void 0, false)] }, void 0, true); } function OrganizationDirectory({ myUserId }) { const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [searchResults, setSearchResults] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [roots, setRoots] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)('org-roots') || null); const [tenantName, setTenantName] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getOrganizationDepartments)('root').then(d => { const list = d.departments || d.items || []; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)('org-roots', list); setRoots(list); }).catch(() => setRoots(prev => prev || [])); try { const tenant = JSON.parse(window.localStorage.getItem('im-tenant') || '{}'); setTenantName(tenant.name || ''); } catch (_) {} }, []); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!query.trim()) { setSearchResults(null); return; } const handle = window.setTimeout(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.searchOrganization)(query).then(d => setSearchResults(d.items || [])).catch(() => setSearchResults([])); }, 300); return () => window.clearTimeout(handle); }, [query]); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "部门组织框架", back: "workbench" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { className: "organization-content", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "workplace-search", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "search" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { value: query, onChange: event => setQuery(event.target.value), placeholder: "搜索成员或部门" }, void 0, false)] }, void 0, true), searchResults ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "organization-tree", children: searchResults.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: "未找到匹配的成员" }, void 0, false) : searchResults.map((item, idx) => item.type === 'department' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(SearchDeptRow, { dept: item.department }, 'd' + (item.department && item.department.department_id || idx), false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(PersonRow, { person: item.user, depth: 0, level: "三", isMe: item.user && (item.user.user_id === myUserId || 'usr' + item.user.user_id === myUserId) }, 'u' + (item.user && item.user.user_id || idx), false)) }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "organization-tree", children: roots == null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: "加载中…" }, void 0, false) : roots.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: "暂无组织架构数据" }, void 0, false) : roots.map(dept => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(DeptNode, { dept: dept, depth: 0, myUserId: myUserId }, dept.department_id, false)) }, void 0, false)] }, void 0, true)] }, void 0, true); } function blocksToContent(blocks) { return blocks.filter(b => b.content.trim()).map(b => (b.start && b.end ? `${b.start}-${b.end}\n` : '') + b.content.trim()).join('\n\n'); } function DailyReportEditor({ onToast }) { const today = toDateInputValue(new Date()); const cacheKey = 'daily-report-editor:' + today; const cached = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)(cacheKey); const [reportId, setReportId] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(cached ? cached.reportId : null); const [version, setVersion] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(cached ? cached.version : null); const versionRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(cached ? cached.version : null); const setVersionBoth = v => { versionRef.current = v; setVersion(v); }; const [blocks, setBlocks] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(cached ? cached.blocks : [{ start: '', end: '', content: '' }]); const [saved, setSaved] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [saveError, setSaveError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [submitting, setSubmitting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const saveChainRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(Promise.resolve()); const draftTimerRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); const saveDraft = react__WEBPACK_IMPORTED_MODULE_0___default().useCallback(nextBlocks => { const run = () => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.updateDailyDraft)(reportId, blocksToContent(nextBlocks), versionRef.current, []).then(r => { setVersionBoth(r.version); setSaved(true); setSaveError(false); (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)(cacheKey, { reportId, version: r.version, blocks: nextBlocks }); return r; }); const next = saveChainRef.current.then(run); saveChainRef.current = next.catch(() => {}); return next; }, [reportId]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.createDailyReport)(today).then(r => { if (r.permissions && r.permissions.can_edit === false) { navigate('daily-report-detail', { report_id: r.report_id }); return; } const nextBlocks = r.content ? [{ start: '', end: '', content: r.content }] : [{ start: '', end: '', content: '' }]; setReportId(r.report_id); setVersionBoth(r.version); setBlocks(nextBlocks); (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)(cacheKey, { reportId: r.report_id, version: r.version, blocks: nextBlocks }); }).catch(err => onToast(err.message || '创建日报失败')); }, []); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!reportId) return undefined; setSaved(false); draftTimerRef.current = window.setTimeout(() => { draftTimerRef.current = null; saveDraft(blocks).catch(() => setSaveError(true)); }, 600); return () => window.clearTimeout(draftTimerRef.current); }, [blocks, reportId, saveDraft]); const updateBlock = (idx, field, value) => setBlocks(v => v.map((b, i) => i === idx ? { ...b, [field]: value } : b)); const addBlock = () => setBlocks(v => v.concat({ start: '', end: '', content: '' })); const removeBlock = idx => setBlocks(v => v.length > 1 ? v.filter((_, i) => i !== idx) : v); const submit = () => { const content = blocksToContent(blocks); if (!content.trim()) { onToast('请填写今日工作总结'); return; } setSubmitting(true); if (draftTimerRef.current) { window.clearTimeout(draftTimerRef.current); draftTimerRef.current = null; } saveDraft(blocks).then(r => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.submitDailyReport)(reportId, r.version)).then(_ => { onToast('日报已提交'); window.setTimeout(() => navigate('daily-report-detail', { report_id: reportId }), 500); }).catch(err => onToast(err.message || '提交失败')).finally(() => setSubmitting(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page report-editor-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "日报", back: "daily-report-mine" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { children: [blocks.map((block, idx) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "daily-report-block", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "daily-report-block-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: "日报" }, void 0, false), blocks.length > 1 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", onClick: () => removeBlock(idx), "aria-label": "删除", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "close" }, void 0, false) }, void 0, false) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "report-field", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: "起止时间" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { className: "daily-report-date", children: formatMeetingDate(new Date(today)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "meeting-time-range", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { type: "time", value: block.start, onChange: e => updateBlock(idx, 'start', e.target.value) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: "至" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { type: "time", value: block.end, onChange: e => updateBlock(idx, 'end', e.target.value) }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "report-field", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: "今日工作总结" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("textarea", { value: block.content, maxLength: "1000", placeholder: "请输入", onChange: e => updateBlock(idx, 'content', e.target.value) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: [block.content.length, "/1000"] }, void 0, true)] }, void 0, true)] }, idx, true)), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: "daily-report-add-block", onClick: addBlock, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "add" }, void 0, false), "添加时间段"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "report-draft-status", children: saveError ? '草稿保存失败,请检查网络后重新编辑' : saved ? '草稿已自动保存' : '正在保存草稿…' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("footer", { className: "workplace-submit-bar", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", disabled: submitting || !reportId, onClick: submit, children: submitting ? '提交中…' : '提交' }, void 0, false) }, void 0, false)] }, void 0, true); } const STATUS_LABEL = { submitted: '已提交', draft: '未提交' }; function DailyReportCard({ report, names, team }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("article", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("header", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: names[report.author_id] || report.author_id }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { className: "role-badge", children: team ? report.department_name || '员工' : '员工' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("em", { className: report.status, children: STATUS_LABEL[report.status] || report.status }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { children: report.content_short || '(未填写内容)' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("footer", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "schedule" }, void 0, false), report.report_date] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", onClick: () => navigate('daily-report-detail', { report_id: report.report_id }), children: ["查看详情", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true); } function DailyReportList({ team, myUserId, onToast }) { const cacheKey = 'daily-reports:' + (team ? 'managed' : 'mine'); const statsCacheKey = 'daily-stats:' + toDateInputValue(new Date()); const [reports, setReports] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)(cacheKey) || null); const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [stats, setStats] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => team && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)(statsCacheKey) || null); const ids = (reports || []).map(r => r.author_id); const names = useUserNames(ids, myUserId); const load = () => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getDailyReports)({ scope: team ? 'managed' : 'mine' }).then(d => { const list = d.reports || d.items || []; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)(cacheKey, list); setReports(list); }).catch(() => setReports(prev => prev || [])); if (team) (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getDailyStatistics)(toDateInputValue(new Date())).then(s => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)(statsCacheKey, s); setStats(s); }).catch(() => {}); }; react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(load, [team]); const filtered = (reports || []).filter(r => { const hay = team ? `${names[r.author_id] || ''}${r.department_name || ''}` : r.report_date; return hay.includes(query); }); const remindMissing = () => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.sendDailyReminders)(toDateInputValue(new Date())).then(_ => onToast('已提醒未提交成员')).catch(err => onToast(err.message || '提醒失败')); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page report-list-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "日报", action: "add", actionLabel: "填写日报", onAction: () => navigate('daily-report-editor'), back: team ? 'daily-report-mine' : 'workbench' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { children: [team && stats ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "report-statistics", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("header", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: formatMeetingDate(new Date()) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: "全公司" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", onClick: () => navigate('daily-report-mine'), children: "我的日报" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: stats.expected_count || 0 }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: "应提交" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: stats.submitted_count || 0 }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: "已提交" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: (stats.expected_count || 0) - (stats.submitted_count || 0) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: "未提交" }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", onClick: remindMissing, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "notifications_active" }, void 0, false), "提醒未提交成员"] }, void 0, true)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "workplace-search", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "search" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { value: query, onChange: e => setQuery(e.target.value), placeholder: team ? '搜索姓名/部门' : '搜索日期' }, void 0, false)] }, void 0, true), !team ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("nav", { className: "report-role-switch", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: "active", children: "我的日报" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", onClick: () => navigate('daily-report-team'), children: "团队统计" }, void 0, false)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "report-cards", children: reports == null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: "加载中…" }, void 0, false) : filtered.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: "暂无日报" }, void 0, false) : filtered.map(r => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(DailyReportCard, { report: r, names: names, team: team }, r.report_id, false)) }, void 0, false)] }, void 0, true)] }, void 0, true); } function DailyReportDetail({ hashParams, myUserId, onToast }) { const reportId = hashParams && hashParams.report_id; const [report, setReport] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => reportId && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)('daily-report:' + reportId) || null); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const names = useUserNames(report ? [report.author_id] : [], myUserId); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!reportId) return; setReport((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)('daily-report:' + reportId) || null); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getDailyReport)(reportId).then(r => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)('daily-report:' + reportId, r); setReport(r); }).catch(err => { onToast(err.message || '日报加载失败'); setLoadError(true); }); }, [reportId]); if (!report) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "查看详情", back: "daily-report-mine" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: loadError ? '日报加载失败' : '加载中…' }, void 0, false) }, void 0, false)] }, void 0, true); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "查看详情", back: "daily-report-mine" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { className: "report-detail", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "report-author", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: names[report.author_id] || '…' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { className: "role-badge", children: "员工" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("em", { className: report.status, children: STATUS_LABEL[report.status] || report.status }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "schedule" }, void 0, false), report.report_date] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("h3", { children: "今日工作总结" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { children: report.content || '未填写' }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true); } function toMonthInputValue(d) { return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`; } function formatMonthLabel(month) { const [y, m] = month.split('-'); return `${y} 年 ${parseInt(m, 10)} 月`; } function MonthlyReportEditor({ onToast }) { const month = toMonthInputValue(new Date()); const cacheKey = 'monthly-report-editor:' + month; const cached = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)(cacheKey); const [reportId, setReportId] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(cached ? cached.reportId : null); const [version, setVersion] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(cached ? cached.version : null); const versionRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(cached ? cached.version : null); const setVersionBoth = v => { versionRef.current = v; setVersion(v); }; const [summary, setSummary] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(cached ? cached.summary : ''); const [plan, setPlan] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(cached ? cached.plan : ''); const [saved, setSaved] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [saveError, setSaveError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [submitting, setSubmitting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const saveChainRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(Promise.resolve()); const draftTimerRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); const saveDraft = react__WEBPACK_IMPORTED_MODULE_0___default().useCallback((s, p) => { const run = () => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.updateMonthlyDraft)(reportId, s, p, versionRef.current, []).then(r => { setVersionBoth(r.version); setSaved(true); setSaveError(false); (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)(cacheKey, { reportId, version: r.version, summary: s, plan: p }); return r; }); const next = saveChainRef.current.then(run); saveChainRef.current = next.catch(() => {}); return next; }, [reportId]); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.createMonthlyReport)(month).then(r => { if (r.permissions && r.permissions.can_edit === false) { navigate('monthly-report-detail', { report_id: r.report_id }); return; } const nextSummary = r.work_summary || ''; const nextPlan = r.next_plan || ''; setReportId(r.report_id); setVersionBoth(r.version); setSummary(nextSummary); setPlan(nextPlan); (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)(cacheKey, { reportId: r.report_id, version: r.version, summary: nextSummary, plan: nextPlan }); }).catch(err => onToast(err.message || '创建月报失败')); }, []); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!reportId) return undefined; setSaved(false); draftTimerRef.current = window.setTimeout(() => { draftTimerRef.current = null; saveDraft(summary, plan).catch(() => setSaveError(true)); }, 600); return () => window.clearTimeout(draftTimerRef.current); }, [summary, plan, reportId, saveDraft]); const submit = () => { if (!summary.trim() || !plan.trim()) { onToast('请完成必填内容'); return; } setSubmitting(true); if (draftTimerRef.current) { window.clearTimeout(draftTimerRef.current); draftTimerRef.current = null; } saveDraft(summary, plan).then(r => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.submitMonthlyReport)(reportId, r.version)).then(_ => { onToast('月报已提交'); window.setTimeout(() => navigate('monthly-report-detail', { report_id: reportId }), 500); }).catch(err => onToast(err.message || '提交失败')).finally(() => setSubmitting(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page report-editor-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "月报", back: "monthly-report-list" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "daily-report-block-header", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: "月报汇总" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "report-field", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: "*" }, void 0, false), "本月工作总结"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("textarea", { value: summary, maxLength: "1000", placeholder: "请输入", onChange: e => setSummary(e.target.value) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: [summary.length, "/1000"] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "report-field", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("b", { children: "*" }, void 0, false), "下月工作计划"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("textarea", { value: plan, maxLength: "1000", placeholder: "请输入", onChange: e => setPlan(e.target.value) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: [plan.length, "/1000"] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "report-draft-status", children: saveError ? '草稿保存失败,请检查网络后重新编辑' : saved ? '草稿已自动保存' : '正在保存草稿…' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("footer", { className: "workplace-submit-bar", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", disabled: submitting || !reportId, onClick: submit, children: submitting ? '提交中…' : '提交' }, void 0, false) }, void 0, false)] }, void 0, true); } function MonthlyReportList({ onToast }) { const [reports, setReports] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)('monthly-reports:mine') || null); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [query, setQuery] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getMonthlyReports)({ scope: 'mine' }).then(d => { const list = d.reports || d.items || []; (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)('monthly-reports:mine', list); setReports(list); }).catch(err => { onToast(err.message || '月报列表加载失败'); setLoadError(true); }); }, []); const filtered = (reports || []).filter(r => (r.month || '').includes(query) || (r.work_summary_short || '').includes(query)); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page report-list-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "月报", action: "add", actionLabel: "填写月报", onAction: () => navigate('monthly-report-editor') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "workplace-search", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "search" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { value: query, onChange: e => setQuery(e.target.value), placeholder: "搜索月份或内容" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "report-cards", children: reports == null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: loadError ? '月报列表加载失败' : '加载中…' }, void 0, false) : filtered.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: "暂无月报" }, void 0, false) : filtered.map(r => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", onClick: () => navigate((r.action || (r.status === 'submitted' ? 'view' : 'edit')) === 'view' ? 'monthly-report-detail' : 'monthly-report-editor', { report_id: r.report_id }), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { className: "report-month", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "calendar_month" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: formatMonthLabel(r.month) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: "工作总结与下月计划" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("em", { className: r.status, children: STATUS_LABEL[r.status] || r.status }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "chevron_right" }, void 0, false)] }, r.report_id, true)) }, void 0, false)] }, void 0, true)] }, void 0, true); } function MonthlyReportDetail({ hashParams, myUserId, onToast }) { const reportId = hashParams && hashParams.report_id; const [report, setReport] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => reportId && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)('monthly-report:' + reportId) || null); const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const names = useUserNames(report ? [report.author_id] : [], myUserId); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!reportId) return; setReport((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)('monthly-report:' + reportId) || null); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getMonthlyReport)(reportId).then(r => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)('monthly-report:' + reportId, r); setReport(r); }).catch(err => { onToast(err.message || '月报加载失败'); setLoadError(true); }); }, [reportId]); if (!report) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "查看详情", back: "monthly-report-list" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: loadError ? '月报加载失败' : '加载中…' }, void 0, false) }, void 0, false)] }, void 0, true); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "查看详情", back: "monthly-report-list" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { className: "report-detail", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { className: "report-author", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("strong", { children: names[report.author_id] || '…' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { className: "role-badge", children: "员工" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("em", { className: report.status, children: STATUS_LABEL[report.status] || report.status }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "schedule" }, void 0, false), formatMonthLabel(report.month)] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("h3", { children: "本月工作总结" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { children: report.work_summary || '未填写' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("h3", { children: "下月工作计划" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { children: report.next_plan || '未填写' }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true); } function deriveSubject(content) { const first = content.trim().split('\n')[0]; return first.length > 30 ? first.slice(0, 30) + '…' : first; } function ExecutiveMailbox({ tinode, noticeOnly, onToast }) { const [config, setConfig] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.readCachedData)('executive-mailbox-config') || null); const [content, setContent] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [anonymous, setAnonymous] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); const [attachments, setAttachments] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]); const [uploading, setUploading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [submitting, setSubmitting] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [noticeOpen, setNoticeOpen] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(!!noticeOnly); const fileInputRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getExecutiveMailboxConfig)().then(c => { (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)('executive-mailbox-config', c); setConfig(c); }).catch(() => setConfig(prev => prev || { enabled: false })); }, []); const pickFile = () => fileInputRef.current && fileInputRef.current.click(); const handleFile = event => { const file = event.target.files && event.target.files[0]; event.target.value = ''; if (!file || !tinode) return; setUploading(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.uploadLargeFile)(tinode, file).then(({ fileId }) => { setAttachments(v => v.concat({ fileId, name: file.name })); }).catch(err => onToast(err.message || '附件上传失败')).finally(() => setUploading(false)); }; const submit = () => { if (!content.trim()) { onToast('请填写反馈内容'); return; } if (config && config.allow_anonymous && !anonymous) { onToast('请选择实名反馈或匿名反馈'); return; } setSubmitting(true); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.submitExecutiveMailboxMessage)({ subject: deriveSubject(content), content: content.trim(), anonymous: anonymous === 'anonymous', attachment_file_ids: attachments.map(a => a.fileId) }).then(_ => { onToast('反馈成功'); setContent(''); setAttachments([]); setAnonymous(null); }).catch(err => onToast(err.message || '提交失败')).finally(() => setSubmitting(false)); }; if (config && !config.enabled) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page mailbox-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "总经理信箱", back: "workbench" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { className: "organization-loading", children: "总经理信箱当前不可用" }, void 0, false) }, void 0, false)] }, void 0, true); } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "workplace-page mailbox-page", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Header, { title: "总经理信箱", back: "workbench", action: config && config.notice ? 'info_outline' : null, actionLabel: "查看使用说明", onAction: () => setNoticeOpen(true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("main", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { className: "mailbox-content", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: "反馈内容" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("textarea", { value: content, maxLength: config && config.max_length || 1000, placeholder: "请输入", onChange: e => setContent(e.target.value) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("small", { children: [content.length, "/", config && config.max_length || 1000] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: "附件" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: "mailbox-upload", onClick: pickFile, disabled: uploading, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: uploading ? 'hourglass_top' : 'upload_file' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: uploading ? '上传中…' : '上传文件' }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { ref: fileInputRef, type: "file", style: { display: 'none' }, onChange: handleFile }, void 0, false), attachments.length ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("ul", { className: "mailbox-attachment-list", children: attachments.map((a, i) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("li", { children: [a.name, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", { className: "material-icons", onClick: () => setAttachments(v => v.filter((_, idx) => idx !== i)), children: "close" }, void 0, false)] }, a.fileId, true)) }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", className: "workplace-primary", disabled: submitting || config == null, onClick: submit, children: submitting ? '提交中…' : '提交' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "mailbox-anonymous-choice", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { type: "radio", name: "mailbox-anon", checked: anonymous === 'named', onChange: () => setAnonymous('named') }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: "实名反馈" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { type: "radio", name: "mailbox-anon", checked: anonymous === 'anonymous', onChange: () => setAnonymous('anonymous'), disabled: config && !config.allow_anonymous }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", { children: "匿名反馈" }, void 0, false)] }, void 0, true)] }, void 0, true)] }, void 0, true), noticeOpen && config && config.notice ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "mailbox-notice-backdrop", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("section", { role: "dialog", "aria-modal": "true", className: "mailbox-notice-dialog", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Icon, { children: "policy" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("h2", { children: config.notice.title || '信箱使用与隐私说明' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", { children: config.notice.content }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("button", { type: "button", onClick: () => { setNoticeOpen(false); if (noticeOnly) navigate('executive-mailbox'); }, children: "我已了解" }, void 0, false)] }, void 0, true) }, void 0, false) : null] }, void 0, true); } function WorkplaceCollaborationView({ view, hashParams, myUserId, tinode, onTopicSelected }) { const [toast, setToast] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); let content; if (view === 'workbench') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Workbench, { onToast: setToast }, void 0, false);else if (view === 'organization-directory') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(OrganizationDirectory, { myUserId: myUserId }, void 0, false);else if (view === 'meeting-organizer' || view === 'meeting-attendee') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Meetings, { onToast: setToast }, void 0, false);else if (view === 'meeting-create') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(MeetingCreate, { myUserId: myUserId, tinode: tinode, onToast: setToast }, void 0, false);else if (view === 'meeting-detail') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(MeetingDetail, { hashParams: hashParams, onToast: setToast }, void 0, false);else if (view === 'daily-report-editor') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(DailyReportEditor, { onToast: setToast }, void 0, false);else if (view === 'monthly-report-editor') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(MonthlyReportEditor, { onToast: setToast }, void 0, false);else if (view === 'daily-report-mine' || view === 'daily-report-team') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(DailyReportList, { team: view === 'daily-report-team', myUserId: myUserId, onToast: setToast }, void 0, false);else if (view === 'monthly-report-list') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(MonthlyReportList, { onToast: setToast }, void 0, false);else if (view === 'daily-report-detail') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(DailyReportDetail, { hashParams: hashParams, myUserId: myUserId, onToast: setToast }, void 0, false);else if (view === 'monthly-report-detail') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(MonthlyReportDetail, { hashParams: hashParams, myUserId: myUserId, onToast: setToast }, void 0, false);else content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(ExecutiveMailbox, { tinode: tinode, noticeOnly: view === 'executive-mailbox-notice', onToast: setToast }, void 0, false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.Fragment, { children: [content, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(Toast, { message: toast, onDone: () => setToast('') }, void 0, false)] }, void 0, true); } /***/ }), /***/ "./src/widgets/alert.jsx": /*!*******************************!*\ !*** ./src/widgets/alert.jsx ***! \*******************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ Alert; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class Alert extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "alert-container", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "alert", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "title", children: this.props.title }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "content", children: this.props.content }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "dialog-buttons", children: [this.props.onReject ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { className: "outline", onClick: this.props.onReject, children: this.props.reject || (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: "Cancel", description: "Button [Cancel]" }, void 0, false) }, void 0, false) : null, this.props.onConfirm ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", { className: "primary", onClick: this.props.onConfirm, children: this.props.confirm || (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: "OK", description: "Button [OK]" }, void 0, false) }, void 0, false) : null] }, void 0, true)] }, void 0, true) }, void 0, false); } } ; /***/ }), /***/ "./src/widgets/audio-player.jsx": /*!**************************************!*\ !*** ./src/widgets/audio-player.jsx ***! \**************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_strformat__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/strformat */ "./src/lib/strformat.js"); /* harmony import */ var _lib_blob_helpers__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/blob-helpers */ "./src/lib/blob-helpers.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const CANVAS_UPSCALING = 2.0; const LINE_WIDTH = 3 * CANVAS_UPSCALING; const SPACING = 2 * CANVAS_UPSCALING; const BAR_COLOR = '#888A'; const BAR_COLOR_DARK = '#666C'; const THUMB_COLOR = '#1781d7'; const MIN_PREVIEW_LENGTH = 16; const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ icon_title_play: { id: 'icon_title_play', defaultMessage: 'Play recording', description: 'Icon tool tip for starting audio playback' } }); class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); let preview = (0,_lib_blob_helpers__WEBPACK_IMPORTED_MODULE_3__.base64ToIntArray)(this.props.preview); if (!Array.isArray(preview) || preview.length < MIN_PREVIEW_LENGTH) { preview = null; } this.state = { canPlay: false, playing: false, currentTime: '0:00', duration: this.props.duration > 0 ? (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.props.duration / 1000) : '-:--', longMin: this.props.duration >= 600000, preview: preview }; this.initAudio = this.initAudio.bind(this); this.initCanvas = this.initCanvas.bind(this); this.resampleBars = this.resampleBars.bind(this); this.visualize = this.visualize.bind(this); this.handlePlay = this.handlePlay.bind(this); this.handleSeek = this.handleSeek.bind(this); this.handleError = this.handleError.bind(this); this.audioPlayer = null; this.viewBuffer = []; this.canvasRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); } componentDidMount() { if (this.props.src) { this.initAudio(); } this.initCanvas(); } componentWillUnmount() { if (this.audioPlayer) { this.audioPlayer.onloadedmetadata = null; this.audioPlayer.ontimeupdate = null; this.audioPlayer.onended = null; this.audioPlayer.pause(); this.audioPlayer = null; } } componentDidUpdate(prevProps) { if (this.props.src != prevProps.src) { this.initAudio(); } if (this.props.preview != prevProps.preview) { let preview = (0,_lib_blob_helpers__WEBPACK_IMPORTED_MODULE_3__.base64ToIntArray)(this.props.preview); if (!Array.isArray(preview) || preview.length < MIN_PREVIEW_LENGTH) { preview = null; } this.setState({ preview: preview }, this.initCanvas); } } initAudio() { this.audioPlayer = new Audio(this.props.src); this.audioPlayer.onloadedmetadata = _ => this.setState({ canPlay: true }); this.audioPlayer.ontimeupdate = _ => this.setState({ currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.audioPlayer.currentTime, this.state.longMin) }); this.audioPlayer.onended = _ => { this.audioPlayer.currentTime = 0; this.setState({ playing: false, currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(0, this.state.longMin) }); }; } initCanvas() { this.canvasRef.current.width = this.canvasRef.current.offsetWidth * CANVAS_UPSCALING; this.canvasRef.current.height = this.canvasRef.current.offsetHeight * CANVAS_UPSCALING; this.canvasContext = this.canvasRef.current.getContext('2d'); this.canvasContext.lineCap = 'round'; this.viewBuffer = this.resampleBars(this.state.preview); this.visualize(); } visualize() { if (!this.canvasRef.current) { return; } const width = this.effectiveWidth; const height = this.canvasRef.current.height; this.canvasContext.lineWidth = LINE_WIDTH; const drawFrame = _ => { if (!this.canvasRef.current || !this.audioPlayer) { return; } this.canvasContext.clearRect(0, 0, this.canvasRef.current.width, height); if (this.viewBuffer) { if (this.state.playing) { window.requestAnimationFrame(drawFrame); } const thumbAt = this.props.duration ? Math.max(0, Math.min(this.audioPlayer.currentTime * 1000 / this.props.duration, 1)) * (width - LINE_WIDTH * 2) : -1; this.canvasContext.beginPath(); this.canvasContext.strokeStyle = BAR_COLOR_DARK; for (let i = 0; i < this.viewBuffer.length; i++) { let x = 1 + i * (LINE_WIDTH + SPACING) + LINE_WIDTH * 0.5; let y = Math.max(this.viewBuffer[i] * height * 0.9, 1); const color = x < thumbAt ? BAR_COLOR_DARK : BAR_COLOR; if (this.canvasContext.strokeStyle != color) { this.canvasContext.stroke(); this.canvasContext.beginPath(); this.canvasContext.strokeStyle = color; } this.canvasContext.moveTo(x, (height - y) * 0.5); this.canvasContext.lineTo(x, (height + y) * 0.5); } this.canvasContext.stroke(); if (this.props.duration) { this.canvasContext.beginPath(); this.canvasContext.arc(thumbAt + LINE_WIDTH * 2, height * 0.5, LINE_WIDTH * 2, 0, 2 * Math.PI); this.canvasContext.fillStyle = THUMB_COLOR; this.canvasContext.fill(); } } }; drawFrame(); } resampleBars(original) { const dstCount = (this.canvasRef.current.width - SPACING) / (LINE_WIDTH + SPACING) | 0; this.effectiveWidth = dstCount * (LINE_WIDTH + SPACING) + SPACING; if (!Array.isArray(original) || original.length == 0) { return Array.apply(null, Array(dstCount)).map(_ => 0.01); } const factor = original.length / dstCount; let amps = []; let maxAmp = -1; for (let i = 0; i < dstCount; i++) { let lo = i * factor | 0; let hi = (i + 1) * factor | 0; if (hi == lo) { amps[i] = original[lo]; } else { let amp = 0.0; for (let j = lo; j < hi; j++) { amp += original[j]; } amps[i] = Math.max(0, amp / (hi - lo)); } maxAmp = Math.max(amps[i], maxAmp); } if (maxAmp > 0) { return amps.map(a => a / maxAmp); } return Array.apply(null, Array(dstCount)).map(_ => 0.01); } handlePlay(e) { e.preventDefault(); if (!this.state.canPlay) { return; } if (this.state.playing) { this.audioPlayer.pause(); this.setState({ playing: false }); } else if (this.audioPlayer.readyState >= 2) { this.audioPlayer.play(); this.setState({ playing: true }, this.visualize); } } handleError(err) { console.error(err); } handleSeek(e) { e.preventDefault(); if (e.target && this.props.duration) { const rect = e.target.getBoundingClientRect(); const offset = (e.clientX - rect.left) / this.effectiveWidth * CANVAS_UPSCALING; this.audioPlayer.currentTime = this.props.duration * offset / 1000; this.setState({ currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.audioPlayer.currentTime, this.state.longMin) }); if (!this.state.playing) { this.visualize(); } } } render() { const playClass = 'material-icons' + (this.props.short ? '' : ' large') + (this.state.canPlay ? '' : ' disabled'); const play = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("a", { href: "#", onClick: this.handlePlay, title: this.props.intl.formatMessage(messages.icon_title_play), children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("i", { className: playClass, children: this.state.playing ? 'pause_circle' : this.state.canPlay ? 'play_circle' : 'not_interested' }, void 0, false) }, void 0, false); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "audio-player", children: this.props.short ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("canvas", { className: "playback", ref: this.canvasRef, onClick: this.handleSeek }, void 0, false), play] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.Fragment, { children: [play, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("canvas", { className: "playback", ref: this.canvasRef, onClick: this.handleSeek }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "timer", children: [this.state.currentTime, "/", this.state.duration] }, void 0, true)] }, void 0, true)] }, void 0, true) }, void 0, false); } } /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(AudioPlayer)); /***/ }), /***/ "./src/widgets/avatar-crop.jsx": /*!*************************************!*\ !*** ./src/widgets/avatar-crop.jsx ***! \*************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ AvatarCrop; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _cropper_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./cropper.jsx */ "./src/widgets/cropper.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class AvatarCrop extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { top: 0, left: 0, width: 0, height: 0, scale: 1 }; this.handleSubmit = this.handleSubmit.bind(this); this.handleChange = this.handleChange.bind(this); } handleChange(left, top, width, height, scale) { this.setState({ left: left, top: top, width: width, height: height, scale: scale }); } handleSubmit() { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_3__.imageCrop)(this.props.mime, this.props.avatar, this.state.left, this.state.top, this.state.width, this.state.height, this.state.scale).then(img => { this.props.onSubmit(img.mime, img.blob, img.width, img.height); }).catch(err => { this.props.onError(err); }); } render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(_cropper_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { source: this.props.avatar, onChange: this.handleChange }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "dialog-buttons", children: [this.props.onCancel ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { className: "secondary", onClick: this.props.onCancel, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: "Cancel", description: "Button [Cancel]" }, void 0, false) }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { className: "primary", onClick: this.handleSubmit, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: "OK", description: "Button [OK]" }, void 0, false) }, void 0, false)] }, void 0, true)] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/avatar-upload.jsx": /*!***************************************!*\ !*** ./src/widgets/avatar-upload.jsx ***! \***************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ AvatarUpload; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _load_spinner_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./load-spinner.jsx */ "./src/widgets/load-spinner.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class AvatarUpload extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { source: props.avatar }; this.handleFileReceived = this.handleFileReceived.bind(this); } componentDidUpdate(prevProps) { if (this.props.avatar != prevProps.avatar) { this.setState({ source: this.props.avatar }); } } handleFileReceived(e) { const image = e.target.files[0]; this.props.onImageUpdated(image.type, URL.createObjectURL(image), image.name); e.target.value = ''; } render() { const randId = 'file-input-avatar-' + ('' + Math.random()).substring(0, 4); const className = 'avatar-upload' + (this.props.readOnly ? ' read-only' : ''); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: className, children: [this.props.readOnly || !this.state.source ? null : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("a", { href: "#", className: "clear-avatar", onClick: e => { e.preventDefault(); this.props.onImageUpdated(); }, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", { className: "material-icons", children: "clear" }, void 0, false) }, void 0, false), this.state.source ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("img", { src: this.props.tinode.authorizeURL((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.sanitizeUrlForMime)(this.state.source, 'image')), className: "preview" }, void 0, false) : this.props.readOnly && this.props.uid ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "avatar-box", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { authorizeURL: this.props.tinode.authorizeURL, avatar: true, topic: this.props.uid, title: this.props.title }, void 0, false) }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "blank", children: [_config_js__WEBPACK_IMPORTED_MODULE_4__.AVATAR_SIZE, "×", _config_js__WEBPACK_IMPORTED_MODULE_4__.AVATAR_SIZE] }, void 0, true), this.props.readOnly ? null : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("input", { type: "file", id: randId, className: "inputfile hidden", accept: "image/*", onChange: this.handleFileReceived }, void 0, false), this.props.readOnly ? null : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("label", { htmlFor: randId, className: "round", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", { className: "material-icons", children: "file_upload" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { show: this.props.uploading, large: true, clear: true, centered: true }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/badge-list.jsx": /*!************************************!*\ !*** ./src/widgets/badge-list.jsx ***! \************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const icon_mapping = { 'staff': 'verified_user' }; const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ badge_verified: { id: 'badge_verified', defaultMessage: 'Verified/official', description: 'Explanation of a verified account or topic badge' }, badge_staff: { id: 'badge_staff', defaultMessage: 'Staff-managed', description: 'Explanation of a staff-managed account or topic badge' }, badge_danger: { id: 'badge_danger', defaultMessage: 'Untrustworthy', description: 'Suspicious or untrustworthy account or topic badge' } }); class BadgeList extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const { formatMessage } = this.props.intl; let badges = null; if (this.props.trustedBadges && this.props.trustedBadges.length > 0) { badges = []; this.props.trustedBadges.forEach(b => { const comment = this.props.short ? null : formatMessage(messages['badge_' + b]); const style = 'material-icons ' + b + '-color'; badges.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "trusted-badge", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: style, children: icon_mapping[b] || b }, void 0, false), " ", comment] }, b, true)); }); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: badges }, void 0, false); } return null; } } ; /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(BadgeList)); /***/ }), /***/ "./src/widgets/batch-forward-dialog.jsx": /*!**********************************************!*\ !*** ./src/widgets/batch-forward-dialog.jsx ***! \**********************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ BatchForwardDialog; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _contact_list_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _search_contacts_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./search-contacts.jsx */ "./src/widgets/search-contacts.jsx"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class BatchForwardDialog extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { query: null, multiSelect: false, selectedTargets: [], confirmTargets: null, sending: false, error: null }; this.handleEscapeKey = this.handleEscapeKey.bind(this); this.handleClose = this.handleClose.bind(this); this.handleSearchContacts = this.handleSearchContacts.bind(this); this.handleContactSelected = this.handleContactSelected.bind(this); this.handleToggleMultiSelect = this.handleToggleMultiSelect.bind(this); this.handleConfirmTargets = this.handleConfirmTargets.bind(this); this.handleCancelConfirm = this.handleCancelConfirm.bind(this); this.handleSend = this.handleSend.bind(this); } componentDidMount() { this.props.onInitFind(); document.addEventListener('keyup', this.handleEscapeKey, false); } componentWillUnmount() { document.removeEventListener('keyup', this.handleEscapeKey, false); } handleEscapeKey(e) { if (e.keyCode === 27) { this.props.hide(); } } handleClose(e) { e.preventDefault(); this.props.hide(); } handleSearchContacts(query) { this.setState({ query: tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.isNullValue(query) ? null : query }); this.props.onSearchContacts(query); } handleToggleMultiSelect(e) { e.preventDefault(); this.setState(s => ({ multiSelect: !s.multiSelect, selectedTargets: [] })); } handleContactSelected(uid) { if (!this.state.multiSelect) { this.setState({ confirmTargets: [uid] }); return; } this.setState(s => ({ selectedTargets: s.selectedTargets.includes(uid) ? s.selectedTargets.filter(t => t != uid) : s.selectedTargets.concat(uid) })); } handleConfirmTargets(e) { e.preventDefault(); if (this.state.selectedTargets.length) { this.setState({ confirmTargets: this.state.selectedTargets.slice() }); } } handleCancelConfirm() { this.setState({ confirmTargets: null, error: null }); } handleSend() { const sources = this.props.seqs.map(seq => ({ topic: this.props.topicName, seq: String(seq) })); this.setState({ sending: true, error: null }); (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.forwardMessages)('separate', sources, this.state.confirmTargets).then(result => { const failed = result && result.failed || []; if (failed.length) { this.setState({ sending: false, error: `${failed.length} 条转发失败,请重试` }); return; } this.props.hide(true); }).catch(err => { this.setState({ sending: false, error: err.message || '转发失败' }); }); } render() { if (this.state.confirmTargets) { const targets = this.state.confirmTargets.map(uid => this.props.tinode.getTopic(uid) || { name: uid, public: null }); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "alert-container", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "forward-dialog batch-forward-confirm", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "title", children: "发送给" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("ul", { className: "contact-box", children: targets.map(t => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("li", { className: "batch-forward-target", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { children: tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.isSelfTopicName(t.name) ? '已保存的消息' : (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_5__.topicDisplayName)(t.name, t.public, t.name) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", { className: "material-icons", children: "chevron_right" }, void 0, false)] }, t.name, true)) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "batch-forward-comment", children: '[逐条转发]共' + this.props.seqs.length + '条消息' }, void 0, false), this.state.error ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "auth-field-error", children: this.state.error }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "batch-forward-actions", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", onClick: this.handleCancelConfirm, disabled: this.state.sending, children: "取消" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { type: "button", className: "primary", onClick: this.handleSend, disabled: this.state.sending, children: this.state.sending ? '发送中…' : '发送' }, void 0, false)] }, void 0, true)] }, void 0, true) }, void 0, false); } let contacts = this.state.query != null ? this.props.searchResults : this.props.contacts; contacts = contacts.filter(c => c.name != this.props.topicSelected && c.acs.isJoiner() && c.acs.isWriter()); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "alert-container", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "forward-dialog", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "title with-control", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: "转发" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("a", { href: "#", onClick: this.handleToggleMultiSelect, children: this.state.multiSelect ? '' : '多选' }, void 0, false), this.state.multiSelect ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("a", { href: "#", onClick: this.handleConfirmTargets, className: this.state.selectedTargets.length ? '' : 'disabled', children: "确定" }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("a", { href: "#", onClick: this.handleClose, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", { className: "material-icons", children: "close" }, void 0, false) }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(_search_contacts_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { placeholder: "搜索联系人", onSearchContacts: this.handleSearchContacts }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(_contact_list_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, contacts: contacts, myUserId: this.props.myUserId, emptyListMessage: "搜索返回任何结果", showOnline: false, showUnread: false, showContextMenu: false, topicSelected: this.state.multiSelect ? this.state.selectedTargets : null, onTopicSelected: this.handleContactSelected }, void 0, false)] }, void 0, true) }, void 0, false); } } /***/ }), /***/ "./src/widgets/button-back.jsx": /*!*************************************!*\ !*** ./src/widgets/button-back.jsx ***! \*************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ ButtonBack; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class ButtonBack extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onBack(); }, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("i", { className: "material-icons", children: "arrow_back" }, void 0, false) }, void 0, false); } } /***/ }), /***/ "./src/widgets/call-incoming.jsx": /*!***************************************!*\ !*** ./src/widgets/call-incoming.jsx ***! \***************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ CallIncoming; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _badge_list_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./badge-list.jsx */ "./src/widgets/badge-list.jsx"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const RING_SOUND = new Audio('audio/call-in.m4a'); class CallIncoming extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { topic: null, fullName: undefined, avatar: null, trustedBadges: [], previousMetaDesc: undefined }; this.resetDesc = this.resetDesc.bind(this); this.onMetaDesc = this.onMetaDesc.bind(this); this.handleRejectCall = this.handleRejectCall.bind(this); this.handleAcceptCall = this.handleAcceptCall.bind(this); this.ringTimer = null; } componentDidMount() { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.resetDesc(topic); if (this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_INCOMING_RECEIVED) { RING_SOUND.play().catch(_ => {}); this.ringTimer = setInterval(_ => { RING_SOUND.play().catch(_ => {}); }, 2000); this.props.onRinging(this.props.topic, this.props.seq); } } componentDidUpdate(props) { const topic = this.props.tinode.getTopic(props.topic); if (!topic) { return; } if (this.onMetaDesc != topic.onMetaDesc) { this.previousMetaDesc = topic.onMetaDesc; topic.onMetaDesc = this.onMetaDesc; } if (this.state.topic != props.topic) { this.setState({ topic: props.topic }); this.resetDesc(topic, props); } } componentWillUnmount() { if (this.ringTimer != null) { clearInterval(this.ringTimer); RING_SOUND.pause(); } const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.setState({ topic: null }); topic.onMetaDesc = this.previousMetaDesc; } resetDesc(topic) { const badges = []; if (topic.trusted) { for (const [key, val] of Object.entries(topic.trusted)) { if (val) { badges.push(key); } } } this.setState({ fullName: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_6__.truncateString)(topic.public ? topic.public.fn : undefined, _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_TITLE_LENGTH), avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__.makeImageUrl)(topic.public ? topic.public.photo : null), trustedBadges: badges }); } onMetaDesc(desc) { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.resetDesc(topic); if (this.previousMetaDesc && this.previousMetaDesc != this.onMetaDesc) { this.previousMetaDesc(desc); } } handleAcceptCall() { this.props.onAcceptCall(this.props.topic); } handleRejectCall() { this.props.onReject(this.props.topic, this.props.seq); this.props.onClose(); } render() { const isAudioOnly = !!this.props.audioOnly; const ringing = this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_INCOMING_RECEIVED; const surfaceClass = isAudioOnly ? 'call-audio-surface' : 'call-video-surface'; const photoStyle = this.state.avatar ? { '--incoming-call-photo': `url(${this.state.avatar})` } : null; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: `call-fullscreen incoming-call-overlay ${surfaceClass} incoming`, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "call-ambient" }, void 0, false), this.state.avatar && (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "incoming-call-photo-blur", style: photoStyle }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "call-peer-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { className: "avatar-box call-product-avatar", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { authorizeURL: this.props.tinode.authorizeURL, avatar: this.state.avatar || true, topic: this.props.topic, title: this.state.fullName }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("h1", { children: [(0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_6__.truncateString)(this.state.fullName, _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_PEER_TITLE_LENGTH), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(_badge_list_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { short: true, trustedBadges: this.state.trustedBadges }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", { children: isAudioOnly ? '对方邀请你语音通话...' : '对方邀请你视频通话...' }, void 0, false), ringing && (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { className: "call-ringing-dots", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {}, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("footer", { className: "call-incoming-actions", children: ringing ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: "call-control danger", onClick: this.handleRejectCall, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", { className: "material-icons", children: "call_end" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: "拒绝" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", { type: "button", className: "call-control", onClick: this.handleAcceptCall, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", { className: "material-icons", children: isAudioOnly ? 'call' : 'videocam' }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("small", { children: "接听" }, void 0, false)] }, void 0, true)] }, void 0, true) : null }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/call-message.jsx": /*!**************************************!*\ !*** ./src/widgets/call-message.jsx ***! \**************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ CallMessage; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class CallMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const isCallDropped = ['busy', 'declined', 'disconnected', 'missed'].includes(this.props.callState); const successClass = 'material-icons medium ' + (isCallDropped ? 'red' : 'green'); const callIcon = this.props.incoming ? isCallDropped ? 'call_missed' : 'call_received' : isCallDropped ? 'call_missed_outgoing' : 'call_made'; const title = this.props.incoming ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "calls_incoming", defaultMessage: "Incoming call", description: "Incoming call label" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "calls_outgoing", defaultMessage: "Outgoing call", description: "Outgoing call label" }, void 0, false); let duration; if (isCallDropped) { switch (this.props.callState) { case 'busy': duration = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_busy", defaultMessage: "busy", description: "Label for busy call line" }, void 0, false); break; case 'declined': duration = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_declined", defaultMessage: "declined", description: "Label for declined call" }, void 0, false); break; case 'missed': duration = this.props.incoming ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_missed", defaultMessage: "missed", description: "Label for missed incoming call" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_cancelled", defaultMessage: "cancelled", description: "Label for cancelled outgoing call" }, void 0, false); break; default: duration = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_disconnected", defaultMessage: "disconnected", description: "Label for disconnected call" }, void 0, false); break; } } else { duration = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.props.duration / 1000) }, void 0, false); } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "call-message", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("i", { className: "material-icons big gray", children: "call" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "flex-column narrow", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { children: title }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "duration", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("i", { className: successClass, children: callIcon }, void 0, false), " ", duration] }, void 0, true)] }, void 0, true)] }, void 0, true); } } /***/ }), /***/ "./src/widgets/call-status.jsx": /*!*************************************!*\ !*** ./src/widgets/call-status.jsx ***! \*************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ CallStatus; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class CallStatus extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const isCallDropped = ['busy', 'declined', 'disconnected', 'missed'].includes(this.props.callState); const icon2 = this.props.incoming ? isCallDropped ? 'call_missed' : 'call_received' : isCallDropped ? 'call_missed_outgoing' : 'call_made'; let duration; if (isCallDropped) { switch (this.props.callState) { case 'busy': duration = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_busy", defaultMessage: "busy", description: "Label for busy call line" }, void 0, false); break; case 'declined': duration = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_declined", defaultMessage: "declined", description: "Label for declined call" }, void 0, false); break; case 'missed': duration = this.props.incoming ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_missed", defaultMessage: "missed", description: "Label for missed incoming call" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_cancelled", defaultMessage: "cancelled", description: "Label for cancelled outgoing call" }, void 0, false); break; default: duration = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_disconnected", defaultMessage: "disconnected", description: "Label for disconnected call" }, void 0, false); break; } } else if (['accepted', 'started'].includes(this.props.callState) && !this.props.duration) { duration = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_in_progress", defaultMessage: "in progress", description: "Label for call in progress" }, void 0, false); } else { duration = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { children: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.props.duration / 1000) }, void 0, false); } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "composed-material", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("i", { className: "material-icons", children: "call" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("i", { className: "material-icons second", children: icon2 }, void 0, false)] }, void 0, true), " ", duration] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/checkbox.jsx": /*!**********************************!*\ !*** ./src/widgets/checkbox.jsx ***! \**********************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ CheckBox; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class CheckBox extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange() { this.props.onChange(this.props.name, !this.props.checked); } render() { let classList = ['material-icons']; let iconName; if (Array.isArray(this.props.className)) { classList.push(...this.props.className); } else if (this.props.className) { classList.push(this.props.className); } if (this.props.onChange) { if (this.props.checked) { classList.push('blue', 'clickable'); iconName = 'check_box'; } else if (this.props.checked === false) { classList.push('blue', 'clickable'); iconName = 'check_box_outline_blank'; } else { classList.push('lt-blue'); iconName = 'indeterminate_check_box'; } } else { if (this.props.checked) { iconName = 'check_box'; } else { iconName = 'check_box_outline_blank'; } } let attrs = { className: classList.join(' '), id: this.props.id }; if (this.props.onChange) { attrs.onClick = this.handleChange; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', attrs, iconName); } } /***/ }), /***/ "./src/widgets/chip-input.jsx": /*!************************************!*\ !*** ./src/widgets/chip-input.jsx ***! \************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ ChipInput; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _chip_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./chip.jsx */ "./src/widgets/chip.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class ChipInput extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = ChipInput.deriveStateFromProps(props); this.state.input = ''; this.state.focused = false; this.handleTextInput = this.handleTextInput.bind(this); this.removeChipAt = this.removeChipAt.bind(this); this.handleChipCancel = this.handleChipCancel.bind(this); this.handleFocusGained = this.handleFocusGained.bind(this); this.handleFocusLost = this.handleFocusLost.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } static deriveStateFromProps(props) { return { sortedChips: ChipInput.sortChips(props.chips, props.staticMembers), chipIndex: ChipInput.indexChips(props.chips) }; } componentDidUpdate(prevProps, prevState) { if (prevProps.chips != this.props.chips || prevProps.staticMembers != this.props.staticMembers || prevProps.prompt != this.props.prompt) { this.setState(ChipInput.deriveStateFromProps(this.props)); } if (!prevState || this.props.chips.length > prevState.sortedChips.length) { this.setState({ input: '' }); } } static indexChips(chips) { const index = {}; let count = 0; chips.forEach(item => { index[item.user] = count; count++; }); return index; } static sortChips(chips, keep) { const required = []; const normal = []; chips.forEach(item => { if (keep && keep.includes(item.user)) { required.push(item); } else { normal.push(item); } }); return required.concat(normal); } handleTextInput(e) { this.setState({ input: e.target.value }); if (this.props.filterFunc) { this.props.filterFunc(e.target.value); } } removeChipAt(idx) { const removed = this.state.sortedChips[idx]; this.props.onChipRemoved(removed.user, this.state.chipIndex[removed.user]); } handleChipCancel(item, idx) { this.removeChipAt(idx); } handleFocusGained() { this.setState({ focused: true }); } handleFocusLost() { this.setState({ focused: false }); if (this.props.onFocusLost) { this.props.onFocusLost(this.state.input); } } handleKeyDown(e) { if (e.key === 'Backspace') { if (this.state.input.length == 0 && this.state.sortedChips.length > 0) { const at = this.state.sortedChips.length - 1; if (this.state.sortedChips[at].user !== this.props.staticMembers) { this.removeChipAt(at); } } } else if (e.key === 'Enter') { if (this.props.onEnter) { this.props.onEnter(this.state.input); } } else if (e.key === 'Escape') { if (this.props.onCancel) { this.props.onCancel(); } } } render() { const chips = []; let count = 0; const staticMembers = this.props.staticMembers || []; this.state.sortedChips.forEach(item => { chips.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(_chip_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: this.props.tinode, onCancel: this.handleChipCancel, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_2__.makeImageUrl)(item.public ? item.public.photo : null), title: item.public ? item.public.fn : undefined, noAvatar: this.props.avatarDisabled, topic: item.user, required: staticMembers.includes(item.user), invalid: item.invalid, index: count }, item.user, false)); count++; }); const className = "chip-input" + (this.state.focused ? ' focused' : ''); const autoFocus = !(this.props.tabIndex > 0); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: className, children: [chips, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { type: "text", placeholder: this.props.prompt, onChange: this.handleTextInput, onFocus: this.handleFocusGained, onBlur: this.handleFocusLost, onKeyDown: this.handleKeyDown, value: this.state.input, tabIndex: this.props.tabIndex, autoFocus: autoFocus }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/chip.jsx": /*!******************************!*\ !*** ./src/widgets/chip.jsx ***! \******************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ Chip; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class Chip extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleCancel = this.handleCancel.bind(this); } handleCancel(e) { e.preventDefault(); this.props.onCancel(this.props.topic, this.props.index); } render() { const title = this.props.title || this.props.topic; const className = this.props.invalid ? 'chip invalid' : 'chip'; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: className, children: [this.props.noAvatar ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: "spacer" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "avatar-box", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { authorizeURL: this.props.tinode.authorizeURL, avatar: this.props.avatar || true, topic: this.props.topic, title: this.props.title }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: title }, void 0, false), this.props.onCancel && !this.props.required ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("a", { href: "#", onClick: this.handleCancel, children: "×" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: "spacer" }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/contact-action.jsx": /*!****************************************!*\ !*** ./src/widgets/contact-action.jsx ***! \****************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class ContactAction extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick(e) { e.preventDefault(); e.stopPropagation(); this.props.onAction(this.props.action); } render() { const { formatMessage } = this.props.intl; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("li", { onClick: this.handleClick, className: "action", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "action-text", children: formatMessage(this.props.title, this.props.values) }, void 0, false) }, void 0, false); } } ; /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ContactAction)); /***/ }), /***/ "./src/widgets/contact-badges.jsx": /*!****************************************!*\ !*** ./src/widgets/contact-badges.jsx ***! \****************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ ContactBadges; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const icon_mapping = { 'muted': 'notifications_off', 'banned': 'block', 'staff': 'verified_user' }; class ContactBadges extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { let badges = null; if (this.props.badges && this.props.badges.length > 0) { badges = []; this.props.badges.forEach(b => { const color = b.color ? ' ' + b.color : ''; if (b.icon) { badges.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("i", { className: 'material-icons as-badge' + color, children: icon_mapping[b.icon] || b.icon }, b.key || b.icon, false)); } else { badges.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("span", { className: 'badge' + color, children: b.name }, b.key || b.name, false)); } }); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.Fragment, { children: badges }, void 0, false); } return null; } } ; /***/ }), /***/ "./src/widgets/contact-list.jsx": /*!**************************************!*\ !*** ./src/widgets/contact-list.jsx ***! \**************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _contact_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact.jsx */ "./src/widgets/contact.jsx"); /* harmony import */ var _contact_action_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./contact-action.jsx */ "./src/widgets/contact-action.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ badge_you: { id: 'badge_you', defaultMessage: 'you', description: 'Badge for indicating the current user' }, badge_owner: { id: 'badge_owner', defaultMessage: 'owner', description: 'Badge for indicating the owner' } }); class ContactList extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const { formatMessage } = this.props.intl; const showCheckmark = Array.isArray(this.props.topicSelected); const contactNodes = []; let contactsCount = 0; if (this.props.showSelfTopic) { const selected = showCheckmark ? this.props.topicSelected.some(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isSelfTopicName) : tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isSelfTopicName(this.props.topicSelected); contactNodes.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(_contact_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, avatar: true, showMode: this.props.showMode, selected: selected, showCheckmark: showCheckmark, onSelected: this.props.onTopicSelected, showContextMenu: this.props.showContextMenu, index: contactNodes.length, item: "slf" }, 'slf', false)); contactsCount++; } if (this.props.contacts && this.props.contacts.length > 0) { const usedKeys = {}; this.props.contacts.forEach(c => { if (c.action) { contactNodes.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(_contact_action_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { title: c.title, action: c.action, values: c.values, onAction: this.props.onAction }, c.action, false)); } else { const key = this.props.showMode ? c.user : c.topic || c.user; if (usedKeys[key]) { return; } usedKeys[key] = true; if (this.props.filterFunc && this.props.filter) { const filterOn = [key]; if (c.private && c.private.comment) { filterOn.push(('' + c.private.comment).toLowerCase()); } const displayName = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_6__.topicDisplayName)(key, c.public, null); if (displayName) { filterOn.push(('' + displayName).toLowerCase()); } if (!this.props.filterFunc(this.props.filter, filterOn)) { return; } } const isChannel = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isChannelTopicName(key); const isGroup = !isChannel && tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isGroupTopicName(key); const selected = showCheckmark ? this.props.topicSelected.indexOf(key) > -1 : this.props.topicSelected === key; const badges = []; if (this.props.showMode) { if (key == this.props.myUserId) { badges.push({ name: formatMessage(messages.badge_you), color: 'green' }); } if (c.acs && c.acs.isOwner()) { badges.push({ name: formatMessage(messages.badge_owner), color: 'blue' }); } } const comment = Array.isArray(c.private) ? c.private.join(',') : c.private ? c.private.comment : null; let preview; let forwarded; let previewIsResponse; let deliveryStatus; if (!this.props.showMode && c.latestMessage) { const msg = c.latestMessage(); if (msg) { forwarded = msg.head ? msg.head.forwarded : null; deliveryStatus = msg._status || c.msgStatus(msg, true); previewIsResponse = msg.from != this.props.myUserId; if (msg.content) { preview = typeof msg.content == 'string' ? msg.content.substr(0, _config_js__WEBPACK_IMPORTED_MODULE_7__.MESSAGE_PREVIEW_LENGTH) : tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.preview(msg.content, _config_js__WEBPACK_IMPORTED_MODULE_7__.MESSAGE_PREVIEW_LENGTH); } } } contactNodes.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)(_contact_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, title: c.public ? (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_6__.topicDisplayName)(key, c.public, null) : null, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__.makeImageUrl)(c.public ? c.public.photo : null), comment: comment, preview: preview, previewIsResponse: previewIsResponse, forwarded: forwarded, received: deliveryStatus, unread: this.props.showUnread ? c.unread : 0, now: c.online && this.props.connected, acs: c.acs, showMode: this.props.showMode, badges: badges, showCheckmark: showCheckmark, selected: selected, pinned: c.pinned, showOnline: this.props.showOnline && !isChannel, isChannel: isChannel, isGroup: isGroup, showContextMenu: this.props.showContextMenu, isVerified: c.trusted && c.trusted.verified, isStaff: c.trusted && c.trusted.staff, isDangerous: c.trusted && c.trusted.danger, deleted: c._deleted, onSelected: this.props.onTopicSelected, item: key, index: contactNodes.length }, key, false)); contactsCount++; } }, this); } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: this.props.noScroll ? null : "scrollable-panel", children: [contactsCount == 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("div", { className: "center-medium-text", style: { whiteSpace: 'pre-line' }, children: this.props.emptyListMessage }, void 0, false) : null, contactNodes.length > 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxDEV)("ul", { className: "contact-box", children: contactNodes }, void 0, false) : null] }, void 0, true); } } ; /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ContactList)); /***/ }), /***/ "./src/widgets/contact.jsx": /*!*********************************!*\ !*** ./src/widgets/contact.jsx ***! \*********************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _contact_badges_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact-badges.jsx */ "./src/widgets/contact-badges.jsx"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _unread_badge_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./unread-badge.jsx */ "./src/widgets/unread-badge.jsx"); /* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ self_topic_name: { id: 'self_topic_name', defaultMessage: 'Saved messages', description: 'Name of self topic for UI' }, self_topic_comment: { id: 'self_topic_comment', defaultMessage: 'Notes, messages, links, files saved for posterity', description: 'Comment for self topic for UI' } }); class Contact extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); this.handleContextClick = this.handleContextClick.bind(this); } handleClick(e) { e.preventDefault(); e.stopPropagation(); if (this.props.onSelected) { this.props.onSelected(this.props.item, this.props.index); } } handleContextClick(e) { e.preventDefault(); e.stopPropagation(); this.props.showContextMenu({ topicName: this.props.item, topicTitle: this.props.title, y: e.pageY, x: e.pageX }); } render() { let title = this.props.title; const self = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isSelfTopicName(this.props.item); if (!title) { if (self) { title = this.props.intl.formatMessage(messages.self_topic_name); } else { title = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("i", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "unnamed_topic", defaultMessage: "Unnamed", description: "Title shown when the topic has no name" }, void 0, false) }, void 0, false); } } else if (title.length > 30) { title = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_8__.truncateString)(title, 30); } const online = this.props.now ? 'online' : 'offline'; const avatar = this.props.avatar ? this.props.avatar : true; const badges = this.props.badges ? this.props.badges.slice() : []; const icon_badges = []; if (this.props.isVerified) { icon_badges.push({ icon: 'verified', color: 'verified-color' }); } if (this.props.isStaff) { icon_badges.push({ icon: 'staff', color: 'staff-color' }); } if (this.props.isDangerous) { icon_badges.push({ icon: 'dangerous', color: 'danger-color' }); } if (this.props.acs) { if (this.props.showMode) { badges.push({ name: this.props.acs.getMode(), key: 'mode' }); } if (this.props.acs.isMuted()) { icon_badges.push({ icon: 'muted' }); } if (!this.props.acs.isJoiner()) { icon_badges.push({ icon: 'banned' }); } } let preview; if (typeof this.props.preview == 'string') { preview = this.props.preview; } else if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isValid(this.props.preview)) { preview = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(this.props.preview, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__.previewFormatter, { formatMessage: this.props.intl.formatMessage, previewIsResponse: this.props.previewIsResponse })); } else if (this.props.preview) { preview = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("i", { className: "material-icons gray", children: "warning_amber" }, void 0, false), " ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("i", { className: "gray", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "invalid_content", defaultMessage: "invalid content", description: "Shown when the message is unreadable" }, void 0, false) }, void 0, false)] }, void 0, true); } const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__.deliveryMarker)(this.props.received); const marker = icon ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("i", { className: 'material-icons small space-right' + (icon.color ? ' ' + icon.color : ''), children: icon.name }, void 0, false) : null; const titleClass = 'contact-title' + (this.props.deleted ? ' deleted' : ''); const comment = preview || this.props.comment || (self ? this.props.intl.formatMessage(messages.self_topic_comment) : '\u00A0'); const bgColor = this.props.showCheckmark ? null : this.props.selected ? 'selected' : this.props.pinned ? 'tpinned' : null; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("li", { className: bgColor, onClick: this.handleClick, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("div", { className: "avatar-box", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { authorizeURL: this.props.tinode.authorizeURL, avatar: avatar, title: this.props.title, topic: this.props.item, deleted: this.props.deleted }, void 0, false), this.props.deleted ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("i", { className: "deleted material-icons", children: "cancel" }, void 0, false) : !self && this.props.showOnline ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("span", { className: online }, void 0, false) : this.props.showCheckmark && this.props.selected ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("i", { className: "checkmark material-icons", children: "check_circle" }, void 0, false) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("div", { className: "text-box", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("span", { className: titleClass, children: title }, void 0, false), this.props.isGroup ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("i", { className: "material-icons as-badge", children: "group" }, void 0, false) : null, this.props.isChannel ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("i", { className: "material-icons as-badge", children: "podcasts" }, void 0, false) : null, !self ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { badges: icon_badges }, void 0, false) : null, !this.props.deleted ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(_unread_badge_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { count: this.props.unread }, void 0, false) : null] }, void 0, true), this.props.showMode ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)(_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { badges: badges }, void 0, false) }, void 0, false) : this.props.small ? null : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("div", { className: "contact-comment", children: [marker, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("span", { children: comment }, void 0, false)] }, void 0, true)] }, void 0, true), this.props.showContextMenu ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("span", { className: "menuTrigger", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("a", { href: "#", onClick: this.handleContextClick, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_9__.jsxDEV)("i", { className: "material-icons", children: "expand_more" }, void 0, false) }, void 0, false) }, void 0, false) : null] }, void 0, true); } } ; /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(Contact)); /***/ }), /***/ "./src/widgets/context-menu.jsx": /*!**************************************!*\ !*** ./src/widgets/context-menu.jsx ***! \**************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const favoriteState = new Map(); function favoriteKey(topicName, seq) { return topicName + ':' + seq; } function findFavorite(topicName, seq) { return (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getFavorites)({ type: 'all' }).then(data => (data.items || []).find(it => it.source && it.source.topic === topicName && String(it.source.seq) === String(seq))); } const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ info: { id: 'menu_item_info', defaultMessage: 'Info', description: 'Show extended topic information' }, clear_messages: { id: 'menu_item_clear_messages', defaultMessage: 'Clear messages', description: 'Delete all messages' }, clear_for_all: { id: 'menu_item_clear_messages_for_all', defaultMessage: 'Clear for All', description: 'Delete all message(s) for all members' }, delete: { id: 'menu_item_delete', defaultMessage: 'Delete', description: 'Delete selected messages' }, delete_for_all: { id: 'menu_item_delete_for_all', defaultMessage: 'Delete for All', description: 'Delete selected message(s) for all members' }, send_retry: { id: 'menu_item_send_retry', defaultMessage: 'Retry', description: 'Retry sending message' }, mute: { id: 'menu_item_mute', defaultMessage: 'Mute', description: 'Turn off notifications' }, unmute: { id: 'menu_item_unmute', defaultMessage: 'Unmute', description: 'Turn notifications on' }, reply: { id: 'menu_item_reply', defaultMessage: 'Reply', description: 'Reply to message' }, forward: { id: 'menu_item_forward', defaultMessage: 'Forward', description: 'Forward message' }, edit: { id: 'menu_item_edit', defaultMessage: 'Edit', description: 'Edit message' }, topic_delete: { id: 'menu_item_delete_topic', defaultMessage: 'Delete', description: 'Delete entire topic' }, topic_delete_warning: { id: 'topic_delete_warning', defaultMessage: 'Are you sure you want to delete this conversation? It cannot be undone.', description: 'Alert warning when deleting entire topic' }, delete_messages_warning: { id: 'delete_messages_warning', defaultMessage: 'Are you sure you want to delete all messages for everyone? It cannot be undone.', description: 'Alert dialog warning when hard-deleting all messages.' }, unblock: { id: 'menu_item_unblock', defaultMessage: 'Unblock', description: 'Unblock topic or user' }, block: { id: 'menu_item_block', defaultMessage: 'Block', description: 'Block topic or user' }, topic_block_warning: { id: 'topic_block_warning', defaultMessage: 'Are you sure you want to block this conversation?', description: 'Alert warning when blocking a topic.' }, member_delete: { id: 'menu_item_member_delete', defaultMessage: 'Remove', description: 'Remove user from topic' }, archive: { id: 'menu_item_archive_topic', defaultMessage: 'Archive', description: 'Move topic from the list of active chats to archive' }, unarchive: { id: 'menu_item_restore_topic', defaultMessage: 'Restore', description: 'Restore topic from archive' }, edit_permissions: { id: 'menu_item_edit_permissions', defaultMessage: 'Edit permissions', description: 'Menu item [Edit permissions]' }, clear_messages_warning: { id: 'clear_messages_warning', defaultMessage: 'Are you sure you want to clear all messages? It cannot be undone.', description: 'Alert dialog warning when deleting all messages.' }, pin_message: { id: 'pin_message', defaultMessage: 'Pin', description: 'Menu item [Pin] for pinning message to the top.' }, unpin_message: { id: 'unpin_message', defaultMessage: 'Unpin', description: 'Menu item [Unpin] for un-pinning the message.' }, pin_chat: { id: 'pin_chat', defaultMessage: 'Pin', description: 'Menu item [Pin] for pinning chat to the top.' }, unpin_chat: { id: 'unpin_chat', defaultMessage: 'Unpin', description: 'Menu item [Unpin] for un-pinning the chat.' } }); class ContextMenu extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.selfRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); const { formatMessage } = props.intl; this.handlePageClick = this.handlePageClick.bind(this); this.handleEscapeKey = this.handleEscapeKey.bind(this); this.handleClick = this.handleClick.bind(this); this.MenuItems = { 'topic_info': { id: 'topic_info', title: formatMessage(messages.info), handler: null }, 'messages_clear': { id: 'messages_clear', title: formatMessage(messages.clear_messages), handler: (params, errorHandler) => { return props.onShowAlert(params.topicTitle || formatMessage(messages.clear_messages), formatMessage(messages.clear_messages_warning), _ => { this.deleteMessages(true, false, params, errorHandler); }, null, true, null); } }, 'messages_clear_hard': { id: 'messages_clear_hard', title: formatMessage(messages.clear_for_all), handler: (params, errorHandler) => { return props.onShowAlert(params.topicTitle || formatMessage(messages.clear_for_all), formatMessage(messages.delete_messages_warning), _ => { return this.deleteMessages(true, true, params, errorHandler); }, null, true, null); } }, 'message_delete': { id: 'message_delete', title: formatMessage(messages.delete), handler: (params, errorHandler) => { return this.deleteMessages(false, false, params, errorHandler); } }, 'message_delete_hard': { id: 'message_delete_hard', title: formatMessage(messages.delete_for_all), handler: (params, errorHandler) => { return this.deleteMessages(false, true, params, errorHandler); } }, 'message_delete_generic': { id: 'message_delete_generic', title: formatMessage(messages.delete), handler: (params, errorHandler) => { return this.deleteMessages(false, true, params, errorHandler); } }, 'menu_item_send_retry': { id: 'menu_item_send_retry', title: formatMessage(messages.send_retry), handler: (params, errorHandler) => { return this.retryMessage(params, errorHandler); } }, 'menu_item_reply': { id: 'menu_item_reply', title: formatMessage(messages.reply), handler: (params, errorHandler) => { return this.replyToMessage(params, errorHandler); } }, 'menu_item_forward': { id: 'menu_item_forward', title: formatMessage(messages.forward), handler: _ => {} }, 'menu_item_copy': { id: 'menu_item_copy', title: '复制', handler: (params, errorHandler) => { return this.copyMessageText(params, errorHandler); } }, 'menu_item_favorite': { id: 'menu_item_favorite', title: favoriteState.has(favoriteKey(props.params && props.params.topicName, props.params && props.params.seq)) ? '取消收藏' : '收藏', handler: (params, errorHandler) => { return favoriteState.has(favoriteKey(params.topicName, params.seq)) ? this.removeFavorite(params, errorHandler) : this.addFavorite(params, errorHandler); } }, 'menu_item_recall': { id: 'menu_item_recall', title: '撤回', handler: (params, errorHandler) => { return this.recallOwnMessage(params, errorHandler); } }, 'menu_item_select': { id: 'menu_item_select', title: '多选', handler: _ => {} }, 'menu_item_edit': { id: 'menu_item_edit', title: formatMessage(messages.edit), handler: (params, errorHandler) => { return this.editMessage(params, errorHandler); } }, 'menu_item_pin': { id: 'menu_item_pin', title: formatMessage(messages.pin_message), handler: (params, errorHandler) => { return this.pinMessage(true, params, errorHandler); } }, 'menu_item_unpin': { id: 'menu_item_unpin', title: formatMessage(messages.unpin_message), handler: (params, errorHandler) => { return this.pinMessage(false, params, errorHandler); } }, 'topic_unmute': { id: 'topic_unmute', title: formatMessage(messages.unmute), handler: this.topicPermissionSetter.bind(this, '+P') }, 'topic_mute': { id: 'topic_mute', title: formatMessage(messages.mute), handler: this.topicPermissionSetter.bind(this, '-P') }, 'topic_unblock': { id: 'topic_unblock', title: formatMessage(messages.unblock), handler: this.topicPermissionSetter.bind(this, '+JP') }, 'topic_block': { id: 'topic_block', title: formatMessage(messages.block), handler: (params, errorHandler) => { return props.onShowAlert(params.topicTitle || formatMessage(messages.block), formatMessage(messages.topic_block_warning), _ => this.topicPermissionSetter('-JP', params, errorHandler).then(ctrl => { this.props.onTopicRemoved(params.topicName); return ctrl; }), null, true, null); } }, 'topic_delete': { id: 'topic_delete', title: formatMessage(messages.topic_delete), handler: (params, errorHandler) => { return props.onShowAlert(params.topicTitle || formatMessage(messages.topic_delete), formatMessage(messages.topic_delete_warning), _ => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } return topic.delTopic(true).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); }, null, true, null); } }, 'topic_archive': { id: 'topic_archive', title: formatMessage(messages.archive), handler: (params, errorHandler) => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } return topic.archive(true).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } }, 'topic_restore': { id: 'topic_restore', title: formatMessage(messages.unarchive), handler: (params, errorHandler) => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } return topic.archive(false).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } }, 'topic_pin': { id: 'topic_pin', title: formatMessage(messages.pin_chat), handler: (params, errorHandler) => { const me = this.props.tinode.getMeTopic(); if (!me) { console.warn("'me' topic not found"); return; } return me.pinTopic(params.topicName, true).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } }, 'topic_unpin': { id: 'topic_unpin', title: formatMessage(messages.unpin_chat), handler: (params, errorHandler) => { const me = this.props.tinode.getMeTopic(); if (!me) { console.warn("'me' topic not found"); return; } return me.pinTopic(params.topicName, false).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } }, 'permissions': { id: 'permissions', title: formatMessage(messages.edit_permissions), handler: null }, 'member_delete': { id: 'member_delete', title: formatMessage(messages.member_delete), handler: (params, errorHandler) => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic || !params.user) { console.warn("Topic or user not found: '" + params.topicName + "', '" + params.user + "'"); return; } return topic.delSubscription(params.user).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } }, 'member_mute': { id: 'member_mute', title: formatMessage(messages.mute), handler: this.topicPermissionSetter.bind(this, '-P') }, 'member_unmute': { id: 'member_unmute', title: formatMessage(messages.unmute), handler: this.topicPermissionSetter.bind(this, '+P') }, 'member_block': { id: 'member_block', title: formatMessage(messages.block), handler: this.topicPermissionSetter.bind(this, '-JP') }, 'member_unblock': { id: 'member_unblock', title: formatMessage(messages.unblock), handler: this.topicPermissionSetter.bind(this, '+JP') } }; } componentDidMount() { document.addEventListener('mousedown', this.handlePageClick, false); document.addEventListener('keyup', this.handleEscapeKey, false); } componentWillUnmount() { document.removeEventListener('mousedown', this.handlePageClick, false); document.removeEventListener('keyup', this.handleEscapeKey, false); } handlePageClick(e) { if (this.selfRef.current.contains(e.target)) { return; } e.preventDefault(); e.stopPropagation(); this.props.hide(); } handleEscapeKey(e) { if (e.keyCode === 27) { this.props.hide(); } } handleClick(e) { e.preventDefault(); e.stopPropagation(); this.props.hide(); let item = this.props.items[e.currentTarget.dataset.id]; if (typeof item == 'string') { item = this.MenuItems[item]; } if (!item) { console.error("Invalid menu item ID", e.currentTarget.dataset.id); } else { this.props.onAction(item.id, item.handler(this.props.params, this.props.onError), this.props.params); } } deleteMessages(all, hard, params, errorHandler) { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } if (!all && topic.cancelSend(params.seq)) { return; } const promise = all ? topic.delMessagesAll(hard) : params.replace > 0 ? topic.delMessagesEdits(params.replace, hard) : topic.delMessagesList([params.seq], hard); return promise.catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } copyMessageText(params, errorHandler) { const text = typeof params.content == 'string' ? params.content : tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.toPlainText(params.content); return navigator.clipboard.writeText(text || '').catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } addFavorite(params, errorHandler) { return (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.favoriteMessages)([{ topic: params.topicName, seq: params.seq }]).then(result => { const failedItem = result && result.failed && result.failed[0]; if (failedItem) { if (errorHandler) { errorHandler(failedItem.reason === 'NOT_FOUND' ? '收藏失败,该消息暂无法收藏,请稍后重试' : '收藏失败', 'err'); } return; } const key = favoriteKey(params.topicName, params.seq); favoriteState.set(key, true); findFavorite(params.topicName, params.seq).then(match => { if (match) favoriteState.set(key, match.favorite_id); }).catch(() => {}); }).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } removeFavorite(params, errorHandler) { const key = favoriteKey(params.topicName, params.seq); const cached = favoriteState.get(key); const finish = favoriteId => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.deleteFavorite)(favoriteId).then(() => favoriteState.delete(key)); const ready = cached && cached !== true ? Promise.resolve(cached) : findFavorite(params.topicName, params.seq).then(match => match && match.favorite_id); return ready.then(favoriteId => { if (!favoriteId) { if (errorHandler) errorHandler('未找到对应收藏', 'err'); return; } return finish(favoriteId); }).catch(err => { if (errorHandler) { errorHandler(err.message || '取消收藏失败', 'err'); } }); } recallOwnMessage(params, errorHandler) { return (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.recallMessage)(params.topicName, params.seq).then(_ => { return this.deleteMessages(false, true, params, errorHandler); }).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } retryMessage(params, errorHandler) { const topic = this.props.tinode.getTopic(params.topicName); if (!topic || !topic.flushMessage(params.seq)) { return; } const msg = topic.createMessage(params.content, false); return topic.publishDraft(msg).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } pinMessage(pin, params, errorHandler) { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { return; } topic.pinMessage(params.seq, pin).catch(err => errorHandler ? errorHandler(err.message, 'err') : null); } topicPermissionSetter(mode, params, errorHandler) { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found", params.topicName); return; } let result = topic.updateMode(params.user, mode); if (errorHandler) { result = result.catch(err => errorHandler(err.message, 'err')); } return result; } replyToMessage(params, errorHandler) { params.pickReply(params.seq, params.content, params.userFrom, params.userName, errorHandler); } editMessage(params, errorHandler) { params.editMessage(params.replace || params.seq, params.content, errorHandler); } render() { const menu = []; let count = 0; this.props.items.forEach(item => { if (typeof item == 'string') { item = this.MenuItems[item]; } if (item && item.title) { const className = item.disabled ? 'disabled' : undefined; menu.push(item.title == '-' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("li", { className: "separator" }, count, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("li", { className: className, onClick: this.handleClick, "data-id": count, children: item.title }, count, false)); } count++; }); const hSize = 12 * _config_js__WEBPACK_IMPORTED_MODULE_3__.REM_SIZE; const vSize = _config_js__WEBPACK_IMPORTED_MODULE_3__.REM_SIZE * (0.7 + menu.length * 2.5); const left = this.props.bounds.right - this.props.clickAt.x < hSize ? this.props.clickAt.x - this.props.bounds.left - hSize : this.props.clickAt.x - this.props.bounds.left; const top = this.props.bounds.bottom - this.props.clickAt.y < vSize ? this.props.clickAt.y - this.props.bounds.top - vSize : this.props.clickAt.y - this.props.bounds.top; const position = { left: left + 'px', top: top + 'px' }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("ul", { className: "menu", style: position, ref: this.selfRef, children: menu }, void 0, false); } } /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ContextMenu)); /***/ }), /***/ "./src/widgets/cropper.jsx": /*!*********************************!*\ !*** ./src/widgets/cropper.jsx ***! \*********************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ Cropper; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const DEFAULT_MAX_ZOOM = 8; class Cropper extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { panX: 0, panY: 0, originX: 0, originY: 0, zoom: 1, minZoom: 0.001, maxZoom: DEFAULT_MAX_ZOOM }; this.overlay = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.cutout = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.preview = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.boundingBox = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.imageWidth = 0; this.imageHeight = 0; this.mouseX = 0; this.mouseY = 0; this.prevDistance = 0; this.cutoutRect = {}; this.bBoxRect = {}; this.originX = 0; this.originY = 0; this.initScaling = this.initScaling.bind(this); this.onZoom = this.onZoom.bind(this); this.handleZoom = this.handleZoom.bind(this); this.mouseDown = this.mouseDown.bind(this); this.mouseUp = this.mouseUp.bind(this); this.mouseMove = this.mouseMove.bind(this); this.mouseTouch = this.mouseTouch.bind(this); this.positionAll = this.positionAll.bind(this); this.translate = this.translate.bind(this); } componentDidMount() { this.overlay.current.addEventListener('mousedown', this.mouseDown, { passive: true }); this.overlay.current.addEventListener('touchstart', this.mouseDown, { passive: true }); this.bBoxRect = this.boundingBox.current.getBoundingClientRect(); this.originX = this.bBoxRect.width / 2; this.originY = this.bBoxRect.height / 2; this.cutoutRect = this.cutout.current.getBoundingClientRect(); } componentWillUnmount() { if (this.overlay.current) { this.overlay.current.removeEventListener('mousedown', this.mouseDown); this.overlay.current.removeEventListener('touchstart', this.mouseDown); } } positionAll(panX, panY, zoom) { this.setState({ panX: panX, panY: panY, zoom: zoom, originX: this.originX - panX, originY: this.originY - panY }); const left = (this.originX - panX) * zoom - this.originX; const top = (this.originY - panY) * zoom - this.originY; this.props.onChange((left + this.cutoutRect.left - this.bBoxRect.left) / zoom, (top + this.cutoutRect.top - this.bBoxRect.top) / zoom, this.cutoutRect.width / zoom, this.cutoutRect.height / zoom, zoom); } static checkBound(currPan, img, cutout, delta) { let nextDiff = Math.min(0, cutout[0] - img[0] - delta, img[1] - cutout[1] + delta); if (nextDiff == 0) { currPan += delta; } else if (Math.min(0, cutout[0] - img[0], img[1] - cutout[1]) < nextDiff) { currPan += delta; } return currPan; } initScaling() { const imgRect = this.preview.current.getBoundingClientRect(); this.imageWidth = imgRect.width; this.imageHeight = imgRect.height; const minZoom = Math.max(this.cutoutRect.width / imgRect.width, this.cutoutRect.height / imgRect.height); this.setState({ minZoom: minZoom, maxZoom: minZoom * DEFAULT_MAX_ZOOM }); const zoom = Math.max(this.bBoxRect.width / imgRect.width, this.bBoxRect.height / imgRect.height); const panX = this.cutoutRect.left - this.bBoxRect.left - (imgRect.width - this.cutoutRect.width) / 2; const panY = this.cutoutRect.top - this.bBoxRect.top - (imgRect.height - this.cutoutRect.height) / 2; this.positionAll(panX, panY, zoom); } onZoom(e) { this.handleZoom(e.target.value); } handleZoom(zoom) { let panX = this.state.panX; let panY = this.state.panY; const imgLeft = this.originX - (this.originX - panX) * zoom; const imgRight = imgLeft + this.imageWidth * zoom; const imgTop = this.originY - (this.originY - panY) * zoom; const imgBottom = imgTop + this.imageHeight * zoom; const coLeft = this.cutoutRect.left - this.bBoxRect.left; const coRight = coLeft + this.cutoutRect.width; const coTop = this.cutoutRect.top - this.bBoxRect.top; const coBottom = coTop + this.cutoutRect.height; if (coLeft < imgLeft) { panX -= (imgLeft - coLeft) / zoom; } else if (coRight > imgRight) { panX += (coRight - imgRight) / zoom; } if (coTop < imgTop) { panY -= (imgTop - coTop) / zoom; } else if (coBottom > imgBottom) { panY += (coBottom - imgBottom) / zoom; } this.positionAll(panX, panY, zoom); } mouseDown(e) { if (e.touches) { this.mouseX = e.touches[0].pageX; this.mouseY = e.touches[0].pageY; } else { this.mouseX = e.pageX; this.mouseY = e.pageY; } window.addEventListener('mousemove', this.mouseMove, { passive: false }); window.addEventListener('touchmove', this.mouseTouch, { passive: false }); window.addEventListener('mouseup', this.mouseUp, { passive: true }); window.addEventListener('touchend', this.mouseUp, { passive: true }); document.body.style['userSelect'] = 'none'; } translate(pageX, pageY) { const dX = (pageX - this.mouseX) / this.state.zoom; const dY = (pageY - this.mouseY) / this.state.zoom; this.mouseX = pageX; this.mouseY = pageY; const imgRect = this.preview.current.getBoundingClientRect(); const panX = Cropper.checkBound(this.state.panX, [imgRect.left, imgRect.right], [this.cutoutRect.left, this.cutoutRect.right], dX); const panY = Cropper.checkBound(this.state.panY, [imgRect.top, imgRect.bottom], [this.cutoutRect.top, this.cutoutRect.bottom], dY); this.positionAll(panX, panY, this.state.zoom); } mouseMove(e) { e.preventDefault(); this.translate(e.pageX, e.pageY); } mouseTouch(e) { e.preventDefault(); if (e.touches.length == 1) { this.translate(e.touches[0].pageX, e.touches[0].pageY); return; } const [touch0, touch1] = e.touches; const distance = Math.sqrt((touch0.pageX - touch1.pageX) * (touch0.pageX - touch1.pageX) + (touch0.pageY - touch1.pageY) * (touch0.pageY - touch1.pageY)); if (!this.prevDistance) { this.prevDistance = distance / this.state.zoom; } let scale = distance / this.prevDistance; this.handleZoom(Math.max(this.minZoom, Math.min(this.maxZoom, scale))); } mouseUp(e) { window.removeEventListener('mousemove', this.mouseMove); window.removeEventListener('touchmove', this.mouseTouch); window.removeEventListener('mouseup', this.mouseUp); window.removeEventListener('touchend', this.mouseUp); document.body.style['userSelect'] = ''; this.positionAll(this.state.panX, this.state.panY, this.state.zoom); } render() { const t3d = `translate3d(${this.state.panX}px, ${this.state.panY}px, 0) scale(${this.state.zoom})`; const orig = `${this.state.originX}px ${this.state.originY}px`; const overlay = { top: `${this.originY - this.state.originY * this.state.zoom}px`, left: `${this.originX - this.state.originX * this.state.zoom}px`, width: `${this.imageWidth * this.state.zoom}px`, height: `${this.imageHeight * this.state.zoom}px` }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", { className: "cropper", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", { className: "bounding-box", ref: this.boundingBox, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("img", { src: this.props.source, className: "preview", alt: "", style: { transform: t3d, transformOrigin: orig }, ref: this.preview, onLoad: this.initScaling }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", { className: "cutout circle", ref: this.cutout }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", { className: "overlay", style: overlay, ref: this.overlay }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", { className: "zoom-wrapper", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("input", { type: "range", className: "zoomer", step: "0.001", min: this.state.minZoom, max: this.state.maxZoom, value: this.state.zoom, onChange: this.onZoom }, void 0, false) }, void 0, false)] }, void 0, true); } } /***/ }), /***/ "./src/widgets/error-panel.jsx": /*!*************************************!*\ !*** ./src/widgets/error-panel.jsx ***! \*************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ ErrorPanel; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./menu-cancel.jsx */ "./src/widgets/menu-cancel.jsx"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class ErrorPanel extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { show: false }; this.hide = this.hide.bind(this); } componentDidUpdate(prevProps) { if (prevProps.level !== this.props.level) { this.setState({ show: !!this.props.level }); } } hide() { this.setState({ show: false }); if (this.props.onClearError) { this.props.onClearError(); } } render() { const icons = { err: 'error', warn: 'warning', info: 'info' }; const level = icons[this.props.level] || ''; const className = 'info-box ' + level; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: className, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "icon", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons", children: level }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: [this.props.text, this.props.action ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: ["\xA0 ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("a", { href: "#", style: { whiteSpace: 'nowrap' }, onClick: e => { e.preventDefault(); this.props.action(); }, children: this.props.actionText }, void 0, false)] }, void 0, true) : null] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "cancel", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(_menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { onCancel: this.hide }, void 0, false) }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/file-progress.jsx": /*!***************************************!*\ !*** ./src/widgets/file-progress.jsx ***! \***************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ FileProgress; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class FileProgress extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "uploader", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { style: { width: this.props.progress * 100 + "%" } }, void 0, false) }, void 0, false), this.props.progress < 0.999 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onCancel(); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons", children: "close" }, void 0, false), " ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "action_cancel", defaultMessage: "cancel", description: "Call to action [cancel]" }, void 0, false)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "upload_finishing", defaultMessage: "finishing...", description: "Notification that upload is finishing" }, void 0, false)] }, void 0, true); } } /***/ }), /***/ "./src/widgets/forward-dialog.jsx": /*!****************************************!*\ !*** ./src/widgets/forward-dialog.jsx ***! \****************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ ForwardDialog; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _search_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./search-contacts.jsx */ "./src/widgets/search-contacts.jsx"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class ForwardDialog extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { query: null }; this.handleEscapeKey = this.handleEscapeKey.bind(this); this.handleClose = this.handleClose.bind(this); this.handleSearchContacts = this.handleSearchContacts.bind(this); this.handleContactSelected = this.handleContactSelected.bind(this); } componentDidMount() { this.props.onInitFind(); } handleEscapeKey(e) { if (e.keyCode === 27) { this.props.hide(false); } } handleClose(e) { e.preventDefault(); this.props.hide(false); } handleSearchContacts(query) { this.setState({ query: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNullValue(query) ? null : query }); this.props.onSearchContacts(query); } handleContactSelected(uid) { this.props.onTopicSelected(uid); this.props.hide(true); } render() { let contacts = this.state.query != null ? this.props.searchResults : this.props.contacts; contacts = contacts.filter(c => { return c.name != this.props.topicSelected && c.acs.isJoiner() && c.acs.isWriter(); }); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "alert-container", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "forward-dialog", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: "title with-control", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "forward_to", defaultMessage: "Forward to", desription: "Title of the contact selector dialog when forwarding a message" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("a", { href: "#", onClick: this.handleClose, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", { className: "material-icons", children: "close" }, void 0, false) }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "forward_to_search_placeholder", defaultMessage: "Search contacts", description: "Contact search prompt when forwarding a message.", children: search_placeholder => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(_search_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { placeholder: search_placeholder, onSearchContacts: this.handleSearchContacts }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "search_no_results", defaultMessage: "Search returned no results", description: "Text shown in contacts view when query returned no results.", children: not_found_placeholder => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(_contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, contacts: contacts, myUserId: this.props.myUserId, emptyListMessage: not_found_placeholder, showOnline: false, showUnread: false, showContextMenu: false, onTopicSelected: this.handleContactSelected }, void 0, false) }, void 0, false)] }, void 0, true) }, void 0, false); } } /***/ }), /***/ "./src/widgets/host-selector.jsx": /*!***************************************!*\ !*** ./src/widgets/host-selector.jsx ***! \***************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ HostSelector; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class HostSelector extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { hostName: props.serverAddress, changed: false }; this.handleHostNameChange = this.handleHostNameChange.bind(this); this.handleEditingFinished = this.handleEditingFinished.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } handleHostNameChange(e) { this.setState({ hostName: e.target.value, changed: true }); } handleEditingFinished() { if (this.state.changed) { this.setState({ changed: false }); this.props.onServerAddressChange(this.state.hostName.trim()); } } handleKeyDown(e) { if (e.key == 'Enter') { this.handleEditingFinished(); } } render() { const hostOptions = []; for (let key in _config_js__WEBPACK_IMPORTED_MODULE_1__.KNOWN_HOSTS) { let item = _config_js__WEBPACK_IMPORTED_MODULE_1__.KNOWN_HOSTS[key]; hostOptions.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("option", { value: item }, item, false)); } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { type: "search", id: "host-name", placeholder: this.props.hostName, list: "known-hosts", className: "quoted", value: this.state.hostName, onChange: this.handleHostNameChange, onBlur: this.handleEditingFinished, onKeyDown: this.handleKeyDown, required: true }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("datalist", { id: "known-hosts", children: hostOptions }, void 0, false)] }, void 0, true); } } /***/ }), /***/ "./src/widgets/in-place-edit.jsx": /*!***************************************!*\ !*** ./src/widgets/in-place-edit.jsx ***! \***************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ InPlaceEdit; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _visible_password_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./visible-password.jsx */ "./src/widgets/visible-password.jsx"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class InPlaceEdit extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.selfRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.state = { active: props.active, initialValue: props.value || '', value: props.value || '', valid: true }; this.handeTextChange = this.handeTextChange.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); this.handleStartEditing = this.handleStartEditing.bind(this); this.handleEditingFinished = this.handleEditingFinished.bind(this); this.handlePasswordFinished = this.handlePasswordFinished.bind(this); } componentDidUpdate(prevProps, prevState) { const newValue = this.props.value || ''; if (prevState.initialValue != newValue && !prevState.active) { this.setState({ initialValue: newValue, value: newValue }); } } handeTextChange(e) { this.setState({ value: e.target.value || '' }); if (this.props.validator) { Promise.resolve(this.props.validator(e.target.value)).then(valid => { this.setState({ valid: valid }); }).catch(err => { if (err) { this.setState({ valid: false }); } }); } } handleKeyDown(e) { if (e.keyCode === 27) { this.setState({ value: this.props.value, active: false }); } else if (e.keyCode === 13) { this.handleEditingFinished(e); } } handleStartEditing() { if (!this.props.readOnly) { this.setState({ active: true }, _ => { if (this.selfRef.current) { this.selfRef.current.focus(); } }); } } handleEditingFinished(event) { const value = this.state.value.trim(); if (this.props.required && (!event.target.checkValidity() || !value)) { this.setState({ value: this.props.value, active: false }); return; } this.setState({ active: false }); if ((value || this.props.value) && value !== this.props.value && this.state.valid) { this.props.onFinished(value); } } handlePasswordFinished(value) { this.setState({ active: false }); if (value && value !== this.props.value) { this.props.onFinished(value); } } render() { if (!this.state.active) { let spanText = this.props.type == 'password' ? '••••••••' : this.state.value; let spanClass = 'in-place-edit' + (this.props.readOnly ? ' disabled' : ''); if (!spanText) { spanText = this.props.placeholder; spanClass += ' placeholder'; } if (!this.props.multiline || this.props.multiline == 1) { spanClass += ' short'; } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { className: spanClass, onClick: this.handleStartEditing, children: [this.props.iconLeft && (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons light-gray", children: this.props.iconLeft }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: spanText }, void 0, false), this.props.iconRight && (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons light-gray", children: this.props.iconRight }, void 0, false)] }, void 0, true); } let element; const attr = {}; if (this.props.type == 'password') { element = _visible_password_jsx__WEBPACK_IMPORTED_MODULE_1__["default"]; attr.onFinished = this.handlePasswordFinished; } else { if (this.props.multiline > 1) { element = 'textarea'; attr.rows = this.props.multiline; attr.className = 'in-place-edit'; } else { element = 'input'; attr.type = this.props.type || 'text'; attr.className = 'in-place-edit' + (this.props.iconLeft ? ' with-icon-left' : this.props.iconRight ? ' with-icon-right' : ''); if (this.props.maxLength) { attr.maxLength = this.props.maxLength; } } attr.value = this.state.value; attr.className += this.state.valid ? '' : ' invalid'; attr.ref = this.selfRef; attr.onChange = this.handeTextChange; attr.onKeyDown = this.handleKeyDown; attr.onBlur = this.handleEditingFinished; } attr.placeholder = this.props.placeholder; attr.required = this.props.required ? 'required' : ''; attr.autoComplete = this.props.autoComplete; attr.autoFocus = true; if (this.props.spellCheck !== undefined) { attr.spellCheck = this.props.spellCheck ? 'true' : 'false'; } if (this.props.iconLeft || this.props.iconRight) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.Fragment, { children: [this.props.iconLeft && (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons light-gray", children: this.props.iconLeft }, void 0, false), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(element, attr, null), this.props.iconRight && (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons light-gray", children: this.props.iconRight }, void 0, false)] }, void 0, true); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(element, attr, null); } } ; /***/ }), /***/ "./src/widgets/inline-video.jsx": /*!**************************************!*\ !*** ./src/widgets/inline-video.jsx ***! \**************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ InlineVideo; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class InlineVideo extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.videoRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.handleClick = this.handleClick.bind(this); } handleClick(e) { if (this.props.onClick) { this.props.onClick(e); } } render() { const duration = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_1__.secondsToTime)(this.props['data-duration'] / 1000); const className = 'inline-video' + (this.props.onClick ? ' image-clickable' : ''); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: className, children: [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', this.props), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "play-control", children: this.props.onClick ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons white x-big", children: "play_arrow" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("img", { src: "img/broken_video.png", style: { filter: 'invert(100%)' }, width: "36", height: "36" }, void 0, false) }, void 0, false), duration ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "duration", children: duration }, void 0, false) : null] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/lazy-image.jsx": /*!************************************!*\ !*** ./src/widgets/lazy-image.jsx ***! \************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ LazyImage; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class LazyImage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { src: this.props.isvideo ? 'img/blankvid.png' : 'img/blankimg.png', style: Object.assign({ padding: '4px' }, this.props.style), className: this.props.className, alt: this.props.alt, onClick: this.props.onClick }; } componentDidMount() { this.props.whenDone.promise.then(data => this.setState({ src: data.src, style: { ...this.state.style, padding: 0 } })).catch(_ => this.setState({ src: this.props.isvideo ? 'img/broken_video.png' : 'img/broken_image.png' })); } componentWillUnmount() { this.props.whenDone.cancel(); } componentDidUpdate(prevProps) { if (prevProps.whenDone != this.props.whenDone) { this.setState({ src: this.props.isvideo ? 'img/blankvid.png' : 'img/blankimg.png', style: { ...this.state.style, padding: '4px' } }); this.props.whenDone.promise.then(data => this.setState({ src: data.src, style: { ...this.state.style, padding: 0 } })).catch(_ => this.setState({ src: this.props.isvideo ? 'img/broken_video.png' : 'img/broken_image.png' })); } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', this.state); } } ; /***/ }), /***/ "./src/widgets/letter-tile.jsx": /*!*************************************!*\ !*** ./src/widgets/letter-tile.jsx ***! \*************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ LetterTile; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class LetterTile extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { let avatar; if (this.props.avatar === true) { if (tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.isSelfTopicName(this.props.topic)) { avatar = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("img", { className: "avatar self", alt: "avatar", src: _config_js__WEBPACK_IMPORTED_MODULE_4__.SELF_AVATAR_URI }, void 0, false); } else { const isGroup = tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.isGroupTopicName(this.props.topic); const iconColor = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__.idToColorClass)(this.props.topic, isGroup); if (this.props.topic && this.props.title && this.props.title.trim()) { const letter = this.props.title.trim().charAt(0); const className = 'lettertile ' + iconColor + (this.props.deleted ? ' disabled' : ''); avatar = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { className: className, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", { children: letter }, void 0, false) }, void 0, false); } else { const className = 'material-icons ' + iconColor + (this.props.deleted ? ' disabled' : ''); avatar = isGroup ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", { className: className, children: "group" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", { className: className, children: "person" }, void 0, false); } } } else if (this.props.avatar) { const url = this.props.authorizeURL((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.sanitizeUrlForMime)(this.props.avatar, 'image')); const className = 'avatar' + (this.props.deleted ? ' deleted' : ''); avatar = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("img", { className: className, alt: "avatar", src: url, onError: e => { e.target.onerror = null; e.target.src = "img/broken_image.png"; } }, void 0, false); } else { avatar = null; } return avatar; } } /***/ }), /***/ "./src/widgets/load-spinner.jsx": /*!**************************************!*\ !*** ./src/widgets/load-spinner.jsx ***! \**************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ LoadSpinner; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class LoadSpinner extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const className = 'load-spinner-box' + (this.props.large ? ' large' : '') + (this.props.clear ? ' clear' : '') + (this.props.centered ? ' centered' : ''); return this.props.show ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", { className: className, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", { className: "loader-spinner" }, void 0, false) }, void 0, false) : null; } } /***/ }), /***/ "./src/widgets/menu-cancel.jsx": /*!*************************************!*\ !*** ./src/widgets/menu-cancel.jsx ***! \*************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ MenuCancel; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class MenuCancel extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onCancel(); }, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("i", { className: "material-icons", children: "close" }, void 0, false) }, void 0, false); } } /***/ }), /***/ "./src/widgets/menu-contacts.jsx": /*!***************************************!*\ !*** ./src/widgets/menu-contacts.jsx ***! \***************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ MenuContacts; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class MenuContacts extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onNewTopic(); }, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("i", { className: "material-icons", children: "chat" }, void 0, false) }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onSettings(); }, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("i", { className: "material-icons", children: "settings" }, void 0, false) }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/menu-start.jsx": /*!************************************!*\ !*** ./src/widgets/menu-start.jsx ***! \************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ MenuStart; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class MenuStart extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onSignUp(); }, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("i", { className: "material-icons", children: "person_add" }, void 0, false) }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onSettings(); }, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("i", { className: "material-icons", children: "settings" }, void 0, false) }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/new-topic-by-id.jsx": /*!*****************************************!*\ !*** ./src/widgets/new-topic-by-id.jsx ***! \*****************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var qrcodejs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! qrcodejs */ "qrcodejs"); /* harmony import */ var qrcodejs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(qrcodejs__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config */ "./src/config.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_2__.defineMessages)({ invalid_id: { id: 'error_invalid_id', defaultMessage: 'Invalid ID', description: 'Error message' } }); class NewTopicById extends (react__WEBPACK_IMPORTED_MODULE_1___default().PureComponent) { constructor(props) { super(props); this.qrCodeRef = react__WEBPACK_IMPORTED_MODULE_1___default().createRef(); this.state = { groupId: '' }; this.handleChange = this.handleChange.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } componentDidMount() { new (qrcodejs__WEBPACK_IMPORTED_MODULE_0___default())(this.qrCodeRef.current, { text: this.props.myURI, width: _config__WEBPACK_IMPORTED_MODULE_3__.QRCODE_SIZE, height: _config__WEBPACK_IMPORTED_MODULE_3__.QRCODE_SIZE }); } handleChange(e) { this.setState({ groupId: e.target.value }); } handleKeyPress(e) { if (e.key === 'Enter') { this.handleSubmit(e); } } handleSubmit(e) { e.preventDefault(); if (this.state.groupId) { const name = this.state.groupId.trim(); const prefix = name.substring(0, 3); if (name.length > 3 && ['usr', 'grp', 'chn'].includes(prefix)) { this.props.onSubmit(name); } else { this.props.onError(this.props.intl.formatMessage(messages.invalid_id), 'err'); } } } render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_2__.FormattedMessage, { id: "group_user_id_prompt", defaultMessage: "Group or User ID", description: "Prompt for entering user or group ID", children: prompt => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("input", { type: "text", placeholder: prompt, value: this.state.groupId, onChange: this.handleChange, onKeyDown: this.handleKeyPress, required: true, autoFocus: true }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "dialog-buttons", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("button", { className: "primary", onClick: this.handleSubmit, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_2__.FormattedMessage, { id: "button_subscribe", defaultMessage: "Subscribe", description: "Button [Subscribe]" }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("br", {}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "panel-form-column", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_2__.FormattedMessage, { id: "label_scan_id", defaultMessage: "Scan my ID:", description: "Label [Scan my ID:]" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "qr-code", ref: this.qrCodeRef }, void 0, false)] }, void 0, true)] }, void 0, true); } } ; /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_2__.injectIntl)(NewTopicById)); /***/ }), /***/ "./src/widgets/new-topic-group.jsx": /*!*****************************************!*\ !*** ./src/widgets/new-topic-group.jsx ***! \*****************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ NewTopicGroup; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _avatar_crop_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./avatar-crop.jsx */ "./src/widgets/avatar-crop.jsx"); /* harmony import */ var _avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _checkbox_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _tag_manager_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./tag-manager.jsx */ "./src/widgets/tag-manager.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class NewTopicGroup extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.fullName = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.state = { fullName: '', private: '', description: '', imageUrl: null, tags: [], isChannel: false, newAvatar: null, newAvatarMime: null }; this.handleFieldEdit = this.handleFieldEdit.bind(this); this.handleImageChanged = this.handleImageChanged.bind(this); this.handleAvatarCropped = this.handleAvatarCropped.bind(this); this.handleAvatarCropCancel = this.handleAvatarCropCancel.bind(this); this.uploadAvatar = this.uploadAvatar.bind(this); this.handleTagsChanged = this.handleTagsChanged.bind(this); this.handleChannelToggle = this.handleChannelToggle.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } componentDidMount() {} handleFieldEdit(name, e) { this.setState({ [name]: e.target.value || '' }); } handleImageChanged(mime, img) { this.setState({ newAvatar: img, newAvatarMime: mime }); } handleAvatarCropped(mime, blob, width, height) { const url = blob ? URL.createObjectURL(blob) : null; this.setState({ imageUrl: url, newAvatar: null, newAvatarMime: null }); if (blob) { this.uploadAvatar(mime, blob, width, height); } } handleAvatarCropCancel() { this.setState({ newAvatar: null, newAvatarMime: null }); } uploadAvatar(mime, blob, width, height) { const readyToUpload = image => { let { mime, blob } = image; if (blob.size > _config_js__WEBPACK_IMPORTED_MODULE_6__.MAX_AVATAR_BYTES) { const uploader = (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_8__.createChatUploader)(this.props.tinode); uploader.upload(blob).then(url => this.setState({ imageUrl: url })).catch(err => this.props.onError(err.message, 'err')); } else { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__.blobToBase64)(blob).then(b64 => this.setState({ imageUrl: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__.makeImageUrl)({ data: b64.bits, type: mime }) })); } }; if (width > _config_js__WEBPACK_IMPORTED_MODULE_6__.AVATAR_SIZE || height > _config_js__WEBPACK_IMPORTED_MODULE_6__.AVATAR_SIZE || width != height) { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__.imageScaled)(blob, _config_js__WEBPACK_IMPORTED_MODULE_6__.AVATAR_SIZE, _config_js__WEBPACK_IMPORTED_MODULE_6__.AVATAR_SIZE, _config_js__WEBPACK_IMPORTED_MODULE_6__.MAX_EXTERN_ATTACHMENT_SIZE, true).then(scaled => readyToUpload(scaled)).catch(err => this.props.onError(err.message, 'err')); } else { readyToUpload({ mime: mime, blob: blob, width: width, height: height }); } } handleTagsChanged(tags) { this.setState({ tags: tags }); } handleChannelToggle() { this.setState({ isChannel: !this.state.isChannel }); } handleSubmit(e) { e.preventDefault(); const fn = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_9__.truncateString)(this.state.fullName.trim(), _config_js__WEBPACK_IMPORTED_MODULE_6__.MAX_TITLE_LENGTH); const comment = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_9__.truncateString)(this.state.private.trim(), _config_js__WEBPACK_IMPORTED_MODULE_6__.MAX_TITLE_LENGTH); const description = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_9__.truncateString)(this.state.description.trim(), _config_js__WEBPACK_IMPORTED_MODULE_6__.MAX_TOPIC_DESCRIPTION_LENGTH); if (fn) { this.props.onSubmit(fn, description, this.state.imageUrl, comment, this.state.tags, this.state.isChannel); } } render() { if (this.state.newAvatar) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(_avatar_crop_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { avatar: this.state.newAvatar, mime: this.state.newAvatarMime, onSubmit: this.handleAvatarCropped, onCancel: this.handleAvatarCropCancel, onError: this.props.onError }, void 0, false); } let submitClasses = 'primary'; if (this.props.disabled) { submitClasses += ' disabled'; } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("form", { className: "panel-form", onSubmit: this.handleSubmit, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", { className: "panel-form-column", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("center", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, avatar: this.state.imageUrl, onError: this.props.onError, onImageUpdated: this.handleImageChanged }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", { className: "group", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("label", { className: "small", htmlFor: "new-topic-fn", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_topic_name", defaultMessage: "Name", description: "Label for editing topic name" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "topic_name_editing_placeholder", defaultMessage: "Freeform name of the group", description: "Prompt for entering topic name", children: placeholder => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("input", { type: "text", id: "new-topic-fn", placeholder: placeholder, ref: this.fullName, value: this.state.fullName, onChange: this.handleFieldEdit.bind(this, 'fullName'), autoFocus: true, required: true, tabIndex: 0 }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", { className: "group", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("label", { className: "small", htmlFor: "new-topic-priv", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_private", defaultMessage: "Private comment", description: "Label for editing 'private'" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "private_editing_placeholder", defaultMessage: "Visible to you only", description: "Placeholder for editing 'private'", children: placeholder => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("input", { type: "text", id: "new-topic-priv", placeholder: placeholder, value: this.state.private, onChange: this.handleFieldEdit.bind(this, 'private'), tabIndex: 1 }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", { className: "group", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("label", { className: "small", htmlFor: "new-topic-desc", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_description", defaultMessage: "Description", description: "Label for description of user or topic" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "description_editing_placeholder", defaultMessage: "Description (optional)", description: "Placeholder for editing topic description", children: placeholder => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("input", { type: "text", id: "new-topic-desc", placeholder: placeholder, value: this.state.description, onChange: this.handleFieldEdit.bind(this, 'description'), tabIndex: 2 }, void 0, false) }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", { className: "panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(_checkbox_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { checked: this.state.isChannel, tabIndex: 3, onChange: this.handleChannelToggle }, void 0, false), "\xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("label", { onClick: this.handleChannelToggle, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "channel_prompt", defaultMessage: "This is a channel", description: "Checkbox label when creating a channel" }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_tag_manager", defaultMessage: "Tags (search & discovery)", description: "Section title for TagManager", children: title => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(_tag_manager_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { tinode: this.props.tinode, tags: this.state.tags, activated: true, onTagsChanged: this.handleTagsChanged, tabIndex: 4, title: title }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", { className: "dialog-buttons", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("button", { className: submitClasses, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_create", defaultMessage: "Create", description: "Button [Create]" }, void 0, false) }, void 0, false) }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/qr-scanner.jsx": /*!************************************!*\ !*** ./src/widgets/qr-scanner.jsx ***! \************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ GroupJoinPreview: function() { return /* binding */ GroupJoinPreview; }, /* harmony export */ "default": function() { return /* binding */ QrScanner; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var jsqr__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! jsqr */ "./node_modules/jsqr/dist/jsQR.js"); /* harmony import */ var jsqr__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(jsqr__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); function Icon({ children }) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("i", { className: "material-icons", "aria-hidden": "true", children: children }, void 0, false); } const SCAN_INTERVAL_MS = 200; const MAX_SCAN_EDGE = 480; const JSQR_OPTIONS = { inversionAttempts: 'dontInvert' }; class QrScanner extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { status: 'starting', errorText: '' }; this.videoRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.canvas = document.createElement('canvas'); this.stream = null; this.timer = null; this.detected = false; this.start = this.start.bind(this); this.stopStream = this.stopStream.bind(this); this.tick = this.tick.bind(this); } componentDidMount() { this.start(); } componentWillUnmount() { this.stopStream(); } start() { if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { this.setState({ status: 'error', errorText: '当前浏览器不支持摄像头访问' }); return; } this.detected = false; this.setState({ status: 'starting', errorText: '' }); navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' }, audio: false }).then(stream => { this.stream = stream; const video = this.videoRef.current; if (!video) { stream.getTracks().forEach(track => track.stop()); return; } video.srcObject = stream; video.play().catch(() => {}); this.setState({ status: 'scanning' }); this.timer = window.setInterval(this.tick, SCAN_INTERVAL_MS); }).catch(err => { const name = err && err.name; const text = name === 'NotAllowedError' ? '未获得摄像头权限,请在浏览器设置中允许访问摄像头' : name === 'NotFoundError' ? '未检测到可用摄像头' : name === 'NotReadableError' ? '摄像头正被其他程序占用' : '摄像头启动失败,请重试'; this.setState({ status: 'error', errorText: text }); }); } stopStream() { if (this.timer) { window.clearInterval(this.timer); this.timer = null; } if (this.stream) { this.stream.getTracks().forEach(track => track.stop()); this.stream = null; } } tick() { if (this.detected) { return; } const video = this.videoRef.current; if (!video || video.readyState !== video.HAVE_ENOUGH_DATA) { return; } const vw = video.videoWidth; const vh = video.videoHeight; if (!vw || !vh) { return; } const scale = Math.min(1, MAX_SCAN_EDGE / Math.max(vw, vh)); const w = Math.round(vw * scale); const h = Math.round(vh * scale); this.canvas.width = w; this.canvas.height = h; const ctx = this.canvas.getContext('2d', { willReadFrequently: true }); ctx.drawImage(video, 0, 0, w, h); let frame; try { frame = ctx.getImageData(0, 0, w, h); } catch (err) { return; } const code = jsqr__WEBPACK_IMPORTED_MODULE_1___default()(frame.data, w, h, JSQR_OPTIONS); if (code && code.data) { this.detected = true; this.setState({ status: 'resolving' }); this.stopStream(); this.props.onDetect(code.data); } } render() { const { status, errorText } = this.state; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "qr-scan-view", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("video", { ref: this.videoRef, className: "qr-scan-video", muted: true, playsInline: true, autoPlay: true }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "qr-scan-mask", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "qr-scan-frame", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("i", { className: "qr-scan-corner qr-scan-corner-tl" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("i", { className: "qr-scan-corner qr-scan-corner-tr" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("i", { className: "qr-scan-corner qr-scan-corner-bl" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("i", { className: "qr-scan-corner qr-scan-corner-br" }, void 0, false)] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("header", { className: "qr-scan-header", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", onClick: this.props.onClose, "aria-label": "返回", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "arrow_back_ios_new" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("h1", { children: "扫一扫" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", {}, void 0, false)] }, void 0, true), status === 'starting' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { className: "qr-scan-hint", children: "正在启动摄像头…" }, void 0, false) : null, status === 'scanning' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { className: "qr-scan-hint", children: "将二维码放入框内,即可自动扫描" }, void 0, false) : null, status === 'resolving' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { className: "qr-scan-hint", children: "识别中…" }, void 0, false) : null, status === 'error' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "qr-scan-error", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "error_outline" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { children: errorText }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", onClick: this.start, children: "重试" }, void 0, false)] }, void 0, true) : null] }, void 0, true); } } function GroupJoinPreview({ group, onSubmit, onCancel }) { const [message, setMessage] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(''); const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false); const [avatarUrl, setAvatarUrl] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(null); react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => { if (!group.avatar_file_id) { return undefined; } let live = true; (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_2__.getFileUrl)(group.avatar_file_id).then(url => { if (live) setAvatarUrl(url); }).catch(() => {}); return () => { live = false; }; }, [group.avatar_file_id]); const submit = () => { setBusy(true); Promise.resolve(onSubmit(message.trim())).finally(() => setBusy(false)); }; return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("div", { className: "qr-join-backdrop", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("section", { className: "qr-join-sheet", role: "dialog", "aria-modal": "true", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("span", { className: "qr-join-avatar", children: avatarUrl ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("img", { src: avatarUrl, alt: "" }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)(Icon, { children: "group" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("h2", { children: group.name || '群聊' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("p", { children: [group.member_count || 0, " 人"] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("input", { value: message, onChange: event => setMessage(event.target.value), placeholder: "验证消息(选填)", maxLength: 60, disabled: busy }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", className: "primary", disabled: busy, onClick: submit, children: busy ? '提交中…' : '申请加入' }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxDEV)("button", { type: "button", onClick: onCancel, disabled: busy, children: "取消" }, void 0, false)] }, void 0, true) }, void 0, false); } /***/ }), /***/ "./src/widgets/search-contacts.jsx": /*!*****************************************!*\ !*** ./src/widgets/search-contacts.jsx ***! \*****************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ SearchContacts; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class SearchContacts extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { edited: false, search: this.props.initialQuery || '' }; this.handleSearchChange = this.handleSearchChange.bind(this); this.handleSearch = this.handleSearch.bind(this); this.handleClear = this.handleClear.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } componentWillUnmount() { if (this.state.edited) { this.setState({ search: '', edited: false }); this.props.onSearchContacts(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.DEL_CHAR); } } handleSearchChange(e) { this.setState({ search: e.target.value }); } handleSearch(e) { e.preventDefault(); const query = this.state.search.trim(); this.setState({ edited: query.length > 0 }); this.props.onSearchContacts(query.length > 0 ? query : tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.DEL_CHAR); } handleClear(e) { e.preventDefault(); if (this.state.edited) { this.props.onSearchContacts(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.DEL_CHAR); } this.setState({ search: '', edited: false }); } handleKeyDown(e) { if (e.key === 'Enter') { this.handleSearch(e); } else if (e.key === 'Escape') { e.stopPropagation(); this.handleClear(e); } } render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons search", children: "search" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("input", { className: "search", type: "text", placeholder: this.props.placeholder, value: this.state.search, onChange: this.handleSearchChange, onKeyDown: this.handleKeyDown, required: true, autoFocus: true }, void 0, false), this.state.search ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("a", { href: "#", onClick: this.handleClear, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons", children: "highlight_off" }, void 0, false) }, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("span", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("i", { className: "material-icons", children: "\xA0" }, void 0, false) }, void 0, false)] }, void 0, true) }, void 0, false); } } ; /***/ }), /***/ "./src/widgets/side-navbar.jsx": /*!*************************************!*\ !*** ./src/widgets/side-navbar.jsx ***! \*************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ SideNavbar; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _button_back_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./button-back.jsx */ "./src/widgets/button-back.jsx"); /* harmony import */ var _contact_badges_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact-badges.jsx */ "./src/widgets/contact-badges.jsx"); /* harmony import */ var _menu_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./menu-contacts.jsx */ "./src/widgets/menu-contacts.jsx"); /* harmony import */ var _menu_start_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./menu-start.jsx */ "./src/widgets/menu-start.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class SideNavbar extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const icon_badges = []; if (this.props.trustedBadges) { this.props.trustedBadges.forEach(b => { icon_badges.push({ icon: b, color: 'badge-inv' }); }); } let avatar = null; if (this.props.tinode) { avatar = this.props.tinode.authorizeURL((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_6__.sanitizeUrlForMime)(this.props.avatar, 'image')); } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { id: "side-caption-panel", className: "caption-panel", children: [this.props.onCancel ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(_button_back_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { onBack: this.props.onCancel }, void 0, false) : null, avatar ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { id: "self-avatar", className: "avatar-box", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { authorizeURL: this.props.tinode.authorizeURL, avatar: avatar, topic: this.props.myUserId, title: this.props.title }, void 0, false) }, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", { id: "sidepanel-title", className: "panel-title", children: [this.props.title, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { badges: icon_badges }, void 0, false)] }, void 0, true), this.props.state === 'login' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(_menu_start_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { onSignUp: this.props.onSignUp, onSettings: this.props.onSettings }, void 0, false) : this.props.state === 'contacts' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(_menu_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { onNewTopic: this.props.onNewTopic, onSettings: this.props.onSettings }, void 0, false) : null] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/tag-manager.jsx": /*!*************************************!*\ !*** ./src/widgets/tag-manager.jsx ***! \*************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ TagManager; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _chip_input_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./chip-input.jsx */ "./src/widgets/chip-input.jsx"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class TagManager extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { tags: this.props.tags || [], alias: tinode_sdk__WEBPACK_IMPORTED_MODULE_3__.Tinode.tagByPrefix(this.props.tags, tinode_sdk__WEBPACK_IMPORTED_MODULE_3__.Tinode.TAG_ALIAS) || '', tagInput: '', activated: this.props.activated }; this.handleTagInput = this.handleTagInput.bind(this); this.handleAddTag = this.handleAddTag.bind(this); this.handleRemoveTag = this.handleRemoveTag.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); } static getDerivedStateFromProps(nextProps, prevState) { const tags = nextProps.tags || []; if (!(0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_5__.arrayEqual)(tags, prevState.tags) && !prevState.activated) { return { tags: tags || [], alias: tinode_sdk__WEBPACK_IMPORTED_MODULE_3__.Tinode.tagByPrefix(tags, tinode_sdk__WEBPACK_IMPORTED_MODULE_3__.Tinode.TAG_ALIAS) || '' }; } return null; } handleTagInput(text) { this.setState({ tagInput: text }); if (text.length > 0) { const last = text[text.length - 1]; if (text[0] == '"') { if (text.length > 1 && last == '"') { this.handleAddTag(text.substring(1, text.length - 1)); } } else if (last == ',' || last == ' ' || last == ';' || last == '"') { this.handleAddTag(text.substring(0, text.length - 1).trim()); } } } handleAddTag(tag) { const maxTagCount = this.props.tinode.getServerParam(tinode_sdk__WEBPACK_IMPORTED_MODULE_3__.Tinode.MAX_TAG_COUNT, _config_js__WEBPACK_IMPORTED_MODULE_4__.MAX_TAG_COUNT); if (tag.length > 0 && this.state.tags.length < maxTagCount) { const tags = this.state.tags.slice(0); tags.push(tag); this.setState({ tags: tags, tagInput: '' }); if (this.props.onTagsChanged) { this.props.onTagsChanged(tags); } return tags; } return this.state.tags; } handleRemoveTag(tag, index) { const tags = this.state.tags.slice(0); tags.splice(index, 1); this.setState({ tags: tags }); if (this.props.onTagsChanged) { this.props.onTagsChanged(tags); } } handleSubmit() { let tags = this.handleAddTag(this.state.tagInput.trim()); tags = tinode_sdk__WEBPACK_IMPORTED_MODULE_3__.Tinode.setUniqueTag(tags, this.state.alias); this.props.onSubmit(tags); this.setState({ activated: false, tags: this.props.tags || [] }); } handleCancel() { this.setState({ activated: false, tagInput: '', tags: this.props.tags || [] }); if (this.props.onCancel) { this.props.onCancel(); } } render() { const minTagLength = this.props.tinode.getServerParam(tinode_sdk__WEBPACK_IMPORTED_MODULE_3__.Tinode.MIN_TAG_LENGTH, _config_js__WEBPACK_IMPORTED_MODULE_4__.MIN_TAG_LENGTH); const maxTagLength = this.props.tinode.getServerParam(tinode_sdk__WEBPACK_IMPORTED_MODULE_3__.Tinode.MAX_TAG_LENGTH, _config_js__WEBPACK_IMPORTED_MODULE_4__.MAX_TAG_LENGTH); let tags = []; if (this.state.activated) { this.state.tags.forEach(tag => { if (tag != this.state.alias) { tags.push({ user: tag, invalid: tag.length < minTagLength || tag.length > maxTagLength }); } }); } else { this.state.tags.forEach(tag => { if (tag != this.state.alias) { tags.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", { className: "badge", children: tag }, tags.length, false)); } }); if (tags.length == 0) { tags = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tags_not_found", defaultMessage: "No tags defined. Add some.", description: "" }, void 0, false) }, void 0, false); } } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "panel-form-column", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "panel-form-row", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("label", { className: "small", children: this.props.title }, void 0, false) }, void 0, false), this.state.activated ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tags_editor_no_tags", defaultMessage: "Add some tags", description: "Tag editor prompt when no tags are found.", children: add_tags_prompt => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(_chip_input_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, chips: tags, avatarDisabled: true, prompt: add_tags_prompt, tabIndex: this.props.tabIndex, onEnter: this.handleAddTag, onFocusLost: this.handleAddTag, onCancel: this.handleCancel, onChipRemoved: this.handleRemoveTag, filterFunc: this.handleTagInput }, void 0, false) }, void 0, false), this.props.onSubmit || this.props.onCancel ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { id: "tag-manager-buttons", className: "dialog-buttons panel-form-row", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { className: "outline", onClick: this.handleCancel, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: "Cancel", description: "Button [Cancel]" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", { className: "primary", onClick: this.handleSubmit, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: "OK", description: "Button [OK]" }, void 0, false) }, void 0, false)] }, void 0, true) : null] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", { className: "quoted", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("a", { href: "#", className: "flat-button", onClick: e => { e.preventDefault(); this.setState({ activated: true }); }, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", { className: "material-icons", children: "edit" }, void 0, false), " \xA0", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_manage_tags", defaultMessage: "Manage", description: "Section title for the list of tags" }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.Fragment, { children: tags }, void 0, false)] }, void 0, true)] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/the-card-mini.jsx": /*!***************************************!*\ !*** ./src/widgets/the-card-mini.jsx ***! \***************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ unknown_name: { id: 'unknown_name', defaultMessage: 'Unknown', description: 'Name to show when the name is missing' } }); class TheCardMini extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleDownload = this.handleDownload.bind(this); this.handleMessage = this.handleMessage.bind(this); } handleDownload(e) { e.preventDefault(); try { const vcard = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.exportVCard(this.props.content); const blob = new Blob([vcard], { type: 'text/vcard' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.style.display = 'none'; a.href = url; a.download = (this.props.content.fn || 'contact') + '.vcf'; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } catch (err) { console.error("Failed to download vcard", err); if (this.props.onError) { this.props.onError("Failed to download vcard", 'err'); } } } handleMessage(e) {} render() { const card = this.props.content; if (!card) { return null; } const uid = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.getFirstTinodeID(card); const contacts = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.getEmails(card).concat(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.getPhones(card)); const org = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.getOrg(card); return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "contact-card", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "contact-body", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "avatar-box", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { authorizeURL: this.props.authorizeURL, topic: uid || 'usr123XXX', avatar: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.getPhotoUrl(card) || true, title: card.fn }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "name-box", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "name", children: card.fn || (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { ...messages.unknown_name }, void 0, false) }, void 0, false), org && (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "org", children: org }, void 0, false)] }, void 0, true)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "contact-actions", children: [uid ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("a", { className: "flat-button", "data-val": uid, onClick: this.props.onChatClick, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "chat_now", defaultMessage: "Chat", description: "Label for message button in contact card" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "divider" }, void 0, false)] }, void 0, true) : contacts.length > 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("a", { className: "flat-button", "data-val": contacts.join(','), onClick: this.props.onFindClick, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "find_user", defaultMessage: "Find", description: "Label for search button in contact card" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", { className: "divider" }, void 0, false)] }, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("a", { className: "flat-button", onClick: this.handleDownload, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "save_action", defaultMessage: "Save", description: "Label for Save button" }, void 0, false) }, void 0, false)] }, void 0, true)] }, void 0, true); } } ; /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(TheCardMini)); /***/ }), /***/ "./src/widgets/topic-desc-edit.jsx": /*!*****************************************!*\ !*** ./src/widgets/topic-desc-edit.jsx ***! \*****************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _avatar_crop_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./avatar-crop.jsx */ "./src/widgets/avatar-crop.jsx"); /* harmony import */ var _avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./in-place-edit.jsx */ "./src/widgets/in-place-edit.jsx"); /* harmony import */ var _tag_manager_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./tag-manager.jsx */ "./src/widgets/tag-manager.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ alias_invalid: { id: 'alias_invalid', defaultMessage: '(invalid)', description: 'Error message for invalid alias' }, alias_already_taken: { id: 'alias_already_taken', defaultMessage: '(already taken)', description: 'Error message for alias already taken' }, self_topic_name: { id: 'self_topic_name', defaultMessage: 'Saved messages', description: 'Name of self topic for UI' }, self_topic_comment: { id: 'self_topic_comment', defaultMessage: 'Notes, messages, links, files saved for posterity', description: 'Comment for self topic for UI' } }); const ALIAS_AVAILABILITY_CHECK_DELAY = 1000; class TopicDescEdit extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); const topic = this.props.tinode.getTopic(this.props.topic); const acs = topic.getAccessMode(); const isSelf = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isSelfTopicName(this.props.topic); this.state = { isMe: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isMeTopicName(this.props.topic), isSelf: isSelf, owner: acs && acs.isOwner(), fullName: topic.public ? topic.public.fn : isSelf ? this.props.intl.formatMessage(messages.self_topic_name) : null, private: topic.private ? topic.private.comment : null, description: topic.public ? topic.public.note : isSelf ? this.props.intl.formatMessage(messages.self_topic_comment) : null, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.makeImageUrl)(topic.public ? topic.public.photo : null), tags: topic.tags() || [], newAvatar: null, newAvatarMime: null, aliasError: '' }; this.previousOnTags = null; this.aliasCheckTimer = null; this.aliasCheckPromise = null; this.tnNewTags = this.tnNewTags.bind(this); this.handleFullNameUpdate = this.handleFullNameUpdate.bind(this); this.handleImageUpdated = this.handleImageUpdated.bind(this); this.handleAvatarCropped = this.handleAvatarCropped.bind(this); this.handleAvatarCropCancel = this.handleAvatarCropCancel.bind(this); this.uploadAvatar = this.uploadAvatar.bind(this); this.handlePrivateUpdate = this.handlePrivateUpdate.bind(this); this.handleAliasUpdate = this.handleAliasUpdate.bind(this); this.handleDescriptionUpdate = this.handleDescriptionUpdate.bind(this); this.handleTagsUpdated = this.handleTagsUpdated.bind(this); this.validateAlias = this.validateAlias.bind(this); this.cancelValidator = this.cancelValidator.bind(this); } componentDidMount() { const topic = this.props.tinode.getTopic(this.props.topic); this.previousOnTags = topic.onTagsUpdated; topic.onTagsUpdated = this.tnNewTags; } componentWillUnmount() { const topic = this.props.tinode.getTopic(this.props.topic); topic.onTagsUpdated = this.previousOnTags; this.cancelValidator(); } tnNewTags(tags) { this.setState({ tags: tags }); } handleFullNameUpdate(fn) { fn = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_10__.truncateString)(fn.trim(), _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_TITLE_LENGTH); if (fn && this.state.fullName !== fn) { this.setState({ fullName: fn }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_11__.theCard)(fn, null)); } } handlePrivateUpdate(comment) { comment = comment.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_TITLE_LENGTH); if (this.state.private !== comment) { this.setState({ private: comment }); this.props.onUpdateTopicDesc(this.props.topic, null, comment || tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.DEL_CHAR); } } handleDescriptionUpdate(desc) { desc = desc.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_TOPIC_DESCRIPTION_LENGTH); if (desc) { this.setState({ description: desc }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_11__.theCard)(null, null, null, desc)); } } handleImageUpdated(mime, img) { this.setState({ newAvatar: img, newAvatarMime: mime }); if (!img) { this.setState({ avatar: null }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_11__.theCard)(null, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.DEL_CHAR)); } } handleAvatarCropped(mime, blob, width, height) { const url = blob ? URL.createObjectURL(blob) : null; this.setState({ avatar: url, newAvatar: null, newAvatarMime: null }); if (blob) { this.uploadAvatar(mime, blob, width, height); } } uploadAvatar(mime, blob, width, height) { const readyToUpload = image => { let { mime, blob } = image; if (blob.size > _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_AVATAR_BYTES) { const uploader = (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_9__.createChatUploader)(this.props.tinode); uploader.upload(blob).then(url => this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_11__.theCard)(null, url))).catch(err => this.props.onError(err.message, 'err')); } else { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.blobToBase64)(blob).then(b64 => { const du = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.makeImageUrl)({ data: b64.bits, type: mime }); this.setState({ source: du }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_11__.theCard)(null, du)); }); } }; if (width > _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE || height > _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE || width != height) { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.imageScaled)(blob, _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE, _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_EXTERN_ATTACHMENT_SIZE, true).then(scaled => readyToUpload(scaled)).catch(err => this.props.onError(err.message, 'err')); } else { readyToUpload({ mime: mime, blob: blob, width: width, height: height }); } } handleAvatarCropCancel() { this.setState({ newAvatar: null, newAvatarMime: null }); } handleAliasUpdate(alias) { alias = (alias || '').trim(); const tags = alias ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.setUniqueTag(this.state.tags, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.TAG_ALIAS + alias.toLowerCase()) : tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.clearTagPrefix(this.state.tags, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.TAG_ALIAS); this.handleTagsUpdated(tags); } validateAlias(alias) { this.cancelValidator(); alias = alias.trim(); if (!alias) { this.setState({ aliasError: '' }); return true; } const valid = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isValidTagValue(alias); if (!valid) { this.setState({ aliasError: this.props.intl.formatMessage(messages.alias_invalid) }); return false; } this.setState({ aliasError: '' }); const fnd = this.props.tinode.getFndTopic(); if (!fnd) { this.setState({ aliasError: '' }); return true; } this.aliasCheckPromise = {}; const validationPromise = new Promise((resolve, reject) => { this.aliasCheckPromise.resolve = resolve; this.aliasCheckPromise.reject = reject; }); this.aliasCheckTimer = setTimeout(_ => { this.aliasCheckTimer = null; fnd.checkTagUniqueness(`${tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.TAG_ALIAS}${alias}`, this.props.topic).then(ok => { this.aliasCheckPromise.resolve(ok); this.setState({ aliasError: ok ? '' : this.props.intl.formatMessage(messages.alias_already_taken) }); }).catch(err => { this.aliasCheckPromise.reject(err); this.setState({ aliasError: err.message }); }); }, ALIAS_AVAILABILITY_CHECK_DELAY); return validationPromise; } cancelValidator() { if (this.aliasCheckTimer) { clearTimeout(this.aliasCheckTimer); this.aliasCheckTimer = null; this.aliasCheckPromise.reject(null); } } handleTagsUpdated(tags) { if ((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_11__.arrayEqual)(this.state.tags.slice(0), tags.slice(0))) { return; } this.props.onUpdateTags(tags); } render() { if (this.state.newAvatar) { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(_avatar_crop_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { avatar: this.state.newAvatar, mime: this.state.newAvatarMime, onSubmit: this.handleAvatarCropped, onCancel: this.handleAvatarCropCancel, onError: this.props.onError }, void 0, false); } const editable = this.state.isMe || this.state.owner && !this.state.isSelf; let alias = this.state.tags && this.state.tags.find(t => t.startsWith('alias:')); if (alias) { alias = alias.substring(6); } return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { className: "panel-form-column", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("center", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { tinode: this.props.tinode, avatar: this.state.avatar, readOnly: !editable, uid: this.props.topic, title: this.state.fullName, onImageUpdated: this.handleImageUpdated, onError: this.props.onError }, void 0, false) }, void 0, false), this.state.isMe ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { className: "group", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_your_name", defaultMessage: "Your name", description: "Label for full name editing" }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "full_name_prompt", defaultMessage: "Full name, e.g. John Doe", description: "Input placeholder for person's full name", children: full_name_placeholder => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: full_name_placeholder, value: this.state.fullName, required: true, onFinished: this.handleFullNameUpdate }, void 0, false) }, void 0, false) }, void 0, false)] }, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { className: "group", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_topic_name", defaultMessage: "Name", description: "Label for editing topic name" }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "topic_name_editing_placeholder", defaultMessage: "Freeform name of the group", description: "Prompt for entering topic name", children: group_name_placeholder => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: group_name_placeholder, readOnly: !editable, value: this.state.fullName, required: true, maxLength: 32, onFinished: this.handleFullNameUpdate }, void 0, false) }, void 0, false) }, void 0, false)] }, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { className: "group", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_private", defaultMessage: "Private comment", description: "Label for editing 'private'" }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "private_editing_placeholder", defaultMessage: "Visible to you only", description: "Placeholder for editing 'private'", children: private_placeholder => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: private_placeholder, value: this.state.private, onFinished: this.handlePrivateUpdate }, void 0, false) }, void 0, false) }, void 0, false)] }, void 0, true)] }, void 0, true), editable || alias ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { className: "group", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("label", { className: 'small ' + (this.state.aliasError ? 'invalid' : ''), children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_alias_edit", defaultMessage: "Alias", description: "Label for editing user or topic alias" }, void 0, false), " ", this.state.aliasError] }, void 0, true) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "alias_editing_placeholder", defaultMessage: "Alias (optional)", description: "Placeholder for editing user or topic alias", children: private_placeholder => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: private_placeholder, readOnly: !editable, value: alias, validator: this.validateAlias, iconLeft: "alternate_email", maxLength: 24, spellCheck: false, onFinished: this.handleAliasUpdate }, void 0, false) }, void 0, false) }, void 0, false)] }, void 0, true) : null, editable || this.state.description ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { className: "group", children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("label", { className: "small", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_description", defaultMessage: "Description", description: "Label for description of user or topic" }, void 0, false) }, void 0, false) }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "description_editing_placeholder", defaultMessage: "Description (optional)", description: "Placeholder for editing topic description", children: private_placeholder => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: private_placeholder, readOnly: !editable, value: this.state.description, multiline: 2, onFinished: this.handleDescriptionUpdate }, void 0, false) }, void 0, false) }, void 0, false)] }, void 0, true) : null] }, void 0, true), editable && !this.state.isMe ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.Fragment, { children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)("div", { className: "hr" }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_tag_manager", defaultMessage: "Tags (search & discovery)", description: "Section title for TagManager", children: title_tag_manager => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxDEV)(_tag_manager_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { tinode: this.props.tinode, title: title_tag_manager, activated: false, tags: this.state.tags, onSubmit: this.handleTagsUpdated }, void 0, false) }, void 0, false)] }, void 0, true) : null] }, void 0, true); } } ; /* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(TopicDescEdit)); /***/ }), /***/ "./src/widgets/unread-badge.jsx": /*!**************************************!*\ !*** ./src/widgets/unread-badge.jsx ***! \**************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ UnreadBadge; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class UnreadBadge extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return this.props.count > 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("span", { className: "unread", children: this.props.count > 9 ? "9+" : this.props.count }, void 0, false) : null; } } ; /***/ }), /***/ "./src/widgets/uploading-image.jsx": /*!*****************************************!*\ !*** ./src/widgets/uploading-image.jsx ***! \*****************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ UploadingImage; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _file_progress_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./file-progress.jsx */ "./src/widgets/file-progress.jsx"); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class UploadingImage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); } render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "inline-image", children: [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', this.props), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", { className: "rounded-container", children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(_file_progress_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { progress: this.props.progress, onCancel: this.props.onCancelUpload }, void 0, false) }, void 0, false)] }, void 0, true); } } ; /***/ }), /***/ "./src/widgets/visible-password.jsx": /*!******************************************!*\ !*** ./src/widgets/visible-password.jsx ***! \******************************************/ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ VisiblePassword; } /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js"); class VisiblePassword extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.inputRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.state = { value: this.props.value || '', visible: false }; this.handleVisibility = this.handleVisibility.bind(this); this.handeTextChange = this.handeTextChange.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); this.handleEditingFinished = this.handleEditingFinished.bind(this); } componentDidMount() { if (this.props.autoFocus) { this.inputRef.current.focus(); } } handeTextChange(e) { this.setState({ value: e.target.value }); if (this.props.onChange) { this.props.onChange(e); } } handleVisibility(e) { e.preventDefault(); this.setState({ visible: !this.state.visible }); } handleKeyDown(e) { if (e.keyCode == 27) { this.setState({ value: this.props.value || '', visible: false }); if (this.props.onFinished) { this.props.onFinished(); } } else if (e.keyCode == 13) { this.handleEditingFinished(); } } handleEditingFinished(e) { if (e) { let currentTarget = e.currentTarget; setTimeout(_ => { if (!currentTarget.contains(document.activeElement)) { if (this.props.onFinished) { this.props.onFinished(this.state.value); } } }, 0); } else if (this.props.onFinished) { this.props.onFinished(this.state.value.trim()); } } render() { return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", { tabIndex: "-1", className: "group-focus", onBlur: this.handleEditingFinished, children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("input", { className: "with-icon-right", type: this.state.visible ? 'text' : 'password', value: this.state.value, placeholder: this.props.placeholder, maxLength: 32, required: this.props.required ? 'required' : '', autoFocus: this.props.autoFocus ? 'autoFocus' : '', autoComplete: this.props.autoComplete, onChange: this.handeTextChange, onKeyDown: this.handleKeyDown, ref: this.inputRef }, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("span", { onClick: this.handleVisibility, children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("i", { className: "material-icons clickable light-gray", children: this.state.visible ? 'visibility' : 'visibility_off' }, void 0, false) }, void 0, false)] }, void 0, true); } } /***/ }), /***/ "./node_modules/jsqr/dist/jsQR.js": /*!****************************************!*\ !*** ./node_modules/jsqr/dist/jsQR.js ***! \****************************************/ /***/ (function(module) { (function webpackUniversalModuleDefinition(root, factory) { if(true) module.exports = factory(); else // removed by dead control flow {} })(typeof self !== 'undefined' ? self : this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __nested_webpack_require_568__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __nested_webpack_require_568__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __nested_webpack_require_568__.m = modules; /******/ /******/ // expose the module cache /******/ __nested_webpack_require_568__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __nested_webpack_require_568__.d = function(exports, name, getter) { /******/ if(!__nested_webpack_require_568__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __nested_webpack_require_568__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __nested_webpack_require_568__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __nested_webpack_require_568__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __nested_webpack_require_568__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __nested_webpack_require_568__(__nested_webpack_require_568__.s = 3); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var BitMatrix = /** @class */ (function () { function BitMatrix(data, width) { this.width = width; this.height = data.length / width; this.data = data; } BitMatrix.createEmpty = function (width, height) { return new BitMatrix(new Uint8ClampedArray(width * height), width); }; BitMatrix.prototype.get = function (x, y) { if (x < 0 || x >= this.width || y < 0 || y >= this.height) { return false; } return !!this.data[y * this.width + x]; }; BitMatrix.prototype.set = function (x, y, v) { this.data[y * this.width + x] = v ? 1 : 0; }; BitMatrix.prototype.setRegion = function (left, top, width, height, v) { for (var y = top; y < top + height; y++) { for (var x = left; x < left + width; x++) { this.set(x, y, !!v); } } }; return BitMatrix; }()); exports.BitMatrix = BitMatrix; /***/ }), /* 1 */ /***/ (function(module, exports, __nested_webpack_require_3952__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var GenericGFPoly_1 = __nested_webpack_require_3952__(2); function addOrSubtractGF(a, b) { return a ^ b; // tslint:disable-line:no-bitwise } exports.addOrSubtractGF = addOrSubtractGF; var GenericGF = /** @class */ (function () { function GenericGF(primitive, size, genBase) { this.primitive = primitive; this.size = size; this.generatorBase = genBase; this.expTable = new Array(this.size); this.logTable = new Array(this.size); var x = 1; for (var i = 0; i < this.size; i++) { this.expTable[i] = x; x = x * 2; if (x >= this.size) { x = (x ^ this.primitive) & (this.size - 1); // tslint:disable-line:no-bitwise } } for (var i = 0; i < this.size - 1; i++) { this.logTable[this.expTable[i]] = i; } this.zero = new GenericGFPoly_1.default(this, Uint8ClampedArray.from([0])); this.one = new GenericGFPoly_1.default(this, Uint8ClampedArray.from([1])); } GenericGF.prototype.multiply = function (a, b) { if (a === 0 || b === 0) { return 0; } return this.expTable[(this.logTable[a] + this.logTable[b]) % (this.size - 1)]; }; GenericGF.prototype.inverse = function (a) { if (a === 0) { throw new Error("Can't invert 0"); } return this.expTable[this.size - this.logTable[a] - 1]; }; GenericGF.prototype.buildMonomial = function (degree, coefficient) { if (degree < 0) { throw new Error("Invalid monomial degree less than 0"); } if (coefficient === 0) { return this.zero; } var coefficients = new Uint8ClampedArray(degree + 1); coefficients[0] = coefficient; return new GenericGFPoly_1.default(this, coefficients); }; GenericGF.prototype.log = function (a) { if (a === 0) { throw new Error("Can't take log(0)"); } return this.logTable[a]; }; GenericGF.prototype.exp = function (a) { return this.expTable[a]; }; return GenericGF; }()); exports.default = GenericGF; /***/ }), /* 2 */ /***/ (function(module, exports, __nested_webpack_require_6272__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var GenericGF_1 = __nested_webpack_require_6272__(1); var GenericGFPoly = /** @class */ (function () { function GenericGFPoly(field, coefficients) { if (coefficients.length === 0) { throw new Error("No coefficients."); } this.field = field; var coefficientsLength = coefficients.length; if (coefficientsLength > 1 && coefficients[0] === 0) { // Leading term must be non-zero for anything except the constant polynomial "0" var firstNonZero = 1; while (firstNonZero < coefficientsLength && coefficients[firstNonZero] === 0) { firstNonZero++; } if (firstNonZero === coefficientsLength) { this.coefficients = field.zero.coefficients; } else { this.coefficients = new Uint8ClampedArray(coefficientsLength - firstNonZero); for (var i = 0; i < this.coefficients.length; i++) { this.coefficients[i] = coefficients[firstNonZero + i]; } } } else { this.coefficients = coefficients; } } GenericGFPoly.prototype.degree = function () { return this.coefficients.length - 1; }; GenericGFPoly.prototype.isZero = function () { return this.coefficients[0] === 0; }; GenericGFPoly.prototype.getCoefficient = function (degree) { return this.coefficients[this.coefficients.length - 1 - degree]; }; GenericGFPoly.prototype.addOrSubtract = function (other) { var _a; if (this.isZero()) { return other; } if (other.isZero()) { return this; } var smallerCoefficients = this.coefficients; var largerCoefficients = other.coefficients; if (smallerCoefficients.length > largerCoefficients.length) { _a = [largerCoefficients, smallerCoefficients], smallerCoefficients = _a[0], largerCoefficients = _a[1]; } var sumDiff = new Uint8ClampedArray(largerCoefficients.length); var lengthDiff = largerCoefficients.length - smallerCoefficients.length; for (var i = 0; i < lengthDiff; i++) { sumDiff[i] = largerCoefficients[i]; } for (var i = lengthDiff; i < largerCoefficients.length; i++) { sumDiff[i] = GenericGF_1.addOrSubtractGF(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); } return new GenericGFPoly(this.field, sumDiff); }; GenericGFPoly.prototype.multiply = function (scalar) { if (scalar === 0) { return this.field.zero; } if (scalar === 1) { return this; } var size = this.coefficients.length; var product = new Uint8ClampedArray(size); for (var i = 0; i < size; i++) { product[i] = this.field.multiply(this.coefficients[i], scalar); } return new GenericGFPoly(this.field, product); }; GenericGFPoly.prototype.multiplyPoly = function (other) { if (this.isZero() || other.isZero()) { return this.field.zero; } var aCoefficients = this.coefficients; var aLength = aCoefficients.length; var bCoefficients = other.coefficients; var bLength = bCoefficients.length; var product = new Uint8ClampedArray(aLength + bLength - 1); for (var i = 0; i < aLength; i++) { var aCoeff = aCoefficients[i]; for (var j = 0; j < bLength; j++) { product[i + j] = GenericGF_1.addOrSubtractGF(product[i + j], this.field.multiply(aCoeff, bCoefficients[j])); } } return new GenericGFPoly(this.field, product); }; GenericGFPoly.prototype.multiplyByMonomial = function (degree, coefficient) { if (degree < 0) { throw new Error("Invalid degree less than 0"); } if (coefficient === 0) { return this.field.zero; } var size = this.coefficients.length; var product = new Uint8ClampedArray(size + degree); for (var i = 0; i < size; i++) { product[i] = this.field.multiply(this.coefficients[i], coefficient); } return new GenericGFPoly(this.field, product); }; GenericGFPoly.prototype.evaluateAt = function (a) { var result = 0; if (a === 0) { // Just return the x^0 coefficient return this.getCoefficient(0); } var size = this.coefficients.length; if (a === 1) { // Just the sum of the coefficients this.coefficients.forEach(function (coefficient) { result = GenericGF_1.addOrSubtractGF(result, coefficient); }); return result; } result = this.coefficients[0]; for (var i = 1; i < size; i++) { result = GenericGF_1.addOrSubtractGF(this.field.multiply(a, result), this.coefficients[i]); } return result; }; return GenericGFPoly; }()); exports.default = GenericGFPoly; /***/ }), /* 3 */ /***/ (function(module, exports, __nested_webpack_require_11547__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var binarizer_1 = __nested_webpack_require_11547__(4); var decoder_1 = __nested_webpack_require_11547__(5); var extractor_1 = __nested_webpack_require_11547__(11); var locator_1 = __nested_webpack_require_11547__(12); function scan(matrix) { var locations = locator_1.locate(matrix); if (!locations) { return null; } for (var _i = 0, locations_1 = locations; _i < locations_1.length; _i++) { var location_1 = locations_1[_i]; var extracted = extractor_1.extract(matrix, location_1); var decoded = decoder_1.decode(extracted.matrix); if (decoded) { return { binaryData: decoded.bytes, data: decoded.text, chunks: decoded.chunks, version: decoded.version, location: { topRightCorner: extracted.mappingFunction(location_1.dimension, 0), topLeftCorner: extracted.mappingFunction(0, 0), bottomRightCorner: extracted.mappingFunction(location_1.dimension, location_1.dimension), bottomLeftCorner: extracted.mappingFunction(0, location_1.dimension), topRightFinderPattern: location_1.topRight, topLeftFinderPattern: location_1.topLeft, bottomLeftFinderPattern: location_1.bottomLeft, bottomRightAlignmentPattern: location_1.alignmentPattern, }, }; } } return null; } var defaultOptions = { inversionAttempts: "attemptBoth", }; function jsQR(data, width, height, providedOptions) { if (providedOptions === void 0) { providedOptions = {}; } var options = defaultOptions; Object.keys(options || {}).forEach(function (opt) { options[opt] = providedOptions[opt] || options[opt]; }); var shouldInvert = options.inversionAttempts === "attemptBoth" || options.inversionAttempts === "invertFirst"; var tryInvertedFirst = options.inversionAttempts === "onlyInvert" || options.inversionAttempts === "invertFirst"; var _a = binarizer_1.binarize(data, width, height, shouldInvert), binarized = _a.binarized, inverted = _a.inverted; var result = scan(tryInvertedFirst ? inverted : binarized); if (!result && (options.inversionAttempts === "attemptBoth" || options.inversionAttempts === "invertFirst")) { result = scan(tryInvertedFirst ? binarized : inverted); } return result; } jsQR.default = jsQR; exports.default = jsQR; /***/ }), /* 4 */ /***/ (function(module, exports, __nested_webpack_require_14168__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var BitMatrix_1 = __nested_webpack_require_14168__(0); var REGION_SIZE = 8; var MIN_DYNAMIC_RANGE = 24; function numBetween(value, min, max) { return value < min ? min : value > max ? max : value; } // Like BitMatrix but accepts arbitry Uint8 values var Matrix = /** @class */ (function () { function Matrix(width, height) { this.width = width; this.data = new Uint8ClampedArray(width * height); } Matrix.prototype.get = function (x, y) { return this.data[y * this.width + x]; }; Matrix.prototype.set = function (x, y, value) { this.data[y * this.width + x] = value; }; return Matrix; }()); function binarize(data, width, height, returnInverted) { if (data.length !== width * height * 4) { throw new Error("Malformed data passed to binarizer."); } // Convert image to greyscale var greyscalePixels = new Matrix(width, height); for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { var r = data[((y * width + x) * 4) + 0]; var g = data[((y * width + x) * 4) + 1]; var b = data[((y * width + x) * 4) + 2]; greyscalePixels.set(x, y, 0.2126 * r + 0.7152 * g + 0.0722 * b); } } var horizontalRegionCount = Math.ceil(width / REGION_SIZE); var verticalRegionCount = Math.ceil(height / REGION_SIZE); var blackPoints = new Matrix(horizontalRegionCount, verticalRegionCount); for (var verticalRegion = 0; verticalRegion < verticalRegionCount; verticalRegion++) { for (var hortizontalRegion = 0; hortizontalRegion < horizontalRegionCount; hortizontalRegion++) { var sum = 0; var min = Infinity; var max = 0; for (var y = 0; y < REGION_SIZE; y++) { for (var x = 0; x < REGION_SIZE; x++) { var pixelLumosity = greyscalePixels.get(hortizontalRegion * REGION_SIZE + x, verticalRegion * REGION_SIZE + y); sum += pixelLumosity; min = Math.min(min, pixelLumosity); max = Math.max(max, pixelLumosity); } } var average = sum / (Math.pow(REGION_SIZE, 2)); if (max - min <= MIN_DYNAMIC_RANGE) { // If variation within the block is low, assume this is a block with only light or only // dark pixels. In that case we do not want to use the average, as it would divide this // low contrast area into black and white pixels, essentially creating data out of noise. // // Default the blackpoint for these blocks to be half the min - effectively white them out average = min / 2; if (verticalRegion > 0 && hortizontalRegion > 0) { // Correct the "white background" assumption for blocks that have neighbors by comparing // the pixels in this block to the previously calculated black points. This is based on // the fact that dark barcode symbology is always surrounded by some amount of light // background for which reasonable black point estimates were made. The bp estimated at // the boundaries is used for the interior. // The (min < bp) is arbitrary but works better than other heuristics that were tried. var averageNeighborBlackPoint = (blackPoints.get(hortizontalRegion, verticalRegion - 1) + (2 * blackPoints.get(hortizontalRegion - 1, verticalRegion)) + blackPoints.get(hortizontalRegion - 1, verticalRegion - 1)) / 4; if (min < averageNeighborBlackPoint) { average = averageNeighborBlackPoint; } } } blackPoints.set(hortizontalRegion, verticalRegion, average); } } var binarized = BitMatrix_1.BitMatrix.createEmpty(width, height); var inverted = null; if (returnInverted) { inverted = BitMatrix_1.BitMatrix.createEmpty(width, height); } for (var verticalRegion = 0; verticalRegion < verticalRegionCount; verticalRegion++) { for (var hortizontalRegion = 0; hortizontalRegion < horizontalRegionCount; hortizontalRegion++) { var left = numBetween(hortizontalRegion, 2, horizontalRegionCount - 3); var top_1 = numBetween(verticalRegion, 2, verticalRegionCount - 3); var sum = 0; for (var xRegion = -2; xRegion <= 2; xRegion++) { for (var yRegion = -2; yRegion <= 2; yRegion++) { sum += blackPoints.get(left + xRegion, top_1 + yRegion); } } var threshold = sum / 25; for (var xRegion = 0; xRegion < REGION_SIZE; xRegion++) { for (var yRegion = 0; yRegion < REGION_SIZE; yRegion++) { var x = hortizontalRegion * REGION_SIZE + xRegion; var y = verticalRegion * REGION_SIZE + yRegion; var lum = greyscalePixels.get(x, y); binarized.set(x, y, lum <= threshold); if (returnInverted) { inverted.set(x, y, !(lum <= threshold)); } } } } } if (returnInverted) { return { binarized: binarized, inverted: inverted }; } return { binarized: binarized }; } exports.binarize = binarize; /***/ }), /* 5 */ /***/ (function(module, exports, __nested_webpack_require_19864__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var BitMatrix_1 = __nested_webpack_require_19864__(0); var decodeData_1 = __nested_webpack_require_19864__(6); var reedsolomon_1 = __nested_webpack_require_19864__(9); var version_1 = __nested_webpack_require_19864__(10); // tslint:disable:no-bitwise function numBitsDiffering(x, y) { var z = x ^ y; var bitCount = 0; while (z) { bitCount++; z &= z - 1; } return bitCount; } function pushBit(bit, byte) { return (byte << 1) | bit; } // tslint:enable:no-bitwise var FORMAT_INFO_TABLE = [ { bits: 0x5412, formatInfo: { errorCorrectionLevel: 1, dataMask: 0 } }, { bits: 0x5125, formatInfo: { errorCorrectionLevel: 1, dataMask: 1 } }, { bits: 0x5E7C, formatInfo: { errorCorrectionLevel: 1, dataMask: 2 } }, { bits: 0x5B4B, formatInfo: { errorCorrectionLevel: 1, dataMask: 3 } }, { bits: 0x45F9, formatInfo: { errorCorrectionLevel: 1, dataMask: 4 } }, { bits: 0x40CE, formatInfo: { errorCorrectionLevel: 1, dataMask: 5 } }, { bits: 0x4F97, formatInfo: { errorCorrectionLevel: 1, dataMask: 6 } }, { bits: 0x4AA0, formatInfo: { errorCorrectionLevel: 1, dataMask: 7 } }, { bits: 0x77C4, formatInfo: { errorCorrectionLevel: 0, dataMask: 0 } }, { bits: 0x72F3, formatInfo: { errorCorrectionLevel: 0, dataMask: 1 } }, { bits: 0x7DAA, formatInfo: { errorCorrectionLevel: 0, dataMask: 2 } }, { bits: 0x789D, formatInfo: { errorCorrectionLevel: 0, dataMask: 3 } }, { bits: 0x662F, formatInfo: { errorCorrectionLevel: 0, dataMask: 4 } }, { bits: 0x6318, formatInfo: { errorCorrectionLevel: 0, dataMask: 5 } }, { bits: 0x6C41, formatInfo: { errorCorrectionLevel: 0, dataMask: 6 } }, { bits: 0x6976, formatInfo: { errorCorrectionLevel: 0, dataMask: 7 } }, { bits: 0x1689, formatInfo: { errorCorrectionLevel: 3, dataMask: 0 } }, { bits: 0x13BE, formatInfo: { errorCorrectionLevel: 3, dataMask: 1 } }, { bits: 0x1CE7, formatInfo: { errorCorrectionLevel: 3, dataMask: 2 } }, { bits: 0x19D0, formatInfo: { errorCorrectionLevel: 3, dataMask: 3 } }, { bits: 0x0762, formatInfo: { errorCorrectionLevel: 3, dataMask: 4 } }, { bits: 0x0255, formatInfo: { errorCorrectionLevel: 3, dataMask: 5 } }, { bits: 0x0D0C, formatInfo: { errorCorrectionLevel: 3, dataMask: 6 } }, { bits: 0x083B, formatInfo: { errorCorrectionLevel: 3, dataMask: 7 } }, { bits: 0x355F, formatInfo: { errorCorrectionLevel: 2, dataMask: 0 } }, { bits: 0x3068, formatInfo: { errorCorrectionLevel: 2, dataMask: 1 } }, { bits: 0x3F31, formatInfo: { errorCorrectionLevel: 2, dataMask: 2 } }, { bits: 0x3A06, formatInfo: { errorCorrectionLevel: 2, dataMask: 3 } }, { bits: 0x24B4, formatInfo: { errorCorrectionLevel: 2, dataMask: 4 } }, { bits: 0x2183, formatInfo: { errorCorrectionLevel: 2, dataMask: 5 } }, { bits: 0x2EDA, formatInfo: { errorCorrectionLevel: 2, dataMask: 6 } }, { bits: 0x2BED, formatInfo: { errorCorrectionLevel: 2, dataMask: 7 } }, ]; var DATA_MASKS = [ function (p) { return ((p.y + p.x) % 2) === 0; }, function (p) { return (p.y % 2) === 0; }, function (p) { return p.x % 3 === 0; }, function (p) { return (p.y + p.x) % 3 === 0; }, function (p) { return (Math.floor(p.y / 2) + Math.floor(p.x / 3)) % 2 === 0; }, function (p) { return ((p.x * p.y) % 2) + ((p.x * p.y) % 3) === 0; }, function (p) { return ((((p.y * p.x) % 2) + (p.y * p.x) % 3) % 2) === 0; }, function (p) { return ((((p.y + p.x) % 2) + (p.y * p.x) % 3) % 2) === 0; }, ]; function buildFunctionPatternMask(version) { var dimension = 17 + 4 * version.versionNumber; var matrix = BitMatrix_1.BitMatrix.createEmpty(dimension, dimension); matrix.setRegion(0, 0, 9, 9, true); // Top left finder pattern + separator + format matrix.setRegion(dimension - 8, 0, 8, 9, true); // Top right finder pattern + separator + format matrix.setRegion(0, dimension - 8, 9, 8, true); // Bottom left finder pattern + separator + format // Alignment patterns for (var _i = 0, _a = version.alignmentPatternCenters; _i < _a.length; _i++) { var x = _a[_i]; for (var _b = 0, _c = version.alignmentPatternCenters; _b < _c.length; _b++) { var y = _c[_b]; if (!(x === 6 && y === 6 || x === 6 && y === dimension - 7 || x === dimension - 7 && y === 6)) { matrix.setRegion(x - 2, y - 2, 5, 5, true); } } } matrix.setRegion(6, 9, 1, dimension - 17, true); // Vertical timing pattern matrix.setRegion(9, 6, dimension - 17, 1, true); // Horizontal timing pattern if (version.versionNumber > 6) { matrix.setRegion(dimension - 11, 0, 3, 6, true); // Version info, top right matrix.setRegion(0, dimension - 11, 6, 3, true); // Version info, bottom left } return matrix; } function readCodewords(matrix, version, formatInfo) { var dataMask = DATA_MASKS[formatInfo.dataMask]; var dimension = matrix.height; var functionPatternMask = buildFunctionPatternMask(version); var codewords = []; var currentByte = 0; var bitsRead = 0; // Read columns in pairs, from right to left var readingUp = true; for (var columnIndex = dimension - 1; columnIndex > 0; columnIndex -= 2) { if (columnIndex === 6) { // Skip whole column with vertical alignment pattern; columnIndex--; } for (var i = 0; i < dimension; i++) { var y = readingUp ? dimension - 1 - i : i; for (var columnOffset = 0; columnOffset < 2; columnOffset++) { var x = columnIndex - columnOffset; if (!functionPatternMask.get(x, y)) { bitsRead++; var bit = matrix.get(x, y); if (dataMask({ y: y, x: x })) { bit = !bit; } currentByte = pushBit(bit, currentByte); if (bitsRead === 8) { // Whole bytes codewords.push(currentByte); bitsRead = 0; currentByte = 0; } } } } readingUp = !readingUp; } return codewords; } function readVersion(matrix) { var dimension = matrix.height; var provisionalVersion = Math.floor((dimension - 17) / 4); if (provisionalVersion <= 6) { // 6 and under dont have version info in the QR code return version_1.VERSIONS[provisionalVersion - 1]; } var topRightVersionBits = 0; for (var y = 5; y >= 0; y--) { for (var x = dimension - 9; x >= dimension - 11; x--) { topRightVersionBits = pushBit(matrix.get(x, y), topRightVersionBits); } } var bottomLeftVersionBits = 0; for (var x = 5; x >= 0; x--) { for (var y = dimension - 9; y >= dimension - 11; y--) { bottomLeftVersionBits = pushBit(matrix.get(x, y), bottomLeftVersionBits); } } var bestDifference = Infinity; var bestVersion; for (var _i = 0, VERSIONS_1 = version_1.VERSIONS; _i < VERSIONS_1.length; _i++) { var version = VERSIONS_1[_i]; if (version.infoBits === topRightVersionBits || version.infoBits === bottomLeftVersionBits) { return version; } var difference = numBitsDiffering(topRightVersionBits, version.infoBits); if (difference < bestDifference) { bestVersion = version; bestDifference = difference; } difference = numBitsDiffering(bottomLeftVersionBits, version.infoBits); if (difference < bestDifference) { bestVersion = version; bestDifference = difference; } } // We can tolerate up to 3 bits of error since no two version info codewords will // differ in less than 8 bits. if (bestDifference <= 3) { return bestVersion; } } function readFormatInformation(matrix) { var topLeftFormatInfoBits = 0; for (var x = 0; x <= 8; x++) { if (x !== 6) { // Skip timing pattern bit topLeftFormatInfoBits = pushBit(matrix.get(x, 8), topLeftFormatInfoBits); } } for (var y = 7; y >= 0; y--) { if (y !== 6) { // Skip timing pattern bit topLeftFormatInfoBits = pushBit(matrix.get(8, y), topLeftFormatInfoBits); } } var dimension = matrix.height; var topRightBottomRightFormatInfoBits = 0; for (var y = dimension - 1; y >= dimension - 7; y--) { // bottom left topRightBottomRightFormatInfoBits = pushBit(matrix.get(8, y), topRightBottomRightFormatInfoBits); } for (var x = dimension - 8; x < dimension; x++) { // top right topRightBottomRightFormatInfoBits = pushBit(matrix.get(x, 8), topRightBottomRightFormatInfoBits); } var bestDifference = Infinity; var bestFormatInfo = null; for (var _i = 0, FORMAT_INFO_TABLE_1 = FORMAT_INFO_TABLE; _i < FORMAT_INFO_TABLE_1.length; _i++) { var _a = FORMAT_INFO_TABLE_1[_i], bits = _a.bits, formatInfo = _a.formatInfo; if (bits === topLeftFormatInfoBits || bits === topRightBottomRightFormatInfoBits) { return formatInfo; } var difference = numBitsDiffering(topLeftFormatInfoBits, bits); if (difference < bestDifference) { bestFormatInfo = formatInfo; bestDifference = difference; } if (topLeftFormatInfoBits !== topRightBottomRightFormatInfoBits) { // also try the other option difference = numBitsDiffering(topRightBottomRightFormatInfoBits, bits); if (difference < bestDifference) { bestFormatInfo = formatInfo; bestDifference = difference; } } } // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits differing means we found a match if (bestDifference <= 3) { return bestFormatInfo; } return null; } function getDataBlocks(codewords, version, ecLevel) { var ecInfo = version.errorCorrectionLevels[ecLevel]; var dataBlocks = []; var totalCodewords = 0; ecInfo.ecBlocks.forEach(function (block) { for (var i = 0; i < block.numBlocks; i++) { dataBlocks.push({ numDataCodewords: block.dataCodewordsPerBlock, codewords: [] }); totalCodewords += block.dataCodewordsPerBlock + ecInfo.ecCodewordsPerBlock; } }); // In some cases the QR code will be malformed enough that we pull off more or less than we should. // If we pull off less there's nothing we can do. // If we pull off more we can safely truncate if (codewords.length < totalCodewords) { return null; } codewords = codewords.slice(0, totalCodewords); var shortBlockSize = ecInfo.ecBlocks[0].dataCodewordsPerBlock; // Pull codewords to fill the blocks up to the minimum size for (var i = 0; i < shortBlockSize; i++) { for (var _i = 0, dataBlocks_1 = dataBlocks; _i < dataBlocks_1.length; _i++) { var dataBlock = dataBlocks_1[_i]; dataBlock.codewords.push(codewords.shift()); } } // If there are any large blocks, pull codewords to fill the last element of those if (ecInfo.ecBlocks.length > 1) { var smallBlockCount = ecInfo.ecBlocks[0].numBlocks; var largeBlockCount = ecInfo.ecBlocks[1].numBlocks; for (var i = 0; i < largeBlockCount; i++) { dataBlocks[smallBlockCount + i].codewords.push(codewords.shift()); } } // Add the rest of the codewords to the blocks. These are the error correction codewords. while (codewords.length > 0) { for (var _a = 0, dataBlocks_2 = dataBlocks; _a < dataBlocks_2.length; _a++) { var dataBlock = dataBlocks_2[_a]; dataBlock.codewords.push(codewords.shift()); } } return dataBlocks; } function decodeMatrix(matrix) { var version = readVersion(matrix); if (!version) { return null; } var formatInfo = readFormatInformation(matrix); if (!formatInfo) { return null; } var codewords = readCodewords(matrix, version, formatInfo); var dataBlocks = getDataBlocks(codewords, version, formatInfo.errorCorrectionLevel); if (!dataBlocks) { return null; } // Count total number of data bytes var totalBytes = dataBlocks.reduce(function (a, b) { return a + b.numDataCodewords; }, 0); var resultBytes = new Uint8ClampedArray(totalBytes); var resultIndex = 0; for (var _i = 0, dataBlocks_3 = dataBlocks; _i < dataBlocks_3.length; _i++) { var dataBlock = dataBlocks_3[_i]; var correctedBytes = reedsolomon_1.decode(dataBlock.codewords, dataBlock.codewords.length - dataBlock.numDataCodewords); if (!correctedBytes) { return null; } for (var i = 0; i < dataBlock.numDataCodewords; i++) { resultBytes[resultIndex++] = correctedBytes[i]; } } try { return decodeData_1.decode(resultBytes, version.versionNumber); } catch (_a) { return null; } } function decode(matrix) { if (matrix == null) { return null; } var result = decodeMatrix(matrix); if (result) { return result; } // Decoding didn't work, try mirroring the QR across the topLeft -> bottomRight line. for (var x = 0; x < matrix.width; x++) { for (var y = x + 1; y < matrix.height; y++) { if (matrix.get(x, y) !== matrix.get(y, x)) { matrix.set(x, y, !matrix.get(x, y)); matrix.set(y, x, !matrix.get(y, x)); } } } return decodeMatrix(matrix); } exports.decode = decode; /***/ }), /* 6 */ /***/ (function(module, exports, __nested_webpack_require_33675__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // tslint:disable:no-bitwise var BitStream_1 = __nested_webpack_require_33675__(7); var shiftJISTable_1 = __nested_webpack_require_33675__(8); var Mode; (function (Mode) { Mode["Numeric"] = "numeric"; Mode["Alphanumeric"] = "alphanumeric"; Mode["Byte"] = "byte"; Mode["Kanji"] = "kanji"; Mode["ECI"] = "eci"; })(Mode = exports.Mode || (exports.Mode = {})); var ModeByte; (function (ModeByte) { ModeByte[ModeByte["Terminator"] = 0] = "Terminator"; ModeByte[ModeByte["Numeric"] = 1] = "Numeric"; ModeByte[ModeByte["Alphanumeric"] = 2] = "Alphanumeric"; ModeByte[ModeByte["Byte"] = 4] = "Byte"; ModeByte[ModeByte["Kanji"] = 8] = "Kanji"; ModeByte[ModeByte["ECI"] = 7] = "ECI"; // StructuredAppend = 0x3, // FNC1FirstPosition = 0x5, // FNC1SecondPosition = 0x9, })(ModeByte || (ModeByte = {})); function decodeNumeric(stream, size) { var bytes = []; var text = ""; var characterCountSize = [10, 12, 14][size]; var length = stream.readBits(characterCountSize); // Read digits in groups of 3 while (length >= 3) { var num = stream.readBits(10); if (num >= 1000) { throw new Error("Invalid numeric value above 999"); } var a = Math.floor(num / 100); var b = Math.floor(num / 10) % 10; var c = num % 10; bytes.push(48 + a, 48 + b, 48 + c); text += a.toString() + b.toString() + c.toString(); length -= 3; } // If the number of digits aren't a multiple of 3, the remaining digits are special cased. if (length === 2) { var num = stream.readBits(7); if (num >= 100) { throw new Error("Invalid numeric value above 99"); } var a = Math.floor(num / 10); var b = num % 10; bytes.push(48 + a, 48 + b); text += a.toString() + b.toString(); } else if (length === 1) { var num = stream.readBits(4); if (num >= 10) { throw new Error("Invalid numeric value above 9"); } bytes.push(48 + num); text += num.toString(); } return { bytes: bytes, text: text }; } var AlphanumericCharacterCodes = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", " ", "$", "%", "*", "+", "-", ".", "/", ":", ]; function decodeAlphanumeric(stream, size) { var bytes = []; var text = ""; var characterCountSize = [9, 11, 13][size]; var length = stream.readBits(characterCountSize); while (length >= 2) { var v = stream.readBits(11); var a = Math.floor(v / 45); var b = v % 45; bytes.push(AlphanumericCharacterCodes[a].charCodeAt(0), AlphanumericCharacterCodes[b].charCodeAt(0)); text += AlphanumericCharacterCodes[a] + AlphanumericCharacterCodes[b]; length -= 2; } if (length === 1) { var a = stream.readBits(6); bytes.push(AlphanumericCharacterCodes[a].charCodeAt(0)); text += AlphanumericCharacterCodes[a]; } return { bytes: bytes, text: text }; } function decodeByte(stream, size) { var bytes = []; var text = ""; var characterCountSize = [8, 16, 16][size]; var length = stream.readBits(characterCountSize); for (var i = 0; i < length; i++) { var b = stream.readBits(8); bytes.push(b); } try { text += decodeURIComponent(bytes.map(function (b) { return "%" + ("0" + b.toString(16)).substr(-2); }).join("")); } catch (_a) { // failed to decode } return { bytes: bytes, text: text }; } function decodeKanji(stream, size) { var bytes = []; var text = ""; var characterCountSize = [8, 10, 12][size]; var length = stream.readBits(characterCountSize); for (var i = 0; i < length; i++) { var k = stream.readBits(13); var c = (Math.floor(k / 0xC0) << 8) | (k % 0xC0); if (c < 0x1F00) { c += 0x8140; } else { c += 0xC140; } bytes.push(c >> 8, c & 0xFF); text += String.fromCharCode(shiftJISTable_1.shiftJISTable[c]); } return { bytes: bytes, text: text }; } function decode(data, version) { var _a, _b, _c, _d; var stream = new BitStream_1.BitStream(data); // There are 3 'sizes' based on the version. 1-9 is small (0), 10-26 is medium (1) and 27-40 is large (2). var size = version <= 9 ? 0 : version <= 26 ? 1 : 2; var result = { text: "", bytes: [], chunks: [], version: version, }; while (stream.available() >= 4) { var mode = stream.readBits(4); if (mode === ModeByte.Terminator) { return result; } else if (mode === ModeByte.ECI) { if (stream.readBits(1) === 0) { result.chunks.push({ type: Mode.ECI, assignmentNumber: stream.readBits(7), }); } else if (stream.readBits(1) === 0) { result.chunks.push({ type: Mode.ECI, assignmentNumber: stream.readBits(14), }); } else if (stream.readBits(1) === 0) { result.chunks.push({ type: Mode.ECI, assignmentNumber: stream.readBits(21), }); } else { // ECI data seems corrupted result.chunks.push({ type: Mode.ECI, assignmentNumber: -1, }); } } else if (mode === ModeByte.Numeric) { var numericResult = decodeNumeric(stream, size); result.text += numericResult.text; (_a = result.bytes).push.apply(_a, numericResult.bytes); result.chunks.push({ type: Mode.Numeric, text: numericResult.text, }); } else if (mode === ModeByte.Alphanumeric) { var alphanumericResult = decodeAlphanumeric(stream, size); result.text += alphanumericResult.text; (_b = result.bytes).push.apply(_b, alphanumericResult.bytes); result.chunks.push({ type: Mode.Alphanumeric, text: alphanumericResult.text, }); } else if (mode === ModeByte.Byte) { var byteResult = decodeByte(stream, size); result.text += byteResult.text; (_c = result.bytes).push.apply(_c, byteResult.bytes); result.chunks.push({ type: Mode.Byte, bytes: byteResult.bytes, text: byteResult.text, }); } else if (mode === ModeByte.Kanji) { var kanjiResult = decodeKanji(stream, size); result.text += kanjiResult.text; (_d = result.bytes).push.apply(_d, kanjiResult.bytes); result.chunks.push({ type: Mode.Kanji, bytes: kanjiResult.bytes, text: kanjiResult.text, }); } } // If there is no data left, or the remaining bits are all 0, then that counts as a termination marker if (stream.available() === 0 || stream.readBits(stream.available()) === 0) { return result; } } exports.decode = decode; /***/ }), /* 7 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; // tslint:disable:no-bitwise Object.defineProperty(exports, "__esModule", { value: true }); var BitStream = /** @class */ (function () { function BitStream(bytes) { this.byteOffset = 0; this.bitOffset = 0; this.bytes = bytes; } BitStream.prototype.readBits = function (numBits) { if (numBits < 1 || numBits > 32 || numBits > this.available()) { throw new Error("Cannot read " + numBits.toString() + " bits"); } var result = 0; // First, read remainder from current byte if (this.bitOffset > 0) { var bitsLeft = 8 - this.bitOffset; var toRead = numBits < bitsLeft ? numBits : bitsLeft; var bitsToNotRead = bitsLeft - toRead; var mask = (0xFF >> (8 - toRead)) << bitsToNotRead; result = (this.bytes[this.byteOffset] & mask) >> bitsToNotRead; numBits -= toRead; this.bitOffset += toRead; if (this.bitOffset === 8) { this.bitOffset = 0; this.byteOffset++; } } // Next read whole bytes if (numBits > 0) { while (numBits >= 8) { result = (result << 8) | (this.bytes[this.byteOffset] & 0xFF); this.byteOffset++; numBits -= 8; } // Finally read a partial byte if (numBits > 0) { var bitsToNotRead = 8 - numBits; var mask = (0xFF >> bitsToNotRead) << bitsToNotRead; result = (result << numBits) | ((this.bytes[this.byteOffset] & mask) >> bitsToNotRead); this.bitOffset += numBits; } } return result; }; BitStream.prototype.available = function () { return 8 * (this.bytes.length - this.byteOffset) - this.bitOffset; }; return BitStream; }()); exports.BitStream = BitStream; /***/ }), /* 8 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.shiftJISTable = { 0x20: 0x0020, 0x21: 0x0021, 0x22: 0x0022, 0x23: 0x0023, 0x24: 0x0024, 0x25: 0x0025, 0x26: 0x0026, 0x27: 0x0027, 0x28: 0x0028, 0x29: 0x0029, 0x2A: 0x002A, 0x2B: 0x002B, 0x2C: 0x002C, 0x2D: 0x002D, 0x2E: 0x002E, 0x2F: 0x002F, 0x30: 0x0030, 0x31: 0x0031, 0x32: 0x0032, 0x33: 0x0033, 0x34: 0x0034, 0x35: 0x0035, 0x36: 0x0036, 0x37: 0x0037, 0x38: 0x0038, 0x39: 0x0039, 0x3A: 0x003A, 0x3B: 0x003B, 0x3C: 0x003C, 0x3D: 0x003D, 0x3E: 0x003E, 0x3F: 0x003F, 0x40: 0x0040, 0x41: 0x0041, 0x42: 0x0042, 0x43: 0x0043, 0x44: 0x0044, 0x45: 0x0045, 0x46: 0x0046, 0x47: 0x0047, 0x48: 0x0048, 0x49: 0x0049, 0x4A: 0x004A, 0x4B: 0x004B, 0x4C: 0x004C, 0x4D: 0x004D, 0x4E: 0x004E, 0x4F: 0x004F, 0x50: 0x0050, 0x51: 0x0051, 0x52: 0x0052, 0x53: 0x0053, 0x54: 0x0054, 0x55: 0x0055, 0x56: 0x0056, 0x57: 0x0057, 0x58: 0x0058, 0x59: 0x0059, 0x5A: 0x005A, 0x5B: 0x005B, 0x5C: 0x00A5, 0x5D: 0x005D, 0x5E: 0x005E, 0x5F: 0x005F, 0x60: 0x0060, 0x61: 0x0061, 0x62: 0x0062, 0x63: 0x0063, 0x64: 0x0064, 0x65: 0x0065, 0x66: 0x0066, 0x67: 0x0067, 0x68: 0x0068, 0x69: 0x0069, 0x6A: 0x006A, 0x6B: 0x006B, 0x6C: 0x006C, 0x6D: 0x006D, 0x6E: 0x006E, 0x6F: 0x006F, 0x70: 0x0070, 0x71: 0x0071, 0x72: 0x0072, 0x73: 0x0073, 0x74: 0x0074, 0x75: 0x0075, 0x76: 0x0076, 0x77: 0x0077, 0x78: 0x0078, 0x79: 0x0079, 0x7A: 0x007A, 0x7B: 0x007B, 0x7C: 0x007C, 0x7D: 0x007D, 0x7E: 0x203E, 0x8140: 0x3000, 0x8141: 0x3001, 0x8142: 0x3002, 0x8143: 0xFF0C, 0x8144: 0xFF0E, 0x8145: 0x30FB, 0x8146: 0xFF1A, 0x8147: 0xFF1B, 0x8148: 0xFF1F, 0x8149: 0xFF01, 0x814A: 0x309B, 0x814B: 0x309C, 0x814C: 0x00B4, 0x814D: 0xFF40, 0x814E: 0x00A8, 0x814F: 0xFF3E, 0x8150: 0xFFE3, 0x8151: 0xFF3F, 0x8152: 0x30FD, 0x8153: 0x30FE, 0x8154: 0x309D, 0x8155: 0x309E, 0x8156: 0x3003, 0x8157: 0x4EDD, 0x8158: 0x3005, 0x8159: 0x3006, 0x815A: 0x3007, 0x815B: 0x30FC, 0x815C: 0x2015, 0x815D: 0x2010, 0x815E: 0xFF0F, 0x815F: 0x005C, 0x8160: 0x301C, 0x8161: 0x2016, 0x8162: 0xFF5C, 0x8163: 0x2026, 0x8164: 0x2025, 0x8165: 0x2018, 0x8166: 0x2019, 0x8167: 0x201C, 0x8168: 0x201D, 0x8169: 0xFF08, 0x816A: 0xFF09, 0x816B: 0x3014, 0x816C: 0x3015, 0x816D: 0xFF3B, 0x816E: 0xFF3D, 0x816F: 0xFF5B, 0x8170: 0xFF5D, 0x8171: 0x3008, 0x8172: 0x3009, 0x8173: 0x300A, 0x8174: 0x300B, 0x8175: 0x300C, 0x8176: 0x300D, 0x8177: 0x300E, 0x8178: 0x300F, 0x8179: 0x3010, 0x817A: 0x3011, 0x817B: 0xFF0B, 0x817C: 0x2212, 0x817D: 0x00B1, 0x817E: 0x00D7, 0x8180: 0x00F7, 0x8181: 0xFF1D, 0x8182: 0x2260, 0x8183: 0xFF1C, 0x8184: 0xFF1E, 0x8185: 0x2266, 0x8186: 0x2267, 0x8187: 0x221E, 0x8188: 0x2234, 0x8189: 0x2642, 0x818A: 0x2640, 0x818B: 0x00B0, 0x818C: 0x2032, 0x818D: 0x2033, 0x818E: 0x2103, 0x818F: 0xFFE5, 0x8190: 0xFF04, 0x8191: 0x00A2, 0x8192: 0x00A3, 0x8193: 0xFF05, 0x8194: 0xFF03, 0x8195: 0xFF06, 0x8196: 0xFF0A, 0x8197: 0xFF20, 0x8198: 0x00A7, 0x8199: 0x2606, 0x819A: 0x2605, 0x819B: 0x25CB, 0x819C: 0x25CF, 0x819D: 0x25CE, 0x819E: 0x25C7, 0x819F: 0x25C6, 0x81A0: 0x25A1, 0x81A1: 0x25A0, 0x81A2: 0x25B3, 0x81A3: 0x25B2, 0x81A4: 0x25BD, 0x81A5: 0x25BC, 0x81A6: 0x203B, 0x81A7: 0x3012, 0x81A8: 0x2192, 0x81A9: 0x2190, 0x81AA: 0x2191, 0x81AB: 0x2193, 0x81AC: 0x3013, 0x81B8: 0x2208, 0x81B9: 0x220B, 0x81BA: 0x2286, 0x81BB: 0x2287, 0x81BC: 0x2282, 0x81BD: 0x2283, 0x81BE: 0x222A, 0x81BF: 0x2229, 0x81C8: 0x2227, 0x81C9: 0x2228, 0x81CA: 0x00AC, 0x81CB: 0x21D2, 0x81CC: 0x21D4, 0x81CD: 0x2200, 0x81CE: 0x2203, 0x81DA: 0x2220, 0x81DB: 0x22A5, 0x81DC: 0x2312, 0x81DD: 0x2202, 0x81DE: 0x2207, 0x81DF: 0x2261, 0x81E0: 0x2252, 0x81E1: 0x226A, 0x81E2: 0x226B, 0x81E3: 0x221A, 0x81E4: 0x223D, 0x81E5: 0x221D, 0x81E6: 0x2235, 0x81E7: 0x222B, 0x81E8: 0x222C, 0x81F0: 0x212B, 0x81F1: 0x2030, 0x81F2: 0x266F, 0x81F3: 0x266D, 0x81F4: 0x266A, 0x81F5: 0x2020, 0x81F6: 0x2021, 0x81F7: 0x00B6, 0x81FC: 0x25EF, 0x824F: 0xFF10, 0x8250: 0xFF11, 0x8251: 0xFF12, 0x8252: 0xFF13, 0x8253: 0xFF14, 0x8254: 0xFF15, 0x8255: 0xFF16, 0x8256: 0xFF17, 0x8257: 0xFF18, 0x8258: 0xFF19, 0x8260: 0xFF21, 0x8261: 0xFF22, 0x8262: 0xFF23, 0x8263: 0xFF24, 0x8264: 0xFF25, 0x8265: 0xFF26, 0x8266: 0xFF27, 0x8267: 0xFF28, 0x8268: 0xFF29, 0x8269: 0xFF2A, 0x826A: 0xFF2B, 0x826B: 0xFF2C, 0x826C: 0xFF2D, 0x826D: 0xFF2E, 0x826E: 0xFF2F, 0x826F: 0xFF30, 0x8270: 0xFF31, 0x8271: 0xFF32, 0x8272: 0xFF33, 0x8273: 0xFF34, 0x8274: 0xFF35, 0x8275: 0xFF36, 0x8276: 0xFF37, 0x8277: 0xFF38, 0x8278: 0xFF39, 0x8279: 0xFF3A, 0x8281: 0xFF41, 0x8282: 0xFF42, 0x8283: 0xFF43, 0x8284: 0xFF44, 0x8285: 0xFF45, 0x8286: 0xFF46, 0x8287: 0xFF47, 0x8288: 0xFF48, 0x8289: 0xFF49, 0x828A: 0xFF4A, 0x828B: 0xFF4B, 0x828C: 0xFF4C, 0x828D: 0xFF4D, 0x828E: 0xFF4E, 0x828F: 0xFF4F, 0x8290: 0xFF50, 0x8291: 0xFF51, 0x8292: 0xFF52, 0x8293: 0xFF53, 0x8294: 0xFF54, 0x8295: 0xFF55, 0x8296: 0xFF56, 0x8297: 0xFF57, 0x8298: 0xFF58, 0x8299: 0xFF59, 0x829A: 0xFF5A, 0x829F: 0x3041, 0x82A0: 0x3042, 0x82A1: 0x3043, 0x82A2: 0x3044, 0x82A3: 0x3045, 0x82A4: 0x3046, 0x82A5: 0x3047, 0x82A6: 0x3048, 0x82A7: 0x3049, 0x82A8: 0x304A, 0x82A9: 0x304B, 0x82AA: 0x304C, 0x82AB: 0x304D, 0x82AC: 0x304E, 0x82AD: 0x304F, 0x82AE: 0x3050, 0x82AF: 0x3051, 0x82B0: 0x3052, 0x82B1: 0x3053, 0x82B2: 0x3054, 0x82B3: 0x3055, 0x82B4: 0x3056, 0x82B5: 0x3057, 0x82B6: 0x3058, 0x82B7: 0x3059, 0x82B8: 0x305A, 0x82B9: 0x305B, 0x82BA: 0x305C, 0x82BB: 0x305D, 0x82BC: 0x305E, 0x82BD: 0x305F, 0x82BE: 0x3060, 0x82BF: 0x3061, 0x82C0: 0x3062, 0x82C1: 0x3063, 0x82C2: 0x3064, 0x82C3: 0x3065, 0x82C4: 0x3066, 0x82C5: 0x3067, 0x82C6: 0x3068, 0x82C7: 0x3069, 0x82C8: 0x306A, 0x82C9: 0x306B, 0x82CA: 0x306C, 0x82CB: 0x306D, 0x82CC: 0x306E, 0x82CD: 0x306F, 0x82CE: 0x3070, 0x82CF: 0x3071, 0x82D0: 0x3072, 0x82D1: 0x3073, 0x82D2: 0x3074, 0x82D3: 0x3075, 0x82D4: 0x3076, 0x82D5: 0x3077, 0x82D6: 0x3078, 0x82D7: 0x3079, 0x82D8: 0x307A, 0x82D9: 0x307B, 0x82DA: 0x307C, 0x82DB: 0x307D, 0x82DC: 0x307E, 0x82DD: 0x307F, 0x82DE: 0x3080, 0x82DF: 0x3081, 0x82E0: 0x3082, 0x82E1: 0x3083, 0x82E2: 0x3084, 0x82E3: 0x3085, 0x82E4: 0x3086, 0x82E5: 0x3087, 0x82E6: 0x3088, 0x82E7: 0x3089, 0x82E8: 0x308A, 0x82E9: 0x308B, 0x82EA: 0x308C, 0x82EB: 0x308D, 0x82EC: 0x308E, 0x82ED: 0x308F, 0x82EE: 0x3090, 0x82EF: 0x3091, 0x82F0: 0x3092, 0x82F1: 0x3093, 0x8340: 0x30A1, 0x8341: 0x30A2, 0x8342: 0x30A3, 0x8343: 0x30A4, 0x8344: 0x30A5, 0x8345: 0x30A6, 0x8346: 0x30A7, 0x8347: 0x30A8, 0x8348: 0x30A9, 0x8349: 0x30AA, 0x834A: 0x30AB, 0x834B: 0x30AC, 0x834C: 0x30AD, 0x834D: 0x30AE, 0x834E: 0x30AF, 0x834F: 0x30B0, 0x8350: 0x30B1, 0x8351: 0x30B2, 0x8352: 0x30B3, 0x8353: 0x30B4, 0x8354: 0x30B5, 0x8355: 0x30B6, 0x8356: 0x30B7, 0x8357: 0x30B8, 0x8358: 0x30B9, 0x8359: 0x30BA, 0x835A: 0x30BB, 0x835B: 0x30BC, 0x835C: 0x30BD, 0x835D: 0x30BE, 0x835E: 0x30BF, 0x835F: 0x30C0, 0x8360: 0x30C1, 0x8361: 0x30C2, 0x8362: 0x30C3, 0x8363: 0x30C4, 0x8364: 0x30C5, 0x8365: 0x30C6, 0x8366: 0x30C7, 0x8367: 0x30C8, 0x8368: 0x30C9, 0x8369: 0x30CA, 0x836A: 0x30CB, 0x836B: 0x30CC, 0x836C: 0x30CD, 0x836D: 0x30CE, 0x836E: 0x30CF, 0x836F: 0x30D0, 0x8370: 0x30D1, 0x8371: 0x30D2, 0x8372: 0x30D3, 0x8373: 0x30D4, 0x8374: 0x30D5, 0x8375: 0x30D6, 0x8376: 0x30D7, 0x8377: 0x30D8, 0x8378: 0x30D9, 0x8379: 0x30DA, 0x837A: 0x30DB, 0x837B: 0x30DC, 0x837C: 0x30DD, 0x837D: 0x30DE, 0x837E: 0x30DF, 0x8380: 0x30E0, 0x8381: 0x30E1, 0x8382: 0x30E2, 0x8383: 0x30E3, 0x8384: 0x30E4, 0x8385: 0x30E5, 0x8386: 0x30E6, 0x8387: 0x30E7, 0x8388: 0x30E8, 0x8389: 0x30E9, 0x838A: 0x30EA, 0x838B: 0x30EB, 0x838C: 0x30EC, 0x838D: 0x30ED, 0x838E: 0x30EE, 0x838F: 0x30EF, 0x8390: 0x30F0, 0x8391: 0x30F1, 0x8392: 0x30F2, 0x8393: 0x30F3, 0x8394: 0x30F4, 0x8395: 0x30F5, 0x8396: 0x30F6, 0x839F: 0x0391, 0x83A0: 0x0392, 0x83A1: 0x0393, 0x83A2: 0x0394, 0x83A3: 0x0395, 0x83A4: 0x0396, 0x83A5: 0x0397, 0x83A6: 0x0398, 0x83A7: 0x0399, 0x83A8: 0x039A, 0x83A9: 0x039B, 0x83AA: 0x039C, 0x83AB: 0x039D, 0x83AC: 0x039E, 0x83AD: 0x039F, 0x83AE: 0x03A0, 0x83AF: 0x03A1, 0x83B0: 0x03A3, 0x83B1: 0x03A4, 0x83B2: 0x03A5, 0x83B3: 0x03A6, 0x83B4: 0x03A7, 0x83B5: 0x03A8, 0x83B6: 0x03A9, 0x83BF: 0x03B1, 0x83C0: 0x03B2, 0x83C1: 0x03B3, 0x83C2: 0x03B4, 0x83C3: 0x03B5, 0x83C4: 0x03B6, 0x83C5: 0x03B7, 0x83C6: 0x03B8, 0x83C7: 0x03B9, 0x83C8: 0x03BA, 0x83C9: 0x03BB, 0x83CA: 0x03BC, 0x83CB: 0x03BD, 0x83CC: 0x03BE, 0x83CD: 0x03BF, 0x83CE: 0x03C0, 0x83CF: 0x03C1, 0x83D0: 0x03C3, 0x83D1: 0x03C4, 0x83D2: 0x03C5, 0x83D3: 0x03C6, 0x83D4: 0x03C7, 0x83D5: 0x03C8, 0x83D6: 0x03C9, 0x8440: 0x0410, 0x8441: 0x0411, 0x8442: 0x0412, 0x8443: 0x0413, 0x8444: 0x0414, 0x8445: 0x0415, 0x8446: 0x0401, 0x8447: 0x0416, 0x8448: 0x0417, 0x8449: 0x0418, 0x844A: 0x0419, 0x844B: 0x041A, 0x844C: 0x041B, 0x844D: 0x041C, 0x844E: 0x041D, 0x844F: 0x041E, 0x8450: 0x041F, 0x8451: 0x0420, 0x8452: 0x0421, 0x8453: 0x0422, 0x8454: 0x0423, 0x8455: 0x0424, 0x8456: 0x0425, 0x8457: 0x0426, 0x8458: 0x0427, 0x8459: 0x0428, 0x845A: 0x0429, 0x845B: 0x042A, 0x845C: 0x042B, 0x845D: 0x042C, 0x845E: 0x042D, 0x845F: 0x042E, 0x8460: 0x042F, 0x8470: 0x0430, 0x8471: 0x0431, 0x8472: 0x0432, 0x8473: 0x0433, 0x8474: 0x0434, 0x8475: 0x0435, 0x8476: 0x0451, 0x8477: 0x0436, 0x8478: 0x0437, 0x8479: 0x0438, 0x847A: 0x0439, 0x847B: 0x043A, 0x847C: 0x043B, 0x847D: 0x043C, 0x847E: 0x043D, 0x8480: 0x043E, 0x8481: 0x043F, 0x8482: 0x0440, 0x8483: 0x0441, 0x8484: 0x0442, 0x8485: 0x0443, 0x8486: 0x0444, 0x8487: 0x0445, 0x8488: 0x0446, 0x8489: 0x0447, 0x848A: 0x0448, 0x848B: 0x0449, 0x848C: 0x044A, 0x848D: 0x044B, 0x848E: 0x044C, 0x848F: 0x044D, 0x8490: 0x044E, 0x8491: 0x044F, 0x849F: 0x2500, 0x84A0: 0x2502, 0x84A1: 0x250C, 0x84A2: 0x2510, 0x84A3: 0x2518, 0x84A4: 0x2514, 0x84A5: 0x251C, 0x84A6: 0x252C, 0x84A7: 0x2524, 0x84A8: 0x2534, 0x84A9: 0x253C, 0x84AA: 0x2501, 0x84AB: 0x2503, 0x84AC: 0x250F, 0x84AD: 0x2513, 0x84AE: 0x251B, 0x84AF: 0x2517, 0x84B0: 0x2523, 0x84B1: 0x2533, 0x84B2: 0x252B, 0x84B3: 0x253B, 0x84B4: 0x254B, 0x84B5: 0x2520, 0x84B6: 0x252F, 0x84B7: 0x2528, 0x84B8: 0x2537, 0x84B9: 0x253F, 0x84BA: 0x251D, 0x84BB: 0x2530, 0x84BC: 0x2525, 0x84BD: 0x2538, 0x84BE: 0x2542, 0x889F: 0x4E9C, 0x88A0: 0x5516, 0x88A1: 0x5A03, 0x88A2: 0x963F, 0x88A3: 0x54C0, 0x88A4: 0x611B, 0x88A5: 0x6328, 0x88A6: 0x59F6, 0x88A7: 0x9022, 0x88A8: 0x8475, 0x88A9: 0x831C, 0x88AA: 0x7A50, 0x88AB: 0x60AA, 0x88AC: 0x63E1, 0x88AD: 0x6E25, 0x88AE: 0x65ED, 0x88AF: 0x8466, 0x88B0: 0x82A6, 0x88B1: 0x9BF5, 0x88B2: 0x6893, 0x88B3: 0x5727, 0x88B4: 0x65A1, 0x88B5: 0x6271, 0x88B6: 0x5B9B, 0x88B7: 0x59D0, 0x88B8: 0x867B, 0x88B9: 0x98F4, 0x88BA: 0x7D62, 0x88BB: 0x7DBE, 0x88BC: 0x9B8E, 0x88BD: 0x6216, 0x88BE: 0x7C9F, 0x88BF: 0x88B7, 0x88C0: 0x5B89, 0x88C1: 0x5EB5, 0x88C2: 0x6309, 0x88C3: 0x6697, 0x88C4: 0x6848, 0x88C5: 0x95C7, 0x88C6: 0x978D, 0x88C7: 0x674F, 0x88C8: 0x4EE5, 0x88C9: 0x4F0A, 0x88CA: 0x4F4D, 0x88CB: 0x4F9D, 0x88CC: 0x5049, 0x88CD: 0x56F2, 0x88CE: 0x5937, 0x88CF: 0x59D4, 0x88D0: 0x5A01, 0x88D1: 0x5C09, 0x88D2: 0x60DF, 0x88D3: 0x610F, 0x88D4: 0x6170, 0x88D5: 0x6613, 0x88D6: 0x6905, 0x88D7: 0x70BA, 0x88D8: 0x754F, 0x88D9: 0x7570, 0x88DA: 0x79FB, 0x88DB: 0x7DAD, 0x88DC: 0x7DEF, 0x88DD: 0x80C3, 0x88DE: 0x840E, 0x88DF: 0x8863, 0x88E0: 0x8B02, 0x88E1: 0x9055, 0x88E2: 0x907A, 0x88E3: 0x533B, 0x88E4: 0x4E95, 0x88E5: 0x4EA5, 0x88E6: 0x57DF, 0x88E7: 0x80B2, 0x88E8: 0x90C1, 0x88E9: 0x78EF, 0x88EA: 0x4E00, 0x88EB: 0x58F1, 0x88EC: 0x6EA2, 0x88ED: 0x9038, 0x88EE: 0x7A32, 0x88EF: 0x8328, 0x88F0: 0x828B, 0x88F1: 0x9C2F, 0x88F2: 0x5141, 0x88F3: 0x5370, 0x88F4: 0x54BD, 0x88F5: 0x54E1, 0x88F6: 0x56E0, 0x88F7: 0x59FB, 0x88F8: 0x5F15, 0x88F9: 0x98F2, 0x88FA: 0x6DEB, 0x88FB: 0x80E4, 0x88FC: 0x852D, 0x8940: 0x9662, 0x8941: 0x9670, 0x8942: 0x96A0, 0x8943: 0x97FB, 0x8944: 0x540B, 0x8945: 0x53F3, 0x8946: 0x5B87, 0x8947: 0x70CF, 0x8948: 0x7FBD, 0x8949: 0x8FC2, 0x894A: 0x96E8, 0x894B: 0x536F, 0x894C: 0x9D5C, 0x894D: 0x7ABA, 0x894E: 0x4E11, 0x894F: 0x7893, 0x8950: 0x81FC, 0x8951: 0x6E26, 0x8952: 0x5618, 0x8953: 0x5504, 0x8954: 0x6B1D, 0x8955: 0x851A, 0x8956: 0x9C3B, 0x8957: 0x59E5, 0x8958: 0x53A9, 0x8959: 0x6D66, 0x895A: 0x74DC, 0x895B: 0x958F, 0x895C: 0x5642, 0x895D: 0x4E91, 0x895E: 0x904B, 0x895F: 0x96F2, 0x8960: 0x834F, 0x8961: 0x990C, 0x8962: 0x53E1, 0x8963: 0x55B6, 0x8964: 0x5B30, 0x8965: 0x5F71, 0x8966: 0x6620, 0x8967: 0x66F3, 0x8968: 0x6804, 0x8969: 0x6C38, 0x896A: 0x6CF3, 0x896B: 0x6D29, 0x896C: 0x745B, 0x896D: 0x76C8, 0x896E: 0x7A4E, 0x896F: 0x9834, 0x8970: 0x82F1, 0x8971: 0x885B, 0x8972: 0x8A60, 0x8973: 0x92ED, 0x8974: 0x6DB2, 0x8975: 0x75AB, 0x8976: 0x76CA, 0x8977: 0x99C5, 0x8978: 0x60A6, 0x8979: 0x8B01, 0x897A: 0x8D8A, 0x897B: 0x95B2, 0x897C: 0x698E, 0x897D: 0x53AD, 0x897E: 0x5186, 0x8980: 0x5712, 0x8981: 0x5830, 0x8982: 0x5944, 0x8983: 0x5BB4, 0x8984: 0x5EF6, 0x8985: 0x6028, 0x8986: 0x63A9, 0x8987: 0x63F4, 0x8988: 0x6CBF, 0x8989: 0x6F14, 0x898A: 0x708E, 0x898B: 0x7114, 0x898C: 0x7159, 0x898D: 0x71D5, 0x898E: 0x733F, 0x898F: 0x7E01, 0x8990: 0x8276, 0x8991: 0x82D1, 0x8992: 0x8597, 0x8993: 0x9060, 0x8994: 0x925B, 0x8995: 0x9D1B, 0x8996: 0x5869, 0x8997: 0x65BC, 0x8998: 0x6C5A, 0x8999: 0x7525, 0x899A: 0x51F9, 0x899B: 0x592E, 0x899C: 0x5965, 0x899D: 0x5F80, 0x899E: 0x5FDC, 0x899F: 0x62BC, 0x89A0: 0x65FA, 0x89A1: 0x6A2A, 0x89A2: 0x6B27, 0x89A3: 0x6BB4, 0x89A4: 0x738B, 0x89A5: 0x7FC1, 0x89A6: 0x8956, 0x89A7: 0x9D2C, 0x89A8: 0x9D0E, 0x89A9: 0x9EC4, 0x89AA: 0x5CA1, 0x89AB: 0x6C96, 0x89AC: 0x837B, 0x89AD: 0x5104, 0x89AE: 0x5C4B, 0x89AF: 0x61B6, 0x89B0: 0x81C6, 0x89B1: 0x6876, 0x89B2: 0x7261, 0x89B3: 0x4E59, 0x89B4: 0x4FFA, 0x89B5: 0x5378, 0x89B6: 0x6069, 0x89B7: 0x6E29, 0x89B8: 0x7A4F, 0x89B9: 0x97F3, 0x89BA: 0x4E0B, 0x89BB: 0x5316, 0x89BC: 0x4EEE, 0x89BD: 0x4F55, 0x89BE: 0x4F3D, 0x89BF: 0x4FA1, 0x89C0: 0x4F73, 0x89C1: 0x52A0, 0x89C2: 0x53EF, 0x89C3: 0x5609, 0x89C4: 0x590F, 0x89C5: 0x5AC1, 0x89C6: 0x5BB6, 0x89C7: 0x5BE1, 0x89C8: 0x79D1, 0x89C9: 0x6687, 0x89CA: 0x679C, 0x89CB: 0x67B6, 0x89CC: 0x6B4C, 0x89CD: 0x6CB3, 0x89CE: 0x706B, 0x89CF: 0x73C2, 0x89D0: 0x798D, 0x89D1: 0x79BE, 0x89D2: 0x7A3C, 0x89D3: 0x7B87, 0x89D4: 0x82B1, 0x89D5: 0x82DB, 0x89D6: 0x8304, 0x89D7: 0x8377, 0x89D8: 0x83EF, 0x89D9: 0x83D3, 0x89DA: 0x8766, 0x89DB: 0x8AB2, 0x89DC: 0x5629, 0x89DD: 0x8CA8, 0x89DE: 0x8FE6, 0x89DF: 0x904E, 0x89E0: 0x971E, 0x89E1: 0x868A, 0x89E2: 0x4FC4, 0x89E3: 0x5CE8, 0x89E4: 0x6211, 0x89E5: 0x7259, 0x89E6: 0x753B, 0x89E7: 0x81E5, 0x89E8: 0x82BD, 0x89E9: 0x86FE, 0x89EA: 0x8CC0, 0x89EB: 0x96C5, 0x89EC: 0x9913, 0x89ED: 0x99D5, 0x89EE: 0x4ECB, 0x89EF: 0x4F1A, 0x89F0: 0x89E3, 0x89F1: 0x56DE, 0x89F2: 0x584A, 0x89F3: 0x58CA, 0x89F4: 0x5EFB, 0x89F5: 0x5FEB, 0x89F6: 0x602A, 0x89F7: 0x6094, 0x89F8: 0x6062, 0x89F9: 0x61D0, 0x89FA: 0x6212, 0x89FB: 0x62D0, 0x89FC: 0x6539, 0x8A40: 0x9B41, 0x8A41: 0x6666, 0x8A42: 0x68B0, 0x8A43: 0x6D77, 0x8A44: 0x7070, 0x8A45: 0x754C, 0x8A46: 0x7686, 0x8A47: 0x7D75, 0x8A48: 0x82A5, 0x8A49: 0x87F9, 0x8A4A: 0x958B, 0x8A4B: 0x968E, 0x8A4C: 0x8C9D, 0x8A4D: 0x51F1, 0x8A4E: 0x52BE, 0x8A4F: 0x5916, 0x8A50: 0x54B3, 0x8A51: 0x5BB3, 0x8A52: 0x5D16, 0x8A53: 0x6168, 0x8A54: 0x6982, 0x8A55: 0x6DAF, 0x8A56: 0x788D, 0x8A57: 0x84CB, 0x8A58: 0x8857, 0x8A59: 0x8A72, 0x8A5A: 0x93A7, 0x8A5B: 0x9AB8, 0x8A5C: 0x6D6C, 0x8A5D: 0x99A8, 0x8A5E: 0x86D9, 0x8A5F: 0x57A3, 0x8A60: 0x67FF, 0x8A61: 0x86CE, 0x8A62: 0x920E, 0x8A63: 0x5283, 0x8A64: 0x5687, 0x8A65: 0x5404, 0x8A66: 0x5ED3, 0x8A67: 0x62E1, 0x8A68: 0x64B9, 0x8A69: 0x683C, 0x8A6A: 0x6838, 0x8A6B: 0x6BBB, 0x8A6C: 0x7372, 0x8A6D: 0x78BA, 0x8A6E: 0x7A6B, 0x8A6F: 0x899A, 0x8A70: 0x89D2, 0x8A71: 0x8D6B, 0x8A72: 0x8F03, 0x8A73: 0x90ED, 0x8A74: 0x95A3, 0x8A75: 0x9694, 0x8A76: 0x9769, 0x8A77: 0x5B66, 0x8A78: 0x5CB3, 0x8A79: 0x697D, 0x8A7A: 0x984D, 0x8A7B: 0x984E, 0x8A7C: 0x639B, 0x8A7D: 0x7B20, 0x8A7E: 0x6A2B, 0x8A80: 0x6A7F, 0x8A81: 0x68B6, 0x8A82: 0x9C0D, 0x8A83: 0x6F5F, 0x8A84: 0x5272, 0x8A85: 0x559D, 0x8A86: 0x6070, 0x8A87: 0x62EC, 0x8A88: 0x6D3B, 0x8A89: 0x6E07, 0x8A8A: 0x6ED1, 0x8A8B: 0x845B, 0x8A8C: 0x8910, 0x8A8D: 0x8F44, 0x8A8E: 0x4E14, 0x8A8F: 0x9C39, 0x8A90: 0x53F6, 0x8A91: 0x691B, 0x8A92: 0x6A3A, 0x8A93: 0x9784, 0x8A94: 0x682A, 0x8A95: 0x515C, 0x8A96: 0x7AC3, 0x8A97: 0x84B2, 0x8A98: 0x91DC, 0x8A99: 0x938C, 0x8A9A: 0x565B, 0x8A9B: 0x9D28, 0x8A9C: 0x6822, 0x8A9D: 0x8305, 0x8A9E: 0x8431, 0x8A9F: 0x7CA5, 0x8AA0: 0x5208, 0x8AA1: 0x82C5, 0x8AA2: 0x74E6, 0x8AA3: 0x4E7E, 0x8AA4: 0x4F83, 0x8AA5: 0x51A0, 0x8AA6: 0x5BD2, 0x8AA7: 0x520A, 0x8AA8: 0x52D8, 0x8AA9: 0x52E7, 0x8AAA: 0x5DFB, 0x8AAB: 0x559A, 0x8AAC: 0x582A, 0x8AAD: 0x59E6, 0x8AAE: 0x5B8C, 0x8AAF: 0x5B98, 0x8AB0: 0x5BDB, 0x8AB1: 0x5E72, 0x8AB2: 0x5E79, 0x8AB3: 0x60A3, 0x8AB4: 0x611F, 0x8AB5: 0x6163, 0x8AB6: 0x61BE, 0x8AB7: 0x63DB, 0x8AB8: 0x6562, 0x8AB9: 0x67D1, 0x8ABA: 0x6853, 0x8ABB: 0x68FA, 0x8ABC: 0x6B3E, 0x8ABD: 0x6B53, 0x8ABE: 0x6C57, 0x8ABF: 0x6F22, 0x8AC0: 0x6F97, 0x8AC1: 0x6F45, 0x8AC2: 0x74B0, 0x8AC3: 0x7518, 0x8AC4: 0x76E3, 0x8AC5: 0x770B, 0x8AC6: 0x7AFF, 0x8AC7: 0x7BA1, 0x8AC8: 0x7C21, 0x8AC9: 0x7DE9, 0x8ACA: 0x7F36, 0x8ACB: 0x7FF0, 0x8ACC: 0x809D, 0x8ACD: 0x8266, 0x8ACE: 0x839E, 0x8ACF: 0x89B3, 0x8AD0: 0x8ACC, 0x8AD1: 0x8CAB, 0x8AD2: 0x9084, 0x8AD3: 0x9451, 0x8AD4: 0x9593, 0x8AD5: 0x9591, 0x8AD6: 0x95A2, 0x8AD7: 0x9665, 0x8AD8: 0x97D3, 0x8AD9: 0x9928, 0x8ADA: 0x8218, 0x8ADB: 0x4E38, 0x8ADC: 0x542B, 0x8ADD: 0x5CB8, 0x8ADE: 0x5DCC, 0x8ADF: 0x73A9, 0x8AE0: 0x764C, 0x8AE1: 0x773C, 0x8AE2: 0x5CA9, 0x8AE3: 0x7FEB, 0x8AE4: 0x8D0B, 0x8AE5: 0x96C1, 0x8AE6: 0x9811, 0x8AE7: 0x9854, 0x8AE8: 0x9858, 0x8AE9: 0x4F01, 0x8AEA: 0x4F0E, 0x8AEB: 0x5371, 0x8AEC: 0x559C, 0x8AED: 0x5668, 0x8AEE: 0x57FA, 0x8AEF: 0x5947, 0x8AF0: 0x5B09, 0x8AF1: 0x5BC4, 0x8AF2: 0x5C90, 0x8AF3: 0x5E0C, 0x8AF4: 0x5E7E, 0x8AF5: 0x5FCC, 0x8AF6: 0x63EE, 0x8AF7: 0x673A, 0x8AF8: 0x65D7, 0x8AF9: 0x65E2, 0x8AFA: 0x671F, 0x8AFB: 0x68CB, 0x8AFC: 0x68C4, 0x8B40: 0x6A5F, 0x8B41: 0x5E30, 0x8B42: 0x6BC5, 0x8B43: 0x6C17, 0x8B44: 0x6C7D, 0x8B45: 0x757F, 0x8B46: 0x7948, 0x8B47: 0x5B63, 0x8B48: 0x7A00, 0x8B49: 0x7D00, 0x8B4A: 0x5FBD, 0x8B4B: 0x898F, 0x8B4C: 0x8A18, 0x8B4D: 0x8CB4, 0x8B4E: 0x8D77, 0x8B4F: 0x8ECC, 0x8B50: 0x8F1D, 0x8B51: 0x98E2, 0x8B52: 0x9A0E, 0x8B53: 0x9B3C, 0x8B54: 0x4E80, 0x8B55: 0x507D, 0x8B56: 0x5100, 0x8B57: 0x5993, 0x8B58: 0x5B9C, 0x8B59: 0x622F, 0x8B5A: 0x6280, 0x8B5B: 0x64EC, 0x8B5C: 0x6B3A, 0x8B5D: 0x72A0, 0x8B5E: 0x7591, 0x8B5F: 0x7947, 0x8B60: 0x7FA9, 0x8B61: 0x87FB, 0x8B62: 0x8ABC, 0x8B63: 0x8B70, 0x8B64: 0x63AC, 0x8B65: 0x83CA, 0x8B66: 0x97A0, 0x8B67: 0x5409, 0x8B68: 0x5403, 0x8B69: 0x55AB, 0x8B6A: 0x6854, 0x8B6B: 0x6A58, 0x8B6C: 0x8A70, 0x8B6D: 0x7827, 0x8B6E: 0x6775, 0x8B6F: 0x9ECD, 0x8B70: 0x5374, 0x8B71: 0x5BA2, 0x8B72: 0x811A, 0x8B73: 0x8650, 0x8B74: 0x9006, 0x8B75: 0x4E18, 0x8B76: 0x4E45, 0x8B77: 0x4EC7, 0x8B78: 0x4F11, 0x8B79: 0x53CA, 0x8B7A: 0x5438, 0x8B7B: 0x5BAE, 0x8B7C: 0x5F13, 0x8B7D: 0x6025, 0x8B7E: 0x6551, 0x8B80: 0x673D, 0x8B81: 0x6C42, 0x8B82: 0x6C72, 0x8B83: 0x6CE3, 0x8B84: 0x7078, 0x8B85: 0x7403, 0x8B86: 0x7A76, 0x8B87: 0x7AAE, 0x8B88: 0x7B08, 0x8B89: 0x7D1A, 0x8B8A: 0x7CFE, 0x8B8B: 0x7D66, 0x8B8C: 0x65E7, 0x8B8D: 0x725B, 0x8B8E: 0x53BB, 0x8B8F: 0x5C45, 0x8B90: 0x5DE8, 0x8B91: 0x62D2, 0x8B92: 0x62E0, 0x8B93: 0x6319, 0x8B94: 0x6E20, 0x8B95: 0x865A, 0x8B96: 0x8A31, 0x8B97: 0x8DDD, 0x8B98: 0x92F8, 0x8B99: 0x6F01, 0x8B9A: 0x79A6, 0x8B9B: 0x9B5A, 0x8B9C: 0x4EA8, 0x8B9D: 0x4EAB, 0x8B9E: 0x4EAC, 0x8B9F: 0x4F9B, 0x8BA0: 0x4FA0, 0x8BA1: 0x50D1, 0x8BA2: 0x5147, 0x8BA3: 0x7AF6, 0x8BA4: 0x5171, 0x8BA5: 0x51F6, 0x8BA6: 0x5354, 0x8BA7: 0x5321, 0x8BA8: 0x537F, 0x8BA9: 0x53EB, 0x8BAA: 0x55AC, 0x8BAB: 0x5883, 0x8BAC: 0x5CE1, 0x8BAD: 0x5F37, 0x8BAE: 0x5F4A, 0x8BAF: 0x602F, 0x8BB0: 0x6050, 0x8BB1: 0x606D, 0x8BB2: 0x631F, 0x8BB3: 0x6559, 0x8BB4: 0x6A4B, 0x8BB5: 0x6CC1, 0x8BB6: 0x72C2, 0x8BB7: 0x72ED, 0x8BB8: 0x77EF, 0x8BB9: 0x80F8, 0x8BBA: 0x8105, 0x8BBB: 0x8208, 0x8BBC: 0x854E, 0x8BBD: 0x90F7, 0x8BBE: 0x93E1, 0x8BBF: 0x97FF, 0x8BC0: 0x9957, 0x8BC1: 0x9A5A, 0x8BC2: 0x4EF0, 0x8BC3: 0x51DD, 0x8BC4: 0x5C2D, 0x8BC5: 0x6681, 0x8BC6: 0x696D, 0x8BC7: 0x5C40, 0x8BC8: 0x66F2, 0x8BC9: 0x6975, 0x8BCA: 0x7389, 0x8BCB: 0x6850, 0x8BCC: 0x7C81, 0x8BCD: 0x50C5, 0x8BCE: 0x52E4, 0x8BCF: 0x5747, 0x8BD0: 0x5DFE, 0x8BD1: 0x9326, 0x8BD2: 0x65A4, 0x8BD3: 0x6B23, 0x8BD4: 0x6B3D, 0x8BD5: 0x7434, 0x8BD6: 0x7981, 0x8BD7: 0x79BD, 0x8BD8: 0x7B4B, 0x8BD9: 0x7DCA, 0x8BDA: 0x82B9, 0x8BDB: 0x83CC, 0x8BDC: 0x887F, 0x8BDD: 0x895F, 0x8BDE: 0x8B39, 0x8BDF: 0x8FD1, 0x8BE0: 0x91D1, 0x8BE1: 0x541F, 0x8BE2: 0x9280, 0x8BE3: 0x4E5D, 0x8BE4: 0x5036, 0x8BE5: 0x53E5, 0x8BE6: 0x533A, 0x8BE7: 0x72D7, 0x8BE8: 0x7396, 0x8BE9: 0x77E9, 0x8BEA: 0x82E6, 0x8BEB: 0x8EAF, 0x8BEC: 0x99C6, 0x8BED: 0x99C8, 0x8BEE: 0x99D2, 0x8BEF: 0x5177, 0x8BF0: 0x611A, 0x8BF1: 0x865E, 0x8BF2: 0x55B0, 0x8BF3: 0x7A7A, 0x8BF4: 0x5076, 0x8BF5: 0x5BD3, 0x8BF6: 0x9047, 0x8BF7: 0x9685, 0x8BF8: 0x4E32, 0x8BF9: 0x6ADB, 0x8BFA: 0x91E7, 0x8BFB: 0x5C51, 0x8BFC: 0x5C48, 0x8C40: 0x6398, 0x8C41: 0x7A9F, 0x8C42: 0x6C93, 0x8C43: 0x9774, 0x8C44: 0x8F61, 0x8C45: 0x7AAA, 0x8C46: 0x718A, 0x8C47: 0x9688, 0x8C48: 0x7C82, 0x8C49: 0x6817, 0x8C4A: 0x7E70, 0x8C4B: 0x6851, 0x8C4C: 0x936C, 0x8C4D: 0x52F2, 0x8C4E: 0x541B, 0x8C4F: 0x85AB, 0x8C50: 0x8A13, 0x8C51: 0x7FA4, 0x8C52: 0x8ECD, 0x8C53: 0x90E1, 0x8C54: 0x5366, 0x8C55: 0x8888, 0x8C56: 0x7941, 0x8C57: 0x4FC2, 0x8C58: 0x50BE, 0x8C59: 0x5211, 0x8C5A: 0x5144, 0x8C5B: 0x5553, 0x8C5C: 0x572D, 0x8C5D: 0x73EA, 0x8C5E: 0x578B, 0x8C5F: 0x5951, 0x8C60: 0x5F62, 0x8C61: 0x5F84, 0x8C62: 0x6075, 0x8C63: 0x6176, 0x8C64: 0x6167, 0x8C65: 0x61A9, 0x8C66: 0x63B2, 0x8C67: 0x643A, 0x8C68: 0x656C, 0x8C69: 0x666F, 0x8C6A: 0x6842, 0x8C6B: 0x6E13, 0x8C6C: 0x7566, 0x8C6D: 0x7A3D, 0x8C6E: 0x7CFB, 0x8C6F: 0x7D4C, 0x8C70: 0x7D99, 0x8C71: 0x7E4B, 0x8C72: 0x7F6B, 0x8C73: 0x830E, 0x8C74: 0x834A, 0x8C75: 0x86CD, 0x8C76: 0x8A08, 0x8C77: 0x8A63, 0x8C78: 0x8B66, 0x8C79: 0x8EFD, 0x8C7A: 0x981A, 0x8C7B: 0x9D8F, 0x8C7C: 0x82B8, 0x8C7D: 0x8FCE, 0x8C7E: 0x9BE8, 0x8C80: 0x5287, 0x8C81: 0x621F, 0x8C82: 0x6483, 0x8C83: 0x6FC0, 0x8C84: 0x9699, 0x8C85: 0x6841, 0x8C86: 0x5091, 0x8C87: 0x6B20, 0x8C88: 0x6C7A, 0x8C89: 0x6F54, 0x8C8A: 0x7A74, 0x8C8B: 0x7D50, 0x8C8C: 0x8840, 0x8C8D: 0x8A23, 0x8C8E: 0x6708, 0x8C8F: 0x4EF6, 0x8C90: 0x5039, 0x8C91: 0x5026, 0x8C92: 0x5065, 0x8C93: 0x517C, 0x8C94: 0x5238, 0x8C95: 0x5263, 0x8C96: 0x55A7, 0x8C97: 0x570F, 0x8C98: 0x5805, 0x8C99: 0x5ACC, 0x8C9A: 0x5EFA, 0x8C9B: 0x61B2, 0x8C9C: 0x61F8, 0x8C9D: 0x62F3, 0x8C9E: 0x6372, 0x8C9F: 0x691C, 0x8CA0: 0x6A29, 0x8CA1: 0x727D, 0x8CA2: 0x72AC, 0x8CA3: 0x732E, 0x8CA4: 0x7814, 0x8CA5: 0x786F, 0x8CA6: 0x7D79, 0x8CA7: 0x770C, 0x8CA8: 0x80A9, 0x8CA9: 0x898B, 0x8CAA: 0x8B19, 0x8CAB: 0x8CE2, 0x8CAC: 0x8ED2, 0x8CAD: 0x9063, 0x8CAE: 0x9375, 0x8CAF: 0x967A, 0x8CB0: 0x9855, 0x8CB1: 0x9A13, 0x8CB2: 0x9E78, 0x8CB3: 0x5143, 0x8CB4: 0x539F, 0x8CB5: 0x53B3, 0x8CB6: 0x5E7B, 0x8CB7: 0x5F26, 0x8CB8: 0x6E1B, 0x8CB9: 0x6E90, 0x8CBA: 0x7384, 0x8CBB: 0x73FE, 0x8CBC: 0x7D43, 0x8CBD: 0x8237, 0x8CBE: 0x8A00, 0x8CBF: 0x8AFA, 0x8CC0: 0x9650, 0x8CC1: 0x4E4E, 0x8CC2: 0x500B, 0x8CC3: 0x53E4, 0x8CC4: 0x547C, 0x8CC5: 0x56FA, 0x8CC6: 0x59D1, 0x8CC7: 0x5B64, 0x8CC8: 0x5DF1, 0x8CC9: 0x5EAB, 0x8CCA: 0x5F27, 0x8CCB: 0x6238, 0x8CCC: 0x6545, 0x8CCD: 0x67AF, 0x8CCE: 0x6E56, 0x8CCF: 0x72D0, 0x8CD0: 0x7CCA, 0x8CD1: 0x88B4, 0x8CD2: 0x80A1, 0x8CD3: 0x80E1, 0x8CD4: 0x83F0, 0x8CD5: 0x864E, 0x8CD6: 0x8A87, 0x8CD7: 0x8DE8, 0x8CD8: 0x9237, 0x8CD9: 0x96C7, 0x8CDA: 0x9867, 0x8CDB: 0x9F13, 0x8CDC: 0x4E94, 0x8CDD: 0x4E92, 0x8CDE: 0x4F0D, 0x8CDF: 0x5348, 0x8CE0: 0x5449, 0x8CE1: 0x543E, 0x8CE2: 0x5A2F, 0x8CE3: 0x5F8C, 0x8CE4: 0x5FA1, 0x8CE5: 0x609F, 0x8CE6: 0x68A7, 0x8CE7: 0x6A8E, 0x8CE8: 0x745A, 0x8CE9: 0x7881, 0x8CEA: 0x8A9E, 0x8CEB: 0x8AA4, 0x8CEC: 0x8B77, 0x8CED: 0x9190, 0x8CEE: 0x4E5E, 0x8CEF: 0x9BC9, 0x8CF0: 0x4EA4, 0x8CF1: 0x4F7C, 0x8CF2: 0x4FAF, 0x8CF3: 0x5019, 0x8CF4: 0x5016, 0x8CF5: 0x5149, 0x8CF6: 0x516C, 0x8CF7: 0x529F, 0x8CF8: 0x52B9, 0x8CF9: 0x52FE, 0x8CFA: 0x539A, 0x8CFB: 0x53E3, 0x8CFC: 0x5411, 0x8D40: 0x540E, 0x8D41: 0x5589, 0x8D42: 0x5751, 0x8D43: 0x57A2, 0x8D44: 0x597D, 0x8D45: 0x5B54, 0x8D46: 0x5B5D, 0x8D47: 0x5B8F, 0x8D48: 0x5DE5, 0x8D49: 0x5DE7, 0x8D4A: 0x5DF7, 0x8D4B: 0x5E78, 0x8D4C: 0x5E83, 0x8D4D: 0x5E9A, 0x8D4E: 0x5EB7, 0x8D4F: 0x5F18, 0x8D50: 0x6052, 0x8D51: 0x614C, 0x8D52: 0x6297, 0x8D53: 0x62D8, 0x8D54: 0x63A7, 0x8D55: 0x653B, 0x8D56: 0x6602, 0x8D57: 0x6643, 0x8D58: 0x66F4, 0x8D59: 0x676D, 0x8D5A: 0x6821, 0x8D5B: 0x6897, 0x8D5C: 0x69CB, 0x8D5D: 0x6C5F, 0x8D5E: 0x6D2A, 0x8D5F: 0x6D69, 0x8D60: 0x6E2F, 0x8D61: 0x6E9D, 0x8D62: 0x7532, 0x8D63: 0x7687, 0x8D64: 0x786C, 0x8D65: 0x7A3F, 0x8D66: 0x7CE0, 0x8D67: 0x7D05, 0x8D68: 0x7D18, 0x8D69: 0x7D5E, 0x8D6A: 0x7DB1, 0x8D6B: 0x8015, 0x8D6C: 0x8003, 0x8D6D: 0x80AF, 0x8D6E: 0x80B1, 0x8D6F: 0x8154, 0x8D70: 0x818F, 0x8D71: 0x822A, 0x8D72: 0x8352, 0x8D73: 0x884C, 0x8D74: 0x8861, 0x8D75: 0x8B1B, 0x8D76: 0x8CA2, 0x8D77: 0x8CFC, 0x8D78: 0x90CA, 0x8D79: 0x9175, 0x8D7A: 0x9271, 0x8D7B: 0x783F, 0x8D7C: 0x92FC, 0x8D7D: 0x95A4, 0x8D7E: 0x964D, 0x8D80: 0x9805, 0x8D81: 0x9999, 0x8D82: 0x9AD8, 0x8D83: 0x9D3B, 0x8D84: 0x525B, 0x8D85: 0x52AB, 0x8D86: 0x53F7, 0x8D87: 0x5408, 0x8D88: 0x58D5, 0x8D89: 0x62F7, 0x8D8A: 0x6FE0, 0x8D8B: 0x8C6A, 0x8D8C: 0x8F5F, 0x8D8D: 0x9EB9, 0x8D8E: 0x514B, 0x8D8F: 0x523B, 0x8D90: 0x544A, 0x8D91: 0x56FD, 0x8D92: 0x7A40, 0x8D93: 0x9177, 0x8D94: 0x9D60, 0x8D95: 0x9ED2, 0x8D96: 0x7344, 0x8D97: 0x6F09, 0x8D98: 0x8170, 0x8D99: 0x7511, 0x8D9A: 0x5FFD, 0x8D9B: 0x60DA, 0x8D9C: 0x9AA8, 0x8D9D: 0x72DB, 0x8D9E: 0x8FBC, 0x8D9F: 0x6B64, 0x8DA0: 0x9803, 0x8DA1: 0x4ECA, 0x8DA2: 0x56F0, 0x8DA3: 0x5764, 0x8DA4: 0x58BE, 0x8DA5: 0x5A5A, 0x8DA6: 0x6068, 0x8DA7: 0x61C7, 0x8DA8: 0x660F, 0x8DA9: 0x6606, 0x8DAA: 0x6839, 0x8DAB: 0x68B1, 0x8DAC: 0x6DF7, 0x8DAD: 0x75D5, 0x8DAE: 0x7D3A, 0x8DAF: 0x826E, 0x8DB0: 0x9B42, 0x8DB1: 0x4E9B, 0x8DB2: 0x4F50, 0x8DB3: 0x53C9, 0x8DB4: 0x5506, 0x8DB5: 0x5D6F, 0x8DB6: 0x5DE6, 0x8DB7: 0x5DEE, 0x8DB8: 0x67FB, 0x8DB9: 0x6C99, 0x8DBA: 0x7473, 0x8DBB: 0x7802, 0x8DBC: 0x8A50, 0x8DBD: 0x9396, 0x8DBE: 0x88DF, 0x8DBF: 0x5750, 0x8DC0: 0x5EA7, 0x8DC1: 0x632B, 0x8DC2: 0x50B5, 0x8DC3: 0x50AC, 0x8DC4: 0x518D, 0x8DC5: 0x6700, 0x8DC6: 0x54C9, 0x8DC7: 0x585E, 0x8DC8: 0x59BB, 0x8DC9: 0x5BB0, 0x8DCA: 0x5F69, 0x8DCB: 0x624D, 0x8DCC: 0x63A1, 0x8DCD: 0x683D, 0x8DCE: 0x6B73, 0x8DCF: 0x6E08, 0x8DD0: 0x707D, 0x8DD1: 0x91C7, 0x8DD2: 0x7280, 0x8DD3: 0x7815, 0x8DD4: 0x7826, 0x8DD5: 0x796D, 0x8DD6: 0x658E, 0x8DD7: 0x7D30, 0x8DD8: 0x83DC, 0x8DD9: 0x88C1, 0x8DDA: 0x8F09, 0x8DDB: 0x969B, 0x8DDC: 0x5264, 0x8DDD: 0x5728, 0x8DDE: 0x6750, 0x8DDF: 0x7F6A, 0x8DE0: 0x8CA1, 0x8DE1: 0x51B4, 0x8DE2: 0x5742, 0x8DE3: 0x962A, 0x8DE4: 0x583A, 0x8DE5: 0x698A, 0x8DE6: 0x80B4, 0x8DE7: 0x54B2, 0x8DE8: 0x5D0E, 0x8DE9: 0x57FC, 0x8DEA: 0x7895, 0x8DEB: 0x9DFA, 0x8DEC: 0x4F5C, 0x8DED: 0x524A, 0x8DEE: 0x548B, 0x8DEF: 0x643E, 0x8DF0: 0x6628, 0x8DF1: 0x6714, 0x8DF2: 0x67F5, 0x8DF3: 0x7A84, 0x8DF4: 0x7B56, 0x8DF5: 0x7D22, 0x8DF6: 0x932F, 0x8DF7: 0x685C, 0x8DF8: 0x9BAD, 0x8DF9: 0x7B39, 0x8DFA: 0x5319, 0x8DFB: 0x518A, 0x8DFC: 0x5237, 0x8E40: 0x5BDF, 0x8E41: 0x62F6, 0x8E42: 0x64AE, 0x8E43: 0x64E6, 0x8E44: 0x672D, 0x8E45: 0x6BBA, 0x8E46: 0x85A9, 0x8E47: 0x96D1, 0x8E48: 0x7690, 0x8E49: 0x9BD6, 0x8E4A: 0x634C, 0x8E4B: 0x9306, 0x8E4C: 0x9BAB, 0x8E4D: 0x76BF, 0x8E4E: 0x6652, 0x8E4F: 0x4E09, 0x8E50: 0x5098, 0x8E51: 0x53C2, 0x8E52: 0x5C71, 0x8E53: 0x60E8, 0x8E54: 0x6492, 0x8E55: 0x6563, 0x8E56: 0x685F, 0x8E57: 0x71E6, 0x8E58: 0x73CA, 0x8E59: 0x7523, 0x8E5A: 0x7B97, 0x8E5B: 0x7E82, 0x8E5C: 0x8695, 0x8E5D: 0x8B83, 0x8E5E: 0x8CDB, 0x8E5F: 0x9178, 0x8E60: 0x9910, 0x8E61: 0x65AC, 0x8E62: 0x66AB, 0x8E63: 0x6B8B, 0x8E64: 0x4ED5, 0x8E65: 0x4ED4, 0x8E66: 0x4F3A, 0x8E67: 0x4F7F, 0x8E68: 0x523A, 0x8E69: 0x53F8, 0x8E6A: 0x53F2, 0x8E6B: 0x55E3, 0x8E6C: 0x56DB, 0x8E6D: 0x58EB, 0x8E6E: 0x59CB, 0x8E6F: 0x59C9, 0x8E70: 0x59FF, 0x8E71: 0x5B50, 0x8E72: 0x5C4D, 0x8E73: 0x5E02, 0x8E74: 0x5E2B, 0x8E75: 0x5FD7, 0x8E76: 0x601D, 0x8E77: 0x6307, 0x8E78: 0x652F, 0x8E79: 0x5B5C, 0x8E7A: 0x65AF, 0x8E7B: 0x65BD, 0x8E7C: 0x65E8, 0x8E7D: 0x679D, 0x8E7E: 0x6B62, 0x8E80: 0x6B7B, 0x8E81: 0x6C0F, 0x8E82: 0x7345, 0x8E83: 0x7949, 0x8E84: 0x79C1, 0x8E85: 0x7CF8, 0x8E86: 0x7D19, 0x8E87: 0x7D2B, 0x8E88: 0x80A2, 0x8E89: 0x8102, 0x8E8A: 0x81F3, 0x8E8B: 0x8996, 0x8E8C: 0x8A5E, 0x8E8D: 0x8A69, 0x8E8E: 0x8A66, 0x8E8F: 0x8A8C, 0x8E90: 0x8AEE, 0x8E91: 0x8CC7, 0x8E92: 0x8CDC, 0x8E93: 0x96CC, 0x8E94: 0x98FC, 0x8E95: 0x6B6F, 0x8E96: 0x4E8B, 0x8E97: 0x4F3C, 0x8E98: 0x4F8D, 0x8E99: 0x5150, 0x8E9A: 0x5B57, 0x8E9B: 0x5BFA, 0x8E9C: 0x6148, 0x8E9D: 0x6301, 0x8E9E: 0x6642, 0x8E9F: 0x6B21, 0x8EA0: 0x6ECB, 0x8EA1: 0x6CBB, 0x8EA2: 0x723E, 0x8EA3: 0x74BD, 0x8EA4: 0x75D4, 0x8EA5: 0x78C1, 0x8EA6: 0x793A, 0x8EA7: 0x800C, 0x8EA8: 0x8033, 0x8EA9: 0x81EA, 0x8EAA: 0x8494, 0x8EAB: 0x8F9E, 0x8EAC: 0x6C50, 0x8EAD: 0x9E7F, 0x8EAE: 0x5F0F, 0x8EAF: 0x8B58, 0x8EB0: 0x9D2B, 0x8EB1: 0x7AFA, 0x8EB2: 0x8EF8, 0x8EB3: 0x5B8D, 0x8EB4: 0x96EB, 0x8EB5: 0x4E03, 0x8EB6: 0x53F1, 0x8EB7: 0x57F7, 0x8EB8: 0x5931, 0x8EB9: 0x5AC9, 0x8EBA: 0x5BA4, 0x8EBB: 0x6089, 0x8EBC: 0x6E7F, 0x8EBD: 0x6F06, 0x8EBE: 0x75BE, 0x8EBF: 0x8CEA, 0x8EC0: 0x5B9F, 0x8EC1: 0x8500, 0x8EC2: 0x7BE0, 0x8EC3: 0x5072, 0x8EC4: 0x67F4, 0x8EC5: 0x829D, 0x8EC6: 0x5C61, 0x8EC7: 0x854A, 0x8EC8: 0x7E1E, 0x8EC9: 0x820E, 0x8ECA: 0x5199, 0x8ECB: 0x5C04, 0x8ECC: 0x6368, 0x8ECD: 0x8D66, 0x8ECE: 0x659C, 0x8ECF: 0x716E, 0x8ED0: 0x793E, 0x8ED1: 0x7D17, 0x8ED2: 0x8005, 0x8ED3: 0x8B1D, 0x8ED4: 0x8ECA, 0x8ED5: 0x906E, 0x8ED6: 0x86C7, 0x8ED7: 0x90AA, 0x8ED8: 0x501F, 0x8ED9: 0x52FA, 0x8EDA: 0x5C3A, 0x8EDB: 0x6753, 0x8EDC: 0x707C, 0x8EDD: 0x7235, 0x8EDE: 0x914C, 0x8EDF: 0x91C8, 0x8EE0: 0x932B, 0x8EE1: 0x82E5, 0x8EE2: 0x5BC2, 0x8EE3: 0x5F31, 0x8EE4: 0x60F9, 0x8EE5: 0x4E3B, 0x8EE6: 0x53D6, 0x8EE7: 0x5B88, 0x8EE8: 0x624B, 0x8EE9: 0x6731, 0x8EEA: 0x6B8A, 0x8EEB: 0x72E9, 0x8EEC: 0x73E0, 0x8EED: 0x7A2E, 0x8EEE: 0x816B, 0x8EEF: 0x8DA3, 0x8EF0: 0x9152, 0x8EF1: 0x9996, 0x8EF2: 0x5112, 0x8EF3: 0x53D7, 0x8EF4: 0x546A, 0x8EF5: 0x5BFF, 0x8EF6: 0x6388, 0x8EF7: 0x6A39, 0x8EF8: 0x7DAC, 0x8EF9: 0x9700, 0x8EFA: 0x56DA, 0x8EFB: 0x53CE, 0x8EFC: 0x5468, 0x8F40: 0x5B97, 0x8F41: 0x5C31, 0x8F42: 0x5DDE, 0x8F43: 0x4FEE, 0x8F44: 0x6101, 0x8F45: 0x62FE, 0x8F46: 0x6D32, 0x8F47: 0x79C0, 0x8F48: 0x79CB, 0x8F49: 0x7D42, 0x8F4A: 0x7E4D, 0x8F4B: 0x7FD2, 0x8F4C: 0x81ED, 0x8F4D: 0x821F, 0x8F4E: 0x8490, 0x8F4F: 0x8846, 0x8F50: 0x8972, 0x8F51: 0x8B90, 0x8F52: 0x8E74, 0x8F53: 0x8F2F, 0x8F54: 0x9031, 0x8F55: 0x914B, 0x8F56: 0x916C, 0x8F57: 0x96C6, 0x8F58: 0x919C, 0x8F59: 0x4EC0, 0x8F5A: 0x4F4F, 0x8F5B: 0x5145, 0x8F5C: 0x5341, 0x8F5D: 0x5F93, 0x8F5E: 0x620E, 0x8F5F: 0x67D4, 0x8F60: 0x6C41, 0x8F61: 0x6E0B, 0x8F62: 0x7363, 0x8F63: 0x7E26, 0x8F64: 0x91CD, 0x8F65: 0x9283, 0x8F66: 0x53D4, 0x8F67: 0x5919, 0x8F68: 0x5BBF, 0x8F69: 0x6DD1, 0x8F6A: 0x795D, 0x8F6B: 0x7E2E, 0x8F6C: 0x7C9B, 0x8F6D: 0x587E, 0x8F6E: 0x719F, 0x8F6F: 0x51FA, 0x8F70: 0x8853, 0x8F71: 0x8FF0, 0x8F72: 0x4FCA, 0x8F73: 0x5CFB, 0x8F74: 0x6625, 0x8F75: 0x77AC, 0x8F76: 0x7AE3, 0x8F77: 0x821C, 0x8F78: 0x99FF, 0x8F79: 0x51C6, 0x8F7A: 0x5FAA, 0x8F7B: 0x65EC, 0x8F7C: 0x696F, 0x8F7D: 0x6B89, 0x8F7E: 0x6DF3, 0x8F80: 0x6E96, 0x8F81: 0x6F64, 0x8F82: 0x76FE, 0x8F83: 0x7D14, 0x8F84: 0x5DE1, 0x8F85: 0x9075, 0x8F86: 0x9187, 0x8F87: 0x9806, 0x8F88: 0x51E6, 0x8F89: 0x521D, 0x8F8A: 0x6240, 0x8F8B: 0x6691, 0x8F8C: 0x66D9, 0x8F8D: 0x6E1A, 0x8F8E: 0x5EB6, 0x8F8F: 0x7DD2, 0x8F90: 0x7F72, 0x8F91: 0x66F8, 0x8F92: 0x85AF, 0x8F93: 0x85F7, 0x8F94: 0x8AF8, 0x8F95: 0x52A9, 0x8F96: 0x53D9, 0x8F97: 0x5973, 0x8F98: 0x5E8F, 0x8F99: 0x5F90, 0x8F9A: 0x6055, 0x8F9B: 0x92E4, 0x8F9C: 0x9664, 0x8F9D: 0x50B7, 0x8F9E: 0x511F, 0x8F9F: 0x52DD, 0x8FA0: 0x5320, 0x8FA1: 0x5347, 0x8FA2: 0x53EC, 0x8FA3: 0x54E8, 0x8FA4: 0x5546, 0x8FA5: 0x5531, 0x8FA6: 0x5617, 0x8FA7: 0x5968, 0x8FA8: 0x59BE, 0x8FA9: 0x5A3C, 0x8FAA: 0x5BB5, 0x8FAB: 0x5C06, 0x8FAC: 0x5C0F, 0x8FAD: 0x5C11, 0x8FAE: 0x5C1A, 0x8FAF: 0x5E84, 0x8FB0: 0x5E8A, 0x8FB1: 0x5EE0, 0x8FB2: 0x5F70, 0x8FB3: 0x627F, 0x8FB4: 0x6284, 0x8FB5: 0x62DB, 0x8FB6: 0x638C, 0x8FB7: 0x6377, 0x8FB8: 0x6607, 0x8FB9: 0x660C, 0x8FBA: 0x662D, 0x8FBB: 0x6676, 0x8FBC: 0x677E, 0x8FBD: 0x68A2, 0x8FBE: 0x6A1F, 0x8FBF: 0x6A35, 0x8FC0: 0x6CBC, 0x8FC1: 0x6D88, 0x8FC2: 0x6E09, 0x8FC3: 0x6E58, 0x8FC4: 0x713C, 0x8FC5: 0x7126, 0x8FC6: 0x7167, 0x8FC7: 0x75C7, 0x8FC8: 0x7701, 0x8FC9: 0x785D, 0x8FCA: 0x7901, 0x8FCB: 0x7965, 0x8FCC: 0x79F0, 0x8FCD: 0x7AE0, 0x8FCE: 0x7B11, 0x8FCF: 0x7CA7, 0x8FD0: 0x7D39, 0x8FD1: 0x8096, 0x8FD2: 0x83D6, 0x8FD3: 0x848B, 0x8FD4: 0x8549, 0x8FD5: 0x885D, 0x8FD6: 0x88F3, 0x8FD7: 0x8A1F, 0x8FD8: 0x8A3C, 0x8FD9: 0x8A54, 0x8FDA: 0x8A73, 0x8FDB: 0x8C61, 0x8FDC: 0x8CDE, 0x8FDD: 0x91A4, 0x8FDE: 0x9266, 0x8FDF: 0x937E, 0x8FE0: 0x9418, 0x8FE1: 0x969C, 0x8FE2: 0x9798, 0x8FE3: 0x4E0A, 0x8FE4: 0x4E08, 0x8FE5: 0x4E1E, 0x8FE6: 0x4E57, 0x8FE7: 0x5197, 0x8FE8: 0x5270, 0x8FE9: 0x57CE, 0x8FEA: 0x5834, 0x8FEB: 0x58CC, 0x8FEC: 0x5B22, 0x8FED: 0x5E38, 0x8FEE: 0x60C5, 0x8FEF: 0x64FE, 0x8FF0: 0x6761, 0x8FF1: 0x6756, 0x8FF2: 0x6D44, 0x8FF3: 0x72B6, 0x8FF4: 0x7573, 0x8FF5: 0x7A63, 0x8FF6: 0x84B8, 0x8FF7: 0x8B72, 0x8FF8: 0x91B8, 0x8FF9: 0x9320, 0x8FFA: 0x5631, 0x8FFB: 0x57F4, 0x8FFC: 0x98FE, 0x9040: 0x62ED, 0x9041: 0x690D, 0x9042: 0x6B96, 0x9043: 0x71ED, 0x9044: 0x7E54, 0x9045: 0x8077, 0x9046: 0x8272, 0x9047: 0x89E6, 0x9048: 0x98DF, 0x9049: 0x8755, 0x904A: 0x8FB1, 0x904B: 0x5C3B, 0x904C: 0x4F38, 0x904D: 0x4FE1, 0x904E: 0x4FB5, 0x904F: 0x5507, 0x9050: 0x5A20, 0x9051: 0x5BDD, 0x9052: 0x5BE9, 0x9053: 0x5FC3, 0x9054: 0x614E, 0x9055: 0x632F, 0x9056: 0x65B0, 0x9057: 0x664B, 0x9058: 0x68EE, 0x9059: 0x699B, 0x905A: 0x6D78, 0x905B: 0x6DF1, 0x905C: 0x7533, 0x905D: 0x75B9, 0x905E: 0x771F, 0x905F: 0x795E, 0x9060: 0x79E6, 0x9061: 0x7D33, 0x9062: 0x81E3, 0x9063: 0x82AF, 0x9064: 0x85AA, 0x9065: 0x89AA, 0x9066: 0x8A3A, 0x9067: 0x8EAB, 0x9068: 0x8F9B, 0x9069: 0x9032, 0x906A: 0x91DD, 0x906B: 0x9707, 0x906C: 0x4EBA, 0x906D: 0x4EC1, 0x906E: 0x5203, 0x906F: 0x5875, 0x9070: 0x58EC, 0x9071: 0x5C0B, 0x9072: 0x751A, 0x9073: 0x5C3D, 0x9074: 0x814E, 0x9075: 0x8A0A, 0x9076: 0x8FC5, 0x9077: 0x9663, 0x9078: 0x976D, 0x9079: 0x7B25, 0x907A: 0x8ACF, 0x907B: 0x9808, 0x907C: 0x9162, 0x907D: 0x56F3, 0x907E: 0x53A8, 0x9080: 0x9017, 0x9081: 0x5439, 0x9082: 0x5782, 0x9083: 0x5E25, 0x9084: 0x63A8, 0x9085: 0x6C34, 0x9086: 0x708A, 0x9087: 0x7761, 0x9088: 0x7C8B, 0x9089: 0x7FE0, 0x908A: 0x8870, 0x908B: 0x9042, 0x908C: 0x9154, 0x908D: 0x9310, 0x908E: 0x9318, 0x908F: 0x968F, 0x9090: 0x745E, 0x9091: 0x9AC4, 0x9092: 0x5D07, 0x9093: 0x5D69, 0x9094: 0x6570, 0x9095: 0x67A2, 0x9096: 0x8DA8, 0x9097: 0x96DB, 0x9098: 0x636E, 0x9099: 0x6749, 0x909A: 0x6919, 0x909B: 0x83C5, 0x909C: 0x9817, 0x909D: 0x96C0, 0x909E: 0x88FE, 0x909F: 0x6F84, 0x90A0: 0x647A, 0x90A1: 0x5BF8, 0x90A2: 0x4E16, 0x90A3: 0x702C, 0x90A4: 0x755D, 0x90A5: 0x662F, 0x90A6: 0x51C4, 0x90A7: 0x5236, 0x90A8: 0x52E2, 0x90A9: 0x59D3, 0x90AA: 0x5F81, 0x90AB: 0x6027, 0x90AC: 0x6210, 0x90AD: 0x653F, 0x90AE: 0x6574, 0x90AF: 0x661F, 0x90B0: 0x6674, 0x90B1: 0x68F2, 0x90B2: 0x6816, 0x90B3: 0x6B63, 0x90B4: 0x6E05, 0x90B5: 0x7272, 0x90B6: 0x751F, 0x90B7: 0x76DB, 0x90B8: 0x7CBE, 0x90B9: 0x8056, 0x90BA: 0x58F0, 0x90BB: 0x88FD, 0x90BC: 0x897F, 0x90BD: 0x8AA0, 0x90BE: 0x8A93, 0x90BF: 0x8ACB, 0x90C0: 0x901D, 0x90C1: 0x9192, 0x90C2: 0x9752, 0x90C3: 0x9759, 0x90C4: 0x6589, 0x90C5: 0x7A0E, 0x90C6: 0x8106, 0x90C7: 0x96BB, 0x90C8: 0x5E2D, 0x90C9: 0x60DC, 0x90CA: 0x621A, 0x90CB: 0x65A5, 0x90CC: 0x6614, 0x90CD: 0x6790, 0x90CE: 0x77F3, 0x90CF: 0x7A4D, 0x90D0: 0x7C4D, 0x90D1: 0x7E3E, 0x90D2: 0x810A, 0x90D3: 0x8CAC, 0x90D4: 0x8D64, 0x90D5: 0x8DE1, 0x90D6: 0x8E5F, 0x90D7: 0x78A9, 0x90D8: 0x5207, 0x90D9: 0x62D9, 0x90DA: 0x63A5, 0x90DB: 0x6442, 0x90DC: 0x6298, 0x90DD: 0x8A2D, 0x90DE: 0x7A83, 0x90DF: 0x7BC0, 0x90E0: 0x8AAC, 0x90E1: 0x96EA, 0x90E2: 0x7D76, 0x90E3: 0x820C, 0x90E4: 0x8749, 0x90E5: 0x4ED9, 0x90E6: 0x5148, 0x90E7: 0x5343, 0x90E8: 0x5360, 0x90E9: 0x5BA3, 0x90EA: 0x5C02, 0x90EB: 0x5C16, 0x90EC: 0x5DDD, 0x90ED: 0x6226, 0x90EE: 0x6247, 0x90EF: 0x64B0, 0x90F0: 0x6813, 0x90F1: 0x6834, 0x90F2: 0x6CC9, 0x90F3: 0x6D45, 0x90F4: 0x6D17, 0x90F5: 0x67D3, 0x90F6: 0x6F5C, 0x90F7: 0x714E, 0x90F8: 0x717D, 0x90F9: 0x65CB, 0x90FA: 0x7A7F, 0x90FB: 0x7BAD, 0x90FC: 0x7DDA, 0x9140: 0x7E4A, 0x9141: 0x7FA8, 0x9142: 0x817A, 0x9143: 0x821B, 0x9144: 0x8239, 0x9145: 0x85A6, 0x9146: 0x8A6E, 0x9147: 0x8CCE, 0x9148: 0x8DF5, 0x9149: 0x9078, 0x914A: 0x9077, 0x914B: 0x92AD, 0x914C: 0x9291, 0x914D: 0x9583, 0x914E: 0x9BAE, 0x914F: 0x524D, 0x9150: 0x5584, 0x9151: 0x6F38, 0x9152: 0x7136, 0x9153: 0x5168, 0x9154: 0x7985, 0x9155: 0x7E55, 0x9156: 0x81B3, 0x9157: 0x7CCE, 0x9158: 0x564C, 0x9159: 0x5851, 0x915A: 0x5CA8, 0x915B: 0x63AA, 0x915C: 0x66FE, 0x915D: 0x66FD, 0x915E: 0x695A, 0x915F: 0x72D9, 0x9160: 0x758F, 0x9161: 0x758E, 0x9162: 0x790E, 0x9163: 0x7956, 0x9164: 0x79DF, 0x9165: 0x7C97, 0x9166: 0x7D20, 0x9167: 0x7D44, 0x9168: 0x8607, 0x9169: 0x8A34, 0x916A: 0x963B, 0x916B: 0x9061, 0x916C: 0x9F20, 0x916D: 0x50E7, 0x916E: 0x5275, 0x916F: 0x53CC, 0x9170: 0x53E2, 0x9171: 0x5009, 0x9172: 0x55AA, 0x9173: 0x58EE, 0x9174: 0x594F, 0x9175: 0x723D, 0x9176: 0x5B8B, 0x9177: 0x5C64, 0x9178: 0x531D, 0x9179: 0x60E3, 0x917A: 0x60F3, 0x917B: 0x635C, 0x917C: 0x6383, 0x917D: 0x633F, 0x917E: 0x63BB, 0x9180: 0x64CD, 0x9181: 0x65E9, 0x9182: 0x66F9, 0x9183: 0x5DE3, 0x9184: 0x69CD, 0x9185: 0x69FD, 0x9186: 0x6F15, 0x9187: 0x71E5, 0x9188: 0x4E89, 0x9189: 0x75E9, 0x918A: 0x76F8, 0x918B: 0x7A93, 0x918C: 0x7CDF, 0x918D: 0x7DCF, 0x918E: 0x7D9C, 0x918F: 0x8061, 0x9190: 0x8349, 0x9191: 0x8358, 0x9192: 0x846C, 0x9193: 0x84BC, 0x9194: 0x85FB, 0x9195: 0x88C5, 0x9196: 0x8D70, 0x9197: 0x9001, 0x9198: 0x906D, 0x9199: 0x9397, 0x919A: 0x971C, 0x919B: 0x9A12, 0x919C: 0x50CF, 0x919D: 0x5897, 0x919E: 0x618E, 0x919F: 0x81D3, 0x91A0: 0x8535, 0x91A1: 0x8D08, 0x91A2: 0x9020, 0x91A3: 0x4FC3, 0x91A4: 0x5074, 0x91A5: 0x5247, 0x91A6: 0x5373, 0x91A7: 0x606F, 0x91A8: 0x6349, 0x91A9: 0x675F, 0x91AA: 0x6E2C, 0x91AB: 0x8DB3, 0x91AC: 0x901F, 0x91AD: 0x4FD7, 0x91AE: 0x5C5E, 0x91AF: 0x8CCA, 0x91B0: 0x65CF, 0x91B1: 0x7D9A, 0x91B2: 0x5352, 0x91B3: 0x8896, 0x91B4: 0x5176, 0x91B5: 0x63C3, 0x91B6: 0x5B58, 0x91B7: 0x5B6B, 0x91B8: 0x5C0A, 0x91B9: 0x640D, 0x91BA: 0x6751, 0x91BB: 0x905C, 0x91BC: 0x4ED6, 0x91BD: 0x591A, 0x91BE: 0x592A, 0x91BF: 0x6C70, 0x91C0: 0x8A51, 0x91C1: 0x553E, 0x91C2: 0x5815, 0x91C3: 0x59A5, 0x91C4: 0x60F0, 0x91C5: 0x6253, 0x91C6: 0x67C1, 0x91C7: 0x8235, 0x91C8: 0x6955, 0x91C9: 0x9640, 0x91CA: 0x99C4, 0x91CB: 0x9A28, 0x91CC: 0x4F53, 0x91CD: 0x5806, 0x91CE: 0x5BFE, 0x91CF: 0x8010, 0x91D0: 0x5CB1, 0x91D1: 0x5E2F, 0x91D2: 0x5F85, 0x91D3: 0x6020, 0x91D4: 0x614B, 0x91D5: 0x6234, 0x91D6: 0x66FF, 0x91D7: 0x6CF0, 0x91D8: 0x6EDE, 0x91D9: 0x80CE, 0x91DA: 0x817F, 0x91DB: 0x82D4, 0x91DC: 0x888B, 0x91DD: 0x8CB8, 0x91DE: 0x9000, 0x91DF: 0x902E, 0x91E0: 0x968A, 0x91E1: 0x9EDB, 0x91E2: 0x9BDB, 0x91E3: 0x4EE3, 0x91E4: 0x53F0, 0x91E5: 0x5927, 0x91E6: 0x7B2C, 0x91E7: 0x918D, 0x91E8: 0x984C, 0x91E9: 0x9DF9, 0x91EA: 0x6EDD, 0x91EB: 0x7027, 0x91EC: 0x5353, 0x91ED: 0x5544, 0x91EE: 0x5B85, 0x91EF: 0x6258, 0x91F0: 0x629E, 0x91F1: 0x62D3, 0x91F2: 0x6CA2, 0x91F3: 0x6FEF, 0x91F4: 0x7422, 0x91F5: 0x8A17, 0x91F6: 0x9438, 0x91F7: 0x6FC1, 0x91F8: 0x8AFE, 0x91F9: 0x8338, 0x91FA: 0x51E7, 0x91FB: 0x86F8, 0x91FC: 0x53EA, 0x9240: 0x53E9, 0x9241: 0x4F46, 0x9242: 0x9054, 0x9243: 0x8FB0, 0x9244: 0x596A, 0x9245: 0x8131, 0x9246: 0x5DFD, 0x9247: 0x7AEA, 0x9248: 0x8FBF, 0x9249: 0x68DA, 0x924A: 0x8C37, 0x924B: 0x72F8, 0x924C: 0x9C48, 0x924D: 0x6A3D, 0x924E: 0x8AB0, 0x924F: 0x4E39, 0x9250: 0x5358, 0x9251: 0x5606, 0x9252: 0x5766, 0x9253: 0x62C5, 0x9254: 0x63A2, 0x9255: 0x65E6, 0x9256: 0x6B4E, 0x9257: 0x6DE1, 0x9258: 0x6E5B, 0x9259: 0x70AD, 0x925A: 0x77ED, 0x925B: 0x7AEF, 0x925C: 0x7BAA, 0x925D: 0x7DBB, 0x925E: 0x803D, 0x925F: 0x80C6, 0x9260: 0x86CB, 0x9261: 0x8A95, 0x9262: 0x935B, 0x9263: 0x56E3, 0x9264: 0x58C7, 0x9265: 0x5F3E, 0x9266: 0x65AD, 0x9267: 0x6696, 0x9268: 0x6A80, 0x9269: 0x6BB5, 0x926A: 0x7537, 0x926B: 0x8AC7, 0x926C: 0x5024, 0x926D: 0x77E5, 0x926E: 0x5730, 0x926F: 0x5F1B, 0x9270: 0x6065, 0x9271: 0x667A, 0x9272: 0x6C60, 0x9273: 0x75F4, 0x9274: 0x7A1A, 0x9275: 0x7F6E, 0x9276: 0x81F4, 0x9277: 0x8718, 0x9278: 0x9045, 0x9279: 0x99B3, 0x927A: 0x7BC9, 0x927B: 0x755C, 0x927C: 0x7AF9, 0x927D: 0x7B51, 0x927E: 0x84C4, 0x9280: 0x9010, 0x9281: 0x79E9, 0x9282: 0x7A92, 0x9283: 0x8336, 0x9284: 0x5AE1, 0x9285: 0x7740, 0x9286: 0x4E2D, 0x9287: 0x4EF2, 0x9288: 0x5B99, 0x9289: 0x5FE0, 0x928A: 0x62BD, 0x928B: 0x663C, 0x928C: 0x67F1, 0x928D: 0x6CE8, 0x928E: 0x866B, 0x928F: 0x8877, 0x9290: 0x8A3B, 0x9291: 0x914E, 0x9292: 0x92F3, 0x9293: 0x99D0, 0x9294: 0x6A17, 0x9295: 0x7026, 0x9296: 0x732A, 0x9297: 0x82E7, 0x9298: 0x8457, 0x9299: 0x8CAF, 0x929A: 0x4E01, 0x929B: 0x5146, 0x929C: 0x51CB, 0x929D: 0x558B, 0x929E: 0x5BF5, 0x929F: 0x5E16, 0x92A0: 0x5E33, 0x92A1: 0x5E81, 0x92A2: 0x5F14, 0x92A3: 0x5F35, 0x92A4: 0x5F6B, 0x92A5: 0x5FB4, 0x92A6: 0x61F2, 0x92A7: 0x6311, 0x92A8: 0x66A2, 0x92A9: 0x671D, 0x92AA: 0x6F6E, 0x92AB: 0x7252, 0x92AC: 0x753A, 0x92AD: 0x773A, 0x92AE: 0x8074, 0x92AF: 0x8139, 0x92B0: 0x8178, 0x92B1: 0x8776, 0x92B2: 0x8ABF, 0x92B3: 0x8ADC, 0x92B4: 0x8D85, 0x92B5: 0x8DF3, 0x92B6: 0x929A, 0x92B7: 0x9577, 0x92B8: 0x9802, 0x92B9: 0x9CE5, 0x92BA: 0x52C5, 0x92BB: 0x6357, 0x92BC: 0x76F4, 0x92BD: 0x6715, 0x92BE: 0x6C88, 0x92BF: 0x73CD, 0x92C0: 0x8CC3, 0x92C1: 0x93AE, 0x92C2: 0x9673, 0x92C3: 0x6D25, 0x92C4: 0x589C, 0x92C5: 0x690E, 0x92C6: 0x69CC, 0x92C7: 0x8FFD, 0x92C8: 0x939A, 0x92C9: 0x75DB, 0x92CA: 0x901A, 0x92CB: 0x585A, 0x92CC: 0x6802, 0x92CD: 0x63B4, 0x92CE: 0x69FB, 0x92CF: 0x4F43, 0x92D0: 0x6F2C, 0x92D1: 0x67D8, 0x92D2: 0x8FBB, 0x92D3: 0x8526, 0x92D4: 0x7DB4, 0x92D5: 0x9354, 0x92D6: 0x693F, 0x92D7: 0x6F70, 0x92D8: 0x576A, 0x92D9: 0x58F7, 0x92DA: 0x5B2C, 0x92DB: 0x7D2C, 0x92DC: 0x722A, 0x92DD: 0x540A, 0x92DE: 0x91E3, 0x92DF: 0x9DB4, 0x92E0: 0x4EAD, 0x92E1: 0x4F4E, 0x92E2: 0x505C, 0x92E3: 0x5075, 0x92E4: 0x5243, 0x92E5: 0x8C9E, 0x92E6: 0x5448, 0x92E7: 0x5824, 0x92E8: 0x5B9A, 0x92E9: 0x5E1D, 0x92EA: 0x5E95, 0x92EB: 0x5EAD, 0x92EC: 0x5EF7, 0x92ED: 0x5F1F, 0x92EE: 0x608C, 0x92EF: 0x62B5, 0x92F0: 0x633A, 0x92F1: 0x63D0, 0x92F2: 0x68AF, 0x92F3: 0x6C40, 0x92F4: 0x7887, 0x92F5: 0x798E, 0x92F6: 0x7A0B, 0x92F7: 0x7DE0, 0x92F8: 0x8247, 0x92F9: 0x8A02, 0x92FA: 0x8AE6, 0x92FB: 0x8E44, 0x92FC: 0x9013, 0x9340: 0x90B8, 0x9341: 0x912D, 0x9342: 0x91D8, 0x9343: 0x9F0E, 0x9344: 0x6CE5, 0x9345: 0x6458, 0x9346: 0x64E2, 0x9347: 0x6575, 0x9348: 0x6EF4, 0x9349: 0x7684, 0x934A: 0x7B1B, 0x934B: 0x9069, 0x934C: 0x93D1, 0x934D: 0x6EBA, 0x934E: 0x54F2, 0x934F: 0x5FB9, 0x9350: 0x64A4, 0x9351: 0x8F4D, 0x9352: 0x8FED, 0x9353: 0x9244, 0x9354: 0x5178, 0x9355: 0x586B, 0x9356: 0x5929, 0x9357: 0x5C55, 0x9358: 0x5E97, 0x9359: 0x6DFB, 0x935A: 0x7E8F, 0x935B: 0x751C, 0x935C: 0x8CBC, 0x935D: 0x8EE2, 0x935E: 0x985B, 0x935F: 0x70B9, 0x9360: 0x4F1D, 0x9361: 0x6BBF, 0x9362: 0x6FB1, 0x9363: 0x7530, 0x9364: 0x96FB, 0x9365: 0x514E, 0x9366: 0x5410, 0x9367: 0x5835, 0x9368: 0x5857, 0x9369: 0x59AC, 0x936A: 0x5C60, 0x936B: 0x5F92, 0x936C: 0x6597, 0x936D: 0x675C, 0x936E: 0x6E21, 0x936F: 0x767B, 0x9370: 0x83DF, 0x9371: 0x8CED, 0x9372: 0x9014, 0x9373: 0x90FD, 0x9374: 0x934D, 0x9375: 0x7825, 0x9376: 0x783A, 0x9377: 0x52AA, 0x9378: 0x5EA6, 0x9379: 0x571F, 0x937A: 0x5974, 0x937B: 0x6012, 0x937C: 0x5012, 0x937D: 0x515A, 0x937E: 0x51AC, 0x9380: 0x51CD, 0x9381: 0x5200, 0x9382: 0x5510, 0x9383: 0x5854, 0x9384: 0x5858, 0x9385: 0x5957, 0x9386: 0x5B95, 0x9387: 0x5CF6, 0x9388: 0x5D8B, 0x9389: 0x60BC, 0x938A: 0x6295, 0x938B: 0x642D, 0x938C: 0x6771, 0x938D: 0x6843, 0x938E: 0x68BC, 0x938F: 0x68DF, 0x9390: 0x76D7, 0x9391: 0x6DD8, 0x9392: 0x6E6F, 0x9393: 0x6D9B, 0x9394: 0x706F, 0x9395: 0x71C8, 0x9396: 0x5F53, 0x9397: 0x75D8, 0x9398: 0x7977, 0x9399: 0x7B49, 0x939A: 0x7B54, 0x939B: 0x7B52, 0x939C: 0x7CD6, 0x939D: 0x7D71, 0x939E: 0x5230, 0x939F: 0x8463, 0x93A0: 0x8569, 0x93A1: 0x85E4, 0x93A2: 0x8A0E, 0x93A3: 0x8B04, 0x93A4: 0x8C46, 0x93A5: 0x8E0F, 0x93A6: 0x9003, 0x93A7: 0x900F, 0x93A8: 0x9419, 0x93A9: 0x9676, 0x93AA: 0x982D, 0x93AB: 0x9A30, 0x93AC: 0x95D8, 0x93AD: 0x50CD, 0x93AE: 0x52D5, 0x93AF: 0x540C, 0x93B0: 0x5802, 0x93B1: 0x5C0E, 0x93B2: 0x61A7, 0x93B3: 0x649E, 0x93B4: 0x6D1E, 0x93B5: 0x77B3, 0x93B6: 0x7AE5, 0x93B7: 0x80F4, 0x93B8: 0x8404, 0x93B9: 0x9053, 0x93BA: 0x9285, 0x93BB: 0x5CE0, 0x93BC: 0x9D07, 0x93BD: 0x533F, 0x93BE: 0x5F97, 0x93BF: 0x5FB3, 0x93C0: 0x6D9C, 0x93C1: 0x7279, 0x93C2: 0x7763, 0x93C3: 0x79BF, 0x93C4: 0x7BE4, 0x93C5: 0x6BD2, 0x93C6: 0x72EC, 0x93C7: 0x8AAD, 0x93C8: 0x6803, 0x93C9: 0x6A61, 0x93CA: 0x51F8, 0x93CB: 0x7A81, 0x93CC: 0x6934, 0x93CD: 0x5C4A, 0x93CE: 0x9CF6, 0x93CF: 0x82EB, 0x93D0: 0x5BC5, 0x93D1: 0x9149, 0x93D2: 0x701E, 0x93D3: 0x5678, 0x93D4: 0x5C6F, 0x93D5: 0x60C7, 0x93D6: 0x6566, 0x93D7: 0x6C8C, 0x93D8: 0x8C5A, 0x93D9: 0x9041, 0x93DA: 0x9813, 0x93DB: 0x5451, 0x93DC: 0x66C7, 0x93DD: 0x920D, 0x93DE: 0x5948, 0x93DF: 0x90A3, 0x93E0: 0x5185, 0x93E1: 0x4E4D, 0x93E2: 0x51EA, 0x93E3: 0x8599, 0x93E4: 0x8B0E, 0x93E5: 0x7058, 0x93E6: 0x637A, 0x93E7: 0x934B, 0x93E8: 0x6962, 0x93E9: 0x99B4, 0x93EA: 0x7E04, 0x93EB: 0x7577, 0x93EC: 0x5357, 0x93ED: 0x6960, 0x93EE: 0x8EDF, 0x93EF: 0x96E3, 0x93F0: 0x6C5D, 0x93F1: 0x4E8C, 0x93F2: 0x5C3C, 0x93F3: 0x5F10, 0x93F4: 0x8FE9, 0x93F5: 0x5302, 0x93F6: 0x8CD1, 0x93F7: 0x8089, 0x93F8: 0x8679, 0x93F9: 0x5EFF, 0x93FA: 0x65E5, 0x93FB: 0x4E73, 0x93FC: 0x5165, 0x9440: 0x5982, 0x9441: 0x5C3F, 0x9442: 0x97EE, 0x9443: 0x4EFB, 0x9444: 0x598A, 0x9445: 0x5FCD, 0x9446: 0x8A8D, 0x9447: 0x6FE1, 0x9448: 0x79B0, 0x9449: 0x7962, 0x944A: 0x5BE7, 0x944B: 0x8471, 0x944C: 0x732B, 0x944D: 0x71B1, 0x944E: 0x5E74, 0x944F: 0x5FF5, 0x9450: 0x637B, 0x9451: 0x649A, 0x9452: 0x71C3, 0x9453: 0x7C98, 0x9454: 0x4E43, 0x9455: 0x5EFC, 0x9456: 0x4E4B, 0x9457: 0x57DC, 0x9458: 0x56A2, 0x9459: 0x60A9, 0x945A: 0x6FC3, 0x945B: 0x7D0D, 0x945C: 0x80FD, 0x945D: 0x8133, 0x945E: 0x81BF, 0x945F: 0x8FB2, 0x9460: 0x8997, 0x9461: 0x86A4, 0x9462: 0x5DF4, 0x9463: 0x628A, 0x9464: 0x64AD, 0x9465: 0x8987, 0x9466: 0x6777, 0x9467: 0x6CE2, 0x9468: 0x6D3E, 0x9469: 0x7436, 0x946A: 0x7834, 0x946B: 0x5A46, 0x946C: 0x7F75, 0x946D: 0x82AD, 0x946E: 0x99AC, 0x946F: 0x4FF3, 0x9470: 0x5EC3, 0x9471: 0x62DD, 0x9472: 0x6392, 0x9473: 0x6557, 0x9474: 0x676F, 0x9475: 0x76C3, 0x9476: 0x724C, 0x9477: 0x80CC, 0x9478: 0x80BA, 0x9479: 0x8F29, 0x947A: 0x914D, 0x947B: 0x500D, 0x947C: 0x57F9, 0x947D: 0x5A92, 0x947E: 0x6885, 0x9480: 0x6973, 0x9481: 0x7164, 0x9482: 0x72FD, 0x9483: 0x8CB7, 0x9484: 0x58F2, 0x9485: 0x8CE0, 0x9486: 0x966A, 0x9487: 0x9019, 0x9488: 0x877F, 0x9489: 0x79E4, 0x948A: 0x77E7, 0x948B: 0x8429, 0x948C: 0x4F2F, 0x948D: 0x5265, 0x948E: 0x535A, 0x948F: 0x62CD, 0x9490: 0x67CF, 0x9491: 0x6CCA, 0x9492: 0x767D, 0x9493: 0x7B94, 0x9494: 0x7C95, 0x9495: 0x8236, 0x9496: 0x8584, 0x9497: 0x8FEB, 0x9498: 0x66DD, 0x9499: 0x6F20, 0x949A: 0x7206, 0x949B: 0x7E1B, 0x949C: 0x83AB, 0x949D: 0x99C1, 0x949E: 0x9EA6, 0x949F: 0x51FD, 0x94A0: 0x7BB1, 0x94A1: 0x7872, 0x94A2: 0x7BB8, 0x94A3: 0x8087, 0x94A4: 0x7B48, 0x94A5: 0x6AE8, 0x94A6: 0x5E61, 0x94A7: 0x808C, 0x94A8: 0x7551, 0x94A9: 0x7560, 0x94AA: 0x516B, 0x94AB: 0x9262, 0x94AC: 0x6E8C, 0x94AD: 0x767A, 0x94AE: 0x9197, 0x94AF: 0x9AEA, 0x94B0: 0x4F10, 0x94B1: 0x7F70, 0x94B2: 0x629C, 0x94B3: 0x7B4F, 0x94B4: 0x95A5, 0x94B5: 0x9CE9, 0x94B6: 0x567A, 0x94B7: 0x5859, 0x94B8: 0x86E4, 0x94B9: 0x96BC, 0x94BA: 0x4F34, 0x94BB: 0x5224, 0x94BC: 0x534A, 0x94BD: 0x53CD, 0x94BE: 0x53DB, 0x94BF: 0x5E06, 0x94C0: 0x642C, 0x94C1: 0x6591, 0x94C2: 0x677F, 0x94C3: 0x6C3E, 0x94C4: 0x6C4E, 0x94C5: 0x7248, 0x94C6: 0x72AF, 0x94C7: 0x73ED, 0x94C8: 0x7554, 0x94C9: 0x7E41, 0x94CA: 0x822C, 0x94CB: 0x85E9, 0x94CC: 0x8CA9, 0x94CD: 0x7BC4, 0x94CE: 0x91C6, 0x94CF: 0x7169, 0x94D0: 0x9812, 0x94D1: 0x98EF, 0x94D2: 0x633D, 0x94D3: 0x6669, 0x94D4: 0x756A, 0x94D5: 0x76E4, 0x94D6: 0x78D0, 0x94D7: 0x8543, 0x94D8: 0x86EE, 0x94D9: 0x532A, 0x94DA: 0x5351, 0x94DB: 0x5426, 0x94DC: 0x5983, 0x94DD: 0x5E87, 0x94DE: 0x5F7C, 0x94DF: 0x60B2, 0x94E0: 0x6249, 0x94E1: 0x6279, 0x94E2: 0x62AB, 0x94E3: 0x6590, 0x94E4: 0x6BD4, 0x94E5: 0x6CCC, 0x94E6: 0x75B2, 0x94E7: 0x76AE, 0x94E8: 0x7891, 0x94E9: 0x79D8, 0x94EA: 0x7DCB, 0x94EB: 0x7F77, 0x94EC: 0x80A5, 0x94ED: 0x88AB, 0x94EE: 0x8AB9, 0x94EF: 0x8CBB, 0x94F0: 0x907F, 0x94F1: 0x975E, 0x94F2: 0x98DB, 0x94F3: 0x6A0B, 0x94F4: 0x7C38, 0x94F5: 0x5099, 0x94F6: 0x5C3E, 0x94F7: 0x5FAE, 0x94F8: 0x6787, 0x94F9: 0x6BD8, 0x94FA: 0x7435, 0x94FB: 0x7709, 0x94FC: 0x7F8E, 0x9540: 0x9F3B, 0x9541: 0x67CA, 0x9542: 0x7A17, 0x9543: 0x5339, 0x9544: 0x758B, 0x9545: 0x9AED, 0x9546: 0x5F66, 0x9547: 0x819D, 0x9548: 0x83F1, 0x9549: 0x8098, 0x954A: 0x5F3C, 0x954B: 0x5FC5, 0x954C: 0x7562, 0x954D: 0x7B46, 0x954E: 0x903C, 0x954F: 0x6867, 0x9550: 0x59EB, 0x9551: 0x5A9B, 0x9552: 0x7D10, 0x9553: 0x767E, 0x9554: 0x8B2C, 0x9555: 0x4FF5, 0x9556: 0x5F6A, 0x9557: 0x6A19, 0x9558: 0x6C37, 0x9559: 0x6F02, 0x955A: 0x74E2, 0x955B: 0x7968, 0x955C: 0x8868, 0x955D: 0x8A55, 0x955E: 0x8C79, 0x955F: 0x5EDF, 0x9560: 0x63CF, 0x9561: 0x75C5, 0x9562: 0x79D2, 0x9563: 0x82D7, 0x9564: 0x9328, 0x9565: 0x92F2, 0x9566: 0x849C, 0x9567: 0x86ED, 0x9568: 0x9C2D, 0x9569: 0x54C1, 0x956A: 0x5F6C, 0x956B: 0x658C, 0x956C: 0x6D5C, 0x956D: 0x7015, 0x956E: 0x8CA7, 0x956F: 0x8CD3, 0x9570: 0x983B, 0x9571: 0x654F, 0x9572: 0x74F6, 0x9573: 0x4E0D, 0x9574: 0x4ED8, 0x9575: 0x57E0, 0x9576: 0x592B, 0x9577: 0x5A66, 0x9578: 0x5BCC, 0x9579: 0x51A8, 0x957A: 0x5E03, 0x957B: 0x5E9C, 0x957C: 0x6016, 0x957D: 0x6276, 0x957E: 0x6577, 0x9580: 0x65A7, 0x9581: 0x666E, 0x9582: 0x6D6E, 0x9583: 0x7236, 0x9584: 0x7B26, 0x9585: 0x8150, 0x9586: 0x819A, 0x9587: 0x8299, 0x9588: 0x8B5C, 0x9589: 0x8CA0, 0x958A: 0x8CE6, 0x958B: 0x8D74, 0x958C: 0x961C, 0x958D: 0x9644, 0x958E: 0x4FAE, 0x958F: 0x64AB, 0x9590: 0x6B66, 0x9591: 0x821E, 0x9592: 0x8461, 0x9593: 0x856A, 0x9594: 0x90E8, 0x9595: 0x5C01, 0x9596: 0x6953, 0x9597: 0x98A8, 0x9598: 0x847A, 0x9599: 0x8557, 0x959A: 0x4F0F, 0x959B: 0x526F, 0x959C: 0x5FA9, 0x959D: 0x5E45, 0x959E: 0x670D, 0x959F: 0x798F, 0x95A0: 0x8179, 0x95A1: 0x8907, 0x95A2: 0x8986, 0x95A3: 0x6DF5, 0x95A4: 0x5F17, 0x95A5: 0x6255, 0x95A6: 0x6CB8, 0x95A7: 0x4ECF, 0x95A8: 0x7269, 0x95A9: 0x9B92, 0x95AA: 0x5206, 0x95AB: 0x543B, 0x95AC: 0x5674, 0x95AD: 0x58B3, 0x95AE: 0x61A4, 0x95AF: 0x626E, 0x95B0: 0x711A, 0x95B1: 0x596E, 0x95B2: 0x7C89, 0x95B3: 0x7CDE, 0x95B4: 0x7D1B, 0x95B5: 0x96F0, 0x95B6: 0x6587, 0x95B7: 0x805E, 0x95B8: 0x4E19, 0x95B9: 0x4F75, 0x95BA: 0x5175, 0x95BB: 0x5840, 0x95BC: 0x5E63, 0x95BD: 0x5E73, 0x95BE: 0x5F0A, 0x95BF: 0x67C4, 0x95C0: 0x4E26, 0x95C1: 0x853D, 0x95C2: 0x9589, 0x95C3: 0x965B, 0x95C4: 0x7C73, 0x95C5: 0x9801, 0x95C6: 0x50FB, 0x95C7: 0x58C1, 0x95C8: 0x7656, 0x95C9: 0x78A7, 0x95CA: 0x5225, 0x95CB: 0x77A5, 0x95CC: 0x8511, 0x95CD: 0x7B86, 0x95CE: 0x504F, 0x95CF: 0x5909, 0x95D0: 0x7247, 0x95D1: 0x7BC7, 0x95D2: 0x7DE8, 0x95D3: 0x8FBA, 0x95D4: 0x8FD4, 0x95D5: 0x904D, 0x95D6: 0x4FBF, 0x95D7: 0x52C9, 0x95D8: 0x5A29, 0x95D9: 0x5F01, 0x95DA: 0x97AD, 0x95DB: 0x4FDD, 0x95DC: 0x8217, 0x95DD: 0x92EA, 0x95DE: 0x5703, 0x95DF: 0x6355, 0x95E0: 0x6B69, 0x95E1: 0x752B, 0x95E2: 0x88DC, 0x95E3: 0x8F14, 0x95E4: 0x7A42, 0x95E5: 0x52DF, 0x95E6: 0x5893, 0x95E7: 0x6155, 0x95E8: 0x620A, 0x95E9: 0x66AE, 0x95EA: 0x6BCD, 0x95EB: 0x7C3F, 0x95EC: 0x83E9, 0x95ED: 0x5023, 0x95EE: 0x4FF8, 0x95EF: 0x5305, 0x95F0: 0x5446, 0x95F1: 0x5831, 0x95F2: 0x5949, 0x95F3: 0x5B9D, 0x95F4: 0x5CF0, 0x95F5: 0x5CEF, 0x95F6: 0x5D29, 0x95F7: 0x5E96, 0x95F8: 0x62B1, 0x95F9: 0x6367, 0x95FA: 0x653E, 0x95FB: 0x65B9, 0x95FC: 0x670B, 0x9640: 0x6CD5, 0x9641: 0x6CE1, 0x9642: 0x70F9, 0x9643: 0x7832, 0x9644: 0x7E2B, 0x9645: 0x80DE, 0x9646: 0x82B3, 0x9647: 0x840C, 0x9648: 0x84EC, 0x9649: 0x8702, 0x964A: 0x8912, 0x964B: 0x8A2A, 0x964C: 0x8C4A, 0x964D: 0x90A6, 0x964E: 0x92D2, 0x964F: 0x98FD, 0x9650: 0x9CF3, 0x9651: 0x9D6C, 0x9652: 0x4E4F, 0x9653: 0x4EA1, 0x9654: 0x508D, 0x9655: 0x5256, 0x9656: 0x574A, 0x9657: 0x59A8, 0x9658: 0x5E3D, 0x9659: 0x5FD8, 0x965A: 0x5FD9, 0x965B: 0x623F, 0x965C: 0x66B4, 0x965D: 0x671B, 0x965E: 0x67D0, 0x965F: 0x68D2, 0x9660: 0x5192, 0x9661: 0x7D21, 0x9662: 0x80AA, 0x9663: 0x81A8, 0x9664: 0x8B00, 0x9665: 0x8C8C, 0x9666: 0x8CBF, 0x9667: 0x927E, 0x9668: 0x9632, 0x9669: 0x5420, 0x966A: 0x982C, 0x966B: 0x5317, 0x966C: 0x50D5, 0x966D: 0x535C, 0x966E: 0x58A8, 0x966F: 0x64B2, 0x9670: 0x6734, 0x9671: 0x7267, 0x9672: 0x7766, 0x9673: 0x7A46, 0x9674: 0x91E6, 0x9675: 0x52C3, 0x9676: 0x6CA1, 0x9677: 0x6B86, 0x9678: 0x5800, 0x9679: 0x5E4C, 0x967A: 0x5954, 0x967B: 0x672C, 0x967C: 0x7FFB, 0x967D: 0x51E1, 0x967E: 0x76C6, 0x9680: 0x6469, 0x9681: 0x78E8, 0x9682: 0x9B54, 0x9683: 0x9EBB, 0x9684: 0x57CB, 0x9685: 0x59B9, 0x9686: 0x6627, 0x9687: 0x679A, 0x9688: 0x6BCE, 0x9689: 0x54E9, 0x968A: 0x69D9, 0x968B: 0x5E55, 0x968C: 0x819C, 0x968D: 0x6795, 0x968E: 0x9BAA, 0x968F: 0x67FE, 0x9690: 0x9C52, 0x9691: 0x685D, 0x9692: 0x4EA6, 0x9693: 0x4FE3, 0x9694: 0x53C8, 0x9695: 0x62B9, 0x9696: 0x672B, 0x9697: 0x6CAB, 0x9698: 0x8FC4, 0x9699: 0x4FAD, 0x969A: 0x7E6D, 0x969B: 0x9EBF, 0x969C: 0x4E07, 0x969D: 0x6162, 0x969E: 0x6E80, 0x969F: 0x6F2B, 0x96A0: 0x8513, 0x96A1: 0x5473, 0x96A2: 0x672A, 0x96A3: 0x9B45, 0x96A4: 0x5DF3, 0x96A5: 0x7B95, 0x96A6: 0x5CAC, 0x96A7: 0x5BC6, 0x96A8: 0x871C, 0x96A9: 0x6E4A, 0x96AA: 0x84D1, 0x96AB: 0x7A14, 0x96AC: 0x8108, 0x96AD: 0x5999, 0x96AE: 0x7C8D, 0x96AF: 0x6C11, 0x96B0: 0x7720, 0x96B1: 0x52D9, 0x96B2: 0x5922, 0x96B3: 0x7121, 0x96B4: 0x725F, 0x96B5: 0x77DB, 0x96B6: 0x9727, 0x96B7: 0x9D61, 0x96B8: 0x690B, 0x96B9: 0x5A7F, 0x96BA: 0x5A18, 0x96BB: 0x51A5, 0x96BC: 0x540D, 0x96BD: 0x547D, 0x96BE: 0x660E, 0x96BF: 0x76DF, 0x96C0: 0x8FF7, 0x96C1: 0x9298, 0x96C2: 0x9CF4, 0x96C3: 0x59EA, 0x96C4: 0x725D, 0x96C5: 0x6EC5, 0x96C6: 0x514D, 0x96C7: 0x68C9, 0x96C8: 0x7DBF, 0x96C9: 0x7DEC, 0x96CA: 0x9762, 0x96CB: 0x9EBA, 0x96CC: 0x6478, 0x96CD: 0x6A21, 0x96CE: 0x8302, 0x96CF: 0x5984, 0x96D0: 0x5B5F, 0x96D1: 0x6BDB, 0x96D2: 0x731B, 0x96D3: 0x76F2, 0x96D4: 0x7DB2, 0x96D5: 0x8017, 0x96D6: 0x8499, 0x96D7: 0x5132, 0x96D8: 0x6728, 0x96D9: 0x9ED9, 0x96DA: 0x76EE, 0x96DB: 0x6762, 0x96DC: 0x52FF, 0x96DD: 0x9905, 0x96DE: 0x5C24, 0x96DF: 0x623B, 0x96E0: 0x7C7E, 0x96E1: 0x8CB0, 0x96E2: 0x554F, 0x96E3: 0x60B6, 0x96E4: 0x7D0B, 0x96E5: 0x9580, 0x96E6: 0x5301, 0x96E7: 0x4E5F, 0x96E8: 0x51B6, 0x96E9: 0x591C, 0x96EA: 0x723A, 0x96EB: 0x8036, 0x96EC: 0x91CE, 0x96ED: 0x5F25, 0x96EE: 0x77E2, 0x96EF: 0x5384, 0x96F0: 0x5F79, 0x96F1: 0x7D04, 0x96F2: 0x85AC, 0x96F3: 0x8A33, 0x96F4: 0x8E8D, 0x96F5: 0x9756, 0x96F6: 0x67F3, 0x96F7: 0x85AE, 0x96F8: 0x9453, 0x96F9: 0x6109, 0x96FA: 0x6108, 0x96FB: 0x6CB9, 0x96FC: 0x7652, 0x9740: 0x8AED, 0x9741: 0x8F38, 0x9742: 0x552F, 0x9743: 0x4F51, 0x9744: 0x512A, 0x9745: 0x52C7, 0x9746: 0x53CB, 0x9747: 0x5BA5, 0x9748: 0x5E7D, 0x9749: 0x60A0, 0x974A: 0x6182, 0x974B: 0x63D6, 0x974C: 0x6709, 0x974D: 0x67DA, 0x974E: 0x6E67, 0x974F: 0x6D8C, 0x9750: 0x7336, 0x9751: 0x7337, 0x9752: 0x7531, 0x9753: 0x7950, 0x9754: 0x88D5, 0x9755: 0x8A98, 0x9756: 0x904A, 0x9757: 0x9091, 0x9758: 0x90F5, 0x9759: 0x96C4, 0x975A: 0x878D, 0x975B: 0x5915, 0x975C: 0x4E88, 0x975D: 0x4F59, 0x975E: 0x4E0E, 0x975F: 0x8A89, 0x9760: 0x8F3F, 0x9761: 0x9810, 0x9762: 0x50AD, 0x9763: 0x5E7C, 0x9764: 0x5996, 0x9765: 0x5BB9, 0x9766: 0x5EB8, 0x9767: 0x63DA, 0x9768: 0x63FA, 0x9769: 0x64C1, 0x976A: 0x66DC, 0x976B: 0x694A, 0x976C: 0x69D8, 0x976D: 0x6D0B, 0x976E: 0x6EB6, 0x976F: 0x7194, 0x9770: 0x7528, 0x9771: 0x7AAF, 0x9772: 0x7F8A, 0x9773: 0x8000, 0x9774: 0x8449, 0x9775: 0x84C9, 0x9776: 0x8981, 0x9777: 0x8B21, 0x9778: 0x8E0A, 0x9779: 0x9065, 0x977A: 0x967D, 0x977B: 0x990A, 0x977C: 0x617E, 0x977D: 0x6291, 0x977E: 0x6B32, 0x9780: 0x6C83, 0x9781: 0x6D74, 0x9782: 0x7FCC, 0x9783: 0x7FFC, 0x9784: 0x6DC0, 0x9785: 0x7F85, 0x9786: 0x87BA, 0x9787: 0x88F8, 0x9788: 0x6765, 0x9789: 0x83B1, 0x978A: 0x983C, 0x978B: 0x96F7, 0x978C: 0x6D1B, 0x978D: 0x7D61, 0x978E: 0x843D, 0x978F: 0x916A, 0x9790: 0x4E71, 0x9791: 0x5375, 0x9792: 0x5D50, 0x9793: 0x6B04, 0x9794: 0x6FEB, 0x9795: 0x85CD, 0x9796: 0x862D, 0x9797: 0x89A7, 0x9798: 0x5229, 0x9799: 0x540F, 0x979A: 0x5C65, 0x979B: 0x674E, 0x979C: 0x68A8, 0x979D: 0x7406, 0x979E: 0x7483, 0x979F: 0x75E2, 0x97A0: 0x88CF, 0x97A1: 0x88E1, 0x97A2: 0x91CC, 0x97A3: 0x96E2, 0x97A4: 0x9678, 0x97A5: 0x5F8B, 0x97A6: 0x7387, 0x97A7: 0x7ACB, 0x97A8: 0x844E, 0x97A9: 0x63A0, 0x97AA: 0x7565, 0x97AB: 0x5289, 0x97AC: 0x6D41, 0x97AD: 0x6E9C, 0x97AE: 0x7409, 0x97AF: 0x7559, 0x97B0: 0x786B, 0x97B1: 0x7C92, 0x97B2: 0x9686, 0x97B3: 0x7ADC, 0x97B4: 0x9F8D, 0x97B5: 0x4FB6, 0x97B6: 0x616E, 0x97B7: 0x65C5, 0x97B8: 0x865C, 0x97B9: 0x4E86, 0x97BA: 0x4EAE, 0x97BB: 0x50DA, 0x97BC: 0x4E21, 0x97BD: 0x51CC, 0x97BE: 0x5BEE, 0x97BF: 0x6599, 0x97C0: 0x6881, 0x97C1: 0x6DBC, 0x97C2: 0x731F, 0x97C3: 0x7642, 0x97C4: 0x77AD, 0x97C5: 0x7A1C, 0x97C6: 0x7CE7, 0x97C7: 0x826F, 0x97C8: 0x8AD2, 0x97C9: 0x907C, 0x97CA: 0x91CF, 0x97CB: 0x9675, 0x97CC: 0x9818, 0x97CD: 0x529B, 0x97CE: 0x7DD1, 0x97CF: 0x502B, 0x97D0: 0x5398, 0x97D1: 0x6797, 0x97D2: 0x6DCB, 0x97D3: 0x71D0, 0x97D4: 0x7433, 0x97D5: 0x81E8, 0x97D6: 0x8F2A, 0x97D7: 0x96A3, 0x97D8: 0x9C57, 0x97D9: 0x9E9F, 0x97DA: 0x7460, 0x97DB: 0x5841, 0x97DC: 0x6D99, 0x97DD: 0x7D2F, 0x97DE: 0x985E, 0x97DF: 0x4EE4, 0x97E0: 0x4F36, 0x97E1: 0x4F8B, 0x97E2: 0x51B7, 0x97E3: 0x52B1, 0x97E4: 0x5DBA, 0x97E5: 0x601C, 0x97E6: 0x73B2, 0x97E7: 0x793C, 0x97E8: 0x82D3, 0x97E9: 0x9234, 0x97EA: 0x96B7, 0x97EB: 0x96F6, 0x97EC: 0x970A, 0x97ED: 0x9E97, 0x97EE: 0x9F62, 0x97EF: 0x66A6, 0x97F0: 0x6B74, 0x97F1: 0x5217, 0x97F2: 0x52A3, 0x97F3: 0x70C8, 0x97F4: 0x88C2, 0x97F5: 0x5EC9, 0x97F6: 0x604B, 0x97F7: 0x6190, 0x97F8: 0x6F23, 0x97F9: 0x7149, 0x97FA: 0x7C3E, 0x97FB: 0x7DF4, 0x97FC: 0x806F, 0x9840: 0x84EE, 0x9841: 0x9023, 0x9842: 0x932C, 0x9843: 0x5442, 0x9844: 0x9B6F, 0x9845: 0x6AD3, 0x9846: 0x7089, 0x9847: 0x8CC2, 0x9848: 0x8DEF, 0x9849: 0x9732, 0x984A: 0x52B4, 0x984B: 0x5A41, 0x984C: 0x5ECA, 0x984D: 0x5F04, 0x984E: 0x6717, 0x984F: 0x697C, 0x9850: 0x6994, 0x9851: 0x6D6A, 0x9852: 0x6F0F, 0x9853: 0x7262, 0x9854: 0x72FC, 0x9855: 0x7BED, 0x9856: 0x8001, 0x9857: 0x807E, 0x9858: 0x874B, 0x9859: 0x90CE, 0x985A: 0x516D, 0x985B: 0x9E93, 0x985C: 0x7984, 0x985D: 0x808B, 0x985E: 0x9332, 0x985F: 0x8AD6, 0x9860: 0x502D, 0x9861: 0x548C, 0x9862: 0x8A71, 0x9863: 0x6B6A, 0x9864: 0x8CC4, 0x9865: 0x8107, 0x9866: 0x60D1, 0x9867: 0x67A0, 0x9868: 0x9DF2, 0x9869: 0x4E99, 0x986A: 0x4E98, 0x986B: 0x9C10, 0x986C: 0x8A6B, 0x986D: 0x85C1, 0x986E: 0x8568, 0x986F: 0x6900, 0x9870: 0x6E7E, 0x9871: 0x7897, 0x9872: 0x8155, 0x989F: 0x5F0C, 0x98A0: 0x4E10, 0x98A1: 0x4E15, 0x98A2: 0x4E2A, 0x98A3: 0x4E31, 0x98A4: 0x4E36, 0x98A5: 0x4E3C, 0x98A6: 0x4E3F, 0x98A7: 0x4E42, 0x98A8: 0x4E56, 0x98A9: 0x4E58, 0x98AA: 0x4E82, 0x98AB: 0x4E85, 0x98AC: 0x8C6B, 0x98AD: 0x4E8A, 0x98AE: 0x8212, 0x98AF: 0x5F0D, 0x98B0: 0x4E8E, 0x98B1: 0x4E9E, 0x98B2: 0x4E9F, 0x98B3: 0x4EA0, 0x98B4: 0x4EA2, 0x98B5: 0x4EB0, 0x98B6: 0x4EB3, 0x98B7: 0x4EB6, 0x98B8: 0x4ECE, 0x98B9: 0x4ECD, 0x98BA: 0x4EC4, 0x98BB: 0x4EC6, 0x98BC: 0x4EC2, 0x98BD: 0x4ED7, 0x98BE: 0x4EDE, 0x98BF: 0x4EED, 0x98C0: 0x4EDF, 0x98C1: 0x4EF7, 0x98C2: 0x4F09, 0x98C3: 0x4F5A, 0x98C4: 0x4F30, 0x98C5: 0x4F5B, 0x98C6: 0x4F5D, 0x98C7: 0x4F57, 0x98C8: 0x4F47, 0x98C9: 0x4F76, 0x98CA: 0x4F88, 0x98CB: 0x4F8F, 0x98CC: 0x4F98, 0x98CD: 0x4F7B, 0x98CE: 0x4F69, 0x98CF: 0x4F70, 0x98D0: 0x4F91, 0x98D1: 0x4F6F, 0x98D2: 0x4F86, 0x98D3: 0x4F96, 0x98D4: 0x5118, 0x98D5: 0x4FD4, 0x98D6: 0x4FDF, 0x98D7: 0x4FCE, 0x98D8: 0x4FD8, 0x98D9: 0x4FDB, 0x98DA: 0x4FD1, 0x98DB: 0x4FDA, 0x98DC: 0x4FD0, 0x98DD: 0x4FE4, 0x98DE: 0x4FE5, 0x98DF: 0x501A, 0x98E0: 0x5028, 0x98E1: 0x5014, 0x98E2: 0x502A, 0x98E3: 0x5025, 0x98E4: 0x5005, 0x98E5: 0x4F1C, 0x98E6: 0x4FF6, 0x98E7: 0x5021, 0x98E8: 0x5029, 0x98E9: 0x502C, 0x98EA: 0x4FFE, 0x98EB: 0x4FEF, 0x98EC: 0x5011, 0x98ED: 0x5006, 0x98EE: 0x5043, 0x98EF: 0x5047, 0x98F0: 0x6703, 0x98F1: 0x5055, 0x98F2: 0x5050, 0x98F3: 0x5048, 0x98F4: 0x505A, 0x98F5: 0x5056, 0x98F6: 0x506C, 0x98F7: 0x5078, 0x98F8: 0x5080, 0x98F9: 0x509A, 0x98FA: 0x5085, 0x98FB: 0x50B4, 0x98FC: 0x50B2, 0x9940: 0x50C9, 0x9941: 0x50CA, 0x9942: 0x50B3, 0x9943: 0x50C2, 0x9944: 0x50D6, 0x9945: 0x50DE, 0x9946: 0x50E5, 0x9947: 0x50ED, 0x9948: 0x50E3, 0x9949: 0x50EE, 0x994A: 0x50F9, 0x994B: 0x50F5, 0x994C: 0x5109, 0x994D: 0x5101, 0x994E: 0x5102, 0x994F: 0x5116, 0x9950: 0x5115, 0x9951: 0x5114, 0x9952: 0x511A, 0x9953: 0x5121, 0x9954: 0x513A, 0x9955: 0x5137, 0x9956: 0x513C, 0x9957: 0x513B, 0x9958: 0x513F, 0x9959: 0x5140, 0x995A: 0x5152, 0x995B: 0x514C, 0x995C: 0x5154, 0x995D: 0x5162, 0x995E: 0x7AF8, 0x995F: 0x5169, 0x9960: 0x516A, 0x9961: 0x516E, 0x9962: 0x5180, 0x9963: 0x5182, 0x9964: 0x56D8, 0x9965: 0x518C, 0x9966: 0x5189, 0x9967: 0x518F, 0x9968: 0x5191, 0x9969: 0x5193, 0x996A: 0x5195, 0x996B: 0x5196, 0x996C: 0x51A4, 0x996D: 0x51A6, 0x996E: 0x51A2, 0x996F: 0x51A9, 0x9970: 0x51AA, 0x9971: 0x51AB, 0x9972: 0x51B3, 0x9973: 0x51B1, 0x9974: 0x51B2, 0x9975: 0x51B0, 0x9976: 0x51B5, 0x9977: 0x51BD, 0x9978: 0x51C5, 0x9979: 0x51C9, 0x997A: 0x51DB, 0x997B: 0x51E0, 0x997C: 0x8655, 0x997D: 0x51E9, 0x997E: 0x51ED, 0x9980: 0x51F0, 0x9981: 0x51F5, 0x9982: 0x51FE, 0x9983: 0x5204, 0x9984: 0x520B, 0x9985: 0x5214, 0x9986: 0x520E, 0x9987: 0x5227, 0x9988: 0x522A, 0x9989: 0x522E, 0x998A: 0x5233, 0x998B: 0x5239, 0x998C: 0x524F, 0x998D: 0x5244, 0x998E: 0x524B, 0x998F: 0x524C, 0x9990: 0x525E, 0x9991: 0x5254, 0x9992: 0x526A, 0x9993: 0x5274, 0x9994: 0x5269, 0x9995: 0x5273, 0x9996: 0x527F, 0x9997: 0x527D, 0x9998: 0x528D, 0x9999: 0x5294, 0x999A: 0x5292, 0x999B: 0x5271, 0x999C: 0x5288, 0x999D: 0x5291, 0x999E: 0x8FA8, 0x999F: 0x8FA7, 0x99A0: 0x52AC, 0x99A1: 0x52AD, 0x99A2: 0x52BC, 0x99A3: 0x52B5, 0x99A4: 0x52C1, 0x99A5: 0x52CD, 0x99A6: 0x52D7, 0x99A7: 0x52DE, 0x99A8: 0x52E3, 0x99A9: 0x52E6, 0x99AA: 0x98ED, 0x99AB: 0x52E0, 0x99AC: 0x52F3, 0x99AD: 0x52F5, 0x99AE: 0x52F8, 0x99AF: 0x52F9, 0x99B0: 0x5306, 0x99B1: 0x5308, 0x99B2: 0x7538, 0x99B3: 0x530D, 0x99B4: 0x5310, 0x99B5: 0x530F, 0x99B6: 0x5315, 0x99B7: 0x531A, 0x99B8: 0x5323, 0x99B9: 0x532F, 0x99BA: 0x5331, 0x99BB: 0x5333, 0x99BC: 0x5338, 0x99BD: 0x5340, 0x99BE: 0x5346, 0x99BF: 0x5345, 0x99C0: 0x4E17, 0x99C1: 0x5349, 0x99C2: 0x534D, 0x99C3: 0x51D6, 0x99C4: 0x535E, 0x99C5: 0x5369, 0x99C6: 0x536E, 0x99C7: 0x5918, 0x99C8: 0x537B, 0x99C9: 0x5377, 0x99CA: 0x5382, 0x99CB: 0x5396, 0x99CC: 0x53A0, 0x99CD: 0x53A6, 0x99CE: 0x53A5, 0x99CF: 0x53AE, 0x99D0: 0x53B0, 0x99D1: 0x53B6, 0x99D2: 0x53C3, 0x99D3: 0x7C12, 0x99D4: 0x96D9, 0x99D5: 0x53DF, 0x99D6: 0x66FC, 0x99D7: 0x71EE, 0x99D8: 0x53EE, 0x99D9: 0x53E8, 0x99DA: 0x53ED, 0x99DB: 0x53FA, 0x99DC: 0x5401, 0x99DD: 0x543D, 0x99DE: 0x5440, 0x99DF: 0x542C, 0x99E0: 0x542D, 0x99E1: 0x543C, 0x99E2: 0x542E, 0x99E3: 0x5436, 0x99E4: 0x5429, 0x99E5: 0x541D, 0x99E6: 0x544E, 0x99E7: 0x548F, 0x99E8: 0x5475, 0x99E9: 0x548E, 0x99EA: 0x545F, 0x99EB: 0x5471, 0x99EC: 0x5477, 0x99ED: 0x5470, 0x99EE: 0x5492, 0x99EF: 0x547B, 0x99F0: 0x5480, 0x99F1: 0x5476, 0x99F2: 0x5484, 0x99F3: 0x5490, 0x99F4: 0x5486, 0x99F5: 0x54C7, 0x99F6: 0x54A2, 0x99F7: 0x54B8, 0x99F8: 0x54A5, 0x99F9: 0x54AC, 0x99FA: 0x54C4, 0x99FB: 0x54C8, 0x99FC: 0x54A8, 0x9A40: 0x54AB, 0x9A41: 0x54C2, 0x9A42: 0x54A4, 0x9A43: 0x54BE, 0x9A44: 0x54BC, 0x9A45: 0x54D8, 0x9A46: 0x54E5, 0x9A47: 0x54E6, 0x9A48: 0x550F, 0x9A49: 0x5514, 0x9A4A: 0x54FD, 0x9A4B: 0x54EE, 0x9A4C: 0x54ED, 0x9A4D: 0x54FA, 0x9A4E: 0x54E2, 0x9A4F: 0x5539, 0x9A50: 0x5540, 0x9A51: 0x5563, 0x9A52: 0x554C, 0x9A53: 0x552E, 0x9A54: 0x555C, 0x9A55: 0x5545, 0x9A56: 0x5556, 0x9A57: 0x5557, 0x9A58: 0x5538, 0x9A59: 0x5533, 0x9A5A: 0x555D, 0x9A5B: 0x5599, 0x9A5C: 0x5580, 0x9A5D: 0x54AF, 0x9A5E: 0x558A, 0x9A5F: 0x559F, 0x9A60: 0x557B, 0x9A61: 0x557E, 0x9A62: 0x5598, 0x9A63: 0x559E, 0x9A64: 0x55AE, 0x9A65: 0x557C, 0x9A66: 0x5583, 0x9A67: 0x55A9, 0x9A68: 0x5587, 0x9A69: 0x55A8, 0x9A6A: 0x55DA, 0x9A6B: 0x55C5, 0x9A6C: 0x55DF, 0x9A6D: 0x55C4, 0x9A6E: 0x55DC, 0x9A6F: 0x55E4, 0x9A70: 0x55D4, 0x9A71: 0x5614, 0x9A72: 0x55F7, 0x9A73: 0x5616, 0x9A74: 0x55FE, 0x9A75: 0x55FD, 0x9A76: 0x561B, 0x9A77: 0x55F9, 0x9A78: 0x564E, 0x9A79: 0x5650, 0x9A7A: 0x71DF, 0x9A7B: 0x5634, 0x9A7C: 0x5636, 0x9A7D: 0x5632, 0x9A7E: 0x5638, 0x9A80: 0x566B, 0x9A81: 0x5664, 0x9A82: 0x562F, 0x9A83: 0x566C, 0x9A84: 0x566A, 0x9A85: 0x5686, 0x9A86: 0x5680, 0x9A87: 0x568A, 0x9A88: 0x56A0, 0x9A89: 0x5694, 0x9A8A: 0x568F, 0x9A8B: 0x56A5, 0x9A8C: 0x56AE, 0x9A8D: 0x56B6, 0x9A8E: 0x56B4, 0x9A8F: 0x56C2, 0x9A90: 0x56BC, 0x9A91: 0x56C1, 0x9A92: 0x56C3, 0x9A93: 0x56C0, 0x9A94: 0x56C8, 0x9A95: 0x56CE, 0x9A96: 0x56D1, 0x9A97: 0x56D3, 0x9A98: 0x56D7, 0x9A99: 0x56EE, 0x9A9A: 0x56F9, 0x9A9B: 0x5700, 0x9A9C: 0x56FF, 0x9A9D: 0x5704, 0x9A9E: 0x5709, 0x9A9F: 0x5708, 0x9AA0: 0x570B, 0x9AA1: 0x570D, 0x9AA2: 0x5713, 0x9AA3: 0x5718, 0x9AA4: 0x5716, 0x9AA5: 0x55C7, 0x9AA6: 0x571C, 0x9AA7: 0x5726, 0x9AA8: 0x5737, 0x9AA9: 0x5738, 0x9AAA: 0x574E, 0x9AAB: 0x573B, 0x9AAC: 0x5740, 0x9AAD: 0x574F, 0x9AAE: 0x5769, 0x9AAF: 0x57C0, 0x9AB0: 0x5788, 0x9AB1: 0x5761, 0x9AB2: 0x577F, 0x9AB3: 0x5789, 0x9AB4: 0x5793, 0x9AB5: 0x57A0, 0x9AB6: 0x57B3, 0x9AB7: 0x57A4, 0x9AB8: 0x57AA, 0x9AB9: 0x57B0, 0x9ABA: 0x57C3, 0x9ABB: 0x57C6, 0x9ABC: 0x57D4, 0x9ABD: 0x57D2, 0x9ABE: 0x57D3, 0x9ABF: 0x580A, 0x9AC0: 0x57D6, 0x9AC1: 0x57E3, 0x9AC2: 0x580B, 0x9AC3: 0x5819, 0x9AC4: 0x581D, 0x9AC5: 0x5872, 0x9AC6: 0x5821, 0x9AC7: 0x5862, 0x9AC8: 0x584B, 0x9AC9: 0x5870, 0x9ACA: 0x6BC0, 0x9ACB: 0x5852, 0x9ACC: 0x583D, 0x9ACD: 0x5879, 0x9ACE: 0x5885, 0x9ACF: 0x58B9, 0x9AD0: 0x589F, 0x9AD1: 0x58AB, 0x9AD2: 0x58BA, 0x9AD3: 0x58DE, 0x9AD4: 0x58BB, 0x9AD5: 0x58B8, 0x9AD6: 0x58AE, 0x9AD7: 0x58C5, 0x9AD8: 0x58D3, 0x9AD9: 0x58D1, 0x9ADA: 0x58D7, 0x9ADB: 0x58D9, 0x9ADC: 0x58D8, 0x9ADD: 0x58E5, 0x9ADE: 0x58DC, 0x9ADF: 0x58E4, 0x9AE0: 0x58DF, 0x9AE1: 0x58EF, 0x9AE2: 0x58FA, 0x9AE3: 0x58F9, 0x9AE4: 0x58FB, 0x9AE5: 0x58FC, 0x9AE6: 0x58FD, 0x9AE7: 0x5902, 0x9AE8: 0x590A, 0x9AE9: 0x5910, 0x9AEA: 0x591B, 0x9AEB: 0x68A6, 0x9AEC: 0x5925, 0x9AED: 0x592C, 0x9AEE: 0x592D, 0x9AEF: 0x5932, 0x9AF0: 0x5938, 0x9AF1: 0x593E, 0x9AF2: 0x7AD2, 0x9AF3: 0x5955, 0x9AF4: 0x5950, 0x9AF5: 0x594E, 0x9AF6: 0x595A, 0x9AF7: 0x5958, 0x9AF8: 0x5962, 0x9AF9: 0x5960, 0x9AFA: 0x5967, 0x9AFB: 0x596C, 0x9AFC: 0x5969, 0x9B40: 0x5978, 0x9B41: 0x5981, 0x9B42: 0x599D, 0x9B43: 0x4F5E, 0x9B44: 0x4FAB, 0x9B45: 0x59A3, 0x9B46: 0x59B2, 0x9B47: 0x59C6, 0x9B48: 0x59E8, 0x9B49: 0x59DC, 0x9B4A: 0x598D, 0x9B4B: 0x59D9, 0x9B4C: 0x59DA, 0x9B4D: 0x5A25, 0x9B4E: 0x5A1F, 0x9B4F: 0x5A11, 0x9B50: 0x5A1C, 0x9B51: 0x5A09, 0x9B52: 0x5A1A, 0x9B53: 0x5A40, 0x9B54: 0x5A6C, 0x9B55: 0x5A49, 0x9B56: 0x5A35, 0x9B57: 0x5A36, 0x9B58: 0x5A62, 0x9B59: 0x5A6A, 0x9B5A: 0x5A9A, 0x9B5B: 0x5ABC, 0x9B5C: 0x5ABE, 0x9B5D: 0x5ACB, 0x9B5E: 0x5AC2, 0x9B5F: 0x5ABD, 0x9B60: 0x5AE3, 0x9B61: 0x5AD7, 0x9B62: 0x5AE6, 0x9B63: 0x5AE9, 0x9B64: 0x5AD6, 0x9B65: 0x5AFA, 0x9B66: 0x5AFB, 0x9B67: 0x5B0C, 0x9B68: 0x5B0B, 0x9B69: 0x5B16, 0x9B6A: 0x5B32, 0x9B6B: 0x5AD0, 0x9B6C: 0x5B2A, 0x9B6D: 0x5B36, 0x9B6E: 0x5B3E, 0x9B6F: 0x5B43, 0x9B70: 0x5B45, 0x9B71: 0x5B40, 0x9B72: 0x5B51, 0x9B73: 0x5B55, 0x9B74: 0x5B5A, 0x9B75: 0x5B5B, 0x9B76: 0x5B65, 0x9B77: 0x5B69, 0x9B78: 0x5B70, 0x9B79: 0x5B73, 0x9B7A: 0x5B75, 0x9B7B: 0x5B78, 0x9B7C: 0x6588, 0x9B7D: 0x5B7A, 0x9B7E: 0x5B80, 0x9B80: 0x5B83, 0x9B81: 0x5BA6, 0x9B82: 0x5BB8, 0x9B83: 0x5BC3, 0x9B84: 0x5BC7, 0x9B85: 0x5BC9, 0x9B86: 0x5BD4, 0x9B87: 0x5BD0, 0x9B88: 0x5BE4, 0x9B89: 0x5BE6, 0x9B8A: 0x5BE2, 0x9B8B: 0x5BDE, 0x9B8C: 0x5BE5, 0x9B8D: 0x5BEB, 0x9B8E: 0x5BF0, 0x9B8F: 0x5BF6, 0x9B90: 0x5BF3, 0x9B91: 0x5C05, 0x9B92: 0x5C07, 0x9B93: 0x5C08, 0x9B94: 0x5C0D, 0x9B95: 0x5C13, 0x9B96: 0x5C20, 0x9B97: 0x5C22, 0x9B98: 0x5C28, 0x9B99: 0x5C38, 0x9B9A: 0x5C39, 0x9B9B: 0x5C41, 0x9B9C: 0x5C46, 0x9B9D: 0x5C4E, 0x9B9E: 0x5C53, 0x9B9F: 0x5C50, 0x9BA0: 0x5C4F, 0x9BA1: 0x5B71, 0x9BA2: 0x5C6C, 0x9BA3: 0x5C6E, 0x9BA4: 0x4E62, 0x9BA5: 0x5C76, 0x9BA6: 0x5C79, 0x9BA7: 0x5C8C, 0x9BA8: 0x5C91, 0x9BA9: 0x5C94, 0x9BAA: 0x599B, 0x9BAB: 0x5CAB, 0x9BAC: 0x5CBB, 0x9BAD: 0x5CB6, 0x9BAE: 0x5CBC, 0x9BAF: 0x5CB7, 0x9BB0: 0x5CC5, 0x9BB1: 0x5CBE, 0x9BB2: 0x5CC7, 0x9BB3: 0x5CD9, 0x9BB4: 0x5CE9, 0x9BB5: 0x5CFD, 0x9BB6: 0x5CFA, 0x9BB7: 0x5CED, 0x9BB8: 0x5D8C, 0x9BB9: 0x5CEA, 0x9BBA: 0x5D0B, 0x9BBB: 0x5D15, 0x9BBC: 0x5D17, 0x9BBD: 0x5D5C, 0x9BBE: 0x5D1F, 0x9BBF: 0x5D1B, 0x9BC0: 0x5D11, 0x9BC1: 0x5D14, 0x9BC2: 0x5D22, 0x9BC3: 0x5D1A, 0x9BC4: 0x5D19, 0x9BC5: 0x5D18, 0x9BC6: 0x5D4C, 0x9BC7: 0x5D52, 0x9BC8: 0x5D4E, 0x9BC9: 0x5D4B, 0x9BCA: 0x5D6C, 0x9BCB: 0x5D73, 0x9BCC: 0x5D76, 0x9BCD: 0x5D87, 0x9BCE: 0x5D84, 0x9BCF: 0x5D82, 0x9BD0: 0x5DA2, 0x9BD1: 0x5D9D, 0x9BD2: 0x5DAC, 0x9BD3: 0x5DAE, 0x9BD4: 0x5DBD, 0x9BD5: 0x5D90, 0x9BD6: 0x5DB7, 0x9BD7: 0x5DBC, 0x9BD8: 0x5DC9, 0x9BD9: 0x5DCD, 0x9BDA: 0x5DD3, 0x9BDB: 0x5DD2, 0x9BDC: 0x5DD6, 0x9BDD: 0x5DDB, 0x9BDE: 0x5DEB, 0x9BDF: 0x5DF2, 0x9BE0: 0x5DF5, 0x9BE1: 0x5E0B, 0x9BE2: 0x5E1A, 0x9BE3: 0x5E19, 0x9BE4: 0x5E11, 0x9BE5: 0x5E1B, 0x9BE6: 0x5E36, 0x9BE7: 0x5E37, 0x9BE8: 0x5E44, 0x9BE9: 0x5E43, 0x9BEA: 0x5E40, 0x9BEB: 0x5E4E, 0x9BEC: 0x5E57, 0x9BED: 0x5E54, 0x9BEE: 0x5E5F, 0x9BEF: 0x5E62, 0x9BF0: 0x5E64, 0x9BF1: 0x5E47, 0x9BF2: 0x5E75, 0x9BF3: 0x5E76, 0x9BF4: 0x5E7A, 0x9BF5: 0x9EBC, 0x9BF6: 0x5E7F, 0x9BF7: 0x5EA0, 0x9BF8: 0x5EC1, 0x9BF9: 0x5EC2, 0x9BFA: 0x5EC8, 0x9BFB: 0x5ED0, 0x9BFC: 0x5ECF, 0x9C40: 0x5ED6, 0x9C41: 0x5EE3, 0x9C42: 0x5EDD, 0x9C43: 0x5EDA, 0x9C44: 0x5EDB, 0x9C45: 0x5EE2, 0x9C46: 0x5EE1, 0x9C47: 0x5EE8, 0x9C48: 0x5EE9, 0x9C49: 0x5EEC, 0x9C4A: 0x5EF1, 0x9C4B: 0x5EF3, 0x9C4C: 0x5EF0, 0x9C4D: 0x5EF4, 0x9C4E: 0x5EF8, 0x9C4F: 0x5EFE, 0x9C50: 0x5F03, 0x9C51: 0x5F09, 0x9C52: 0x5F5D, 0x9C53: 0x5F5C, 0x9C54: 0x5F0B, 0x9C55: 0x5F11, 0x9C56: 0x5F16, 0x9C57: 0x5F29, 0x9C58: 0x5F2D, 0x9C59: 0x5F38, 0x9C5A: 0x5F41, 0x9C5B: 0x5F48, 0x9C5C: 0x5F4C, 0x9C5D: 0x5F4E, 0x9C5E: 0x5F2F, 0x9C5F: 0x5F51, 0x9C60: 0x5F56, 0x9C61: 0x5F57, 0x9C62: 0x5F59, 0x9C63: 0x5F61, 0x9C64: 0x5F6D, 0x9C65: 0x5F73, 0x9C66: 0x5F77, 0x9C67: 0x5F83, 0x9C68: 0x5F82, 0x9C69: 0x5F7F, 0x9C6A: 0x5F8A, 0x9C6B: 0x5F88, 0x9C6C: 0x5F91, 0x9C6D: 0x5F87, 0x9C6E: 0x5F9E, 0x9C6F: 0x5F99, 0x9C70: 0x5F98, 0x9C71: 0x5FA0, 0x9C72: 0x5FA8, 0x9C73: 0x5FAD, 0x9C74: 0x5FBC, 0x9C75: 0x5FD6, 0x9C76: 0x5FFB, 0x9C77: 0x5FE4, 0x9C78: 0x5FF8, 0x9C79: 0x5FF1, 0x9C7A: 0x5FDD, 0x9C7B: 0x60B3, 0x9C7C: 0x5FFF, 0x9C7D: 0x6021, 0x9C7E: 0x6060, 0x9C80: 0x6019, 0x9C81: 0x6010, 0x9C82: 0x6029, 0x9C83: 0x600E, 0x9C84: 0x6031, 0x9C85: 0x601B, 0x9C86: 0x6015, 0x9C87: 0x602B, 0x9C88: 0x6026, 0x9C89: 0x600F, 0x9C8A: 0x603A, 0x9C8B: 0x605A, 0x9C8C: 0x6041, 0x9C8D: 0x606A, 0x9C8E: 0x6077, 0x9C8F: 0x605F, 0x9C90: 0x604A, 0x9C91: 0x6046, 0x9C92: 0x604D, 0x9C93: 0x6063, 0x9C94: 0x6043, 0x9C95: 0x6064, 0x9C96: 0x6042, 0x9C97: 0x606C, 0x9C98: 0x606B, 0x9C99: 0x6059, 0x9C9A: 0x6081, 0x9C9B: 0x608D, 0x9C9C: 0x60E7, 0x9C9D: 0x6083, 0x9C9E: 0x609A, 0x9C9F: 0x6084, 0x9CA0: 0x609B, 0x9CA1: 0x6096, 0x9CA2: 0x6097, 0x9CA3: 0x6092, 0x9CA4: 0x60A7, 0x9CA5: 0x608B, 0x9CA6: 0x60E1, 0x9CA7: 0x60B8, 0x9CA8: 0x60E0, 0x9CA9: 0x60D3, 0x9CAA: 0x60B4, 0x9CAB: 0x5FF0, 0x9CAC: 0x60BD, 0x9CAD: 0x60C6, 0x9CAE: 0x60B5, 0x9CAF: 0x60D8, 0x9CB0: 0x614D, 0x9CB1: 0x6115, 0x9CB2: 0x6106, 0x9CB3: 0x60F6, 0x9CB4: 0x60F7, 0x9CB5: 0x6100, 0x9CB6: 0x60F4, 0x9CB7: 0x60FA, 0x9CB8: 0x6103, 0x9CB9: 0x6121, 0x9CBA: 0x60FB, 0x9CBB: 0x60F1, 0x9CBC: 0x610D, 0x9CBD: 0x610E, 0x9CBE: 0x6147, 0x9CBF: 0x613E, 0x9CC0: 0x6128, 0x9CC1: 0x6127, 0x9CC2: 0x614A, 0x9CC3: 0x613F, 0x9CC4: 0x613C, 0x9CC5: 0x612C, 0x9CC6: 0x6134, 0x9CC7: 0x613D, 0x9CC8: 0x6142, 0x9CC9: 0x6144, 0x9CCA: 0x6173, 0x9CCB: 0x6177, 0x9CCC: 0x6158, 0x9CCD: 0x6159, 0x9CCE: 0x615A, 0x9CCF: 0x616B, 0x9CD0: 0x6174, 0x9CD1: 0x616F, 0x9CD2: 0x6165, 0x9CD3: 0x6171, 0x9CD4: 0x615F, 0x9CD5: 0x615D, 0x9CD6: 0x6153, 0x9CD7: 0x6175, 0x9CD8: 0x6199, 0x9CD9: 0x6196, 0x9CDA: 0x6187, 0x9CDB: 0x61AC, 0x9CDC: 0x6194, 0x9CDD: 0x619A, 0x9CDE: 0x618A, 0x9CDF: 0x6191, 0x9CE0: 0x61AB, 0x9CE1: 0x61AE, 0x9CE2: 0x61CC, 0x9CE3: 0x61CA, 0x9CE4: 0x61C9, 0x9CE5: 0x61F7, 0x9CE6: 0x61C8, 0x9CE7: 0x61C3, 0x9CE8: 0x61C6, 0x9CE9: 0x61BA, 0x9CEA: 0x61CB, 0x9CEB: 0x7F79, 0x9CEC: 0x61CD, 0x9CED: 0x61E6, 0x9CEE: 0x61E3, 0x9CEF: 0x61F6, 0x9CF0: 0x61FA, 0x9CF1: 0x61F4, 0x9CF2: 0x61FF, 0x9CF3: 0x61FD, 0x9CF4: 0x61FC, 0x9CF5: 0x61FE, 0x9CF6: 0x6200, 0x9CF7: 0x6208, 0x9CF8: 0x6209, 0x9CF9: 0x620D, 0x9CFA: 0x620C, 0x9CFB: 0x6214, 0x9CFC: 0x621B, 0x9D40: 0x621E, 0x9D41: 0x6221, 0x9D42: 0x622A, 0x9D43: 0x622E, 0x9D44: 0x6230, 0x9D45: 0x6232, 0x9D46: 0x6233, 0x9D47: 0x6241, 0x9D48: 0x624E, 0x9D49: 0x625E, 0x9D4A: 0x6263, 0x9D4B: 0x625B, 0x9D4C: 0x6260, 0x9D4D: 0x6268, 0x9D4E: 0x627C, 0x9D4F: 0x6282, 0x9D50: 0x6289, 0x9D51: 0x627E, 0x9D52: 0x6292, 0x9D53: 0x6293, 0x9D54: 0x6296, 0x9D55: 0x62D4, 0x9D56: 0x6283, 0x9D57: 0x6294, 0x9D58: 0x62D7, 0x9D59: 0x62D1, 0x9D5A: 0x62BB, 0x9D5B: 0x62CF, 0x9D5C: 0x62FF, 0x9D5D: 0x62C6, 0x9D5E: 0x64D4, 0x9D5F: 0x62C8, 0x9D60: 0x62DC, 0x9D61: 0x62CC, 0x9D62: 0x62CA, 0x9D63: 0x62C2, 0x9D64: 0x62C7, 0x9D65: 0x629B, 0x9D66: 0x62C9, 0x9D67: 0x630C, 0x9D68: 0x62EE, 0x9D69: 0x62F1, 0x9D6A: 0x6327, 0x9D6B: 0x6302, 0x9D6C: 0x6308, 0x9D6D: 0x62EF, 0x9D6E: 0x62F5, 0x9D6F: 0x6350, 0x9D70: 0x633E, 0x9D71: 0x634D, 0x9D72: 0x641C, 0x9D73: 0x634F, 0x9D74: 0x6396, 0x9D75: 0x638E, 0x9D76: 0x6380, 0x9D77: 0x63AB, 0x9D78: 0x6376, 0x9D79: 0x63A3, 0x9D7A: 0x638F, 0x9D7B: 0x6389, 0x9D7C: 0x639F, 0x9D7D: 0x63B5, 0x9D7E: 0x636B, 0x9D80: 0x6369, 0x9D81: 0x63BE, 0x9D82: 0x63E9, 0x9D83: 0x63C0, 0x9D84: 0x63C6, 0x9D85: 0x63E3, 0x9D86: 0x63C9, 0x9D87: 0x63D2, 0x9D88: 0x63F6, 0x9D89: 0x63C4, 0x9D8A: 0x6416, 0x9D8B: 0x6434, 0x9D8C: 0x6406, 0x9D8D: 0x6413, 0x9D8E: 0x6426, 0x9D8F: 0x6436, 0x9D90: 0x651D, 0x9D91: 0x6417, 0x9D92: 0x6428, 0x9D93: 0x640F, 0x9D94: 0x6467, 0x9D95: 0x646F, 0x9D96: 0x6476, 0x9D97: 0x644E, 0x9D98: 0x652A, 0x9D99: 0x6495, 0x9D9A: 0x6493, 0x9D9B: 0x64A5, 0x9D9C: 0x64A9, 0x9D9D: 0x6488, 0x9D9E: 0x64BC, 0x9D9F: 0x64DA, 0x9DA0: 0x64D2, 0x9DA1: 0x64C5, 0x9DA2: 0x64C7, 0x9DA3: 0x64BB, 0x9DA4: 0x64D8, 0x9DA5: 0x64C2, 0x9DA6: 0x64F1, 0x9DA7: 0x64E7, 0x9DA8: 0x8209, 0x9DA9: 0x64E0, 0x9DAA: 0x64E1, 0x9DAB: 0x62AC, 0x9DAC: 0x64E3, 0x9DAD: 0x64EF, 0x9DAE: 0x652C, 0x9DAF: 0x64F6, 0x9DB0: 0x64F4, 0x9DB1: 0x64F2, 0x9DB2: 0x64FA, 0x9DB3: 0x6500, 0x9DB4: 0x64FD, 0x9DB5: 0x6518, 0x9DB6: 0x651C, 0x9DB7: 0x6505, 0x9DB8: 0x6524, 0x9DB9: 0x6523, 0x9DBA: 0x652B, 0x9DBB: 0x6534, 0x9DBC: 0x6535, 0x9DBD: 0x6537, 0x9DBE: 0x6536, 0x9DBF: 0x6538, 0x9DC0: 0x754B, 0x9DC1: 0x6548, 0x9DC2: 0x6556, 0x9DC3: 0x6555, 0x9DC4: 0x654D, 0x9DC5: 0x6558, 0x9DC6: 0x655E, 0x9DC7: 0x655D, 0x9DC8: 0x6572, 0x9DC9: 0x6578, 0x9DCA: 0x6582, 0x9DCB: 0x6583, 0x9DCC: 0x8B8A, 0x9DCD: 0x659B, 0x9DCE: 0x659F, 0x9DCF: 0x65AB, 0x9DD0: 0x65B7, 0x9DD1: 0x65C3, 0x9DD2: 0x65C6, 0x9DD3: 0x65C1, 0x9DD4: 0x65C4, 0x9DD5: 0x65CC, 0x9DD6: 0x65D2, 0x9DD7: 0x65DB, 0x9DD8: 0x65D9, 0x9DD9: 0x65E0, 0x9DDA: 0x65E1, 0x9DDB: 0x65F1, 0x9DDC: 0x6772, 0x9DDD: 0x660A, 0x9DDE: 0x6603, 0x9DDF: 0x65FB, 0x9DE0: 0x6773, 0x9DE1: 0x6635, 0x9DE2: 0x6636, 0x9DE3: 0x6634, 0x9DE4: 0x661C, 0x9DE5: 0x664F, 0x9DE6: 0x6644, 0x9DE7: 0x6649, 0x9DE8: 0x6641, 0x9DE9: 0x665E, 0x9DEA: 0x665D, 0x9DEB: 0x6664, 0x9DEC: 0x6667, 0x9DED: 0x6668, 0x9DEE: 0x665F, 0x9DEF: 0x6662, 0x9DF0: 0x6670, 0x9DF1: 0x6683, 0x9DF2: 0x6688, 0x9DF3: 0x668E, 0x9DF4: 0x6689, 0x9DF5: 0x6684, 0x9DF6: 0x6698, 0x9DF7: 0x669D, 0x9DF8: 0x66C1, 0x9DF9: 0x66B9, 0x9DFA: 0x66C9, 0x9DFB: 0x66BE, 0x9DFC: 0x66BC, 0x9E40: 0x66C4, 0x9E41: 0x66B8, 0x9E42: 0x66D6, 0x9E43: 0x66DA, 0x9E44: 0x66E0, 0x9E45: 0x663F, 0x9E46: 0x66E6, 0x9E47: 0x66E9, 0x9E48: 0x66F0, 0x9E49: 0x66F5, 0x9E4A: 0x66F7, 0x9E4B: 0x670F, 0x9E4C: 0x6716, 0x9E4D: 0x671E, 0x9E4E: 0x6726, 0x9E4F: 0x6727, 0x9E50: 0x9738, 0x9E51: 0x672E, 0x9E52: 0x673F, 0x9E53: 0x6736, 0x9E54: 0x6741, 0x9E55: 0x6738, 0x9E56: 0x6737, 0x9E57: 0x6746, 0x9E58: 0x675E, 0x9E59: 0x6760, 0x9E5A: 0x6759, 0x9E5B: 0x6763, 0x9E5C: 0x6764, 0x9E5D: 0x6789, 0x9E5E: 0x6770, 0x9E5F: 0x67A9, 0x9E60: 0x677C, 0x9E61: 0x676A, 0x9E62: 0x678C, 0x9E63: 0x678B, 0x9E64: 0x67A6, 0x9E65: 0x67A1, 0x9E66: 0x6785, 0x9E67: 0x67B7, 0x9E68: 0x67EF, 0x9E69: 0x67B4, 0x9E6A: 0x67EC, 0x9E6B: 0x67B3, 0x9E6C: 0x67E9, 0x9E6D: 0x67B8, 0x9E6E: 0x67E4, 0x9E6F: 0x67DE, 0x9E70: 0x67DD, 0x9E71: 0x67E2, 0x9E72: 0x67EE, 0x9E73: 0x67B9, 0x9E74: 0x67CE, 0x9E75: 0x67C6, 0x9E76: 0x67E7, 0x9E77: 0x6A9C, 0x9E78: 0x681E, 0x9E79: 0x6846, 0x9E7A: 0x6829, 0x9E7B: 0x6840, 0x9E7C: 0x684D, 0x9E7D: 0x6832, 0x9E7E: 0x684E, 0x9E80: 0x68B3, 0x9E81: 0x682B, 0x9E82: 0x6859, 0x9E83: 0x6863, 0x9E84: 0x6877, 0x9E85: 0x687F, 0x9E86: 0x689F, 0x9E87: 0x688F, 0x9E88: 0x68AD, 0x9E89: 0x6894, 0x9E8A: 0x689D, 0x9E8B: 0x689B, 0x9E8C: 0x6883, 0x9E8D: 0x6AAE, 0x9E8E: 0x68B9, 0x9E8F: 0x6874, 0x9E90: 0x68B5, 0x9E91: 0x68A0, 0x9E92: 0x68BA, 0x9E93: 0x690F, 0x9E94: 0x688D, 0x9E95: 0x687E, 0x9E96: 0x6901, 0x9E97: 0x68CA, 0x9E98: 0x6908, 0x9E99: 0x68D8, 0x9E9A: 0x6922, 0x9E9B: 0x6926, 0x9E9C: 0x68E1, 0x9E9D: 0x690C, 0x9E9E: 0x68CD, 0x9E9F: 0x68D4, 0x9EA0: 0x68E7, 0x9EA1: 0x68D5, 0x9EA2: 0x6936, 0x9EA3: 0x6912, 0x9EA4: 0x6904, 0x9EA5: 0x68D7, 0x9EA6: 0x68E3, 0x9EA7: 0x6925, 0x9EA8: 0x68F9, 0x9EA9: 0x68E0, 0x9EAA: 0x68EF, 0x9EAB: 0x6928, 0x9EAC: 0x692A, 0x9EAD: 0x691A, 0x9EAE: 0x6923, 0x9EAF: 0x6921, 0x9EB0: 0x68C6, 0x9EB1: 0x6979, 0x9EB2: 0x6977, 0x9EB3: 0x695C, 0x9EB4: 0x6978, 0x9EB5: 0x696B, 0x9EB6: 0x6954, 0x9EB7: 0x697E, 0x9EB8: 0x696E, 0x9EB9: 0x6939, 0x9EBA: 0x6974, 0x9EBB: 0x693D, 0x9EBC: 0x6959, 0x9EBD: 0x6930, 0x9EBE: 0x6961, 0x9EBF: 0x695E, 0x9EC0: 0x695D, 0x9EC1: 0x6981, 0x9EC2: 0x696A, 0x9EC3: 0x69B2, 0x9EC4: 0x69AE, 0x9EC5: 0x69D0, 0x9EC6: 0x69BF, 0x9EC7: 0x69C1, 0x9EC8: 0x69D3, 0x9EC9: 0x69BE, 0x9ECA: 0x69CE, 0x9ECB: 0x5BE8, 0x9ECC: 0x69CA, 0x9ECD: 0x69DD, 0x9ECE: 0x69BB, 0x9ECF: 0x69C3, 0x9ED0: 0x69A7, 0x9ED1: 0x6A2E, 0x9ED2: 0x6991, 0x9ED3: 0x69A0, 0x9ED4: 0x699C, 0x9ED5: 0x6995, 0x9ED6: 0x69B4, 0x9ED7: 0x69DE, 0x9ED8: 0x69E8, 0x9ED9: 0x6A02, 0x9EDA: 0x6A1B, 0x9EDB: 0x69FF, 0x9EDC: 0x6B0A, 0x9EDD: 0x69F9, 0x9EDE: 0x69F2, 0x9EDF: 0x69E7, 0x9EE0: 0x6A05, 0x9EE1: 0x69B1, 0x9EE2: 0x6A1E, 0x9EE3: 0x69ED, 0x9EE4: 0x6A14, 0x9EE5: 0x69EB, 0x9EE6: 0x6A0A, 0x9EE7: 0x6A12, 0x9EE8: 0x6AC1, 0x9EE9: 0x6A23, 0x9EEA: 0x6A13, 0x9EEB: 0x6A44, 0x9EEC: 0x6A0C, 0x9EED: 0x6A72, 0x9EEE: 0x6A36, 0x9EEF: 0x6A78, 0x9EF0: 0x6A47, 0x9EF1: 0x6A62, 0x9EF2: 0x6A59, 0x9EF3: 0x6A66, 0x9EF4: 0x6A48, 0x9EF5: 0x6A38, 0x9EF6: 0x6A22, 0x9EF7: 0x6A90, 0x9EF8: 0x6A8D, 0x9EF9: 0x6AA0, 0x9EFA: 0x6A84, 0x9EFB: 0x6AA2, 0x9EFC: 0x6AA3, 0x9F40: 0x6A97, 0x9F41: 0x8617, 0x9F42: 0x6ABB, 0x9F43: 0x6AC3, 0x9F44: 0x6AC2, 0x9F45: 0x6AB8, 0x9F46: 0x6AB3, 0x9F47: 0x6AAC, 0x9F48: 0x6ADE, 0x9F49: 0x6AD1, 0x9F4A: 0x6ADF, 0x9F4B: 0x6AAA, 0x9F4C: 0x6ADA, 0x9F4D: 0x6AEA, 0x9F4E: 0x6AFB, 0x9F4F: 0x6B05, 0x9F50: 0x8616, 0x9F51: 0x6AFA, 0x9F52: 0x6B12, 0x9F53: 0x6B16, 0x9F54: 0x9B31, 0x9F55: 0x6B1F, 0x9F56: 0x6B38, 0x9F57: 0x6B37, 0x9F58: 0x76DC, 0x9F59: 0x6B39, 0x9F5A: 0x98EE, 0x9F5B: 0x6B47, 0x9F5C: 0x6B43, 0x9F5D: 0x6B49, 0x9F5E: 0x6B50, 0x9F5F: 0x6B59, 0x9F60: 0x6B54, 0x9F61: 0x6B5B, 0x9F62: 0x6B5F, 0x9F63: 0x6B61, 0x9F64: 0x6B78, 0x9F65: 0x6B79, 0x9F66: 0x6B7F, 0x9F67: 0x6B80, 0x9F68: 0x6B84, 0x9F69: 0x6B83, 0x9F6A: 0x6B8D, 0x9F6B: 0x6B98, 0x9F6C: 0x6B95, 0x9F6D: 0x6B9E, 0x9F6E: 0x6BA4, 0x9F6F: 0x6BAA, 0x9F70: 0x6BAB, 0x9F71: 0x6BAF, 0x9F72: 0x6BB2, 0x9F73: 0x6BB1, 0x9F74: 0x6BB3, 0x9F75: 0x6BB7, 0x9F76: 0x6BBC, 0x9F77: 0x6BC6, 0x9F78: 0x6BCB, 0x9F79: 0x6BD3, 0x9F7A: 0x6BDF, 0x9F7B: 0x6BEC, 0x9F7C: 0x6BEB, 0x9F7D: 0x6BF3, 0x9F7E: 0x6BEF, 0x9F80: 0x9EBE, 0x9F81: 0x6C08, 0x9F82: 0x6C13, 0x9F83: 0x6C14, 0x9F84: 0x6C1B, 0x9F85: 0x6C24, 0x9F86: 0x6C23, 0x9F87: 0x6C5E, 0x9F88: 0x6C55, 0x9F89: 0x6C62, 0x9F8A: 0x6C6A, 0x9F8B: 0x6C82, 0x9F8C: 0x6C8D, 0x9F8D: 0x6C9A, 0x9F8E: 0x6C81, 0x9F8F: 0x6C9B, 0x9F90: 0x6C7E, 0x9F91: 0x6C68, 0x9F92: 0x6C73, 0x9F93: 0x6C92, 0x9F94: 0x6C90, 0x9F95: 0x6CC4, 0x9F96: 0x6CF1, 0x9F97: 0x6CD3, 0x9F98: 0x6CBD, 0x9F99: 0x6CD7, 0x9F9A: 0x6CC5, 0x9F9B: 0x6CDD, 0x9F9C: 0x6CAE, 0x9F9D: 0x6CB1, 0x9F9E: 0x6CBE, 0x9F9F: 0x6CBA, 0x9FA0: 0x6CDB, 0x9FA1: 0x6CEF, 0x9FA2: 0x6CD9, 0x9FA3: 0x6CEA, 0x9FA4: 0x6D1F, 0x9FA5: 0x884D, 0x9FA6: 0x6D36, 0x9FA7: 0x6D2B, 0x9FA8: 0x6D3D, 0x9FA9: 0x6D38, 0x9FAA: 0x6D19, 0x9FAB: 0x6D35, 0x9FAC: 0x6D33, 0x9FAD: 0x6D12, 0x9FAE: 0x6D0C, 0x9FAF: 0x6D63, 0x9FB0: 0x6D93, 0x9FB1: 0x6D64, 0x9FB2: 0x6D5A, 0x9FB3: 0x6D79, 0x9FB4: 0x6D59, 0x9FB5: 0x6D8E, 0x9FB6: 0x6D95, 0x9FB7: 0x6FE4, 0x9FB8: 0x6D85, 0x9FB9: 0x6DF9, 0x9FBA: 0x6E15, 0x9FBB: 0x6E0A, 0x9FBC: 0x6DB5, 0x9FBD: 0x6DC7, 0x9FBE: 0x6DE6, 0x9FBF: 0x6DB8, 0x9FC0: 0x6DC6, 0x9FC1: 0x6DEC, 0x9FC2: 0x6DDE, 0x9FC3: 0x6DCC, 0x9FC4: 0x6DE8, 0x9FC5: 0x6DD2, 0x9FC6: 0x6DC5, 0x9FC7: 0x6DFA, 0x9FC8: 0x6DD9, 0x9FC9: 0x6DE4, 0x9FCA: 0x6DD5, 0x9FCB: 0x6DEA, 0x9FCC: 0x6DEE, 0x9FCD: 0x6E2D, 0x9FCE: 0x6E6E, 0x9FCF: 0x6E2E, 0x9FD0: 0x6E19, 0x9FD1: 0x6E72, 0x9FD2: 0x6E5F, 0x9FD3: 0x6E3E, 0x9FD4: 0x6E23, 0x9FD5: 0x6E6B, 0x9FD6: 0x6E2B, 0x9FD7: 0x6E76, 0x9FD8: 0x6E4D, 0x9FD9: 0x6E1F, 0x9FDA: 0x6E43, 0x9FDB: 0x6E3A, 0x9FDC: 0x6E4E, 0x9FDD: 0x6E24, 0x9FDE: 0x6EFF, 0x9FDF: 0x6E1D, 0x9FE0: 0x6E38, 0x9FE1: 0x6E82, 0x9FE2: 0x6EAA, 0x9FE3: 0x6E98, 0x9FE4: 0x6EC9, 0x9FE5: 0x6EB7, 0x9FE6: 0x6ED3, 0x9FE7: 0x6EBD, 0x9FE8: 0x6EAF, 0x9FE9: 0x6EC4, 0x9FEA: 0x6EB2, 0x9FEB: 0x6ED4, 0x9FEC: 0x6ED5, 0x9FED: 0x6E8F, 0x9FEE: 0x6EA5, 0x9FEF: 0x6EC2, 0x9FF0: 0x6E9F, 0x9FF1: 0x6F41, 0x9FF2: 0x6F11, 0x9FF3: 0x704C, 0x9FF4: 0x6EEC, 0x9FF5: 0x6EF8, 0x9FF6: 0x6EFE, 0x9FF7: 0x6F3F, 0x9FF8: 0x6EF2, 0x9FF9: 0x6F31, 0x9FFA: 0x6EEF, 0x9FFB: 0x6F32, 0x9FFC: 0x6ECC, 0xA1: 0xFF61, 0xA2: 0xFF62, 0xA3: 0xFF63, 0xA4: 0xFF64, 0xA5: 0xFF65, 0xA6: 0xFF66, 0xA7: 0xFF67, 0xA8: 0xFF68, 0xA9: 0xFF69, 0xAA: 0xFF6A, 0xAB: 0xFF6B, 0xAC: 0xFF6C, 0xAD: 0xFF6D, 0xAE: 0xFF6E, 0xAF: 0xFF6F, 0xB0: 0xFF70, 0xB1: 0xFF71, 0xB2: 0xFF72, 0xB3: 0xFF73, 0xB4: 0xFF74, 0xB5: 0xFF75, 0xB6: 0xFF76, 0xB7: 0xFF77, 0xB8: 0xFF78, 0xB9: 0xFF79, 0xBA: 0xFF7A, 0xBB: 0xFF7B, 0xBC: 0xFF7C, 0xBD: 0xFF7D, 0xBE: 0xFF7E, 0xBF: 0xFF7F, 0xC0: 0xFF80, 0xC1: 0xFF81, 0xC2: 0xFF82, 0xC3: 0xFF83, 0xC4: 0xFF84, 0xC5: 0xFF85, 0xC6: 0xFF86, 0xC7: 0xFF87, 0xC8: 0xFF88, 0xC9: 0xFF89, 0xCA: 0xFF8A, 0xCB: 0xFF8B, 0xCC: 0xFF8C, 0xCD: 0xFF8D, 0xCE: 0xFF8E, 0xCF: 0xFF8F, 0xD0: 0xFF90, 0xD1: 0xFF91, 0xD2: 0xFF92, 0xD3: 0xFF93, 0xD4: 0xFF94, 0xD5: 0xFF95, 0xD6: 0xFF96, 0xD7: 0xFF97, 0xD8: 0xFF98, 0xD9: 0xFF99, 0xDA: 0xFF9A, 0xDB: 0xFF9B, 0xDC: 0xFF9C, 0xDD: 0xFF9D, 0xDE: 0xFF9E, 0xDF: 0xFF9F, 0xE040: 0x6F3E, 0xE041: 0x6F13, 0xE042: 0x6EF7, 0xE043: 0x6F86, 0xE044: 0x6F7A, 0xE045: 0x6F78, 0xE046: 0x6F81, 0xE047: 0x6F80, 0xE048: 0x6F6F, 0xE049: 0x6F5B, 0xE04A: 0x6FF3, 0xE04B: 0x6F6D, 0xE04C: 0x6F82, 0xE04D: 0x6F7C, 0xE04E: 0x6F58, 0xE04F: 0x6F8E, 0xE050: 0x6F91, 0xE051: 0x6FC2, 0xE052: 0x6F66, 0xE053: 0x6FB3, 0xE054: 0x6FA3, 0xE055: 0x6FA1, 0xE056: 0x6FA4, 0xE057: 0x6FB9, 0xE058: 0x6FC6, 0xE059: 0x6FAA, 0xE05A: 0x6FDF, 0xE05B: 0x6FD5, 0xE05C: 0x6FEC, 0xE05D: 0x6FD4, 0xE05E: 0x6FD8, 0xE05F: 0x6FF1, 0xE060: 0x6FEE, 0xE061: 0x6FDB, 0xE062: 0x7009, 0xE063: 0x700B, 0xE064: 0x6FFA, 0xE065: 0x7011, 0xE066: 0x7001, 0xE067: 0x700F, 0xE068: 0x6FFE, 0xE069: 0x701B, 0xE06A: 0x701A, 0xE06B: 0x6F74, 0xE06C: 0x701D, 0xE06D: 0x7018, 0xE06E: 0x701F, 0xE06F: 0x7030, 0xE070: 0x703E, 0xE071: 0x7032, 0xE072: 0x7051, 0xE073: 0x7063, 0xE074: 0x7099, 0xE075: 0x7092, 0xE076: 0x70AF, 0xE077: 0x70F1, 0xE078: 0x70AC, 0xE079: 0x70B8, 0xE07A: 0x70B3, 0xE07B: 0x70AE, 0xE07C: 0x70DF, 0xE07D: 0x70CB, 0xE07E: 0x70DD, 0xE080: 0x70D9, 0xE081: 0x7109, 0xE082: 0x70FD, 0xE083: 0x711C, 0xE084: 0x7119, 0xE085: 0x7165, 0xE086: 0x7155, 0xE087: 0x7188, 0xE088: 0x7166, 0xE089: 0x7162, 0xE08A: 0x714C, 0xE08B: 0x7156, 0xE08C: 0x716C, 0xE08D: 0x718F, 0xE08E: 0x71FB, 0xE08F: 0x7184, 0xE090: 0x7195, 0xE091: 0x71A8, 0xE092: 0x71AC, 0xE093: 0x71D7, 0xE094: 0x71B9, 0xE095: 0x71BE, 0xE096: 0x71D2, 0xE097: 0x71C9, 0xE098: 0x71D4, 0xE099: 0x71CE, 0xE09A: 0x71E0, 0xE09B: 0x71EC, 0xE09C: 0x71E7, 0xE09D: 0x71F5, 0xE09E: 0x71FC, 0xE09F: 0x71F9, 0xE0A0: 0x71FF, 0xE0A1: 0x720D, 0xE0A2: 0x7210, 0xE0A3: 0x721B, 0xE0A4: 0x7228, 0xE0A5: 0x722D, 0xE0A6: 0x722C, 0xE0A7: 0x7230, 0xE0A8: 0x7232, 0xE0A9: 0x723B, 0xE0AA: 0x723C, 0xE0AB: 0x723F, 0xE0AC: 0x7240, 0xE0AD: 0x7246, 0xE0AE: 0x724B, 0xE0AF: 0x7258, 0xE0B0: 0x7274, 0xE0B1: 0x727E, 0xE0B2: 0x7282, 0xE0B3: 0x7281, 0xE0B4: 0x7287, 0xE0B5: 0x7292, 0xE0B6: 0x7296, 0xE0B7: 0x72A2, 0xE0B8: 0x72A7, 0xE0B9: 0x72B9, 0xE0BA: 0x72B2, 0xE0BB: 0x72C3, 0xE0BC: 0x72C6, 0xE0BD: 0x72C4, 0xE0BE: 0x72CE, 0xE0BF: 0x72D2, 0xE0C0: 0x72E2, 0xE0C1: 0x72E0, 0xE0C2: 0x72E1, 0xE0C3: 0x72F9, 0xE0C4: 0x72F7, 0xE0C5: 0x500F, 0xE0C6: 0x7317, 0xE0C7: 0x730A, 0xE0C8: 0x731C, 0xE0C9: 0x7316, 0xE0CA: 0x731D, 0xE0CB: 0x7334, 0xE0CC: 0x732F, 0xE0CD: 0x7329, 0xE0CE: 0x7325, 0xE0CF: 0x733E, 0xE0D0: 0x734E, 0xE0D1: 0x734F, 0xE0D2: 0x9ED8, 0xE0D3: 0x7357, 0xE0D4: 0x736A, 0xE0D5: 0x7368, 0xE0D6: 0x7370, 0xE0D7: 0x7378, 0xE0D8: 0x7375, 0xE0D9: 0x737B, 0xE0DA: 0x737A, 0xE0DB: 0x73C8, 0xE0DC: 0x73B3, 0xE0DD: 0x73CE, 0xE0DE: 0x73BB, 0xE0DF: 0x73C0, 0xE0E0: 0x73E5, 0xE0E1: 0x73EE, 0xE0E2: 0x73DE, 0xE0E3: 0x74A2, 0xE0E4: 0x7405, 0xE0E5: 0x746F, 0xE0E6: 0x7425, 0xE0E7: 0x73F8, 0xE0E8: 0x7432, 0xE0E9: 0x743A, 0xE0EA: 0x7455, 0xE0EB: 0x743F, 0xE0EC: 0x745F, 0xE0ED: 0x7459, 0xE0EE: 0x7441, 0xE0EF: 0x745C, 0xE0F0: 0x7469, 0xE0F1: 0x7470, 0xE0F2: 0x7463, 0xE0F3: 0x746A, 0xE0F4: 0x7476, 0xE0F5: 0x747E, 0xE0F6: 0x748B, 0xE0F7: 0x749E, 0xE0F8: 0x74A7, 0xE0F9: 0x74CA, 0xE0FA: 0x74CF, 0xE0FB: 0x74D4, 0xE0FC: 0x73F1, 0xE140: 0x74E0, 0xE141: 0x74E3, 0xE142: 0x74E7, 0xE143: 0x74E9, 0xE144: 0x74EE, 0xE145: 0x74F2, 0xE146: 0x74F0, 0xE147: 0x74F1, 0xE148: 0x74F8, 0xE149: 0x74F7, 0xE14A: 0x7504, 0xE14B: 0x7503, 0xE14C: 0x7505, 0xE14D: 0x750C, 0xE14E: 0x750E, 0xE14F: 0x750D, 0xE150: 0x7515, 0xE151: 0x7513, 0xE152: 0x751E, 0xE153: 0x7526, 0xE154: 0x752C, 0xE155: 0x753C, 0xE156: 0x7544, 0xE157: 0x754D, 0xE158: 0x754A, 0xE159: 0x7549, 0xE15A: 0x755B, 0xE15B: 0x7546, 0xE15C: 0x755A, 0xE15D: 0x7569, 0xE15E: 0x7564, 0xE15F: 0x7567, 0xE160: 0x756B, 0xE161: 0x756D, 0xE162: 0x7578, 0xE163: 0x7576, 0xE164: 0x7586, 0xE165: 0x7587, 0xE166: 0x7574, 0xE167: 0x758A, 0xE168: 0x7589, 0xE169: 0x7582, 0xE16A: 0x7594, 0xE16B: 0x759A, 0xE16C: 0x759D, 0xE16D: 0x75A5, 0xE16E: 0x75A3, 0xE16F: 0x75C2, 0xE170: 0x75B3, 0xE171: 0x75C3, 0xE172: 0x75B5, 0xE173: 0x75BD, 0xE174: 0x75B8, 0xE175: 0x75BC, 0xE176: 0x75B1, 0xE177: 0x75CD, 0xE178: 0x75CA, 0xE179: 0x75D2, 0xE17A: 0x75D9, 0xE17B: 0x75E3, 0xE17C: 0x75DE, 0xE17D: 0x75FE, 0xE17E: 0x75FF, 0xE180: 0x75FC, 0xE181: 0x7601, 0xE182: 0x75F0, 0xE183: 0x75FA, 0xE184: 0x75F2, 0xE185: 0x75F3, 0xE186: 0x760B, 0xE187: 0x760D, 0xE188: 0x7609, 0xE189: 0x761F, 0xE18A: 0x7627, 0xE18B: 0x7620, 0xE18C: 0x7621, 0xE18D: 0x7622, 0xE18E: 0x7624, 0xE18F: 0x7634, 0xE190: 0x7630, 0xE191: 0x763B, 0xE192: 0x7647, 0xE193: 0x7648, 0xE194: 0x7646, 0xE195: 0x765C, 0xE196: 0x7658, 0xE197: 0x7661, 0xE198: 0x7662, 0xE199: 0x7668, 0xE19A: 0x7669, 0xE19B: 0x766A, 0xE19C: 0x7667, 0xE19D: 0x766C, 0xE19E: 0x7670, 0xE19F: 0x7672, 0xE1A0: 0x7676, 0xE1A1: 0x7678, 0xE1A2: 0x767C, 0xE1A3: 0x7680, 0xE1A4: 0x7683, 0xE1A5: 0x7688, 0xE1A6: 0x768B, 0xE1A7: 0x768E, 0xE1A8: 0x7696, 0xE1A9: 0x7693, 0xE1AA: 0x7699, 0xE1AB: 0x769A, 0xE1AC: 0x76B0, 0xE1AD: 0x76B4, 0xE1AE: 0x76B8, 0xE1AF: 0x76B9, 0xE1B0: 0x76BA, 0xE1B1: 0x76C2, 0xE1B2: 0x76CD, 0xE1B3: 0x76D6, 0xE1B4: 0x76D2, 0xE1B5: 0x76DE, 0xE1B6: 0x76E1, 0xE1B7: 0x76E5, 0xE1B8: 0x76E7, 0xE1B9: 0x76EA, 0xE1BA: 0x862F, 0xE1BB: 0x76FB, 0xE1BC: 0x7708, 0xE1BD: 0x7707, 0xE1BE: 0x7704, 0xE1BF: 0x7729, 0xE1C0: 0x7724, 0xE1C1: 0x771E, 0xE1C2: 0x7725, 0xE1C3: 0x7726, 0xE1C4: 0x771B, 0xE1C5: 0x7737, 0xE1C6: 0x7738, 0xE1C7: 0x7747, 0xE1C8: 0x775A, 0xE1C9: 0x7768, 0xE1CA: 0x776B, 0xE1CB: 0x775B, 0xE1CC: 0x7765, 0xE1CD: 0x777F, 0xE1CE: 0x777E, 0xE1CF: 0x7779, 0xE1D0: 0x778E, 0xE1D1: 0x778B, 0xE1D2: 0x7791, 0xE1D3: 0x77A0, 0xE1D4: 0x779E, 0xE1D5: 0x77B0, 0xE1D6: 0x77B6, 0xE1D7: 0x77B9, 0xE1D8: 0x77BF, 0xE1D9: 0x77BC, 0xE1DA: 0x77BD, 0xE1DB: 0x77BB, 0xE1DC: 0x77C7, 0xE1DD: 0x77CD, 0xE1DE: 0x77D7, 0xE1DF: 0x77DA, 0xE1E0: 0x77DC, 0xE1E1: 0x77E3, 0xE1E2: 0x77EE, 0xE1E3: 0x77FC, 0xE1E4: 0x780C, 0xE1E5: 0x7812, 0xE1E6: 0x7926, 0xE1E7: 0x7820, 0xE1E8: 0x792A, 0xE1E9: 0x7845, 0xE1EA: 0x788E, 0xE1EB: 0x7874, 0xE1EC: 0x7886, 0xE1ED: 0x787C, 0xE1EE: 0x789A, 0xE1EF: 0x788C, 0xE1F0: 0x78A3, 0xE1F1: 0x78B5, 0xE1F2: 0x78AA, 0xE1F3: 0x78AF, 0xE1F4: 0x78D1, 0xE1F5: 0x78C6, 0xE1F6: 0x78CB, 0xE1F7: 0x78D4, 0xE1F8: 0x78BE, 0xE1F9: 0x78BC, 0xE1FA: 0x78C5, 0xE1FB: 0x78CA, 0xE1FC: 0x78EC, 0xE240: 0x78E7, 0xE241: 0x78DA, 0xE242: 0x78FD, 0xE243: 0x78F4, 0xE244: 0x7907, 0xE245: 0x7912, 0xE246: 0x7911, 0xE247: 0x7919, 0xE248: 0x792C, 0xE249: 0x792B, 0xE24A: 0x7940, 0xE24B: 0x7960, 0xE24C: 0x7957, 0xE24D: 0x795F, 0xE24E: 0x795A, 0xE24F: 0x7955, 0xE250: 0x7953, 0xE251: 0x797A, 0xE252: 0x797F, 0xE253: 0x798A, 0xE254: 0x799D, 0xE255: 0x79A7, 0xE256: 0x9F4B, 0xE257: 0x79AA, 0xE258: 0x79AE, 0xE259: 0x79B3, 0xE25A: 0x79B9, 0xE25B: 0x79BA, 0xE25C: 0x79C9, 0xE25D: 0x79D5, 0xE25E: 0x79E7, 0xE25F: 0x79EC, 0xE260: 0x79E1, 0xE261: 0x79E3, 0xE262: 0x7A08, 0xE263: 0x7A0D, 0xE264: 0x7A18, 0xE265: 0x7A19, 0xE266: 0x7A20, 0xE267: 0x7A1F, 0xE268: 0x7980, 0xE269: 0x7A31, 0xE26A: 0x7A3B, 0xE26B: 0x7A3E, 0xE26C: 0x7A37, 0xE26D: 0x7A43, 0xE26E: 0x7A57, 0xE26F: 0x7A49, 0xE270: 0x7A61, 0xE271: 0x7A62, 0xE272: 0x7A69, 0xE273: 0x9F9D, 0xE274: 0x7A70, 0xE275: 0x7A79, 0xE276: 0x7A7D, 0xE277: 0x7A88, 0xE278: 0x7A97, 0xE279: 0x7A95, 0xE27A: 0x7A98, 0xE27B: 0x7A96, 0xE27C: 0x7AA9, 0xE27D: 0x7AC8, 0xE27E: 0x7AB0, 0xE280: 0x7AB6, 0xE281: 0x7AC5, 0xE282: 0x7AC4, 0xE283: 0x7ABF, 0xE284: 0x9083, 0xE285: 0x7AC7, 0xE286: 0x7ACA, 0xE287: 0x7ACD, 0xE288: 0x7ACF, 0xE289: 0x7AD5, 0xE28A: 0x7AD3, 0xE28B: 0x7AD9, 0xE28C: 0x7ADA, 0xE28D: 0x7ADD, 0xE28E: 0x7AE1, 0xE28F: 0x7AE2, 0xE290: 0x7AE6, 0xE291: 0x7AED, 0xE292: 0x7AF0, 0xE293: 0x7B02, 0xE294: 0x7B0F, 0xE295: 0x7B0A, 0xE296: 0x7B06, 0xE297: 0x7B33, 0xE298: 0x7B18, 0xE299: 0x7B19, 0xE29A: 0x7B1E, 0xE29B: 0x7B35, 0xE29C: 0x7B28, 0xE29D: 0x7B36, 0xE29E: 0x7B50, 0xE29F: 0x7B7A, 0xE2A0: 0x7B04, 0xE2A1: 0x7B4D, 0xE2A2: 0x7B0B, 0xE2A3: 0x7B4C, 0xE2A4: 0x7B45, 0xE2A5: 0x7B75, 0xE2A6: 0x7B65, 0xE2A7: 0x7B74, 0xE2A8: 0x7B67, 0xE2A9: 0x7B70, 0xE2AA: 0x7B71, 0xE2AB: 0x7B6C, 0xE2AC: 0x7B6E, 0xE2AD: 0x7B9D, 0xE2AE: 0x7B98, 0xE2AF: 0x7B9F, 0xE2B0: 0x7B8D, 0xE2B1: 0x7B9C, 0xE2B2: 0x7B9A, 0xE2B3: 0x7B8B, 0xE2B4: 0x7B92, 0xE2B5: 0x7B8F, 0xE2B6: 0x7B5D, 0xE2B7: 0x7B99, 0xE2B8: 0x7BCB, 0xE2B9: 0x7BC1, 0xE2BA: 0x7BCC, 0xE2BB: 0x7BCF, 0xE2BC: 0x7BB4, 0xE2BD: 0x7BC6, 0xE2BE: 0x7BDD, 0xE2BF: 0x7BE9, 0xE2C0: 0x7C11, 0xE2C1: 0x7C14, 0xE2C2: 0x7BE6, 0xE2C3: 0x7BE5, 0xE2C4: 0x7C60, 0xE2C5: 0x7C00, 0xE2C6: 0x7C07, 0xE2C7: 0x7C13, 0xE2C8: 0x7BF3, 0xE2C9: 0x7BF7, 0xE2CA: 0x7C17, 0xE2CB: 0x7C0D, 0xE2CC: 0x7BF6, 0xE2CD: 0x7C23, 0xE2CE: 0x7C27, 0xE2CF: 0x7C2A, 0xE2D0: 0x7C1F, 0xE2D1: 0x7C37, 0xE2D2: 0x7C2B, 0xE2D3: 0x7C3D, 0xE2D4: 0x7C4C, 0xE2D5: 0x7C43, 0xE2D6: 0x7C54, 0xE2D7: 0x7C4F, 0xE2D8: 0x7C40, 0xE2D9: 0x7C50, 0xE2DA: 0x7C58, 0xE2DB: 0x7C5F, 0xE2DC: 0x7C64, 0xE2DD: 0x7C56, 0xE2DE: 0x7C65, 0xE2DF: 0x7C6C, 0xE2E0: 0x7C75, 0xE2E1: 0x7C83, 0xE2E2: 0x7C90, 0xE2E3: 0x7CA4, 0xE2E4: 0x7CAD, 0xE2E5: 0x7CA2, 0xE2E6: 0x7CAB, 0xE2E7: 0x7CA1, 0xE2E8: 0x7CA8, 0xE2E9: 0x7CB3, 0xE2EA: 0x7CB2, 0xE2EB: 0x7CB1, 0xE2EC: 0x7CAE, 0xE2ED: 0x7CB9, 0xE2EE: 0x7CBD, 0xE2EF: 0x7CC0, 0xE2F0: 0x7CC5, 0xE2F1: 0x7CC2, 0xE2F2: 0x7CD8, 0xE2F3: 0x7CD2, 0xE2F4: 0x7CDC, 0xE2F5: 0x7CE2, 0xE2F6: 0x9B3B, 0xE2F7: 0x7CEF, 0xE2F8: 0x7CF2, 0xE2F9: 0x7CF4, 0xE2FA: 0x7CF6, 0xE2FB: 0x7CFA, 0xE2FC: 0x7D06, 0xE340: 0x7D02, 0xE341: 0x7D1C, 0xE342: 0x7D15, 0xE343: 0x7D0A, 0xE344: 0x7D45, 0xE345: 0x7D4B, 0xE346: 0x7D2E, 0xE347: 0x7D32, 0xE348: 0x7D3F, 0xE349: 0x7D35, 0xE34A: 0x7D46, 0xE34B: 0x7D73, 0xE34C: 0x7D56, 0xE34D: 0x7D4E, 0xE34E: 0x7D72, 0xE34F: 0x7D68, 0xE350: 0x7D6E, 0xE351: 0x7D4F, 0xE352: 0x7D63, 0xE353: 0x7D93, 0xE354: 0x7D89, 0xE355: 0x7D5B, 0xE356: 0x7D8F, 0xE357: 0x7D7D, 0xE358: 0x7D9B, 0xE359: 0x7DBA, 0xE35A: 0x7DAE, 0xE35B: 0x7DA3, 0xE35C: 0x7DB5, 0xE35D: 0x7DC7, 0xE35E: 0x7DBD, 0xE35F: 0x7DAB, 0xE360: 0x7E3D, 0xE361: 0x7DA2, 0xE362: 0x7DAF, 0xE363: 0x7DDC, 0xE364: 0x7DB8, 0xE365: 0x7D9F, 0xE366: 0x7DB0, 0xE367: 0x7DD8, 0xE368: 0x7DDD, 0xE369: 0x7DE4, 0xE36A: 0x7DDE, 0xE36B: 0x7DFB, 0xE36C: 0x7DF2, 0xE36D: 0x7DE1, 0xE36E: 0x7E05, 0xE36F: 0x7E0A, 0xE370: 0x7E23, 0xE371: 0x7E21, 0xE372: 0x7E12, 0xE373: 0x7E31, 0xE374: 0x7E1F, 0xE375: 0x7E09, 0xE376: 0x7E0B, 0xE377: 0x7E22, 0xE378: 0x7E46, 0xE379: 0x7E66, 0xE37A: 0x7E3B, 0xE37B: 0x7E35, 0xE37C: 0x7E39, 0xE37D: 0x7E43, 0xE37E: 0x7E37, 0xE380: 0x7E32, 0xE381: 0x7E3A, 0xE382: 0x7E67, 0xE383: 0x7E5D, 0xE384: 0x7E56, 0xE385: 0x7E5E, 0xE386: 0x7E59, 0xE387: 0x7E5A, 0xE388: 0x7E79, 0xE389: 0x7E6A, 0xE38A: 0x7E69, 0xE38B: 0x7E7C, 0xE38C: 0x7E7B, 0xE38D: 0x7E83, 0xE38E: 0x7DD5, 0xE38F: 0x7E7D, 0xE390: 0x8FAE, 0xE391: 0x7E7F, 0xE392: 0x7E88, 0xE393: 0x7E89, 0xE394: 0x7E8C, 0xE395: 0x7E92, 0xE396: 0x7E90, 0xE397: 0x7E93, 0xE398: 0x7E94, 0xE399: 0x7E96, 0xE39A: 0x7E8E, 0xE39B: 0x7E9B, 0xE39C: 0x7E9C, 0xE39D: 0x7F38, 0xE39E: 0x7F3A, 0xE39F: 0x7F45, 0xE3A0: 0x7F4C, 0xE3A1: 0x7F4D, 0xE3A2: 0x7F4E, 0xE3A3: 0x7F50, 0xE3A4: 0x7F51, 0xE3A5: 0x7F55, 0xE3A6: 0x7F54, 0xE3A7: 0x7F58, 0xE3A8: 0x7F5F, 0xE3A9: 0x7F60, 0xE3AA: 0x7F68, 0xE3AB: 0x7F69, 0xE3AC: 0x7F67, 0xE3AD: 0x7F78, 0xE3AE: 0x7F82, 0xE3AF: 0x7F86, 0xE3B0: 0x7F83, 0xE3B1: 0x7F88, 0xE3B2: 0x7F87, 0xE3B3: 0x7F8C, 0xE3B4: 0x7F94, 0xE3B5: 0x7F9E, 0xE3B6: 0x7F9D, 0xE3B7: 0x7F9A, 0xE3B8: 0x7FA3, 0xE3B9: 0x7FAF, 0xE3BA: 0x7FB2, 0xE3BB: 0x7FB9, 0xE3BC: 0x7FAE, 0xE3BD: 0x7FB6, 0xE3BE: 0x7FB8, 0xE3BF: 0x8B71, 0xE3C0: 0x7FC5, 0xE3C1: 0x7FC6, 0xE3C2: 0x7FCA, 0xE3C3: 0x7FD5, 0xE3C4: 0x7FD4, 0xE3C5: 0x7FE1, 0xE3C6: 0x7FE6, 0xE3C7: 0x7FE9, 0xE3C8: 0x7FF3, 0xE3C9: 0x7FF9, 0xE3CA: 0x98DC, 0xE3CB: 0x8006, 0xE3CC: 0x8004, 0xE3CD: 0x800B, 0xE3CE: 0x8012, 0xE3CF: 0x8018, 0xE3D0: 0x8019, 0xE3D1: 0x801C, 0xE3D2: 0x8021, 0xE3D3: 0x8028, 0xE3D4: 0x803F, 0xE3D5: 0x803B, 0xE3D6: 0x804A, 0xE3D7: 0x8046, 0xE3D8: 0x8052, 0xE3D9: 0x8058, 0xE3DA: 0x805A, 0xE3DB: 0x805F, 0xE3DC: 0x8062, 0xE3DD: 0x8068, 0xE3DE: 0x8073, 0xE3DF: 0x8072, 0xE3E0: 0x8070, 0xE3E1: 0x8076, 0xE3E2: 0x8079, 0xE3E3: 0x807D, 0xE3E4: 0x807F, 0xE3E5: 0x8084, 0xE3E6: 0x8086, 0xE3E7: 0x8085, 0xE3E8: 0x809B, 0xE3E9: 0x8093, 0xE3EA: 0x809A, 0xE3EB: 0x80AD, 0xE3EC: 0x5190, 0xE3ED: 0x80AC, 0xE3EE: 0x80DB, 0xE3EF: 0x80E5, 0xE3F0: 0x80D9, 0xE3F1: 0x80DD, 0xE3F2: 0x80C4, 0xE3F3: 0x80DA, 0xE3F4: 0x80D6, 0xE3F5: 0x8109, 0xE3F6: 0x80EF, 0xE3F7: 0x80F1, 0xE3F8: 0x811B, 0xE3F9: 0x8129, 0xE3FA: 0x8123, 0xE3FB: 0x812F, 0xE3FC: 0x814B, 0xE440: 0x968B, 0xE441: 0x8146, 0xE442: 0x813E, 0xE443: 0x8153, 0xE444: 0x8151, 0xE445: 0x80FC, 0xE446: 0x8171, 0xE447: 0x816E, 0xE448: 0x8165, 0xE449: 0x8166, 0xE44A: 0x8174, 0xE44B: 0x8183, 0xE44C: 0x8188, 0xE44D: 0x818A, 0xE44E: 0x8180, 0xE44F: 0x8182, 0xE450: 0x81A0, 0xE451: 0x8195, 0xE452: 0x81A4, 0xE453: 0x81A3, 0xE454: 0x815F, 0xE455: 0x8193, 0xE456: 0x81A9, 0xE457: 0x81B0, 0xE458: 0x81B5, 0xE459: 0x81BE, 0xE45A: 0x81B8, 0xE45B: 0x81BD, 0xE45C: 0x81C0, 0xE45D: 0x81C2, 0xE45E: 0x81BA, 0xE45F: 0x81C9, 0xE460: 0x81CD, 0xE461: 0x81D1, 0xE462: 0x81D9, 0xE463: 0x81D8, 0xE464: 0x81C8, 0xE465: 0x81DA, 0xE466: 0x81DF, 0xE467: 0x81E0, 0xE468: 0x81E7, 0xE469: 0x81FA, 0xE46A: 0x81FB, 0xE46B: 0x81FE, 0xE46C: 0x8201, 0xE46D: 0x8202, 0xE46E: 0x8205, 0xE46F: 0x8207, 0xE470: 0x820A, 0xE471: 0x820D, 0xE472: 0x8210, 0xE473: 0x8216, 0xE474: 0x8229, 0xE475: 0x822B, 0xE476: 0x8238, 0xE477: 0x8233, 0xE478: 0x8240, 0xE479: 0x8259, 0xE47A: 0x8258, 0xE47B: 0x825D, 0xE47C: 0x825A, 0xE47D: 0x825F, 0xE47E: 0x8264, 0xE480: 0x8262, 0xE481: 0x8268, 0xE482: 0x826A, 0xE483: 0x826B, 0xE484: 0x822E, 0xE485: 0x8271, 0xE486: 0x8277, 0xE487: 0x8278, 0xE488: 0x827E, 0xE489: 0x828D, 0xE48A: 0x8292, 0xE48B: 0x82AB, 0xE48C: 0x829F, 0xE48D: 0x82BB, 0xE48E: 0x82AC, 0xE48F: 0x82E1, 0xE490: 0x82E3, 0xE491: 0x82DF, 0xE492: 0x82D2, 0xE493: 0x82F4, 0xE494: 0x82F3, 0xE495: 0x82FA, 0xE496: 0x8393, 0xE497: 0x8303, 0xE498: 0x82FB, 0xE499: 0x82F9, 0xE49A: 0x82DE, 0xE49B: 0x8306, 0xE49C: 0x82DC, 0xE49D: 0x8309, 0xE49E: 0x82D9, 0xE49F: 0x8335, 0xE4A0: 0x8334, 0xE4A1: 0x8316, 0xE4A2: 0x8332, 0xE4A3: 0x8331, 0xE4A4: 0x8340, 0xE4A5: 0x8339, 0xE4A6: 0x8350, 0xE4A7: 0x8345, 0xE4A8: 0x832F, 0xE4A9: 0x832B, 0xE4AA: 0x8317, 0xE4AB: 0x8318, 0xE4AC: 0x8385, 0xE4AD: 0x839A, 0xE4AE: 0x83AA, 0xE4AF: 0x839F, 0xE4B0: 0x83A2, 0xE4B1: 0x8396, 0xE4B2: 0x8323, 0xE4B3: 0x838E, 0xE4B4: 0x8387, 0xE4B5: 0x838A, 0xE4B6: 0x837C, 0xE4B7: 0x83B5, 0xE4B8: 0x8373, 0xE4B9: 0x8375, 0xE4BA: 0x83A0, 0xE4BB: 0x8389, 0xE4BC: 0x83A8, 0xE4BD: 0x83F4, 0xE4BE: 0x8413, 0xE4BF: 0x83EB, 0xE4C0: 0x83CE, 0xE4C1: 0x83FD, 0xE4C2: 0x8403, 0xE4C3: 0x83D8, 0xE4C4: 0x840B, 0xE4C5: 0x83C1, 0xE4C6: 0x83F7, 0xE4C7: 0x8407, 0xE4C8: 0x83E0, 0xE4C9: 0x83F2, 0xE4CA: 0x840D, 0xE4CB: 0x8422, 0xE4CC: 0x8420, 0xE4CD: 0x83BD, 0xE4CE: 0x8438, 0xE4CF: 0x8506, 0xE4D0: 0x83FB, 0xE4D1: 0x846D, 0xE4D2: 0x842A, 0xE4D3: 0x843C, 0xE4D4: 0x855A, 0xE4D5: 0x8484, 0xE4D6: 0x8477, 0xE4D7: 0x846B, 0xE4D8: 0x84AD, 0xE4D9: 0x846E, 0xE4DA: 0x8482, 0xE4DB: 0x8469, 0xE4DC: 0x8446, 0xE4DD: 0x842C, 0xE4DE: 0x846F, 0xE4DF: 0x8479, 0xE4E0: 0x8435, 0xE4E1: 0x84CA, 0xE4E2: 0x8462, 0xE4E3: 0x84B9, 0xE4E4: 0x84BF, 0xE4E5: 0x849F, 0xE4E6: 0x84D9, 0xE4E7: 0x84CD, 0xE4E8: 0x84BB, 0xE4E9: 0x84DA, 0xE4EA: 0x84D0, 0xE4EB: 0x84C1, 0xE4EC: 0x84C6, 0xE4ED: 0x84D6, 0xE4EE: 0x84A1, 0xE4EF: 0x8521, 0xE4F0: 0x84FF, 0xE4F1: 0x84F4, 0xE4F2: 0x8517, 0xE4F3: 0x8518, 0xE4F4: 0x852C, 0xE4F5: 0x851F, 0xE4F6: 0x8515, 0xE4F7: 0x8514, 0xE4F8: 0x84FC, 0xE4F9: 0x8540, 0xE4FA: 0x8563, 0xE4FB: 0x8558, 0xE4FC: 0x8548, 0xE540: 0x8541, 0xE541: 0x8602, 0xE542: 0x854B, 0xE543: 0x8555, 0xE544: 0x8580, 0xE545: 0x85A4, 0xE546: 0x8588, 0xE547: 0x8591, 0xE548: 0x858A, 0xE549: 0x85A8, 0xE54A: 0x856D, 0xE54B: 0x8594, 0xE54C: 0x859B, 0xE54D: 0x85EA, 0xE54E: 0x8587, 0xE54F: 0x859C, 0xE550: 0x8577, 0xE551: 0x857E, 0xE552: 0x8590, 0xE553: 0x85C9, 0xE554: 0x85BA, 0xE555: 0x85CF, 0xE556: 0x85B9, 0xE557: 0x85D0, 0xE558: 0x85D5, 0xE559: 0x85DD, 0xE55A: 0x85E5, 0xE55B: 0x85DC, 0xE55C: 0x85F9, 0xE55D: 0x860A, 0xE55E: 0x8613, 0xE55F: 0x860B, 0xE560: 0x85FE, 0xE561: 0x85FA, 0xE562: 0x8606, 0xE563: 0x8622, 0xE564: 0x861A, 0xE565: 0x8630, 0xE566: 0x863F, 0xE567: 0x864D, 0xE568: 0x4E55, 0xE569: 0x8654, 0xE56A: 0x865F, 0xE56B: 0x8667, 0xE56C: 0x8671, 0xE56D: 0x8693, 0xE56E: 0x86A3, 0xE56F: 0x86A9, 0xE570: 0x86AA, 0xE571: 0x868B, 0xE572: 0x868C, 0xE573: 0x86B6, 0xE574: 0x86AF, 0xE575: 0x86C4, 0xE576: 0x86C6, 0xE577: 0x86B0, 0xE578: 0x86C9, 0xE579: 0x8823, 0xE57A: 0x86AB, 0xE57B: 0x86D4, 0xE57C: 0x86DE, 0xE57D: 0x86E9, 0xE57E: 0x86EC, 0xE580: 0x86DF, 0xE581: 0x86DB, 0xE582: 0x86EF, 0xE583: 0x8712, 0xE584: 0x8706, 0xE585: 0x8708, 0xE586: 0x8700, 0xE587: 0x8703, 0xE588: 0x86FB, 0xE589: 0x8711, 0xE58A: 0x8709, 0xE58B: 0x870D, 0xE58C: 0x86F9, 0xE58D: 0x870A, 0xE58E: 0x8734, 0xE58F: 0x873F, 0xE590: 0x8737, 0xE591: 0x873B, 0xE592: 0x8725, 0xE593: 0x8729, 0xE594: 0x871A, 0xE595: 0x8760, 0xE596: 0x875F, 0xE597: 0x8778, 0xE598: 0x874C, 0xE599: 0x874E, 0xE59A: 0x8774, 0xE59B: 0x8757, 0xE59C: 0x8768, 0xE59D: 0x876E, 0xE59E: 0x8759, 0xE59F: 0x8753, 0xE5A0: 0x8763, 0xE5A1: 0x876A, 0xE5A2: 0x8805, 0xE5A3: 0x87A2, 0xE5A4: 0x879F, 0xE5A5: 0x8782, 0xE5A6: 0x87AF, 0xE5A7: 0x87CB, 0xE5A8: 0x87BD, 0xE5A9: 0x87C0, 0xE5AA: 0x87D0, 0xE5AB: 0x96D6, 0xE5AC: 0x87AB, 0xE5AD: 0x87C4, 0xE5AE: 0x87B3, 0xE5AF: 0x87C7, 0xE5B0: 0x87C6, 0xE5B1: 0x87BB, 0xE5B2: 0x87EF, 0xE5B3: 0x87F2, 0xE5B4: 0x87E0, 0xE5B5: 0x880F, 0xE5B6: 0x880D, 0xE5B7: 0x87FE, 0xE5B8: 0x87F6, 0xE5B9: 0x87F7, 0xE5BA: 0x880E, 0xE5BB: 0x87D2, 0xE5BC: 0x8811, 0xE5BD: 0x8816, 0xE5BE: 0x8815, 0xE5BF: 0x8822, 0xE5C0: 0x8821, 0xE5C1: 0x8831, 0xE5C2: 0x8836, 0xE5C3: 0x8839, 0xE5C4: 0x8827, 0xE5C5: 0x883B, 0xE5C6: 0x8844, 0xE5C7: 0x8842, 0xE5C8: 0x8852, 0xE5C9: 0x8859, 0xE5CA: 0x885E, 0xE5CB: 0x8862, 0xE5CC: 0x886B, 0xE5CD: 0x8881, 0xE5CE: 0x887E, 0xE5CF: 0x889E, 0xE5D0: 0x8875, 0xE5D1: 0x887D, 0xE5D2: 0x88B5, 0xE5D3: 0x8872, 0xE5D4: 0x8882, 0xE5D5: 0x8897, 0xE5D6: 0x8892, 0xE5D7: 0x88AE, 0xE5D8: 0x8899, 0xE5D9: 0x88A2, 0xE5DA: 0x888D, 0xE5DB: 0x88A4, 0xE5DC: 0x88B0, 0xE5DD: 0x88BF, 0xE5DE: 0x88B1, 0xE5DF: 0x88C3, 0xE5E0: 0x88C4, 0xE5E1: 0x88D4, 0xE5E2: 0x88D8, 0xE5E3: 0x88D9, 0xE5E4: 0x88DD, 0xE5E5: 0x88F9, 0xE5E6: 0x8902, 0xE5E7: 0x88FC, 0xE5E8: 0x88F4, 0xE5E9: 0x88E8, 0xE5EA: 0x88F2, 0xE5EB: 0x8904, 0xE5EC: 0x890C, 0xE5ED: 0x890A, 0xE5EE: 0x8913, 0xE5EF: 0x8943, 0xE5F0: 0x891E, 0xE5F1: 0x8925, 0xE5F2: 0x892A, 0xE5F3: 0x892B, 0xE5F4: 0x8941, 0xE5F5: 0x8944, 0xE5F6: 0x893B, 0xE5F7: 0x8936, 0xE5F8: 0x8938, 0xE5F9: 0x894C, 0xE5FA: 0x891D, 0xE5FB: 0x8960, 0xE5FC: 0x895E, 0xE640: 0x8966, 0xE641: 0x8964, 0xE642: 0x896D, 0xE643: 0x896A, 0xE644: 0x896F, 0xE645: 0x8974, 0xE646: 0x8977, 0xE647: 0x897E, 0xE648: 0x8983, 0xE649: 0x8988, 0xE64A: 0x898A, 0xE64B: 0x8993, 0xE64C: 0x8998, 0xE64D: 0x89A1, 0xE64E: 0x89A9, 0xE64F: 0x89A6, 0xE650: 0x89AC, 0xE651: 0x89AF, 0xE652: 0x89B2, 0xE653: 0x89BA, 0xE654: 0x89BD, 0xE655: 0x89BF, 0xE656: 0x89C0, 0xE657: 0x89DA, 0xE658: 0x89DC, 0xE659: 0x89DD, 0xE65A: 0x89E7, 0xE65B: 0x89F4, 0xE65C: 0x89F8, 0xE65D: 0x8A03, 0xE65E: 0x8A16, 0xE65F: 0x8A10, 0xE660: 0x8A0C, 0xE661: 0x8A1B, 0xE662: 0x8A1D, 0xE663: 0x8A25, 0xE664: 0x8A36, 0xE665: 0x8A41, 0xE666: 0x8A5B, 0xE667: 0x8A52, 0xE668: 0x8A46, 0xE669: 0x8A48, 0xE66A: 0x8A7C, 0xE66B: 0x8A6D, 0xE66C: 0x8A6C, 0xE66D: 0x8A62, 0xE66E: 0x8A85, 0xE66F: 0x8A82, 0xE670: 0x8A84, 0xE671: 0x8AA8, 0xE672: 0x8AA1, 0xE673: 0x8A91, 0xE674: 0x8AA5, 0xE675: 0x8AA6, 0xE676: 0x8A9A, 0xE677: 0x8AA3, 0xE678: 0x8AC4, 0xE679: 0x8ACD, 0xE67A: 0x8AC2, 0xE67B: 0x8ADA, 0xE67C: 0x8AEB, 0xE67D: 0x8AF3, 0xE67E: 0x8AE7, 0xE680: 0x8AE4, 0xE681: 0x8AF1, 0xE682: 0x8B14, 0xE683: 0x8AE0, 0xE684: 0x8AE2, 0xE685: 0x8AF7, 0xE686: 0x8ADE, 0xE687: 0x8ADB, 0xE688: 0x8B0C, 0xE689: 0x8B07, 0xE68A: 0x8B1A, 0xE68B: 0x8AE1, 0xE68C: 0x8B16, 0xE68D: 0x8B10, 0xE68E: 0x8B17, 0xE68F: 0x8B20, 0xE690: 0x8B33, 0xE691: 0x97AB, 0xE692: 0x8B26, 0xE693: 0x8B2B, 0xE694: 0x8B3E, 0xE695: 0x8B28, 0xE696: 0x8B41, 0xE697: 0x8B4C, 0xE698: 0x8B4F, 0xE699: 0x8B4E, 0xE69A: 0x8B49, 0xE69B: 0x8B56, 0xE69C: 0x8B5B, 0xE69D: 0x8B5A, 0xE69E: 0x8B6B, 0xE69F: 0x8B5F, 0xE6A0: 0x8B6C, 0xE6A1: 0x8B6F, 0xE6A2: 0x8B74, 0xE6A3: 0x8B7D, 0xE6A4: 0x8B80, 0xE6A5: 0x8B8C, 0xE6A6: 0x8B8E, 0xE6A7: 0x8B92, 0xE6A8: 0x8B93, 0xE6A9: 0x8B96, 0xE6AA: 0x8B99, 0xE6AB: 0x8B9A, 0xE6AC: 0x8C3A, 0xE6AD: 0x8C41, 0xE6AE: 0x8C3F, 0xE6AF: 0x8C48, 0xE6B0: 0x8C4C, 0xE6B1: 0x8C4E, 0xE6B2: 0x8C50, 0xE6B3: 0x8C55, 0xE6B4: 0x8C62, 0xE6B5: 0x8C6C, 0xE6B6: 0x8C78, 0xE6B7: 0x8C7A, 0xE6B8: 0x8C82, 0xE6B9: 0x8C89, 0xE6BA: 0x8C85, 0xE6BB: 0x8C8A, 0xE6BC: 0x8C8D, 0xE6BD: 0x8C8E, 0xE6BE: 0x8C94, 0xE6BF: 0x8C7C, 0xE6C0: 0x8C98, 0xE6C1: 0x621D, 0xE6C2: 0x8CAD, 0xE6C3: 0x8CAA, 0xE6C4: 0x8CBD, 0xE6C5: 0x8CB2, 0xE6C6: 0x8CB3, 0xE6C7: 0x8CAE, 0xE6C8: 0x8CB6, 0xE6C9: 0x8CC8, 0xE6CA: 0x8CC1, 0xE6CB: 0x8CE4, 0xE6CC: 0x8CE3, 0xE6CD: 0x8CDA, 0xE6CE: 0x8CFD, 0xE6CF: 0x8CFA, 0xE6D0: 0x8CFB, 0xE6D1: 0x8D04, 0xE6D2: 0x8D05, 0xE6D3: 0x8D0A, 0xE6D4: 0x8D07, 0xE6D5: 0x8D0F, 0xE6D6: 0x8D0D, 0xE6D7: 0x8D10, 0xE6D8: 0x9F4E, 0xE6D9: 0x8D13, 0xE6DA: 0x8CCD, 0xE6DB: 0x8D14, 0xE6DC: 0x8D16, 0xE6DD: 0x8D67, 0xE6DE: 0x8D6D, 0xE6DF: 0x8D71, 0xE6E0: 0x8D73, 0xE6E1: 0x8D81, 0xE6E2: 0x8D99, 0xE6E3: 0x8DC2, 0xE6E4: 0x8DBE, 0xE6E5: 0x8DBA, 0xE6E6: 0x8DCF, 0xE6E7: 0x8DDA, 0xE6E8: 0x8DD6, 0xE6E9: 0x8DCC, 0xE6EA: 0x8DDB, 0xE6EB: 0x8DCB, 0xE6EC: 0x8DEA, 0xE6ED: 0x8DEB, 0xE6EE: 0x8DDF, 0xE6EF: 0x8DE3, 0xE6F0: 0x8DFC, 0xE6F1: 0x8E08, 0xE6F2: 0x8E09, 0xE6F3: 0x8DFF, 0xE6F4: 0x8E1D, 0xE6F5: 0x8E1E, 0xE6F6: 0x8E10, 0xE6F7: 0x8E1F, 0xE6F8: 0x8E42, 0xE6F9: 0x8E35, 0xE6FA: 0x8E30, 0xE6FB: 0x8E34, 0xE6FC: 0x8E4A, 0xE740: 0x8E47, 0xE741: 0x8E49, 0xE742: 0x8E4C, 0xE743: 0x8E50, 0xE744: 0x8E48, 0xE745: 0x8E59, 0xE746: 0x8E64, 0xE747: 0x8E60, 0xE748: 0x8E2A, 0xE749: 0x8E63, 0xE74A: 0x8E55, 0xE74B: 0x8E76, 0xE74C: 0x8E72, 0xE74D: 0x8E7C, 0xE74E: 0x8E81, 0xE74F: 0x8E87, 0xE750: 0x8E85, 0xE751: 0x8E84, 0xE752: 0x8E8B, 0xE753: 0x8E8A, 0xE754: 0x8E93, 0xE755: 0x8E91, 0xE756: 0x8E94, 0xE757: 0x8E99, 0xE758: 0x8EAA, 0xE759: 0x8EA1, 0xE75A: 0x8EAC, 0xE75B: 0x8EB0, 0xE75C: 0x8EC6, 0xE75D: 0x8EB1, 0xE75E: 0x8EBE, 0xE75F: 0x8EC5, 0xE760: 0x8EC8, 0xE761: 0x8ECB, 0xE762: 0x8EDB, 0xE763: 0x8EE3, 0xE764: 0x8EFC, 0xE765: 0x8EFB, 0xE766: 0x8EEB, 0xE767: 0x8EFE, 0xE768: 0x8F0A, 0xE769: 0x8F05, 0xE76A: 0x8F15, 0xE76B: 0x8F12, 0xE76C: 0x8F19, 0xE76D: 0x8F13, 0xE76E: 0x8F1C, 0xE76F: 0x8F1F, 0xE770: 0x8F1B, 0xE771: 0x8F0C, 0xE772: 0x8F26, 0xE773: 0x8F33, 0xE774: 0x8F3B, 0xE775: 0x8F39, 0xE776: 0x8F45, 0xE777: 0x8F42, 0xE778: 0x8F3E, 0xE779: 0x8F4C, 0xE77A: 0x8F49, 0xE77B: 0x8F46, 0xE77C: 0x8F4E, 0xE77D: 0x8F57, 0xE77E: 0x8F5C, 0xE780: 0x8F62, 0xE781: 0x8F63, 0xE782: 0x8F64, 0xE783: 0x8F9C, 0xE784: 0x8F9F, 0xE785: 0x8FA3, 0xE786: 0x8FAD, 0xE787: 0x8FAF, 0xE788: 0x8FB7, 0xE789: 0x8FDA, 0xE78A: 0x8FE5, 0xE78B: 0x8FE2, 0xE78C: 0x8FEA, 0xE78D: 0x8FEF, 0xE78E: 0x9087, 0xE78F: 0x8FF4, 0xE790: 0x9005, 0xE791: 0x8FF9, 0xE792: 0x8FFA, 0xE793: 0x9011, 0xE794: 0x9015, 0xE795: 0x9021, 0xE796: 0x900D, 0xE797: 0x901E, 0xE798: 0x9016, 0xE799: 0x900B, 0xE79A: 0x9027, 0xE79B: 0x9036, 0xE79C: 0x9035, 0xE79D: 0x9039, 0xE79E: 0x8FF8, 0xE79F: 0x904F, 0xE7A0: 0x9050, 0xE7A1: 0x9051, 0xE7A2: 0x9052, 0xE7A3: 0x900E, 0xE7A4: 0x9049, 0xE7A5: 0x903E, 0xE7A6: 0x9056, 0xE7A7: 0x9058, 0xE7A8: 0x905E, 0xE7A9: 0x9068, 0xE7AA: 0x906F, 0xE7AB: 0x9076, 0xE7AC: 0x96A8, 0xE7AD: 0x9072, 0xE7AE: 0x9082, 0xE7AF: 0x907D, 0xE7B0: 0x9081, 0xE7B1: 0x9080, 0xE7B2: 0x908A, 0xE7B3: 0x9089, 0xE7B4: 0x908F, 0xE7B5: 0x90A8, 0xE7B6: 0x90AF, 0xE7B7: 0x90B1, 0xE7B8: 0x90B5, 0xE7B9: 0x90E2, 0xE7BA: 0x90E4, 0xE7BB: 0x6248, 0xE7BC: 0x90DB, 0xE7BD: 0x9102, 0xE7BE: 0x9112, 0xE7BF: 0x9119, 0xE7C0: 0x9132, 0xE7C1: 0x9130, 0xE7C2: 0x914A, 0xE7C3: 0x9156, 0xE7C4: 0x9158, 0xE7C5: 0x9163, 0xE7C6: 0x9165, 0xE7C7: 0x9169, 0xE7C8: 0x9173, 0xE7C9: 0x9172, 0xE7CA: 0x918B, 0xE7CB: 0x9189, 0xE7CC: 0x9182, 0xE7CD: 0x91A2, 0xE7CE: 0x91AB, 0xE7CF: 0x91AF, 0xE7D0: 0x91AA, 0xE7D1: 0x91B5, 0xE7D2: 0x91B4, 0xE7D3: 0x91BA, 0xE7D4: 0x91C0, 0xE7D5: 0x91C1, 0xE7D6: 0x91C9, 0xE7D7: 0x91CB, 0xE7D8: 0x91D0, 0xE7D9: 0x91D6, 0xE7DA: 0x91DF, 0xE7DB: 0x91E1, 0xE7DC: 0x91DB, 0xE7DD: 0x91FC, 0xE7DE: 0x91F5, 0xE7DF: 0x91F6, 0xE7E0: 0x921E, 0xE7E1: 0x91FF, 0xE7E2: 0x9214, 0xE7E3: 0x922C, 0xE7E4: 0x9215, 0xE7E5: 0x9211, 0xE7E6: 0x925E, 0xE7E7: 0x9257, 0xE7E8: 0x9245, 0xE7E9: 0x9249, 0xE7EA: 0x9264, 0xE7EB: 0x9248, 0xE7EC: 0x9295, 0xE7ED: 0x923F, 0xE7EE: 0x924B, 0xE7EF: 0x9250, 0xE7F0: 0x929C, 0xE7F1: 0x9296, 0xE7F2: 0x9293, 0xE7F3: 0x929B, 0xE7F4: 0x925A, 0xE7F5: 0x92CF, 0xE7F6: 0x92B9, 0xE7F7: 0x92B7, 0xE7F8: 0x92E9, 0xE7F9: 0x930F, 0xE7FA: 0x92FA, 0xE7FB: 0x9344, 0xE7FC: 0x932E, 0xE840: 0x9319, 0xE841: 0x9322, 0xE842: 0x931A, 0xE843: 0x9323, 0xE844: 0x933A, 0xE845: 0x9335, 0xE846: 0x933B, 0xE847: 0x935C, 0xE848: 0x9360, 0xE849: 0x937C, 0xE84A: 0x936E, 0xE84B: 0x9356, 0xE84C: 0x93B0, 0xE84D: 0x93AC, 0xE84E: 0x93AD, 0xE84F: 0x9394, 0xE850: 0x93B9, 0xE851: 0x93D6, 0xE852: 0x93D7, 0xE853: 0x93E8, 0xE854: 0x93E5, 0xE855: 0x93D8, 0xE856: 0x93C3, 0xE857: 0x93DD, 0xE858: 0x93D0, 0xE859: 0x93C8, 0xE85A: 0x93E4, 0xE85B: 0x941A, 0xE85C: 0x9414, 0xE85D: 0x9413, 0xE85E: 0x9403, 0xE85F: 0x9407, 0xE860: 0x9410, 0xE861: 0x9436, 0xE862: 0x942B, 0xE863: 0x9435, 0xE864: 0x9421, 0xE865: 0x943A, 0xE866: 0x9441, 0xE867: 0x9452, 0xE868: 0x9444, 0xE869: 0x945B, 0xE86A: 0x9460, 0xE86B: 0x9462, 0xE86C: 0x945E, 0xE86D: 0x946A, 0xE86E: 0x9229, 0xE86F: 0x9470, 0xE870: 0x9475, 0xE871: 0x9477, 0xE872: 0x947D, 0xE873: 0x945A, 0xE874: 0x947C, 0xE875: 0x947E, 0xE876: 0x9481, 0xE877: 0x947F, 0xE878: 0x9582, 0xE879: 0x9587, 0xE87A: 0x958A, 0xE87B: 0x9594, 0xE87C: 0x9596, 0xE87D: 0x9598, 0xE87E: 0x9599, 0xE880: 0x95A0, 0xE881: 0x95A8, 0xE882: 0x95A7, 0xE883: 0x95AD, 0xE884: 0x95BC, 0xE885: 0x95BB, 0xE886: 0x95B9, 0xE887: 0x95BE, 0xE888: 0x95CA, 0xE889: 0x6FF6, 0xE88A: 0x95C3, 0xE88B: 0x95CD, 0xE88C: 0x95CC, 0xE88D: 0x95D5, 0xE88E: 0x95D4, 0xE88F: 0x95D6, 0xE890: 0x95DC, 0xE891: 0x95E1, 0xE892: 0x95E5, 0xE893: 0x95E2, 0xE894: 0x9621, 0xE895: 0x9628, 0xE896: 0x962E, 0xE897: 0x962F, 0xE898: 0x9642, 0xE899: 0x964C, 0xE89A: 0x964F, 0xE89B: 0x964B, 0xE89C: 0x9677, 0xE89D: 0x965C, 0xE89E: 0x965E, 0xE89F: 0x965D, 0xE8A0: 0x965F, 0xE8A1: 0x9666, 0xE8A2: 0x9672, 0xE8A3: 0x966C, 0xE8A4: 0x968D, 0xE8A5: 0x9698, 0xE8A6: 0x9695, 0xE8A7: 0x9697, 0xE8A8: 0x96AA, 0xE8A9: 0x96A7, 0xE8AA: 0x96B1, 0xE8AB: 0x96B2, 0xE8AC: 0x96B0, 0xE8AD: 0x96B4, 0xE8AE: 0x96B6, 0xE8AF: 0x96B8, 0xE8B0: 0x96B9, 0xE8B1: 0x96CE, 0xE8B2: 0x96CB, 0xE8B3: 0x96C9, 0xE8B4: 0x96CD, 0xE8B5: 0x894D, 0xE8B6: 0x96DC, 0xE8B7: 0x970D, 0xE8B8: 0x96D5, 0xE8B9: 0x96F9, 0xE8BA: 0x9704, 0xE8BB: 0x9706, 0xE8BC: 0x9708, 0xE8BD: 0x9713, 0xE8BE: 0x970E, 0xE8BF: 0x9711, 0xE8C0: 0x970F, 0xE8C1: 0x9716, 0xE8C2: 0x9719, 0xE8C3: 0x9724, 0xE8C4: 0x972A, 0xE8C5: 0x9730, 0xE8C6: 0x9739, 0xE8C7: 0x973D, 0xE8C8: 0x973E, 0xE8C9: 0x9744, 0xE8CA: 0x9746, 0xE8CB: 0x9748, 0xE8CC: 0x9742, 0xE8CD: 0x9749, 0xE8CE: 0x975C, 0xE8CF: 0x9760, 0xE8D0: 0x9764, 0xE8D1: 0x9766, 0xE8D2: 0x9768, 0xE8D3: 0x52D2, 0xE8D4: 0x976B, 0xE8D5: 0x9771, 0xE8D6: 0x9779, 0xE8D7: 0x9785, 0xE8D8: 0x977C, 0xE8D9: 0x9781, 0xE8DA: 0x977A, 0xE8DB: 0x9786, 0xE8DC: 0x978B, 0xE8DD: 0x978F, 0xE8DE: 0x9790, 0xE8DF: 0x979C, 0xE8E0: 0x97A8, 0xE8E1: 0x97A6, 0xE8E2: 0x97A3, 0xE8E3: 0x97B3, 0xE8E4: 0x97B4, 0xE8E5: 0x97C3, 0xE8E6: 0x97C6, 0xE8E7: 0x97C8, 0xE8E8: 0x97CB, 0xE8E9: 0x97DC, 0xE8EA: 0x97ED, 0xE8EB: 0x9F4F, 0xE8EC: 0x97F2, 0xE8ED: 0x7ADF, 0xE8EE: 0x97F6, 0xE8EF: 0x97F5, 0xE8F0: 0x980F, 0xE8F1: 0x980C, 0xE8F2: 0x9838, 0xE8F3: 0x9824, 0xE8F4: 0x9821, 0xE8F5: 0x9837, 0xE8F6: 0x983D, 0xE8F7: 0x9846, 0xE8F8: 0x984F, 0xE8F9: 0x984B, 0xE8FA: 0x986B, 0xE8FB: 0x986F, 0xE8FC: 0x9870, 0xE940: 0x9871, 0xE941: 0x9874, 0xE942: 0x9873, 0xE943: 0x98AA, 0xE944: 0x98AF, 0xE945: 0x98B1, 0xE946: 0x98B6, 0xE947: 0x98C4, 0xE948: 0x98C3, 0xE949: 0x98C6, 0xE94A: 0x98E9, 0xE94B: 0x98EB, 0xE94C: 0x9903, 0xE94D: 0x9909, 0xE94E: 0x9912, 0xE94F: 0x9914, 0xE950: 0x9918, 0xE951: 0x9921, 0xE952: 0x991D, 0xE953: 0x991E, 0xE954: 0x9924, 0xE955: 0x9920, 0xE956: 0x992C, 0xE957: 0x992E, 0xE958: 0x993D, 0xE959: 0x993E, 0xE95A: 0x9942, 0xE95B: 0x9949, 0xE95C: 0x9945, 0xE95D: 0x9950, 0xE95E: 0x994B, 0xE95F: 0x9951, 0xE960: 0x9952, 0xE961: 0x994C, 0xE962: 0x9955, 0xE963: 0x9997, 0xE964: 0x9998, 0xE965: 0x99A5, 0xE966: 0x99AD, 0xE967: 0x99AE, 0xE968: 0x99BC, 0xE969: 0x99DF, 0xE96A: 0x99DB, 0xE96B: 0x99DD, 0xE96C: 0x99D8, 0xE96D: 0x99D1, 0xE96E: 0x99ED, 0xE96F: 0x99EE, 0xE970: 0x99F1, 0xE971: 0x99F2, 0xE972: 0x99FB, 0xE973: 0x99F8, 0xE974: 0x9A01, 0xE975: 0x9A0F, 0xE976: 0x9A05, 0xE977: 0x99E2, 0xE978: 0x9A19, 0xE979: 0x9A2B, 0xE97A: 0x9A37, 0xE97B: 0x9A45, 0xE97C: 0x9A42, 0xE97D: 0x9A40, 0xE97E: 0x9A43, 0xE980: 0x9A3E, 0xE981: 0x9A55, 0xE982: 0x9A4D, 0xE983: 0x9A5B, 0xE984: 0x9A57, 0xE985: 0x9A5F, 0xE986: 0x9A62, 0xE987: 0x9A65, 0xE988: 0x9A64, 0xE989: 0x9A69, 0xE98A: 0x9A6B, 0xE98B: 0x9A6A, 0xE98C: 0x9AAD, 0xE98D: 0x9AB0, 0xE98E: 0x9ABC, 0xE98F: 0x9AC0, 0xE990: 0x9ACF, 0xE991: 0x9AD1, 0xE992: 0x9AD3, 0xE993: 0x9AD4, 0xE994: 0x9ADE, 0xE995: 0x9ADF, 0xE996: 0x9AE2, 0xE997: 0x9AE3, 0xE998: 0x9AE6, 0xE999: 0x9AEF, 0xE99A: 0x9AEB, 0xE99B: 0x9AEE, 0xE99C: 0x9AF4, 0xE99D: 0x9AF1, 0xE99E: 0x9AF7, 0xE99F: 0x9AFB, 0xE9A0: 0x9B06, 0xE9A1: 0x9B18, 0xE9A2: 0x9B1A, 0xE9A3: 0x9B1F, 0xE9A4: 0x9B22, 0xE9A5: 0x9B23, 0xE9A6: 0x9B25, 0xE9A7: 0x9B27, 0xE9A8: 0x9B28, 0xE9A9: 0x9B29, 0xE9AA: 0x9B2A, 0xE9AB: 0x9B2E, 0xE9AC: 0x9B2F, 0xE9AD: 0x9B32, 0xE9AE: 0x9B44, 0xE9AF: 0x9B43, 0xE9B0: 0x9B4F, 0xE9B1: 0x9B4D, 0xE9B2: 0x9B4E, 0xE9B3: 0x9B51, 0xE9B4: 0x9B58, 0xE9B5: 0x9B74, 0xE9B6: 0x9B93, 0xE9B7: 0x9B83, 0xE9B8: 0x9B91, 0xE9B9: 0x9B96, 0xE9BA: 0x9B97, 0xE9BB: 0x9B9F, 0xE9BC: 0x9BA0, 0xE9BD: 0x9BA8, 0xE9BE: 0x9BB4, 0xE9BF: 0x9BC0, 0xE9C0: 0x9BCA, 0xE9C1: 0x9BB9, 0xE9C2: 0x9BC6, 0xE9C3: 0x9BCF, 0xE9C4: 0x9BD1, 0xE9C5: 0x9BD2, 0xE9C6: 0x9BE3, 0xE9C7: 0x9BE2, 0xE9C8: 0x9BE4, 0xE9C9: 0x9BD4, 0xE9CA: 0x9BE1, 0xE9CB: 0x9C3A, 0xE9CC: 0x9BF2, 0xE9CD: 0x9BF1, 0xE9CE: 0x9BF0, 0xE9CF: 0x9C15, 0xE9D0: 0x9C14, 0xE9D1: 0x9C09, 0xE9D2: 0x9C13, 0xE9D3: 0x9C0C, 0xE9D4: 0x9C06, 0xE9D5: 0x9C08, 0xE9D6: 0x9C12, 0xE9D7: 0x9C0A, 0xE9D8: 0x9C04, 0xE9D9: 0x9C2E, 0xE9DA: 0x9C1B, 0xE9DB: 0x9C25, 0xE9DC: 0x9C24, 0xE9DD: 0x9C21, 0xE9DE: 0x9C30, 0xE9DF: 0x9C47, 0xE9E0: 0x9C32, 0xE9E1: 0x9C46, 0xE9E2: 0x9C3E, 0xE9E3: 0x9C5A, 0xE9E4: 0x9C60, 0xE9E5: 0x9C67, 0xE9E6: 0x9C76, 0xE9E7: 0x9C78, 0xE9E8: 0x9CE7, 0xE9E9: 0x9CEC, 0xE9EA: 0x9CF0, 0xE9EB: 0x9D09, 0xE9EC: 0x9D08, 0xE9ED: 0x9CEB, 0xE9EE: 0x9D03, 0xE9EF: 0x9D06, 0xE9F0: 0x9D2A, 0xE9F1: 0x9D26, 0xE9F2: 0x9DAF, 0xE9F3: 0x9D23, 0xE9F4: 0x9D1F, 0xE9F5: 0x9D44, 0xE9F6: 0x9D15, 0xE9F7: 0x9D12, 0xE9F8: 0x9D41, 0xE9F9: 0x9D3F, 0xE9FA: 0x9D3E, 0xE9FB: 0x9D46, 0xE9FC: 0x9D48, 0xEA40: 0x9D5D, 0xEA41: 0x9D5E, 0xEA42: 0x9D64, 0xEA43: 0x9D51, 0xEA44: 0x9D50, 0xEA45: 0x9D59, 0xEA46: 0x9D72, 0xEA47: 0x9D89, 0xEA48: 0x9D87, 0xEA49: 0x9DAB, 0xEA4A: 0x9D6F, 0xEA4B: 0x9D7A, 0xEA4C: 0x9D9A, 0xEA4D: 0x9DA4, 0xEA4E: 0x9DA9, 0xEA4F: 0x9DB2, 0xEA50: 0x9DC4, 0xEA51: 0x9DC1, 0xEA52: 0x9DBB, 0xEA53: 0x9DB8, 0xEA54: 0x9DBA, 0xEA55: 0x9DC6, 0xEA56: 0x9DCF, 0xEA57: 0x9DC2, 0xEA58: 0x9DD9, 0xEA59: 0x9DD3, 0xEA5A: 0x9DF8, 0xEA5B: 0x9DE6, 0xEA5C: 0x9DED, 0xEA5D: 0x9DEF, 0xEA5E: 0x9DFD, 0xEA5F: 0x9E1A, 0xEA60: 0x9E1B, 0xEA61: 0x9E1E, 0xEA62: 0x9E75, 0xEA63: 0x9E79, 0xEA64: 0x9E7D, 0xEA65: 0x9E81, 0xEA66: 0x9E88, 0xEA67: 0x9E8B, 0xEA68: 0x9E8C, 0xEA69: 0x9E92, 0xEA6A: 0x9E95, 0xEA6B: 0x9E91, 0xEA6C: 0x9E9D, 0xEA6D: 0x9EA5, 0xEA6E: 0x9EA9, 0xEA6F: 0x9EB8, 0xEA70: 0x9EAA, 0xEA71: 0x9EAD, 0xEA72: 0x9761, 0xEA73: 0x9ECC, 0xEA74: 0x9ECE, 0xEA75: 0x9ECF, 0xEA76: 0x9ED0, 0xEA77: 0x9ED4, 0xEA78: 0x9EDC, 0xEA79: 0x9EDE, 0xEA7A: 0x9EDD, 0xEA7B: 0x9EE0, 0xEA7C: 0x9EE5, 0xEA7D: 0x9EE8, 0xEA7E: 0x9EEF, 0xEA80: 0x9EF4, 0xEA81: 0x9EF6, 0xEA82: 0x9EF7, 0xEA83: 0x9EF9, 0xEA84: 0x9EFB, 0xEA85: 0x9EFC, 0xEA86: 0x9EFD, 0xEA87: 0x9F07, 0xEA88: 0x9F08, 0xEA89: 0x76B7, 0xEA8A: 0x9F15, 0xEA8B: 0x9F21, 0xEA8C: 0x9F2C, 0xEA8D: 0x9F3E, 0xEA8E: 0x9F4A, 0xEA8F: 0x9F52, 0xEA90: 0x9F54, 0xEA91: 0x9F63, 0xEA92: 0x9F5F, 0xEA93: 0x9F60, 0xEA94: 0x9F61, 0xEA95: 0x9F66, 0xEA96: 0x9F67, 0xEA97: 0x9F6C, 0xEA98: 0x9F6A, 0xEA99: 0x9F77, 0xEA9A: 0x9F72, 0xEA9B: 0x9F76, 0xEA9C: 0x9F95, 0xEA9D: 0x9F9C, 0xEA9E: 0x9FA0, 0xEA9F: 0x582F, 0xEAA0: 0x69C7, 0xEAA1: 0x9059, 0xEAA2: 0x7464, 0xEAA3: 0x51DC, 0xEAA4: 0x7199, }; /***/ }), /* 9 */ /***/ (function(module, exports, __nested_webpack_require_183922__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var GenericGF_1 = __nested_webpack_require_183922__(1); var GenericGFPoly_1 = __nested_webpack_require_183922__(2); function runEuclideanAlgorithm(field, a, b, R) { var _a; // Assume a's degree is >= b's if (a.degree() < b.degree()) { _a = [b, a], a = _a[0], b = _a[1]; } var rLast = a; var r = b; var tLast = field.zero; var t = field.one; // Run Euclidean algorithm until r's degree is less than R/2 while (r.degree() >= R / 2) { var rLastLast = rLast; var tLastLast = tLast; rLast = r; tLast = t; // Divide rLastLast by rLast, with quotient in q and remainder in r if (rLast.isZero()) { // Euclidean algorithm already terminated? return null; } r = rLastLast; var q = field.zero; var denominatorLeadingTerm = rLast.getCoefficient(rLast.degree()); var dltInverse = field.inverse(denominatorLeadingTerm); while (r.degree() >= rLast.degree() && !r.isZero()) { var degreeDiff = r.degree() - rLast.degree(); var scale = field.multiply(r.getCoefficient(r.degree()), dltInverse); q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale)); r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale)); } t = q.multiplyPoly(tLast).addOrSubtract(tLastLast); if (r.degree() >= rLast.degree()) { return null; } } var sigmaTildeAtZero = t.getCoefficient(0); if (sigmaTildeAtZero === 0) { return null; } var inverse = field.inverse(sigmaTildeAtZero); return [t.multiply(inverse), r.multiply(inverse)]; } function findErrorLocations(field, errorLocator) { // This is a direct application of Chien's search var numErrors = errorLocator.degree(); if (numErrors === 1) { return [errorLocator.getCoefficient(1)]; } var result = new Array(numErrors); var errorCount = 0; for (var i = 1; i < field.size && errorCount < numErrors; i++) { if (errorLocator.evaluateAt(i) === 0) { result[errorCount] = field.inverse(i); errorCount++; } } if (errorCount !== numErrors) { return null; } return result; } function findErrorMagnitudes(field, errorEvaluator, errorLocations) { // This is directly applying Forney's Formula var s = errorLocations.length; var result = new Array(s); for (var i = 0; i < s; i++) { var xiInverse = field.inverse(errorLocations[i]); var denominator = 1; for (var j = 0; j < s; j++) { if (i !== j) { denominator = field.multiply(denominator, GenericGF_1.addOrSubtractGF(1, field.multiply(errorLocations[j], xiInverse))); } } result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denominator)); if (field.generatorBase !== 0) { result[i] = field.multiply(result[i], xiInverse); } } return result; } function decode(bytes, twoS) { var outputBytes = new Uint8ClampedArray(bytes.length); outputBytes.set(bytes); var field = new GenericGF_1.default(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1 var poly = new GenericGFPoly_1.default(field, outputBytes); var syndromeCoefficients = new Uint8ClampedArray(twoS); var error = false; for (var s = 0; s < twoS; s++) { var evaluation = poly.evaluateAt(field.exp(s + field.generatorBase)); syndromeCoefficients[syndromeCoefficients.length - 1 - s] = evaluation; if (evaluation !== 0) { error = true; } } if (!error) { return outputBytes; } var syndrome = new GenericGFPoly_1.default(field, syndromeCoefficients); var sigmaOmega = runEuclideanAlgorithm(field, field.buildMonomial(twoS, 1), syndrome, twoS); if (sigmaOmega === null) { return null; } var errorLocations = findErrorLocations(field, sigmaOmega[0]); if (errorLocations == null) { return null; } var errorMagnitudes = findErrorMagnitudes(field, sigmaOmega[1], errorLocations); for (var i = 0; i < errorLocations.length; i++) { var position = outputBytes.length - 1 - field.log(errorLocations[i]); if (position < 0) { return null; } outputBytes[position] = GenericGF_1.addOrSubtractGF(outputBytes[position], errorMagnitudes[i]); } return outputBytes; } exports.decode = decode; /***/ }), /* 10 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.VERSIONS = [ { infoBits: null, versionNumber: 1, alignmentPatternCenters: [], errorCorrectionLevels: [ { ecCodewordsPerBlock: 7, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 19 }], }, { ecCodewordsPerBlock: 10, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 16 }], }, { ecCodewordsPerBlock: 13, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 13 }], }, { ecCodewordsPerBlock: 17, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 9 }], }, ], }, { infoBits: null, versionNumber: 2, alignmentPatternCenters: [6, 18], errorCorrectionLevels: [ { ecCodewordsPerBlock: 10, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 34 }], }, { ecCodewordsPerBlock: 16, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 28 }], }, { ecCodewordsPerBlock: 22, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 22 }], }, { ecCodewordsPerBlock: 28, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 16 }], }, ], }, { infoBits: null, versionNumber: 3, alignmentPatternCenters: [6, 22], errorCorrectionLevels: [ { ecCodewordsPerBlock: 15, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 55 }], }, { ecCodewordsPerBlock: 26, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 44 }], }, { ecCodewordsPerBlock: 18, ecBlocks: [{ numBlocks: 2, dataCodewordsPerBlock: 17 }], }, { ecCodewordsPerBlock: 22, ecBlocks: [{ numBlocks: 2, dataCodewordsPerBlock: 13 }], }, ], }, { infoBits: null, versionNumber: 4, alignmentPatternCenters: [6, 26], errorCorrectionLevels: [ { ecCodewordsPerBlock: 20, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 80 }], }, { ecCodewordsPerBlock: 18, ecBlocks: [{ numBlocks: 2, dataCodewordsPerBlock: 32 }], }, { ecCodewordsPerBlock: 26, ecBlocks: [{ numBlocks: 2, dataCodewordsPerBlock: 24 }], }, { ecCodewordsPerBlock: 16, ecBlocks: [{ numBlocks: 4, dataCodewordsPerBlock: 9 }], }, ], }, { infoBits: null, versionNumber: 5, alignmentPatternCenters: [6, 30], errorCorrectionLevels: [ { ecCodewordsPerBlock: 26, ecBlocks: [{ numBlocks: 1, dataCodewordsPerBlock: 108 }], }, { ecCodewordsPerBlock: 24, ecBlocks: [{ numBlocks: 2, dataCodewordsPerBlock: 43 }], }, { ecCodewordsPerBlock: 18, ecBlocks: [ { numBlocks: 2, dataCodewordsPerBlock: 15 }, { numBlocks: 2, dataCodewordsPerBlock: 16 }, ], }, { ecCodewordsPerBlock: 22, ecBlocks: [ { numBlocks: 2, dataCodewordsPerBlock: 11 }, { numBlocks: 2, dataCodewordsPerBlock: 12 }, ], }, ], }, { infoBits: null, versionNumber: 6, alignmentPatternCenters: [6, 34], errorCorrectionLevels: [ { ecCodewordsPerBlock: 18, ecBlocks: [{ numBlocks: 2, dataCodewordsPerBlock: 68 }], }, { ecCodewordsPerBlock: 16, ecBlocks: [{ numBlocks: 4, dataCodewordsPerBlock: 27 }], }, { ecCodewordsPerBlock: 24, ecBlocks: [{ numBlocks: 4, dataCodewordsPerBlock: 19 }], }, { ecCodewordsPerBlock: 28, ecBlocks: [{ numBlocks: 4, dataCodewordsPerBlock: 15 }], }, ], }, { infoBits: 0x07C94, versionNumber: 7, alignmentPatternCenters: [6, 22, 38], errorCorrectionLevels: [ { ecCodewordsPerBlock: 20, ecBlocks: [{ numBlocks: 2, dataCodewordsPerBlock: 78 }], }, { ecCodewordsPerBlock: 18, ecBlocks: [{ numBlocks: 4, dataCodewordsPerBlock: 31 }], }, { ecCodewordsPerBlock: 18, ecBlocks: [ { numBlocks: 2, dataCodewordsPerBlock: 14 }, { numBlocks: 4, dataCodewordsPerBlock: 15 }, ], }, { ecCodewordsPerBlock: 26, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 13 }, { numBlocks: 1, dataCodewordsPerBlock: 14 }, ], }, ], }, { infoBits: 0x085BC, versionNumber: 8, alignmentPatternCenters: [6, 24, 42], errorCorrectionLevels: [ { ecCodewordsPerBlock: 24, ecBlocks: [{ numBlocks: 2, dataCodewordsPerBlock: 97 }], }, { ecCodewordsPerBlock: 22, ecBlocks: [ { numBlocks: 2, dataCodewordsPerBlock: 38 }, { numBlocks: 2, dataCodewordsPerBlock: 39 }, ], }, { ecCodewordsPerBlock: 22, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 18 }, { numBlocks: 2, dataCodewordsPerBlock: 19 }, ], }, { ecCodewordsPerBlock: 26, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 14 }, { numBlocks: 2, dataCodewordsPerBlock: 15 }, ], }, ], }, { infoBits: 0x09A99, versionNumber: 9, alignmentPatternCenters: [6, 26, 46], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [{ numBlocks: 2, dataCodewordsPerBlock: 116 }], }, { ecCodewordsPerBlock: 22, ecBlocks: [ { numBlocks: 3, dataCodewordsPerBlock: 36 }, { numBlocks: 2, dataCodewordsPerBlock: 37 }, ], }, { ecCodewordsPerBlock: 20, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 16 }, { numBlocks: 4, dataCodewordsPerBlock: 17 }, ], }, { ecCodewordsPerBlock: 24, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 12 }, { numBlocks: 4, dataCodewordsPerBlock: 13 }, ], }, ], }, { infoBits: 0x0A4D3, versionNumber: 10, alignmentPatternCenters: [6, 28, 50], errorCorrectionLevels: [ { ecCodewordsPerBlock: 18, ecBlocks: [ { numBlocks: 2, dataCodewordsPerBlock: 68 }, { numBlocks: 2, dataCodewordsPerBlock: 69 }, ], }, { ecCodewordsPerBlock: 26, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 43 }, { numBlocks: 1, dataCodewordsPerBlock: 44 }, ], }, { ecCodewordsPerBlock: 24, ecBlocks: [ { numBlocks: 6, dataCodewordsPerBlock: 19 }, { numBlocks: 2, dataCodewordsPerBlock: 20 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 6, dataCodewordsPerBlock: 15 }, { numBlocks: 2, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x0BBF6, versionNumber: 11, alignmentPatternCenters: [6, 30, 54], errorCorrectionLevels: [ { ecCodewordsPerBlock: 20, ecBlocks: [{ numBlocks: 4, dataCodewordsPerBlock: 81 }], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 1, dataCodewordsPerBlock: 50 }, { numBlocks: 4, dataCodewordsPerBlock: 51 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 22 }, { numBlocks: 4, dataCodewordsPerBlock: 23 }, ], }, { ecCodewordsPerBlock: 24, ecBlocks: [ { numBlocks: 3, dataCodewordsPerBlock: 12 }, { numBlocks: 8, dataCodewordsPerBlock: 13 }, ], }, ], }, { infoBits: 0x0C762, versionNumber: 12, alignmentPatternCenters: [6, 32, 58], errorCorrectionLevels: [ { ecCodewordsPerBlock: 24, ecBlocks: [ { numBlocks: 2, dataCodewordsPerBlock: 92 }, { numBlocks: 2, dataCodewordsPerBlock: 93 }, ], }, { ecCodewordsPerBlock: 22, ecBlocks: [ { numBlocks: 6, dataCodewordsPerBlock: 36 }, { numBlocks: 2, dataCodewordsPerBlock: 37 }, ], }, { ecCodewordsPerBlock: 26, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 20 }, { numBlocks: 6, dataCodewordsPerBlock: 21 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 7, dataCodewordsPerBlock: 14 }, { numBlocks: 4, dataCodewordsPerBlock: 15 }, ], }, ], }, { infoBits: 0x0D847, versionNumber: 13, alignmentPatternCenters: [6, 34, 62], errorCorrectionLevels: [ { ecCodewordsPerBlock: 26, ecBlocks: [{ numBlocks: 4, dataCodewordsPerBlock: 107 }], }, { ecCodewordsPerBlock: 22, ecBlocks: [ { numBlocks: 8, dataCodewordsPerBlock: 37 }, { numBlocks: 1, dataCodewordsPerBlock: 38 }, ], }, { ecCodewordsPerBlock: 24, ecBlocks: [ { numBlocks: 8, dataCodewordsPerBlock: 20 }, { numBlocks: 4, dataCodewordsPerBlock: 21 }, ], }, { ecCodewordsPerBlock: 22, ecBlocks: [ { numBlocks: 12, dataCodewordsPerBlock: 11 }, { numBlocks: 4, dataCodewordsPerBlock: 12 }, ], }, ], }, { infoBits: 0x0E60D, versionNumber: 14, alignmentPatternCenters: [6, 26, 46, 66], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 3, dataCodewordsPerBlock: 115 }, { numBlocks: 1, dataCodewordsPerBlock: 116 }, ], }, { ecCodewordsPerBlock: 24, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 40 }, { numBlocks: 5, dataCodewordsPerBlock: 41 }, ], }, { ecCodewordsPerBlock: 20, ecBlocks: [ { numBlocks: 11, dataCodewordsPerBlock: 16 }, { numBlocks: 5, dataCodewordsPerBlock: 17 }, ], }, { ecCodewordsPerBlock: 24, ecBlocks: [ { numBlocks: 11, dataCodewordsPerBlock: 12 }, { numBlocks: 5, dataCodewordsPerBlock: 13 }, ], }, ], }, { infoBits: 0x0F928, versionNumber: 15, alignmentPatternCenters: [6, 26, 48, 70], errorCorrectionLevels: [ { ecCodewordsPerBlock: 22, ecBlocks: [ { numBlocks: 5, dataCodewordsPerBlock: 87 }, { numBlocks: 1, dataCodewordsPerBlock: 88 }, ], }, { ecCodewordsPerBlock: 24, ecBlocks: [ { numBlocks: 5, dataCodewordsPerBlock: 41 }, { numBlocks: 5, dataCodewordsPerBlock: 42 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 5, dataCodewordsPerBlock: 24 }, { numBlocks: 7, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 24, ecBlocks: [ { numBlocks: 11, dataCodewordsPerBlock: 12 }, { numBlocks: 7, dataCodewordsPerBlock: 13 }, ], }, ], }, { infoBits: 0x10B78, versionNumber: 16, alignmentPatternCenters: [6, 26, 50, 74], errorCorrectionLevels: [ { ecCodewordsPerBlock: 24, ecBlocks: [ { numBlocks: 5, dataCodewordsPerBlock: 98 }, { numBlocks: 1, dataCodewordsPerBlock: 99 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 7, dataCodewordsPerBlock: 45 }, { numBlocks: 3, dataCodewordsPerBlock: 46 }, ], }, { ecCodewordsPerBlock: 24, ecBlocks: [ { numBlocks: 15, dataCodewordsPerBlock: 19 }, { numBlocks: 2, dataCodewordsPerBlock: 20 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 3, dataCodewordsPerBlock: 15 }, { numBlocks: 13, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x1145D, versionNumber: 17, alignmentPatternCenters: [6, 30, 54, 78], errorCorrectionLevels: [ { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 1, dataCodewordsPerBlock: 107 }, { numBlocks: 5, dataCodewordsPerBlock: 108 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 10, dataCodewordsPerBlock: 46 }, { numBlocks: 1, dataCodewordsPerBlock: 47 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 1, dataCodewordsPerBlock: 22 }, { numBlocks: 15, dataCodewordsPerBlock: 23 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 2, dataCodewordsPerBlock: 14 }, { numBlocks: 17, dataCodewordsPerBlock: 15 }, ], }, ], }, { infoBits: 0x12A17, versionNumber: 18, alignmentPatternCenters: [6, 30, 56, 82], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 5, dataCodewordsPerBlock: 120 }, { numBlocks: 1, dataCodewordsPerBlock: 121 }, ], }, { ecCodewordsPerBlock: 26, ecBlocks: [ { numBlocks: 9, dataCodewordsPerBlock: 43 }, { numBlocks: 4, dataCodewordsPerBlock: 44 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 17, dataCodewordsPerBlock: 22 }, { numBlocks: 1, dataCodewordsPerBlock: 23 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 2, dataCodewordsPerBlock: 14 }, { numBlocks: 19, dataCodewordsPerBlock: 15 }, ], }, ], }, { infoBits: 0x13532, versionNumber: 19, alignmentPatternCenters: [6, 30, 58, 86], errorCorrectionLevels: [ { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 3, dataCodewordsPerBlock: 113 }, { numBlocks: 4, dataCodewordsPerBlock: 114 }, ], }, { ecCodewordsPerBlock: 26, ecBlocks: [ { numBlocks: 3, dataCodewordsPerBlock: 44 }, { numBlocks: 11, dataCodewordsPerBlock: 45 }, ], }, { ecCodewordsPerBlock: 26, ecBlocks: [ { numBlocks: 17, dataCodewordsPerBlock: 21 }, { numBlocks: 4, dataCodewordsPerBlock: 22 }, ], }, { ecCodewordsPerBlock: 26, ecBlocks: [ { numBlocks: 9, dataCodewordsPerBlock: 13 }, { numBlocks: 16, dataCodewordsPerBlock: 14 }, ], }, ], }, { infoBits: 0x149A6, versionNumber: 20, alignmentPatternCenters: [6, 34, 62, 90], errorCorrectionLevels: [ { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 3, dataCodewordsPerBlock: 107 }, { numBlocks: 5, dataCodewordsPerBlock: 108 }, ], }, { ecCodewordsPerBlock: 26, ecBlocks: [ { numBlocks: 3, dataCodewordsPerBlock: 41 }, { numBlocks: 13, dataCodewordsPerBlock: 42 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 15, dataCodewordsPerBlock: 24 }, { numBlocks: 5, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 15, dataCodewordsPerBlock: 15 }, { numBlocks: 10, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x15683, versionNumber: 21, alignmentPatternCenters: [6, 28, 50, 72, 94], errorCorrectionLevels: [ { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 116 }, { numBlocks: 4, dataCodewordsPerBlock: 117 }, ], }, { ecCodewordsPerBlock: 26, ecBlocks: [{ numBlocks: 17, dataCodewordsPerBlock: 42 }], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 17, dataCodewordsPerBlock: 22 }, { numBlocks: 6, dataCodewordsPerBlock: 23 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 19, dataCodewordsPerBlock: 16 }, { numBlocks: 6, dataCodewordsPerBlock: 17 }, ], }, ], }, { infoBits: 0x168C9, versionNumber: 22, alignmentPatternCenters: [6, 26, 50, 74, 98], errorCorrectionLevels: [ { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 2, dataCodewordsPerBlock: 111 }, { numBlocks: 7, dataCodewordsPerBlock: 112 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [{ numBlocks: 17, dataCodewordsPerBlock: 46 }], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 7, dataCodewordsPerBlock: 24 }, { numBlocks: 16, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 24, ecBlocks: [{ numBlocks: 34, dataCodewordsPerBlock: 13 }], }, ], }, { infoBits: 0x177EC, versionNumber: 23, alignmentPatternCenters: [6, 30, 54, 74, 102], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 121 }, { numBlocks: 5, dataCodewordsPerBlock: 122 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 47 }, { numBlocks: 14, dataCodewordsPerBlock: 48 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 11, dataCodewordsPerBlock: 24 }, { numBlocks: 14, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 16, dataCodewordsPerBlock: 15 }, { numBlocks: 14, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x18EC4, versionNumber: 24, alignmentPatternCenters: [6, 28, 54, 80, 106], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 6, dataCodewordsPerBlock: 117 }, { numBlocks: 4, dataCodewordsPerBlock: 118 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 6, dataCodewordsPerBlock: 45 }, { numBlocks: 14, dataCodewordsPerBlock: 46 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 11, dataCodewordsPerBlock: 24 }, { numBlocks: 16, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 30, dataCodewordsPerBlock: 16 }, { numBlocks: 2, dataCodewordsPerBlock: 17 }, ], }, ], }, { infoBits: 0x191E1, versionNumber: 25, alignmentPatternCenters: [6, 32, 58, 84, 110], errorCorrectionLevels: [ { ecCodewordsPerBlock: 26, ecBlocks: [ { numBlocks: 8, dataCodewordsPerBlock: 106 }, { numBlocks: 4, dataCodewordsPerBlock: 107 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 8, dataCodewordsPerBlock: 47 }, { numBlocks: 13, dataCodewordsPerBlock: 48 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 7, dataCodewordsPerBlock: 24 }, { numBlocks: 22, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 22, dataCodewordsPerBlock: 15 }, { numBlocks: 13, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x1AFAB, versionNumber: 26, alignmentPatternCenters: [6, 30, 58, 86, 114], errorCorrectionLevels: [ { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 10, dataCodewordsPerBlock: 114 }, { numBlocks: 2, dataCodewordsPerBlock: 115 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 19, dataCodewordsPerBlock: 46 }, { numBlocks: 4, dataCodewordsPerBlock: 47 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 28, dataCodewordsPerBlock: 22 }, { numBlocks: 6, dataCodewordsPerBlock: 23 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 33, dataCodewordsPerBlock: 16 }, { numBlocks: 4, dataCodewordsPerBlock: 17 }, ], }, ], }, { infoBits: 0x1B08E, versionNumber: 27, alignmentPatternCenters: [6, 34, 62, 90, 118], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 8, dataCodewordsPerBlock: 122 }, { numBlocks: 4, dataCodewordsPerBlock: 123 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 22, dataCodewordsPerBlock: 45 }, { numBlocks: 3, dataCodewordsPerBlock: 46 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 8, dataCodewordsPerBlock: 23 }, { numBlocks: 26, dataCodewordsPerBlock: 24 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 12, dataCodewordsPerBlock: 15 }, { numBlocks: 28, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x1CC1A, versionNumber: 28, alignmentPatternCenters: [6, 26, 50, 74, 98, 122], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 3, dataCodewordsPerBlock: 117 }, { numBlocks: 10, dataCodewordsPerBlock: 118 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 3, dataCodewordsPerBlock: 45 }, { numBlocks: 23, dataCodewordsPerBlock: 46 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 24 }, { numBlocks: 31, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 11, dataCodewordsPerBlock: 15 }, { numBlocks: 31, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x1D33F, versionNumber: 29, alignmentPatternCenters: [6, 30, 54, 78, 102, 126], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 7, dataCodewordsPerBlock: 116 }, { numBlocks: 7, dataCodewordsPerBlock: 117 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 21, dataCodewordsPerBlock: 45 }, { numBlocks: 7, dataCodewordsPerBlock: 46 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 1, dataCodewordsPerBlock: 23 }, { numBlocks: 37, dataCodewordsPerBlock: 24 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 19, dataCodewordsPerBlock: 15 }, { numBlocks: 26, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x1ED75, versionNumber: 30, alignmentPatternCenters: [6, 26, 52, 78, 104, 130], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 5, dataCodewordsPerBlock: 115 }, { numBlocks: 10, dataCodewordsPerBlock: 116 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 19, dataCodewordsPerBlock: 47 }, { numBlocks: 10, dataCodewordsPerBlock: 48 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 15, dataCodewordsPerBlock: 24 }, { numBlocks: 25, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 23, dataCodewordsPerBlock: 15 }, { numBlocks: 25, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x1F250, versionNumber: 31, alignmentPatternCenters: [6, 30, 56, 82, 108, 134], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 13, dataCodewordsPerBlock: 115 }, { numBlocks: 3, dataCodewordsPerBlock: 116 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 2, dataCodewordsPerBlock: 46 }, { numBlocks: 29, dataCodewordsPerBlock: 47 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 42, dataCodewordsPerBlock: 24 }, { numBlocks: 1, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 23, dataCodewordsPerBlock: 15 }, { numBlocks: 28, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x209D5, versionNumber: 32, alignmentPatternCenters: [6, 34, 60, 86, 112, 138], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [{ numBlocks: 17, dataCodewordsPerBlock: 115 }], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 10, dataCodewordsPerBlock: 46 }, { numBlocks: 23, dataCodewordsPerBlock: 47 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 10, dataCodewordsPerBlock: 24 }, { numBlocks: 35, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 19, dataCodewordsPerBlock: 15 }, { numBlocks: 35, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x216F0, versionNumber: 33, alignmentPatternCenters: [6, 30, 58, 86, 114, 142], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 17, dataCodewordsPerBlock: 115 }, { numBlocks: 1, dataCodewordsPerBlock: 116 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 14, dataCodewordsPerBlock: 46 }, { numBlocks: 21, dataCodewordsPerBlock: 47 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 29, dataCodewordsPerBlock: 24 }, { numBlocks: 19, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 11, dataCodewordsPerBlock: 15 }, { numBlocks: 46, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x228BA, versionNumber: 34, alignmentPatternCenters: [6, 34, 62, 90, 118, 146], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 13, dataCodewordsPerBlock: 115 }, { numBlocks: 6, dataCodewordsPerBlock: 116 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 14, dataCodewordsPerBlock: 46 }, { numBlocks: 23, dataCodewordsPerBlock: 47 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 44, dataCodewordsPerBlock: 24 }, { numBlocks: 7, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 59, dataCodewordsPerBlock: 16 }, { numBlocks: 1, dataCodewordsPerBlock: 17 }, ], }, ], }, { infoBits: 0x2379F, versionNumber: 35, alignmentPatternCenters: [6, 30, 54, 78, 102, 126, 150], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 12, dataCodewordsPerBlock: 121 }, { numBlocks: 7, dataCodewordsPerBlock: 122 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 12, dataCodewordsPerBlock: 47 }, { numBlocks: 26, dataCodewordsPerBlock: 48 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 39, dataCodewordsPerBlock: 24 }, { numBlocks: 14, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 22, dataCodewordsPerBlock: 15 }, { numBlocks: 41, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x24B0B, versionNumber: 36, alignmentPatternCenters: [6, 24, 50, 76, 102, 128, 154], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 6, dataCodewordsPerBlock: 121 }, { numBlocks: 14, dataCodewordsPerBlock: 122 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 6, dataCodewordsPerBlock: 47 }, { numBlocks: 34, dataCodewordsPerBlock: 48 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 46, dataCodewordsPerBlock: 24 }, { numBlocks: 10, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 2, dataCodewordsPerBlock: 15 }, { numBlocks: 64, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x2542E, versionNumber: 37, alignmentPatternCenters: [6, 28, 54, 80, 106, 132, 158], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 17, dataCodewordsPerBlock: 122 }, { numBlocks: 4, dataCodewordsPerBlock: 123 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 29, dataCodewordsPerBlock: 46 }, { numBlocks: 14, dataCodewordsPerBlock: 47 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 49, dataCodewordsPerBlock: 24 }, { numBlocks: 10, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 24, dataCodewordsPerBlock: 15 }, { numBlocks: 46, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x26A64, versionNumber: 38, alignmentPatternCenters: [6, 32, 58, 84, 110, 136, 162], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 4, dataCodewordsPerBlock: 122 }, { numBlocks: 18, dataCodewordsPerBlock: 123 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 13, dataCodewordsPerBlock: 46 }, { numBlocks: 32, dataCodewordsPerBlock: 47 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 48, dataCodewordsPerBlock: 24 }, { numBlocks: 14, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 42, dataCodewordsPerBlock: 15 }, { numBlocks: 32, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x27541, versionNumber: 39, alignmentPatternCenters: [6, 26, 54, 82, 110, 138, 166], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 20, dataCodewordsPerBlock: 117 }, { numBlocks: 4, dataCodewordsPerBlock: 118 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 40, dataCodewordsPerBlock: 47 }, { numBlocks: 7, dataCodewordsPerBlock: 48 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 43, dataCodewordsPerBlock: 24 }, { numBlocks: 22, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 10, dataCodewordsPerBlock: 15 }, { numBlocks: 67, dataCodewordsPerBlock: 16 }, ], }, ], }, { infoBits: 0x28C69, versionNumber: 40, alignmentPatternCenters: [6, 30, 58, 86, 114, 142, 170], errorCorrectionLevels: [ { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 19, dataCodewordsPerBlock: 118 }, { numBlocks: 6, dataCodewordsPerBlock: 119 }, ], }, { ecCodewordsPerBlock: 28, ecBlocks: [ { numBlocks: 18, dataCodewordsPerBlock: 47 }, { numBlocks: 31, dataCodewordsPerBlock: 48 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 34, dataCodewordsPerBlock: 24 }, { numBlocks: 34, dataCodewordsPerBlock: 25 }, ], }, { ecCodewordsPerBlock: 30, ecBlocks: [ { numBlocks: 20, dataCodewordsPerBlock: 15 }, { numBlocks: 61, dataCodewordsPerBlock: 16 }, ], }, ], }, ]; /***/ }), /* 11 */ /***/ (function(module, exports, __nested_webpack_require_231645__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var BitMatrix_1 = __nested_webpack_require_231645__(0); function squareToQuadrilateral(p1, p2, p3, p4) { var dx3 = p1.x - p2.x + p3.x - p4.x; var dy3 = p1.y - p2.y + p3.y - p4.y; if (dx3 === 0 && dy3 === 0) { // Affine return { a11: p2.x - p1.x, a12: p2.y - p1.y, a13: 0, a21: p3.x - p2.x, a22: p3.y - p2.y, a23: 0, a31: p1.x, a32: p1.y, a33: 1, }; } else { var dx1 = p2.x - p3.x; var dx2 = p4.x - p3.x; var dy1 = p2.y - p3.y; var dy2 = p4.y - p3.y; var denominator = dx1 * dy2 - dx2 * dy1; var a13 = (dx3 * dy2 - dx2 * dy3) / denominator; var a23 = (dx1 * dy3 - dx3 * dy1) / denominator; return { a11: p2.x - p1.x + a13 * p2.x, a12: p2.y - p1.y + a13 * p2.y, a13: a13, a21: p4.x - p1.x + a23 * p4.x, a22: p4.y - p1.y + a23 * p4.y, a23: a23, a31: p1.x, a32: p1.y, a33: 1, }; } } function quadrilateralToSquare(p1, p2, p3, p4) { // Here, the adjoint serves as the inverse: var sToQ = squareToQuadrilateral(p1, p2, p3, p4); return { a11: sToQ.a22 * sToQ.a33 - sToQ.a23 * sToQ.a32, a12: sToQ.a13 * sToQ.a32 - sToQ.a12 * sToQ.a33, a13: sToQ.a12 * sToQ.a23 - sToQ.a13 * sToQ.a22, a21: sToQ.a23 * sToQ.a31 - sToQ.a21 * sToQ.a33, a22: sToQ.a11 * sToQ.a33 - sToQ.a13 * sToQ.a31, a23: sToQ.a13 * sToQ.a21 - sToQ.a11 * sToQ.a23, a31: sToQ.a21 * sToQ.a32 - sToQ.a22 * sToQ.a31, a32: sToQ.a12 * sToQ.a31 - sToQ.a11 * sToQ.a32, a33: sToQ.a11 * sToQ.a22 - sToQ.a12 * sToQ.a21, }; } function times(a, b) { return { a11: a.a11 * b.a11 + a.a21 * b.a12 + a.a31 * b.a13, a12: a.a12 * b.a11 + a.a22 * b.a12 + a.a32 * b.a13, a13: a.a13 * b.a11 + a.a23 * b.a12 + a.a33 * b.a13, a21: a.a11 * b.a21 + a.a21 * b.a22 + a.a31 * b.a23, a22: a.a12 * b.a21 + a.a22 * b.a22 + a.a32 * b.a23, a23: a.a13 * b.a21 + a.a23 * b.a22 + a.a33 * b.a23, a31: a.a11 * b.a31 + a.a21 * b.a32 + a.a31 * b.a33, a32: a.a12 * b.a31 + a.a22 * b.a32 + a.a32 * b.a33, a33: a.a13 * b.a31 + a.a23 * b.a32 + a.a33 * b.a33, }; } function extract(image, location) { var qToS = quadrilateralToSquare({ x: 3.5, y: 3.5 }, { x: location.dimension - 3.5, y: 3.5 }, { x: location.dimension - 6.5, y: location.dimension - 6.5 }, { x: 3.5, y: location.dimension - 3.5 }); var sToQ = squareToQuadrilateral(location.topLeft, location.topRight, location.alignmentPattern, location.bottomLeft); var transform = times(sToQ, qToS); var matrix = BitMatrix_1.BitMatrix.createEmpty(location.dimension, location.dimension); var mappingFunction = function (x, y) { var denominator = transform.a13 * x + transform.a23 * y + transform.a33; return { x: (transform.a11 * x + transform.a21 * y + transform.a31) / denominator, y: (transform.a12 * x + transform.a22 * y + transform.a32) / denominator, }; }; for (var y = 0; y < location.dimension; y++) { for (var x = 0; x < location.dimension; x++) { var xValue = x + 0.5; var yValue = y + 0.5; var sourcePixel = mappingFunction(xValue, yValue); matrix.set(x, y, image.get(Math.floor(sourcePixel.x), Math.floor(sourcePixel.y))); } } return { matrix: matrix, mappingFunction: mappingFunction, }; } exports.extract = extract; /***/ }), /* 12 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var MAX_FINDERPATTERNS_TO_SEARCH = 4; var MIN_QUAD_RATIO = 0.5; var MAX_QUAD_RATIO = 1.5; var distance = function (a, b) { return Math.sqrt(Math.pow((b.x - a.x), 2) + Math.pow((b.y - a.y), 2)); }; function sum(values) { return values.reduce(function (a, b) { return a + b; }); } // Takes three finder patterns and organizes them into topLeft, topRight, etc function reorderFinderPatterns(pattern1, pattern2, pattern3) { var _a, _b, _c, _d; // Find distances between pattern centers var oneTwoDistance = distance(pattern1, pattern2); var twoThreeDistance = distance(pattern2, pattern3); var oneThreeDistance = distance(pattern1, pattern3); var bottomLeft; var topLeft; var topRight; // Assume one closest to other two is B; A and C will just be guesses at first if (twoThreeDistance >= oneTwoDistance && twoThreeDistance >= oneThreeDistance) { _a = [pattern2, pattern1, pattern3], bottomLeft = _a[0], topLeft = _a[1], topRight = _a[2]; } else if (oneThreeDistance >= twoThreeDistance && oneThreeDistance >= oneTwoDistance) { _b = [pattern1, pattern2, pattern3], bottomLeft = _b[0], topLeft = _b[1], topRight = _b[2]; } else { _c = [pattern1, pattern3, pattern2], bottomLeft = _c[0], topLeft = _c[1], topRight = _c[2]; } // Use cross product to figure out whether bottomLeft (A) and topRight (C) are correct or flipped in relation to topLeft (B) // This asks whether BC x BA has a positive z component, which is the arrangement we want. If it's negative, then // we've got it flipped around and should swap topRight and bottomLeft. if (((topRight.x - topLeft.x) * (bottomLeft.y - topLeft.y)) - ((topRight.y - topLeft.y) * (bottomLeft.x - topLeft.x)) < 0) { _d = [topRight, bottomLeft], bottomLeft = _d[0], topRight = _d[1]; } return { bottomLeft: bottomLeft, topLeft: topLeft, topRight: topRight }; } // Computes the dimension (number of modules on a side) of the QR Code based on the position of the finder patterns function computeDimension(topLeft, topRight, bottomLeft, matrix) { var moduleSize = (sum(countBlackWhiteRun(topLeft, bottomLeft, matrix, 5)) / 7 + // Divide by 7 since the ratio is 1:1:3:1:1 sum(countBlackWhiteRun(topLeft, topRight, matrix, 5)) / 7 + sum(countBlackWhiteRun(bottomLeft, topLeft, matrix, 5)) / 7 + sum(countBlackWhiteRun(topRight, topLeft, matrix, 5)) / 7) / 4; if (moduleSize < 1) { throw new Error("Invalid module size"); } var topDimension = Math.round(distance(topLeft, topRight) / moduleSize); var sideDimension = Math.round(distance(topLeft, bottomLeft) / moduleSize); var dimension = Math.floor((topDimension + sideDimension) / 2) + 7; switch (dimension % 4) { case 0: dimension++; break; case 2: dimension--; break; } return { dimension: dimension, moduleSize: moduleSize }; } // Takes an origin point and an end point and counts the sizes of the black white run from the origin towards the end point. // Returns an array of elements, representing the pixel size of the black white run. // Uses a variant of http://en.wikipedia.org/wiki/Bresenham's_line_algorithm function countBlackWhiteRunTowardsPoint(origin, end, matrix, length) { var switchPoints = [{ x: Math.floor(origin.x), y: Math.floor(origin.y) }]; var steep = Math.abs(end.y - origin.y) > Math.abs(end.x - origin.x); var fromX; var fromY; var toX; var toY; if (steep) { fromX = Math.floor(origin.y); fromY = Math.floor(origin.x); toX = Math.floor(end.y); toY = Math.floor(end.x); } else { fromX = Math.floor(origin.x); fromY = Math.floor(origin.y); toX = Math.floor(end.x); toY = Math.floor(end.y); } var dx = Math.abs(toX - fromX); var dy = Math.abs(toY - fromY); var error = Math.floor(-dx / 2); var xStep = fromX < toX ? 1 : -1; var yStep = fromY < toY ? 1 : -1; var currentPixel = true; // Loop up until x == toX, but not beyond for (var x = fromX, y = fromY; x !== toX + xStep; x += xStep) { // Does current pixel mean we have moved white to black or vice versa? // Scanning black in state 0,2 and white in state 1, so if we find the wrong // color, advance to next state or end if we are in state 2 already var realX = steep ? y : x; var realY = steep ? x : y; if (matrix.get(realX, realY) !== currentPixel) { currentPixel = !currentPixel; switchPoints.push({ x: realX, y: realY }); if (switchPoints.length === length + 1) { break; } } error += dy; if (error > 0) { if (y === toY) { break; } y += yStep; error -= dx; } } var distances = []; for (var i = 0; i < length; i++) { if (switchPoints[i] && switchPoints[i + 1]) { distances.push(distance(switchPoints[i], switchPoints[i + 1])); } else { distances.push(0); } } return distances; } // Takes an origin point and an end point and counts the sizes of the black white run in the origin point // along the line that intersects with the end point. Returns an array of elements, representing the pixel sizes // of the black white run. Takes a length which represents the number of switches from black to white to look for. function countBlackWhiteRun(origin, end, matrix, length) { var _a; var rise = end.y - origin.y; var run = end.x - origin.x; var towardsEnd = countBlackWhiteRunTowardsPoint(origin, end, matrix, Math.ceil(length / 2)); var awayFromEnd = countBlackWhiteRunTowardsPoint(origin, { x: origin.x - run, y: origin.y - rise }, matrix, Math.ceil(length / 2)); var middleValue = towardsEnd.shift() + awayFromEnd.shift() - 1; // Substract one so we don't double count a pixel return (_a = awayFromEnd.concat(middleValue)).concat.apply(_a, towardsEnd); } // Takes in a black white run and an array of expected ratios. Returns the average size of the run as well as the "error" - // that is the amount the run diverges from the expected ratio function scoreBlackWhiteRun(sequence, ratios) { var averageSize = sum(sequence) / sum(ratios); var error = 0; ratios.forEach(function (ratio, i) { error += Math.pow((sequence[i] - ratio * averageSize), 2); }); return { averageSize: averageSize, error: error }; } // Takes an X,Y point and an array of sizes and scores the point against those ratios. // For example for a finder pattern takes the ratio list of 1:1:3:1:1 and checks horizontal, vertical and diagonal ratios // against that. function scorePattern(point, ratios, matrix) { try { var horizontalRun = countBlackWhiteRun(point, { x: -1, y: point.y }, matrix, ratios.length); var verticalRun = countBlackWhiteRun(point, { x: point.x, y: -1 }, matrix, ratios.length); var topLeftPoint = { x: Math.max(0, point.x - point.y) - 1, y: Math.max(0, point.y - point.x) - 1, }; var topLeftBottomRightRun = countBlackWhiteRun(point, topLeftPoint, matrix, ratios.length); var bottomLeftPoint = { x: Math.min(matrix.width, point.x + point.y) + 1, y: Math.min(matrix.height, point.y + point.x) + 1, }; var bottomLeftTopRightRun = countBlackWhiteRun(point, bottomLeftPoint, matrix, ratios.length); var horzError = scoreBlackWhiteRun(horizontalRun, ratios); var vertError = scoreBlackWhiteRun(verticalRun, ratios); var diagDownError = scoreBlackWhiteRun(topLeftBottomRightRun, ratios); var diagUpError = scoreBlackWhiteRun(bottomLeftTopRightRun, ratios); var ratioError = Math.sqrt(horzError.error * horzError.error + vertError.error * vertError.error + diagDownError.error * diagDownError.error + diagUpError.error * diagUpError.error); var avgSize = (horzError.averageSize + vertError.averageSize + diagDownError.averageSize + diagUpError.averageSize) / 4; var sizeError = (Math.pow((horzError.averageSize - avgSize), 2) + Math.pow((vertError.averageSize - avgSize), 2) + Math.pow((diagDownError.averageSize - avgSize), 2) + Math.pow((diagUpError.averageSize - avgSize), 2)) / avgSize; return ratioError + sizeError; } catch (_a) { return Infinity; } } function recenterLocation(matrix, p) { var leftX = Math.round(p.x); while (matrix.get(leftX, Math.round(p.y))) { leftX--; } var rightX = Math.round(p.x); while (matrix.get(rightX, Math.round(p.y))) { rightX++; } var x = (leftX + rightX) / 2; var topY = Math.round(p.y); while (matrix.get(Math.round(x), topY)) { topY--; } var bottomY = Math.round(p.y); while (matrix.get(Math.round(x), bottomY)) { bottomY++; } var y = (topY + bottomY) / 2; return { x: x, y: y }; } function locate(matrix) { var finderPatternQuads = []; var activeFinderPatternQuads = []; var alignmentPatternQuads = []; var activeAlignmentPatternQuads = []; var _loop_1 = function (y) { var length_1 = 0; var lastBit = false; var scans = [0, 0, 0, 0, 0]; var _loop_2 = function (x) { var v = matrix.get(x, y); if (v === lastBit) { length_1++; } else { scans = [scans[1], scans[2], scans[3], scans[4], length_1]; length_1 = 1; lastBit = v; // Do the last 5 color changes ~ match the expected ratio for a finder pattern? 1:1:3:1:1 of b:w:b:w:b var averageFinderPatternBlocksize = sum(scans) / 7; var validFinderPattern = Math.abs(scans[0] - averageFinderPatternBlocksize) < averageFinderPatternBlocksize && Math.abs(scans[1] - averageFinderPatternBlocksize) < averageFinderPatternBlocksize && Math.abs(scans[2] - 3 * averageFinderPatternBlocksize) < 3 * averageFinderPatternBlocksize && Math.abs(scans[3] - averageFinderPatternBlocksize) < averageFinderPatternBlocksize && Math.abs(scans[4] - averageFinderPatternBlocksize) < averageFinderPatternBlocksize && !v; // And make sure the current pixel is white since finder patterns are bordered in white // Do the last 3 color changes ~ match the expected ratio for an alignment pattern? 1:1:1 of w:b:w var averageAlignmentPatternBlocksize = sum(scans.slice(-3)) / 3; var validAlignmentPattern = Math.abs(scans[2] - averageAlignmentPatternBlocksize) < averageAlignmentPatternBlocksize && Math.abs(scans[3] - averageAlignmentPatternBlocksize) < averageAlignmentPatternBlocksize && Math.abs(scans[4] - averageAlignmentPatternBlocksize) < averageAlignmentPatternBlocksize && v; // Is the current pixel black since alignment patterns are bordered in black if (validFinderPattern) { // Compute the start and end x values of the large center black square var endX_1 = x - scans[3] - scans[4]; var startX_1 = endX_1 - scans[2]; var line = { startX: startX_1, endX: endX_1, y: y }; // Is there a quad directly above the current spot? If so, extend it with the new line. Otherwise, create a new quad with // that line as the starting point. var matchingQuads = activeFinderPatternQuads.filter(function (q) { return (startX_1 >= q.bottom.startX && startX_1 <= q.bottom.endX) || (endX_1 >= q.bottom.startX && startX_1 <= q.bottom.endX) || (startX_1 <= q.bottom.startX && endX_1 >= q.bottom.endX && ((scans[2] / (q.bottom.endX - q.bottom.startX)) < MAX_QUAD_RATIO && (scans[2] / (q.bottom.endX - q.bottom.startX)) > MIN_QUAD_RATIO)); }); if (matchingQuads.length > 0) { matchingQuads[0].bottom = line; } else { activeFinderPatternQuads.push({ top: line, bottom: line }); } } if (validAlignmentPattern) { // Compute the start and end x values of the center black square var endX_2 = x - scans[4]; var startX_2 = endX_2 - scans[3]; var line = { startX: startX_2, y: y, endX: endX_2 }; // Is there a quad directly above the current spot? If so, extend it with the new line. Otherwise, create a new quad with // that line as the starting point. var matchingQuads = activeAlignmentPatternQuads.filter(function (q) { return (startX_2 >= q.bottom.startX && startX_2 <= q.bottom.endX) || (endX_2 >= q.bottom.startX && startX_2 <= q.bottom.endX) || (startX_2 <= q.bottom.startX && endX_2 >= q.bottom.endX && ((scans[2] / (q.bottom.endX - q.bottom.startX)) < MAX_QUAD_RATIO && (scans[2] / (q.bottom.endX - q.bottom.startX)) > MIN_QUAD_RATIO)); }); if (matchingQuads.length > 0) { matchingQuads[0].bottom = line; } else { activeAlignmentPatternQuads.push({ top: line, bottom: line }); } } } }; for (var x = -1; x <= matrix.width; x++) { _loop_2(x); } finderPatternQuads.push.apply(finderPatternQuads, activeFinderPatternQuads.filter(function (q) { return q.bottom.y !== y && q.bottom.y - q.top.y >= 2; })); activeFinderPatternQuads = activeFinderPatternQuads.filter(function (q) { return q.bottom.y === y; }); alignmentPatternQuads.push.apply(alignmentPatternQuads, activeAlignmentPatternQuads.filter(function (q) { return q.bottom.y !== y; })); activeAlignmentPatternQuads = activeAlignmentPatternQuads.filter(function (q) { return q.bottom.y === y; }); }; for (var y = 0; y <= matrix.height; y++) { _loop_1(y); } finderPatternQuads.push.apply(finderPatternQuads, activeFinderPatternQuads.filter(function (q) { return q.bottom.y - q.top.y >= 2; })); alignmentPatternQuads.push.apply(alignmentPatternQuads, activeAlignmentPatternQuads); var finderPatternGroups = finderPatternQuads .filter(function (q) { return q.bottom.y - q.top.y >= 2; }) // All quads must be at least 2px tall since the center square is larger than a block .map(function (q) { var x = (q.top.startX + q.top.endX + q.bottom.startX + q.bottom.endX) / 4; var y = (q.top.y + q.bottom.y + 1) / 2; if (!matrix.get(Math.round(x), Math.round(y))) { return; } var lengths = [q.top.endX - q.top.startX, q.bottom.endX - q.bottom.startX, q.bottom.y - q.top.y + 1]; var size = sum(lengths) / lengths.length; var score = scorePattern({ x: Math.round(x), y: Math.round(y) }, [1, 1, 3, 1, 1], matrix); return { score: score, x: x, y: y, size: size }; }) .filter(function (q) { return !!q; }) // Filter out any rejected quads from above .sort(function (a, b) { return a.score - b.score; }) // Now take the top finder pattern options and try to find 2 other options with a similar size. .map(function (point, i, finderPatterns) { if (i > MAX_FINDERPATTERNS_TO_SEARCH) { return null; } var otherPoints = finderPatterns .filter(function (p, ii) { return i !== ii; }) .map(function (p) { return ({ x: p.x, y: p.y, score: p.score + (Math.pow((p.size - point.size), 2)) / point.size, size: p.size }); }) .sort(function (a, b) { return a.score - b.score; }); if (otherPoints.length < 2) { return null; } var score = point.score + otherPoints[0].score + otherPoints[1].score; return { points: [point].concat(otherPoints.slice(0, 2)), score: score }; }) .filter(function (q) { return !!q; }) // Filter out any rejected finder patterns from above .sort(function (a, b) { return a.score - b.score; }); if (finderPatternGroups.length === 0) { return null; } var _a = reorderFinderPatterns(finderPatternGroups[0].points[0], finderPatternGroups[0].points[1], finderPatternGroups[0].points[2]), topRight = _a.topRight, topLeft = _a.topLeft, bottomLeft = _a.bottomLeft; var alignment = findAlignmentPattern(matrix, alignmentPatternQuads, topRight, topLeft, bottomLeft); var result = []; if (alignment) { result.push({ alignmentPattern: { x: alignment.alignmentPattern.x, y: alignment.alignmentPattern.y }, bottomLeft: { x: bottomLeft.x, y: bottomLeft.y }, dimension: alignment.dimension, topLeft: { x: topLeft.x, y: topLeft.y }, topRight: { x: topRight.x, y: topRight.y }, }); } // We normally use the center of the quads as the location of the tracking points, which is optimal for most cases and will account // for a skew in the image. However, In some cases, a slight skew might not be real and instead be caused by image compression // errors and/or low resolution. For those cases, we'd be better off centering the point exactly in the middle of the black area. We // compute and return the location data for the naively centered points as it is little additional work and allows for multiple // attempts at decoding harder images. var midTopRight = recenterLocation(matrix, topRight); var midTopLeft = recenterLocation(matrix, topLeft); var midBottomLeft = recenterLocation(matrix, bottomLeft); var centeredAlignment = findAlignmentPattern(matrix, alignmentPatternQuads, midTopRight, midTopLeft, midBottomLeft); if (centeredAlignment) { result.push({ alignmentPattern: { x: centeredAlignment.alignmentPattern.x, y: centeredAlignment.alignmentPattern.y }, bottomLeft: { x: midBottomLeft.x, y: midBottomLeft.y }, topLeft: { x: midTopLeft.x, y: midTopLeft.y }, topRight: { x: midTopRight.x, y: midTopRight.y }, dimension: centeredAlignment.dimension, }); } if (result.length === 0) { return null; } return result; } exports.locate = locate; function findAlignmentPattern(matrix, alignmentPatternQuads, topRight, topLeft, bottomLeft) { var _a; // Now that we've found the three finder patterns we can determine the blockSize and the size of the QR code. // We'll use these to help find the alignment pattern but also later when we do the extraction. var dimension; var moduleSize; try { (_a = computeDimension(topLeft, topRight, bottomLeft, matrix), dimension = _a.dimension, moduleSize = _a.moduleSize); } catch (e) { return null; } // Now find the alignment pattern var bottomRightFinderPattern = { x: topRight.x - topLeft.x + bottomLeft.x, y: topRight.y - topLeft.y + bottomLeft.y, }; var modulesBetweenFinderPatterns = ((distance(topLeft, bottomLeft) + distance(topLeft, topRight)) / 2 / moduleSize); var correctionToTopLeft = 1 - (3 / modulesBetweenFinderPatterns); var expectedAlignmentPattern = { x: topLeft.x + correctionToTopLeft * (bottomRightFinderPattern.x - topLeft.x), y: topLeft.y + correctionToTopLeft * (bottomRightFinderPattern.y - topLeft.y), }; var alignmentPatterns = alignmentPatternQuads .map(function (q) { var x = (q.top.startX + q.top.endX + q.bottom.startX + q.bottom.endX) / 4; var y = (q.top.y + q.bottom.y + 1) / 2; if (!matrix.get(Math.floor(x), Math.floor(y))) { return; } var lengths = [q.top.endX - q.top.startX, q.bottom.endX - q.bottom.startX, (q.bottom.y - q.top.y + 1)]; var size = sum(lengths) / lengths.length; var sizeScore = scorePattern({ x: Math.floor(x), y: Math.floor(y) }, [1, 1, 1], matrix); var score = sizeScore + distance({ x: x, y: y }, expectedAlignmentPattern); return { x: x, y: y, score: score }; }) .filter(function (v) { return !!v; }) .sort(function (a, b) { return a.score - b.score; }); // If there are less than 15 modules between finder patterns it's a version 1 QR code and as such has no alignmemnt pattern // so we can only use our best guess. var alignmentPattern = modulesBetweenFinderPatterns >= 15 && alignmentPatterns.length ? alignmentPatterns[0] : expectedAlignmentPattern; return { alignmentPattern: alignmentPattern, dimension: dimension }; } /***/ }) /******/ ])["default"]; }); /***/ }), /***/ "./node_modules/react-dom/client.js": /*!******************************************!*\ !*** ./node_modules/react-dom/client.js ***! \******************************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { "use strict"; var m = __webpack_require__(/*! react-dom */ "react-dom"); if (false) // removed by dead control flow {} else { var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; exports.createRoot = function(c, o) { i.usingClientEntryPoint = true; try { return m.createRoot(c, o); } finally { i.usingClientEntryPoint = false; } }; exports.hydrateRoot = function(c, h, o) { i.usingClientEntryPoint = true; try { return m.hydrateRoot(c, h, o); } finally { i.usingClientEntryPoint = false; } }; } /***/ }), /***/ "./node_modules/react/cjs/react-jsx-dev-runtime.development.js": /*!*********************************************************************!*\ !*** ./node_modules/react/cjs/react-jsx-dev-runtime.development.js ***! \*********************************************************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { "use strict"; /** * @license React * react-jsx-dev-runtime.development.js * * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ if (true) { (function() { 'use strict'; var React = __webpack_require__(/*! react */ "react"); // ATTENTION // When adding new symbols to this file, // Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols' // The Symbol used to tag the ReactElement-like types. var REACT_ELEMENT_TYPE = Symbol.for('react.element'); var REACT_PORTAL_TYPE = Symbol.for('react.portal'); var REACT_FRAGMENT_TYPE = Symbol.for('react.fragment'); var REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode'); var REACT_PROFILER_TYPE = Symbol.for('react.profiler'); var REACT_PROVIDER_TYPE = Symbol.for('react.provider'); var REACT_CONTEXT_TYPE = Symbol.for('react.context'); var REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref'); var REACT_SUSPENSE_TYPE = Symbol.for('react.suspense'); var REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list'); var REACT_MEMO_TYPE = Symbol.for('react.memo'); var REACT_LAZY_TYPE = Symbol.for('react.lazy'); var REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen'); var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; var FAUX_ITERATOR_SYMBOL = '@@iterator'; function getIteratorFn(maybeIterable) { if (maybeIterable === null || typeof maybeIterable !== 'object') { return null; } var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; if (typeof maybeIterator === 'function') { return maybeIterator; } return null; } var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; function error(format) { { { for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { args[_key2 - 1] = arguments[_key2]; } printWarning('error', format, args); } } } function printWarning(level, format, args) { // When changing this logic, you might want to also // update consoleWithStackDev.www.js as well. { var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; var stack = ReactDebugCurrentFrame.getStackAddendum(); if (stack !== '') { format += '%s'; args = args.concat([stack]); } // eslint-disable-next-line react-internal/safe-string-coercion var argsWithFormat = args.map(function (item) { return String(item); }); // Careful: RN currently depends on this prefix argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it // breaks IE9: https://github.com/facebook/react/issues/13610 // eslint-disable-next-line react-internal/no-production-logging Function.prototype.apply.call(console[level], console, argsWithFormat); } } // ----------------------------------------------------------------------------- var enableScopeAPI = false; // Experimental Create Event Handle API. var enableCacheElement = false; var enableTransitionTracing = false; // No known bugs, but needs performance testing var enableLegacyHidden = false; // Enables unstable_avoidThisFallback feature in Fiber // stuff. Intended to enable React core members to more easily debug scheduling // issues in DEV builds. var enableDebugTracing = false; // Track which Fiber(s) schedule render work. var REACT_MODULE_REFERENCE; { REACT_MODULE_REFERENCE = Symbol.for('react.module.reference'); } function isValidElementType(type) { if (typeof type === 'string' || typeof type === 'function') { return true; } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill). if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden || type === REACT_OFFSCREEN_TYPE || enableScopeAPI || enableCacheElement || enableTransitionTracing ) { return true; } if (typeof type === 'object' && type !== null) { if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object // types supported by any Flight configuration anywhere since // we don't know which Flight build this will end up being used // with. type.$$typeof === REACT_MODULE_REFERENCE || type.getModuleId !== undefined) { return true; } } return false; } function getWrappedName(outerType, innerType, wrapperName) { var displayName = outerType.displayName; if (displayName) { return displayName; } var functionName = innerType.displayName || innerType.name || ''; return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName; } // Keep in sync with react-reconciler/getComponentNameFromFiber function getContextName(type) { return type.displayName || 'Context'; } // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. function getComponentNameFromType(type) { if (type == null) { // Host root, text node or just invalid type. return null; } { if (typeof type.tag === 'number') { error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.'); } } if (typeof type === 'function') { return type.displayName || type.name || null; } if (typeof type === 'string') { return type; } switch (type) { case REACT_FRAGMENT_TYPE: return 'Fragment'; case REACT_PORTAL_TYPE: return 'Portal'; case REACT_PROFILER_TYPE: return 'Profiler'; case REACT_STRICT_MODE_TYPE: return 'StrictMode'; case REACT_SUSPENSE_TYPE: return 'Suspense'; case REACT_SUSPENSE_LIST_TYPE: return 'SuspenseList'; } if (typeof type === 'object') { switch (type.$$typeof) { case REACT_CONTEXT_TYPE: var context = type; return getContextName(context) + '.Consumer'; case REACT_PROVIDER_TYPE: var provider = type; return getContextName(provider._context) + '.Provider'; case REACT_FORWARD_REF_TYPE: return getWrappedName(type, type.render, 'ForwardRef'); case REACT_MEMO_TYPE: var outerName = type.displayName || null; if (outerName !== null) { return outerName; } return getComponentNameFromType(type.type) || 'Memo'; case REACT_LAZY_TYPE: { var lazyComponent = type; var payload = lazyComponent._payload; var init = lazyComponent._init; try { return getComponentNameFromType(init(payload)); } catch (x) { return null; } } // eslint-disable-next-line no-fallthrough } } return null; } var assign = Object.assign; // Helpers to patch console.logs to avoid logging during side-effect free // replaying on render function. This currently only patches the object // lazily which won't cover if the log function was extracted eagerly. // We could also eagerly patch the method. var disabledDepth = 0; var prevLog; var prevInfo; var prevWarn; var prevError; var prevGroup; var prevGroupCollapsed; var prevGroupEnd; function disabledLog() {} disabledLog.__reactDisabledLog = true; function disableLogs() { { if (disabledDepth === 0) { /* eslint-disable react-internal/no-production-logging */ prevLog = console.log; prevInfo = console.info; prevWarn = console.warn; prevError = console.error; prevGroup = console.group; prevGroupCollapsed = console.groupCollapsed; prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099 var props = { configurable: true, enumerable: true, value: disabledLog, writable: true }; // $FlowFixMe Flow thinks console is immutable. Object.defineProperties(console, { info: props, log: props, warn: props, error: props, group: props, groupCollapsed: props, groupEnd: props }); /* eslint-enable react-internal/no-production-logging */ } disabledDepth++; } } function reenableLogs() { { disabledDepth--; if (disabledDepth === 0) { /* eslint-disable react-internal/no-production-logging */ var props = { configurable: true, enumerable: true, writable: true }; // $FlowFixMe Flow thinks console is immutable. Object.defineProperties(console, { log: assign({}, props, { value: prevLog }), info: assign({}, props, { value: prevInfo }), warn: assign({}, props, { value: prevWarn }), error: assign({}, props, { value: prevError }), group: assign({}, props, { value: prevGroup }), groupCollapsed: assign({}, props, { value: prevGroupCollapsed }), groupEnd: assign({}, props, { value: prevGroupEnd }) }); /* eslint-enable react-internal/no-production-logging */ } if (disabledDepth < 0) { error('disabledDepth fell below zero. ' + 'This is a bug in React. Please file an issue.'); } } } var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; var prefix; function describeBuiltInComponentFrame(name, source, ownerFn) { { if (prefix === undefined) { // Extract the VM specific prefix used by each line. try { throw Error(); } catch (x) { var match = x.stack.trim().match(/\n( *(at )?)/); prefix = match && match[1] || ''; } } // We use the prefix to ensure our stacks line up with native stack frames. return '\n' + prefix + name; } } var reentry = false; var componentFrameCache; { var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; componentFrameCache = new PossiblyWeakMap(); } function describeNativeComponentFrame(fn, construct) { // If something asked for a stack inside a fake render, it should get ignored. if ( !fn || reentry) { return ''; } { var frame = componentFrameCache.get(fn); if (frame !== undefined) { return frame; } } var control; reentry = true; var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe It does accept undefined. Error.prepareStackTrace = undefined; var previousDispatcher; { previousDispatcher = ReactCurrentDispatcher.current; // Set the dispatcher in DEV because this might be call in the render function // for warnings. ReactCurrentDispatcher.current = null; disableLogs(); } try { // This should throw. if (construct) { // Something should be setting the props in the constructor. var Fake = function () { throw Error(); }; // $FlowFixMe Object.defineProperty(Fake.prototype, 'props', { set: function () { // We use a throwing setter instead of frozen or non-writable props // because that won't throw in a non-strict mode function. throw Error(); } }); if (typeof Reflect === 'object' && Reflect.construct) { // We construct a different control for this case to include any extra // frames added by the construct call. try { Reflect.construct(Fake, []); } catch (x) { control = x; } Reflect.construct(fn, [], Fake); } else { try { Fake.call(); } catch (x) { control = x; } fn.call(Fake.prototype); } } else { try { throw Error(); } catch (x) { control = x; } fn(); } } catch (sample) { // This is inlined manually because closure doesn't do it for us. if (sample && control && typeof sample.stack === 'string') { // This extracts the first frame from the sample that isn't also in the control. // Skipping one frame that we assume is the frame that calls the two. var sampleLines = sample.stack.split('\n'); var controlLines = control.stack.split('\n'); var s = sampleLines.length - 1; var c = controlLines.length - 1; while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { // We expect at least one stack frame to be shared. // Typically this will be the root most one. However, stack frames may be // cut off due to maximum stack limits. In this case, one maybe cut off // earlier than the other. We assume that the sample is longer or the same // and there for cut off earlier. So we should find the root most frame in // the sample somewhere in the control. c--; } for (; s >= 1 && c >= 0; s--, c--) { // Next we find the first one that isn't the same which should be the // frame that called our sample function and the control. if (sampleLines[s] !== controlLines[c]) { // In V8, the first line is describing the message but other VMs don't. // If we're about to return the first line, and the control is also on the same // line, that's a pretty good indicator that our sample threw at same line as // the control. I.e. before we entered the sample frame. So we ignore this result. // This can happen if you passed a class to function component, or non-function. if (s !== 1 || c !== 1) { do { s--; c--; // We may still have similar intermediate frames from the construct call. // The next one that isn't the same should be our match though. if (c < 0 || sampleLines[s] !== controlLines[c]) { // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. var _frame = '\n' + sampleLines[s].replace(' at new ', ' at '); // If our component frame is labeled "" // but we have a user-provided "displayName" // splice it in to make the stack more readable. if (fn.displayName && _frame.includes('')) { _frame = _frame.replace('', fn.displayName); } { if (typeof fn === 'function') { componentFrameCache.set(fn, _frame); } } // Return the line we found. return _frame; } } while (s >= 1 && c >= 0); } break; } } } } finally { reentry = false; { ReactCurrentDispatcher.current = previousDispatcher; reenableLogs(); } Error.prepareStackTrace = previousPrepareStackTrace; } // Fallback to just using the name if we couldn't make it throw. var name = fn ? fn.displayName || fn.name : ''; var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ''; { if (typeof fn === 'function') { componentFrameCache.set(fn, syntheticFrame); } } return syntheticFrame; } function describeFunctionComponentFrame(fn, source, ownerFn) { { return describeNativeComponentFrame(fn, false); } } function shouldConstruct(Component) { var prototype = Component.prototype; return !!(prototype && prototype.isReactComponent); } function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) { if (type == null) { return ''; } if (typeof type === 'function') { { return describeNativeComponentFrame(type, shouldConstruct(type)); } } if (typeof type === 'string') { return describeBuiltInComponentFrame(type); } switch (type) { case REACT_SUSPENSE_TYPE: return describeBuiltInComponentFrame('Suspense'); case REACT_SUSPENSE_LIST_TYPE: return describeBuiltInComponentFrame('SuspenseList'); } if (typeof type === 'object') { switch (type.$$typeof) { case REACT_FORWARD_REF_TYPE: return describeFunctionComponentFrame(type.render); case REACT_MEMO_TYPE: // Memo may contain any component type so we recursively resolve it. return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn); case REACT_LAZY_TYPE: { var lazyComponent = type; var payload = lazyComponent._payload; var init = lazyComponent._init; try { // Lazy may contain any component type so we recursively resolve it. return describeUnknownElementTypeFrameInDEV(init(payload), source, ownerFn); } catch (x) {} } } } return ''; } var hasOwnProperty = Object.prototype.hasOwnProperty; var loggedTypeFailures = {}; var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; function setCurrentlyValidatingElement(element) { { if (element) { var owner = element._owner; var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null); ReactDebugCurrentFrame.setExtraStackFrame(stack); } else { ReactDebugCurrentFrame.setExtraStackFrame(null); } } } function checkPropTypes(typeSpecs, values, location, componentName, element) { { // $FlowFixMe This is okay but Flow doesn't know it. var has = Function.call.bind(hasOwnProperty); for (var typeSpecName in typeSpecs) { if (has(typeSpecs, typeSpecName)) { var error$1 = void 0; // Prop type validation may throw. In case they do, we don't want to // fail the render phase where it didn't fail before. So we log it. // After these have been cleaned up, we'll let them throw. try { // This is intentionally an invariant that gets caught. It's the same // behavior as without this statement except with a better message. if (typeof typeSpecs[typeSpecName] !== 'function') { // eslint-disable-next-line react-internal/prod-error-codes var err = Error((componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' + 'This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.'); err.name = 'Invariant Violation'; throw err; } error$1 = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'); } catch (ex) { error$1 = ex; } if (error$1 && !(error$1 instanceof Error)) { setCurrentlyValidatingElement(element); error('%s: type specification of %s' + ' `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error$1); setCurrentlyValidatingElement(null); } if (error$1 instanceof Error && !(error$1.message in loggedTypeFailures)) { // Only monitor this failure once because there tends to be a lot of the // same error. loggedTypeFailures[error$1.message] = true; setCurrentlyValidatingElement(element); error('Failed %s type: %s', location, error$1.message); setCurrentlyValidatingElement(null); } } } } } var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare function isArray(a) { return isArrayImpl(a); } /* * The `'' + value` pattern (used in in perf-sensitive code) throws for Symbol * and Temporal.* types. See https://github.com/facebook/react/pull/22064. * * The functions in this module will throw an easier-to-understand, * easier-to-debug exception with a clear errors message message explaining the * problem. (Instead of a confusing exception thrown inside the implementation * of the `value` object). */ // $FlowFixMe only called in DEV, so void return is not possible. function typeName(value) { { // toStringTag is needed for namespaced types like Temporal.Instant var hasToStringTag = typeof Symbol === 'function' && Symbol.toStringTag; var type = hasToStringTag && value[Symbol.toStringTag] || value.constructor.name || 'Object'; return type; } } // $FlowFixMe only called in DEV, so void return is not possible. function willCoercionThrow(value) { { try { testStringCoercion(value); return false; } catch (e) { return true; } } } function testStringCoercion(value) { // If you ended up here by following an exception call stack, here's what's // happened: you supplied an object or symbol value to React (as a prop, key, // DOM attribute, CSS property, string ref, etc.) and when React tried to // coerce it to a string using `'' + value`, an exception was thrown. // // The most common types that will cause this exception are `Symbol` instances // and Temporal objects like `Temporal.Instant`. But any object that has a // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this // exception. (Library authors do this to prevent users from using built-in // numeric operators like `+` or comparison operators like `>=` because custom // methods are needed to perform accurate arithmetic or comparison.) // // To fix the problem, coerce this object or symbol value to a string before // passing it to React. The most reliable way is usually `String(value)`. // // To find which value is throwing, check the browser or debugger console. // Before this exception was thrown, there should be `console.error` output // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the // problem and how that type was used: key, atrribute, input value prop, etc. // In most cases, this console output also shows the component and its // ancestor components where the exception happened. // // eslint-disable-next-line react-internal/safe-string-coercion return '' + value; } function checkKeyStringCoercion(value) { { if (willCoercionThrow(value)) { error('The provided key is an unsupported type %s.' + ' This value must be coerced to a string before before using it here.', typeName(value)); return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } } } var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; var RESERVED_PROPS = { key: true, ref: true, __self: true, __source: true }; var specialPropKeyWarningShown; var specialPropRefWarningShown; var didWarnAboutStringRefs; { didWarnAboutStringRefs = {}; } function hasValidRef(config) { { if (hasOwnProperty.call(config, 'ref')) { var getter = Object.getOwnPropertyDescriptor(config, 'ref').get; if (getter && getter.isReactWarning) { return false; } } } return config.ref !== undefined; } function hasValidKey(config) { { if (hasOwnProperty.call(config, 'key')) { var getter = Object.getOwnPropertyDescriptor(config, 'key').get; if (getter && getter.isReactWarning) { return false; } } } return config.key !== undefined; } function warnIfStringRefCannotBeAutoConverted(config, self) { { if (typeof config.ref === 'string' && ReactCurrentOwner.current && self && ReactCurrentOwner.current.stateNode !== self) { var componentName = getComponentNameFromType(ReactCurrentOwner.current.type); if (!didWarnAboutStringRefs[componentName]) { error('Component "%s" contains the string ref "%s". ' + 'Support for string refs will be removed in a future major release. ' + 'This case cannot be automatically converted to an arrow function. ' + 'We ask you to manually fix this case by using useRef() or createRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://reactjs.org/link/strict-mode-string-ref', getComponentNameFromType(ReactCurrentOwner.current.type), config.ref); didWarnAboutStringRefs[componentName] = true; } } } } function defineKeyPropWarningGetter(props, displayName) { { var warnAboutAccessingKey = function () { if (!specialPropKeyWarningShown) { specialPropKeyWarningShown = true; error('%s: `key` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://reactjs.org/link/special-props)', displayName); } }; warnAboutAccessingKey.isReactWarning = true; Object.defineProperty(props, 'key', { get: warnAboutAccessingKey, configurable: true }); } } function defineRefPropWarningGetter(props, displayName) { { var warnAboutAccessingRef = function () { if (!specialPropRefWarningShown) { specialPropRefWarningShown = true; error('%s: `ref` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://reactjs.org/link/special-props)', displayName); } }; warnAboutAccessingRef.isReactWarning = true; Object.defineProperty(props, 'ref', { get: warnAboutAccessingRef, configurable: true }); } } /** * Factory method to create a new React element. This no longer adheres to * the class pattern, so do not use new to call it. Also, instanceof check * will not work. Instead test $$typeof field against Symbol.for('react.element') to check * if something is a React Element. * * @param {*} type * @param {*} props * @param {*} key * @param {string|object} ref * @param {*} owner * @param {*} self A *temporary* helper to detect places where `this` is * different from the `owner` when React.createElement is called, so that we * can warn. We want to get rid of owner and replace string `ref`s with arrow * functions, and as long as `this` and owner are the same, there will be no * change in behavior. * @param {*} source An annotation object (added by a transpiler or otherwise) * indicating filename, line number, and/or other information. * @internal */ var ReactElement = function (type, key, ref, self, source, owner, props) { var element = { // This tag allows us to uniquely identify this as a React Element $$typeof: REACT_ELEMENT_TYPE, // Built-in properties that belong on the element type: type, key: key, ref: ref, props: props, // Record the component responsible for creating this element. _owner: owner }; { // The validation flag is currently mutative. We put it on // an external backing store so that we can freeze the whole object. // This can be replaced with a WeakMap once they are implemented in // commonly used development environments. element._store = {}; // To make comparing ReactElements easier for testing purposes, we make // the validation flag non-enumerable (where possible, which should // include every environment we run tests in), so the test framework // ignores it. Object.defineProperty(element._store, 'validated', { configurable: false, enumerable: false, writable: true, value: false }); // self and source are DEV only properties. Object.defineProperty(element, '_self', { configurable: false, enumerable: false, writable: false, value: self }); // Two elements created in two different places should be considered // equal for testing purposes and therefore we hide it from enumeration. Object.defineProperty(element, '_source', { configurable: false, enumerable: false, writable: false, value: source }); if (Object.freeze) { Object.freeze(element.props); Object.freeze(element); } } return element; }; /** * https://github.com/reactjs/rfcs/pull/107 * @param {*} type * @param {object} props * @param {string} key */ function jsxDEV(type, config, maybeKey, source, self) { { var propName; // Reserved names are extracted var props = {}; var key = null; var ref = null; // Currently, key can be spread in as a prop. This causes a potential // issue if key is also explicitly declared (ie.

// or
). We want to deprecate key spread, // but as an intermediary step, we will use jsxDEV for everything except //
, because we aren't currently able to tell if // key is explicitly declared to be undefined or not. if (maybeKey !== undefined) { { checkKeyStringCoercion(maybeKey); } key = '' + maybeKey; } if (hasValidKey(config)) { { checkKeyStringCoercion(config.key); } key = '' + config.key; } if (hasValidRef(config)) { ref = config.ref; warnIfStringRefCannotBeAutoConverted(config, self); } // Remaining properties are added to a new props object for (propName in config) { if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) { props[propName] = config[propName]; } } // Resolve default props if (type && type.defaultProps) { var defaultProps = type.defaultProps; for (propName in defaultProps) { if (props[propName] === undefined) { props[propName] = defaultProps[propName]; } } } if (key || ref) { var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; if (key) { defineKeyPropWarningGetter(props, displayName); } if (ref) { defineRefPropWarningGetter(props, displayName); } } return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props); } } var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame; function setCurrentlyValidatingElement$1(element) { { if (element) { var owner = element._owner; var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null); ReactDebugCurrentFrame$1.setExtraStackFrame(stack); } else { ReactDebugCurrentFrame$1.setExtraStackFrame(null); } } } var propTypesMisspellWarningShown; { propTypesMisspellWarningShown = false; } /** * Verifies the object is a ReactElement. * See https://reactjs.org/docs/react-api.html#isvalidelement * @param {?object} object * @return {boolean} True if `object` is a ReactElement. * @final */ function isValidElement(object) { { return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; } } function getDeclarationErrorAddendum() { { if (ReactCurrentOwner$1.current) { var name = getComponentNameFromType(ReactCurrentOwner$1.current.type); if (name) { return '\n\nCheck the render method of `' + name + '`.'; } } return ''; } } function getSourceInfoErrorAddendum(source) { { if (source !== undefined) { var fileName = source.fileName.replace(/^.*[\\\/]/, ''); var lineNumber = source.lineNumber; return '\n\nCheck your code at ' + fileName + ':' + lineNumber + '.'; } return ''; } } /** * Warn if there's no key explicitly set on dynamic arrays of children or * object keys are not valid. This allows us to keep track of children between * updates. */ var ownerHasKeyUseWarning = {}; function getCurrentComponentErrorInfo(parentType) { { var info = getDeclarationErrorAddendum(); if (!info) { var parentName = typeof parentType === 'string' ? parentType : parentType.displayName || parentType.name; if (parentName) { info = "\n\nCheck the top-level render call using <" + parentName + ">."; } } return info; } } /** * Warn if the element doesn't have an explicit key assigned to it. * This element is in an array. The array could grow and shrink or be * reordered. All children that haven't already been validated are required to * have a "key" property assigned to it. Error statuses are cached so a warning * will only be shown once. * * @internal * @param {ReactElement} element Element that requires a key. * @param {*} parentType element's parent's type. */ function validateExplicitKey(element, parentType) { { if (!element._store || element._store.validated || element.key != null) { return; } element._store.validated = true; var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType); if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { return; } ownerHasKeyUseWarning[currentComponentErrorInfo] = true; // Usually the current owner is the offender, but if it accepts children as a // property, it may be the creator of the child that's responsible for // assigning it a key. var childOwner = ''; if (element && element._owner && element._owner !== ReactCurrentOwner$1.current) { // Give the component that originally created this child. childOwner = " It was passed a child from " + getComponentNameFromType(element._owner.type) + "."; } setCurrentlyValidatingElement$1(element); error('Each child in a list should have a unique "key" prop.' + '%s%s See https://reactjs.org/link/warning-keys for more information.', currentComponentErrorInfo, childOwner); setCurrentlyValidatingElement$1(null); } } /** * Ensure that every element either is passed in a static location, in an * array with an explicit keys property defined, or in an object literal * with valid key property. * * @internal * @param {ReactNode} node Statically passed child of any type. * @param {*} parentType node's parent's type. */ function validateChildKeys(node, parentType) { { if (typeof node !== 'object') { return; } if (isArray(node)) { for (var i = 0; i < node.length; i++) { var child = node[i]; if (isValidElement(child)) { validateExplicitKey(child, parentType); } } } else if (isValidElement(node)) { // This element was passed in a valid location. if (node._store) { node._store.validated = true; } } else if (node) { var iteratorFn = getIteratorFn(node); if (typeof iteratorFn === 'function') { // Entry iterators used to provide implicit keys, // but now we print a separate warning for them later. if (iteratorFn !== node.entries) { var iterator = iteratorFn.call(node); var step; while (!(step = iterator.next()).done) { if (isValidElement(step.value)) { validateExplicitKey(step.value, parentType); } } } } } } } /** * Given an element, validate that its props follow the propTypes definition, * provided by the type. * * @param {ReactElement} element */ function validatePropTypes(element) { { var type = element.type; if (type === null || type === undefined || typeof type === 'string') { return; } var propTypes; if (typeof type === 'function') { propTypes = type.propTypes; } else if (typeof type === 'object' && (type.$$typeof === REACT_FORWARD_REF_TYPE || // Note: Memo only checks outer props here. // Inner props are checked in the reconciler. type.$$typeof === REACT_MEMO_TYPE)) { propTypes = type.propTypes; } else { return; } if (propTypes) { // Intentionally inside to avoid triggering lazy initializers: var name = getComponentNameFromType(type); checkPropTypes(propTypes, element.props, 'prop', name, element); } else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) { propTypesMisspellWarningShown = true; // Intentionally inside to avoid triggering lazy initializers: var _name = getComponentNameFromType(type); error('Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?', _name || 'Unknown'); } if (typeof type.getDefaultProps === 'function' && !type.getDefaultProps.isReactClassApproved) { error('getDefaultProps is only used on classic React.createClass ' + 'definitions. Use a static property named `defaultProps` instead.'); } } } /** * Given a fragment, validate that it can only be provided with fragment props * @param {ReactElement} fragment */ function validateFragmentProps(fragment) { { var keys = Object.keys(fragment.props); for (var i = 0; i < keys.length; i++) { var key = keys[i]; if (key !== 'children' && key !== 'key') { setCurrentlyValidatingElement$1(fragment); error('Invalid prop `%s` supplied to `React.Fragment`. ' + 'React.Fragment can only have `key` and `children` props.', key); setCurrentlyValidatingElement$1(null); break; } } if (fragment.ref !== null) { setCurrentlyValidatingElement$1(fragment); error('Invalid attribute `ref` supplied to `React.Fragment`.'); setCurrentlyValidatingElement$1(null); } } } var didWarnAboutKeySpread = {}; function jsxWithValidation(type, props, key, isStaticChildren, source, self) { { var validType = isValidElementType(type); // We warn in this case but don't throw. We expect the element creation to // succeed and there will likely be errors in render. if (!validType) { var info = ''; if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) { info += ' You likely forgot to export your component from the file ' + "it's defined in, or you might have mixed up default and named imports."; } var sourceInfo = getSourceInfoErrorAddendum(source); if (sourceInfo) { info += sourceInfo; } else { info += getDeclarationErrorAddendum(); } var typeString; if (type === null) { typeString = 'null'; } else if (isArray(type)) { typeString = 'array'; } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) { typeString = "<" + (getComponentNameFromType(type.type) || 'Unknown') + " />"; info = ' Did you accidentally export a JSX literal instead of a component?'; } else { typeString = typeof type; } error('React.jsx: type is invalid -- expected a string (for ' + 'built-in components) or a class/function (for composite ' + 'components) but got: %s.%s', typeString, info); } var element = jsxDEV(type, props, key, source, self); // The result can be nullish if a mock or a custom function is used. // TODO: Drop this when these are no longer allowed as the type argument. if (element == null) { return element; } // Skip key warning if the type isn't valid since our key validation logic // doesn't expect a non-string/function type and can throw confusing errors. // We don't want exception behavior to differ between dev and prod. // (Rendering will throw with a helpful message and as soon as the type is // fixed, the key warnings will appear.) if (validType) { var children = props.children; if (children !== undefined) { if (isStaticChildren) { if (isArray(children)) { for (var i = 0; i < children.length; i++) { validateChildKeys(children[i], type); } if (Object.freeze) { Object.freeze(children); } } else { error('React.jsx: Static children should always be an array. ' + 'You are likely explicitly calling React.jsxs or React.jsxDEV. ' + 'Use the Babel transform instead.'); } } else { validateChildKeys(children, type); } } } { if (hasOwnProperty.call(props, 'key')) { var componentName = getComponentNameFromType(type); var keys = Object.keys(props).filter(function (k) { return k !== 'key'; }); var beforeExample = keys.length > 0 ? '{key: someKey, ' + keys.join(': ..., ') + ': ...}' : '{key: someKey}'; if (!didWarnAboutKeySpread[componentName + beforeExample]) { var afterExample = keys.length > 0 ? '{' + keys.join(': ..., ') + ': ...}' : '{}'; error('A props object containing a "key" prop is being spread into JSX:\n' + ' let props = %s;\n' + ' <%s {...props} />\n' + 'React keys must be passed directly to JSX without using spread:\n' + ' let props = %s;\n' + ' <%s key={someKey} {...props} />', beforeExample, componentName, afterExample, componentName); didWarnAboutKeySpread[componentName + beforeExample] = true; } } } if (type === REACT_FRAGMENT_TYPE) { validateFragmentProps(element); } else { validatePropTypes(element); } return element; } } // These two functions exist to still get child warnings in dev var jsxDEV$1 = jsxWithValidation ; exports.Fragment = REACT_FRAGMENT_TYPE; exports.jsxDEV = jsxDEV$1; })(); } /***/ }), /***/ "./node_modules/react/jsx-dev-runtime.js": /*!***********************************************!*\ !*** ./node_modules/react/jsx-dev-runtime.js ***! \***********************************************/ /***/ (function(module, __unused_webpack_exports, __webpack_require__) { "use strict"; if (false) // removed by dead control flow {} else { module.exports = __webpack_require__(/*! ./cjs/react-jsx-dev-runtime.development.js */ "./node_modules/react/cjs/react-jsx-dev-runtime.development.js"); } /***/ }), /***/ "qrcodejs": /*!*************************!*\ !*** external "QRCode" ***! \*************************/ /***/ (function(module) { "use strict"; module.exports = QRCode; /***/ }), /***/ "react": /*!************************!*\ !*** external "React" ***! \************************/ /***/ (function(module) { "use strict"; module.exports = React; /***/ }), /***/ "react-dom": /*!***************************!*\ !*** external "ReactDOM" ***! \***************************/ /***/ (function(module) { "use strict"; module.exports = ReactDOM; /***/ }), /***/ "react-intl": /*!****************************!*\ !*** external "ReactIntl" ***! \****************************/ /***/ (function(module) { "use strict"; module.exports = ReactIntl; /***/ }), /***/ "tinode-sdk": /*!*************************!*\ !*** external "tinode" ***! \*************************/ /***/ (function(module) { "use strict"; module.exports = tinode; /***/ }), /***/ "./node_modules/@firebase/app/dist/esm/index.esm.js": /*!**********************************************************!*\ !*** ./node_modules/@firebase/app/dist/esm/index.esm.js ***! \**********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ FirebaseError: function() { return /* reexport safe */ _firebase_util__WEBPACK_IMPORTED_MODULE_2__.FirebaseError; }, /* harmony export */ SDK_VERSION: function() { return /* binding */ SDK_VERSION; }, /* harmony export */ _DEFAULT_ENTRY_NAME: function() { return /* binding */ DEFAULT_ENTRY_NAME; }, /* harmony export */ _addComponent: function() { return /* binding */ _addComponent; }, /* harmony export */ _addOrOverwriteComponent: function() { return /* binding */ _addOrOverwriteComponent; }, /* harmony export */ _apps: function() { return /* binding */ _apps; }, /* harmony export */ _clearComponents: function() { return /* binding */ _clearComponents; }, /* harmony export */ _components: function() { return /* binding */ _components; }, /* harmony export */ _getProvider: function() { return /* binding */ _getProvider; }, /* harmony export */ _isFirebaseApp: function() { return /* binding */ _isFirebaseApp; }, /* harmony export */ _isFirebaseServerApp: function() { return /* binding */ _isFirebaseServerApp; }, /* harmony export */ _isFirebaseServerAppSettings: function() { return /* binding */ _isFirebaseServerAppSettings; }, /* harmony export */ _registerComponent: function() { return /* binding */ _registerComponent; }, /* harmony export */ _removeServiceInstance: function() { return /* binding */ _removeServiceInstance; }, /* harmony export */ _serverApps: function() { return /* binding */ _serverApps; }, /* harmony export */ deleteApp: function() { return /* binding */ deleteApp; }, /* harmony export */ getApp: function() { return /* binding */ getApp; }, /* harmony export */ getApps: function() { return /* binding */ getApps; }, /* harmony export */ initializeApp: function() { return /* binding */ initializeApp; }, /* harmony export */ initializeServerApp: function() { return /* binding */ initializeServerApp; }, /* harmony export */ onLog: function() { return /* binding */ onLog; }, /* harmony export */ registerVersion: function() { return /* binding */ registerVersion; }, /* harmony export */ setLogLevel: function() { return /* binding */ setLogLevel; } /* harmony export */ }); /* harmony import */ var _firebase_component__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/component */ "./node_modules/@firebase/component/dist/esm/index.esm.js"); /* harmony import */ var _firebase_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @firebase/logger */ "./node_modules/@firebase/logger/dist/esm/index.esm.js"); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm.js"); /* harmony import */ var idb__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! idb */ "./node_modules/idb/build/index.js"); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class PlatformLoggerServiceImpl { constructor(container) { this.container = container; } // In initial implementation, this will be called by installations on // auth token refresh, and installations will send this string. getPlatformInfoString() { const providers = this.container.getProviders(); // Loop through providers and get library/version pairs from any that are // version components. return providers .map(provider => { if (isVersionServiceProvider(provider)) { const service = provider.getImmediate(); return `${service.library}/${service.version}`; } else { return null; } }) .filter(logString => logString) .join(' '); } } /** * * @param provider check if this provider provides a VersionService * * NOTE: Using Provider<'app-version'> is a hack to indicate that the provider * provides VersionService. The provider is not necessarily a 'app-version' * provider. */ function isVersionServiceProvider(provider) { const component = provider.getComponent(); return component?.type === "VERSION" /* ComponentType.VERSION */; } const name$q = "@firebase/app"; const version$1 = "0.15.0"; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const logger = new _firebase_logger__WEBPACK_IMPORTED_MODULE_1__.Logger('@firebase/app'); const name$p = "@firebase/app-compat"; const name$o = "@firebase/analytics-compat"; const name$n = "@firebase/analytics"; const name$m = "@firebase/app-check-compat"; const name$l = "@firebase/app-check"; const name$k = "@firebase/auth"; const name$j = "@firebase/auth-compat"; const name$i = "@firebase/database"; const name$h = "@firebase/data-connect"; const name$g = "@firebase/database-compat"; const name$f = "@firebase/functions"; const name$e = "@firebase/functions-compat"; const name$d = "@firebase/installations"; const name$c = "@firebase/installations-compat"; const name$b = "@firebase/messaging"; const name$a = "@firebase/messaging-compat"; const name$9 = "@firebase/performance"; const name$8 = "@firebase/performance-compat"; const name$7 = "@firebase/remote-config"; const name$6 = "@firebase/remote-config-compat"; const name$5 = "@firebase/storage"; const name$4 = "@firebase/storage-compat"; const name$3 = "@firebase/firestore"; const name$2 = "@firebase/ai"; const name$1 = "@firebase/firestore-compat"; const name = "firebase"; const version = "12.15.0"; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * The default app name * * @internal */ const DEFAULT_ENTRY_NAME = '[DEFAULT]'; const PLATFORM_LOG_STRING = { [name$q]: 'fire-core', [name$p]: 'fire-core-compat', [name$n]: 'fire-analytics', [name$o]: 'fire-analytics-compat', [name$l]: 'fire-app-check', [name$m]: 'fire-app-check-compat', [name$k]: 'fire-auth', [name$j]: 'fire-auth-compat', [name$i]: 'fire-rtdb', [name$h]: 'fire-data-connect', [name$g]: 'fire-rtdb-compat', [name$f]: 'fire-fn', [name$e]: 'fire-fn-compat', [name$d]: 'fire-iid', [name$c]: 'fire-iid-compat', [name$b]: 'fire-fcm', [name$a]: 'fire-fcm-compat', [name$9]: 'fire-perf', [name$8]: 'fire-perf-compat', [name$7]: 'fire-rc', [name$6]: 'fire-rc-compat', [name$5]: 'fire-gcs', [name$4]: 'fire-gcs-compat', [name$3]: 'fire-fst', [name$1]: 'fire-fst-compat', [name$2]: 'fire-vertex', 'fire-js': 'fire-js', // Platform identifier for JS SDK. [name]: 'fire-js-all' }; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @internal */ const _apps = new Map(); /** * @internal */ const _serverApps = new Map(); /** * Registered components. * * @internal */ // eslint-disable-next-line @typescript-eslint/no-explicit-any const _components = new Map(); /** * @param component - the component being added to this app's container * * @internal */ function _addComponent(app, component) { try { app.container.addComponent(component); } catch (e) { logger.debug(`Component ${component.name} failed to register with FirebaseApp ${app.name}`, e); } } /** * * @internal */ function _addOrOverwriteComponent(app, component) { app.container.addOrOverwriteComponent(component); } /** * * @param component - the component to register * @returns whether or not the component is registered successfully * * @internal */ function _registerComponent(component) { const componentName = component.name; if (_components.has(componentName)) { logger.debug(`There were multiple attempts to register component ${componentName}.`); return false; } _components.set(componentName, component); // add the component to existing app instances for (const app of _apps.values()) { _addComponent(app, component); } for (const serverApp of _serverApps.values()) { _addComponent(serverApp, component); } return true; } /** * * @param app - FirebaseApp instance * @param name - service name * * @returns the provider for the service with the matching name * * @internal */ function _getProvider(app, name) { const heartbeatController = app.container .getProvider('heartbeat') .getImmediate({ optional: true }); if (heartbeatController) { void heartbeatController.triggerHeartbeat(); } return app.container.getProvider(name); } /** * * @param app - FirebaseApp instance * @param name - service name * @param instanceIdentifier - service instance identifier in case the service supports multiple instances * * @internal */ function _removeServiceInstance(app, name, instanceIdentifier = DEFAULT_ENTRY_NAME) { _getProvider(app, name).clearInstance(instanceIdentifier); } /** * * @param obj - an object of type FirebaseApp, FirebaseOptions or FirebaseAppSettings. * * @returns true if the provide object is of type FirebaseApp. * * @internal */ function _isFirebaseApp(obj) { return obj.options !== undefined; } /** * * @param obj - an object of type FirebaseApp, FirebaseOptions or FirebaseAppSettings. * * @returns true if the provided object is of type FirebaseServerAppImpl. * * @internal */ function _isFirebaseServerAppSettings(obj) { if (_isFirebaseApp(obj)) { return false; } return ('authIdToken' in obj || 'appCheckToken' in obj || 'releaseOnDeref' in obj || 'automaticDataCollectionEnabled' in obj); } /** * * @param obj - an object of type FirebaseApp. * * @returns true if the provided object is of type FirebaseServerAppImpl. * * @internal */ function _isFirebaseServerApp(obj) { if (obj === null || obj === undefined) { return false; } return obj.settings !== undefined; } /** * Test only * * @internal */ function _clearComponents() { _components.clear(); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const ERRORS = { ["no-app" /* AppError.NO_APP */]: "No Firebase App '{$appName}' has been created - " + 'call initializeApp() first', ["bad-app-name" /* AppError.BAD_APP_NAME */]: "Illegal App name: '{$appName}'", ["duplicate-app" /* AppError.DUPLICATE_APP */]: "Firebase App named '{$appName}' already exists with different options or config", ["app-deleted" /* AppError.APP_DELETED */]: "Firebase App named '{$appName}' already deleted", ["server-app-deleted" /* AppError.SERVER_APP_DELETED */]: 'Firebase Server App has been deleted', ["no-options" /* AppError.NO_OPTIONS */]: 'Need to provide options, when not being deployed to hosting via source.', ["invalid-app-argument" /* AppError.INVALID_APP_ARGUMENT */]: 'firebase.{$appName}() takes either no argument or a ' + 'Firebase App instance.', ["invalid-log-argument" /* AppError.INVALID_LOG_ARGUMENT */]: 'First argument to `onLog` must be null or a function.', ["idb-open" /* AppError.IDB_OPEN */]: 'Error thrown when opening IndexedDB. Original error: {$originalErrorMessage}.', ["idb-get" /* AppError.IDB_GET */]: 'Error thrown when reading from IndexedDB. Original error: {$originalErrorMessage}.', ["idb-set" /* AppError.IDB_WRITE */]: 'Error thrown when writing to IndexedDB. Original error: {$originalErrorMessage}.', ["idb-delete" /* AppError.IDB_DELETE */]: 'Error thrown when deleting from IndexedDB. Original error: {$originalErrorMessage}.', ["finalization-registry-not-supported" /* AppError.FINALIZATION_REGISTRY_NOT_SUPPORTED */]: 'FirebaseServerApp deleteOnDeref field defined but the JS runtime does not support FinalizationRegistry.', ["invalid-server-app-environment" /* AppError.INVALID_SERVER_APP_ENVIRONMENT */]: 'FirebaseServerApp is not for use in browser environments.' }; const ERROR_FACTORY = new _firebase_util__WEBPACK_IMPORTED_MODULE_2__.ErrorFactory('app', 'Firebase', ERRORS); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class FirebaseAppImpl { constructor(options, config, container) { this._isDeleted = false; this._options = { ...options }; this._config = { ...config }; this._name = config.name; this._automaticDataCollectionEnabled = config.automaticDataCollectionEnabled; this._container = container; this.container.addComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component('app', () => this, "PUBLIC" /* ComponentType.PUBLIC */)); } get automaticDataCollectionEnabled() { this.checkDestroyed(); return this._automaticDataCollectionEnabled; } set automaticDataCollectionEnabled(val) { this.checkDestroyed(); this._automaticDataCollectionEnabled = val; } get name() { this.checkDestroyed(); return this._name; } get options() { this.checkDestroyed(); return this._options; } get config() { this.checkDestroyed(); return this._config; } get container() { return this._container; } get isDeleted() { return this._isDeleted; } set isDeleted(val) { this._isDeleted = val; } /** * This function will throw an Error if the App has already been deleted - * use before performing API actions on the App. */ checkDestroyed() { if (this.isDeleted) { throw ERROR_FACTORY.create("app-deleted" /* AppError.APP_DELETED */, { appName: this._name }); } } } /** * @license * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Parse the token and check to see if the `exp` claim is in the future. // Reports an error to the console if the token or claim could not be parsed, or if `exp` is in // the past. function validateTokenTTL(base64Token, tokenName) { const secondPart = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.base64Decode)(base64Token.split('.')[1]); if (secondPart === null) { console.error(`FirebaseServerApp ${tokenName} is invalid: second part could not be parsed.`); return; } const expClaim = JSON.parse(secondPart).exp; if (expClaim === undefined) { console.error(`FirebaseServerApp ${tokenName} is invalid: expiration claim could not be parsed`); return; } const exp = JSON.parse(secondPart).exp * 1000; const now = new Date().getTime(); const diff = exp - now; if (diff <= 0) { console.error(`FirebaseServerApp ${tokenName} is invalid: the token has expired.`); } } class FirebaseServerAppImpl extends FirebaseAppImpl { constructor(options, serverConfig, name, container) { // Build configuration parameters for the FirebaseAppImpl base class. const automaticDataCollectionEnabled = serverConfig.automaticDataCollectionEnabled !== undefined ? serverConfig.automaticDataCollectionEnabled : true; // Create the FirebaseAppSettings object for the FirebaseAppImp constructor. const config = { name, automaticDataCollectionEnabled }; if (options.apiKey !== undefined) { // Construct the parent FirebaseAppImp object. super(options, config, container); } else { const appImpl = options; super(appImpl.options, config, container); } // Now construct the data for the FirebaseServerAppImpl. this._serverConfig = { automaticDataCollectionEnabled, ...serverConfig }; // Ensure that the current time is within the `authIdtoken` window of validity. if (this._serverConfig.authIdToken) { validateTokenTTL(this._serverConfig.authIdToken, 'authIdToken'); } // Ensure that the current time is within the `appCheckToken` window of validity. if (this._serverConfig.appCheckToken) { validateTokenTTL(this._serverConfig.appCheckToken, 'appCheckToken'); } this._finalizationRegistry = null; if (typeof FinalizationRegistry !== 'undefined') { this._finalizationRegistry = new FinalizationRegistry(() => { this.automaticCleanup(); }); } this._refCount = 0; this.incRefCount(this._serverConfig.releaseOnDeref); // Do not retain a hard reference to the dref object, otherwise the FinalizationRegistry // will never trigger. this._serverConfig.releaseOnDeref = undefined; serverConfig.releaseOnDeref = undefined; registerVersion(name$q, version$1, 'serverapp'); } toJSON() { return undefined; } get refCount() { return this._refCount; } // Increment the reference count of this server app. If an object is provided, register it // with the finalization registry. incRefCount(obj) { if (this.isDeleted) { return; } this._refCount++; if (obj !== undefined && this._finalizationRegistry !== null) { this._finalizationRegistry.register(obj, this); } } // Decrement the reference count. decRefCount() { if (this.isDeleted) { return 0; } return --this._refCount; } // Invoked by the FinalizationRegistry callback to note that this app should go through its // reference counts and delete itself if no reference count remain. The coordinating logic that // handles this is in deleteApp(...). automaticCleanup() { void deleteApp(this); } get settings() { this.checkDestroyed(); return this._serverConfig; } /** * This function will throw an Error if the App has already been deleted - * use before performing API actions on the App. */ checkDestroyed() { if (this.isDeleted) { throw ERROR_FACTORY.create("server-app-deleted" /* AppError.SERVER_APP_DELETED */); } } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * The current SDK version. * * @public */ const SDK_VERSION = version; function initializeApp(_options, rawConfig = {}) { let options = _options; if (typeof rawConfig !== 'object') { const name = rawConfig; rawConfig = { name }; } const config = { name: DEFAULT_ENTRY_NAME, automaticDataCollectionEnabled: true, ...rawConfig }; const name = config.name; if (typeof name !== 'string' || !name) { throw ERROR_FACTORY.create("bad-app-name" /* AppError.BAD_APP_NAME */, { appName: String(name) }); } options || (options = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.getDefaultAppConfig)()); if (!options) { throw ERROR_FACTORY.create("no-options" /* AppError.NO_OPTIONS */); } const existingApp = _apps.get(name); if (existingApp) { // return the existing app if options and config deep equal the ones in the existing app. if ((0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.deepEqual)(options, existingApp.options) && (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.deepEqual)(config, existingApp.config)) { return existingApp; } else { throw ERROR_FACTORY.create("duplicate-app" /* AppError.DUPLICATE_APP */, { appName: name }); } } const container = new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.ComponentContainer(name); for (const component of _components.values()) { container.addComponent(component); } const newApp = new FirebaseAppImpl(options, config, container); _apps.set(name, newApp); return newApp; } function initializeServerApp(_options, _serverAppConfig = {}) { if ((0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.isBrowser)() && !(0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.isWebWorker)()) { // FirebaseServerApp isn't designed to be run in browsers. throw ERROR_FACTORY.create("invalid-server-app-environment" /* AppError.INVALID_SERVER_APP_ENVIRONMENT */); } let firebaseOptions; let serverAppSettings = _serverAppConfig || {}; if (_options) { if (_isFirebaseApp(_options)) { firebaseOptions = _options.options; } else if (_isFirebaseServerAppSettings(_options)) { serverAppSettings = _options; } else { firebaseOptions = _options; } } if (serverAppSettings.automaticDataCollectionEnabled === undefined) { serverAppSettings.automaticDataCollectionEnabled = true; } firebaseOptions || (firebaseOptions = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.getDefaultAppConfig)()); if (!firebaseOptions) { throw ERROR_FACTORY.create("no-options" /* AppError.NO_OPTIONS */); } // Build an app name based on a hash of the configuration options. const nameObj = { ...serverAppSettings, ...firebaseOptions }; // However, Do not mangle the name based on releaseOnDeref, since it will vary between the // construction of FirebaseServerApp instances. For example, if the object is the request headers. if (nameObj.releaseOnDeref !== undefined) { delete nameObj.releaseOnDeref; } const hashCode = (s) => { return [...s].reduce((hash, c) => (Math.imul(31, hash) + c.charCodeAt(0)) | 0, 0); }; if (serverAppSettings.releaseOnDeref !== undefined) { if (typeof FinalizationRegistry === 'undefined') { throw ERROR_FACTORY.create("finalization-registry-not-supported" /* AppError.FINALIZATION_REGISTRY_NOT_SUPPORTED */, {}); } } const nameString = '' + hashCode(JSON.stringify(nameObj)); const existingApp = _serverApps.get(nameString); if (existingApp) { existingApp.incRefCount(serverAppSettings.releaseOnDeref); return existingApp; } const container = new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.ComponentContainer(nameString); for (const component of _components.values()) { container.addComponent(component); } const newApp = new FirebaseServerAppImpl(firebaseOptions, serverAppSettings, nameString, container); _serverApps.set(nameString, newApp); return newApp; } /** * Retrieves a {@link @firebase/app#FirebaseApp} instance. * * When called with no arguments, the default app is returned. When an app name * is provided, the app corresponding to that name is returned. * * An exception is thrown if the app being retrieved has not yet been * initialized. * * @example * ```javascript * // Return the default app * const app = getApp(); * ``` * * @example * ```javascript * // Return a named app * const otherApp = getApp("otherApp"); * ``` * * @param name - Optional name of the app to return. If no name is * provided, the default is `"[DEFAULT]"`. * * @returns The app corresponding to the provided app name. * If no app name is provided, the default app is returned. * * @public */ function getApp(name = DEFAULT_ENTRY_NAME) { const app = _apps.get(name); if (!app && name === DEFAULT_ENTRY_NAME && (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.getDefaultAppConfig)()) { return initializeApp(); } if (!app) { throw ERROR_FACTORY.create("no-app" /* AppError.NO_APP */, { appName: name }); } return app; } /** * A (read-only) array of all initialized apps. * @public */ function getApps() { return Array.from(_apps.values()); } /** * Renders this app unusable and frees the resources of all associated * services. * * @example * ```javascript * deleteApp(app) * .then(function() { * console.log("App deleted successfully"); * }) * .catch(function(error) { * console.log("Error deleting app:", error); * }); * ``` * * @public */ async function deleteApp(app) { let cleanupProviders = false; const name = app.name; if (_apps.has(name)) { cleanupProviders = true; _apps.delete(name); } else if (_serverApps.has(name)) { const firebaseServerApp = app; if (firebaseServerApp.decRefCount() <= 0) { _serverApps.delete(name); cleanupProviders = true; } } if (cleanupProviders) { await Promise.all(app.container .getProviders() .map(provider => provider.delete())); app.isDeleted = true; } } /** * Registers a library's name and version for platform logging purposes. * @param library - Name of 1p or 3p library (e.g. firestore, angularfire) * @param version - Current version of that library. * @param variant - Bundle variant, e.g., node, rn, etc. * * @public */ function registerVersion(libraryKeyOrName, version, variant) { // TODO: We can use this check to whitelist strings when/if we set up // a good whitelist system. let library = PLATFORM_LOG_STRING[libraryKeyOrName] ?? libraryKeyOrName; if (variant) { library += `-${variant}`; } const libraryMismatch = library.match(/\s|\//); const versionMismatch = version.match(/\s|\//); if (libraryMismatch || versionMismatch) { const warning = [ `Unable to register library "${library}" with version "${version}":` ]; if (libraryMismatch) { warning.push(`library name "${library}" contains illegal characters (whitespace or "/")`); } if (libraryMismatch && versionMismatch) { warning.push('and'); } if (versionMismatch) { warning.push(`version name "${version}" contains illegal characters (whitespace or "/")`); } logger.warn(warning.join(' ')); return; } _registerComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component(`${library}-version`, () => ({ library, version }), "VERSION" /* ComponentType.VERSION */)); } /** * Sets log handler for all Firebase SDKs. * @param logCallback - An optional custom log handler that executes user code whenever * the Firebase SDK makes a logging call. * * @public */ function onLog(logCallback, options) { if (logCallback !== null && typeof logCallback !== 'function') { throw ERROR_FACTORY.create("invalid-log-argument" /* AppError.INVALID_LOG_ARGUMENT */); } (0,_firebase_logger__WEBPACK_IMPORTED_MODULE_1__.setUserLogHandler)(logCallback, options); } /** * Sets log level for all Firebase SDKs. * * All of the log types above the current log level are captured (i.e. if * you set the log level to `info`, errors are logged, but `debug` and * `verbose` logs are not). * * @public */ function setLogLevel(logLevel) { (0,_firebase_logger__WEBPACK_IMPORTED_MODULE_1__.setLogLevel)(logLevel); } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DB_NAME = 'firebase-heartbeat-database'; const DB_VERSION = 1; const STORE_NAME = 'firebase-heartbeat-store'; let dbPromise = null; function getDbPromise() { if (!dbPromise) { dbPromise = (0,idb__WEBPACK_IMPORTED_MODULE_3__.openDB)(DB_NAME, DB_VERSION, { upgrade: (db, oldVersion) => { // We don't use 'break' in this switch statement, the fall-through // behavior is what we want, because if there are multiple versions between // the old version and the current version, we want ALL the migrations // that correspond to those versions to run, not only the last one. // eslint-disable-next-line default-case switch (oldVersion) { case 0: try { db.createObjectStore(STORE_NAME); } catch (e) { // Safari/iOS browsers throw occasional exceptions on // db.createObjectStore() that may be a bug. Avoid blocking // the rest of the app functionality. console.warn(e); } } } }).catch(e => { throw ERROR_FACTORY.create("idb-open" /* AppError.IDB_OPEN */, { originalErrorMessage: e.message }); }); } return dbPromise; } async function readHeartbeatsFromIndexedDB(app) { try { const db = await getDbPromise(); const tx = db.transaction(STORE_NAME); const result = await tx.objectStore(STORE_NAME).get(computeKey(app)); // We already have the value but tx.done can throw, // so we need to await it here to catch errors await tx.done; return result; } catch (e) { if (e instanceof _firebase_util__WEBPACK_IMPORTED_MODULE_2__.FirebaseError) { logger.warn(e.message); } else { const idbGetError = ERROR_FACTORY.create("idb-get" /* AppError.IDB_GET */, { originalErrorMessage: e?.message }); logger.warn(idbGetError.message); } } } async function writeHeartbeatsToIndexedDB(app, heartbeatObject) { try { const db = await getDbPromise(); const tx = db.transaction(STORE_NAME, 'readwrite'); const objectStore = tx.objectStore(STORE_NAME); await objectStore.put(heartbeatObject, computeKey(app)); await tx.done; } catch (e) { if (e instanceof _firebase_util__WEBPACK_IMPORTED_MODULE_2__.FirebaseError) { logger.warn(e.message); } else { const idbGetError = ERROR_FACTORY.create("idb-set" /* AppError.IDB_WRITE */, { originalErrorMessage: e?.message }); logger.warn(idbGetError.message); } } } function computeKey(app) { return `${app.name}!${app.options.appId}`; } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const MAX_HEADER_BYTES = 1024; const MAX_NUM_STORED_HEARTBEATS = 30; class HeartbeatServiceImpl { constructor(container) { this.container = container; /** * In-memory cache for heartbeats, used by getHeartbeatsHeader() to generate * the header string. * Stores one record per date. This will be consolidated into the standard * format of one record per user agent string before being sent as a header. * Populated from indexedDB when the controller is instantiated and should * be kept in sync with indexedDB. * Leave public for easier testing. */ this._heartbeatsCache = null; const app = this.container.getProvider('app').getImmediate(); this._storage = new HeartbeatStorageImpl(app); this._heartbeatsCachePromise = this._storage.read().then(result => { this._heartbeatsCache = result; return result; }); } /** * Called to report a heartbeat. The function will generate * a HeartbeatsByUserAgent object, update heartbeatsCache, and persist it * to IndexedDB. * Note that we only store one heartbeat per day. So if a heartbeat for today is * already logged, subsequent calls to this function in the same day will be ignored. */ async triggerHeartbeat() { try { const platformLogger = this.container .getProvider('platform-logger') .getImmediate(); // This is the "Firebase user agent" string from the platform logger // service, not the browser user agent. const agent = platformLogger.getPlatformInfoString(); const date = getUTCDateString(); if (this._heartbeatsCache?.heartbeats == null) { this._heartbeatsCache = await this._heartbeatsCachePromise; // If we failed to construct a heartbeats cache, then return immediately. if (this._heartbeatsCache?.heartbeats == null) { return; } } // Do not store a heartbeat if one is already stored for this day // or if a header has already been sent today. if (this._heartbeatsCache.lastSentHeartbeatDate === date || this._heartbeatsCache.heartbeats.some(singleDateHeartbeat => singleDateHeartbeat.date === date)) { return; } else { // There is no entry for this date. Create one. this._heartbeatsCache.heartbeats.push({ date, agent }); // If the number of stored heartbeats exceeds the maximum number of stored heartbeats, remove the heartbeat with the earliest date. // Since this is executed each time a heartbeat is pushed, the limit can only be exceeded by one, so only one needs to be removed. if (this._heartbeatsCache.heartbeats.length > MAX_NUM_STORED_HEARTBEATS) { const earliestHeartbeatIdx = getEarliestHeartbeatIdx(this._heartbeatsCache.heartbeats); this._heartbeatsCache.heartbeats.splice(earliestHeartbeatIdx, 1); } } return this._storage.overwrite(this._heartbeatsCache); } catch (e) { logger.warn(e); } } /** * Returns a base64 encoded string which can be attached to the heartbeat-specific header directly. * It also clears all heartbeats from memory as well as in IndexedDB. * * NOTE: Consuming product SDKs should not send the header if this method * returns an empty string. */ async getHeartbeatsHeader() { try { if (this._heartbeatsCache === null) { await this._heartbeatsCachePromise; } // If it's still null or the array is empty, there is no data to send. if (this._heartbeatsCache?.heartbeats == null || this._heartbeatsCache.heartbeats.length === 0) { return ''; } const date = getUTCDateString(); // Extract as many heartbeats from the cache as will fit under the size limit. const { heartbeatsToSend, unsentEntries } = extractHeartbeatsForHeader(this._heartbeatsCache.heartbeats); const headerString = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.base64urlEncodeWithoutPadding)(JSON.stringify({ version: 2, heartbeats: heartbeatsToSend })); // Store last sent date to prevent another being logged/sent for the same day. this._heartbeatsCache.lastSentHeartbeatDate = date; if (unsentEntries.length > 0) { // Store any unsent entries if they exist. this._heartbeatsCache.heartbeats = unsentEntries; // This seems more likely than emptying the array (below) to lead to some odd state // since the cache isn't empty and this will be called again on the next request, // and is probably safest if we await it. await this._storage.overwrite(this._heartbeatsCache); } else { this._heartbeatsCache.heartbeats = []; // Do not wait for this, to reduce latency. void this._storage.overwrite(this._heartbeatsCache); } return headerString; } catch (e) { logger.warn(e); return ''; } } } function getUTCDateString() { const today = new Date(); // Returns date format 'YYYY-MM-DD' return today.toISOString().substring(0, 10); } function extractHeartbeatsForHeader(heartbeatsCache, maxSize = MAX_HEADER_BYTES) { // Heartbeats grouped by user agent in the standard format to be sent in // the header. const heartbeatsToSend = []; // Single date format heartbeats that are not sent. let unsentEntries = heartbeatsCache.slice(); for (const singleDateHeartbeat of heartbeatsCache) { // Look for an existing entry with the same user agent. const heartbeatEntry = heartbeatsToSend.find(hb => hb.agent === singleDateHeartbeat.agent); if (!heartbeatEntry) { // If no entry for this user agent exists, create one. heartbeatsToSend.push({ agent: singleDateHeartbeat.agent, dates: [singleDateHeartbeat.date] }); if (countBytes(heartbeatsToSend) > maxSize) { // If the header would exceed max size, remove the added heartbeat // entry and stop adding to the header. heartbeatsToSend.pop(); break; } } else { heartbeatEntry.dates.push(singleDateHeartbeat.date); // If the header would exceed max size, remove the added date // and stop adding to the header. if (countBytes(heartbeatsToSend) > maxSize) { heartbeatEntry.dates.pop(); break; } } // Pop unsent entry from queue. (Skipped if adding the entry exceeded // quota and the loop breaks early.) unsentEntries = unsentEntries.slice(1); } return { heartbeatsToSend, unsentEntries }; } class HeartbeatStorageImpl { constructor(app) { this.app = app; this._canUseIndexedDBPromise = this.runIndexedDBEnvironmentCheck(); } async runIndexedDBEnvironmentCheck() { if (!(0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.isIndexedDBAvailable)()) { return false; } else { return (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.validateIndexedDBOpenable)() .then(() => true) .catch(() => false); } } /** * Read all heartbeats. */ async read() { const canUseIndexedDB = await this._canUseIndexedDBPromise; if (!canUseIndexedDB) { return { heartbeats: [] }; } else { const idbHeartbeatObject = await readHeartbeatsFromIndexedDB(this.app); if (idbHeartbeatObject?.heartbeats) { return idbHeartbeatObject; } else { return { heartbeats: [] }; } } } // overwrite the storage with the provided heartbeats async overwrite(heartbeatsObject) { const canUseIndexedDB = await this._canUseIndexedDBPromise; if (!canUseIndexedDB) { return; } else { const existingHeartbeatsObject = await this.read(); return writeHeartbeatsToIndexedDB(this.app, { lastSentHeartbeatDate: heartbeatsObject.lastSentHeartbeatDate ?? existingHeartbeatsObject.lastSentHeartbeatDate, heartbeats: heartbeatsObject.heartbeats }); } } // add heartbeats async add(heartbeatsObject) { const canUseIndexedDB = await this._canUseIndexedDBPromise; if (!canUseIndexedDB) { return; } else { const existingHeartbeatsObject = await this.read(); return writeHeartbeatsToIndexedDB(this.app, { lastSentHeartbeatDate: heartbeatsObject.lastSentHeartbeatDate ?? existingHeartbeatsObject.lastSentHeartbeatDate, heartbeats: [ ...existingHeartbeatsObject.heartbeats, ...heartbeatsObject.heartbeats ] }); } } } /** * Calculate bytes of a HeartbeatsByUserAgent array after being wrapped * in a platform logging header JSON object, stringified, and converted * to base 64. */ function countBytes(heartbeatsCache) { // base64 has a restricted set of characters, all of which should be 1 byte. return (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.base64urlEncodeWithoutPadding)( // heartbeatsCache wrapper properties JSON.stringify({ version: 2, heartbeats: heartbeatsCache })).length; } /** * Returns the index of the heartbeat with the earliest date. * If the heartbeats array is empty, -1 is returned. */ function getEarliestHeartbeatIdx(heartbeats) { if (heartbeats.length === 0) { return -1; } let earliestHeartbeatIdx = 0; let earliestHeartbeatDate = heartbeats[0].date; for (let i = 1; i < heartbeats.length; i++) { if (heartbeats[i].date < earliestHeartbeatDate) { earliestHeartbeatDate = heartbeats[i].date; earliestHeartbeatIdx = i; } } return earliestHeartbeatIdx; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function registerCoreComponents(variant) { _registerComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component('platform-logger', container => new PlatformLoggerServiceImpl(container), "PRIVATE" /* ComponentType.PRIVATE */)); _registerComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component('heartbeat', container => new HeartbeatServiceImpl(container), "PRIVATE" /* ComponentType.PRIVATE */)); // Register `app` package. registerVersion(name$q, version$1, variant); // BUILD_TARGET will be replaced by values like esm, cjs, etc during the compilation registerVersion(name$q, version$1, 'esm2020'); // Register platform SDK identifier (no version). registerVersion('fire-js', ''); } /** * Firebase App * * @remarks This package coordinates the communication between the different Firebase components * @packageDocumentation */ registerCoreComponents(''); //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./node_modules/@firebase/component/dist/esm/index.esm.js": /*!****************************************************************!*\ !*** ./node_modules/@firebase/component/dist/esm/index.esm.js ***! \****************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Component: function() { return /* binding */ Component; }, /* harmony export */ ComponentContainer: function() { return /* binding */ ComponentContainer; }, /* harmony export */ Provider: function() { return /* binding */ Provider; } /* harmony export */ }); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm.js"); /** * Component for service name T, e.g. `auth`, `auth-internal` */ class Component { /** * * @param name The public service name, e.g. app, auth, firestore, database * @param instanceFactory Service factory responsible for creating the public interface * @param type whether the service provided by the component is public or private */ constructor(name, instanceFactory, type) { this.name = name; this.instanceFactory = instanceFactory; this.type = type; this.multipleInstances = false; /** * Properties to be added to the service namespace */ this.serviceProps = {}; this.instantiationMode = "LAZY" /* InstantiationMode.LAZY */; this.onInstanceCreated = null; } setInstantiationMode(mode) { this.instantiationMode = mode; return this; } setMultipleInstances(multipleInstances) { this.multipleInstances = multipleInstances; return this; } setServiceProps(props) { this.serviceProps = props; return this; } setInstanceCreatedCallback(callback) { this.onInstanceCreated = callback; return this; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DEFAULT_ENTRY_NAME = '[DEFAULT]'; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Provider for instance for service name T, e.g. 'auth', 'auth-internal' * NameServiceMapping[T] is an alias for the type of the instance */ class Provider { constructor(name, container) { this.name = name; this.container = container; this.component = null; this.instances = new Map(); this.instancesDeferred = new Map(); this.instancesOptions = new Map(); this.onInitCallbacks = new Map(); } /** * @param identifier A provider can provide multiple instances of a service * if this.component.multipleInstances is true. */ get(identifier) { // if multipleInstances is not supported, use the default name const normalizedIdentifier = this.normalizeInstanceIdentifier(identifier); if (!this.instancesDeferred.has(normalizedIdentifier)) { const deferred = new _firebase_util__WEBPACK_IMPORTED_MODULE_0__.Deferred(); this.instancesDeferred.set(normalizedIdentifier, deferred); if (this.isInitialized(normalizedIdentifier) || this.shouldAutoInitialize()) { // initialize the service if it can be auto-initialized try { const instance = this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier }); if (instance) { deferred.resolve(instance); } } catch (e) { // when the instance factory throws an exception during get(), it should not cause // a fatal error. We just return the unresolved promise in this case. } } } return this.instancesDeferred.get(normalizedIdentifier).promise; } getImmediate(options) { // if multipleInstances is not supported, use the default name const normalizedIdentifier = this.normalizeInstanceIdentifier(options?.identifier); const optional = options?.optional ?? false; if (this.isInitialized(normalizedIdentifier) || this.shouldAutoInitialize()) { try { return this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier }); } catch (e) { if (optional) { return null; } else { throw e; } } } else { // In case a component is not initialized and should/cannot be auto-initialized at the moment, return null if the optional flag is set, or throw if (optional) { return null; } else { throw Error(`Service ${this.name} is not available`); } } } getComponent() { return this.component; } setComponent(component) { if (component.name !== this.name) { throw Error(`Mismatching Component ${component.name} for Provider ${this.name}.`); } if (this.component) { throw Error(`Component for ${this.name} has already been provided`); } this.component = component; // return early without attempting to initialize the component if the component requires explicit initialization (calling `Provider.initialize()`) if (!this.shouldAutoInitialize()) { return; } // if the service is eager, initialize the default instance if (isComponentEager(component)) { try { this.getOrInitializeService({ instanceIdentifier: DEFAULT_ENTRY_NAME }); } catch (e) { // when the instance factory for an eager Component throws an exception during the eager // initialization, it should not cause a fatal error. // TODO: Investigate if we need to make it configurable, because some component may want to cause // a fatal error in this case? } } // Create service instances for the pending promises and resolve them // NOTE: if this.multipleInstances is false, only the default instance will be created // and all promises with resolve with it regardless of the identifier. for (const [instanceIdentifier, instanceDeferred] of this.instancesDeferred.entries()) { const normalizedIdentifier = this.normalizeInstanceIdentifier(instanceIdentifier); try { // `getOrInitializeService()` should always return a valid instance since a component is guaranteed. use ! to make typescript happy. const instance = this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier }); instanceDeferred.resolve(instance); } catch (e) { // when the instance factory throws an exception, it should not cause // a fatal error. We just leave the promise unresolved. } } } clearInstance(identifier = DEFAULT_ENTRY_NAME) { this.instancesDeferred.delete(identifier); this.instancesOptions.delete(identifier); this.instances.delete(identifier); } // app.delete() will call this method on every provider to delete the services // TODO: should we mark the provider as deleted? async delete() { const services = Array.from(this.instances.values()); await Promise.all([ ...services .filter(service => 'INTERNAL' in service) // legacy services // eslint-disable-next-line @typescript-eslint/no-explicit-any .map(service => service.INTERNAL.delete()), ...services .filter(service => '_delete' in service) // modularized services // eslint-disable-next-line @typescript-eslint/no-explicit-any .map(service => service._delete()) ]); } isComponentSet() { return this.component != null; } isInitialized(identifier = DEFAULT_ENTRY_NAME) { return this.instances.has(identifier); } getOptions(identifier = DEFAULT_ENTRY_NAME) { return this.instancesOptions.get(identifier) || {}; } initialize(opts = {}) { const { options = {} } = opts; const normalizedIdentifier = this.normalizeInstanceIdentifier(opts.instanceIdentifier); if (this.isInitialized(normalizedIdentifier)) { throw Error(`${this.name}(${normalizedIdentifier}) has already been initialized`); } if (!this.isComponentSet()) { throw Error(`Component ${this.name} has not been registered yet`); } const instance = this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier, options }); // resolve any pending promise waiting for the service instance for (const [instanceIdentifier, instanceDeferred] of this.instancesDeferred.entries()) { const normalizedDeferredIdentifier = this.normalizeInstanceIdentifier(instanceIdentifier); if (normalizedIdentifier === normalizedDeferredIdentifier) { instanceDeferred.resolve(instance); } } return instance; } /** * * @param callback - a function that will be invoked after the provider has been initialized by calling provider.initialize(). * The function is invoked SYNCHRONOUSLY, so it should not execute any longrunning tasks in order to not block the program. * * @param identifier An optional instance identifier * @returns a function to unregister the callback */ onInit(callback, identifier) { const normalizedIdentifier = this.normalizeInstanceIdentifier(identifier); const existingCallbacks = this.onInitCallbacks.get(normalizedIdentifier) ?? new Set(); existingCallbacks.add(callback); this.onInitCallbacks.set(normalizedIdentifier, existingCallbacks); const existingInstance = this.instances.get(normalizedIdentifier); if (existingInstance) { callback(existingInstance, normalizedIdentifier); } return () => { existingCallbacks.delete(callback); }; } /** * Invoke onInit callbacks synchronously * @param instance the service instance` */ invokeOnInitCallbacks(instance, identifier) { const callbacks = this.onInitCallbacks.get(identifier); if (!callbacks) { return; } for (const callback of callbacks) { try { callback(instance, identifier); } catch { // ignore errors in the onInit callback } } } getOrInitializeService({ instanceIdentifier, options = {} }) { let instance = this.instances.get(instanceIdentifier); if (!instance && this.component) { instance = this.component.instanceFactory(this.container, { instanceIdentifier: normalizeIdentifierForFactory(instanceIdentifier), options }); this.instances.set(instanceIdentifier, instance); this.instancesOptions.set(instanceIdentifier, options); /** * Invoke onInit listeners. * Note this.component.onInstanceCreated is different, which is used by the component creator, * while onInit listeners are registered by consumers of the provider. */ this.invokeOnInitCallbacks(instance, instanceIdentifier); /** * Order is important * onInstanceCreated() should be called after this.instances.set(instanceIdentifier, instance); which * makes `isInitialized()` return true. */ if (this.component.onInstanceCreated) { try { this.component.onInstanceCreated(this.container, instanceIdentifier, instance); } catch { // ignore errors in the onInstanceCreatedCallback } } } return instance || null; } normalizeInstanceIdentifier(identifier = DEFAULT_ENTRY_NAME) { if (this.component) { return this.component.multipleInstances ? identifier : DEFAULT_ENTRY_NAME; } else { return identifier; // assume multiple instances are supported before the component is provided. } } shouldAutoInitialize() { return (!!this.component && this.component.instantiationMode !== "EXPLICIT" /* InstantiationMode.EXPLICIT */); } } // undefined should be passed to the service factory for the default instance function normalizeIdentifierForFactory(identifier) { return identifier === DEFAULT_ENTRY_NAME ? undefined : identifier; } function isComponentEager(component) { return component.instantiationMode === "EAGER" /* InstantiationMode.EAGER */; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * ComponentContainer that provides Providers for service name T, e.g. `auth`, `auth-internal` */ class ComponentContainer { constructor(name) { this.name = name; this.providers = new Map(); } /** * * @param component Component being added * @param overwrite When a component with the same name has already been registered, * if overwrite is true: overwrite the existing component with the new component and create a new * provider with the new component. It can be useful in tests where you want to use different mocks * for different tests. * if overwrite is false: throw an exception */ addComponent(component) { const provider = this.getProvider(component.name); if (provider.isComponentSet()) { throw new Error(`Component ${component.name} has already been registered with ${this.name}`); } provider.setComponent(component); } addOrOverwriteComponent(component) { const provider = this.getProvider(component.name); if (provider.isComponentSet()) { // delete the existing provider from the container, so we can register the new component this.providers.delete(component.name); } this.addComponent(component); } /** * getProvider provides a type safe interface where it can only be called with a field name * present in NameServiceMapping interface. * * Firebase SDKs providing services should extend NameServiceMapping interface to register * themselves. */ getProvider(name) { if (this.providers.has(name)) { return this.providers.get(name); } // create a Provider for a service that hasn't registered with Firebase const provider = new Provider(name, this); this.providers.set(name, provider); return provider; } getProviders() { return Array.from(this.providers.values()); } } //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./node_modules/@firebase/installations/dist/esm/index.esm.js": /*!********************************************************************!*\ !*** ./node_modules/@firebase/installations/dist/esm/index.esm.js ***! \********************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ deleteInstallations: function() { return /* binding */ deleteInstallations; }, /* harmony export */ getId: function() { return /* binding */ getId; }, /* harmony export */ getInstallations: function() { return /* binding */ getInstallations; }, /* harmony export */ getToken: function() { return /* binding */ getToken; }, /* harmony export */ onIdChange: function() { return /* binding */ onIdChange; } /* harmony export */ }); /* harmony import */ var _firebase_app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/app */ "./node_modules/@firebase/app/dist/esm/index.esm.js"); /* harmony import */ var _firebase_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @firebase/component */ "./node_modules/@firebase/component/dist/esm/index.esm.js"); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm.js"); /* harmony import */ var idb__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! idb */ "./node_modules/idb/build/index.js"); const name = "@firebase/installations"; const version = "0.6.22"; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const PENDING_TIMEOUT_MS = 10000; const PACKAGE_VERSION = `w:${version}`; const INTERNAL_AUTH_VERSION = 'FIS_v2'; const INSTALLATIONS_API_URL = 'https://firebaseinstallations.googleapis.com/v1'; const TOKEN_EXPIRATION_BUFFER = 60 * 60 * 1000; // One hour const SERVICE = 'installations'; const SERVICE_NAME = 'Installations'; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const ERROR_DESCRIPTION_MAP = { ["missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"', ["not-registered" /* ErrorCode.NOT_REGISTERED */]: 'Firebase Installation is not registered.', ["installation-not-found" /* ErrorCode.INSTALLATION_NOT_FOUND */]: 'Firebase Installation not found.', ["request-failed" /* ErrorCode.REQUEST_FAILED */]: '{$requestName} request failed with error "{$serverCode} {$serverStatus}: {$serverMessage}"', ["app-offline" /* ErrorCode.APP_OFFLINE */]: 'Could not process request. Application offline.', ["delete-pending-registration" /* ErrorCode.DELETE_PENDING_REGISTRATION */]: "Can't delete installation while there is a pending registration request." }; const ERROR_FACTORY = new _firebase_util__WEBPACK_IMPORTED_MODULE_2__.ErrorFactory(SERVICE, SERVICE_NAME, ERROR_DESCRIPTION_MAP); /** Returns true if error is a FirebaseError that is based on an error from the server. */ function isServerError(error) { return (error instanceof _firebase_util__WEBPACK_IMPORTED_MODULE_2__.FirebaseError && error.code.includes("request-failed" /* ErrorCode.REQUEST_FAILED */)); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function getInstallationsEndpoint({ projectId }) { return `${INSTALLATIONS_API_URL}/projects/${projectId}/installations`; } function extractAuthTokenInfoFromResponse(response) { return { token: response.token, requestStatus: 2 /* RequestStatus.COMPLETED */, expiresIn: getExpiresInFromResponseExpiresIn(response.expiresIn), creationTime: Date.now() }; } async function getErrorFromResponse(requestName, response) { const responseJson = await response.json(); const errorData = responseJson.error; return ERROR_FACTORY.create("request-failed" /* ErrorCode.REQUEST_FAILED */, { requestName, serverCode: errorData.code, serverMessage: errorData.message, serverStatus: errorData.status }); } function getHeaders({ apiKey }) { return new Headers({ 'Content-Type': 'application/json', Accept: 'application/json', 'x-goog-api-key': apiKey }); } function getHeadersWithAuth(appConfig, { refreshToken }) { const headers = getHeaders(appConfig); headers.append('Authorization', getAuthorizationHeader(refreshToken)); return headers; } /** * Calls the passed in fetch wrapper and returns the response. * If the returned response has a status of 5xx, re-runs the function once and * returns the response. */ async function retryIfServerError(fn) { const result = await fn(); if (result.status >= 500 && result.status < 600) { // Internal Server Error. Retry request. return fn(); } return result; } function getExpiresInFromResponseExpiresIn(responseExpiresIn) { // This works because the server will never respond with fractions of a second. return Number(responseExpiresIn.replace('s', '000')); } function getAuthorizationHeader(refreshToken) { return `${INTERNAL_AUTH_VERSION} ${refreshToken}`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function createInstallationRequest({ appConfig, heartbeatServiceProvider }, { fid }) { const endpoint = getInstallationsEndpoint(appConfig); const headers = getHeaders(appConfig); // If heartbeat service exists, add the heartbeat string to the header. const heartbeatService = heartbeatServiceProvider.getImmediate({ optional: true }); if (heartbeatService) { const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader(); if (heartbeatsHeader) { headers.append('x-firebase-client', heartbeatsHeader); } } const body = { fid, authVersion: INTERNAL_AUTH_VERSION, appId: appConfig.appId, sdkVersion: PACKAGE_VERSION }; const request = { method: 'POST', headers, body: JSON.stringify(body) }; const response = await retryIfServerError(() => fetch(endpoint, request)); if (response.ok) { const responseValue = await response.json(); const registeredInstallationEntry = { fid: responseValue.fid || fid, registrationStatus: 2 /* RequestStatus.COMPLETED */, refreshToken: responseValue.refreshToken, authToken: extractAuthTokenInfoFromResponse(responseValue.authToken) }; return registeredInstallationEntry; } else { throw await getErrorFromResponse('Create Installation', response); } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** Returns a promise that resolves after given time passes. */ function sleep(ms) { return new Promise(resolve => { setTimeout(resolve, ms); }); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function bufferToBase64UrlSafe(array) { const b64 = btoa(String.fromCharCode(...array)); return b64.replace(/\+/g, '-').replace(/\//g, '_'); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const VALID_FID_PATTERN = /^[cdef][\w-]{21}$/; const INVALID_FID = ''; /** * Generates a new FID using random values from Web Crypto API. * Returns an empty string if FID generation fails for any reason. */ function generateFid() { try { // A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5 // bytes. our implementation generates a 17 byte array instead. const fidByteArray = new Uint8Array(17); const crypto = self.crypto || self.msCrypto; crypto.getRandomValues(fidByteArray); // Replace the first 4 random bits with the constant FID header of 0b0111. fidByteArray[0] = 0b01110000 + (fidByteArray[0] % 0b00010000); const fid = encode(fidByteArray); return VALID_FID_PATTERN.test(fid) ? fid : INVALID_FID; } catch { // FID generation errored return INVALID_FID; } } /** Converts a FID Uint8Array to a base64 string representation. */ function encode(fidByteArray) { const b64String = bufferToBase64UrlSafe(fidByteArray); // Remove the 23rd character that was added because of the extra 4 bits at the // end of our 17 byte array, and the '=' padding. return b64String.substr(0, 22); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** Returns a string key that can be used to identify the app. */ function getKey(appConfig) { return `${appConfig.appName}!${appConfig.appId}`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const fidChangeCallbacks = new Map(); /** * Calls the onIdChange callbacks with the new FID value, and broadcasts the * change to other tabs. */ function fidChanged(appConfig, fid) { const key = getKey(appConfig); callFidChangeCallbacks(key, fid); broadcastFidChange(key, fid); } function addCallback(appConfig, callback) { // Open the broadcast channel if it's not already open, // to be able to listen to change events from other tabs. getBroadcastChannel(); const key = getKey(appConfig); let callbackSet = fidChangeCallbacks.get(key); if (!callbackSet) { callbackSet = new Set(); fidChangeCallbacks.set(key, callbackSet); } callbackSet.add(callback); } function removeCallback(appConfig, callback) { const key = getKey(appConfig); const callbackSet = fidChangeCallbacks.get(key); if (!callbackSet) { return; } callbackSet.delete(callback); if (callbackSet.size === 0) { fidChangeCallbacks.delete(key); } // Close broadcast channel if there are no more callbacks. closeBroadcastChannel(); } function callFidChangeCallbacks(key, fid) { const callbacks = fidChangeCallbacks.get(key); if (!callbacks) { return; } for (const callback of callbacks) { callback(fid); } } function broadcastFidChange(key, fid) { const channel = getBroadcastChannel(); if (channel) { channel.postMessage({ key, fid }); } closeBroadcastChannel(); } let broadcastChannel = null; /** Opens and returns a BroadcastChannel if it is supported by the browser. */ function getBroadcastChannel() { if (!broadcastChannel && 'BroadcastChannel' in self) { broadcastChannel = new BroadcastChannel('[Firebase] FID Change'); broadcastChannel.onmessage = e => { callFidChangeCallbacks(e.data.key, e.data.fid); }; } return broadcastChannel; } function closeBroadcastChannel() { if (fidChangeCallbacks.size === 0 && broadcastChannel) { broadcastChannel.close(); broadcastChannel = null; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DATABASE_NAME = 'firebase-installations-database'; const DATABASE_VERSION = 1; const OBJECT_STORE_NAME = 'firebase-installations-store'; let dbPromise = null; function getDbPromise() { if (!dbPromise) { dbPromise = (0,idb__WEBPACK_IMPORTED_MODULE_3__.openDB)(DATABASE_NAME, DATABASE_VERSION, { upgrade: (db, oldVersion) => { // We don't use 'break' in this switch statement, the fall-through // behavior is what we want, because if there are multiple versions between // the old version and the current version, we want ALL the migrations // that correspond to those versions to run, not only the last one. // eslint-disable-next-line default-case switch (oldVersion) { case 0: db.createObjectStore(OBJECT_STORE_NAME); } } }); } return dbPromise; } /** Assigns or overwrites the record for the given key with the given value. */ async function set(appConfig, value) { const key = getKey(appConfig); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); const objectStore = tx.objectStore(OBJECT_STORE_NAME); const oldValue = (await objectStore.get(key)); await objectStore.put(value, key); await tx.done; if (!oldValue || oldValue.fid !== value.fid) { fidChanged(appConfig, value.fid); } return value; } /** Removes record(s) from the objectStore that match the given key. */ async function remove(appConfig) { const key = getKey(appConfig); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(OBJECT_STORE_NAME).delete(key); await tx.done; } /** * Atomically updates a record with the result of updateFn, which gets * called with the current value. If newValue is undefined, the record is * deleted instead. * @return Updated value */ async function update(appConfig, updateFn) { const key = getKey(appConfig); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); const store = tx.objectStore(OBJECT_STORE_NAME); const oldValue = (await store.get(key)); const newValue = updateFn(oldValue); if (newValue === undefined) { await store.delete(key); } else { await store.put(newValue, key); } await tx.done; if (newValue && (!oldValue || oldValue.fid !== newValue.fid)) { fidChanged(appConfig, newValue.fid); } return newValue; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Updates and returns the InstallationEntry from the database. * Also triggers a registration request if it is necessary and possible. */ async function getInstallationEntry(installations) { let registrationPromise; const installationEntry = await update(installations.appConfig, oldEntry => { const installationEntry = updateOrCreateInstallationEntry(oldEntry); const entryWithPromise = triggerRegistrationIfNecessary(installations, installationEntry); registrationPromise = entryWithPromise.registrationPromise; return entryWithPromise.installationEntry; }); if (installationEntry.fid === INVALID_FID) { // FID generation failed. Waiting for the FID from the server. return { installationEntry: await registrationPromise }; } return { installationEntry, registrationPromise }; } /** * Creates a new Installation Entry if one does not exist. * Also clears timed out pending requests. */ function updateOrCreateInstallationEntry(oldEntry) { const entry = oldEntry || { fid: generateFid(), registrationStatus: 0 /* RequestStatus.NOT_STARTED */ }; return clearTimedOutRequest(entry); } /** * If the Firebase Installation is not registered yet, this will trigger the * registration and return an InProgressInstallationEntry. * * If registrationPromise does not exist, the installationEntry is guaranteed * to be registered. */ function triggerRegistrationIfNecessary(installations, installationEntry) { if (installationEntry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) { if (!navigator.onLine) { // Registration required but app is offline. const registrationPromiseWithError = Promise.reject(ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */)); return { installationEntry, registrationPromise: registrationPromiseWithError }; } // Try registering. Change status to IN_PROGRESS. const inProgressEntry = { fid: installationEntry.fid, registrationStatus: 1 /* RequestStatus.IN_PROGRESS */, registrationTime: Date.now() }; const registrationPromise = registerInstallation(installations, inProgressEntry); return { installationEntry: inProgressEntry, registrationPromise }; } else if (installationEntry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) { return { installationEntry, registrationPromise: waitUntilFidRegistration(installations) }; } else { return { installationEntry }; } } /** This will be executed only once for each new Firebase Installation. */ async function registerInstallation(installations, installationEntry) { try { const registeredInstallationEntry = await createInstallationRequest(installations, installationEntry); return set(installations.appConfig, registeredInstallationEntry); } catch (e) { if (isServerError(e) && e.customData.serverCode === 409) { // Server returned a "FID cannot be used" error. // Generate a new ID next time. await remove(installations.appConfig); } else { // Registration failed. Set FID as not registered. await set(installations.appConfig, { fid: installationEntry.fid, registrationStatus: 0 /* RequestStatus.NOT_STARTED */ }); } throw e; } } /** Call if FID registration is pending in another request. */ async function waitUntilFidRegistration(installations) { // Unfortunately, there is no way of reliably observing when a value in // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers), // so we need to poll. let entry = await updateInstallationRequest(installations.appConfig); while (entry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) { // createInstallation request still in progress. await sleep(100); entry = await updateInstallationRequest(installations.appConfig); } if (entry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) { // The request timed out or failed in a different call. Try again. const { installationEntry, registrationPromise } = await getInstallationEntry(installations); if (registrationPromise) { return registrationPromise; } else { // if there is no registrationPromise, entry is registered. return installationEntry; } } return entry; } /** * Called only if there is a CreateInstallation request in progress. * * Updates the InstallationEntry in the DB based on the status of the * CreateInstallation request. * * Returns the updated InstallationEntry. */ function updateInstallationRequest(appConfig) { return update(appConfig, oldEntry => { if (!oldEntry) { throw ERROR_FACTORY.create("installation-not-found" /* ErrorCode.INSTALLATION_NOT_FOUND */); } return clearTimedOutRequest(oldEntry); }); } function clearTimedOutRequest(entry) { if (hasInstallationRequestTimedOut(entry)) { return { fid: entry.fid, registrationStatus: 0 /* RequestStatus.NOT_STARTED */ }; } return entry; } function hasInstallationRequestTimedOut(installationEntry) { return (installationEntry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */ && installationEntry.registrationTime + PENDING_TIMEOUT_MS < Date.now()); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function generateAuthTokenRequest({ appConfig, heartbeatServiceProvider }, installationEntry) { const endpoint = getGenerateAuthTokenEndpoint(appConfig, installationEntry); const headers = getHeadersWithAuth(appConfig, installationEntry); // If heartbeat service exists, add the heartbeat string to the header. const heartbeatService = heartbeatServiceProvider.getImmediate({ optional: true }); if (heartbeatService) { const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader(); if (heartbeatsHeader) { headers.append('x-firebase-client', heartbeatsHeader); } } const body = { installation: { sdkVersion: PACKAGE_VERSION, appId: appConfig.appId } }; const request = { method: 'POST', headers, body: JSON.stringify(body) }; const response = await retryIfServerError(() => fetch(endpoint, request)); if (response.ok) { const responseValue = await response.json(); const completedAuthToken = extractAuthTokenInfoFromResponse(responseValue); return completedAuthToken; } else { throw await getErrorFromResponse('Generate Auth Token', response); } } function getGenerateAuthTokenEndpoint(appConfig, { fid }) { return `${getInstallationsEndpoint(appConfig)}/${fid}/authTokens:generate`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns a valid authentication token for the installation. Generates a new * token if one doesn't exist, is expired or about to expire. * * Should only be called if the Firebase Installation is registered. */ async function refreshAuthToken(installations, forceRefresh = false) { let tokenPromise; const entry = await update(installations.appConfig, oldEntry => { if (!isEntryRegistered(oldEntry)) { throw ERROR_FACTORY.create("not-registered" /* ErrorCode.NOT_REGISTERED */); } const oldAuthToken = oldEntry.authToken; if (!forceRefresh && isAuthTokenValid(oldAuthToken)) { // There is a valid token in the DB. return oldEntry; } else if (oldAuthToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */) { // There already is a token request in progress. tokenPromise = waitUntilAuthTokenRequest(installations, forceRefresh); return oldEntry; } else { // No token or token expired. if (!navigator.onLine) { throw ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */); } const inProgressEntry = makeAuthTokenRequestInProgressEntry(oldEntry); tokenPromise = fetchAuthTokenFromServer(installations, inProgressEntry); return inProgressEntry; } }); const authToken = tokenPromise ? await tokenPromise : entry.authToken; return authToken; } /** * Call only if FID is registered and Auth Token request is in progress. * * Waits until the current pending request finishes. If the request times out, * tries once in this thread as well. */ async function waitUntilAuthTokenRequest(installations, forceRefresh) { // Unfortunately, there is no way of reliably observing when a value in // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers), // so we need to poll. let entry = await updateAuthTokenRequest(installations.appConfig); while (entry.authToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */) { // generateAuthToken still in progress. await sleep(100); entry = await updateAuthTokenRequest(installations.appConfig); } const authToken = entry.authToken; if (authToken.requestStatus === 0 /* RequestStatus.NOT_STARTED */) { // The request timed out or failed in a different call. Try again. return refreshAuthToken(installations, forceRefresh); } else { return authToken; } } /** * Called only if there is a GenerateAuthToken request in progress. * * Updates the InstallationEntry in the DB based on the status of the * GenerateAuthToken request. * * Returns the updated InstallationEntry. */ function updateAuthTokenRequest(appConfig) { return update(appConfig, oldEntry => { if (!isEntryRegistered(oldEntry)) { throw ERROR_FACTORY.create("not-registered" /* ErrorCode.NOT_REGISTERED */); } const oldAuthToken = oldEntry.authToken; if (hasAuthTokenRequestTimedOut(oldAuthToken)) { return { ...oldEntry, authToken: { requestStatus: 0 /* RequestStatus.NOT_STARTED */ } }; } return oldEntry; }); } async function fetchAuthTokenFromServer(installations, installationEntry) { try { const authToken = await generateAuthTokenRequest(installations, installationEntry); const updatedInstallationEntry = { ...installationEntry, authToken }; await set(installations.appConfig, updatedInstallationEntry); return authToken; } catch (e) { if (isServerError(e) && (e.customData.serverCode === 401 || e.customData.serverCode === 404)) { // Server returned a "FID not found" or a "Invalid authentication" error. // Generate a new ID next time. await remove(installations.appConfig); } else { const updatedInstallationEntry = { ...installationEntry, authToken: { requestStatus: 0 /* RequestStatus.NOT_STARTED */ } }; await set(installations.appConfig, updatedInstallationEntry); } throw e; } } function isEntryRegistered(installationEntry) { return (installationEntry !== undefined && installationEntry.registrationStatus === 2 /* RequestStatus.COMPLETED */); } function isAuthTokenValid(authToken) { return (authToken.requestStatus === 2 /* RequestStatus.COMPLETED */ && !isAuthTokenExpired(authToken)); } function isAuthTokenExpired(authToken) { const now = Date.now(); return (now < authToken.creationTime || authToken.creationTime + authToken.expiresIn < now + TOKEN_EXPIRATION_BUFFER); } /** Returns an updated InstallationEntry with an InProgressAuthToken. */ function makeAuthTokenRequestInProgressEntry(oldEntry) { const inProgressAuthToken = { requestStatus: 1 /* RequestStatus.IN_PROGRESS */, requestTime: Date.now() }; return { ...oldEntry, authToken: inProgressAuthToken }; } function hasAuthTokenRequestTimedOut(authToken) { return (authToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */ && authToken.requestTime + PENDING_TIMEOUT_MS < Date.now()); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Creates a Firebase Installation if there isn't one for the app and * returns the Installation ID. * @param installations - The `Installations` instance. * * @public */ async function getId(installations) { const installationsImpl = installations; const { installationEntry, registrationPromise } = await getInstallationEntry(installationsImpl); if (registrationPromise) { registrationPromise.catch(console.error); } else { // If the installation is already registered, update the authentication // token if needed. refreshAuthToken(installationsImpl).catch(console.error); } return installationEntry.fid; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns a Firebase Installations auth token, identifying the current * Firebase Installation. * @param installations - The `Installations` instance. * @param forceRefresh - Force refresh regardless of token expiration. * * @public */ async function getToken(installations, forceRefresh = false) { const installationsImpl = installations; await completeInstallationRegistration(installationsImpl); // At this point we either have a Registered Installation in the DB, or we've // already thrown an error. const authToken = await refreshAuthToken(installationsImpl, forceRefresh); return authToken.token; } async function completeInstallationRegistration(installations) { const { registrationPromise } = await getInstallationEntry(installations); if (registrationPromise) { // A createInstallation request is in progress. Wait until it finishes. await registrationPromise; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function deleteInstallationRequest(appConfig, installationEntry) { const endpoint = getDeleteEndpoint(appConfig, installationEntry); const headers = getHeadersWithAuth(appConfig, installationEntry); const request = { method: 'DELETE', headers }; const response = await retryIfServerError(() => fetch(endpoint, request)); if (!response.ok) { throw await getErrorFromResponse('Delete Installation', response); } } function getDeleteEndpoint(appConfig, { fid }) { return `${getInstallationsEndpoint(appConfig)}/${fid}`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Deletes the Firebase Installation and all associated data. * @param installations - The `Installations` instance. * * @public */ async function deleteInstallations(installations) { const { appConfig } = installations; const entry = await update(appConfig, oldEntry => { if (oldEntry && oldEntry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) { // Delete the unregistered entry without sending a deleteInstallation request. return undefined; } return oldEntry; }); if (entry) { if (entry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) { // Can't delete while trying to register. throw ERROR_FACTORY.create("delete-pending-registration" /* ErrorCode.DELETE_PENDING_REGISTRATION */); } else if (entry.registrationStatus === 2 /* RequestStatus.COMPLETED */) { if (!navigator.onLine) { throw ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */); } else { await deleteInstallationRequest(appConfig, entry); await remove(appConfig); } } } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Sets a new callback that will get called when Installation ID changes. * Returns an unsubscribe function that will remove the callback when called. * @param installations - The `Installations` instance. * @param callback - The callback function that is invoked when FID changes. * @returns A function that can be called to unsubscribe. * * @public */ function onIdChange(installations, callback) { const { appConfig } = installations; addCallback(appConfig, callback); return () => { removeCallback(appConfig, callback); }; } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns an instance of {@link Installations} associated with the given * {@link @firebase/app#FirebaseApp} instance. * @param app - The {@link @firebase/app#FirebaseApp} instance. * * @public */ function getInstallations(app = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.getApp)()) { const installationsImpl = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider)(app, 'installations').getImmediate(); return installationsImpl; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function extractAppConfig(app) { if (!app || !app.options) { throw getMissingValueError('App Configuration'); } if (!app.name) { throw getMissingValueError('App Name'); } // Required app config keys const configKeys = [ 'projectId', 'apiKey', 'appId' ]; for (const keyName of configKeys) { if (!app.options[keyName]) { throw getMissingValueError(keyName); } } return { appName: app.name, projectId: app.options.projectId, apiKey: app.options.apiKey, appId: app.options.appId }; } function getMissingValueError(valueName) { return ERROR_FACTORY.create("missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */, { valueName }); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const INSTALLATIONS_NAME = 'installations'; const INSTALLATIONS_NAME_INTERNAL = 'installations-internal'; const publicFactory = (container) => { const app = container.getProvider('app').getImmediate(); // Throws if app isn't configured properly. const appConfig = extractAppConfig(app); const heartbeatServiceProvider = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider)(app, 'heartbeat'); const installationsImpl = { app, appConfig, heartbeatServiceProvider, _delete: () => Promise.resolve() }; return installationsImpl; }; const internalFactory = (container) => { const app = container.getProvider('app').getImmediate(); // Internal FIS instance relies on public FIS instance. const installations = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider)(app, INSTALLATIONS_NAME).getImmediate(); const installationsInternal = { getId: () => getId(installations), getToken: (forceRefresh) => getToken(installations, forceRefresh) }; return installationsInternal; }; function registerInstallations() { (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component(INSTALLATIONS_NAME, publicFactory, "PUBLIC" /* ComponentType.PUBLIC */)); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component(INSTALLATIONS_NAME_INTERNAL, internalFactory, "PRIVATE" /* ComponentType.PRIVATE */)); } /** * The Firebase Installations Web SDK. * This SDK does not work in a Node.js environment. * * @packageDocumentation */ registerInstallations(); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion)(name, version); // BUILD_TARGET will be replaced by values like esm, cjs, etc during the compilation (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion)(name, version, 'esm2020'); //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./node_modules/@firebase/logger/dist/esm/index.esm.js": /*!*************************************************************!*\ !*** ./node_modules/@firebase/logger/dist/esm/index.esm.js ***! \*************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LogLevel: function() { return /* binding */ LogLevel; }, /* harmony export */ Logger: function() { return /* binding */ Logger; }, /* harmony export */ setLogLevel: function() { return /* binding */ setLogLevel; }, /* harmony export */ setUserLogHandler: function() { return /* binding */ setUserLogHandler; } /* harmony export */ }); /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A container for all of the Logger instances */ const instances = []; /** * The JS SDK supports 5 log levels and also allows a user the ability to * silence the logs altogether. * * The order is a follows: * DEBUG < VERBOSE < INFO < WARN < ERROR * * All of the log types above the current log level will be captured (i.e. if * you set the log level to `INFO`, errors will still be logged, but `DEBUG` and * `VERBOSE` logs will not) */ var LogLevel; (function (LogLevel) { LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG"; LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; LogLevel[LogLevel["INFO"] = 2] = "INFO"; LogLevel[LogLevel["WARN"] = 3] = "WARN"; LogLevel[LogLevel["ERROR"] = 4] = "ERROR"; LogLevel[LogLevel["SILENT"] = 5] = "SILENT"; })(LogLevel || (LogLevel = {})); const levelStringToEnum = { 'debug': LogLevel.DEBUG, 'verbose': LogLevel.VERBOSE, 'info': LogLevel.INFO, 'warn': LogLevel.WARN, 'error': LogLevel.ERROR, 'silent': LogLevel.SILENT }; /** * The default log level */ const defaultLogLevel = LogLevel.INFO; /** * By default, `console.debug` is not displayed in the developer console (in * chrome). To avoid forcing users to have to opt-in to these logs twice * (i.e. once for firebase, and once in the console), we are sending `DEBUG` * logs to the `console.log` function. */ const ConsoleMethod = { [LogLevel.DEBUG]: 'log', [LogLevel.VERBOSE]: 'log', [LogLevel.INFO]: 'info', [LogLevel.WARN]: 'warn', [LogLevel.ERROR]: 'error' }; /** * The default log handler will forward DEBUG, VERBOSE, INFO, WARN, and ERROR * messages on to their corresponding console counterparts (if the log method * is supported by the current log level) */ const defaultLogHandler = (instance, logType, ...args) => { if (logType < instance.logLevel) { return; } const now = new Date().toISOString(); const method = ConsoleMethod[logType]; if (method) { console[method](`[${now}] ${instance.name}:`, ...args); } else { throw new Error(`Attempted to log a message with an invalid logType (value: ${logType})`); } }; class Logger { /** * Gives you an instance of a Logger to capture messages according to * Firebase's logging scheme. * * @param name The name that the logs will be associated with */ constructor(name) { this.name = name; /** * The log level of the given Logger instance. */ this._logLevel = defaultLogLevel; /** * The main (internal) log handler for the Logger instance. * Can be set to a new function in internal package code but not by user. */ this._logHandler = defaultLogHandler; /** * The optional, additional, user-defined log handler for the Logger instance. */ this._userLogHandler = null; /** * Capture the current instance for later use */ instances.push(this); } get logLevel() { return this._logLevel; } set logLevel(val) { if (!(val in LogLevel)) { throw new TypeError(`Invalid value "${val}" assigned to \`logLevel\``); } this._logLevel = val; } // Workaround for setter/getter having to be the same type. setLogLevel(val) { this._logLevel = typeof val === 'string' ? levelStringToEnum[val] : val; } get logHandler() { return this._logHandler; } set logHandler(val) { if (typeof val !== 'function') { throw new TypeError('Value assigned to `logHandler` must be a function'); } this._logHandler = val; } get userLogHandler() { return this._userLogHandler; } set userLogHandler(val) { this._userLogHandler = val; } /** * The functions below are all based on the `console` interface */ debug(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.DEBUG, ...args); this._logHandler(this, LogLevel.DEBUG, ...args); } log(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.VERBOSE, ...args); this._logHandler(this, LogLevel.VERBOSE, ...args); } info(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.INFO, ...args); this._logHandler(this, LogLevel.INFO, ...args); } warn(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.WARN, ...args); this._logHandler(this, LogLevel.WARN, ...args); } error(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.ERROR, ...args); this._logHandler(this, LogLevel.ERROR, ...args); } } function setLogLevel(level) { instances.forEach(inst => { inst.setLogLevel(level); }); } function setUserLogHandler(logCallback, options) { for (const instance of instances) { let customLogLevel = null; if (options && options.level) { customLogLevel = levelStringToEnum[options.level]; } if (logCallback === null) { instance.userLogHandler = null; } else { instance.userLogHandler = (instance, level, ...args) => { const message = args .map(arg => { if (arg == null) { return null; } else if (typeof arg === 'string') { return arg; } else if (typeof arg === 'number' || typeof arg === 'boolean') { return arg.toString(); } else if (arg instanceof Error) { return arg.message; } else { try { return JSON.stringify(arg); } catch (ignored) { return null; } } }) .filter(arg => arg) .join(' '); if (level >= (customLogLevel ?? instance.logLevel)) { logCallback({ level: LogLevel[level].toLowerCase(), message, args, type: instance.name }); } }; } } } //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./node_modules/@firebase/messaging/dist/esm/index.esm.js": /*!****************************************************************!*\ !*** ./node_modules/@firebase/messaging/dist/esm/index.esm.js ***! \****************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ deleteToken: function() { return /* binding */ deleteToken; }, /* harmony export */ getMessaging: function() { return /* binding */ getMessagingInWindow; }, /* harmony export */ getToken: function() { return /* binding */ getToken; }, /* harmony export */ isSupported: function() { return /* binding */ isWindowSupported; }, /* harmony export */ onMessage: function() { return /* binding */ onMessage; }, /* harmony export */ onRegistered: function() { return /* binding */ onRegistered; }, /* harmony export */ onUnregistered: function() { return /* binding */ onUnregistered; }, /* harmony export */ register: function() { return /* binding */ register; }, /* harmony export */ unregister: function() { return /* binding */ unregister; } /* harmony export */ }); /* harmony import */ var _firebase_installations__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/installations */ "./node_modules/@firebase/installations/dist/esm/index.esm.js"); /* harmony import */ var _firebase_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @firebase/component */ "./node_modules/@firebase/component/dist/esm/index.esm.js"); /* harmony import */ var idb__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! idb */ "./node_modules/idb/build/index.js"); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm.js"); /* harmony import */ var _firebase_app__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @firebase/app */ "./node_modules/@firebase/app/dist/esm/index.esm.js"); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DEFAULT_SW_PATH = '/firebase-messaging-sw.js'; const DEFAULT_SW_SCOPE = '/firebase-cloud-messaging-push-scope'; const DEFAULT_VAPID_KEY = 'BDOU99-h67HcA6JeFXHbSNMu7e2yNNu3RzoMj8TM4W88jITfq7ZmPvIM1Iv-4_l2LxQcYwhqby2xGpWwzjfAnG4'; const ENDPOINT = 'https://fcmregistrations.googleapis.com/v1'; const CONSOLE_CAMPAIGN_ID = 'google.c.a.c_id'; const CONSOLE_CAMPAIGN_NAME = 'google.c.a.c_l'; const CONSOLE_CAMPAIGN_TIME = 'google.c.a.ts'; /** Set to '1' if Analytics is enabled for the campaign */ const CONSOLE_CAMPAIGN_ANALYTICS_ENABLED = 'google.c.a.e'; const DEFAULT_REGISTRATION_TIMEOUT = 10000; var MessageType$1; (function (MessageType) { MessageType[MessageType["DATA_MESSAGE"] = 1] = "DATA_MESSAGE"; MessageType[MessageType["DISPLAY_NOTIFICATION"] = 3] = "DISPLAY_NOTIFICATION"; })(MessageType$1 || (MessageType$1 = {})); /** * @license * Copyright 2018 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ var MessageType; (function (MessageType) { MessageType["PUSH_RECEIVED"] = "push-received"; MessageType["NOTIFICATION_CLICKED"] = "notification-clicked"; MessageType["FID_REGISTERED"] = "fid-registered"; })(MessageType || (MessageType = {})); /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function arrayToBase64(array) { const uint8Array = new Uint8Array(array); const base64String = btoa(String.fromCharCode(...uint8Array)); return base64String.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); } function base64ToArray(base64String) { const padding = '='.repeat((4 - (base64String.length % 4)) % 4); const base64 = (base64String + padding) .replace(/\-/g, '+') .replace(/_/g, '/'); const rawData = atob(base64); const outputArray = new Uint8Array(rawData.length); for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); } return outputArray; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const OLD_DB_NAME = 'fcm_token_details_db'; /** * The last DB version of 'fcm_token_details_db' was 4. This is one higher, so that the upgrade * callback is called for all versions of the old DB. */ const OLD_DB_VERSION = 5; const OLD_OBJECT_STORE_NAME = 'fcm_token_object_Store'; async function migrateOldDatabase(senderId) { if ('databases' in indexedDB) { // indexedDb.databases() is an IndexedDB v3 API and does not exist in all browsers. TODO: Remove // typecast when it lands in TS types. const databases = await indexedDB.databases(); const dbNames = databases.map(db => db.name); if (!dbNames.includes(OLD_DB_NAME)) { // old DB didn't exist, no need to open. return null; } } let tokenDetails = null; const db = await (0,idb__WEBPACK_IMPORTED_MODULE_2__.openDB)(OLD_DB_NAME, OLD_DB_VERSION, { upgrade: async (db, oldVersion, newVersion, upgradeTransaction) => { if (oldVersion < 2) { // Database too old, skip migration. return; } if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) { // Database did not exist. Nothing to do. return; } const objectStore = upgradeTransaction.objectStore(OLD_OBJECT_STORE_NAME); const value = await objectStore.index('fcmSenderId').get(senderId); await objectStore.clear(); if (!value) { // No entry in the database, nothing to migrate. return; } if (oldVersion === 2) { const oldDetails = value; if (!oldDetails.auth || !oldDetails.p256dh || !oldDetails.endpoint) { return; } tokenDetails = { token: oldDetails.fcmToken, createTime: oldDetails.createTime ?? Date.now(), subscriptionOptions: { auth: oldDetails.auth, p256dh: oldDetails.p256dh, endpoint: oldDetails.endpoint, swScope: oldDetails.swScope, vapidKey: typeof oldDetails.vapidKey === 'string' ? oldDetails.vapidKey : arrayToBase64(oldDetails.vapidKey) } }; } else if (oldVersion === 3) { const oldDetails = value; tokenDetails = { token: oldDetails.fcmToken, createTime: oldDetails.createTime, subscriptionOptions: { auth: arrayToBase64(oldDetails.auth), p256dh: arrayToBase64(oldDetails.p256dh), endpoint: oldDetails.endpoint, swScope: oldDetails.swScope, vapidKey: arrayToBase64(oldDetails.vapidKey) } }; } else if (oldVersion === 4) { const oldDetails = value; tokenDetails = { token: oldDetails.fcmToken, createTime: oldDetails.createTime, subscriptionOptions: { auth: arrayToBase64(oldDetails.auth), p256dh: arrayToBase64(oldDetails.p256dh), endpoint: oldDetails.endpoint, swScope: oldDetails.swScope, vapidKey: arrayToBase64(oldDetails.vapidKey) } }; } } }); db.close(); // Delete all old databases. await (0,idb__WEBPACK_IMPORTED_MODULE_2__.deleteDB)(OLD_DB_NAME); await (0,idb__WEBPACK_IMPORTED_MODULE_2__.deleteDB)('fcm_vapid_details_db'); await (0,idb__WEBPACK_IMPORTED_MODULE_2__.deleteDB)('undefined'); return checkTokenDetails(tokenDetails) ? tokenDetails : null; } function checkTokenDetails(tokenDetails) { if (!tokenDetails || !tokenDetails.subscriptionOptions) { return false; } const { subscriptionOptions } = tokenDetails; return (typeof tokenDetails.createTime === 'number' && tokenDetails.createTime > 0 && typeof tokenDetails.token === 'string' && tokenDetails.token.length > 0 && typeof subscriptionOptions.auth === 'string' && subscriptionOptions.auth.length > 0 && typeof subscriptionOptions.p256dh === 'string' && subscriptionOptions.p256dh.length > 0 && typeof subscriptionOptions.endpoint === 'string' && subscriptionOptions.endpoint.length > 0 && typeof subscriptionOptions.swScope === 'string' && subscriptionOptions.swScope.length > 0 && typeof subscriptionOptions.vapidKey === 'string' && subscriptionOptions.vapidKey.length > 0); } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const ERROR_MAP = { ["missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"', ["only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */]: 'This method is available in a Window context.', ["only-available-in-sw" /* ErrorCode.AVAILABLE_IN_SW */]: 'This method is available in a service worker context.', ["permission-default" /* ErrorCode.PERMISSION_DEFAULT */]: 'The notification permission was not granted and dismissed instead.', ["permission-blocked" /* ErrorCode.PERMISSION_BLOCKED */]: 'The notification permission was not granted and blocked instead.', ["unsupported-browser" /* ErrorCode.UNSUPPORTED_BROWSER */]: "This browser doesn't support the API's required to use the Firebase SDK.", ["indexed-db-unsupported" /* ErrorCode.INDEXED_DB_UNSUPPORTED */]: "This browser doesn't support indexedDb.open() (ex. Safari iFrame, Firefox Private Browsing, etc)", ["failed-service-worker-registration" /* ErrorCode.FAILED_DEFAULT_REGISTRATION */]: 'We are unable to register the default service worker. {$browserErrorMessage}', ["token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */]: 'A problem occurred while subscribing the user to FCM: {$errorInfo}', ["token-subscribe-no-token" /* ErrorCode.TOKEN_SUBSCRIBE_NO_TOKEN */]: 'FCM returned no token when subscribing the user to push.', ["fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */]: 'A problem occurred while creating an FCM registration via FID: {$errorInfo}', ["fid-unregister-failed" /* ErrorCode.FID_UNREGISTER_FAILED */]: 'A problem occurred while unregistering the FCM registration via FID: {$errorInfo}', ["fid-registration-idb-schema-unavailable" /* ErrorCode.FID_REGISTRATION_IDB_SCHEMA_UNAVAILABLE */]: 'Unable to read or persist FID registration metadata because the messaging ' + 'IndexedDB schema is unavailable (for example, the database could not be ' + 'upgraded to the latest version).', ["token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */]: 'A problem occurred while unsubscribing the ' + 'user from FCM: {$errorInfo}', ["token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */]: 'A problem occurred while updating the user from FCM: {$errorInfo}', ["token-update-no-token" /* ErrorCode.TOKEN_UPDATE_NO_TOKEN */]: 'FCM returned no token when updating the user to push.', ["use-sw-after-get-token" /* ErrorCode.USE_SW_AFTER_GET_TOKEN */]: 'The useServiceWorker() method may only be called once and must be ' + 'called before calling getToken() to ensure your service worker is used.', ["invalid-sw-registration" /* ErrorCode.INVALID_SW_REGISTRATION */]: 'The input to useServiceWorker() must be a ServiceWorkerRegistration.', ["invalid-bg-handler" /* ErrorCode.INVALID_BG_HANDLER */]: 'The input to setBackgroundMessageHandler() must be a function.', ["invalid-vapid-key" /* ErrorCode.INVALID_VAPID_KEY */]: 'The public VAPID key must be a string.', ["use-vapid-key-after-get-token" /* ErrorCode.USE_VAPID_KEY_AFTER_GET_TOKEN */]: 'The usePublicVapidKey() method may only be called once and must be ' + 'called before calling getToken() to ensure your VAPID key is used.', ["invalid-on-registered-handler" /* ErrorCode.INVALID_ON_REGISTERED_HANDLER */]: 'No onRegistered callback handler was provided or registered. Implement onRegistered() before register().' }; const ERROR_FACTORY = new _firebase_util__WEBPACK_IMPORTED_MODULE_3__.ErrorFactory('messaging', 'Messaging', ERROR_MAP); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DATABASE_NAME = 'firebase-messaging-database'; const DATABASE_VERSION = 2; const TOKEN_OBJECT_STORE_NAME = 'firebase-messaging-store'; const FID_REGISTRATION_OBJECT_STORE_NAME = 'firebase-messaging-fid-registration-store'; const defaultIdb = { openDB: idb__WEBPACK_IMPORTED_MODULE_2__.openDB, deleteDB: idb__WEBPACK_IMPORTED_MODULE_2__.deleteDB }; let idbImpl = defaultIdb; // Open v2, but fall back to v1 if upgrade/open fails. Cache as `unknown` and guard store access. let dbPromise = null; function migrateMessagingDb(upgradeDb, oldVersion, targetSchemaVersion) { // Intentional fall-through for v2: run all intermediate migrations. // eslint-disable-next-line default-case switch (oldVersion) { case 0: upgradeDb.createObjectStore(TOKEN_OBJECT_STORE_NAME); if (targetSchemaVersion === 1) { break; } // fall through case 1: if (targetSchemaVersion === 2) { upgradeDb.createObjectStore(FID_REGISTRATION_OBJECT_STORE_NAME); } } } function createOpenDbOptions(targetSchemaVersion) { return { upgrade: (upgradeDb, oldVersion) => { migrateMessagingDb(upgradeDb, oldVersion, targetSchemaVersion); }, blocked: () => { /* no-op */ }, blocking: (_currentVersion, _blockedVersion, event) => { dbPromise = null; event.target?.close(); }, terminated: () => { dbPromise = null; } }; } function getDbPromise() { if (!dbPromise) { const openLatest = idbImpl.openDB(DATABASE_NAME, DATABASE_VERSION, createOpenDbOptions(2)); // Assign synchronously to avoid concurrent openDB() calls. dbPromise = openLatest.catch(() => idbImpl.openDB(DATABASE_NAME, DATABASE_VERSION - 1, createOpenDbOptions(1))); } return dbPromise; } function hasObjectStore(db, storeName) { return db.objectStoreNames.contains(storeName); } function assertFidRegistrationObjectStore(db) { if (!hasObjectStore(db, FID_REGISTRATION_OBJECT_STORE_NAME)) { throw ERROR_FACTORY.create("fid-registration-idb-schema-unavailable" /* ErrorCode.FID_REGISTRATION_IDB_SCHEMA_UNAVAILABLE */); } } async function dbGet(firebaseDependencies) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); const tokenDetails = (await db .transaction(TOKEN_OBJECT_STORE_NAME) .objectStore(TOKEN_OBJECT_STORE_NAME) .get(key)); if (tokenDetails) { return tokenDetails; } else { const oldTokenDetails = await migrateOldDatabase(firebaseDependencies.appConfig.senderId); if (oldTokenDetails) { await dbSet(firebaseDependencies, oldTokenDetails); return oldTokenDetails; } } } async function dbSet(firebaseDependencies, tokenDetails) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); const stores = [TOKEN_OBJECT_STORE_NAME]; const hasFidStore = hasObjectStore(db, FID_REGISTRATION_OBJECT_STORE_NAME); if (hasFidStore) { stores.push(FID_REGISTRATION_OBJECT_STORE_NAME); } const tx = db.transaction(stores, 'readwrite'); await tx.objectStore(TOKEN_OBJECT_STORE_NAME).put(tokenDetails, key); if (hasFidStore) { await tx.objectStore(FID_REGISTRATION_OBJECT_STORE_NAME).delete(key); } await tx.done; return tokenDetails; } async function dbRemove(firebaseDependencies) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); const tx = db.transaction(TOKEN_OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(TOKEN_OBJECT_STORE_NAME).delete(key); await tx.done; } async function dbGetFidRegistration(firebaseDependencies) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); assertFidRegistrationObjectStore(db); return (await db .transaction(FID_REGISTRATION_OBJECT_STORE_NAME) .objectStore(FID_REGISTRATION_OBJECT_STORE_NAME) .get(key)); } async function dbSetFidRegistration(firebaseDependencies, details) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); assertFidRegistrationObjectStore(db); const tx = db.transaction([TOKEN_OBJECT_STORE_NAME, FID_REGISTRATION_OBJECT_STORE_NAME], 'readwrite'); await tx.objectStore(FID_REGISTRATION_OBJECT_STORE_NAME).put(details, key); await tx.objectStore(TOKEN_OBJECT_STORE_NAME).delete(key); await tx.done; return details; } async function dbRemoveFidRegistration(firebaseDependencies) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); assertFidRegistrationObjectStore(db); const tx = db.transaction(FID_REGISTRATION_OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(FID_REGISTRATION_OBJECT_STORE_NAME).delete(key); await tx.done; } function getKey({ appConfig }) { return appConfig.appId; } const name = "@firebase/messaging"; const version = "0.13.0"; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** Max attempts (initial fetch + retries) when CreateRegistration `fetch()` throws. */ const FID_REGISTRATION_FETCH_MAX_ATTEMPTS = 3; /** Base delay in ms; backoff is `BASE * 2^attempt` after each failed attempt. */ const FID_REGISTRATION_FETCH_BASE_BACKOFF_MS = 1000; async function requestGetToken(firebaseDependencies, subscriptionOptions) { const headers = await getHeaders(firebaseDependencies); const body = getBody(subscriptionOptions, firebaseDependencies.appConfig.appName, /* includeSdkVersion= */ false); const subscribeOptions = { method: 'POST', headers, body: JSON.stringify(body) }; let responseData; try { const response = await fetch(getEndpoint(firebaseDependencies.appConfig), subscribeOptions); responseData = await response.json(); } catch (err) { throw ERROR_FACTORY.create("token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */, { errorInfo: err?.toString() }); } if (responseData.error) { const message = responseData.error.message; throw ERROR_FACTORY.create("token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */, { errorInfo: message }); } if (!responseData.token) { throw ERROR_FACTORY.create("token-subscribe-no-token" /* ErrorCode.TOKEN_SUBSCRIBE_NO_TOKEN */); } return responseData.token; } async function requestCreateRegistration(firebaseDependencies, subscriptionOptions) { const headers = await getHeaders(firebaseDependencies); const body = getBody(subscriptionOptions, firebaseDependencies.appConfig.appName, /* includeSdkVersion= */ true); const subscribeOptions = { method: 'POST', headers, body: JSON.stringify(body) }; let response; try { response = await fetchWithExponentialRetry(() => fetch(getEndpoint(firebaseDependencies.appConfig), subscribeOptions), FID_REGISTRATION_FETCH_MAX_ATTEMPTS, FID_REGISTRATION_FETCH_BASE_BACKOFF_MS); } catch (err) { throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, { errorInfo: err?.toString() }); } if (response.ok) { const responseFid = await parseCreateRegistrationSuccessFid(response); return { responseFid }; } // `fetch()` succeeded, but the backend returned a non-2xx response. // Best-effort parse the body to extract `error.message`, but always fail with // `FID_REGISTRATION_FAILED` to keep the error surface uniform. // Best-effort extraction of error details; the main signal is response.ok / status. let responseData; try { responseData = (await response.json()); } catch (err) { throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, { errorInfo: response.statusText }); } const message = responseData.error?.message ?? response.statusText; throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, { errorInfo: message }); } /** * Deletes an FCM Web registration via DeleteRegistration using the Firebase Installation ID (FID). */ async function requestDeleteRegistration(firebaseDependencies, fid) { const headers = await getHeaders(firebaseDependencies); const options = { method: 'DELETE', headers }; let response; try { response = await fetch(`${getEndpoint(firebaseDependencies.appConfig)}/${fid}`, options); } catch (err) { throw ERROR_FACTORY.create("fid-unregister-failed" /* ErrorCode.FID_UNREGISTER_FAILED */, { errorInfo: err?.toString() }); } if (response.ok) { return; } // Best-effort parse error details; surface uniform error code. try { const responseData = (await response.json()); const message = responseData.error?.message ?? response.statusText; throw message; } catch (err) { // If parsing failed, fall back to status text. throw ERROR_FACTORY.create("fid-unregister-failed" /* ErrorCode.FID_UNREGISTER_FAILED */, { errorInfo: (typeof err === 'string' && err) || response.statusText || err?.toString() }); } } /** * Parses a successful CreateRegistration body. The backend must return JSON with a non-empty * string `name`: a resource name `projects/{projectId}/registrations/{fid}` */ async function parseCreateRegistrationSuccessFid(response) { const text = await response.text(); if (!text.trim()) { throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, { errorInfo: 'CreateRegistration succeeded but response body is empty' }); } let data; try { data = JSON.parse(text); } catch { throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, { errorInfo: 'CreateRegistration succeeded but response body is not valid JSON' }); } const name = data.name; if (typeof name !== 'string' || name.length === 0) { throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, { errorInfo: 'CreateRegistration succeeded but response did not include a non-empty name' }); } return parseFidFromRegistrationResourceName(name); } const REGISTRATIONS_NAME_SEGMENT = '/registrations/'; /** Extracts the Firebase Installation ID from CreateRegistration `name` (resource path). */ function parseFidFromRegistrationResourceName(name) { const segmentIndex = name.indexOf(REGISTRATIONS_NAME_SEGMENT); if (segmentIndex !== -1) { const fid = name.slice(segmentIndex + REGISTRATIONS_NAME_SEGMENT.length); if (fid.length > 0) { return fid; } } throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, { errorInfo: 'CreateRegistration succeeded but response name is not a valid registration resource name' }); } async function requestUpdateToken(firebaseDependencies, tokenDetails) { const headers = await getHeaders(firebaseDependencies); const body = getBody(tokenDetails.subscriptionOptions, firebaseDependencies.appConfig.appName, /* includeSdkVersion= */ false); const updateOptions = { method: 'PATCH', headers, body: JSON.stringify(body) }; let responseData; try { const response = await fetch(`${getEndpoint(firebaseDependencies.appConfig)}/${tokenDetails.token}`, updateOptions); responseData = await response.json(); } catch (err) { throw ERROR_FACTORY.create("token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */, { errorInfo: err?.toString() }); } if (responseData.error) { const message = responseData.error.message; throw ERROR_FACTORY.create("token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */, { errorInfo: message }); } if (!responseData.token) { throw ERROR_FACTORY.create("token-update-no-token" /* ErrorCode.TOKEN_UPDATE_NO_TOKEN */); } return responseData.token; } async function requestDeleteToken(firebaseDependencies, token) { const headers = await getHeaders(firebaseDependencies); const unsubscribeOptions = { method: 'DELETE', headers }; try { const response = await fetch(`${getEndpoint(firebaseDependencies.appConfig)}/${token}`, unsubscribeOptions); const responseData = await response.json(); if (responseData.error) { const message = responseData.error.message; throw ERROR_FACTORY.create("token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */, { errorInfo: message }); } } catch (err) { throw ERROR_FACTORY.create("token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */, { errorInfo: err?.toString() }); } } /** * Re-runs `operation` when it throws, with exponential backoff between attempts. * Rethrows the last error if all attempts fail. */ async function fetchWithExponentialRetry(operation, maxAttempts, baseBackoffMs) { let lastError; for (let attempt = 0; attempt < maxAttempts; attempt++) { try { return await operation(); } catch (err) { lastError = err; if (attempt < maxAttempts - 1) { const delayMs = baseBackoffMs * Math.pow(2, attempt); await new Promise(resolve => setTimeout(resolve, delayMs)); } } } throw lastError; } function getEndpoint({ projectId }) { return `${ENDPOINT}/projects/${projectId}/registrations`; } async function getHeaders({ appConfig, installations }) { const authToken = await installations.getToken(); return new Headers({ 'Content-Type': 'application/json', Accept: 'application/json', 'x-goog-api-key': appConfig.apiKey, 'x-goog-firebase-installations-auth': `FIS ${authToken}` }); } /** * Hostname for the registering web client (e.g. `www.example.com`), or the app name * (`appNameFallback`) when the scope cannot be resolved (e.g. some test environments). */ function getRegistrationOrigin(swScope, appNameFallback) { try { if (/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(swScope)) { return new URL(swScope).host; } } catch { // Fall through to relative-scope handling. } try { if (typeof self !== 'undefined' && self.location?.href) { return new URL(swScope, self.location.origin).host; } } catch { // Fall through. } if (typeof self !== 'undefined' && self.location?.host) { return self.location.host; } return appNameFallback; } function getBody({ p256dh, auth, endpoint, vapidKey, swScope }, appNameFallback, includeSdkVersion) { const body = { web: { origin: getRegistrationOrigin(swScope, appNameFallback), endpoint, auth, p256dh } }; if (includeSdkVersion) { // eslint-disable-next-line camelcase body.fcm_sdk_version = version; } if (vapidKey !== DEFAULT_VAPID_KEY) { body.web.applicationPubKey = vapidKey; } return body; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // UpdateRegistration will be called once every week. const TOKEN_EXPIRATION_MS = 7 * 24 * 60 * 60 * 1000; // 7 days async function getTokenInternal(messaging) { const pushSubscription = await getPushSubscription$1(messaging.swRegistration, messaging.vapidKey); const subscriptionOptions = { vapidKey: messaging.vapidKey, swScope: messaging.swRegistration.scope, endpoint: pushSubscription.endpoint, auth: arrayToBase64(pushSubscription.getKey('auth')), p256dh: arrayToBase64(pushSubscription.getKey('p256dh')) }; const tokenDetails = await dbGet(messaging.firebaseDependencies); if (!tokenDetails) { // No token, get a new one. return getNewToken(messaging.firebaseDependencies, subscriptionOptions); } else if (!isTokenValid(tokenDetails.subscriptionOptions, subscriptionOptions)) { // Invalid token, get a new one. try { await requestDeleteToken(messaging.firebaseDependencies, tokenDetails.token); } catch (e) { // Suppress errors because of #2364 console.warn(e); } return getNewToken(messaging.firebaseDependencies, subscriptionOptions); } else if (Date.now() >= tokenDetails.createTime + TOKEN_EXPIRATION_MS) { // Weekly token refresh return updateToken(messaging, { token: tokenDetails.token, createTime: Date.now(), subscriptionOptions }); } else { // Valid token, nothing to do. return tokenDetails.token; } } /** * Legacy getToken() path: there is a token row in IndexedDB. Revoke it with FCM, drop the row, and * clear any leftover FID registration metadata (apps may mix APIs). */ async function revokeLegacyFcmTokenAndClearCaches(messaging, tokenDetails) { await requestDeleteToken(messaging.firebaseDependencies, tokenDetails.token); await dbRemove(messaging.firebaseDependencies); await removeFidRegistrationBestEffort(messaging.firebaseDependencies); } /** * No legacy token row: the client may only have FID-based registration (register() flow). If so, * delete that registration on the server, always scrub local FID metadata, then surface * onUnregistered when we actually had an FID. */ async function revokeFidRegistrationIfStored(messaging) { const stored = await dbGetFidRegistration(messaging.firebaseDependencies).catch(() => undefined); const fid = stored?.fid; if (fid) { await requestDeleteRegistration(messaging.firebaseDependencies, fid); } await removeFidRegistrationBestEffort(messaging.firebaseDependencies); if (fid) { notifyOnUnregistered(messaging, fid); } } /** * Revokes the app's FCM registration: legacy token (getToken/deleteToken) and/or FID-based * registration (register/unregister), clears local caches, notifies onUnregistered when a stored * FID existed, then unsubscribes the push subscription when present. */ async function revokeRegistrationInternal(messaging) { const tokenDetails = await dbGet(messaging.firebaseDependencies); if (tokenDetails) { await revokeLegacyFcmTokenAndClearCaches(messaging, tokenDetails); } else { await revokeFidRegistrationIfStored(messaging); } // Unsubscribe from the push subscription. const pushSubscription = await messaging.swRegistration.pushManager.getSubscription(); if (pushSubscription) { return pushSubscription.unsubscribe(); } // If there's no SW, consider it a success. return true; } async function updateToken(messaging, tokenDetails) { try { const updatedToken = await requestUpdateToken(messaging.firebaseDependencies, tokenDetails); const updatedTokenDetails = { ...tokenDetails, token: updatedToken, createTime: Date.now() }; await dbSet(messaging.firebaseDependencies, updatedTokenDetails); return updatedToken; } catch (e) { throw e; } } async function getNewToken(firebaseDependencies, subscriptionOptions) { const token = await requestGetToken(firebaseDependencies, subscriptionOptions); const tokenDetails = { token, createTime: Date.now(), subscriptionOptions }; await dbSet(firebaseDependencies, tokenDetails); return tokenDetails.token; } /** * Gets a PushSubscription for the current user. */ async function getPushSubscription$1(swRegistration, vapidKey) { const subscription = await swRegistration.pushManager.getSubscription(); if (subscription) { return subscription; } return swRegistration.pushManager.subscribe({ userVisibleOnly: true, // Chrome <= 75 doesn't support base64-encoded VAPID key. For backward compatibility, VAPID key // submitted to pushManager#subscribe must be of type Uint8Array. applicationServerKey: base64ToArray(vapidKey) }); } /** * Checks if the saved tokenDetails object matches the configuration provided. */ function isTokenValid(dbOptions, currentOptions) { const isVapidKeyEqual = currentOptions.vapidKey === dbOptions.vapidKey; const isEndpointEqual = currentOptions.endpoint === dbOptions.endpoint; const isAuthEqual = currentOptions.auth === dbOptions.auth; const isP256dhEqual = currentOptions.p256dh === dbOptions.p256dh; return isVapidKeyEqual && isEndpointEqual && isAuthEqual && isP256dhEqual; } /** Clears FID registration metadata; apps may mix legacy getToken() with FID register/unregister. */ async function removeFidRegistrationBestEffort(firebaseDependencies) { try { await dbRemoveFidRegistration(firebaseDependencies); } catch { // Ignore. } } function notifyOnRegistered(messaging, fid) { const handler = messaging.onRegisteredHandler; if (!handler) { return; } if (typeof handler === 'function') { handler(fid); } else { handler.next(fid); } } function notifyOnUnregistered(messaging, fid) { const handler = messaging.onUnregisteredHandler; if (!handler) { return; } if (typeof handler === 'function') { handler(fid); } else { handler.next(fid); } } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function registerDefaultSw(messaging) { try { messaging.swRegistration = await navigator.serviceWorker.register(DEFAULT_SW_PATH, { scope: DEFAULT_SW_SCOPE }); // The timing when browser updates sw when sw has an update is unreliable from experiment. It // leads to version conflict when the SDK upgrades to a newer version in the main page, but sw // is stuck with the old version. For example, // https://github.com/firebase/firebase-js-sdk/issues/2590 The following line reliably updates // sw if there was an update. messaging.swRegistration.update().catch(() => { /* it is non blocking and we don't care if it failed */ }); await waitForRegistrationActive(messaging.swRegistration); } catch (e) { throw ERROR_FACTORY.create("failed-service-worker-registration" /* ErrorCode.FAILED_DEFAULT_REGISTRATION */, { browserErrorMessage: e?.message }); } } /** * Waits for registration to become active. MDN documentation claims that * a service worker registration should be ready to use after awaiting * navigator.serviceWorker.register() but that doesn't seem to be the case in * practice, causing the SDK to throw errors when calling * swRegistration.pushManager.subscribe() too soon after register(). The only * solution seems to be waiting for the service worker registration `state` * to become "active". */ async function waitForRegistrationActive(registration) { return new Promise((resolve, reject) => { const rejectTimeout = setTimeout(() => reject(new Error(`Service worker not registered after ${DEFAULT_REGISTRATION_TIMEOUT} ms`)), DEFAULT_REGISTRATION_TIMEOUT); const incomingSw = registration.installing || registration.waiting; if (registration.active) { clearTimeout(rejectTimeout); resolve(); } else if (incomingSw) { incomingSw.onstatechange = ev => { if (ev.target?.state === 'activated') { incomingSw.onstatechange = null; clearTimeout(rejectTimeout); resolve(); } }; } else { clearTimeout(rejectTimeout); reject(new Error('No incoming service worker found.')); } }); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function updateSwReg(messaging, swRegistration) { if (!swRegistration && !messaging.swRegistration) { await registerDefaultSw(messaging); } if (!swRegistration && !!messaging.swRegistration) { return; } if (!(swRegistration instanceof ServiceWorkerRegistration)) { throw ERROR_FACTORY.create("invalid-sw-registration" /* ErrorCode.INVALID_SW_REGISTRATION */); } messaging.swRegistration = swRegistration; } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function updateVapidKey(messaging, vapidKey) { if (!!vapidKey) { messaging.vapidKey = vapidKey; } else if (!messaging.vapidKey) { messaging.vapidKey = DEFAULT_VAPID_KEY; } } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** Retries when CreateRegistration echoes an FID that does not match Installations.getId(). */ const FID_REGISTRATION_FID_MATCH_MAX_ATTEMPTS = 3; /** * For the new FID-based register path: * - Create (or refresh) an FCM Web registration in the backend via CreateRegistration. * - Use the FIS auth token produced by the installations instance (implicitly associated with FID). * - CreateRegistration must echo the installation in `name` (e.g. * `projects/{projectId}/registrations/{fid}`); it must match `expectedFid` from * Installations.getId(). On mismatch we refresh the auth token and retry, then fail with * `fid-registration-failed`. */ async function registerFcmRegistrationWithFid(messaging, expectedFid) { const pushSubscription = await getPushSubscription(messaging.swRegistration, messaging.vapidKey); const subscriptionOptions = { vapidKey: messaging.vapidKey, swScope: messaging.swRegistration.scope, endpoint: pushSubscription.endpoint, auth: arrayToBase64(pushSubscription.getKey('auth')), p256dh: arrayToBase64(pushSubscription.getKey('p256dh')) }; const installations = messaging.firebaseDependencies.installations; for (let attempt = 0; attempt < FID_REGISTRATION_FID_MATCH_MAX_ATTEMPTS; attempt++) { const { responseFid } = await requestCreateRegistration(messaging.firebaseDependencies, subscriptionOptions); if (responseFid === expectedFid) { return; } // If CreateRegistration echoes an unexpected FID, the FIS auth token used for the request may // be stale relative to the installation the backend associates with the call. Force-refresh // the token before retrying so the next attempt uses credentials aligned with Installations. if (attempt < FID_REGISTRATION_FID_MATCH_MAX_ATTEMPTS - 1) { await installations.getToken(true); } } throw ERROR_FACTORY.create("fid-registration-failed" /* ErrorCode.FID_REGISTRATION_FAILED */, { errorInfo: 'CreateRegistration response FID does not match Firebase Installation ID' }); } async function getPushSubscription(swRegistration, vapidKey) { const subscription = await swRegistration.pushManager.getSubscription(); if (subscription) { return subscription; } // Chrome/Firefox require applicationServerKey to be of type Uint8Array. return swRegistration.pushManager.subscribe({ userVisibleOnly: true, // `PushManager.subscribe` expects a `BufferSource`; `base64ToArray` produces a typed array. // Cast to satisfy the lib typing differences across TS DOM versions. applicationServerKey: base64ToArray(vapidKey) }); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const FID_REGISTRATION_REFRESH_MS = 7 * 24 * 60 * 60 * 1000; // 7 days /** * Registers the app instance with FCM using its Firebase Installation ID (FID). The FID is * delivered via the `onRegistered` callback. Call this to establish an FID-based identity. * Once `onRegistered` provides an FID, instruct your backend to remove any legacy token * previously associated with this instance. The backend send API supports FID as a target. * * When called multiple times, `onRegistered` is invoked on each call with the current FID. * Backend registration sync runs on first register, when the FID changes, or on weekly refresh. * * @param messaging - The MessagingService instance. * @param options - Optional. Same options as getToken (vapidKey, serviceWorkerRegistration). */ async function register$1(messaging, options) { if (!navigator) { throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */); } if (Notification.permission === 'default') { await Notification.requestPermission(); } if (Notification.permission !== 'granted') { throw ERROR_FACTORY.create("permission-blocked" /* ErrorCode.PERMISSION_BLOCKED */); } if (!messaging.onRegisteredHandler) { throw ERROR_FACTORY.create("invalid-on-registered-handler" /* ErrorCode.INVALID_ON_REGISTERED_HANDLER */); } await updateVapidKey(messaging, options?.vapidKey); await updateSwReg(messaging, options?.serviceWorkerRegistration); // Keep the queue alive after a failed register() so future calls can retry. const prev = messaging._registerNotifyChain.catch(() => { }); messaging._registerNotifyChain = prev.then(async () => { const fid = await messaging.firebaseDependencies.installations.getId(); const stored = await dbGetFidRegistration(messaging.firebaseDependencies); const now = Date.now(); const shouldRefresh = !stored || stored.fid !== fid || now >= stored.lastRegisterTime + FID_REGISTRATION_REFRESH_MS; if (shouldRefresh) { await registerFcmRegistrationWithFid(messaging, fid); await dbSetFidRegistration(messaging.firebaseDependencies, { fid, lastRegisterTime: now, vapidKey: messaging.vapidKey }); } const handler = messaging.onRegisteredHandler; if (!handler) { throw ERROR_FACTORY.create("invalid-on-registered-handler" /* ErrorCode.INVALID_ON_REGISTERED_HANDLER */); } notifyOnRegistered(messaging, fid); }); return messaging._registerNotifyChain; } /** * @license * Copyright 2026 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * When the Firebase Installation ID changes, re-run `register()` so FCM registration and * onRegistered run for the new FID. No-op if no onRegistered handler is set or the app * instance was never registered with FCM. */ function subscribeFidChangeRegistration(messaging, installations) { return (0,_firebase_installations__WEBPACK_IMPORTED_MODULE_0__.onIdChange)(installations, () => { void (async () => { if (!messaging.onRegisteredHandler) { return; } const stored = await dbGetFidRegistration(messaging.firebaseDependencies); if (!stored) { return; } await register$1(messaging).catch(() => { // Best-effort: permission may be revoked or SW unavailable after FID rotation. }); })(); }); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function externalizePayload(internalPayload) { const payload = { from: internalPayload.from, // eslint-disable-next-line camelcase collapseKey: internalPayload.collapse_key, // eslint-disable-next-line camelcase messageId: internalPayload.fcmMessageId }; propagateNotificationPayload(payload, internalPayload); propagateDataPayload(payload, internalPayload); propagateFcmOptions(payload, internalPayload); return payload; } function propagateNotificationPayload(payload, messagePayloadInternal) { if (!messagePayloadInternal.notification) { return; } payload.notification = {}; const title = messagePayloadInternal.notification.title; if (!!title) { payload.notification.title = title; } const body = messagePayloadInternal.notification.body; if (!!body) { payload.notification.body = body; } const image = messagePayloadInternal.notification.image; if (!!image) { payload.notification.image = image; } const icon = messagePayloadInternal.notification.icon; if (!!icon) { payload.notification.icon = icon; } } function propagateDataPayload(payload, messagePayloadInternal) { if (!messagePayloadInternal.data) { return; } payload.data = messagePayloadInternal.data; } function propagateFcmOptions(payload, messagePayloadInternal) { // fcmOptions.link value is written into notification.click_action. see more in b/232072111 if (!messagePayloadInternal.fcmOptions && !messagePayloadInternal.notification?.click_action) { return; } payload.fcmOptions = {}; const link = messagePayloadInternal.fcmOptions?.link ?? messagePayloadInternal.notification?.click_action; if (!!link) { payload.fcmOptions.link = link; } // eslint-disable-next-line camelcase const analyticsLabel = messagePayloadInternal.fcmOptions?.analytics_label; if (!!analyticsLabel) { payload.fcmOptions.analyticsLabel = analyticsLabel; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function isConsoleMessage(data) { // This message has a campaign ID, meaning it was sent using the Firebase Console. return typeof data === 'object' && !!data && CONSOLE_CAMPAIGN_ID in data; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ _mergeStrings('AzSCbw63g1R0nCw85jG8', 'Iaya3yLKwmgvh7cF0q4'); function _mergeStrings(s1, s2) { const resultArray = []; for (let i = 0; i < s1.length; i++) { resultArray.push(s1.charAt(i)); if (i < s2.length) { resultArray.push(s2.charAt(i)); } } return resultArray.join(''); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function extractAppConfig(app) { if (!app || !app.options) { throw getMissingValueError('App Configuration Object'); } if (!app.name) { throw getMissingValueError('App Name'); } // Required app config keys const configKeys = [ 'projectId', 'apiKey', 'appId', 'messagingSenderId' ]; const { options } = app; for (const keyName of configKeys) { if (!options[keyName]) { throw getMissingValueError(keyName); } } return { appName: app.name, projectId: options.projectId, apiKey: options.apiKey, appId: options.appId, senderId: options.messagingSenderId }; } function getMissingValueError(valueName) { return ERROR_FACTORY.create("missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */, { valueName }); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class MessagingService { constructor(app, installations, analyticsProvider) { // logging is only done with end user consent. Default to false. this.deliveryMetricsExportedToBigQueryEnabled = false; this.onBackgroundMessageHandler = null; this.onMessageHandler = null; /** Observer for the event that the app instance is registered with FCM via Firebase Installation ID (FID). */ this.onRegisteredHandler = null; /** Observer for the event that the app instance is unregistered from FCM (FID no longer active). */ this.onUnregisteredHandler = null; /** * Serializes the FID get + compare + notify step so concurrent register() calls * do not race each other. */ this._registerNotifyChain = Promise.resolve(); /** Unsubscribe from Installations `onIdChange` when messaging is deleted. */ this._fidChangeUnsubscribe = null; this.logEvents = []; /** * Single source of truth for the logging loop lifecycle. * * `scheduled` holds the active timer id; `flushing` indicates an async dispatch * is in progress (prevents duplicate starts); `stopped` means idle. */ this.logQueue = { state: 'stopped' }; const appConfig = extractAppConfig(app); this.firebaseDependencies = { app, appConfig, installations, analyticsProvider }; } _delete() { if (this._fidChangeUnsubscribe) { this._fidChangeUnsubscribe(); this._fidChangeUnsubscribe = null; } if (this.logQueue.state === 'scheduled') { clearTimeout(this.logQueue.timerId); } this.logQueue = { state: 'stopped' }; return Promise.resolve(); } } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function getToken$1(messaging, options) { if (!navigator) { throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */); } if (Notification.permission === 'default') { await Notification.requestPermission(); } if (Notification.permission !== 'granted') { throw ERROR_FACTORY.create("permission-blocked" /* ErrorCode.PERMISSION_BLOCKED */); } await updateVapidKey(messaging, options?.vapidKey); await updateSwReg(messaging, options?.serviceWorkerRegistration); return getTokenInternal(messaging); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function logToScion(messaging, messageType, data) { const eventType = getEventType(messageType); const analytics = await messaging.firebaseDependencies.analyticsProvider.get(); analytics.logEvent(eventType, { /* eslint-disable camelcase */ message_id: data[CONSOLE_CAMPAIGN_ID], message_name: data[CONSOLE_CAMPAIGN_NAME], message_time: data[CONSOLE_CAMPAIGN_TIME], message_device_time: Math.floor(Date.now() / 1000) /* eslint-enable camelcase */ }); } function getEventType(messageType) { switch (messageType) { case MessageType.NOTIFICATION_CLICKED: return 'notification_open'; case MessageType.PUSH_RECEIVED: return 'notification_foreground'; default: throw new Error(); } } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function messageEventListener(messaging, event) { const internalPayload = event.data; if (!internalPayload.isFirebaseMessaging) { return; } if (messaging.onMessageHandler && internalPayload.messageType === MessageType.PUSH_RECEIVED) { if (typeof messaging.onMessageHandler === 'function') { messaging.onMessageHandler(externalizePayload(internalPayload)); } else { messaging.onMessageHandler.next(externalizePayload(internalPayload)); } } if (messaging.onRegisteredHandler && internalPayload.messageType === MessageType.FID_REGISTERED) { const fid = internalPayload.fid; if (typeof messaging.onRegisteredHandler === 'function') { messaging.onRegisteredHandler(fid); } else { messaging.onRegisteredHandler.next(fid); } } // Log to Scion if applicable const dataPayload = internalPayload.data; if (isConsoleMessage(dataPayload) && dataPayload[CONSOLE_CAMPAIGN_ANALYTICS_ENABLED] === '1') { await logToScion(messaging, internalPayload.messageType, dataPayload); } } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const WindowMessagingFactory = (container) => { const messaging = new MessagingService(container.getProvider('app').getImmediate(), container.getProvider('installations-internal').getImmediate(), container.getProvider('analytics-internal')); navigator.serviceWorker.addEventListener('message', e => messageEventListener(messaging, e)); messaging._fidChangeUnsubscribe = subscribeFidChangeRegistration(messaging, container.getProvider('installations').getImmediate()); return messaging; }; const WindowMessagingInternalFactory = (container) => { const messaging = container .getProvider('messaging') .getImmediate(); const messagingInternal = { getToken: (options) => getToken$1(messaging, options), register: (options) => register$1(messaging, options) }; return messagingInternal; }; function registerMessagingInWindow() { (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component('messaging', WindowMessagingFactory, "PUBLIC" /* ComponentType.PUBLIC */)); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component('messaging-internal', WindowMessagingInternalFactory, "PRIVATE" /* ComponentType.PRIVATE */)); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__.registerVersion)(name, version); // BUILD_TARGET will be replaced by values like esm, cjs, etc during the compilation (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__.registerVersion)(name, version, 'esm2020'); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Checks if all required APIs exist in the browser. * @returns a Promise that resolves to a boolean. * * @public */ async function isWindowSupported() { try { // This throws if open() is unsupported, so adding it to the conditional // statement below can cause an uncaught error. await (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.validateIndexedDBOpenable)(); } catch (e) { return false; } // firebase-js-sdk/issues/2393 reveals that idb#open in Safari iframe and Firefox private browsing // might be prohibited to run. In these contexts, an error would be thrown during the messaging // instantiating phase, informing the developers to import/call isSupported for special handling. return (typeof window !== 'undefined' && (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.isIndexedDBAvailable)() && (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.areCookiesEnabled)() && 'serviceWorker' in navigator && 'PushManager' in window && 'Notification' in window && 'fetch' in window && ServiceWorkerRegistration.prototype.hasOwnProperty('showNotification') && PushSubscription.prototype.hasOwnProperty('getKey')); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function deleteToken$1(messaging) { if (!navigator) { throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */); } if (!messaging.swRegistration) { await registerDefaultSw(messaging); } return revokeRegistrationInternal(messaging); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function onMessage$1(messaging, nextOrObserver) { if (!navigator) { throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */); } messaging.onMessageHandler = nextOrObserver; return () => { messaging.onMessageHandler = null; }; } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Subscribes to an event that the app instance is registered with FCM via Firebase Installation ID (FID). * Use the FID passed to the callback to upload it to your application server. * * @param messaging - The {@link MessagingService} instance. * @param nextOrObserver - A function or observer object called when an FID is registered. * @returns Unsubscribe function to stop listening. */ function onRegistered$1(messaging, nextOrObserver) { messaging.onRegisteredHandler = nextOrObserver; return () => { if (messaging.onRegisteredHandler === nextOrObserver) { messaging.onRegisteredHandler = null; } }; } /** * @license * Copyright 2026 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Subscribes to an event that the app instance is unregistered from FCM so the FID is no longer active. * Use this to notify your backend to remove this FID to prevent 404 errors on send. * * @param messaging - The {@link MessagingService} instance. * @param nextOrObserver - A function or observer object called with the unregistered FID. * @returns Unsubscribe function to stop listening. */ function onUnregistered$1(messaging, nextOrObserver) { messaging.onUnregisteredHandler = nextOrObserver; return () => { if (messaging.onUnregisteredHandler === nextOrObserver) { messaging.onUnregisteredHandler = null; } }; } /** * @license * Copyright 2026 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Unregisters the app instance from FCM by deleting its FID-based registration. * * On success, triggers the `onUnregistered` callback (if set) with the unregistered FID. * * @param messaging - The MessagingService instance. */ async function unregister$1(messaging) { if (!navigator) { throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */); } // Prefer the last successfully registered FID from local metadata when available. const stored = await dbGetFidRegistration(messaging.firebaseDependencies).catch(() => undefined); const fid = stored?.fid ?? (await messaging.firebaseDependencies.installations.getId()); await requestDeleteRegistration(messaging.firebaseDependencies, fid); // Best-effort local cleanup; still resolve even if schema is unavailable. try { await dbRemoveFidRegistration(messaging.firebaseDependencies); } catch { // Ignore. } // Best-effort cleanup of legacy token details created via getToken(). try { await dbRemove(messaging.firebaseDependencies); } catch { // Ignore. } const handler = messaging.onUnregisteredHandler; if (!handler) { return; } if (typeof handler === 'function') { handler(fid); } else { handler.next(fid); } } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Retrieves a Firebase Cloud Messaging instance. * * @returns The Firebase Cloud Messaging instance associated with the provided firebase app. * * @public */ function getMessagingInWindow(app = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__.getApp)()) { // Conscious decision to make this async check non-blocking during the messaging instance // initialization phase for performance consideration. An error would be thrown latter for // developer's information. Developers can then choose to import and call `isSupported` for // special handling. isWindowSupported().then(isSupported => { // If `isWindowSupported()` resolved, but returned false. if (!isSupported) { throw ERROR_FACTORY.create("unsupported-browser" /* ErrorCode.UNSUPPORTED_BROWSER */); } }, _ => { // If `isWindowSupported()` rejected. throw ERROR_FACTORY.create("indexed-db-unsupported" /* ErrorCode.INDEXED_DB_UNSUPPORTED */); }); return (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__._getProvider)((0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(app), 'messaging').getImmediate(); } /** * Subscribes the {@link Messaging} instance to push notifications. Returns a Firebase Cloud * Messaging registration token that can be used to send push messages to that {@link Messaging} * instance. * * If notification permission isn't already granted, this method asks the user for permission. The * returned promise rejects if the user does not allow the app to show notifications. * * @param messaging - The {@link Messaging} instance. * @param options - Provides an optional vapid key and an optional service worker registration. * * @returns The promise resolves with an FCM registration token. * * @deprecated Use {@link register} together with {@link onRegistered} for Firebase * Installation ID-based messaging instead of retrieving an FCM registration token with this API. * * @public */ async function getToken(messaging, options) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return getToken$1(messaging, options); } /** * Deletes the registration token associated with this {@link Messaging} instance and unsubscribes * the {@link Messaging} instance from the push subscription. * * If there is no legacy registration token but the client has FID-based registration metadata * (from {@link register}), this deletes that registration on the server, clears local metadata, and * invokes {@link onUnregistered} with the removed FID when successful. * * @param messaging - The {@link Messaging} instance. * * @returns The promise resolves when the token has been successfully deleted. * * @deprecated Use {@link onUnregistered} to observe when the client is no longer * registered and update your backend accordingly, instead of explicitly deleting the * registration token with this API. * * @public */ function deleteToken(messaging) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return deleteToken$1(messaging); } /** * When a push message is received and the user is currently on a page for your origin, the * message is passed to the page and an `onMessage()` event is dispatched with the payload of * the push message. * * * @param messaging - The {@link Messaging} instance. * @param nextOrObserver - This function, or observer object with `next` defined, * is called when a message is received and the user is currently viewing your page. * @returns To stop listening for messages execute this returned function. * * @public */ function onMessage(messaging, nextOrObserver) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return onMessage$1(messaging, nextOrObserver); } /** * Registers the app instance with FCM using its Firebase Installation ID (FID). The FID is * delivered via the {@link onRegistered} callback, not as a return value. Call this to establish * an FID-based identity; once {@link onRegistered} provides an FID, instruct your backend to * remove any legacy token previously associated with this instance. The backend send API * supports FID as a target. * * @param messaging - The {@link Messaging} instance. * @param options - Optional. VAPID key and/or service worker registration (same as getToken). * @returns Promise that resolves when registration has been initiated; FID is delivered via onRegistered. * * @public */ async function register(messaging, options) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return register$1(messaging, options); } /** * Unregisters the app instance from FCM by deleting its FID-based registration. * On success, triggers {@link onUnregistered} (if registered) with the unregistered FID. * * @param messaging - The {@link Messaging} instance. * * @public */ async function unregister(messaging) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return unregister$1(messaging); } /** * Subscribes to an event that the app instance is registered with FCM via Firebase Installation ID (FID). * Use the FID passed to the callback to upload it to your application server. When you receive an FID * after calling {@link register}, instruct your backend to remove any legacy token for this instance. * * @param messaging - The {@link Messaging} instance. * @param nextOrObserver - A function or observer object called when an FID is registered. * @returns Unsubscribe function to stop listening. * * @public */ function onRegistered(messaging, nextOrObserver) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return onRegistered$1(messaging, nextOrObserver); } /** * Subscribes to an event that the app instance is unregistered from FCM (FID no longer active). * Use this to notify your backend to remove this FID to prevent 404 errors on send. * * @param messaging - The {@link Messaging} instance. * @param nextOrObserver - A function or observer object called with the unregistered FID. * @returns Unsubscribe function to stop listening. * * @public */ function onUnregistered(messaging, nextOrObserver) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return onUnregistered$1(messaging, nextOrObserver); } /** * The Firebase Cloud Messaging Web SDK. * This SDK does not work in a Node.js environment. * * @packageDocumentation */ registerMessagingInWindow(); //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./node_modules/@firebase/util/dist/postinstall.mjs": /*!**********************************************************!*\ !*** ./node_modules/@firebase/util/dist/postinstall.mjs ***! \**********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getDefaultsFromPostinstall: function() { return /* binding */ getDefaultsFromPostinstall; } /* harmony export */ }); const getDefaultsFromPostinstall = () => (undefined); /***/ }), /***/ "./node_modules/firebase/app/dist/esm/index.esm.js": /*!*********************************************************!*\ !*** ./node_modules/firebase/app/dist/esm/index.esm.js ***! \*********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ FirebaseError: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.FirebaseError; }, /* harmony export */ SDK_VERSION: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.SDK_VERSION; }, /* harmony export */ _DEFAULT_ENTRY_NAME: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._DEFAULT_ENTRY_NAME; }, /* harmony export */ _addComponent: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._addComponent; }, /* harmony export */ _addOrOverwriteComponent: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._addOrOverwriteComponent; }, /* harmony export */ _apps: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._apps; }, /* harmony export */ _clearComponents: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._clearComponents; }, /* harmony export */ _components: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._components; }, /* harmony export */ _getProvider: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider; }, /* harmony export */ _isFirebaseApp: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._isFirebaseApp; }, /* harmony export */ _isFirebaseServerApp: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._isFirebaseServerApp; }, /* harmony export */ _isFirebaseServerAppSettings: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._isFirebaseServerAppSettings; }, /* harmony export */ _registerComponent: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._registerComponent; }, /* harmony export */ _removeServiceInstance: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._removeServiceInstance; }, /* harmony export */ _serverApps: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._serverApps; }, /* harmony export */ deleteApp: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.deleteApp; }, /* harmony export */ getApp: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.getApp; }, /* harmony export */ getApps: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.getApps; }, /* harmony export */ initializeApp: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.initializeApp; }, /* harmony export */ initializeServerApp: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.initializeServerApp; }, /* harmony export */ onLog: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.onLog; }, /* harmony export */ registerVersion: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion; }, /* harmony export */ setLogLevel: function() { return /* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.setLogLevel; } /* harmony export */ }); /* harmony import */ var _firebase_app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/app */ "./node_modules/@firebase/app/dist/esm/index.esm.js"); var name = "firebase"; var version = "12.15.0"; /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion)(name, version, 'app'); //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./node_modules/firebase/messaging/dist/esm/index.esm.js": /*!***************************************************************!*\ !*** ./node_modules/firebase/messaging/dist/esm/index.esm.js ***! \***************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ deleteToken: function() { return /* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.deleteToken; }, /* harmony export */ getMessaging: function() { return /* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.getMessaging; }, /* harmony export */ getToken: function() { return /* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.getToken; }, /* harmony export */ isSupported: function() { return /* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.isSupported; }, /* harmony export */ onMessage: function() { return /* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.onMessage; }, /* harmony export */ onRegistered: function() { return /* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.onRegistered; }, /* harmony export */ onUnregistered: function() { return /* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.onUnregistered; }, /* harmony export */ register: function() { return /* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.register; }, /* harmony export */ unregister: function() { return /* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.unregister; } /* harmony export */ }); /* harmony import */ var _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/messaging */ "./node_modules/@firebase/messaging/dist/esm/index.esm.js"); //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./node_modules/idb/build/index.js": /*!*****************************************!*\ !*** ./node_modules/idb/build/index.js ***! \*****************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ deleteDB: function() { return /* binding */ deleteDB; }, /* harmony export */ openDB: function() { return /* binding */ openDB; }, /* harmony export */ unwrap: function() { return /* reexport safe */ _wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.u; }, /* harmony export */ wrap: function() { return /* reexport safe */ _wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w; } /* harmony export */ }); /* harmony import */ var _wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./wrap-idb-value.js */ "./node_modules/idb/build/wrap-idb-value.js"); /** * Open a database. * * @param name Name of the database. * @param version Schema version. * @param callbacks Additional callbacks. */ function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) { const request = indexedDB.open(name, version); const openPromise = (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request); if (upgrade) { request.addEventListener('upgradeneeded', (event) => { upgrade((0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request.result), event.oldVersion, event.newVersion, (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request.transaction), event); }); } if (blocked) { request.addEventListener('blocked', (event) => blocked( // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405 event.oldVersion, event.newVersion, event)); } openPromise .then((db) => { if (terminated) db.addEventListener('close', () => terminated()); if (blocking) { db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event)); } }) .catch(() => { }); return openPromise; } /** * Delete a database. * * @param name Name of the database. */ function deleteDB(name, { blocked } = {}) { const request = indexedDB.deleteDatabase(name); if (blocked) { request.addEventListener('blocked', (event) => blocked( // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405 event.oldVersion, event)); } return (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request).then(() => undefined); } const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count']; const writeMethods = ['put', 'add', 'delete', 'clear']; const cachedMethods = new Map(); function getMethod(target, prop) { if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === 'string')) { return; } if (cachedMethods.get(prop)) return cachedMethods.get(prop); const targetFuncName = prop.replace(/FromIndex$/, ''); const useIndex = prop !== targetFuncName; const isWrite = writeMethods.includes(targetFuncName); if ( // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge. !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))) { return; } const method = async function (storeName, ...args) { // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :( const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly'); let target = tx.store; if (useIndex) target = target.index(args.shift()); // Must reject if op rejects. // If it's a write operation, must reject if tx.done rejects. // Must reject with op rejection first. // Must resolve with op value. // Must handle both promises (no unhandled rejections) return (await Promise.all([ target[targetFuncName](...args), isWrite && tx.done, ]))[0]; }; cachedMethods.set(prop, method); return method; } (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.r)((oldTraps) => ({ ...oldTraps, get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver), has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop), })); /***/ }), /***/ "./node_modules/idb/build/wrap-idb-value.js": /*!**************************************************!*\ !*** ./node_modules/idb/build/wrap-idb-value.js ***! \**************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ a: function() { return /* binding */ reverseTransformCache; }, /* harmony export */ i: function() { return /* binding */ instanceOfAny; }, /* harmony export */ r: function() { return /* binding */ replaceTraps; }, /* harmony export */ u: function() { return /* binding */ unwrap; }, /* harmony export */ w: function() { return /* binding */ wrap; } /* harmony export */ }); const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c); let idbProxyableTypes; let cursorAdvanceMethods; // This is a function to prevent it throwing up in node environments. function getIdbProxyableTypes() { return (idbProxyableTypes || (idbProxyableTypes = [ IDBDatabase, IDBObjectStore, IDBIndex, IDBCursor, IDBTransaction, ])); } // This is a function to prevent it throwing up in node environments. function getCursorAdvanceMethods() { return (cursorAdvanceMethods || (cursorAdvanceMethods = [ IDBCursor.prototype.advance, IDBCursor.prototype.continue, IDBCursor.prototype.continuePrimaryKey, ])); } const cursorRequestMap = new WeakMap(); const transactionDoneMap = new WeakMap(); const transactionStoreNamesMap = new WeakMap(); const transformCache = new WeakMap(); const reverseTransformCache = new WeakMap(); function promisifyRequest(request) { const promise = new Promise((resolve, reject) => { const unlisten = () => { request.removeEventListener('success', success); request.removeEventListener('error', error); }; const success = () => { resolve(wrap(request.result)); unlisten(); }; const error = () => { reject(request.error); unlisten(); }; request.addEventListener('success', success); request.addEventListener('error', error); }); promise .then((value) => { // Since cursoring reuses the IDBRequest (*sigh*), we cache it for later retrieval // (see wrapFunction). if (value instanceof IDBCursor) { cursorRequestMap.set(value, request); } // Catching to avoid "Uncaught Promise exceptions" }) .catch(() => { }); // This mapping exists in reverseTransformCache but doesn't doesn't exist in transformCache. This // is because we create many promises from a single IDBRequest. reverseTransformCache.set(promise, request); return promise; } function cacheDonePromiseForTransaction(tx) { // Early bail if we've already created a done promise for this transaction. if (transactionDoneMap.has(tx)) return; const done = new Promise((resolve, reject) => { const unlisten = () => { tx.removeEventListener('complete', complete); tx.removeEventListener('error', error); tx.removeEventListener('abort', error); }; const complete = () => { resolve(); unlisten(); }; const error = () => { reject(tx.error || new DOMException('AbortError', 'AbortError')); unlisten(); }; tx.addEventListener('complete', complete); tx.addEventListener('error', error); tx.addEventListener('abort', error); }); // Cache it for later retrieval. transactionDoneMap.set(tx, done); } let idbProxyTraps = { get(target, prop, receiver) { if (target instanceof IDBTransaction) { // Special handling for transaction.done. if (prop === 'done') return transactionDoneMap.get(target); // Polyfill for objectStoreNames because of Edge. if (prop === 'objectStoreNames') { return target.objectStoreNames || transactionStoreNamesMap.get(target); } // Make tx.store return the only store in the transaction, or undefined if there are many. if (prop === 'store') { return receiver.objectStoreNames[1] ? undefined : receiver.objectStore(receiver.objectStoreNames[0]); } } // Else transform whatever we get back. return wrap(target[prop]); }, set(target, prop, value) { target[prop] = value; return true; }, has(target, prop) { if (target instanceof IDBTransaction && (prop === 'done' || prop === 'store')) { return true; } return prop in target; }, }; function replaceTraps(callback) { idbProxyTraps = callback(idbProxyTraps); } function wrapFunction(func) { // Due to expected object equality (which is enforced by the caching in `wrap`), we // only create one new func per func. // Edge doesn't support objectStoreNames (booo), so we polyfill it here. if (func === IDBDatabase.prototype.transaction && !('objectStoreNames' in IDBTransaction.prototype)) { return function (storeNames, ...args) { const tx = func.call(unwrap(this), storeNames, ...args); transactionStoreNamesMap.set(tx, storeNames.sort ? storeNames.sort() : [storeNames]); return wrap(tx); }; } // Cursor methods are special, as the behaviour is a little more different to standard IDB. In // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense // with real promises, so each advance methods returns a new promise for the cursor object, or // undefined if the end of the cursor has been reached. if (getCursorAdvanceMethods().includes(func)) { return function (...args) { // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use // the original object. func.apply(unwrap(this), args); return wrap(cursorRequestMap.get(this)); }; } return function (...args) { // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use // the original object. return wrap(func.apply(unwrap(this), args)); }; } function transformCachableValue(value) { if (typeof value === 'function') return wrapFunction(value); // This doesn't return, it just creates a 'done' promise for the transaction, // which is later returned for transaction.done (see idbObjectHandler). if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value); if (instanceOfAny(value, getIdbProxyableTypes())) return new Proxy(value, idbProxyTraps); // Return the same value back if we're not going to transform it. return value; } function wrap(value) { // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached. if (value instanceof IDBRequest) return promisifyRequest(value); // If we've already transformed this value before, reuse the transformed value. // This is faster, but it also provides object equality. if (transformCache.has(value)) return transformCache.get(value); const newValue = transformCachableValue(value); // Not all types are transformed. // These may be primitive types, so they can't be WeakMap keys. if (newValue !== value) { transformCache.set(value, newValue); reverseTransformCache.set(newValue, value); } return newValue; } const unwrap = (value) => reverseTransformCache.get(value); /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs": /*!**************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/common/constant.mjs ***! \**************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DoubleUnicodePrefixReg: function() { return /* binding */ DoubleUnicodePrefixReg; }, /* harmony export */ DoubleUnicodeReg: function() { return /* binding */ DoubleUnicodeReg; }, /* harmony export */ DoubleUnicodeSuffixReg: function() { return /* binding */ DoubleUnicodeSuffixReg; }, /* harmony export */ Priority: function() { return /* binding */ Priority; }, /* harmony export */ Probability: function() { return /* binding */ Probability; } /* harmony export */ }); const DoubleUnicodePrefixReg = /^[\uD800-\uDBFF]$/; const DoubleUnicodeSuffixReg = /^[\uDC00-\uDFFF]$/; const DoubleUnicodeReg = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g; var Probability; (function (Probability) { Probability[Probability["Unknown"] = 1e-13] = "Unknown"; Probability[Probability["Rule"] = 1e-12] = "Rule"; Probability[Probability["DICT"] = 2e-8] = "DICT"; Probability[Probability["Surname"] = 1] = "Surname"; Probability[Probability["Custom"] = 1] = "Custom"; })(Probability || (Probability = {})); const Priority = { Normal: 1, Surname: 10, Custom: 100, }; /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/common/segmentit/index.mjs": /*!*********************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/common/segmentit/index.mjs ***! \*********************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* empty/unused harmony star reexport */ /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AC: function() { return /* binding */ AC; }, /* harmony export */ TokenizationAlgorithm: function() { return /* binding */ TokenizationAlgorithm; }, /* harmony export */ acTree: function() { return /* binding */ acTree; }, /* harmony export */ ensureAcBuilt: function() { return /* binding */ ensureAcBuilt; }, /* harmony export */ scheduleAcBuild: function() { return /* binding */ scheduleAcBuild; } /* harmony export */ }); /* harmony import */ var _data_patterns_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../data/patterns.mjs */ "./node_modules/pinyin-pro/dist/esm/data/patterns.mjs"); /* harmony import */ var _max_probability_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./max-probability.mjs */ "./node_modules/pinyin-pro/dist/esm/common/segmentit/max-probability.mjs"); /* harmony import */ var _min_tokenization_mjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./min-tokenization.mjs */ "./node_modules/pinyin-pro/dist/esm/common/segmentit/min-tokenization.mjs"); /* harmony import */ var _reverse_max_match_mjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./reverse-max-match.mjs */ "./node_modules/pinyin-pro/dist/esm/common/segmentit/reverse-max-match.mjs"); /* harmony import */ var _constant_mjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../constant.mjs */ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs"); /* harmony import */ var _utils_mjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../utils.mjs */ "./node_modules/pinyin-pro/dist/esm/common/utils.mjs"); var TokenizationAlgorithm; (function (TokenizationAlgorithm) { TokenizationAlgorithm[TokenizationAlgorithm["ReverseMaxMatch"] = 1] = "ReverseMaxMatch"; TokenizationAlgorithm[TokenizationAlgorithm["MaxProbability"] = 2] = "MaxProbability"; TokenizationAlgorithm[TokenizationAlgorithm["MinTokenization"] = 3] = "MinTokenization"; })(TokenizationAlgorithm || (TokenizationAlgorithm = {})); class TrieNode { constructor(parent, key = "") { this.children = new Map(); this.fail = null; this.patterns = []; this.parent = parent; this.key = key; } } class AC { constructor() { this.dictMap = new Map(); this.queues = []; this.root = new TrieNode(null); } build(patternList) { this.buildTrie(patternList); this.buildFailPointer(); } // 构建 trie 树 buildTrie(patternList) { for (let pattern of patternList) { const zhChars = (0,_utils_mjs__WEBPACK_IMPORTED_MODULE_6__.splitString)(pattern.zh); let cur = this.root; for (let i = 0; i < zhChars.length; i++) { let c = zhChars[i]; if (!cur.children.has(c)) { const trieNode = new TrieNode(cur, c); cur.children.set(c, trieNode); this.addNodeToQueues(trieNode, i + 1); } cur = cur.children.get(c); } this.insertPattern(cur.patterns, pattern); pattern.node = cur; this.addPatternToDictMap(pattern); } } // 构建失败指针 buildFailPointer() { let queue = []; let queueIndex = 0; this.queues.forEach((_queue) => { queue = queue.concat(_queue); }); this.queues = []; while (queue.length > queueIndex) { let node = queue[queueIndex++]; let failNode = node.parent && node.parent.fail; let key = node.key; while (failNode && !failNode.children.has(key)) { failNode = failNode.fail; } if (!failNode) { node.fail = this.root; } else { node.fail = failNode.children.get(key); } } } // 将 pattern 添加到 dictMap 中 addPatternToDictMap(pattern) { if (!this.dictMap.has(pattern.dict)) { this.dictMap.set(pattern.dict, new Set()); } this.dictMap.get(pattern.dict).add(pattern); } addNodeToQueues(trieNode, depth) { if (!this.queues[depth]) { this.queues[depth] = []; } this.queues[depth].push(trieNode); } // 按照优先级插入 pattern insertPattern(patterns, pattern) { for (let i = patterns.length - 1; i >= 0; i--) { const _pattern = patterns[i]; if (pattern.priority === _pattern.priority && pattern.probability >= _pattern.probability) { patterns[i + 1] = _pattern; } else if (pattern.priority > _pattern.priority) { patterns[i + 1] = _pattern; } else { patterns[i + 1] = pattern; return; } } patterns[0] = pattern; } removeDict(dictName) { if (this.dictMap.has(dictName)) { const set = this.dictMap.get(dictName); set.forEach((pattern) => { pattern.node.patterns = pattern.node.patterns.filter((_pattern) => _pattern !== pattern); }); this.dictMap.delete(dictName); } } // 搜索字符串返回匹配的模式串 match(text, surname, zhChars = (0,_utils_mjs__WEBPACK_IMPORTED_MODULE_6__.splitString)(text)) { let cur = this.root; let result = []; for (let i = 0; i < zhChars.length; i++) { let c = zhChars[i]; let next = cur.children.size ? cur.children.get(c) : undefined; while (!next && cur !== this.root) { if (!cur.fail) { cur = this.root; break; } cur = cur.fail; next = cur.children.size ? cur.children.get(c) : undefined; } if (next) { cur = next; const pattern = cur.patterns.find((item) => { if (surname === "off") { return item.priority !== _constant_mjs__WEBPACK_IMPORTED_MODULE_5__.Priority.Surname; } else if (surname === "head") { return item.length - 1 - i === 0; } else { return true; } }); if (pattern) { result.push(Object.assign(Object.assign({}, pattern), { index: i - pattern.length + 1 })); } let failNode = cur.fail; while (failNode !== null) { const pattern = failNode.patterns.find((item) => { if (surname === "off") { return item.priority !== _constant_mjs__WEBPACK_IMPORTED_MODULE_5__.Priority.Surname; } else if (surname === "head") { return item.length - 1 - i === 0; } else { return true; } }); if (pattern) { result.push(Object.assign(Object.assign({}, pattern), { index: i - pattern.length + 1 })); } failNode = failNode.fail; } } } return result; } search(text, surname, algorithm = 2 /* TokenizationAlgorithm.MaxProbability */, zhChars = (0,_utils_mjs__WEBPACK_IMPORTED_MODULE_6__.splitString)(text)) { const patterns = this.match(text, surname, zhChars); if (algorithm === 1 /* TokenizationAlgorithm.ReverseMaxMatch */) { return (0,_reverse_max_match_mjs__WEBPACK_IMPORTED_MODULE_4__.reverseMaxMatch)(patterns); } else if (algorithm === 3 /* TokenizationAlgorithm.MinTokenization */) { return (0,_min_tokenization_mjs__WEBPACK_IMPORTED_MODULE_3__.minTokenization)(patterns, zhChars.length); } return (0,_max_probability_mjs__WEBPACK_IMPORTED_MODULE_2__.maxProbability)(patterns, zhChars.length); } } let acBuilt = false; const acTree = new AC(); function ensureAcBuilt() { if (!acBuilt) { acTree.build(_data_patterns_mjs__WEBPACK_IMPORTED_MODULE_0__.PatternsNormal); acBuilt = true; } } function scheduleAcBuild() { if (typeof requestIdleCallback === "function") { requestIdleCallback(() => ensureAcBuilt()); } else { setTimeout(ensureAcBuilt, 0); } } scheduleAcBuild(); /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/common/segmentit/max-probability.mjs": /*!*******************************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/common/segmentit/max-probability.mjs ***! \*******************************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ maxProbability: function() { return /* binding */ maxProbability; } /* harmony export */ }); /* harmony import */ var _constant_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../constant.mjs */ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs"); // 根据 probability 和 decimal 获取两个概率中最大的 function getMaxProbability(a, b) { if (!a) { return b; } if (a.decimal < b.decimal) { return a; } else if (a.decimal === b.decimal) { return a.probability > b.probability ? a : b; } else { return b; } } // probability 小于 1e-300 时,为防止小数溢出需要进位 function checkDecimal(prob) { if (prob.probability < 1e-300) { prob.probability *= 1e300; prob.decimal += 1; } } function getPatternDecimal(pattern) { if (pattern.priority === _constant_mjs__WEBPACK_IMPORTED_MODULE_0__.Priority.Custom) { return -(pattern.length * pattern.length * 100); } if (pattern.priority === _constant_mjs__WEBPACK_IMPORTED_MODULE_0__.Priority.Surname) { return -(pattern.length * pattern.length * 10); } return 0; } // 最大概率算法 function maxProbability(patterns, length) { const dp = []; const terminalDP = { probability: 1, decimal: 0, nextIndex: length, }; let patternIndex = patterns.length - 1; let pattern = patterns[patternIndex]; // 按照长度去除重叠词 for (let i = length - 1; i >= 0; i--) { // suffix const suffixDP = i + 1 >= length ? terminalDP : dp[i + 1]; const nextIndex = suffixDP.pattern ? i + 1 : suffixDP.nextIndex; while (pattern && pattern.index + pattern.length - 1 === i) { const startIndex = pattern.index; const curDP = { probability: pattern.probability * suffixDP.probability, decimal: suffixDP.decimal + getPatternDecimal(pattern), pattern, nextIndex, }; checkDecimal(curDP); dp[startIndex] = getMaxProbability(dp[startIndex], curDP); pattern = patterns[--patternIndex]; } // dp[i] const iDP = { probability: 1e-13 /* Probability.Unknown */ * suffixDP.probability, decimal: 0, nextIndex, }; checkDecimal(iDP); dp[i] = getMaxProbability(dp[i], iDP); } const result = []; let index = 0; while (index < length) { const item = dp[index]; if (item.pattern) { result.push(item.pattern); } index = item.nextIndex; } return result; } /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/common/segmentit/min-tokenization.mjs": /*!********************************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/common/segmentit/min-tokenization.mjs ***! \********************************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ minTokenization: function() { return /* binding */ minTokenization; } /* harmony export */ }); /* harmony import */ var _constant_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../constant.mjs */ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs"); // 取最少分词数 function getMinCount(a, b) { if (!a) { return b; } return a.count <= b.count ? a : b; } function getPatternCount(pattern) { if (pattern.priority === _constant_mjs__WEBPACK_IMPORTED_MODULE_0__.Priority.Custom) { return -(pattern.length * pattern.length * 100000); } if (pattern.priority === _constant_mjs__WEBPACK_IMPORTED_MODULE_0__.Priority.Surname) { return -(pattern.length * pattern.length * 100); } return 1; } // 最少分词算法 function minTokenization(patterns, length) { const dp = []; let patternIndex = patterns.length - 1; let pattern = patterns[patternIndex]; // 按照长度去除重叠词 for (let i = length - 1; i >= 0; i--) { // suffix const suffixDP = i + 1 >= length ? { count: 0, patterns: [] } : dp[i + 1]; while (pattern && pattern.index + pattern.length - 1 === i) { const startIndex = pattern.index; const curDP = { count: getPatternCount(pattern) + suffixDP.count, patterns: suffixDP.patterns, concatPattern: pattern }; dp[startIndex] = getMinCount(dp[startIndex], curDP); pattern = patterns[--patternIndex]; } // dp[i] const iDP = { count: 1 + suffixDP.count, patterns: suffixDP.patterns, }; dp[i] = getMinCount(dp[i], iDP); if (dp[i].concatPattern) { dp[i].patterns = dp[i].patterns.concat(dp[i].concatPattern); dp[i].concatPattern = undefined; delete dp[i + 1]; } } return dp[0].patterns.reverse(); } /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/common/segmentit/reverse-max-match.mjs": /*!*********************************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/common/segmentit/reverse-max-match.mjs ***! \*********************************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ reverseMaxMatch: function() { return /* binding */ reverseMaxMatch; } /* harmony export */ }); // 判断 pre 是否可以被忽略的重叠词 function isIgnorablePattern(cur, pre) { // 未重叠 if (pre.index + pre.length <= cur.index) { return false; } if (pre.priority > cur.priority) { return false; } if (pre.priority === cur.priority && pre.length > cur.length) { return false; } return true; } // 逆向最大匹配算法 function reverseMaxMatch(patterns) { const filteredArr = []; // 按照长度去除重叠词 for (let i = patterns.length - 1; i >= 0;) { const { index } = patterns[i]; let j = i - 1; while (j >= 0 && isIgnorablePattern(patterns[i], patterns[j])) { j--; } if (j < 0 || patterns[j].index + patterns[j].length <= index) { filteredArr.push(patterns[i]); } i = j; } return filteredArr.reverse(); } /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/common/utils.mjs": /*!***********************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/common/utils.mjs ***! \***********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ FastDictFactory: function() { return /* binding */ FastDictFactory; }, /* harmony export */ splitString: function() { return /* binding */ splitString; }, /* harmony export */ stringLength: function() { return /* binding */ stringLength; } /* harmony export */ }); /* harmony import */ var _constant_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./constant.mjs */ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs"); function stringLength(text) { var _a; return text.length - (((_a = text.match(_constant_mjs__WEBPACK_IMPORTED_MODULE_0__.DoubleUnicodeReg)) === null || _a === void 0 ? void 0 : _a.length) || 0); } // 双音节字符处理 function splitString(text) { _constant_mjs__WEBPACK_IMPORTED_MODULE_0__.DoubleUnicodeReg.lastIndex = 0; if (!_constant_mjs__WEBPACK_IMPORTED_MODULE_0__.DoubleUnicodeReg.test(text)) { return text.split(""); } const result = []; let i = 0; while (i < text.length) { const char = text[i]; if (_constant_mjs__WEBPACK_IMPORTED_MODULE_0__.DoubleUnicodePrefixReg.test(char) && _constant_mjs__WEBPACK_IMPORTED_MODULE_0__.DoubleUnicodeSuffixReg.test(text[i + 1])) { result.push(text.substring(i, i + 2)); i += 2; } else { result.push(char); i += 1; } } return result; } class FastDictFactory { constructor() { this.NumberDICT = []; this.StringDICT = new Map(); } get(word) { if (word.length > 1) { return this.StringDICT.get(word); } else { const code = word.charCodeAt(0); return this.NumberDICT[code]; } } set(word, pinyin) { if (word.length > 1) { this.StringDICT.set(word, pinyin); } else { const code = word.charCodeAt(0); this.NumberDICT[code] = pinyin; } } clear() { this.NumberDICT = []; this.StringDICT.clear(); } } /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/core/custom/state.mjs": /*!****************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/core/custom/state.mjs ***! \****************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ customMultipleDict: function() { return /* binding */ customMultipleDict; }, /* harmony export */ customPolyphonicDict: function() { return /* binding */ customPolyphonicDict; } /* harmony export */ }); /* harmony import */ var _common_utils_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../common/utils.mjs */ "./node_modules/pinyin-pro/dist/esm/common/utils.mjs"); const customMultipleDict = new _common_utils_mjs__WEBPACK_IMPORTED_MODULE_0__.FastDictFactory(); const customPolyphonicDict = new _common_utils_mjs__WEBPACK_IMPORTED_MODULE_0__.FastDictFactory(); /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/core/pinyin/all.mjs": /*!**************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/core/pinyin/all.mjs ***! \**************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getAllPinyin: function() { return /* binding */ getAllPinyin; } /* harmony export */ }); /* harmony import */ var _data_dict1_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../data/dict1.mjs */ "./node_modules/pinyin-pro/dist/esm/data/dict1.mjs"); /* harmony import */ var _custom_state_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../custom/state.mjs */ "./node_modules/pinyin-pro/dist/esm/core/custom/state.mjs"); /* harmony import */ var _data_surname_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../data/surname.mjs */ "./node_modules/pinyin-pro/dist/esm/data/surname.mjs"); /** 获取单字的全部拼音,供 pinyin、polyphonic 和 match 复用。 */ const getAllPinyin = (char, surname = "off") => { let pinyin = _data_dict1_mjs__WEBPACK_IMPORTED_MODULE_0__["default"].get(char) ? _data_dict1_mjs__WEBPACK_IMPORTED_MODULE_0__["default"].get(char).split(" ") : []; if (_custom_state_mjs__WEBPACK_IMPORTED_MODULE_1__.customMultipleDict.get(char)) { pinyin = _custom_state_mjs__WEBPACK_IMPORTED_MODULE_1__.customMultipleDict.get(char).split(" "); } else if (surname !== "off") { const surnamePinyin = _data_surname_mjs__WEBPACK_IMPORTED_MODULE_2__["default"][char]; if (surnamePinyin) { pinyin = [surnamePinyin].concat(pinyin.filter((py) => py !== surnamePinyin)); } } return pinyin; }; /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/core/pinyin/handle.mjs": /*!*****************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/core/pinyin/handle.mjs ***! \*****************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* empty/unused harmony star reexport */ /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getFinalParts: function() { return /* binding */ getFinalParts; }, /* harmony export */ getFinalPartsFromFinal: function() { return /* binding */ getFinalPartsFromFinal; }, /* harmony export */ getFirstLetter: function() { return /* binding */ getFirstLetter; }, /* harmony export */ getInitialAndFinal: function() { return /* binding */ getInitialAndFinal; }, /* harmony export */ getMultiplePinyin: function() { return /* binding */ getMultiplePinyin; }, /* harmony export */ getNumOfTone: function() { return /* binding */ getNumOfTone; }, /* harmony export */ getPinyin: function() { return /* binding */ getPinyin; }, /* harmony export */ getPinyinWithNum: function() { return /* binding */ getPinyinWithNum; }, /* harmony export */ getPinyinWithoutTone: function() { return /* binding */ getPinyinWithoutTone; }, /* harmony export */ getSingleWordPinyin: function() { return /* binding */ getSingleWordPinyin; }, /* harmony export */ processToneSandhi: function() { return /* binding */ processToneSandhi; } /* harmony export */ }); /* harmony import */ var _data_special_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../data/special.mjs */ "./node_modules/pinyin-pro/dist/esm/data/special.mjs"); /* harmony import */ var _data_dict1_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../data/dict1.mjs */ "./node_modules/pinyin-pro/dist/esm/data/dict1.mjs"); /* harmony import */ var _all_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./all.mjs */ "./node_modules/pinyin-pro/dist/esm/core/pinyin/all.mjs"); /* harmony import */ var _common_segmentit_index_mjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../common/segmentit/index.mjs */ "./node_modules/pinyin-pro/dist/esm/common/segmentit/index.mjs"); /* harmony import */ var _common_constant_mjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../common/constant.mjs */ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs"); /* harmony import */ var _common_utils_mjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../common/utils.mjs */ "./node_modules/pinyin-pro/dist/esm/common/utils.mjs"); /* harmony import */ var _traditional_index_mjs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../traditional/index.mjs */ "./node_modules/pinyin-pro/dist/esm/core/traditional/index.mjs"); const getSingleWordPinyin = (char) => { const pinyin = _data_dict1_mjs__WEBPACK_IMPORTED_MODULE_1__["default"].get(char); // 若查到, 则返回第一个拼音; 若未查到, 返回原字符 if (!pinyin) return char; const index = pinyin.indexOf(" "); return index === -1 ? pinyin : pinyin.slice(0, index); }; const getTraditionalWords = (word) => { const traditionalWords = []; const traditionalDict = (0,_traditional_index_mjs__WEBPACK_IMPORTED_MODULE_7__.getTraditionalDict)(); for (let i = 0; i < word.length; i++) { const key = word[i]; const code = key.charCodeAt(0); if (traditionalDict[code]) { traditionalWords[i] = traditionalDict[code]; } else { traditionalWords[i] = key; } } return traditionalWords.join(""); }; const getPinyin = (word, list, surname, segmentit, traditional, zhChars = (0,_common_utils_mjs__WEBPACK_IMPORTED_MODULE_6__.splitString)(word)) => { (0,_common_segmentit_index_mjs__WEBPACK_IMPORTED_MODULE_4__.ensureAcBuilt)(); const searchWord = traditional ? getTraditionalWords(word) : word; const searchChars = traditional ? (0,_common_utils_mjs__WEBPACK_IMPORTED_MODULE_6__.splitString)(searchWord) : zhChars; const matches = _common_segmentit_index_mjs__WEBPACK_IMPORTED_MODULE_4__.acTree.search(searchWord, surname, segmentit, searchChars); let matchIndex = 0; const processFuncs = getProcessFuncs(word); for (let i = 0; i < zhChars.length;) { const match = matches[matchIndex]; if (match && i === match.index) { if (match.length === 1 && match.priority <= _common_constant_mjs__WEBPACK_IMPORTED_MODULE_5__.Priority.Normal) { const char = zhChars[i]; match.zh = char; let pinyin = ""; pinyin = processSepecialPinyin(char, zhChars[i - 1], zhChars[i + 1], processFuncs); list[i] = { origin: char, result: pinyin, isZh: pinyin !== char, originPinyin: pinyin, }; i++; matchIndex++; continue; } const pinyins = match.pinyin.split(" "); let pinyinIndex = 0; if (traditional) { match.zh = zhChars .slice(match.index, match.index + match.length) .join(""); } for (let j = 0; j < match.length; j++) { list[i + j] = { origin: zhChars[j + match.index], result: pinyins[pinyinIndex] || "", isZh: true, originPinyin: pinyins[pinyinIndex] || "", }; pinyinIndex++; } i += match.length; matchIndex++; } else { const char = zhChars[i]; let pinyin = ""; pinyin = processSepecialPinyin(char, zhChars[i - 1], zhChars[i + 1], processFuncs); list[i] = { origin: char, result: pinyin, isZh: pinyin !== char, originPinyin: pinyin, }; i++; } } return { list, matches }; }; const getPinyinWithoutTone = (pinyin) => { return pinyin .replace(/(ā|á|ǎ|à)/g, "a") .replace(/(ō|ó|ǒ|ò)/g, "o") .replace(/(ē|é|ě|è)/g, "e") .replace(/(ī|í|ǐ|ì)/g, "i") .replace(/(ū|ú|ǔ|ù)/g, "u") .replace(/(ǖ|ǘ|ǚ|ǜ)/g, "ü") .replace(/(n̄|ń|ň|ǹ)/g, "n") .replace(/(m̄|ḿ|m̌|m̀)/g, "m") .replace(/(ê̄|ế|ê̌|ề)/g, "ê"); }; const getMultiplePinyin = (word, surname = "off") => { let pinyin = (0,_all_mjs__WEBPACK_IMPORTED_MODULE_2__.getAllPinyin)(word, surname); if (pinyin.length > 0) { return pinyin.map((value) => ({ origin: word, result: value, isZh: true, originPinyin: value, })); } else { return [ { origin: word, result: word, isZh: false, originPinyin: word, }, ]; } }; const getInitialAndFinal = (pinyin, initialPattern) => { const pinyin_arr = pinyin.split(" "); const initial_arr = []; const final_arr = []; for (let _pinyin of pinyin_arr) { for (let _initial of _data_special_mjs__WEBPACK_IMPORTED_MODULE_0__.InitialList) { if (_pinyin.startsWith(_initial)) { let _final = _pinyin.slice(_initial.length); if (_data_special_mjs__WEBPACK_IMPORTED_MODULE_0__.SpecialInitialList.indexOf(_initial) !== -1 && _data_special_mjs__WEBPACK_IMPORTED_MODULE_0__.SpecialFinalList.indexOf(_final) !== -1) { // 针对 jqx 的 u 特殊处理 _final = _data_special_mjs__WEBPACK_IMPORTED_MODULE_0__.SpecialFinalMap[_final]; } initial_arr.push(_initial); final_arr.push(_final); break; } } } if (initialPattern === "standard") { initial_arr.forEach((initial, index) => { if (initial === "y" || initial === "w") { initial_arr[index] = ""; } }); } return { final: final_arr.join(" "), initial: initial_arr.join(" "), // 声母 }; }; function getFinalPartsFromFinal(final) { let head = "", body = "", tail = ""; if (_data_special_mjs__WEBPACK_IMPORTED_MODULE_0__.doubleFinalList.indexOf(getPinyinWithoutTone(final)) !== -1) { head = final[0]; body = final[1]; tail = final.slice(2); } else { body = final[0] || ""; tail = final.slice(1) || ""; } return { head, body, tail }; } const getFinalParts = (pinyin) => { const { final } = getInitialAndFinal(pinyin); return getFinalPartsFromFinal(final); }; const getNumOfTone = (pinyin) => { const reg_tone1 = /(ā|ō|ē|ī|ū|ǖ|n̄|m̄|ê̄)/; const reg_tone2 = /(á|ó|é|í|ú|ǘ|ń|ḿ|ế)/; const reg_tone3 = /(ǎ|ǒ|ě|ǐ|ǔ|ǚ|ň|m̌|ê̌)/; const reg_tone4 = /(à|ò|è|ì|ù|ǜ|ǹ|m̀|ề)/; const reg_tone0 = /(a|o|e|i|u|ü|ê)/; const special_tone = /(n|m)$/; const tone_num_arr = []; const pinyin_arr = pinyin.split(" "); pinyin_arr.forEach((_pinyin) => { if (reg_tone1.test(_pinyin)) { tone_num_arr.push("1"); } else if (reg_tone2.test(_pinyin)) { tone_num_arr.push("2"); } else if (reg_tone3.test(_pinyin)) { tone_num_arr.push("3"); } else if (reg_tone4.test(_pinyin)) { tone_num_arr.push("4"); } else if (reg_tone0.test(_pinyin)) { tone_num_arr.push("0"); } else if (special_tone.test(_pinyin)) { tone_num_arr.push("0"); } else { tone_num_arr.push(""); } }); return tone_num_arr.join(" "); }; const getPinyinWithNum = (pinyin, originPinyin) => { const pinyin_arr = getPinyinWithoutTone(pinyin).split(" "); const tone_num_arr = getNumOfTone(originPinyin).split(" "); const res_arr = []; pinyin_arr.forEach((item, index) => { res_arr.push(`${item}${tone_num_arr[index]}`); }); return res_arr.join(" "); }; const getFirstLetter = (pinyin, isZh) => { const first_letter_arr = []; const pinyin_arr = pinyin.split(" "); pinyin_arr.forEach((pinyin) => { first_letter_arr.push(isZh ? pinyin[0] : pinyin); }); return first_letter_arr.join(" "); }; // 处理「一」和 「不」字的变调 function processToneSandhi(cur, pre, next) { if (_data_special_mjs__WEBPACK_IMPORTED_MODULE_0__.toneSandhiList.indexOf(cur) === -1) { return getSingleWordPinyin(cur); } // 轻声变调:说不说,说一说,叠词之间发音为轻声 if (pre === next && pre && getSingleWordPinyin(pre) !== pre) { return getPinyinWithoutTone(getSingleWordPinyin(cur)); } // 「一」和 「不」字变调处理 if (next && !_data_special_mjs__WEBPACK_IMPORTED_MODULE_0__.toneSandhiIgnoreSuffix[cur].includes(next)) { const nextPinyin = getSingleWordPinyin(next); if (nextPinyin !== next) { const nextTone = getNumOfTone(nextPinyin); const pinyinMap = _data_special_mjs__WEBPACK_IMPORTED_MODULE_0__.toneSandhiMap[cur]; for (let pinyin in pinyinMap) { const tones = pinyinMap[pinyin]; if (tones.indexOf(Number(nextTone)) !== -1) { return pinyin; } } } } } // 处理「了」字的变调 function processToneSandhiLiao(cur, pre, _) { if (cur === "了" && (!pre || !_data_dict1_mjs__WEBPACK_IMPORTED_MODULE_1__["default"].get(pre))) { return "liǎo"; } } // 处理叠字符[々] function processReduplicationChar(cur, pre, _) { if (cur === "々") { if (!pre || !_data_dict1_mjs__WEBPACK_IMPORTED_MODULE_1__["default"].get(pre)) { return "tóng"; } else { return _data_dict1_mjs__WEBPACK_IMPORTED_MODULE_1__["default"].get(pre).split(" ")[0]; } } } function getProcessFuncs(text) { const processes = []; if (text.includes("々")) { processes.push(processReduplicationChar); } processes.push(processToneSandhiLiao); processes.push(processToneSandhi); return processes; } function processSepecialPinyin(cur, pre, next, funcs) { for (let func of funcs) { const res = func(cur, pre, next); if (res) { return res; } } return getSingleWordPinyin(cur); } /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/core/pinyin/index.mjs": /*!****************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/core/pinyin/index.mjs ***! \****************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ pinyin: function() { return /* binding */ pinyin; } /* harmony export */ }); /* harmony import */ var _common_utils_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../common/utils.mjs */ "./node_modules/pinyin-pro/dist/esm/common/utils.mjs"); /* harmony import */ var _handle_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./handle.mjs */ "./node_modules/pinyin-pro/dist/esm/core/pinyin/handle.mjs"); /* harmony import */ var _middlewares_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./middlewares.mjs */ "./node_modules/pinyin-pro/dist/esm/core/pinyin/middlewares.mjs"); const DEFAULT_OPTIONS = { pattern: "pinyin", toneType: "symbol", type: "string", multiple: false, mode: "normal", removeNonZh: false, nonZh: "spaced", v: false, separator: " ", toneSandhi: true, segmentit: 2 /* TokenizationAlgorithm.MaxProbability */, }; /** * @description: 获取汉语字符串的拼音 * @param {string} word 要转换的汉语字符串 * @param {CompleteOptions=} options 配置项 * @return {string | string[] | AllData[]} options.type 为 string 时,返回字符串,中间用空格隔开;为 array 时,返回拼音字符串数组;为 all 时返回全部信息的数组 */ function pinyin(word, options) { options = Object.assign(Object.assign({}, DEFAULT_OPTIONS), (options || {})); // 校验 word 类型是否正确 const legal = (0,_middlewares_mjs__WEBPACK_IMPORTED_MODULE_2__.validateType)(word); if (!legal) { return word; } // 传入空字符串 if (word === "") { return options.type === "array" || options.type === "all" ? [] : ""; } if (options.surname === undefined) { if (options.mode === "surname") { options.surname = "all"; } else { options.surname = "off"; } } if (options.type === "all") { options.pattern = "pinyin"; } if (options.pattern === "num") { options.toneType = "none"; } if (options.removeNonZh) { options.nonZh = "removed"; } const zhChars = (0,_common_utils_mjs__WEBPACK_IMPORTED_MODULE_0__.splitString)(word); let _list = Array(zhChars.length); let { list } = (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getPinyin)(word, _list, options.surname, options.segmentit, options.traditional, zhChars); // 一和不变调处理 list = (0,_middlewares_mjs__WEBPACK_IMPORTED_MODULE_2__.middlewareToneSandhi)(list, options.toneSandhi); // nonZh 参数及 removeNonZh 参数 list = (0,_middlewares_mjs__WEBPACK_IMPORTED_MODULE_2__.middleWareNonZh)(list, options); // multiple 参数 const multipleList = (0,_middlewares_mjs__WEBPACK_IMPORTED_MODULE_2__.middlewareMultiple)(word, options); if (multipleList) { list = multipleList; } // pattern 参数 (0,_middlewares_mjs__WEBPACK_IMPORTED_MODULE_2__.middlewarePattern)(list, options); // toneType参数处理 (0,_middlewares_mjs__WEBPACK_IMPORTED_MODULE_2__.middlewareToneType)(list, options); // v参数处理 (0,_middlewares_mjs__WEBPACK_IMPORTED_MODULE_2__.middlewareV)(list, options); // type 参数处理 return (0,_middlewares_mjs__WEBPACK_IMPORTED_MODULE_2__.middlewareType)(list, options, word); } /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/core/pinyin/middlewares.mjs": /*!**********************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/core/pinyin/middlewares.mjs ***! \**********************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ isNonZhScope: function() { return /* binding */ isNonZhScope; }, /* harmony export */ middleWareNonZh: function() { return /* binding */ middleWareNonZh; }, /* harmony export */ middlewareMultiple: function() { return /* binding */ middlewareMultiple; }, /* harmony export */ middlewarePattern: function() { return /* binding */ middlewarePattern; }, /* harmony export */ middlewareToneSandhi: function() { return /* binding */ middlewareToneSandhi; }, /* harmony export */ middlewareToneType: function() { return /* binding */ middlewareToneType; }, /* harmony export */ middlewareType: function() { return /* binding */ middlewareType; }, /* harmony export */ middlewareV: function() { return /* binding */ middlewareV; }, /* harmony export */ validateType: function() { return /* binding */ validateType; } /* harmony export */ }); /* harmony import */ var _common_utils_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../common/utils.mjs */ "./node_modules/pinyin-pro/dist/esm/common/utils.mjs"); /* harmony import */ var _handle_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./handle.mjs */ "./node_modules/pinyin-pro/dist/esm/core/pinyin/handle.mjs"); /* harmony import */ var _data_dict1_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../data/dict1.mjs */ "./node_modules/pinyin-pro/dist/esm/data/dict1.mjs"); /* harmony import */ var _all_mjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./all.mjs */ "./node_modules/pinyin-pro/dist/esm/core/pinyin/all.mjs"); // 验证输入是否为字符串 const validateType = (word) => { if (typeof word !== "string") { console.error("The first param of pinyin is error: " + word + ' is not assignable to type "string".'); return false; } else { return true; } }; function isNonZhScope(char, scope) { if (scope instanceof RegExp) { // Global and sticky regexes retain lastIndex between calls. if (scope.global || scope.sticky) { scope.lastIndex = 0; } return scope.test(char); } return true; } // nonZh 属性处理 const middleWareNonZh = (list, options) => { let nonZh = options.nonZh; if (nonZh === "removed") { return list.filter((item) => item.isZh || !isNonZhScope(item.origin, options.nonZhScope)); } else if (nonZh === "consecutive") { for (let i = list.length - 2; i >= 0; i--) { const cur = list[i]; const pre = list[i + 1]; if (!cur.isZh && !pre.isZh && isNonZhScope(cur.origin, options.nonZhScope) && isNonZhScope(pre.origin, options.nonZhScope)) { cur.origin += pre.origin; cur.result += pre.result; pre.delete = true; } } return list.filter((item) => !item.delete); } else { return list; } }; // multiple 属性处理 const middlewareMultiple = (word, options) => { if (options.multiple && (0,_common_utils_mjs__WEBPACK_IMPORTED_MODULE_0__.stringLength)(word) === 1) { return (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getMultiplePinyin)(word, options.surname); } else { return false; } }; // pattern 属性处理 const middlewarePattern = (list, options) => { switch (options.pattern) { case "pinyin": break; case "num": list.forEach((item) => { item.result = item.isZh ? (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getNumOfTone)(item.result) : ""; }); break; case "initial": list.forEach((item) => { item.result = item.isZh ? (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getInitialAndFinal)(item.result, options.initialPattern).initial : ""; }); break; case "final": list.forEach((item) => { item.result = item.isZh ? (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getInitialAndFinal)(item.result, options.initialPattern).final : ""; }); break; case "first": list.forEach((item) => { item.result = (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getFirstLetter)(item.result, item.isZh); }); break; case "finalHead": list.forEach((item) => { item.result = item.isZh ? (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getFinalParts)(item.result).head : ""; }); break; case "finalBody": list.forEach((item) => { item.result = item.isZh ? (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getFinalParts)(item.result).body : ""; }); break; case "finalTail": list.forEach((item) => { item.result = item.isZh ? (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getFinalParts)(item.result).tail : ""; }); break; } }; // toneType 属性处理 const middlewareToneType = (list, options) => { switch (options.toneType) { case "symbol": break; case "none": list.forEach((item) => { if (item.isZh) { item.result = (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getPinyinWithoutTone)(item.result); } }); break; case "num": { list.forEach((item) => { if (item.isZh) { item.result = (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getPinyinWithNum)(item.result, item.originPinyin); } }); break; } } }; // v 属性处理 const middlewareV = (list, options) => { if (options.v) { list.forEach((item) => { if (item.isZh) { item.result = item.result.replace(/ü/g, typeof options.v === "string" ? options.v : "v"); } }); } }; // type 属性处理 const middlewareType = (list, options, word) => { if (options.multiple && (0,_common_utils_mjs__WEBPACK_IMPORTED_MODULE_0__.stringLength)(word) === 1) { let last = ""; list = list.filter((item) => { const res = item.result !== last; last = item.result; return res; }); } if (options.type === "array") { return list.map((item) => item.result); } if (options.type === "all") { return list.map((item) => { const pinyin = item.isZh ? item.result : ""; const { initial, final } = (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getInitialAndFinal)(pinyin, options.initialPattern); const { head, body, tail } = (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getFinalPartsFromFinal)(final); let polyphonic = []; if (pinyin !== "") { polyphonic = [pinyin].concat((0,_all_mjs__WEBPACK_IMPORTED_MODULE_3__.getAllPinyin)(item.origin, options.surname).filter((item) => item !== pinyin)); } return { origin: item.origin, pinyin, initial, final, first: (0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getFirstLetter)(item.result, item.isZh), finalHead: head, finalBody: body, finalTail: tail, num: Number((0,_handle_mjs__WEBPACK_IMPORTED_MODULE_1__.getNumOfTone)(item.originPinyin)), isZh: item.isZh, polyphonic, inZhRange: !!_data_dict1_mjs__WEBPACK_IMPORTED_MODULE_2__["default"].get(item.origin), result: item.result, }; }); } return list.map((item) => item.result).join(options.separator); }; // 是否开启变调 const middlewareToneSandhi = (list, toneSandhi) => { if (toneSandhi === false) { list.forEach((item) => { if (item.origin === "一") { item.result = item.originPinyin = "yī"; } else if (item.origin === "不") { item.result = item.originPinyin = "bù"; } }); } return list; }; /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/core/traditional/index.mjs": /*!*********************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/core/traditional/index.mjs ***! \*********************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ addTraditionalDict: function() { return /* binding */ addTraditionalDict; }, /* harmony export */ getTraditionalDict: function() { return /* binding */ getTraditionalDict; } /* harmony export */ }); const traditionalDict = []; function addTraditionalDict(dict) { for (let key in dict) { const value = dict[key]; const code = key.charCodeAt(0); traditionalDict[code] = value; } } function getTraditionalDict() { return traditionalDict; } /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/data/dict1.mjs": /*!*********************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/data/dict1.mjs ***! \*********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": function() { return /* binding */ DICT1; } /* harmony export */ }); /* harmony import */ var _common_utils_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common/utils.mjs */ "./node_modules/pinyin-pro/dist/esm/common/utils.mjs"); const map = { 'bǎng páng pāng': ['膀'], líng: [ '〇', '伶', '凌', '刢', '囹', '坽', '夌', '姈', '婈', '孁', '岺', '彾', '掕', '昤', '朎', '柃', '棂', '櫺', '欞', '泠', '淩', '澪', '灵', '燯', '爧', '狑', '玲', '琌', '瓴', '皊', '砱', '祾', '秢', '竛', '笭', '紷', '綾', '绫', '羐', '羚', '翎', '聆', '舲', '苓', '菱', '蓤', '蔆', '蕶', '蛉', '衑', '裬', '詅', '跉', '軨', '輘', '酃', '醽', '鈴', '錂', '铃', '閝', '陵', '零', '霊', '霗', '霛', '霝', '靈', '駖', '魿', '鯪', '鲮', '鴒', '鸰', '鹷', '麢', '齡', '齢', '龄', '龗', '㥄', ], yī: [ '一', '乊', '伊', '依', '医', '吚', '咿', '噫', '壱', '壹', '夁', '嫛', '嬄', '弌', '揖', '撎', '檹', '毉', '洢', '渏', '漪', '瑿', '畩', '祎', '禕', '稦', '繄', '蛜', '衤', '譩', '辷', '郼', '醫', '銥', '铱', '鷖', '鹥', '黟', '黳', ], 'dīng zhēng': ['丁'], 'kǎo qiǎo yú': ['丂'], qī: [ '七', '倛', '僛', '凄', '嘁', '墄', '娸', '悽', '慼', '慽', '戚', '捿', '柒', '桤', '桼', '棲', '榿', '欺', '沏', '淒', '漆', '紪', '緀', '萋', '褄', '諆', '迉', '郪', '鏚', '霋', '魌', '鶈', ], shàng: ['丄', '尙', '尚', '恦', '緔', '绱'], xià: [ '丅', '下', '乤', '圷', '夏', '夓', '懗', '梺', '疜', '睱', '罅', '鎼', '鏬', ], hǎn: ['丆', '喊', '浫', '罕', '豃', '㘎'], 'wàn mò': ['万'], zhàng: [ '丈', '仗', '墇', '嶂', '帐', '帳', '幛', '扙', '杖', '涱', '痮', '瘬', '瘴', '瞕', '粀', '胀', '脹', '賬', '账', '障', ], sān: ['三', '厁', '叁', '弎', '毵', '毶', '毿', '犙', '鬖'], 'shàng shǎng shang': ['上'], 'qí jī': ['丌', '其', '奇'], 'bù fǒu': ['不'], 'yǔ yù yú': ['与'], miǎn: [ '丏', '偭', '免', '冕', '勉', '勔', '喕', '娩', '愐', '汅', '沔', '湎', '睌', '緬', '缅', '腼', '葂', '靦', '鮸', '𩾃', ], gài: [ '丐', '乢', '匃', '匄', '戤', '概', '槩', '槪', '溉', '漑', '瓂', '葢', '鈣', '钙', '𬮿', ], chǒu: ['丑', '丒', '侴', '吜', '杽', '瞅', '矁', '醜', '魗'], zhuān: [ '专', '叀', '嫥', '専', '專', '瑼', '甎', '砖', '磗', '磚', '蟤', '諯', '鄟', '顓', '颛', '鱄', '䏝', ], 'qiě jū': ['且'], pī: [ '丕', '伓', '伾', '噼', '坯', '岯', '憵', '批', '披', '炋', '狉', '狓', '砒', '磇', '礔', '礕', '秛', '秠', '耚', '豾', '邳', '鈚', '鉟', '銔', '錃', '錍', '霹', '駓', '髬', '魾', '𬳵', ], shì: [ '世', '丗', '亊', '事', '仕', '侍', '冟', '势', '勢', '卋', '呩', '嗜', '噬', '士', '奭', '嬕', '室', '市', '式', '弑', '弒', '恀', '恃', '戺', '拭', '揓', '是', '昰', '枾', '柿', '栻', '澨', '烒', '煶', '眂', '眎', '眡', '睗', '示', '礻', '筮', '簭', '舐', '舓', '襫', '視', '视', '觢', '試', '誓', '諡', '謚', '试', '谥', '貰', '贳', '軾', '轼', '逝', '遾', '釈', '释', '釋', '鈰', '鉃', '鉽', '铈', '飾', '餙', '餝', '饰', '鰘', '䏡', '𬤊', ], qiū: [ '丘', '丠', '坵', '媝', '恘', '恷', '楸', '秋', '秌', '穐', '篍', '緧', '萩', '蘒', '蚯', '蝵', '蟗', '蠤', '趥', '邱', '鞦', '鞧', '鰌', '鰍', '鳅', '鶖', '鹙', '龝', ], bǐng: [ '丙', '屛', '怲', '抦', '昞', '昺', '柄', '棅', '炳', '禀', '秉', '稟', '苪', '蛃', '邴', '鈵', '陃', '鞆', '餅', '餠', '饼', ], yè: [ '业', '亱', '僷', '墷', '夜', '嶪', '嶫', '抴', '捙', '擛', '擪', '擫', '晔', '曄', '曅', '曗', '曳', '曵', '枼', '枽', '業', '洂', '液', '澲', '烨', '燁', '爗', '璍', '皣', '瞱', '瞸', '礏', '腋', '葉', '謁', '谒', '邺', '鄴', '鍱', '鐷', '靥', '靨', '頁', '页', '餣', '饁', '馌', '驜', '鵺', '鸈', ], cóng: [ '丛', '从', '叢', '婃', '孮', '従', '徔', '徖', '悰', '樷', '欉', '淙', '灇', '爜', '琮', '藂', '誴', '賨', '賩', '錝', ], dōng: [ '东', '倲', '冬', '咚', '埬', '岽', '崬', '徚', '昸', '東', '氡', '氭', '涷', '笗', '苳', '菄', '蝀', '鮗', '鯟', '鶇', '鶫', '鸫', '鼕', '𬟽', ], sī: [ '丝', '俬', '凘', '厮', '司', '咝', '嘶', '噝', '媤', '廝', '恖', '撕', '斯', '楒', '泀', '澌', '燍', '禗', '禠', '私', '糹', '絲', '緦', '纟', '缌', '罳', '蕬', '虒', '蛳', '蜤', '螄', '蟖', '蟴', '鉰', '銯', '鍶', '鐁', '锶', '颸', '飔', '騦', '鷥', '鸶', '鼶', '㟃', ], chéng: [ '丞', '呈', '城', '埕', '堘', '塍', '塖', '宬', '峸', '惩', '懲', '成', '承', '挰', '掁', '揨', '枨', '棖', '橙', '檙', '洆', '溗', '澂', '珵', '珹', '畻', '程', '窚', '筬', '絾', '脭', '荿', '誠', '诚', '郕', '酲', '鋮', '铖', '騬', '鯎', ], diū: ['丟', '丢', '銩', '铥'], liǎng: [ '両', '两', '兩', '唡', '啢', '掚', '緉', '脼', '蜽', '裲', '魉', '魎', '𬜯', ], yǒu: [ '丣', '卣', '友', '梄', '湵', '牖', '禉', '羑', '聈', '苃', '莠', '蜏', '酉', '銪', '铕', '黝', ], yán: [ '严', '厳', '啱', '喦', '嚴', '塩', '壛', '壧', '妍', '姸', '娫', '娮', '岩', '嵒', '嵓', '巌', '巖', '巗', '延', '揅', '昖', '楌', '檐', '櫩', '欕', '沿', '炎', '炏', '狿', '琂', '盐', '碞', '筵', '簷', '莚', '蔅', '虤', '蜒', '言', '訁', '訮', '詽', '讠', '郔', '閆', '閻', '闫', '阎', '顏', '顔', '颜', '鹽', '麣', '𫄧', ], bìng: [ '並', '併', '倂', '傡', '垪', '摒', '栤', '病', '窉', '竝', '誁', '靐', '鮩', ], 'sàng sāng': ['丧'], gǔn: [ '丨', '惃', '滚', '滾', '磙', '緄', '绲', '蓘', '蔉', '衮', '袞', '輥', '辊', '鮌', '鯀', '鲧', ], jiū: [ '丩', '勼', '啾', '揪', '揫', '朻', '究', '糾', '纠', '萛', '赳', '阄', '鬏', '鬮', '鳩', '鸠', ], 'gè gě': ['个', '個', '各'], yā: [ '丫', '圧', '孲', '庘', '押', '枒', '桠', '椏', '錏', '鐚', '鴉', '鴨', '鵶', '鸦', '鸭', ], pán: [ '丬', '媻', '幋', '槃', '洀', '瀊', '爿', '盘', '盤', '磐', '縏', '蒰', '蟠', '蹒', '蹣', '鎜', '鞶', ], 'zhōng zhòng': ['中'], jǐ: [ '丮', '妀', '己', '戟', '挤', '掎', '撠', '擠', '橶', '泲', '犱', '脊', '虮', '蟣', '魢', '鱾', '麂', ], jiè: [ '丯', '介', '借', '唶', '堺', '屆', '届', '岕', '庎', '徣', '戒', '楐', '犗', '玠', '琾', '界', '畍', '疥', '砎', '蚧', '蛶', '衸', '褯', '誡', '诫', '鎅', '骱', '魪', ], fēng: [ '丰', '仹', '偑', '僼', '凨', '凬', '凮', '妦', '寷', '封', '峯', '峰', '崶', '枫', '楓', '檒', '沣', '沨', '渢', '灃', '烽', '犎', '猦', '琒', '疯', '瘋', '盽', '砜', '碸', '篈', '蘴', '蜂', '蠭', '豐', '鄷', '酆', '鋒', '鎽', '鏠', '锋', '霻', '靊', '飌', '麷', ], 'guàn kuàng': ['丱'], chuàn: ['串', '汌', '玔', '賗', '釧', '钏'], chǎn: [ '丳', '产', '冁', '剷', '囅', '嵼', '旵', '浐', '滻', '灛', '產', '産', '簅', '蒇', '蕆', '諂', '譂', '讇', '谄', '鏟', '铲', '閳', '闡', '阐', '骣', '𬊤', ], lín: [ '临', '冧', '壣', '崊', '嶙', '斴', '晽', '暽', '林', '潾', '瀶', '燐', '琳', '璘', '瞵', '碄', '磷', '粦', '粼', '繗', '翷', '臨', '轔', '辚', '遴', '邻', '鄰', '鏻', '阾', '隣', '霖', '驎', '鱗', '鳞', '麐', '麟', '𬴊', '𬭸', ], zhuó: [ '丵', '劅', '卓', '啄', '圴', '妰', '娺', '撯', '擆', '擢', '斫', '斮', '斱', '斲', '斵', '晫', '椓', '浊', '浞', '濁', '灼', '烵', '琸', '硺', '禚', '窡', '籗', '籱', '罬', '茁', '蠗', '蠿', '諁', '諑', '謶', '诼', '酌', '鐲', '镯', '鵫', '鷟', '䓬', '𬸦', ], zhǔ: [ '丶', '主', '劯', '嘱', '囑', '宔', '帾', '拄', '渚', '濐', '煑', '煮', '燝', '瞩', '矚', '罜', '詝', '陼', '鸀', '麈', '𬣞', ], bā: [ '丷', '仈', '八', '叭', '哵', '夿', '岜', '巴', '捌', '朳', '玐', '疤', '笆', '粑', '羓', '芭', '蚆', '豝', '釟', ], wán: [ '丸', '刓', '完', '岏', '抏', '捖', '汍', '烷', '玩', '琓', '笂', '紈', '纨', '翫', '芄', '貦', '頑', '顽', ], dān: [ '丹', '勯', '匰', '単', '妉', '媅', '殚', '殫', '甔', '眈', '砃', '箪', '簞', '耼', '耽', '聃', '聸', '褝', '襌', '躭', '郸', '鄲', '酖', '頕', ], 'wèi wéi': ['为'], 'jǐng dǎn': ['丼'], 'lì lí': ['丽'], jǔ: [ '举', '弆', '挙', '擧', '椇', '榉', '榘', '櫸', '欅', '矩', '筥', '聥', '舉', '莒', '蒟', '襷', '踽', '齟', '龃', ], piě: ['丿', '苤', '鐅', '𬭯'], fú: [ '乀', '伏', '俘', '凫', '刜', '匐', '咈', '哹', '垘', '孚', '岪', '巿', '帗', '幅', '幞', '弗', '彿', '怫', '扶', '柫', '栿', '桴', '氟', '泭', '浮', '涪', '澓', '炥', '玸', '甶', '畉', '癁', '祓', '福', '稪', '符', '箙', '紱', '紼', '絥', '綍', '绂', '绋', '罘', '罦', '翇', '艀', '芙', '芣', '苻', '茀', '茯', '菔', '葍', '虙', '蚨', '蜉', '蝠', '袚', '袱', '襆', '襥', '諨', '豧', '踾', '輻', '辐', '郛', '鉘', '鉜', '韍', '韨', '颫', '髴', '鮄', '鮲', '鳧', '鳬', '鴔', '鵩', '黻', ], 'yí jí': ['乁'], yì: [ '乂', '义', '亄', '亦', '亿', '伇', '伿', '佾', '俋', '億', '兿', '刈', '劓', '劮', '勚', '勩', '匇', '呓', '呭', '呹', '唈', '囈', '圛', '坄', '垼', '埸', '奕', '嫕', '嬑', '寱', '屹', '峄', '嶧', '帟', '帠', '幆', '廙', '异', '弈', '弋', '役', '忆', '怈', '怿', '悒', '意', '憶', '懌', '懿', '抑', '挹', '敡', '易', '晹', '曀', '曎', '杙', '枍', '棭', '榏', '槸', '檍', '歝', '殔', '殪', '殹', '毅', '浂', '浥', '浳', '湙', '溢', '潩', '澺', '瀷', '炈', '焲', '熠', '熤', '熼', '燚', '燡', '燱', '獈', '玴', '異', '疫', '痬', '瘗', '瘞', '瘱', '癔', '益', '瞖', '穓', '竩', '篒', '縊', '繶', '繹', '绎', '缢', '義', '羿', '翊', '翌', '翳', '翼', '耴', '肄', '肊', '膉', '臆', '艗', '艺', '芅', '苅', '萟', '蓺', '薏', '藙', '藝', '蘙', '虉', '蜴', '螠', '衪', '袣', '裔', '裛', '褹', '襼', '訲', '訳', '詍', '詣', '誼', '譯', '議', '讛', '议', '译', '诣', '谊', '豙', '豛', '豷', '貖', '贀', '跇', '轶', '逸', '邑', '鄓', '醷', '釴', '鈠', '鎰', '鐿', '镒', '镱', '阣', '隿', '霬', '饐', '駅', '驛', '驿', '骮', '鮨', '鶂', '鶃', '鶍', '鷁', '鷊', '鷧', '鷾', '鸃', '鹝', '鹢', '黓', '齸', '𬬩', '㑊', '𫄷', '𬟁', ], nǎi: ['乃', '倷', '奶', '嬭', '廼', '氖', '疓', '艿', '迺', '釢'], wǔ: [ '乄', '五', '仵', '伍', '侮', '倵', '儛', '午', '啎', '妩', '娬', '嫵', '庑', '廡', '忤', '怃', '憮', '摀', '武', '潕', '熓', '牾', '玝', '珷', '瑦', '甒', '碔', '舞', '躌', '迕', '逜', '陚', '鵡', '鹉', '𣲘', ], jiǔ: [ '久', '乆', '九', '乣', '奺', '杦', '汣', '灸', '玖', '紤', '舏', '酒', '镹', '韭', '韮', ], 'tuō zhé': ['乇', '杔', '馲'], 'me mó ma yāo': ['么'], zhī: [ '之', '倁', '卮', '巵', '搘', '支', '栀', '梔', '椥', '榰', '汁', '泜', '疷', '祗', '祬', '秓', '稙', '綕', '肢', '胑', '胝', '脂', '芝', '蘵', '蜘', '衼', '隻', '鳷', '鴲', '鼅', '𦭜', ], 'wū wù': ['乌'], zhà: [ '乍', '咤', '宱', '搾', '榨', '溠', '痄', '蚱', '詐', '诈', '醡', '霅', '䃎', ], hū: [ '乎', '乯', '匢', '匫', '呼', '唿', '嘑', '垀', '寣', '幠', '忽', '惚', '昒', '歑', '泘', '淴', '滹', '烀', '苸', '虍', '虖', '謼', '軤', '轷', '雐', ], fá: [ '乏', '伐', '傠', '坺', '垡', '墢', '姂', '栰', '浌', '瞂', '笩', '筏', '罚', '罰', '罸', '藅', '閥', '阀', ], 'lè yuè yào lào': ['乐', '樂'], yín: [ '乑', '吟', '噖', '嚚', '圁', '垠', '夤', '婬', '寅', '峾', '崟', '崯', '檭', '殥', '泿', '淫', '滛', '烎', '犾', '狺', '璌', '硍', '碒', '荶', '蔩', '訔', '訚', '訡', '誾', '鄞', '鈝', '銀', '银', '霪', '鷣', '齦', ], pīng: ['乒', '俜', '娉', '涄', '甹', '砯', '聠', '艵', '頩'], pāng: ['乓', '滂', '胮', '膖', '雱', '霶'], qiáo: [ '乔', '侨', '僑', '嫶', '憔', '桥', '槗', '樵', '橋', '櫵', '犞', '瞧', '硚', '礄', '荍', '荞', '蕎', '藮', '譙', '趫', '鐈', '鞒', '鞽', '顦', ], hǔ: ['乕', '琥', '萀', '虎', '虝', '錿', '鯱'], guāi: ['乖'], 'chéng shèng': ['乗', '乘', '娍'], yǐ: [ '乙', '乛', '以', '倚', '偯', '嬟', '崺', '已', '庡', '扆', '攺', '敼', '旑', '旖', '檥', '矣', '礒', '笖', '舣', '艤', '苡', '苢', '蚁', '螘', '蟻', '裿', '踦', '輢', '轙', '逘', '酏', '釔', '鈘', '鉯', '钇', '顗', '鳦', '齮', '𫖮', '𬺈', ], 'háo yǐ': ['乚'], 'niè miē': ['乜'], qǐ: [ '乞', '企', '启', '唘', '啓', '啔', '啟', '婍', '屺', '杞', '棨', '玘', '盀', '綺', '绮', '芑', '諬', '起', '邔', '闙', ], yě: ['也', '冶', '嘢', '埜', '壄', '漜', '野'], xí: [ '习', '喺', '媳', '嶍', '席', '椺', '檄', '漝', '習', '蓆', '袭', '襲', '覡', '觋', '謵', '趘', '郋', '鎴', '隰', '霫', '飁', '騱', '騽', '驨', '鰼', '鳛', '𠅤', '𫘬', ], xiāng: [ '乡', '厢', '廂', '忀', '楿', '欀', '湘', '瓖', '稥', '箱', '緗', '缃', '膷', '芗', '萫', '葙', '薌', '襄', '郷', '鄉', '鄊', '鄕', '鑲', '镶', '香', '驤', '骧', '鱜', '麘', '𬙋', ], shū: [ '书', '倏', '倐', '儵', '叔', '姝', '尗', '抒', '掓', '摅', '攄', '書', '枢', '梳', '樞', '殊', '殳', '毹', '毺', '淑', '瀭', '焂', '疎', '疏', '紓', '綀', '纾', '舒', '菽', '蔬', '踈', '軗', '輸', '输', '鄃', '陎', '鮛', '鵨', ], dǒu: ['乧', '抖', '枓', '蚪', '鈄', '阧', '陡'], shǐ: [ '乨', '使', '兘', '史', '始', '宩', '屎', '榁', '矢', '笶', '豕', '鉂', '駛', '驶', ], jī: [ '乩', '僟', '击', '刉', '刏', '剞', '叽', '唧', '喞', '嗘', '嘰', '圾', '基', '墼', '姬', '屐', '嵆', '嵇', '撃', '擊', '朞', '机', '枅', '樭', '機', '毄', '激', '犄', '玑', '璣', '畸', '畿', '癪', '矶', '磯', '积', '積', '笄', '筓', '箕', '簊', '緁', '羁', '羇', '羈', '耭', '肌', '芨', '虀', '覉', '覊', '譏', '譤', '讥', '賫', '賷', '赍', '跻', '踑', '躋', '躸', '銈', '錤', '鐖', '鑇', '鑙', '隮', '雞', '鞿', '韲', '飢', '饑', '饥', '魕', '鳮', '鶏', '鶺', '鷄', '鸄', '鸡', '齎', '齏', '齑', '𬯀', '𫓯', '𫓹', '𫌀', ], náng: ['乪', '嚢', '欜', '蠰', '饢'], jiā: [ '乫', '佳', '傢', '加', '嘉', '抸', '枷', '梜', '毠', '泇', '浃', '浹', '犌', '猳', '珈', '痂', '笳', '糘', '耞', '腵', '葭', '袈', '豭', '貑', '跏', '迦', '鉫', '鎵', '镓', '鴐', '麚', '𬂩', ], jù: [ '乬', '倨', '倶', '具', '剧', '劇', '勮', '埧', '埾', '壉', '姖', '屦', '屨', '岠', '巨', '巪', '怇', '惧', '愳', '懅', '懼', '拒', '拠', '昛', '歫', '洰', '澽', '炬', '烥', '犋', '秬', '窭', '窶', '簴', '粔', '耟', '聚', '虡', '蚷', '詎', '讵', '豦', '距', '踞', '躆', '遽', '邭', '醵', '鉅', '鐻', '钜', '颶', '飓', '駏', '鮔', ], shí: [ '乭', '十', '埘', '塒', '姼', '实', '実', '寔', '實', '峕', '嵵', '时', '旹', '時', '榯', '湜', '溡', '炻', '祏', '竍', '蚀', '蝕', '辻', '遈', '鉐', '飠', '饣', '鮖', '鰣', '鲥', '鼫', '鼭', ], mǎo: ['乮', '冇', '卯', '峁', '戼', '昴', '泖', '笷', '蓩', '鉚', '铆'], mǎi: ['买', '嘪', '荬', '蕒', '買', '鷶'], luàn: ['乱', '亂', '釠'], rǔ: ['乳', '擩', '汝', '肗', '辱', '鄏'], xué: [ '乴', '学', '學', '峃', '嶨', '斈', '泶', '澩', '燢', '穴', '茓', '袕', '踅', '鷽', '鸴', ], yǎn: [ '䶮', '乵', '俨', '偃', '儼', '兖', '兗', '厣', '厴', '噞', '孍', '嵃', '巘', '巚', '弇', '愝', '戭', '扊', '抁', '掩', '揜', '曮', '椼', '檿', '沇', '渷', '演', '琰', '甗', '眼', '罨', '萒', '蝘', '衍', '褗', '躽', '遃', '郾', '隒', '顩', '魇', '魘', '鰋', '鶠', '黡', '黤', '黬', '黭', '黶', '鼴', '鼹', '齴', '龑', '𬸘', '𬙂', '𪩘', ], fǔ: [ '乶', '俌', '俛', '俯', '府', '弣', '抚', '拊', '撫', '斧', '椨', '滏', '焤', '甫', '盙', '簠', '腐', '腑', '蜅', '輔', '辅', '郙', '釜', '釡', '阝', '頫', '鬴', '黼', '㕮', '𫖯', ], shā: [ '乷', '唦', '杀', '桬', '殺', '毮', '猀', '痧', '砂', '硰', '紗', '繺', '纱', '蔱', '裟', '鎩', '铩', '閷', '髿', '魦', '鯊', '鯋', '鲨', ], nǎ: ['乸', '雫'], qián: [ '乹', '亁', '仱', '偂', '前', '墘', '媊', '岒', '拑', '掮', '榩', '橬', '歬', '潛', '潜', '濳', '灊', '箝', '葥', '虔', '軡', '鈐', '鉗', '銭', '錢', '鎆', '钤', '钱', '钳', '靬', '騚', '騝', '鰬', '黔', '黚', ], suǒ: [ '乺', '唢', '嗩', '所', '暛', '溑', '溹', '琐', '琑', '瑣', '索', '褨', '鎖', '鎻', '鏁', '锁', ], yú: [ '乻', '于', '亐', '伃', '余', '堣', '堬', '妤', '娛', '娯', '娱', '嬩', '崳', '嵎', '嵛', '愚', '扵', '揄', '旟', '楡', '楰', '榆', '欤', '歈', '歟', '歶', '渔', '渝', '湡', '漁', '澞', '牏', '狳', '玗', '玙', '瑜', '璵', '盂', '睮', '窬', '竽', '籅', '羭', '腴', '臾', '舁', '舆', '艅', '茰', '萮', '萸', '蕍', '蘛', '虞', '虶', '蝓', '螸', '衧', '褕', '覦', '觎', '諛', '謣', '谀', '踰', '輿', '轝', '逾', '邘', '酑', '鍝', '隅', '雓', '雩', '餘', '馀', '騟', '骬', '髃', '魚', '魣', '鮽', '鯲', '鰅', '鱼', '鷠', '鸆', '齵', ], zhù: [ '乼', '伫', '佇', '住', '坾', '墸', '壴', '嵀', '拀', '杼', '柱', '樦', '殶', '注', '炷', '疰', '眝', '祝', '祩', '竚', '筯', '箸', '篫', '簗', '紵', '紸', '纻', '羜', '翥', '苎', '莇', '蛀', '註', '貯', '贮', '跓', '軴', '鉒', '鋳', '鑄', '铸', '馵', '駐', '驻', ], zhě: ['乽', '者', '褶', '襵', '赭', '踷', '鍺', '锗'], 'qián gān': ['乾'], 'zhì luàn': ['乿'], guī: [ '亀', '圭', '妫', '媯', '嫢', '嬀', '帰', '归', '摫', '椝', '槻', '槼', '櫷', '歸', '珪', '瑰', '璝', '瓌', '皈', '瞡', '硅', '茥', '蘬', '規', '规', '邽', '郌', '閨', '闺', '騩', '鬶', '鬹', ], 'lǐn lìn': ['亃'], jué: [ '亅', '决', '刔', '劂', '匷', '厥', '噊', '孒', '孓', '崛', '崫', '嶥', '彏', '憠', '憰', '戄', '抉', '挗', '掘', '攫', '桷', '橛', '橜', '欮', '氒', '決', '灍', '焳', '熦', '爑', '爴', '爵', '獗', '玃', '玦', '玨', '珏', '瑴', '瘚', '矍', '矡', '砄', '絕', '絶', '绝', '臄', '芵', '蕝', '蕨', '虳', '蟨', '蟩', '觖', '觮', '觼', '訣', '譎', '诀', '谲', '貜', '赽', '趉', '蹷', '躩', '鈌', '鐍', '鐝', '钁', '镢', '鴂', '鴃', '鷢', '𫘝', '㵐', '𫔎', ], 'le liǎo': ['了'], 'gè mā': ['亇'], 'yǔ yú': ['予', '懙'], zhēng: [ '争', '佂', '凧', '姃', '媜', '峥', '崝', '崢', '征', '徰', '炡', '烝', '爭', '狰', '猙', '癥', '眐', '睁', '睜', '筝', '箏', '篜', '聇', '脀', '蒸', '踭', '鉦', '錚', '鏳', '鬇', ], èr: ['二', '刵', '咡', '弍', '弐', '樲', '誀', '貮', '貳', '贰', '髶'], chù: [ '亍', '傗', '儊', '怵', '憷', '搐', '斶', '歜', '珿', '琡', '矗', '竌', '絀', '绌', '臅', '触', '觸', '豖', '鄐', '閦', '黜', ], kuī: ['亏', '刲', '岿', '巋', '盔', '窥', '窺', '聧', '虧', '闚', '顝'], yún: [ '云', '伝', '勻', '匀', '囩', '妘', '愪', '抣', '昀', '橒', '沄', '涢', '溳', '澐', '熉', '畇', '秐', '筼', '篔', '紜', '縜', '纭', '耘', '芸', '蒷', '蕓', '郧', '鄖', '鋆', '雲', ], hù: [ '互', '冱', '嗀', '嚛', '婟', '嫭', '嫮', '岵', '帍', '弖', '怙', '戶', '户', '戸', '戽', '扈', '护', '昈', '槴', '沍', '沪', '滬', '熩', '瓠', '祜', '笏', '簄', '粐', '綔', '蔰', '護', '豰', '鄠', '鍙', '頀', '鱯', '鳠', '鳸', '鸌', '鹱', ], qí: [ '亓', '剘', '埼', '岐', '岓', '崎', '嵜', '愭', '掑', '斉', '斊', '旂', '旗', '棊', '棋', '檱', '櫀', '歧', '淇', '濝', '猉', '玂', '琦', '琪', '璂', '畦', '疧', '碁', '碕', '祁', '祈', '祺', '禥', '竒', '簯', '簱', '籏', '粸', '綥', '綦', '肵', '脐', '臍', '艩', '芪', '萁', '萕', '蕲', '藄', '蘄', '蚑', '蚚', '蛴', '蜝', '蜞', '螧', '蠐', '褀', '軝', '鄿', '釮', '錡', '锜', '陭', '頎', '颀', '騎', '騏', '騹', '骐', '骑', '鬐', '鬿', '鯕', '鰭', '鲯', '鳍', '鵸', '鶀', '麒', '麡', '𨙸', '𬨂', '䓫', ], jǐng: [ '井', '儆', '刭', '剄', '坓', '宑', '幜', '憬', '暻', '殌', '汫', '汬', '澋', '璄', '璟', '璥', '穽', '肼', '蟼', '警', '阱', '頚', '頸', ], sì: [ '亖', '佀', '価', '儩', '兕', '嗣', '四', '姒', '娰', '孠', '寺', '巳', '柶', '榹', '汜', '泗', '泤', '洍', '洠', '涘', '瀃', '牭', '祀', '禩', '竢', '笥', '耜', '肂', '肆', '蕼', '覗', '貄', '釲', '鈶', '鈻', '飤', '飼', '饲', '駟', '騃', '驷', ], suì: [ '亗', '嬘', '岁', '嵗', '旞', '檖', '歲', '歳', '澻', '煫', '燧', '璲', '砕', '碎', '祟', '禭', '穂', '穗', '穟', '繀', '繐', '繸', '襚', '誶', '譢', '谇', '賥', '邃', '鐆', '鐩', '隧', '韢', '𫟦', '𬭼', ], gèn: ['亘', '亙', '揯', '搄', '茛'], yà: [ '亚', '亜', '俹', '冴', '劜', '圔', '圠', '埡', '娅', '婭', '揠', '氩', '氬', '犽', '砑', '稏', '聐', '襾', '覀', '訝', '讶', '迓', '齾', ], 'xiē suò': ['些'], 'qí zhāi': ['亝', '齊'], 'yā yà': ['亞', '压', '垭', '壓', '铔'], 'jí qì': ['亟', '焏'], tóu: ['亠', '投', '頭', '骰'], 'wáng wú': ['亡'], 'kàng háng gāng': ['亢'], dà: ['亣', '眔'], jiāo: [ '交', '僬', '娇', '嬌', '峧', '嶕', '嶣', '憍', '椒', '浇', '澆', '焦', '礁', '穚', '簥', '胶', '膠', '膲', '茭', '茮', '蕉', '虠', '蛟', '蟭', '跤', '轇', '郊', '鐎', '驕', '骄', '鮫', '鲛', '鵁', '鷦', '鷮', '鹪', '䴔', ], hài: ['亥', '嗐', '害', '氦', '餀', '饚', '駭', '駴', '骇'], 'hēng pēng': ['亨'], mǔ: [ '亩', '姆', '峔', '拇', '母', '牡', '牳', '畂', '畆', '畒', '畝', '畞', '畮', '砪', '胟', '踇', '鉧', '𬭁', '𧿹', ], ye: ['亪'], xiǎng: [ '享', '亯', '响', '想', '晑', '蚃', '蠁', '響', '飨', '餉', '饗', '饷', '鮝', '鯗', '鱶', '鲞', ], jīng: [ '京', '亰', '兢', '坕', '坙', '婛', '惊', '旌', '旍', '晶', '橸', '泾', '涇', '猄', '睛', '秔', '稉', '粳', '精', '経', '經', '綡', '聙', '腈', '茎', '荆', '荊', '菁', '葏', '驚', '鯨', '鲸', '鶁', '鶄', '麖', '麠', '鼱', '䴖', ], tíng: [ '亭', '停', '婷', '嵉', '庭', '廷', '楟', '榳', '筳', '聤', '莛', '葶', '蜓', '蝏', '諪', '邒', '霆', '鼮', '䗴', ], liàng: ['亮', '喨', '悢', '晾', '湸', '諒', '谅', '輌', '輛', '辆', '鍄'], 'qīn qìng': ['亲', '親'], bó: [ '亳', '仢', '侼', '僰', '博', '帛', '愽', '懪', '挬', '搏', '欂', '浡', '淿', '渤', '煿', '牔', '狛', '瓝', '礴', '秡', '箔', '簙', '糪', '胉', '脖', '膊', '舶', '艊', '萡', '葧', '袯', '襏', '襮', '謈', '踣', '郣', '鈸', '鉑', '鋍', '鎛', '鑮', '钹', '铂', '镈', '餺', '馎', '馛', '馞', '駁', '駮', '驳', '髆', '鵓', '鹁', ], yòu: [ '亴', '佑', '佦', '侑', '又', '右', '哊', '唀', '囿', '姷', '宥', '峟', '幼', '狖', '祐', '蚴', '誘', '诱', '貁', '迶', '酭', '釉', '鼬', ], xiè: [ '亵', '伳', '偞', '偰', '僁', '卨', '卸', '噧', '塮', '夑', '媟', '屑', '屧', '廨', '徢', '懈', '暬', '械', '榍', '榭', '泻', '洩', '渫', '澥', '瀉', '瀣', '灺', '炧', '炨', '燮', '爕', '獬', '祄', '禼', '糏', '紲', '絏', '絬', '繲', '纈', '绁', '缷', '薢', '薤', '蟹', '蠏', '褉', '褻', '謝', '谢', '躞', '邂', '靾', '韰', '齂', '齘', '齛', '齥', '𬹼', '𤫉', ], 'dǎn dàn': ['亶', '馾'], lián: [ '亷', '劆', '匲', '匳', '嗹', '噒', '奁', '奩', '嫾', '帘', '廉', '怜', '憐', '涟', '漣', '濂', '濓', '瀮', '熑', '燫', '簾', '籢', '籨', '縺', '翴', '联', '聨', '聫', '聮', '聯', '臁', '莲', '蓮', '薕', '螊', '蠊', '裢', '褳', '覝', '謰', '蹥', '连', '連', '鎌', '鐮', '镰', '鬑', '鰱', '鲢', ], duǒ: [ '亸', '哚', '嚲', '埵', '崜', '朵', '朶', '綞', '缍', '趓', '躱', '躲', '軃', ], 'wěi mén': ['亹', '斖'], rén: ['人', '亻', '仁', '壬', '忈', '忎', '朲', '秂', '芢', '魜', '鵀'], jí: [ '亼', '亽', '伋', '佶', '偮', '卙', '即', '卽', '及', '叝', '吉', '堲', '塉', '姞', '嫉', '岌', '嵴', '嶯', '彶', '忣', '急', '愱', '戢', '揤', '极', '棘', '楫', '極', '槉', '檝', '殛', '汲', '湒', '潗', '疾', '瘠', '皍', '笈', '箿', '籍', '級', '级', '膌', '艥', '蒺', '蕀', '蕺', '蝍', '螏', '襋', '觙', '谻', '踖', '蹐', '躤', '輯', '轚', '辑', '郆', '銡', '鍓', '鏶', '集', '雧', '霵', '鹡', '㴔', ], wáng: ['亾', '仼', '兦', '莣', '蚟'], 'shén shí': ['什'], lè: [ '仂', '叻', '忇', '氻', '泐', '玏', '砳', '簕', '艻', '阞', '韷', '餎', '鰳', '鱳', '鳓', ], dīng: ['仃', '叮', '帄', '玎', '疔', '盯', '耵', '虰', '靪'], zè: ['仄', '崱', '庂', '捑', '昃', '昗', '汄'], 'jǐn jìn': ['仅', '僅', '嫤'], 'pú pū': ['仆'], 'chóu qiú': ['仇'], zhǎng: ['仉', '幥', '掌', '礃'], jīn: [ '今', '堻', '巾', '惍', '斤', '津', '珒', '琻', '璡', '砛', '筋', '荕', '衿', '襟', '觔', '金', '釒', '釿', '钅', '鹶', '黅', '𬬱', ], bīng: ['仌', '仒', '兵', '冫', '冰', '掤', '氷', '鋲'], réng: ['仍', '礽', '芿', '辸', '陾'], fó: ['仏', '坲', '梻'], 'jīn sǎn': ['仐'], lún: [ '仑', '伦', '侖', '倫', '囵', '圇', '婨', '崘', '崙', '棆', '沦', '淪', '磮', '腀', '菕', '蜦', '踚', '輪', '轮', '錀', '陯', '鯩', '𬬭', ], cāng: [ '仓', '仺', '倉', '凔', '嵢', '沧', '滄', '濸', '獊', '舱', '艙', '苍', '蒼', '螥', '鸧', ], 'zǎi zǐ zī': ['仔'], tā: ['他', '塌', '它', '榙', '溻', '牠', '祂', '褟', '趿', '遢', '闧'], fù: [ '付', '偩', '傅', '冨', '副', '咐', '坿', '复', '妇', '婦', '媍', '嬔', '富', '復', '椱', '祔', '禣', '竎', '緮', '縛', '缚', '腹', '萯', '蕧', '蚹', '蛗', '蝜', '蝮', '袝', '複', '覄', '覆', '訃', '詂', '讣', '負', '賦', '賻', '负', '赋', '赙', '赴', '輹', '鍑', '鍢', '阜', '附', '馥', '駙', '驸', '鮒', '鰒', '鲋', '鳆', '㳇', ], xiān: [ '仙', '仚', '佡', '僊', '僲', '先', '嘕', '奾', '屳', '廯', '忺', '憸', '掀', '暹', '杴', '氙', '珗', '祆', '秈', '籼', '繊', '纎', '纖', '苮', '褼', '襳', '跹', '蹮', '躚', '酰', '鍁', '锨', '韯', '韱', '馦', '鱻', '鶱', '𬸣', ], 'tuō chà duó': ['仛'], hóng: [ '仜', '吰', '垬', '妅', '娂', '宏', '宖', '弘', '彋', '汯', '泓', '洪', '浤', '渱', '潂', '玒', '玜', '竑', '竤', '篊', '粠', '紘', '紭', '綋', '纮', '翃', '翝', '耾', '苰', '荭', '葒', '葓', '谹', '谼', '鈜', '鉷', '鋐', '閎', '闳', '霐', '霟', '鞃', '魟', '鴻', '鸿', '黉', '黌', '𫟹', '𬭎', ], tóng: [ '仝', '佟', '哃', '峂', '峝', '庝', '彤', '晍', '曈', '桐', '氃', '浵', '潼', '犝', '獞', '眮', '瞳', '砼', '秱', '童', '粡', '膧', '茼', '蚒', '詷', '赨', '酮', '鉖', '鉵', '銅', '铜', '餇', '鮦', '鲖', '𫍣', '𦒍', ], rèn: [ '仞', '仭', '刃', '刄', '妊', '姙', '屻', '岃', '扨', '牣', '祍', '紉', '紝', '絍', '纫', '纴', '肕', '腍', '衽', '袵', '訒', '認', '认', '讱', '軔', '轫', '鈓', '靭', '靱', '韌', '韧', '飪', '餁', '饪', ], qiān: [ '仟', '佥', '僉', '千', '圲', '奷', '孯', '岍', '悭', '愆', '慳', '扦', '拪', '搴', '撁', '攐', '攑', '攓', '杄', '櫏', '汘', '汧', '牵', '牽', '竏', '签', '簽', '籖', '籤', '粁', '芊', '茾', '蚈', '褰', '諐', '謙', '谦', '谸', '迁', '遷', '釺', '鈆', '鉛', '鏲', '钎', '阡', '韆', '顅', '騫', '骞', '鬜', '鬝', '鵮', '鹐', ], 'gǎn hàn': ['仠'], 'yì gē': ['仡'], dài: [ '代', '侢', '叇', '垈', '埭', '岱', '帒', '带', '帯', '帶', '廗', '怠', '戴', '曃', '柋', '殆', '瀻', '玳', '瑇', '甙', '簤', '紿', '緿', '绐', '艜', '蝳', '袋', '襶', '貣', '贷', '蹛', '軑', '軚', '軩', '轪', '迨', '霴', '靆', '鴏', '黛', '黱', ], 'lìng líng lǐng': ['令'], chào: ['仦', '耖', '觘'], 'cháng zhǎng': ['仧', '兏', '長', '长'], sā: ['仨'], cháng: [ '仩', '偿', '償', '嘗', '嚐', '嫦', '尝', '常', '徜', '瑺', '瓺', '甞', '肠', '腸', '膓', '苌', '萇', '镸', '鱨', '鲿', ], yí: [ '仪', '侇', '儀', '冝', '匜', '咦', '圯', '夷', '姨', '宐', '宜', '宧', '寲', '峓', '嶬', '嶷', '巸', '彛', '彜', '彝', '彞', '怡', '恞', '扅', '暆', '栘', '椬', '椸', '沂', '洟', '熪', '瓵', '痍', '移', '簃', '籎', '羠', '胰', '萓', '蛦', '螔', '觺', '謻', '貽', '贻', '跠', '迻', '遺', '鏔', '頉', '頤', '頥', '顊', '颐', '饴', '鮧', '鴺', ], mù: [ '仫', '凩', '募', '墓', '幕', '幙', '慔', '慕', '暮', '暯', '木', '楘', '毣', '沐', '炑', '牧', '狇', '目', '睦', '穆', '艒', '苜', '莯', '蚞', '鉬', '钼', '雮', '霂', ], 'men mén': ['们'], fǎn: ['仮', '反', '橎', '返'], 'chào miǎo': ['仯'], 'yǎng áng': ['仰'], zhòng: [ '仲', '众', '堹', '妕', '媑', '狆', '眾', '祌', '筗', '茽', '蚛', '衆', '衶', '諥', ], 'pǐ pí': ['仳'], wò: [ '仴', '偓', '卧', '媉', '幄', '握', '楃', '沃', '渥', '濣', '瓁', '瞃', '硪', '肟', '腛', '臥', '齷', '龌', ], jiàn: [ '件', '俴', '健', '僭', '剑', '剣', '剱', '劍', '劎', '劒', '劔', '墹', '寋', '建', '徤', '擶', '旔', '楗', '毽', '洊', '涧', '澗', '牮', '珔', '瞷', '磵', '礀', '箭', '糋', '繝', '腱', '臶', '舰', '艦', '荐', '薦', '覸', '諓', '諫', '譛', '谏', '賎', '賤', '贱', '趝', '践', '踐', '踺', '轞', '鉴', '鍳', '鍵', '鐱', '鑑', '鑒', '鑬', '鑳', '键', '間', '餞', '饯', '𬣡', ], 'jià jiè jie': ['价'], 'yǎo fó': ['仸'], 'rèn rén': ['任'], 'fèn bīn': ['份'], dī: [ '仾', '低', '啲', '埞', '堤', '岻', '彽', '樀', '滴', '磾', '秪', '羝', '袛', '趆', '隄', '鞮', '䃅', ], fǎng: [ '仿', '倣', '旊', '昉', '昘', '瓬', '眆', '紡', '纺', '舫', '訪', '访', '髣', '鶭', ], zhōng: [ '伀', '刣', '妐', '幒', '彸', '忠', '柊', '汷', '泈', '炂', '盅', '籦', '終', '终', '舯', '蔠', '蜙', '螤', '螽', '衳', '衷', '蹱', '鈡', '鍾', '鐘', '钟', '锺', '鴤', '鼨', ], pèi: [ '伂', '佩', '姵', '帔', '斾', '旆', '沛', '浿', '珮', '蓜', '轡', '辔', '配', '霈', '馷', ], diào: [ '伄', '吊', '弔', '掉', '瘹', '盄', '窎', '窵', '竨', '訋', '釣', '鈟', '銱', '鋽', '鑃', '钓', '铞', '雿', '魡', ], dùn: [ '伅', '潡', '炖', '燉', '盾', '砘', '碷', '踲', '逇', '遁', '遯', '鈍', '钝', ], wěn: ['伆', '刎', '吻', '呅', '抆', '桽', '稳', '穏', '穩', '紊', '肳', '脗'], xǐn: ['伈'], kàng: ['伉', '匟', '囥', '抗', '炕', '鈧', '钪'], ài: [ '伌', '僾', '塧', '壒', '嫒', '嬡', '愛', '懓', '暧', '曖', '爱', '瑷', '璦', '皧', '瞹', '砹', '硋', '碍', '礙', '薆', '譺', '賹', '鑀', '隘', '靉', '餲', '馤', '鱫', '鴱', ], 'jì qí': ['伎', '薺'], 'xiū xǔ': ['休'], 'jìn yín': ['伒'], dǎn: [ '伔', '刐', '撢', '玬', '瓭', '紞', '胆', '膽', '衴', '賧', '赕', '黕', '𬘘', ], fū: [ '伕', '呋', '娐', '孵', '尃', '怤', '懯', '敷', '旉', '玞', '砆', '稃', '筟', '糐', '綒', '肤', '膚', '荂', '荴', '衭', '趺', '跗', '邞', '鄜', '酜', '鈇', '麩', '麬', '麱', '麸', '𫓧', ], tǎng: [ '伖', '傥', '儻', '埫', '戃', '曭', '爣', '矘', '躺', '鎲', '钂', '镋', ], yōu: [ '优', '優', '呦', '嚘', '峳', '幽', '忧', '悠', '憂', '攸', '櫌', '滺', '瀀', '纋', '羪', '耰', '逌', '鄾', '麀', ], huǒ: ['伙', '夥', '火', '煷', '邩', '鈥', '钬'], 'huì kuài': ['会', '會', '浍', '璯'], yǔ: [ '伛', '俁', '俣', '偊', '傴', '匬', '噳', '圄', '圉', '宇', '寙', '屿', '嶼', '庾', '挧', '敔', '斞', '楀', '瑀', '瘐', '祤', '禹', '穥', '窳', '羽', '與', '萭', '貐', '鄅', '頨', '麌', '齬', '龉', '㺄', ], cuì: [ '伜', '啛', '忰', '悴', '毳', '淬', '焠', '疩', '瘁', '竁', '粋', '粹', '紣', '綷', '翆', '翠', '脃', '脆', '脺', '膬', '膵', '臎', '萃', '襊', '顇', ], sǎn: ['伞', '傘', '糤', '繖', '饊', '馓'], wěi: [ '伟', '伪', '偉', '偽', '僞', '儰', '娓', '寪', '屗', '崣', '嶉', '徫', '愇', '捤', '暐', '梶', '洧', '浘', '渨', '炜', '煒', '猥', '玮', '瑋', '痿', '緯', '纬', '腲', '艉', '芛', '苇', '荱', '萎', '葦', '蒍', '蔿', '蜼', '諉', '诿', '踓', '鍡', '韑', '韙', '韡', '韪', '頠', '颹', '骩', '骪', '骫', '鮪', '鲔', '𫇭', '𬀩', '𬱟', ], 'chuán zhuàn': ['传', '傳'], 'chē jū': ['伡', '俥', '车'], 'jū chē': ['車'], yá: [ '伢', '厑', '厓', '堐', '岈', '崕', '崖', '涯', '漄', '牙', '玡', '琊', '睚', '笌', '芽', '蚜', '衙', '齖', ], qiàn: [ '伣', '俔', '倩', '儙', '刋', '壍', '嬱', '悓', '棈', '椠', '槧', '欠', '歉', '皘', '篏', '篟', '縴', '芡', '蒨', '蔳', '輤', '𬘬', ], shāng: [ '伤', '傷', '商', '墒', '慯', '殇', '殤', '滳', '漡', '熵', '蔏', '螪', '觞', '觴', '謪', '鬺', ], chāng: [ '伥', '倀', '娼', '昌', '椙', '淐', '猖', '琩', '菖', '裮', '錩', '锠', '閶', '阊', '鯧', '鲳', '鼚', ], 'chen cāng': ['伧'], xùn: [ '伨', '侚', '卂', '噀', '巺', '巽', '徇', '愻', '殉', '殾', '汛', '潠', '狥', '蕈', '訊', '訓', '訙', '训', '讯', '迅', '迿', '逊', '遜', '鑂', '顨', '馴', '驯', ], xìn: ['伩', '囟', '孞', '脪', '舋', '衅', '訫', '釁', '阠', '顖'], chǐ: [ '伬', '侈', '卶', '叺', '呎', '垑', '恥', '歯', '耻', '肔', '胣', '蚇', '裭', '褫', '豉', '鉹', '齒', '齿', ], 'xián xuán': ['伭'], 'nú nǔ': ['伮'], 'bó bǎi': ['伯'], 'gū gù': ['估'], nǐ: ['伱', '你', '儞', '孴', '拟', '擬', '旎', '晲', '狔', '苨', '薿', '隬'], 'nì ní': ['伲'], bàn: [ '伴', '办', '半', '姅', '怑', '扮', '瓣', '秚', '絆', '绊', '辦', '鉡', '靽', ], xù: [ '伵', '侐', '勖', '勗', '卹', '叙', '垿', '壻', '婿', '序', '恤', '敍', '敘', '旭', '昫', '朂', '槒', '欰', '殈', '汿', '沀', '洫', '溆', '漵', '潊', '烅', '烼', '煦', '獝', '珬', '盢', '瞁', '稸', '絮', '続', '緒', '緖', '續', '绪', '续', '聓', '聟', '蓄', '藚', '訹', '賉', '酗', '頊', '鱮', '㳚', ], zhòu: [ '伷', '僽', '冑', '呪', '咒', '咮', '宙', '昼', '晝', '甃', '皱', '皺', '籀', '籒', '籕', '粙', '紂', '縐', '纣', '绉', '胄', '荮', '葤', '詋', '酎', '駎', '驟', '骤', '㤘', '㑇', ], shēn: [ '伸', '侁', '兟', '呻', '堔', '妽', '娠', '屾', '峷', '扟', '敒', '曑', '柛', '氠', '深', '燊', '珅', '甡', '甧', '申', '眒', '砷', '穼', '籶', '籸', '糂', '紳', '绅', '罙', '罧', '葠', '蓡', '蔘', '薓', '裑', '訷', '詵', '诜', '身', '駪', '鯓', '鯵', '鰺', '鲹', '鵢', '𬳽', ], qū: [ '伹', '佉', '匤', '呿', '坥', '屈', '岖', '岴', '嶇', '憈', '抾', '敺', '浀', '煀', '祛', '筁', '粬', '胠', '蛆', '蛐', '袪', '覻', '詘', '诎', '趍', '躯', '軀', '阹', '駆', '駈', '驅', '驱', '髷', '魼', '鰸', '鱋', '鶌', '麯', '麴', '麹', '黢', '㭕', '𪨰', '䓛', ], 'sì cì': ['伺'], bēng: ['伻', '嘣', '奟', '崩', '嵭', '閍'], 'sì shì': ['似'], 'jiā qié gā': ['伽'], 'yǐ chì': ['佁'], 'diàn tián': ['佃', '钿'], 'hān gàn': ['佄'], mài: [ '佅', '劢', '勱', '卖', '唛', '売', '脈', '衇', '賣', '迈', '邁', '霡', '霢', '麥', '麦', '鿏', ], dàn: [ '但', '僤', '啖', '啗', '啿', '噉', '嚪', '帎', '憺', '旦', '柦', '氮', '沊', '泹', '淡', '狚', '疍', '癚', '禫', '窞', '腅', '萏', '蓞', '蛋', '蜑', '觛', '訑', '誕', '诞', '贉', '霮', '餤', '饏', '駳', '髧', '鴠', '𫢸', ], bù: [ '佈', '勏', '吥', '咘', '埗', '埠', '布', '廍', '怖', '悑', '步', '歨', '歩', '瓿', '篰', '荹', '蔀', '踄', '部', '郶', '鈈', '钚', '餢', ], bǐ: [ '佊', '俾', '匕', '夶', '妣', '彼', '朼', '柀', '比', '毞', '沘', '疕', '秕', '笔', '筆', '粃', '聛', '舭', '貏', '鄙', ], 'zhāo shào': ['佋'], cǐ: ['佌', '此', '泚', '皉', '𫚖'], wèi: [ '位', '卫', '味', '喂', '墛', '媦', '慰', '懀', '未', '渭', '煟', '熭', '犚', '猬', '畏', '緭', '罻', '胃', '苿', '菋', '藯', '蘶', '蝟', '螱', '衛', '衞', '褽', '謂', '讆', '讏', '谓', '躗', '躛', '軎', '轊', '鏏', '霨', '餧', '餵', '饖', '魏', '鮇', '鳚', ], zuǒ: ['佐', '左', '繓'], yǎng: [ '佒', '傟', '养', '坱', '岟', '慃', '懩', '攁', '氧', '氱', '炴', '痒', '癢', '礢', '紻', '蝆', '軮', '養', '駚', ], 'tǐ tī': ['体', '體'], zhàn: [ '佔', '偡', '嶘', '战', '戦', '戰', '栈', '桟', '棧', '湛', '站', '綻', '绽', '菚', '蘸', '虥', '虦', '譧', '轏', '驏', ], 'hé hē hè': ['何'], bì: [ '佖', '咇', '哔', '嗶', '坒', '堛', '壁', '奰', '妼', '婢', '嬖', '币', '幣', '幤', '庇', '庳', '廦', '弊', '弻', '弼', '彃', '必', '怭', '愊', '愎', '敝', '斃', '梐', '毕', '毖', '毙', '湢', '滗', '滭', '潷', '煏', '熚', '狴', '獘', '獙', '珌', '璧', '畀', '畢', '疪', '痹', '痺', '皕', '睤', '碧', '筚', '箅', '箆', '篦', '篳', '粊', '綼', '縪', '繴', '罼', '腷', '苾', '荜', '萆', '萞', '蓖', '蓽', '蔽', '薜', '蜌', '袐', '襅', '襞', '襣', '觱', '詖', '诐', '貱', '贔', '赑', '跸', '蹕', '躃', '躄', '避', '邲', '鄨', '鄪', '鉍', '鏎', '鐴', '铋', '閇', '閉', '閟', '闭', '陛', '韠', '飶', '饆', '馝', '駜', '驆', '髀', '魓', '鮅', '鷝', '鷩', '鼊', ], tuó: [ '佗', '坨', '堶', '岮', '槖', '橐', '沱', '砣', '砤', '碢', '紽', '詑', '跎', '酡', '阤', '陀', '陁', '駝', '駞', '騨', '驒', '驝', '驼', '鮀', '鴕', '鸵', '鼉', '鼍', '鼧', '𬶍', ], shé: ['佘', '舌', '虵', '蛥'], 'yì dié': ['佚', '昳', '泆', '軼'], 'fó fú bì bó': ['佛'], 'zuò zuō': ['作'], gōu: [ '佝', '沟', '溝', '痀', '篝', '簼', '緱', '缑', '袧', '褠', '鈎', '鉤', '钩', '鞲', '韝', ], nìng: ['佞', '侫', '倿', '寕', '泞', '澝', '濘'], qú: [ '佢', '劬', '戵', '斪', '欋', '欔', '氍', '淭', '灈', '爠', '璖', '璩', '癯', '磲', '籧', '絇', '胊', '臞', '菃', '葋', '蕖', '蘧', '蟝', '蠷', '蠼', '衐', '衢', '躣', '軥', '鑺', '鴝', '鸜', '鸲', '鼩', ], 'yōng yòng': ['佣'], wǎ: ['佤', '咓', '砙', '邷'], kǎ: ['佧', '垰', '胩', '裃', '鉲'], bāo: [ '佨', '勹', '包', '孢', '煲', '笣', '胞', '苞', '蕔', '裦', '褒', '襃', '闁', '齙', '龅', ], 'huái huí': ['佪'], 'gé hè': ['佫'], lǎo: [ '佬', '咾', '恅', '栳', '狫', '珯', '硓', '老', '耂', '荖', '蛯', '轑', '銠', '铑', '鮱', ], xiáng: ['佭', '庠', '栙', '祥', '絴', '翔', '詳', '跭'], gé: [ '佮', '匌', '呄', '嗝', '塥', '愅', '挌', '搿', '槅', '櫊', '滆', '膈', '臵', '茖', '觡', '諽', '輵', '轕', '閣', '阁', '隔', '鞷', '韐', '韚', '騔', '骼', '鮯', ], yáng: [ '佯', '劷', '垟', '崸', '徉', '扬', '揚', '敭', '旸', '昜', '暘', '杨', '楊', '洋', '炀', '珜', '疡', '瘍', '眻', '蛘', '諹', '輰', '鍚', '钖', '阦', '阳', '陽', '霷', '颺', '飏', '鰑', '鴹', '鸉', ], bǎi: ['佰', '捭', '摆', '擺', '栢', '百', '竡', '粨', '襬'], fǎ: ['佱', '峜', '法', '灋', '砝', '鍅'], mǐng: ['佲', '凕', '姳', '慏', '酩'], 'èr nài': ['佴'], hěn: ['佷', '很', '狠', '詪', '𬣳'], huó: ['佸', '活'], guǐ: [ '佹', '匦', '匭', '厬', '垝', '姽', '宄', '庋', '庪', '恑', '晷', '湀', '癸', '祪', '簋', '蛫', '蟡', '觤', '詭', '诡', '軌', '轨', '陒', '鬼', ], quán: [ '佺', '全', '啳', '埢', '姾', '峑', '巏', '拳', '搼', '权', '楾', '権', '權', '泉', '洤', '湶', '牷', '犈', '瑔', '痊', '硂', '筌', '縓', '荃', '葲', '蜷', '蠸', '觠', '詮', '诠', '跧', '踡', '輇', '辁', '醛', '銓', '铨', '闎', '顴', '颧', '駩', '騡', '鬈', '鰁', '鳈', '齤', ], tiāo: ['佻', '庣', '旫', '祧', '聎'], jiǎo: [ '佼', '儌', '孂', '挢', '搅', '撟', '撹', '攪', '敫', '敽', '敿', '晈', '暞', '曒', '灚', '燞', '狡', '璬', '皎', '皦', '絞', '纐', '绞', '腳', '臫', '蟜', '譑', '賋', '踋', '鉸', '铰', '餃', '饺', '鱎', '龣', ], cì: [ '佽', '刾', '庛', '朿', '栨', '次', '絘', '茦', '莿', '蛓', '螆', '賜', '赐', ], xíng: [ '侀', '刑', '哘', '型', '娙', '形', '洐', '硎', '蛵', '邢', '郉', '鈃', '鉶', '銒', '钘', '铏', '陉', '陘', '餳', '𫰛', ], tuō: [ '侂', '咃', '咜', '圫', '托', '拕', '拖', '汑', '脫', '脱', '莌', '袥', '託', '讬', '飥', '饦', '魠', '鮵', ], kǎn: ['侃', '偘', '冚', '坎', '惂', '砍', '莰', '輡', '轗', '顑'], zhí: [ '侄', '値', '值', '埴', '執', '姪', '嬂', '戠', '执', '摭', '植', '樴', '淔', '漐', '直', '禃', '絷', '縶', '聀', '职', '職', '膱', '蟙', '跖', '踯', '蹠', '躑', '軄', '釞', '馽', ], gāi: [ '侅', '垓', '姟', '峐', '晐', '畡', '祴', '荄', '該', '该', '豥', '賅', '賌', '赅', '陔', ], lái: [ '來', '俫', '倈', '崃', '崍', '庲', '来', '梾', '棶', '涞', '淶', '猍', '琜', '筙', '箂', '莱', '萊', '逨', '郲', '錸', '铼', '騋', '鯠', '鶆', '麳', ], kuǎ: ['侉', '咵', '垮', '銙'], gōng: [ '侊', '公', '功', '匑', '匔', '塨', '宫', '宮', '工', '幊', '弓', '恭', '攻', '杛', '碽', '糼', '糿', '肱', '觥', '觵', '躬', '躳', '髸', '龔', '龚', '䢼', ], lì: [ '例', '俐', '俪', '傈', '儮', '儷', '凓', '利', '力', '励', '勵', '历', '厉', '厤', '厯', '厲', '叓', '吏', '呖', '唎', '唳', '嚦', '囇', '坜', '塛', '壢', '娳', '婯', '屴', '岦', '悧', '悷', '慄', '戾', '搮', '暦', '曆', '曞', '朸', '枥', '栃', '栗', '栛', '檪', '櫔', '櫪', '欐', '歴', '歷', '沥', '沴', '涖', '溧', '濿', '瀝', '爏', '犡', '猁', '珕', '瑮', '瓅', '瓑', '瓥', '疬', '痢', '癧', '盭', '睙', '砅', '砺', '砾', '磿', '礪', '礫', '礰', '禲', '秝', '立', '笠', '篥', '粒', '粝', '糲', '脷', '苈', '茘', '荔', '莅', '莉', '蒚', '蒞', '藶', '蚸', '蛎', '蛠', '蜧', '蝷', '蠇', '蠣', '詈', '讈', '赲', '轢', '轣', '轹', '酈', '鉝', '隶', '隷', '雳', '靂', '靋', '鬁', '鳨', '鴗', '鷅', '麜', '𫵷', '𬍛', ], yīn: [ '侌', '凐', '喑', '噾', '囙', '因', '垔', '堙', '姻', '婣', '愔', '慇', '栶', '氤', '洇', '溵', '濦', '瘖', '禋', '秵', '筃', '絪', '緸', '茵', '蒑', '蔭', '裀', '諲', '銦', '铟', '闉', '阥', '阴', '陰', '陻', '隂', '霒', '霠', '鞇', '音', '韾', '駰', '骃', '齗', '𬘡', '𬤇', '𬮱', ], mǐ: [ '侎', '孊', '弭', '敉', '洣', '渳', '灖', '米', '粎', '羋', '脒', '芈', '葞', '蔝', '銤', ], zhū: [ '侏', '株', '槠', '橥', '櫧', '櫫', '洙', '潴', '瀦', '猪', '珠', '硃', '秼', '絑', '茱', '蕏', '蛛', '蝫', '蠩', '袾', '誅', '諸', '诛', '诸', '豬', '跦', '邾', '銖', '铢', '駯', '鮢', '鯺', '鴸', '鼄', ], ān: [ '侒', '偣', '媕', '安', '峖', '庵', '桉', '氨', '盦', '盫', '腤', '菴', '萻', '葊', '蓭', '誝', '諳', '谙', '鞌', '鞍', '韽', '馣', '鮟', '鵪', '鶕', '鹌', '𩽾', ], lù: [ '侓', '僇', '勎', '勠', '圥', '坴', '塶', '娽', '峍', '廘', '彔', '录', '戮', '摝', '椂', '樚', '淕', '淥', '渌', '漉', '潞', '琭', '璐', '甪', '盝', '睩', '硉', '祿', '禄', '稑', '穋', '箓', '簏', '簬', '簵', '簶', '籙', '粶', '蔍', '蕗', '虂', '螰', '賂', '赂', '趢', '路', '踛', '蹗', '輅', '轆', '辂', '辘', '逯', '醁', '錄', '録', '錴', '鏴', '陸', '騄', '騼', '鯥', '鴼', '鵦', '鵱', '鷺', '鹭', '鹿', '麓', '𫘧', ], móu: ['侔', '劺', '恈', '眸', '蛑', '謀', '谋', '踎', '鍪', '鴾', '麰'], ér: [ '侕', '儿', '児', '兒', '峏', '栭', '洏', '粫', '而', '胹', '荋', '袻', '輀', '轜', '陑', '隭', '髵', '鮞', '鲕', '鴯', '鸸', ], 'dòng tǒng tóng': ['侗'], chà: ['侘', '奼', '姹', '岔', '汊', '詫', '诧'], chì: [ '侙', '傺', '勅', '勑', '叱', '啻', '彳', '恜', '慗', '憏', '懘', '抶', '敕', '斥', '杘', '湁', '灻', '炽', '烾', '熾', '痓', '痸', '瘛', '翄', '翅', '翤', '翨', '腟', '赤', '趩', '遫', '鉓', '雴', '飭', '饬', '鶒', '鷘', ], 'gòng gōng': ['供', '共'], zhōu: [ '侜', '周', '喌', '州', '徟', '洲', '淍', '炿', '烐', '珘', '矪', '舟', '謅', '譸', '诌', '賙', '赒', '輈', '輖', '辀', '週', '郮', '銂', '霌', '駲', '騆', '鵃', '鸼', ], rú: [ '侞', '儒', '嚅', '如', '嬬', '孺', '帤', '曘', '桇', '渪', '濡', '筎', '茹', '蕠', '薷', '蝡', '蠕', '袽', '襦', '邚', '醹', '銣', '铷', '顬', '颥', '鱬', '鴑', '鴽', ], 'jiàn cún': ['侟'], xiá: [ '侠', '俠', '匣', '峡', '峽', '敮', '暇', '柙', '炠', '烚', '狎', '狭', '狹', '珨', '瑕', '硖', '硤', '碬', '祫', '筪', '縖', '翈', '舝', '舺', '蕸', '赮', '轄', '辖', '遐', '鍜', '鎋', '陜', '陿', '霞', '騢', '魻', '鶷', '黠', ], lǚ: [ '侣', '侶', '儢', '吕', '呂', '屡', '屢', '履', '挔', '捛', '旅', '梠', '焒', '祣', '稆', '穭', '絽', '縷', '缕', '膂', '膐', '褛', '褸', '郘', '鋁', '铝', ], ta: ['侤'], 'jiǎo yáo': ['侥', '僥', '徺'], zhēn: [ '侦', '偵', '寊', '帧', '帪', '幀', '搸', '斟', '桢', '楨', '榛', '樼', '殝', '浈', '湞', '潧', '澵', '獉', '珍', '珎', '瑧', '甄', '眞', '真', '砧', '碪', '祯', '禎', '禛', '箴', '胗', '臻', '葴', '蒖', '蓁', '薽', '貞', '贞', '轃', '遉', '酙', '針', '鉁', '錱', '鍼', '针', '鱵', ], 'cè zè zhāi': ['侧', '側'], kuài: [ '侩', '儈', '凷', '哙', '噲', '圦', '块', '塊', '巜', '廥', '快', '旝', '欳', '狯', '獪', '筷', '糩', '脍', '膾', '郐', '鄶', '鱠', '鲙', ], chái: ['侪', '儕', '喍', '柴', '犲', '祡', '豺'], nóng: [ '侬', '儂', '农', '哝', '噥', '檂', '欁', '浓', '濃', '燶', '禯', '秾', '穠', '脓', '膿', '蕽', '襛', '譨', '農', '辳', '醲', '鬞', '𬪩', ], jǐn: [ '侭', '儘', '卺', '厪', '巹', '槿', '漌', '瑾', '紧', '緊', '菫', '蓳', '謹', '谨', '錦', '锦', '饉', '馑', ], 'hóu hòu': ['侯', '矦'], jiǒng: [ '侰', '僒', '冏', '囧', '泂', '澃', '炯', '烱', '煚', '煛', '熲', '燛', '窘', '綗', '褧', '迥', '逈', '顈', '颎', '䌹', ], 'chěng tǐng': ['侱'], 'zhèn zhēn': ['侲', '揕'], zuò: [ '侳', '做', '唑', '坐', '岝', '岞', '座', '祚', '糳', '胙', '葃', '葄', '蓙', '袏', '阼', ], qīn: [ '侵', '兓', '媇', '嵚', '嶔', '欽', '衾', '誛', '钦', '顉', '駸', '骎', '鮼', ], jú: [ '侷', '啹', '婅', '局', '巈', '椈', '橘', '泦', '淗', '湨', '焗', '犑', '狊', '粷', '菊', '蘜', '趜', '跼', '蹫', '輂', '郹', '閰', '駶', '驧', '鵙', '鵴', '鶪', '鼰', '鼳', '䴗', ], 'shù dōu': ['侸'], tǐng: [ '侹', '圢', '娗', '挺', '涏', '烶', '珽', '脡', '艇', '誔', '頲', '颋', ], shèn: [ '侺', '愼', '慎', '昚', '涁', '渗', '滲', '瘆', '瘮', '眘', '祳', '肾', '胂', '脤', '腎', '蜃', '蜄', '鋠', ], 'tuì tuó': ['侻'], nán: [ '侽', '喃', '娚', '抩', '暔', '枏', '柟', '楠', '男', '畘', '莮', '萳', '遖', ], xiāo: [ '侾', '哓', '嘵', '嚻', '囂', '婋', '宯', '宵', '庨', '彇', '揱', '枭', '枵', '梟', '櫹', '歊', '毊', '消', '潇', '瀟', '灱', '灲', '烋', '焇', '猇', '獢', '痚', '痟', '硝', '硣', '窙', '箫', '簘', '簫', '綃', '绡', '翛', '膮', '萧', '蕭', '虈', '虓', '蟂', '蟏', '蟰', '蠨', '踃', '逍', '銷', '销', '霄', '颵', '驍', '骁', '髇', '髐', '魈', '鴞', '鴵', '鷍', '鸮', ], 'biàn pián': ['便', '緶', '缏'], tuǐ: ['俀', '腿', '蹆', '骽'], xì: [ '係', '匸', '卌', '呬', '墍', '屃', '屓', '屭', '忥', '怬', '恄', '椞', '潝', '潟', '澙', '熂', '犔', '磶', '禊', '細', '綌', '縘', '细', '绤', '舃', '舄', '蕮', '虩', '衋', '覤', '赩', '趇', '郤', '釳', '阋', '隙', '隟', '霼', '餼', '饩', '鬩', '黖', ], cù: [ '促', '媨', '憱', '猝', '瘄', '瘯', '簇', '縬', '脨', '蔟', '誎', '趗', '踧', '踿', '蹙', '蹴', '蹵', '醋', '顣', '鼀', ], é: [ '俄', '囮', '娥', '峉', '峨', '峩', '涐', '珴', '皒', '睋', '磀', '莪', '訛', '誐', '譌', '讹', '迗', '鈋', '鋨', '锇', '頟', '額', '额', '魤', '鵝', '鵞', '鹅', ], qiú: [ '俅', '叴', '唒', '囚', '崷', '巯', '巰', '扏', '梂', '殏', '毬', '求', '汓', '泅', '浗', '湭', '煪', '犰', '玌', '球', '璆', '皳', '盚', '紌', '絿', '肍', '芁', '莍', '虬', '虯', '蛷', '裘', '觓', '觩', '訄', '訅', '賕', '赇', '逎', '逑', '遒', '酋', '釚', '釻', '銶', '頄', '鮂', '鯄', '鰽', '鼽', '𨱇', ], xú: ['俆', '徐', '禑'], 'guàng kuāng': ['俇'], kù: [ '俈', '喾', '嚳', '库', '庫', '廤', '瘔', '絝', '绔', '袴', '裤', '褲', '酷', ], wù: [ '俉', '务', '務', '勿', '卼', '坞', '塢', '奦', '婺', '寤', '屼', '岉', '嵨', '忢', '悞', '悟', '悮', '戊', '扤', '晤', '杌', '溩', '焐', '熃', '物', '痦', '矹', '窹', '粅', '蘁', '誤', '误', '鋈', '阢', '隖', '雾', '霚', '霧', '靰', '騖', '骛', '鶩', '鹜', '鼿', '齀', ], jùn: [ '俊', '儁', '呁', '埈', '寯', '峻', '懏', '捃', '攟', '晙', '棞', '燇', '珺', '畯', '竣', '箟', '蜠', '賐', '郡', '陖', '餕', '馂', '駿', '骏', '鵔', '鵕', '鵘', '䐃', ], liáng: [ '俍', '墚', '梁', '椋', '樑', '粮', '粱', '糧', '良', '輬', '辌', '𫟅', ], zǔ: ['俎', '唨', '爼', '祖', '組', '组', '詛', '诅', '鎺', '阻', '靻'], 'qiào xiào': ['俏'], yǒng: [ '俑', '勇', '勈', '咏', '埇', '塎', '嵱', '彮', '怺', '恿', '悀', '惥', '愑', '愹', '慂', '柡', '栐', '永', '泳', '湧', '甬', '蛹', '詠', '踊', '踴', '鯒', '鲬', ], hùn: ['俒', '倱', '圂', '尡', '慁', '掍', '溷', '焝', '睴', '觨', '諢', '诨'], jìng: [ '俓', '傹', '境', '妌', '婙', '婧', '弪', '弳', '径', '徑', '敬', '曔', '桱', '梷', '浄', '瀞', '獍', '痉', '痙', '竞', '竟', '竫', '競', '竸', '胫', '脛', '莖', '誩', '踁', '迳', '逕', '鏡', '镜', '靖', '静', '靜', '鵛', ], sàn: ['俕', '閐'], pěi: ['俖'], sú: ['俗'], xī: [ '俙', '僖', '兮', '凞', '卥', '厀', '吸', '唏', '唽', '嘻', '噏', '嚱', '夕', '奚', '嬆', '嬉', '屖', '嵠', '巇', '希', '徆', '徯', '息', '悉', '悕', '惁', '惜', '昔', '晞', '晰', '晳', '曦', '析', '桸', '榽', '樨', '橀', '欷', '氥', '汐', '浠', '淅', '渓', '溪', '烯', '焁', '焈', '焟', '熄', '熈', '熙', '熹', '熺', '熻', '燨', '爔', '牺', '犀', '犠', '犧', '琋', '瘜', '皙', '睎', '瞦', '矽', '硒', '磎', '礂', '稀', '穸', '窸', '粞', '糦', '緆', '繥', '羲', '翕', '翖', '肸', '肹', '膝', '舾', '莃', '菥', '蒠', '蜥', '螅', '蟋', '蠵', '西', '觹', '觽', '觿', '譆', '谿', '豀', '豨', '豯', '貕', '赥', '邜', '鄎', '酅', '醯', '釸', '錫', '鏭', '鐊', '鑴', '锡', '隵', '餏', '饎', '饻', '鯑', '鵗', '鸂', '鼷', ], lǐ: [ '俚', '娌', '峢', '峲', '李', '欚', '浬', '澧', '理', '礼', '禮', '粴', '裏', '裡', '豊', '逦', '邐', '醴', '鋰', '锂', '鯉', '鱧', '鱱', '鲤', '鳢', ], bǎo: [ '保', '堢', '媬', '宝', '寚', '寳', '寶', '珤', '緥', '葆', '藵', '褓', '賲', '靌', '飹', '飽', '饱', '駂', '鳵', '鴇', '鸨', ], 'yú shù yù': ['俞'], 'sì qí': ['俟'], 'xìn shēn': ['信'], xiū: [ '俢', '修', '咻', '庥', '樇', '烌', '羞', '脙', '脩', '臹', '貅', '銝', '鎀', '飍', '饈', '馐', '髤', '髹', '鮴', '鱃', '鵂', '鸺', '䗛', ], dì: [ '俤', '偙', '僀', '埊', '墑', '墬', '娣', '帝', '怟', '旳', '梊', '焍', '玓', '甋', '眱', '睇', '碲', '祶', '禘', '第', '締', '缔', '腣', '菂', '蒂', '蔕', '蝃', '蝭', '螮', '諦', '谛', '踶', '递', '逓', '遞', '遰', '鉪', '𤧛', '䗖', ], chóu: [ '俦', '儔', '嬦', '惆', '愁', '懤', '栦', '燽', '畴', '疇', '皗', '稠', '筹', '籌', '絒', '綢', '绸', '菗', '詶', '讎', '讐', '踌', '躊', '酧', '酬', '醻', '雔', '雠', '雦', ], zhì: [ '俧', '偫', '儨', '制', '劕', '垁', '娡', '寘', '帙', '帜', '幟', '庢', '庤', '廌', '彘', '徏', '徝', '志', '忮', '懥', '懫', '挃', '挚', '掷', '摯', '擲', '旘', '晊', '智', '栉', '桎', '梽', '櫍', '櫛', '治', '洷', '滍', '滞', '滯', '潌', '瀄', '炙', '熫', '狾', '猘', '璏', '瓆', '痔', '痣', '礩', '祑', '秩', '秷', '稚', '稺', '穉', '窒', '紩', '緻', '置', '翐', '膣', '至', '致', '芖', '蛭', '袟', '袠', '製', '覟', '觗', '觯', '觶', '誌', '豑', '豒', '貭', '質', '贄', '质', '贽', '跱', '踬', '躓', '輊', '轾', '郅', '銍', '鋕', '鑕', '铚', '锧', '陟', '隲', '雉', '駤', '騭', '騺', '驇', '骘', '鯯', '鴙', '鷙', '鸷', '𬃊', ], 'liǎ liǎng': ['俩'], jiǎn: [ '俭', '倹', '儉', '减', '剪', '堿', '弿', '彅', '戩', '戬', '拣', '挸', '捡', '揀', '撿', '枧', '柬', '梘', '检', '検', '檢', '減', '湕', '瀽', '瑐', '睑', '瞼', '硷', '碱', '礆', '笕', '筧', '简', '簡', '絸', '繭', '翦', '茧', '藆', '蠒', '裥', '襇', '襉', '襺', '詃', '謇', '謭', '譾', '谫', '趼', '蹇', '鐗', '鬋', '鰎', '鹸', '鹻', '鹼', ], huò: [ '俰', '咟', '嚯', '嚿', '奯', '彠', '惑', '或', '擭', '旤', '曤', '檴', '沎', '湱', '瀖', '獲', '癨', '眓', '矐', '祸', '禍', '穫', '窢', '耯', '臛', '艧', '获', '蒦', '藿', '蠖', '謋', '貨', '货', '鍃', '鑊', '镬', '雘', '霍', '靃', '韄', '㸌', ], 'jù jū': ['俱', '据', '鋸', '锯'], xiào: [ '俲', '傚', '効', '咲', '哮', '啸', '嘋', '嘨', '嘯', '孝', '效', '斅', '斆', '歗', '涍', '熽', '笑', '詨', '誟', ], pái: ['俳', '徘', '牌', '犤', '猅', '簰', '簲', '輫'], biào: ['俵', '鰾', '鳔'], 'chù tì': ['俶'], fèi: [ '俷', '剕', '厞', '吠', '屝', '废', '廃', '廢', '昲', '曊', '櫠', '沸', '濷', '狒', '癈', '肺', '萉', '費', '费', '鐨', '镄', '陫', '靅', '鼣', ], fèng: ['俸', '凤', '奉', '湗', '焨', '煈', '賵', '赗', '鳯', '鳳', '鴌'], ǎn: ['俺', '唵', '埯', '揞', '罯', '銨', '铵'], bèi: [ '俻', '倍', '偝', '偹', '備', '僃', '备', '悖', '惫', '愂', '憊', '昁', '梖', '焙', '牬', '犕', '狈', '狽', '珼', '琲', '碚', '禙', '糒', '苝', '蓓', '蛽', '褙', '貝', '贝', '軰', '輩', '辈', '邶', '郥', '鄁', '鋇', '鐾', '钡', '鞁', '鞴', '𬇙', ], yù: [ '俼', '儥', '喅', '喩', '喻', '域', '堉', '妪', '嫗', '寓', '峪', '嶎', '庽', '彧', '御', '愈', '慾', '戫', '昱', '棛', '棜', '棫', '櫲', '欎', '欝', '欲', '毓', '浴', '淯', '滪', '潏', '澦', '灪', '焴', '煜', '燏', '燠', '爩', '狱', '獄', '玉', '琙', '瘉', '癒', '砡', '硢', '硲', '礇', '礖', '礜', '禦', '秗', '稢', '稶', '篽', '籞', '籲', '粖', '緎', '罭', '聿', '肀', '艈', '芋', '芌', '茟', '蒮', '蓣', '蓹', '蕷', '蘌', '蜟', '蜮', '袬', '裕', '誉', '諭', '譽', '谕', '豫', '軉', '輍', '逳', '遇', '遹', '郁', '醧', '鈺', '鋊', '錥', '鐭', '钰', '閾', '阈', '雤', '霱', '預', '预', '飫', '饇', '饫', '馭', '驈', '驭', '鬰', '鬱', '鬻', '魊', '鱊', '鳿', '鴥', '鴧', '鴪', '鵒', '鷸', '鸒', '鹆', '鹬', ], xīn: [ '俽', '噺', '妡', '嬜', '廞', '心', '忄', '忻', '惞', '新', '昕', '杺', '欣', '歆', '炘', '盺', '薪', '訢', '辛', '邤', '鈊', '鋅', '鑫', '锌', '馨', '馫', '䜣', '𫷷', ], 'hǔ chí': ['俿'], jiù: [ '倃', '僦', '匓', '匛', '匶', '厩', '咎', '就', '廄', '廏', '廐', '慦', '捄', '救', '旧', '柩', '柾', '桕', '欍', '殧', '疚', '臼', '舅', '舊', '鯦', '鷲', '鹫', '麔', '齨', '㠇', ], yáo: [ '倄', '傜', '嗂', '垚', '堯', '姚', '媱', '尧', '尭', '峣', '嶢', '嶤', '徭', '揺', '搖', '摇', '摿', '暚', '榣', '烑', '爻', '猺', '珧', '瑤', '瑶', '磘', '窑', '窯', '窰', '肴', '蘨', '謠', '謡', '谣', '軺', '轺', '遙', '遥', '邎', '顤', '颻', '飖', '餆', '餚', '鰩', '鱙', '鳐', ], 'cuì zú': ['倅'], 'liǎng liǎ': ['倆'], wǎn: [ '倇', '唍', '婉', '惋', '挽', '晚', '晥', '晩', '晼', '梚', '椀', '琬', '畹', '皖', '盌', '碗', '綩', '綰', '绾', '脘', '萖', '踠', '輓', '鋔', ], zǒng: [ '倊', '偬', '傯', '嵸', '总', '惣', '捴', '搃', '摠', '燪', '総', '緫', '縂', '總', '蓗', ], guān: [ '倌', '关', '官', '棺', '瘝', '癏', '窤', '蒄', '関', '闗', '關', '鰥', '鱞', '鳏', ], tiǎn: [ '倎', '唺', '忝', '悿', '晪', '殄', '淟', '睓', '腆', '舔', '覥', '觍', '賟', '錪', '餂', ], mén: ['們', '扪', '捫', '璊', '菛', '虋', '鍆', '钔', '門', '閅', '门', '𫞩'], 'dǎo dào': ['倒'], 'tán tàn': ['倓', '埮'], 'juè jué': ['倔'], chuí: [ '倕', '垂', '埀', '捶', '搥', '桘', '棰', '槌', '箠', '腄', '菙', '錘', '鎚', '锤', '陲', '顀', ], xìng: [ '倖', '姓', '婞', '嬹', '幸', '性', '悻', '杏', '涬', '緈', '臖', '荇', '莕', '葕', ], péng: [ '倗', '傰', '塜', '塳', '弸', '憉', '捀', '朋', '棚', '椖', '樥', '硼', '稝', '竼', '篷', '纄', '膨', '芃', '蓬', '蘕', '蟚', '蟛', '袶', '輣', '錋', '鑝', '韸', '韼', '騯', '髼', '鬅', '鬔', '鵬', '鹏', ], 'tǎng cháng': ['倘'], hòu: [ '候', '厚', '后', '垕', '堠', '後', '洉', '茩', '豞', '逅', '郈', '鮜', '鱟', '鲎', '鲘', ], tì: [ '倜', '剃', '嚏', '嚔', '屉', '屜', '悌', '悐', '惕', '惖', '戻', '掦', '替', '朑', '歒', '殢', '涕', '瓋', '笹', '籊', '薙', '褅', '逖', '逷', '髰', '鬀', '鬄', ], gàn: [ '倝', '凎', '幹', '榦', '檊', '淦', '灨', '盰', '紺', '绀', '詌', '贑', '赣', '骭', '㽏', ], 'liàng jìng': ['倞', '靓'], suī: [ '倠', '哸', '夊', '滖', '濉', '眭', '睢', '芕', '荽', '荾', '虽', '雖', '鞖', ], 'chàng chāng': ['倡'], jié: [ '倢', '偼', '傑', '刦', '刧', '刼', '劫', '劼', '卩', '卪', '婕', '媫', '孑', '岊', '崨', '嵥', '嶻', '巀', '幯', '截', '捷', '掶', '擮', '昅', '杢', '杰', '桀', '桝', '楬', '楶', '榤', '洁', '滐', '潔', '狤', '睫', '礍', '竭', '節', '羯', '莭', '蓵', '蛣', '蜐', '蠘', '蠞', '蠽', '衱', '袺', '訐', '詰', '誱', '讦', '踕', '迼', '鉣', '鍻', '镼', '頡', '鮚', '鲒', '㛃', ], 'kǒng kōng': ['倥'], juàn: [ '倦', '劵', '奆', '慻', '桊', '淃', '狷', '獧', '眷', '睊', '睠', '絭', '絹', '绢', '罥', '羂', '腃', '蔨', '鄄', '餋', ], zōng: [ '倧', '堫', '宗', '嵏', '嵕', '惾', '朡', '棕', '椶', '熧', '猣', '磫', '緃', '翪', '腙', '葼', '蝬', '豵', '踨', '踪', '蹤', '鍐', '鑁', '騌', '騣', '骔', '鬃', '鬉', '鬷', '鯮', '鯼', ], ní: [ '倪', '坭', '埿', '尼', '屔', '怩', '淣', '猊', '籾', '聣', '蚭', '蜺', '觬', '貎', '跜', '輗', '郳', '鈮', '铌', '霓', '馜', '鯢', '鲵', '麑', '齯', '𫐐', '𫠜', ], zhuō: [ '倬', '拙', '捉', '桌', '梲', '棁', '棳', '槕', '涿', '窧', '鐯', '䦃', ], 'wō wēi': ['倭'], luǒ: ['倮', '剆', '曪', '瘰', '癳', '臝', '蓏', '蠃', '裸', '躶'], sōng: [ '倯', '凇', '娀', '崧', '嵩', '庺', '憽', '松', '枀', '枩', '柗', '梥', '檧', '淞', '濍', '硹', '菘', '鬆', ], lèng: ['倰', '堎', '愣', '睖', '踜'], zì: [ '倳', '剚', '字', '恣', '渍', '漬', '牸', '眥', '眦', '胔', '胾', '自', '茡', '荢', ], bèn: ['倴', '坌', '捹', '撪', '渀', '笨', '逩'], cǎi: ['倸', '啋', '婇', '彩', '採', '棌', '毝', '睬', '綵', '跴', '踩'], zhài: ['债', '債', '寨', '瘵', '砦'], yē: ['倻', '吔', '噎', '擨', '暍', '椰', '歋', '潱', '蠮'], shà: ['倽', '唼', '喢', '歃', '箑', '翜', '翣', '萐', '閯', '霎'], qīng: [ '倾', '傾', '卿', '圊', '寈', '氢', '氫', '淸', '清', '蜻', '軽', '輕', '轻', '郬', '錆', '鑋', '靑', '青', '鯖', ], yīng: [ '偀', '嘤', '噟', '嚶', '婴', '媖', '嫈', '嬰', '孆', '孾', '愥', '撄', '攖', '朠', '桜', '樱', '櫻', '渶', '煐', '珱', '瑛', '璎', '瓔', '甇', '甖', '碤', '礯', '緓', '纓', '绬', '缨', '罂', '罃', '罌', '膺', '英', '莺', '蘡', '蝧', '蠳', '褮', '譻', '賏', '軈', '鑍', '锳', '霙', '韺', '鴬', '鶑', '鶧', '鶯', '鷪', '鷹', '鸎', '鸚', '鹦', '鹰', '䓨', ], 'chēng chèn': ['偁', '爯'], ruǎn: ['偄', '朊', '瑌', '瓀', '碝', '礝', '腝', '軟', '輭', '软', '阮'], 'zhòng tóng': ['偅'], chǔn: ['偆', '惷', '睶', '萶', '蠢', '賰'], 'jiǎ jià': ['假'], 'jì jié': ['偈'], 'bǐng bìng': ['偋'], ruò: [ '偌', '叒', '嵶', '弱', '楉', '焫', '爇', '箬', '篛', '蒻', '鄀', '鰙', '鰯', '鶸', ], tí: [ '偍', '厗', '啼', '嗁', '崹', '漽', '瑅', '睼', '禵', '稊', '緹', '缇', '罤', '蕛', '褆', '謕', '趧', '蹄', '蹏', '醍', '鍗', '題', '题', '騠', '鮷', '鯷', '鳀', '鵜', '鷤', '鹈', '𫘨', ], wēi: [ '偎', '危', '喴', '威', '媙', '嶶', '巍', '微', '愄', '揋', '揻', '椳', '楲', '溦', '烓', '煨', '燰', '癓', '縅', '葨', '葳', '薇', '蜲', '蝛', '覣', '詴', '逶', '隇', '隈', '霺', '鰃', '鰄', '鳂', ], piān: ['偏', '囨', '媥', '楄', '犏', '篇', '翩', '鍂'], yàn: [ '偐', '厌', '厭', '唁', '喭', '嚈', '嚥', '堰', '妟', '姲', '嬊', '嬿', '宴', '彥', '彦', '敥', '晏', '暥', '曕', '曣', '滟', '灎', '灔', '灧', '灩', '焔', '焰', '焱', '熖', '燄', '牪', '猒', '砚', '硯', '艳', '艶', '艷', '覎', '觃', '觾', '諺', '讌', '讞', '谚', '谳', '豓', '豔', '贋', '贗', '赝', '軅', '酀', '酽', '醼', '釅', '雁', '餍', '饜', '騐', '験', '騴', '驗', '驠', '验', '鬳', '鳫', '鴈', '鴳', '鷃', '鷰', '齞', ], 'tǎng dàng': ['偒'], è: [ '偔', '匎', '卾', '厄', '呝', '咢', '噩', '垩', '堊', '堮', '岋', '崿', '廅', '悪', '愕', '戹', '扼', '搤', '搹', '擜', '櫮', '歞', '歺', '湂', '琧', '砈', '砐', '硆', '腭', '苊', '萼', '蕚', '蚅', '蝁', '覨', '諤', '讍', '谔', '豟', '軛', '軶', '轭', '遌', '遏', '遻', '鄂', '鈪', '鍔', '鑩', '锷', '阨', '阸', '頞', '顎', '颚', '餓', '餩', '饿', '鰐', '鰪', '鱷', '鳄', '鶚', '鹗', '齃', '齶', '𫫇', '𥔲', ], xié: [ '偕', '勰', '协', '協', '嗋', '垥', '奊', '恊', '愶', '拹', '携', '撷', '擕', '擷', '攜', '斜', '旪', '熁', '燲', '綊', '緳', '縀', '缬', '翓', '胁', '脅', '脇', '脋', '膎', '蝢', '衺', '襭', '諧', '讗', '谐', '鞋', '鞵', '龤', '㙦', ], chě: ['偖', '扯', '撦'], shěng: ['偗', '渻', '眚'], chā: [ '偛', '嗏', '扠', '挿', '插', '揷', '疀', '臿', '艖', '銟', '鍤', '锸', '餷', ], huáng: [ '偟', '凰', '喤', '堭', '墴', '媓', '崲', '徨', '惶', '楻', '湟', '煌', '獚', '瑝', '璜', '癀', '皇', '磺', '穔', '篁', '簧', '艎', '葟', '蝗', '蟥', '諻', '趪', '遑', '鍠', '鐄', '锽', '隍', '韹', '餭', '騜', '鰉', '鱑', '鳇', '鷬', '黃', '黄', '𨱑', ], yǎo: [ '偠', '咬', '婹', '宎', '岆', '杳', '柼', '榚', '溔', '狕', '窅', '窈', '舀', '苭', '闄', '騕', '鷕', '齩', ], 'chǒu qiào': ['偢'], yóu: [ '偤', '尤', '庮', '怣', '沋', '油', '浟', '游', '犹', '猶', '猷', '由', '疣', '秞', '肬', '莜', '莸', '蕕', '蚰', '蝣', '訧', '輏', '輶', '逰', '遊', '邮', '郵', '鈾', '铀', '駀', '魷', '鮋', '鱿', '鲉', '𬨎', ], xū: [ '偦', '墟', '媭', '嬃', '楈', '欨', '歔', '燸', '疞', '盱', '綇', '縃', '繻', '胥', '蕦', '虗', '虚', '虛', '蝑', '裇', '訏', '許', '諝', '譃', '谞', '鑐', '需', '須', '须', '顼', '驉', '鬚', '魆', '魖', '𬣙', '𦈡', ], zhā: [ '偧', '哳', '抯', '挓', '揸', '摣', '樝', '渣', '皶', '觰', '譇', '齄', '齇', ], cī: ['偨', '疵', '蠀', '趀', '骴', '髊', '齹'], bī: ['偪', '屄', '楅', '毴', '豍', '逼', '鰏', '鲾', '鵖'], xún: [ '偱', '噚', '寻', '尋', '峋', '巡', '廵', '循', '恂', '揗', '攳', '旬', '杊', '栒', '桪', '樳', '洵', '浔', '潯', '燅', '燖', '珣', '璕', '畃', '紃', '荀', '蟳', '詢', '询', '鄩', '鱏', '鱘', '鲟', '𬘓', '𬩽', '𬍤', '𬊈', ], 'cāi sī': ['偲'], duān: ['偳', '媏', '端', '褍', '鍴'], ǒu: ['偶', '吘', '嘔', '耦', '腢', '蕅', '藕', '𬉼', '𠙶'], tōu: ['偷', '偸', '鍮'], 'zán zá zǎ': ['偺'], 'lǚ lóu': ['偻', '僂'], fèn: [ '偾', '僨', '奋', '奮', '弅', '忿', '愤', '憤', '瀵', '瞓', '秎', '粪', '糞', '膹', '鱝', '鲼', ], 'kuǐ guī': ['傀'], sǒu: ['傁', '叜', '叟', '嗾', '櫢', '瞍', '薮', '藪'], 'zhì sī tí': ['傂'], sù: [ '傃', '僳', '嗉', '塐', '塑', '夙', '嫊', '愫', '憟', '榡', '樎', '樕', '殐', '泝', '涑', '溯', '溸', '潚', '潥', '玊', '珟', '璛', '簌', '粛', '粟', '素', '縤', '肃', '肅', '膆', '蔌', '藗', '觫', '訴', '謖', '诉', '谡', '趚', '蹜', '速', '遡', '遬', '鋉', '餗', '驌', '骕', '鱐', '鷫', '鹔', '𫗧', ], xiā: ['傄', '煆', '瞎', '虲', '谺', '颬', '鰕'], 'yuàn yuán': ['傆', '媛'], rǒng: ['傇', '冗', '宂', '氄', '軵'], nù: ['傉', '怒'], yùn: [ '傊', '孕', '恽', '惲', '愠', '慍', '枟', '腪', '蕴', '薀', '藴', '蘊', '褞', '貟', '运', '運', '郓', '鄆', '酝', '醖', '醞', '韗', '韞', '韵', '韻', '餫', ], 'gòu jiǎng': ['傋'], mà: ['傌', '嘜', '榪', '睰', '祃', '禡', '罵', '閁', '駡', '骂', '鬕'], bàng: [ '傍', '塝', '棒', '玤', '稖', '艕', '蒡', '蜯', '謗', '谤', '鎊', '镑', ], diān: [ '傎', '厧', '嵮', '巅', '巓', '巔', '掂', '攧', '敁', '槇', '滇', '癫', '癲', '蹎', '顚', '顛', '颠', '齻', ], táng: [ '傏', '唐', '啺', '坣', '堂', '塘', '搪', '棠', '榶', '溏', '漟', '煻', '瑭', '磄', '禟', '篖', '糃', '糖', '糛', '膅', '膛', '蓎', '螗', '螳', '赯', '踼', '鄌', '醣', '鎕', '隚', '餹', '饄', '鶶', '䣘', ], hào: [ '傐', '哠', '恏', '昊', '昦', '晧', '暠', '暤', '暭', '曍', '浩', '淏', '澔', '灏', '灝', '皓', '皜', '皞', '皡', '皥', '耗', '聕', '薃', '號', '鄗', '顥', '颢', '鰝', ], 'xī xì': ['傒'], shān: [ '傓', '删', '刪', '剼', '圸', '山', '挻', '搧', '柵', '檆', '潸', '澘', '煽', '狦', '珊', '笘', '縿', '羴', '羶', '脠', '舢', '芟', '衫', '跚', '軕', '邖', '閊', '鯅', ], 'qiàn jiān': ['傔'], 'què jué': ['傕', '埆'], 'cāng chen': ['傖'], róng: [ '傛', '媶', '嫆', '嬫', '容', '峵', '嵘', '嶸', '戎', '搈', '曧', '栄', '榕', '榮', '榵', '毧', '溶', '瀜', '烿', '熔', '狨', '瑢', '穁', '絨', '绒', '羢', '肜', '茙', '茸', '荣', '蓉', '蝾', '融', '螎', '蠑', '褣', '鎔', '镕', '駥', ], 'tà tàn': ['傝'], suō: [ '傞', '唆', '嗍', '嗦', '娑', '摍', '桫', '梭', '睃', '簑', '簔', '羧', '莏', '蓑', '趖', '鮻', ], dǎi: ['傣', '歹'], zài: ['傤', '儎', '再', '在', '扗', '洅', '載', '酨'], gǔ: [ '傦', '古', '啒', '尳', '愲', '榖', '榾', '汩', '淈', '濲', '瀔', '牯', '皷', '皼', '盬', '瞽', '穀', '罟', '羖', '股', '脵', '臌', '薣', '蛊', '蠱', '詁', '诂', '轂', '逧', '鈷', '钴', '餶', '馉', '鼓', '鼔', '𦙶', ], bīn: [ '傧', '宾', '彬', '斌', '椕', '滨', '濒', '濱', '濵', '瀕', '繽', '缤', '虨', '豩', '豳', '賓', '賔', '邠', '鑌', '镔', '霦', '顮', ], chǔ: [ '储', '儲', '杵', '椘', '楚', '楮', '檚', '濋', '璴', '础', '礎', '禇', '處', '齭', '齼', '𬺓', ], nuó: ['傩', '儺', '挪', '梛', '橠'], 'cān càn': ['傪'], lěi: [ '傫', '儡', '厽', '垒', '塁', '壘', '壨', '櫐', '灅', '癗', '矋', '磊', '礨', '耒', '蕌', '蕾', '藟', '蘽', '蠝', '誄', '讄', '诔', '鑸', '鸓', ], cuī: ['催', '凗', '墔', '崔', '嵟', '慛', '摧', '榱', '獕', '磪', '鏙'], yōng: [ '傭', '嗈', '墉', '壅', '嫞', '庸', '廱', '慵', '拥', '擁', '滽', '灉', '牅', '痈', '癕', '癰', '臃', '邕', '郺', '鄘', '鏞', '镛', '雍', '雝', '饔', '鱅', '鳙', '鷛', ], 'zāo cáo': ['傮'], sǒng: ['傱', '嵷', '怂', '悚', '愯', '慫', '竦', '耸', '聳', '駷', '㧐'], ào: [ '傲', '坳', '垇', '墺', '奡', '嫯', '岙', '岰', '嶴', '懊', '擙', '澳', '鏊', '驁', '骜', ], 'qī còu': ['傶'], chuǎng: ['傸', '磢', '闖', '闯'], shǎ: ['傻', '儍'], hàn: [ '傼', '垾', '悍', '憾', '扞', '捍', '撖', '撼', '旱', '晘', '暵', '汉', '涆', '漢', '瀚', '焊', '猂', '皔', '睅', '翰', '莟', '菡', '蛿', '蜭', '螒', '譀', '輚', '釬', '銲', '鋎', '雗', '頷', '顄', '颔', '駻', '鶾', ], zhāng: [ '傽', '嫜', '张', '張', '彰', '慞', '暲', '樟', '漳', '獐', '璋', '章', '粻', '蔁', '蟑', '遧', '鄣', '鏱', '餦', '騿', '鱆', '麞', ], 'yān yàn': ['傿', '墕', '嬮'], 'piào biāo': ['僄', '骠'], liàn: [ '僆', '堜', '媡', '恋', '戀', '楝', '殓', '殮', '湅', '潋', '澰', '瀲', '炼', '煉', '瑓', '練', '纞', '练', '萰', '錬', '鍊', '鏈', '链', '鰊', '𬶠', ], màn: [ '㵘', '僈', '墁', '幔', '慢', '曼', '漫', '澷', '熳', '獌', '縵', '缦', '蔄', '蘰', '鄤', '鏝', '镘', '𬜬', ], 'tàn tǎn': ['僋'], yíng: [ '僌', '営', '塋', '嬴', '攍', '楹', '櫿', '溁', '溋', '滢', '潆', '濙', '濚', '濴', '瀅', '瀛', '瀠', '瀯', '灐', '灜', '熒', '營', '瑩', '盁', '盈', '禜', '籝', '籯', '縈', '茔', '荧', '莹', '萤', '营', '萦', '萾', '蓥', '藀', '蛍', '蝇', '蝿', '螢', '蠅', '謍', '贏', '赢', '迎', '鎣', ], dòng: [ '働', '冻', '凍', '动', '動', '姛', '戙', '挏', '栋', '棟', '湩', '硐', '胨', '胴', '腖', '迵', '霘', '駧', ], zhuàn: [ '僎', '啭', '囀', '堟', '撰', '灷', '瑑', '篆', '腞', '蒃', '襈', '譔', '饌', '馔', ], xiàng: [ '像', '勨', '向', '嚮', '姠', '嶑', '曏', '橡', '珦', '缿', '蟓', '衖', '襐', '象', '鐌', '項', '项', '鱌', ], shàn: [ '僐', '善', '墠', '墡', '嬗', '擅', '敾', '椫', '樿', '歚', '汕', '灗', '疝', '磰', '繕', '缮', '膳', '蟮', '蟺', '訕', '謆', '譱', '讪', '贍', '赡', '赸', '鄯', '鐥', '饍', '騸', '骟', '鱓', '鱔', '鳝', '𫮃', ], 'tuí tuǐ': ['僓'], zǔn: ['僔', '噂', '撙', '譐'], pú: [ '僕', '匍', '圤', '墣', '濮', '獛', '璞', '瞨', '穙', '莆', '菐', '菩', '葡', '蒱', '蒲', '贌', '酺', '鏷', '镤', ], láo: [ '僗', '劳', '労', '勞', '哰', '崂', '嶗', '憥', '朥', '浶', '牢', '痨', '癆', '窂', '簩', '醪', '鐒', '铹', '顟', '髝', '𫭼', ], chǎng: ['僘', '厰', '廠', '敞', '昶', '氅', '鋹', '𬬮'], guāng: [ '僙', '光', '咣', '垙', '姯', '洸', '灮', '炗', '炚', '炛', '烡', '珖', '胱', '茪', '輄', '銧', '黆', '𨐈', ], liáo: [ '僚', '嘹', '嫽', '寥', '寮', '尞', '屪', '嵺', '嶚', '嶛', '廫', '憀', '敹', '暸', '橑', '獠', '璙', '疗', '療', '竂', '簝', '繚', '缭', '聊', '膋', '膫', '藔', '蟟', '豂', '賿', '蹘', '辽', '遼', '飉', '髎', '鷯', '鹩', ], dèng: ['僜', '凳', '墱', '嶝', '櫈', '瞪', '磴', '覴', '邓', '鄧', '隥'], 'chán zhàn zhuàn': ['僝'], bō: [ '僠', '嶓', '拨', '撥', '播', '波', '溊', '玻', '癶', '盋', '砵', '碆', '礡', '缽', '菠', '袰', '蹳', '鉢', '钵', '餑', '饽', '驋', '鱍', '𬭛', ], huì: [ '僡', '匯', '卉', '喙', '嘒', '嚖', '圚', '嬒', '寭', '屶', '屷', '彗', '彙', '彚', '徻', '恚', '恵', '惠', '慧', '憓', '懳', '晦', '暳', '槥', '橞', '檅', '櫘', '汇', '泋', '滙', '潓', '烩', '燴', '獩', '璤', '瞺', '硊', '秽', '穢', '篲', '絵', '繪', '绘', '翙', '翽', '荟', '蔧', '蕙', '薈', '薉', '蟪', '詯', '誨', '諱', '譓', '譿', '讳', '诲', '賄', '贿', '鐬', '闠', '阓', '靧', '頮', '顪', '颒', '餯', '𬤝', '𬭬', ], chuǎn: ['僢', '喘', '舛', '荈', '踳'], 'tiě jiàn': ['僣'], sēng: ['僧', '鬙'], xiàn: [ '僩', '僴', '哯', '垷', '塪', '姭', '娊', '宪', '岘', '峴', '憲', '撊', '晛', '橌', '橺', '涀', '瀗', '献', '獻', '现', '現', '県', '睍', '粯', '糮', '絤', '綫', '線', '线', '缐', '羡', '羨', '腺', '臔', '臽', '苋', '莧', '誢', '豏', '鋧', '錎', '限', '陥', '陷', '霰', '餡', '馅', '麲', '鼸', '𬀪', '𪾢', ], 'yù jú': ['僪'], 'è wū': ['僫'], 'tóng zhuàng': ['僮'], lǐn: [ '僯', '凛', '凜', '廩', '廪', '懍', '懔', '撛', '檁', '檩', '澟', '癛', '癝', ], gù: [ '僱', '凅', '固', '堌', '崓', '崮', '故', '梏', '棝', '牿', '痼', '祻', '錮', '锢', '雇', '顧', '顾', '鯝', '鲴', ], jiāng: [ '僵', '壃', '姜', '橿', '殭', '江', '畕', '疅', '礓', '繮', '缰', '翞', '茳', '葁', '薑', '螀', '螿', '豇', '韁', '鱂', '鳉', ], mǐn: [ '僶', '冺', '刡', '勄', '悯', '惽', '愍', '慜', '憫', '抿', '敃', '敏', '敯', '泯', '潣', '皿', '笢', '笽', '簢', '蠠', '閔', '閩', '闵', '闽', '鰵', '鳘', '黽', ], jìn: [ '僸', '凚', '噤', '嚍', '墐', '壗', '妗', '嬧', '搢', '晉', '晋', '枃', '殣', '浕', '浸', '溍', '濅', '濜', '烬', '煡', '燼', '琎', '瑨', '璶', '盡', '祲', '縉', '缙', '荩', '藎', '覲', '觐', '賮', '贐', '赆', '近', '进', '進', '靳', '齽', ], 'jià jie': ['價'], qiào: [ '僺', '峭', '帩', '撬', '殻', '窍', '竅', '誚', '诮', '躈', '陗', '鞩', '韒', '髚', ], pì: ['僻', '媲', '嫓', '屁', '澼', '甓', '疈', '譬', '闢', '鷿', '鸊', '䴙'], sài: ['僿', '簺', '賽', '赛'], 'chán tǎn shàn': ['儃'], 'dāng dàng': ['儅', '当', '闣'], xuān: [ '儇', '喧', '塇', '媗', '宣', '愃', '愋', '揎', '昍', '暄', '煊', '煖', '瑄', '睻', '矎', '禤', '箮', '翧', '翾', '萱', '萲', '蓒', '蕿', '藼', '蘐', '蝖', '蠉', '諠', '諼', '譞', '谖', '軒', '轩', '鍹', '駽', '鰚', '𫓶', '𫍽', ], 'dān dàn': ['儋', '擔', '瘅'], càn: ['儏', '澯', '灿', '燦', '璨', '粲', '薒', '謲'], 'bīn bìn': ['儐'], 'án àn': ['儑'], tái: [ '儓', '坮', '嬯', '抬', '擡', '檯', '炱', '炲', '籉', '臺', '薹', '跆', '邰', '颱', '鮐', '鲐', ], lán: [ '儖', '兰', '囒', '婪', '岚', '嵐', '幱', '拦', '攔', '斓', '斕', '栏', '欄', '欗', '澜', '瀾', '灆', '灡', '燣', '燷', '璼', '篮', '籃', '籣', '繿', '葻', '蓝', '藍', '蘫', '蘭', '褴', '襕', '襤', '襴', '襽', '譋', '讕', '谰', '躝', '鑭', '镧', '闌', '阑', '韊', '𬒗', ], 'nǐ yì ài yí': ['儗'], méng: [ '儚', '幪', '曚', '朦', '橗', '檬', '氋', '溕', '濛', '甍', '甿', '盟', '礞', '艨', '莔', '萌', '蕄', '虻', '蝱', '鄳', '鄸', '霿', '靀', '顭', '饛', '鯍', '鸏', '鹲', '𫑡', '㠓', ], níng: [ '儜', '凝', '咛', '嚀', '嬣', '柠', '橣', '檸', '狞', '獰', '聍', '聹', '薴', '鑏', '鬡', '鸋', ], qióng: [ '儝', '卭', '宆', '惸', '憌', '桏', '橩', '焪', '焭', '煢', '熍', '琼', '瓊', '睘', '穷', '穹', '窮', '竆', '笻', '筇', '舼', '茕', '藑', '藭', '蛩', '蛬', '赹', '跫', '邛', '銎', '䓖', ], liè: [ '儠', '冽', '列', '劣', '劽', '埒', '埓', '姴', '峛', '巤', '挒', '捩', '栵', '洌', '浖', '烈', '烮', '煭', '犣', '猎', '猟', '獵', '聗', '脟', '茢', '蛚', '趔', '躐', '迾', '颲', '鬛', '鬣', '鮤', '鱲', '鴷', '䴕', '𫚭', ], kuǎng: ['儣', '夼', '懭'], bào: [ '儤', '勽', '報', '忁', '报', '抱', '曓', '爆', '犦', '菢', '虣', '蚫', '豹', '鉋', '鑤', '铇', '骲', '髱', '鮑', '鲍', ], biāo: [ '儦', '墂', '幖', '彪', '标', '標', '滮', '瀌', '熛', '爂', '猋', '瘭', '磦', '膘', '臕', '謤', '贆', '鏢', '鑣', '镖', '镳', '颮', '颷', '飆', '飇', '飈', '飊', '飑', '飙', '飚', '驫', '骉', '髟', ], zǎn: ['儧', '儹', '噆', '攅', '昝', '趱', '趲'], háo: [ '儫', '嗥', '嘷', '噑', '嚎', '壕', '椃', '毜', '毫', '濠', '獆', '獔', '竓', '籇', '蚝', '蠔', '譹', '豪', ], qìng: ['儬', '凊', '庆', '慶', '櫦', '濪', '碃', '磬', '罄', '靘'], chèn: [ '儭', '嚫', '榇', '櫬', '疢', '衬', '襯', '讖', '谶', '趁', '趂', '齓', '齔', '龀', ], téng: [ '儯', '幐', '滕', '漛', '疼', '籐', '籘', '縢', '腾', '藤', '虅', '螣', '誊', '謄', '邆', '駦', '騰', '驣', '鰧', '䲢', ], 'lǒng lóng lòng': ['儱'], 'chán chàn': ['儳'], 'ráng xiāng': ['儴', '勷'], 'huì xié': ['儶'], luó: [ '儸', '攞', '椤', '欏', '猡', '玀', '箩', '籮', '罗', '羅', '脶', '腡', '萝', '蘿', '螺', '覼', '逻', '邏', '鏍', '鑼', '锣', '镙', '饠', '騾', '驘', '骡', '鸁', ], léi: [ '儽', '嫘', '檑', '欙', '瓃', '畾', '縲', '纍', '纝', '缧', '罍', '羸', '蔂', '蘲', '虆', '轠', '鐳', '鑘', '镭', '雷', '靁', '鱩', '鼺', ], 'nàng nāng': ['儾'], 'wù wū': ['兀'], yǔn: [ '允', '喗', '夽', '抎', '殒', '殞', '狁', '磒', '荺', '賱', '鈗', '阭', '陨', '隕', '霣', '馻', '齫', '齳', ], zān: ['兂', '橵', '簪', '簮', '糌', '鐕', '鐟', '鵤'], yuán: [ '元', '円', '原', '厡', '厵', '园', '圆', '圎', '園', '圓', '垣', '塬', '媴', '嫄', '援', '榞', '榬', '橼', '櫞', '沅', '湲', '源', '溒', '爰', '猨', '猿', '笎', '緣', '縁', '缘', '羱', '茒', '薗', '蝝', '蝯', '螈', '袁', '褤', '謜', '轅', '辕', '邍', '邧', '酛', '鈨', '鎱', '騵', '魭', '鶢', '鶰', '黿', '鼋', '𫘪', ], xiōng: [ '兄', '兇', '凶', '匂', '匈', '哅', '忷', '恟', '汹', '洶', '胷', '胸', '芎', '訩', '詾', '讻', ], chōng: [ '充', '嘃', '忡', '憃', '憧', '摏', '沖', '浺', '珫', '罿', '翀', '舂', '艟', '茺', '衝', '蹖', '㳘', ], zhào: [ '兆', '垗', '旐', '曌', '枛', '櫂', '照', '燳', '狣', '瞾', '笊', '罀', '罩', '羄', '肁', '肇', '肈', '詔', '诏', '赵', '趙', '鮡', '𬶐', ], 'duì ruì yuè': ['兊', '兌', '兑'], kè: [ '克', '刻', '勀', '勊', '堁', '娔', '客', '恪', '愙', '氪', '溘', '碦', '緙', '缂', '艐', '衉', '課', '课', '錁', '锞', '騍', '骒', ], tù: ['兎', '兔', '堍', '迌', '鵵'], dǎng: ['党', '攩', '欓', '譡', '讜', '谠', '黨', '𣗋'], dōu: ['兜', '兠', '唗', '橷', '篼', '蔸'], huǎng: [ '兤', '奛', '幌', '怳', '恍', '晄', '炾', '熀', '縨', '詤', '謊', '谎', ], rù: ['入', '嗕', '媷', '扖', '杁', '洳', '溽', '縟', '缛', '蓐', '褥', '鳰'], nèi: ['內', '氝', '氞', '錗'], 'yú shù': ['兪'], 'liù lù': ['六'], han: ['兯', '爳'], tiān: ['兲', '天', '婖', '添', '酟', '靔', '靝', '黇'], 'xīng xìng': ['兴'], diǎn: [ '典', '嚸', '奌', '婰', '敟', '椣', '点', '碘', '蒧', '蕇', '踮', '點', ], 'zī cí': ['兹'], jiān: [ '兼', '冿', '囏', '坚', '堅', '奸', '姦', '姧', '尖', '幵', '惤', '戋', '戔', '搛', '椾', '樫', '櫼', '歼', '殱', '殲', '湔', '瀐', '瀸', '煎', '熞', '熸', '牋', '瑊', '睷', '礛', '礷', '笺', '箋', '緘', '縑', '缄', '缣', '肩', '艰', '艱', '菅', '菺', '葌', '蒹', '蔪', '蕑', '蕳', '虃', '譼', '豜', '鑯', '雃', '鞯', '韀', '韉', '餰', '馢', '鰔', '鰜', '鰹', '鲣', '鳒', '鵑', '鵳', '鶼', '鹣', '麉', ], shòu: [ '兽', '受', '售', '壽', '夀', '寿', '授', '狩', '獣', '獸', '痩', '瘦', '綬', '绶', '膄', ], jì: [ '兾', '冀', '剂', '剤', '劑', '勣', '坖', '垍', '塈', '妓', '季', '寂', '寄', '廭', '彑', '徛', '忌', '悸', '惎', '懻', '技', '旡', '既', '旣', '暨', '暩', '曁', '梞', '檕', '檵', '洎', '漃', '漈', '瀱', '痵', '癠', '禝', '稩', '稷', '穄', '穊', '穧', '紀', '継', '績', '繋', '繼', '继', '绩', '罽', '臮', '芰', '茍', '茤', '葪', '蓟', '蔇', '薊', '蘎', '蘮', '蘻', '裚', '襀', '覬', '觊', '計', '記', '誋', '计', '记', '跡', '跽', '蹟', '迹', '际', '際', '霁', '霽', '驥', '骥', '髻', '鬾', '魝', '魥', '鯚', '鯽', '鰶', '鰿', '鱀', '鱭', '鲚', '鲫', '鵋', '鷑', '齌', '𪟝', '𬶨', '𬶭', ], jiōng: ['冂', '冋', '坰', '埛', '扃', '蘏', '蘔', '駉', '駫', '𬳶'], mào: [ '冃', '冐', '媢', '帽', '愗', '懋', '暓', '柕', '楙', '毷', '瑁', '皃', '眊', '瞀', '耄', '茂', '萺', '蝐', '袤', '覒', '貌', '貿', '贸', '鄚', '鄮', ], rǎn: ['冄', '冉', '姌', '媣', '染', '珃', '苒', '蒅', '䎃'], 'nèi nà': ['内'], gāng: [ '冈', '冮', '刚', '剛', '堈', '堽', '岡', '掆', '摃', '棡', '牨', '犅', '疘', '綱', '纲', '缸', '罁', '罡', '肛', '釭', '鎠', '㭎', ], cè: [ '冊', '册', '厕', '厠', '夨', '廁', '恻', '惻', '憡', '敇', '测', '測', '笧', '策', '筞', '筴', '箣', '荝', '萗', '萴', '蓛', ], guǎ: ['冎', '剐', '剮', '叧', '寡'], 'mào mò': ['冒'], gòu: [ '冓', '啂', '坸', '垢', '够', '夠', '媾', '彀', '搆', '撀', '构', '構', '煹', '覯', '觏', '訽', '詬', '诟', '購', '购', '遘', '雊', ], xǔ: ['冔', '喣', '暊', '栩', '珝', '盨', '糈', '詡', '諿', '诩', '鄦', '醑'], mì: [ '冖', '冪', '嘧', '塓', '宻', '密', '峚', '幂', '幎', '幦', '怽', '榓', '樒', '櫁', '汨', '淧', '滵', '漞', '濗', '熐', '羃', '蔤', '蜜', '覓', '覔', '覛', '觅', '謐', '谧', '鼏', ], 'yóu yín': ['冘'], xiě: ['写', '冩', '藛'], jūn: [ '军', '君', '均', '桾', '汮', '皲', '皸', '皹', '碅', '莙', '蚐', '袀', '覠', '軍', '鈞', '銁', '銞', '鍕', '钧', '頵', '鮶', '鲪', '麏', ], mí: [ '冞', '擟', '瀰', '爢', '猕', '獼', '祢', '禰', '縻', '蒾', '藌', '蘪', '蘼', '袮', '詸', '謎', '迷', '醚', '醾', '醿', '釄', '镾', '鸍', '麊', '麋', '麛', ], 'guān guàn': ['冠', '覌', '観', '觀', '观'], měng: [ '冡', '勐', '懵', '掹', '猛', '獴', '艋', '蜢', '蠓', '錳', '锰', '鯭', '鼆', ], zhǒng: ['冢', '塚', '尰', '歱', '煄', '瘇', '肿', '腫', '踵'], zuì: [ '冣', '嶵', '晬', '最', '栬', '槜', '檇', '檌', '祽', '絊', '罪', '蕞', '辠', '酔', '酻', '醉', '錊', ], yuān: [ '冤', '剈', '囦', '嬽', '寃', '棩', '淵', '渁', '渆', '渊', '渕', '灁', '眢', '肙', '葾', '蒬', '蜎', '蜵', '駌', '鳶', '鴛', '鵷', '鸢', '鸳', '鹓', '鼘', '鼝', ], míng: [ '冥', '名', '明', '暝', '朙', '榠', '洺', '溟', '猽', '眀', '眳', '瞑', '茗', '螟', '覭', '詺', '鄍', '銘', '铭', '鳴', '鸣', ], kòu: [ '冦', '叩', '宼', '寇', '扣', '敂', '滱', '窛', '筘', '簆', '蔲', '蔻', '釦', '鷇', ], tài: [ '冭', '太', '夳', '忲', '态', '態', '汰', '汱', '泰', '溙', '肽', '舦', '酞', '鈦', '钛', ], 'féng píng': ['冯', '馮'], 'chōng chòng': ['冲'], kuàng: [ '况', '圹', '壙', '岲', '懬', '旷', '昿', '曠', '框', '況', '爌', '眖', '眶', '矿', '砿', '礦', '穬', '絋', '絖', '纊', '纩', '貺', '贶', '軦', '邝', '鄺', '鉱', '鋛', '鑛', '黋', ], lěng: ['冷'], pàn: [ '冸', '判', '叛', '沜', '泮', '溿', '炍', '牉', '畔', '盼', '聁', '袢', '襻', '詊', '鋬', '鑻', '頖', '鵥', ], fā: ['冹', '彂', '沷', '発', '發'], xiǎn: [ '冼', '尟', '尠', '崄', '嶮', '幰', '攇', '显', '櫶', '毨', '灦', '烍', '燹', '狝', '猃', '獫', '獮', '玁', '禒', '筅', '箲', '藓', '蘚', '蚬', '蜆', '譣', '赻', '跣', '鍌', '险', '険', '險', '韅', '顕', '顯', '㬎', ], qià: ['冾', '圶', '帢', '恰', '殎', '洽', '硈', '胢', '髂'], 'jìng chēng': ['净', '凈', '淨'], sōu: [ '凁', '嗖', '廀', '廋', '捜', '搜', '摉', '溲', '獀', '艘', '蒐', '螋', '鄋', '醙', '鎪', '锼', '颼', '飕', '餿', '馊', '騪', ], měi: [ '凂', '媄', '媺', '嬍', '嵄', '挴', '毎', '每', '浼', '渼', '燘', '美', '躾', '鎂', '镁', '黣', ], tú: [ '凃', '図', '图', '圖', '圗', '塗', '屠', '峹', '嵞', '庩', '廜', '徒', '悇', '揬', '涂', '瘏', '筡', '腯', '荼', '蒤', '跿', '途', '酴', '鈯', '鍎', '馟', '駼', '鵌', '鶟', '鷋', '鷵', '𬳿', ], zhǔn: ['准', '凖', '埻', '準', '𬘯'], 'liáng liàng': ['凉', '涼', '量'], diāo: [ '凋', '刁', '刟', '叼', '奝', '弴', '彫', '汈', '琱', '碉', '簓', '虭', '蛁', '貂', '錭', '雕', '鮉', '鯛', '鲷', '鵰', '鼦', ], còu: ['凑', '湊', '腠', '輳', '辏'], ái: ['凒', '啀', '嘊', '捱', '溰', '癌', '皑', '皚'], duó: ['凙', '剫', '夺', '奪', '痥', '踱', '鈬', '鐸', '铎'], dú: [ '凟', '匵', '嬻', '椟', '櫝', '殰', '涜', '牍', '牘', '犊', '犢', '独', '獨', '瓄', '皾', '裻', '読', '讀', '讟', '豄', '贕', '錖', '鑟', '韇', '韣', '韥', '騳', '髑', '黩', '黷', ], 'jǐ jī': ['几'], fán: [ '凡', '凢', '凣', '匥', '墦', '杋', '柉', '棥', '樊', '瀿', '烦', '煩', '燔', '璠', '矾', '礬', '笲', '籵', '緐', '羳', '舤', '舧', '薠', '蘩', '蠜', '襎', '蹯', '釩', '鐇', '鐢', '钒', '鷭', '𫔍', '𬸪', ], jū: [ '凥', '匊', '娵', '婮', '居', '崌', '抅', '挶', '掬', '梮', '椐', '檋', '毩', '毱', '泃', '涺', '狙', '琚', '疽', '砠', '罝', '腒', '艍', '蜛', '裾', '諊', '跔', '踘', '躹', '陱', '雎', '鞠', '鞫', '駒', '驹', '鮈', '鴡', '鶋', '𬶋', ], 'chù chǔ': ['処', '处'], zhǐ: [ '凪', '劧', '咫', '址', '坧', '帋', '恉', '扺', '指', '旨', '枳', '止', '汦', '沚', '洔', '淽', '疻', '砋', '祉', '秖', '紙', '纸', '芷', '藢', '衹', '襧', '訨', '趾', '軹', '轵', '酯', '阯', '黹', ], píng: [ '凭', '凴', '呯', '坪', '塀', '岼', '帡', '帲', '幈', '平', '慿', '憑', '枰', '洴', '焩', '玶', '瓶', '甁', '竮', '箳', '簈', '缾', '荓', '萍', '蓱', '蚲', '蛢', '評', '评', '軿', '輧', '郱', '鮃', '鲆', ], kǎi: [ '凯', '凱', '剀', '剴', '垲', '塏', '恺', '愷', '慨', '暟', '蒈', '輆', '鍇', '鎧', '铠', '锴', '闓', '闿', '颽', ], gān: [ '凲', '坩', '尲', '尴', '尶', '尷', '柑', '泔', '漧', '玕', '甘', '疳', '矸', '竿', '筸', '粓', '肝', '苷', '迀', '酐', '魐', ], 'kǎn qiǎn': ['凵'], tū: [ '凸', '堗', '嶀', '捸', '涋', '湥', '痜', '禿', '秃', '突', '葖', '鋵', '鵚', '鼵', '㻬', ], 'āo wā': ['凹'], chū: ['出', '初', '岀', '摴', '榋', '樗', '貙', '齣', '䢺', '䝙'], dàng: [ '凼', '圵', '垱', '壋', '档', '檔', '氹', '璗', '瓽', '盪', '瞊', '砀', '碭', '礑', '簜', '荡', '菪', '蕩', '蘯', '趤', '逿', '雼', '𬍡', ], hán: [ '函', '凾', '含', '圅', '娢', '寒', '崡', '晗', '梒', '浛', '涵', '澏', '焓', '琀', '甝', '筨', '蜬', '邗', '邯', '鋡', '韓', '韩', ], záo: ['凿', '鑿'], dāo: ['刀', '刂', '忉', '氘', '舠', '螩', '釖', '魛', '鱽'], chuāng: ['刅', '摐', '牎', '牕', '疮', '瘡', '窓', '窗', '窻'], 'fēn fèn': ['分'], 'qiè qiē': ['切'], kān: ['刊', '勘', '堪', '戡', '栞', '龕', '龛'], cǔn: ['刌', '忖'], chú: [ '刍', '厨', '幮', '廚', '橱', '櫉', '櫥', '滁', '犓', '篨', '耡', '芻', '蒢', '蒭', '蜍', '蟵', '豠', '趎', '蹰', '躇', '躕', '鉏', '鋤', '锄', '除', '雏', '雛', '鶵', ], 'huà huá': ['划'], lí: [ '刕', '剓', '剺', '劙', '厘', '喱', '嚟', '囄', '嫠', '孷', '廲', '悡', '梨', '梸', '棃', '漓', '灕', '犁', '犂', '狸', '琍', '璃', '瓈', '盠', '睝', '离', '穲', '竰', '筣', '篱', '籬', '糎', '縭', '缡', '罹', '艃', '荲', '菞', '蓠', '蔾', '藜', '蘺', '蜊', '蟍', '蟸', '蠫', '褵', '謧', '貍', '醨', '鋫', '錅', '鏫', '鑗', '離', '驪', '骊', '鯏', '鯬', '鱺', '鲡', '鵹', '鸝', '鹂', '黎', '黧', '㰀', ], yuè: [ '刖', '嬳', '岄', '岳', '嶽', '恱', '悅', '悦', '戉', '抈', '捳', '月', '樾', '瀹', '爚', '玥', '礿', '禴', '篗', '籆', '籥', '籰', '粤', '粵', '蘥', '蚎', '蚏', '説', '越', '跀', '跃', '躍', '軏', '鈅', '鉞', '鑰', '钺', '閱', '閲', '阅', '鸑', '鸙', '黦', '龠', '𫐄', '𬸚', ], liú: [ '刘', '劉', '嚠', '媹', '嵧', '旈', '旒', '榴', '橊', '流', '浏', '瀏', '琉', '瑠', '瑬', '璢', '畄', '留', '畱', '疁', '瘤', '癅', '硫', '蒥', '蓅', '蟉', '裗', '鎏', '鏐', '鐂', '镠', '飀', '飅', '飗', '駠', '駵', '騮', '驑', '骝', '鰡', '鶹', '鹠', '麍', ], zé: [ '则', '則', '啧', '嘖', '嫧', '帻', '幘', '択', '樍', '歵', '沢', '泎', '溭', '皟', '瞔', '矠', '礋', '箦', '簀', '舴', '蔶', '蠌', '襗', '謮', '賾', '赜', '迮', '鸅', '齚', '齰', ], 'chuàng chuāng': ['创', '創'], qù: ['刞', '厺', '去', '閴', '闃', '阒', '麮', '鼁'], 'bié biè': ['別', '别'], 'páo bào': ['刨'], 'chǎn chàn': ['刬', '剗', '幝'], guā: [ '刮', '劀', '桰', '歄', '煱', '瓜', '胍', '踻', '颪', '颳', '騧', '鴰', '鸹', ], gēng: [ '刯', '庚', '椩', '浭', '焿', '畊', '絚', '羮', '羹', '耕', '菮', '賡', '赓', '鶊', '鹒', ], dào: [ '到', '噵', '悼', '椡', '檤', '燾', '瓙', '盗', '盜', '稲', '稻', '纛', '翿', '艔', '菿', '衜', '衟', '軇', '道', ], chuàng: ['刱', '剏', '剙', '怆', '愴'], kū: ['刳', '哭', '圐', '堀', '枯', '桍', '矻', '窟', '跍', '郀', '骷', '鮬'], duò: [ '刴', '剁', '墯', '尮', '惰', '憜', '挅', '桗', '舵', '跥', '跺', '陊', '陏', '飿', '饳', '鵽', ], 'shuā shuà': ['刷'], 'quàn xuàn': ['券'], 'chà shā': ['刹', '剎'], 'cì cī': ['刺'], guì: [ '刽', '刿', '劊', '劌', '撌', '攰', '昋', '桂', '椢', '槶', '樻', '櫃', '猤', '禬', '筀', '蓕', '襘', '貴', '贵', '跪', '鐀', '鑎', '鞼', '鱖', '鱥', ], lóu: [ '剅', '娄', '婁', '廔', '楼', '樓', '溇', '漊', '熡', '耧', '耬', '艛', '蒌', '蔞', '蝼', '螻', '謱', '軁', '遱', '鞻', '髅', '髏', '𪣻', ], cuò: [ '剉', '剒', '厝', '夎', '挫', '措', '棤', '莝', '莡', '蓌', '逪', '銼', '錯', '锉', '错', ], 'xiāo xuē': ['削'], 'kēi kè': ['剋', '尅'], 'là lá': ['剌'], tī: ['剔', '梯', '踢', '銻', '锑', '鷈', '鷉', '䏲', '䴘'], pōu: ['剖'], wān: ['剜', '塆', '壪', '帵', '弯', '彎', '湾', '潫', '灣', '睕', '蜿', '豌'], 'bāo bō': ['剝', '剥'], duō: ['剟', '咄', '哆', '嚉', '多', '夛', '掇', '毲', '畓', '裰', '㙍'], qíng: [ '剠', '勍', '夝', '情', '擎', '晴', '暒', '棾', '樈', '檠', '氰', '甠', '硘', '葝', '黥', ], 'yǎn shàn': ['剡'], 'dū zhuó': ['剢'], yān: [ '剦', '嫣', '崦', '嶖', '恹', '懕', '懨', '樮', '淊', '淹', '漹', '烟', '焉', '焑', '煙', '珚', '篶', '胭', '臙', '菸', '鄢', '醃', '閹', '阉', '黫', ], huō: ['剨', '劐', '吙', '攉', '秴', '耠', '锪', '騞', '𬴃'], shèng: [ '剩', '剰', '勝', '圣', '墭', '嵊', '晠', '榺', '橳', '琞', '聖', '蕂', '貹', '賸', ], 'duān zhì': ['剬'], wū: [ '剭', '呜', '嗚', '圬', '屋', '巫', '弙', '杇', '歍', '汙', '汚', '污', '洿', '烏', '窏', '箼', '螐', '誈', '誣', '诬', '邬', '鄔', '鎢', '钨', '鰞', '鴮', ], gē: [ '割', '哥', '圪', '彁', '戈', '戓', '戨', '歌', '滒', '犵', '肐', '袼', '謌', '鎶', '鴚', '鴿', '鸽', ], 'dá zhá': ['剳'], chuán: ['剶', '暷', '椽', '篅', '舡', '舩', '船', '輲', '遄'], 'tuán zhuān': ['剸', '漙', '篿'], 'lù jiū': ['剹'], pēng: ['剻', '匉', '嘭', '怦', '恲', '抨', '梈', '烹', '砰', '軯', '駍'], piāo: ['剽', '勡', '慓', '旚', '犥', '翲', '螵', '飃', '飄', '飘', '魒'], kōu: ['剾', '彄', '抠', '摳', '眍', '瞘', '芤', '𫸩'], 'jiǎo chāo': ['剿', '劋', '勦', '摷'], qiāo: [ '劁', '勪', '墝', '幧', '敲', '橇', '毃', '燆', '硗', '磽', '繑', '趬', '跷', '踍', '蹺', '蹻', '郻', '鄡', '鄥', '鍫', '鍬', '鐰', '锹', '頝', ], 'huá huà': ['劃'], 'zhā zhá': ['劄'], 'pī pǐ': ['劈', '悂'], tāng: ['劏', '嘡', '羰', '薚', '蝪', '蹚', '鞺', '鼞'], chán: [ '劖', '嚵', '壥', '婵', '嬋', '巉', '廛', '棎', '毚', '湹', '潹', '潺', '澶', '瀍', '瀺', '煘', '獑', '磛', '緾', '纏', '纒', '缠', '艬', '蝉', '蟐', '蟬', '蟾', '誗', '讒', '谗', '躔', '鄽', '酁', '鋋', '鑱', '镵', '饞', '馋', ], zuān: ['劗', '躜', '躦', '鉆', '鑚'], mó: [ '劘', '嫫', '嬤', '嬷', '尛', '摹', '擵', '橅', '糢', '膜', '藦', '蘑', '謨', '謩', '谟', '饃', '饝', '馍', '髍', '魔', '魹', ], zhú: [ '劚', '斸', '曯', '欘', '灟', '炢', '烛', '燭', '爥', '瘃', '竹', '笁', '笜', '舳', '茿', '蓫', '蠋', '蠾', '躅', '逐', '逫', '钃', '鱁', ], quàn: ['劝', '勧', '勸', '牶', '韏'], 'jìn jìng': ['劤', '劲', '勁'], kēng: ['劥', '坑', '牼', '硁', '硜', '誙', '銵', '鍞', '鏗', '铿', '阬'], 'xié liè': ['劦'], 'zhù chú': ['助'], nǔ: ['努', '弩', '砮', '胬'], shào: ['劭', '卲', '哨', '潲', '紹', '綤', '绍', '袑', '邵'], miǎo: ['劰', '杪', '淼', '渺', '眇', '秒', '篎', '緲', '缈', '藐', '邈'], kǒu: ['劶', '口'], wā: [ '劸', '娲', '媧', '屲', '挖', '攨', '洼', '溛', '漥', '瓾', '畖', '穵', '窊', '窪', '蛙', '韈', '鼃', ], kuāng: [ '劻', '匡', '匩', '哐', '恇', '洭', '筐', '筺', '誆', '诓', '軭', '邼', ], hé: [ '劾', '咊', '啝', '姀', '峆', '敆', '曷', '柇', '楁', '毼', '河', '涸', '渮', '澕', '熆', '皬', '盇', '盉', '盍', '盒', '禾', '篕', '籺', '粭', '翮', '菏', '萂', '覈', '訸', '詥', '郃', '釛', '鉌', '鑉', '閡', '闔', '阂', '阖', '鞨', '頜', '餄', '饸', '魺', '鹖', '麧', '齕', '龁', '龢', '𬌗', ], gào: [ '勂', '吿', '告', '峼', '祮', '祰', '禞', '筶', '誥', '诰', '郜', '鋯', '锆', ], 'bó bèi': ['勃'], láng: [ '勆', '嫏', '廊', '斏', '桹', '榔', '樃', '欴', '狼', '琅', '瑯', '硠', '稂', '艆', '蓈', '蜋', '螂', '躴', '郒', '郞', '鋃', '鎯', '锒', ], xūn: [ '勋', '勛', '勲', '勳', '嚑', '坃', '埙', '塤', '壎', '壦', '曛', '燻', '獯', '矄', '纁', '臐', '薫', '薰', '蘍', '醺', '𫄸', ], 'juàn juān': ['勌', '瓹'], 'lè lēi': ['勒'], kài: ['勓', '炌', '烗', '鎎'], 'wěng yǎng': ['勜'], qín: [ '勤', '嗪', '噙', '嶜', '庈', '懃', '懄', '捦', '擒', '斳', '檎', '澿', '珡', '琴', '琹', '瘽', '禽', '秦', '耹', '芩', '芹', '菦', '螓', '蠄', '鈙', '鈫', '雂', '靲', '鳹', '鵭', ], jiàng: [ '勥', '匞', '匠', '嵹', '弜', '弶', '摾', '櫤', '洚', '滰', '犟', '糡', '糨', '絳', '绛', '謽', '酱', '醤', '醬', ], fān: [ '勫', '嬏', '帆', '幡', '忛', '憣', '旙', '旛', '繙', '翻', '藩', '轓', '颿', '飜', '鱕', ], juān: ['勬', '姢', '娟', '捐', '涓', '蠲', '裐', '鎸', '鐫', '镌', '鹃'], 'tóng dòng': ['勭', '烔', '燑', '狪'], lǜ: [ '勴', '垏', '嵂', '律', '慮', '氯', '滤', '濾', '爈', '箻', '綠', '繂', '膟', '葎', '虑', '鑢', ], chè: [ '勶', '坼', '彻', '徹', '掣', '撤', '澈', '烢', '爡', '瞮', '硩', '聅', '迠', '頙', '㬚', ], sháo: ['勺', '玿', '韶'], 'gōu gòu': ['勾'], cōng: [ '匆', '囪', '囱', '忩', '怱', '悤', '暰', '樬', '漗', '瑽', '璁', '瞛', '篵', '繱', '聡', '聦', '聪', '聰', '苁', '茐', '葱', '蓯', '蔥', '蟌', '鍯', '鏓', '鏦', '騘', '驄', '骢', ], 'táo yáo': ['匋', '陶'], páo: ['匏', '咆', '垉', '庖', '爮', '狍', '袍', '褜', '軳', '鞄', '麅'], dá: [ '匒', '妲', '怛', '炟', '燵', '畣', '笪', '羍', '荙', '薘', '蟽', '詚', '达', '迏', '迖', '迚', '逹', '達', '鐽', '靼', '鞑', '韃', '龖', '龘', '𫟼', ], 'huà huā': ['化'], 'běi bèi': ['北'], nǎo: ['匘', '垴', '堖', '嫐', '恼', '悩', '惱', '瑙', '碯', '脑', '脳', '腦'], 'chí shi': ['匙'], fāng: ['匚', '堏', '方', '淓', '牥', '芳', '邡', '鈁', '錺', '钫', '鴋'], zā: ['匝', '咂', '帀', '沞', '臜', '臢', '迊', '鉔', '魳'], qiè: [ '匧', '厒', '妾', '怯', '悏', '惬', '愜', '挈', '穕', '窃', '竊', '笡', '箧', '篋', '籡', '踥', '鍥', '锲', '鯜', ], 'zāng cáng': ['匨'], fěi: ['匪', '奜', '悱', '棐', '榧', '篚', '翡', '蕜', '誹', '诽'], 'kuì guì': ['匮', '匱'], suǎn: ['匴'], pǐ: ['匹', '噽', '嚭', '圮', '庀', '痞', '癖', '脴', '苉', '銢', '鴄'], 'qū ōu': ['区', '區'], 'kē qià': ['匼'], 'yǎn yàn': ['匽', '棪'], biǎn: ['匾', '惼', '揙', '碥', '稨', '窆', '藊', '褊', '貶', '贬', '鴘'], nì: [ '匿', '堄', '嫟', '嬺', '惄', '愵', '昵', '暱', '氼', '眤', '睨', '縌', '胒', '腻', '膩', '逆', '𨺙', ], niàn: ['卄', '唸', '埝', '廿', '念', '惗', '艌'], sà: ['卅', '櫒', '脎', '萨', '蕯', '薩', '鈒', '隡', '颯', '飒', '馺'], zú: ['卆', '哫', '崪', '族', '箤', '足', '踤', '镞'], shēng: [ '升', '呏', '声', '斘', '昇', '曻', '枡', '殅', '泩', '湦', '焺', '牲', '珄', '生', '甥', '竔', '笙', '聲', '鉎', '鍟', '阩', '陞', '陹', '鵿', '鼪', ], wàn: [ '卍', '卐', '忨', '杤', '瞣', '脕', '腕', '萬', '蟃', '贎', '輐', '錽', '𬇕', ], 'huá huà huā': ['华', '華'], bēi: ['卑', '悲', '揹', '杯', '桮', '盃', '碑', '藣', '鵯', '鹎'], 'zú cù': ['卒'], 'dān shàn chán': ['单', '單'], 'nán nā': ['南'], 'shuài lǜ': ['卛'], 'bǔ bo pú': ['卜'], 'kuàng guàn': ['卝'], biàn: [ '卞', '变', '変', '峅', '弁', '徧', '忭', '抃', '昪', '汳', '汴', '玣', '艑', '苄', '覍', '諚', '變', '辡', '辧', '辨', '辩', '辫', '辮', '辯', '遍', '釆', '𨚕', ], bǔ: ['卟', '哺', '捕', '补', '補', '鸔', '𬷕'], 'zhàn zhān': ['占', '覱'], 'kǎ qiǎ': ['卡'], lú: [ '卢', '嚧', '垆', '壚', '庐', '廬', '曥', '枦', '栌', '櫨', '泸', '瀘', '炉', '爐', '獹', '玈', '瓐', '盧', '矑', '籚', '纑', '罏', '胪', '臚', '舮', '舻', '艫', '芦', '蘆', '蠦', '轤', '轳', '鈩', '鑪', '顱', '颅', '馿', '髗', '魲', '鱸', '鲈', '鸕', '鸬', '黸', '𬬻', ], lǔ: [ '卤', '塷', '掳', '擄', '樐', '橹', '櫓', '氌', '滷', '澛', '瀂', '硵', '磠', '穞', '艣', '艪', '蓾', '虏', '虜', '鏀', '鐪', '鑥', '镥', '魯', '鲁', '鹵', ], guà: ['卦', '啩', '挂', '掛', '罣', '褂', '詿', '诖'], 'áng yǎng': ['卬'], yìn: [ '印', '垽', '堷', '廕', '慭', '憖', '憗', '懚', '洕', '湚', '猌', '癊', '胤', '茚', '酳', '鮣', '䲟', ], què: [ '却', '卻', '塙', '崅', '悫', '愨', '慤', '搉', '榷', '燩', '琷', '皵', '确', '確', '礭', '闋', '阕', '鵲', '鹊', '𬒈', ], luǎn: ['卵'], 'juàn juǎn': ['卷', '巻'], 'chǎng ān hàn': ['厂'], 'wěi yán': ['厃'], tīng: [ '厅', '厛', '听', '庁', '廰', '廳', '汀', '烃', '烴', '綎', '耓', '聴', '聼', '聽', '鞓', '𬘩', ], 'zhé zhái': ['厇'], 'hàn àn': ['厈', '屽'], yǎ: ['厊', '唖', '庌', '痖', '瘂', '蕥'], shè: [ '厍', '厙', '弽', '慑', '慴', '懾', '摂', '欇', '涉', '涻', '渉', '滠', '灄', '社', '舎', '蔎', '蠂', '設', '设', '赦', '騇', '麝', ], dǐ: [ '厎', '呧', '坘', '弤', '抵', '拞', '掋', '牴', '砥', '菧', '觝', '詆', '诋', '軧', '邸', '阺', '骶', '鯳', ], 'zhǎ zhǎi': ['厏'], páng: ['厐', '嫎', '庞', '徬', '舽', '螃', '逄', '鰟', '鳑', '龎', '龐'], 'zhì shī': ['厔'], máng: [ '厖', '吂', '哤', '娏', '忙', '恾', '杗', '杧', '汒', '浝', '牻', '痝', '盲', '硭', '笀', '芒', '茫', '蘉', '邙', '釯', '鋩', '铓', '駹', ], zuī: ['厜', '樶', '纗', '蟕'], 'shà xià': ['厦', '廈'], áo: [ '厫', '嗷', '嗸', '廒', '敖', '滶', '獒', '獓', '璈', '翱', '翶', '翺', '聱', '蔜', '螯', '謷', '謸', '遨', '鏖', '隞', '鰲', '鳌', '鷔', '鼇', ], 'lán qiān': ['厱'], 'sī mǒu': ['厶'], 'gōng hóng': ['厷'], 'lín miǎo': ['厸'], 'qiú róu': ['厹'], dū: ['厾', '嘟', '督', '醏'], 'xiàn xuán': ['县', '縣'], 'cān shēn cēn sān': ['参', '參', '叄', '叅'], 'ài yǐ': ['叆'], 'chā chà chǎ chá': ['叉'], shuāng: [ '双', '孀', '孇', '欆', '礵', '艭', '雙', '霜', '騻', '驦', '骦', '鷞', '鸘', '鹴', ], shōu: ['収', '收'], guái: ['叏'], bá: [ '叐', '妭', '抜', '拔', '炦', '癹', '胈', '茇', '菝', '詙', '跋', '軷', '魃', '鼥', ], 'fā fà': ['发'], 'zhuó yǐ lì jué': ['叕'], qǔ: ['取', '娶', '竬', '蝺', '詓', '齲', '龋'], 'jiǎ xiá': ['叚', '徦'], 'wèi yù': ['叞', '尉', '蔚'], dié: [ '叠', '垤', '堞', '峌', '幉', '恎', '惵', '戜', '曡', '殜', '氎', '牃', '牒', '瓞', '畳', '疂', '疉', '疊', '碟', '絰', '绖', '耊', '耋', '胅', '艓', '苵', '蜨', '蝶', '褋', '詄', '諜', '谍', '跮', '蹀', '迭', '镻', '鰈', '鲽', '鴩', '𫶇', ], ruì: ['叡', '枘', '汭', '瑞', '睿', '芮', '蚋', '蜹', '銳', '鋭', '锐'], 'jù gōu': ['句'], lìng: ['另', '呤', '炩', '蘦'], 'dāo dáo tāo': ['叨'], 'zhī zhǐ': ['只'], jiào: [ '叫', '呌', '嘂', '嘦', '噍', '嬓', '斍', '斠', '滘', '漖', '獥', '珓', '皭', '窖', '藠', '訆', '譥', '趭', '較', '轎', '轿', '较', '酵', '醮', '釂', ], 'zhào shào': ['召'], 'kě kè': ['可'], 'tái tāi': ['台', '苔'], pǒ: ['叵', '尀', '笸', '箥', '鉕', '钷', '駊'], 'yè xié': ['叶'], 'hào háo': ['号'], tàn: ['叹', '嘆', '探', '歎', '湠', '炭', '碳', '舕'], 'hōng hóng': ['叿'], miē: ['吀', '咩', '哶', '孭'], 'xū yū yù': ['吁'], chī: [ '吃', '哧', '喫', '嗤', '噄', '妛', '媸', '彨', '彲', '摛', '攡', '殦', '瓻', '痴', '癡', '眵', '瞝', '笞', '粚', '胵', '蚩', '螭', '訵', '魑', '鴟', '鵄', '鸱', '黐', '齝', '𫄨', ], 'xuān sòng': ['吅'], yāo: [ '吆', '喓', '夭', '妖', '幺', '楆', '殀', '祅', '腰', '葽', '訞', '邀', '鴁', '鴢', '㙘', ], zǐ: [ '吇', '姉', '姊', '子', '杍', '梓', '榟', '橴', '滓', '矷', '秭', '笫', '籽', '紫', '耔', '虸', '訿', '釨', ], 'hé gě': ['合', '鲄'], 'cùn dòu': ['吋'], 'tóng tòng': ['同'], 'tǔ tù': ['吐', '唋'], 'zhà zhā': ['吒', '奓'], 'xià hè': ['吓'], 'ā yā': ['吖'], 'ma má mǎ': ['吗'], lìn: [ '吝', '恡', '悋', '橉', '焛', '甐', '膦', '蔺', '藺', '賃', '赁', '蹸', '躏', '躙', '躪', '轥', '閵', ], tūn: ['吞', '暾', '朜', '焞'], 'bǐ pǐ': ['吡'], qìn: ['吢', '吣', '唚', '抋', '揿', '搇', '撳', '沁', '瀙', '菣', '藽'], 'jiè gè': ['吤'], 'fǒu pǐ': ['否'], 'ba bā': ['吧'], dūn: [ '吨', '噸', '墩', '墪', '惇', '撉', '撴', '犜', '獤', '礅', '蜳', '蹾', '驐', ], fēn: [ '吩', '帉', '昐', '朆', '梤', '棻', '氛', '竕', '紛', '纷', '翂', '芬', '衯', '訜', '躮', '酚', '鈖', '雰', '餴', '饙', '馚', ], 'é huā': ['吪'], 'kēng háng': ['吭', '妔'], shǔn: ['吮'], 'zhī zī': ['吱'], 'yǐn shěn': ['吲'], wú: [ '吳', '吴', '呉', '墲', '峿', '梧', '橆', '毋', '洖', '浯', '無', '珸', '璑', '祦', '芜', '茣', '莁', '蕪', '蜈', '蟱', '譕', '郚', '鋙', '铻', '鯃', '鵐', '鷡', '鹀', '鼯', ], 'chǎo chāo': ['吵'], 'nà nè': ['吶'], 'xuè chuò jué': ['吷'], chuī: ['吹', '炊', '龡'], 'dōu rú': ['吺'], hǒu: ['吼', '犼'], 'hōng hǒu ōu': ['吽'], 'wú yù': ['吾'], 'ya yā': ['呀'], 'è e': ['呃'], dāi: ['呆', '懛', '獃'], 'mèn qǐ': ['呇'], hōng: [ '呍', '嚝', '揈', '灴', '烘', '焢', '硡', '薨', '訇', '谾', '軣', '輷', '轟', '轰', '鍧', ], nà: [ '呐', '捺', '笝', '納', '纳', '肭', '蒳', '衲', '豽', '貀', '軜', '郍', '鈉', '钠', '靹', '魶', ], 'tūn tiān': ['呑'], 'fǔ ḿ': ['呒', '嘸'], 'dāi tǎi': ['呔'], 'ǒu ōu òu': ['呕'], 'bài bei': ['呗'], 'yuán yún yùn': ['员', '員'], guō: [ '呙', '啯', '嘓', '埚', '堝', '墎', '崞', '彉', '彍', '懖', '猓', '瘑', '聒', '蝈', '蟈', '郭', '鈛', '鍋', '锅', ], 'huá qì': ['呚'], 'qiàng qiāng': ['呛', '跄'], shī: [ '呞', '失', '尸', '屍', '师', '師', '施', '浉', '湤', '湿', '溮', '溼', '濕', '狮', '獅', '瑡', '絁', '葹', '蒒', '蓍', '虱', '蝨', '褷', '襹', '詩', '诗', '邿', '釃', '鉇', '鍦', '鯴', '鰤', '鲺', '鳲', '鳾', '鶳', '鸤', '䴓', '𫚕', ], juǎn: ['呟', '埍', '臇', '菤', '錈', '锩'], pěn: ['呠', '翸'], 'wěn mǐn': ['呡'], 'ne ní': ['呢'], 'ḿ m̀ móu': ['呣'], rán: [ '呥', '嘫', '然', '燃', '繎', '肰', '蚦', '蚺', '衻', '袇', '袡', '髥', '髯', ], 'tiè chè': ['呫'], 'qì zhī': ['呮'], 'zǐ cī': ['呰'], 'guā gū guǎ': ['呱'], 'cī zī': ['呲'], 'hǒu xǔ gòu': ['呴'], 'hē ā á ǎ à a': ['呵'], náo: [ '呶', '夒', '峱', '嶩', '巎', '挠', '撓', '猱', '硇', '蛲', '蟯', '詉', '譊', '鐃', '铙', ], 'xiā gā': ['呷'], pēi: ['呸', '怌', '肧', '胚', '衃', '醅'], 'háo xiāo': ['呺'], mìng: ['命', '掵'], 'dá dàn': ['呾'], 'zuǐ jǔ': ['咀'], 'xián gān': ['咁'], pǒu: ['咅', '哣', '犃'], 'yǎng yāng': ['咉'], 'zǎ zé zhā': ['咋'], 'hé hè huó huò hú': ['和'], hāi: ['咍'], dā: ['咑', '哒', '噠', '墶', '搭', '撘', '耷', '褡', '鎝', '𨱏'], 'kǎ kā': ['咔'], gū: [ '咕', '唂', '唃', '姑', '嫴', '孤', '巬', '巭', '柧', '橭', '沽', '泒', '稒', '笟', '箍', '箛', '篐', '罛', '苽', '菇', '菰', '蓇', '觚', '軱', '軲', '轱', '辜', '酤', '鈲', '鮕', '鴣', '鸪', ], 'kā gā': ['咖'], zuo: ['咗'], lóng: [ '咙', '嚨', '嶐', '巃', '巄', '昽', '曨', '朧', '栊', '槞', '櫳', '湰', '滝', '漋', '爖', '珑', '瓏', '癃', '眬', '矓', '砻', '礱', '礲', '窿', '竜', '聋', '聾', '胧', '茏', '蘢', '蠪', '蠬', '襱', '豅', '鏧', '鑨', '霳', '靇', '驡', '鸗', '龍', '龒', '龙', ], 'xiàn xián': ['咞'], qì: [ '咠', '唭', '噐', '器', '夡', '弃', '憇', '憩', '暣', '棄', '欫', '气', '気', '氣', '汔', '汽', '泣', '湆', '湇', '炁', '甈', '盵', '矵', '碛', '碶', '磜', '磧', '罊', '芞', '葺', '藒', '蟿', '訖', '讫', '迄', '鐑', ], 'xì dié': ['咥'], 'liē liě lié lie': ['咧'], zī: [ '咨', '嗞', '姕', '姿', '孜', '孳', '孶', '崰', '嵫', '栥', '椔', '淄', '湽', '滋', '澬', '玆', '禌', '秶', '粢', '紎', '緇', '緕', '纃', '缁', '茊', '茲', '葘', '諮', '谘', '貲', '資', '赀', '资', '赼', '趑', '趦', '輜', '輺', '辎', '鄑', '鈭', '錙', '鍿', '鎡', '锱', '镃', '頾', '頿', '髭', '鯔', '鰦', '鲻', '鶅', '鼒', '齍', '齜', '龇', ], mī: ['咪'], 'jī xī qià': ['咭'], 'gē luò kǎ lo': ['咯'], 'shù xún': ['咰'], 'zán zá zǎ zan': ['咱'], 'hāi ké': ['咳'], huī: [ '咴', '噅', '噕', '婎', '媈', '幑', '徽', '恢', '拻', '挥', '揮', '晖', '暉', '楎', '洃', '瀈', '灰', '灳', '烣', '睳', '禈', '翚', '翬', '蘳', '袆', '褘', '詼', '诙', '豗', '輝', '辉', '鰴', '麾', '㧑', ], 'huài shì': ['咶'], táo: [ '咷', '啕', '桃', '檮', '洮', '淘', '祹', '綯', '绹', '萄', '蜪', '裪', '迯', '逃', '醄', '鋾', '鞀', '鞉', '饀', '駣', '騊', '鼗', '𫘦', ], xián: [ '咸', '啣', '娴', '娹', '婱', '嫌', '嫺', '嫻', '弦', '挦', '撏', '涎', '湺', '澖', '甉', '痫', '癇', '癎', '絃', '胘', '舷', '藖', '蚿', '蛝', '衔', '衘', '誸', '諴', '賢', '贒', '贤', '輱', '醎', '銜', '鑦', '閑', '闲', '鷳', '鷴', '鷼', '鹇', '鹹', '麙', '𫍯', ], 'è àn': ['咹'], 'xuān xuǎn': ['咺', '烜'], 'wāi hé wǒ guǎ guō': ['咼'], 'yàn yè yān': ['咽'], āi: ['哀', '哎', '埃', '溾', '銰', '鎄', '锿'], pǐn: ['品', '榀'], shěn: [ '哂', '婶', '嬸', '审', '宷', '審', '弞', '曋', '渖', '瀋', '瞫', '矤', '矧', '覾', '訠', '諗', '讅', '谂', '谉', '邥', '頣', '魫', ], 'hǒng hōng hòng': ['哄'], 'wā wa': ['哇'], 'hā hǎ hà': ['哈'], zāi: ['哉', '栽', '渽', '溨', '災', '灾', '烖', '睵', '賳'], 'dì diè': ['哋'], pài: ['哌', '沠', '派', '渒', '湃', '蒎', '鎃'], 'gén hěn': ['哏'], 'yǎ yā': ['哑', '雅'], 'yuě huì': ['哕', '噦'], nián: ['哖', '年', '秊', '秥', '鮎', '鯰', '鲇', '鲶', '鵇', '黏'], 'huá huā': ['哗', '嘩'], 'jì jiē zhāi': ['哜', '嚌'], mōu: ['哞'], 'yō yo': ['哟', '喲'], lòng: ['哢', '梇', '贚'], 'ò ó é': ['哦'], 'lī lǐ li': ['哩'], 'nǎ na nǎi né něi': ['哪'], hè: [ '哬', '垎', '壑', '寉', '惒', '焃', '煂', '燺', '爀', '癋', '碋', '翯', '褐', '謞', '賀', '贺', '赫', '靍', '靎', '靏', '鶴', '鸖', '鹤', ], 'bō pò bā': ['哱'], zhé: [ '哲', '啠', '喆', '嚞', '埑', '悊', '摺', '晢', '晣', '歽', '矺', '砓', '磔', '籷', '粍', '虴', '蛰', '蟄', '袩', '詟', '謫', '謺', '讁', '讋', '谪', '輒', '輙', '轍', '辄', '辙', '鮿', ], 'liàng láng': ['哴'], 'liè lǜ': ['哷'], hān: ['哻', '憨', '蚶', '谽', '酣', '頇', '顸', '馠', '魽', '鼾'], 'hēng hng': ['哼'], gěng: [ '哽', '埂', '峺', '挭', '梗', '綆', '绠', '耿', '莄', '郠', '骾', '鯁', '鲠', '𬒔', ], 'chuò yuè': ['哾'], 'gě jiā': ['哿'], 'bei bài': ['唄'], 'hán hàn': ['唅'], chún: [ '唇', '浱', '湻', '滣', '漘', '犉', '純', '纯', '脣', '莼', '蒓', '蓴', '醇', '醕', '錞', '陙', '鯙', '鶉', '鹑', '𬭚', ], 'ài āi': ['唉'], 'jiá qiǎn': ['唊'], 'yán dàn xián': ['唌'], chē: ['唓', '砗', '硨', '莗', '蛼'], 'wú ńg ń': ['唔'], zào: [ '唕', '唣', '噪', '慥', '梍', '灶', '煰', '燥', '皁', '皂', '竃', '竈', '簉', '艁', '譟', '趮', '躁', '造', '𥖨', ], dí: [ '唙', '啇', '嘀', '嚁', '嫡', '廸', '敌', '敵', '梑', '涤', '滌', '狄', '笛', '籴', '糴', '苖', '荻', '蔋', '蔐', '藡', '覿', '觌', '豴', '迪', '靮', '頔', '馰', '髢', '鸐', '𬱖', ], 'gòng hǒng gǒng': ['唝', '嗊'], dóu: ['唞'], 'lào láo': ['唠', '嘮', '憦'], huàn: [ '唤', '喚', '奂', '奐', '宦', '嵈', '幻', '患', '愌', '换', '換', '擐', '攌', '梙', '槵', '浣', '涣', '渙', '漶', '澣', '烉', '焕', '煥', '瑍', '痪', '瘓', '睆', '肒', '藧', '豢', '轘', '逭', '鯇', '鯶', '鰀', '鲩', ], léng: ['唥', '塄', '楞', '碐', '薐'], 'wō wěi': ['唩'], fěng: ['唪', '覂', '諷', '讽'], 'yín jìn': ['唫'], 'hǔ xià': ['唬'], wéi: [ '唯', '围', '圍', '壝', '峗', '峞', '嵬', '帏', '帷', '幃', '惟', '桅', '沩', '洈', '涠', '湋', '溈', '潍', '潙', '潿', '濰', '犩', '矀', '維', '维', '蓶', '覹', '违', '違', '鄬', '醀', '鍏', '闈', '闱', '韋', '韦', '鮠', '𣲗', '𬶏', ], shuā: ['唰'], chàng: ['唱', '怅', '悵', '暢', '焻', '畅', '畼', '誯', '韔', '鬯'], 'ér wā': ['唲'], qiàng: ['唴', '炝', '熗', '羻'], yō: ['唷'], yū: ['唹', '淤', '瘀', '盓', '箊', '紆', '纡', '込', '迂', '迃', '陓'], lài: [ '唻', '濑', '瀨', '瀬', '癞', '癩', '睐', '睞', '籁', '籟', '藾', '賚', '賴', '赉', '赖', '頼', '顂', '鵣', ], tuò: ['唾', '嶞', '柝', '毤', '毻', '箨', '籜', '萚', '蘀', '跅'], 'zhōu zhāo tiào': ['啁'], kěn: ['啃', '垦', '墾', '恳', '懇', '肎', '肯', '肻', '豤', '錹'], 'zhuó zhào': ['啅', '濯'], 'hēng hèng': ['啈', '悙'], 'lín lán': ['啉'], 'a ā á ǎ à': ['啊'], qiāng: [ '啌', '嗴', '嶈', '戕', '摤', '斨', '枪', '槍', '溬', '牄', '猐', '獇', '羌', '羗', '腔', '蜣', '謒', '鏘', '锖', '锵', ], 'tūn zhūn xiāng duǐ': ['啍'], wèn: ['問', '妏', '揾', '搵', '璺', '问', '顐'], 'cuì qi': ['啐'], 'dié shà jié tì': ['啑'], 'yuē wā': ['啘'], 'zǐ cǐ': ['啙'], 'bǐ tú': ['啚'], 'chuò chuài': ['啜'], 'yǎ yā è': ['啞'], fēi: [ '啡', '婓', '婔', '扉', '暃', '渄', '猆', '緋', '绯', '裶', '霏', '非', '靟', '飛', '飝', '飞', '餥', '馡', '騑', '騛', '鯡', '鲱', '𬴂', ], pí: [ '啤', '壀', '枇', '毗', '毘', '焷', '琵', '疲', '皮', '篺', '罴', '羆', '脾', '腗', '膍', '蚍', '蚽', '蜱', '螷', '蠯', '豼', '貔', '郫', '鈹', '阰', '陴', '隦', '魮', '鮍', '鲏', '鵧', '鼙', ], shá: ['啥'], 'lā la': ['啦'], 'yīng qíng': ['啨'], pā: ['啪', '妑', '舥', '葩', '趴'], 'zhě shì': ['啫'], sè: [ '啬', '嗇', '懎', '擌', '栜', '歮', '涩', '渋', '澀', '澁', '濇', '濏', '瀒', '瑟', '璱', '瘷', '穑', '穡', '穯', '繬', '譅', '轖', '銫', '鏼', '铯', '飋', ], niè: [ '啮', '嗫', '噛', '嚙', '囁', '囓', '圼', '孼', '孽', '嵲', '嶭', '巕', '帇', '敜', '枿', '槷', '櫱', '涅', '湼', '痆', '篞', '籋', '糱', '糵', '聂', '聶', '臬', '臲', '蘖', '蠥', '讘', '踂', '踗', '踙', '蹑', '躡', '錜', '鎳', '鑈', '鑷', '钀', '镊', '镍', '闑', '陧', '隉', '顳', '颞', '齧', '𫔶', ], 'luō luó luo': ['啰', '囉'], 'tān chǎn tuō': ['啴'], bo: ['啵', '蔔'], dìng: [ '啶', '定', '椗', '矴', '碇', '碠', '磸', '聢', '腚', '萣', '蝊', '訂', '订', '錠', '锭', '顁', '飣', '饤', ], lāng: ['啷'], 'án ān': ['啽'], kā: ['喀', '擖'], 'yóng yú': ['喁'], 'lā lá lǎ': ['喇'], jiē: [ '喈', '喼', '嗟', '堦', '媘', '接', '掲', '擑', '湝', '煯', '疖', '痎', '癤', '皆', '秸', '稭', '脻', '蝔', '街', '謯', '阶', '階', '鞂', '鶛', ], hóu: [ '喉', '帿', '猴', '瘊', '睺', '篌', '糇', '翭', '葔', '鄇', '鍭', '餱', '骺', '鯸', '𬭤', ], 'dié zhá': ['喋'], wāi: ['喎', '歪', '竵'], 'nuò rě': ['喏'], 'xù huò guó': ['喐'], zán: ['喒'], 'wō ō': ['喔'], hú: [ '喖', '嘝', '囫', '壶', '壷', '壺', '媩', '弧', '搰', '斛', '楜', '槲', '湖', '瀫', '焀', '煳', '狐', '猢', '瑚', '瓳', '箶', '絗', '縠', '胡', '葫', '蔛', '蝴', '螜', '衚', '觳', '醐', '鍸', '頶', '餬', '鬍', '魱', '鰗', '鵠', '鶘', '鶦', '鹕', ], 'huàn yuán xuǎn hé': ['喛'], xǐ: [ '喜', '囍', '壐', '屣', '徙', '憙', '枲', '橲', '歖', '漇', '玺', '璽', '矖', '禧', '縰', '葈', '葸', '蓰', '蟢', '謑', '蹝', '躧', '鈢', '鉨', '鉩', '鱚', '𬭳', '𬶮', ], 'hē hè yè': ['喝'], kuì: [ '喟', '嘳', '媿', '嬇', '愦', '愧', '憒', '篑', '簣', '籄', '聩', '聭', '聵', '膭', '蕢', '謉', '餽', '饋', '馈', ], 'zhǒng chuáng': ['喠'], 'wéi wèi': ['喡', '為', '爲'], 'duó zhà': ['喥'], 'sāng sàng': ['喪'], 'qiáo jiāo': ['喬'], 'pèn bēn': ['喯'], 'cān sūn qī': ['喰'], 'zhā chā': ['喳'], miāo: ['喵'], 'pēn pèn': ['喷'], kuí: [ '喹', '夔', '奎', '巙', '戣', '揆', '晆', '暌', '楏', '楑', '櫆', '犪', '睽', '葵', '藈', '蘷', '虁', '蝰', '躨', '逵', '鄈', '鍨', '鍷', '頯', '馗', '騤', '骙', '魁', ], 'lou lóu': ['喽'], 'zào qiāo': ['喿'], 'hè xiāo xiào hù': ['嗃'], 'á shà': ['嗄'], xiù: [ '嗅', '岫', '峀', '溴', '珛', '琇', '璓', '秀', '綉', '繍', '繡', '绣', '螑', '袖', '褎', '褏', '銹', '鏥', '鏽', '锈', '齅', ], 'qiāng qiàng': ['嗆', '戗', '戧', '蹌', '蹡'], 'ài yì': ['嗌', '艾'], 'má mǎ ma': ['嗎'], 'kè kē': ['嗑'], 'dā tà': ['嗒', '鎉'], sǎng: ['嗓', '搡', '磉', '褬', '鎟', '顙', '颡'], chēn: ['嗔', '抻', '琛', '瞋', '諃', '謓', '賝', '郴', '𬘭'], 'wā gǔ': ['嗗'], 'pǎng bēng': ['嗙'], 'xián qiǎn qiān': ['嗛'], lào: ['嗠', '嫪', '橯', '涝', '澇', '耢', '耮', '躼', '軂', '酪'], wēng: ['嗡', '翁', '聬', '螉', '鎓', '鶲', '鹟', '𬭩'], wà: ['嗢', '腽', '膃', '袜', '襪', '韤'], 'hēi hāi': ['嗨'], hē: ['嗬', '欱', '蠚', '訶', '诃'], zi: ['嗭'], sǎi: ['嗮'], 'ǹg ńg ňg': ['嗯'], gě: ['嗰', '舸'], ná: ['嗱', '拏', '拿', '鎿', '镎'], diǎ: ['嗲'], 'ài ǎi āi': ['嗳'], tōng: ['嗵', '樋', '炵', '蓪'], 'zuī suī': ['嗺'], 'zhē zhè zhù zhe': ['嗻'], mò: [ '嗼', '圽', '塻', '墨', '妺', '嫼', '寞', '帞', '昩', '末', '枺', '歿', '殁', '沫', '漠', '爅', '獏', '瘼', '皌', '眽', '眿', '瞐', '瞙', '砞', '礳', '秣', '絈', '纆', '耱', '茉', '莈', '蓦', '蛨', '蟔', '貃', '貊', '貘', '銆', '鏌', '镆', '陌', '靺', '驀', '魩', '默', '黙', '𬙊', ], sòu: ['嗽', '瘶'], tǎn: [ '嗿', '坦', '忐', '憳', '憻', '暺', '毯', '璮', '菼', '袒', '襢', '醓', '鉭', '钽', ], 'jiào dǎo': ['嘄'], 'kǎi gě': ['嘅'], 'shān càn': ['嘇'], cáo: ['嘈', '嶆', '曹', '曺', '槽', '漕', '艚', '蓸', '螬', '褿', '鏪', '𥕢'], piào: ['嘌', '徱', '蔈', '驃'], 'lóu lou': ['嘍'], gǎ: ['尕', '玍'], 'gǔ jiǎ': ['嘏'], 'jiāo xiāo': ['嘐'], 'xū shī': ['嘘', '噓'], pó: ['嘙', '嚩', '婆', '櫇', '皤', '鄱'], 'dē dēi': ['嘚'], 'ma má': ['嘛'], 'lē lei': ['嘞'], 'gā gá gǎ': ['嘠'], sāi: ['嘥', '噻', '毢', '腮', '顋', '鰓'], 'zuō chuài': ['嘬'], 'cháo zhāo': ['嘲', '朝', '鼂'], zuǐ: ['嘴', '噿', '嶊', '璻'], 'qiáo qiào': ['嘺', '翹', '谯'], 'chù xù shòu': ['嘼'], 'tān chǎn': ['嘽'], 'dàn tán': ['嘾', '弾', '彈', '惔', '澹'], 'hēi mò': ['嘿'], ě: ['噁', '砨', '頋', '騀', '鵈'], 'fān bo': ['噃'], chuáng: ['噇', '床', '牀'], 'cù zā hé': ['噈'], 'tūn kuò': ['噋'], 'cēng chēng': ['噌'], dēng: ['噔', '嬁', '灯', '燈', '璒', '登', '竳', '簦', '艠', '豋'], pū: ['噗', '扑', '撲', '攴', '攵', '潽', '炇', '陠'], juē: ['噘', '屩', '屫', '撧'], lū: ['噜', '嚕', '撸', '擼', '謢'], zhān: [ '噡', '岾', '惉', '旃', '旜', '枬', '栴', '毡', '氈', '氊', '沾', '瞻', '薝', '蛅', '詀', '詹', '譫', '谵', '趈', '邅', '閚', '霑', '飦', '饘', '驙', '魙', '鱣', '鸇', '鹯', '𫗴', ], ō: ['噢'], 'zhòu zhuó': ['噣'], 'jiào qiào chī': ['噭'], yuàn: [ '噮', '妴', '怨', '愿', '掾', '瑗', '禐', '苑', '衏', '裫', '褑', '院', '願', ], 'ǎi ài āi': ['噯'], 'yōng yǒng': ['噰', '澭'], 'jué xué': ['噱'], 'pēn pèn fèn': ['噴'], gá: ['噶', '尜', '釓', '錷', '钆'], 'xīn hěn hèn': ['噷'], dāng: ['噹', '澢', '珰', '璫', '筜', '簹', '艡', '蟷', '裆', '襠'], làn: ['嚂', '滥', '濫', '烂', '燗', '爁', '爛', '爤', '瓓', '糷', '钄'], tà: [ '嚃', '嚺', '崉', '挞', '搨', '撻', '榻', '橽', '毾', '涾', '澾', '濌', '禢', '粏', '誻', '譶', '蹋', '蹹', '躂', '躢', '遝', '錔', '闒', '闥', '闼', '阘', '鞜', '鞳', ], 'huō huò ǒ': ['嚄'], hāo: ['嚆', '茠', '蒿', '薅'], 'hè xià': ['嚇'], 'xiù pì': ['嚊'], 'zhōu chóu': ['嚋', '盩', '诪'], mē: ['嚒'], 'chā cā': ['嚓'], 'bó pào bào': ['嚗'], 'me mèi mò': ['嚜'], 'xié hái': ['嚡'], 'áo xiāo': ['嚣'], mō: ['嚤', '摸'], pín: [ '嚬', '娦', '嫔', '嬪', '玭', '矉', '薲', '蠙', '貧', '贫', '顰', '颦', '𬞟', ], mè: ['嚰', '濹'], 'rǎng rāng': ['嚷'], lá: ['嚹', '旯'], 'jiáo jué jiào': ['嚼'], chuò: [ '嚽', '娖', '擉', '歠', '涰', '磭', '踀', '輟', '辍', '辵', '辶', '酫', '鑡', '餟', '齪', '龊', ], 'huān huàn': ['嚾'], 'zá cà': ['囃'], chài: ['囆', '虿', '蠆', '袃', '訍'], 'náng nāng': ['囊'], 'zá zàn cān': ['囋'], sū: ['囌', '櫯', '甦', '稣', '穌', '窣', '蘇', '蘓', '酥', '鯂'], zèng: ['囎', '熷', '甑', '贈', '赠', '鋥', '锃'], 'zá niè yàn': ['囐'], nāng: ['囔'], 'luó luō luo': ['囖'], 'wéi guó': ['囗'], huí: [ '囘', '回', '囬', '廻', '廽', '恛', '洄', '痐', '茴', '蚘', '蛔', '蛕', '蜖', '迴', '逥', '鮰', ], nín: ['囜', '您', '脌'], 'jiǎn nān': ['囝'], nān: ['囡'], tuán: ['团', '団', '團', '慱', '抟', '摶', '檲', '糰', '鏄', '鷒', '鷻'], 'tún dùn': ['囤', '坉'], guó: [ '囯', '囶', '囻', '国', '圀', '國', '帼', '幗', '慖', '摑', '漍', '聝', '腘', '膕', '蔮', '虢', '馘', '𬇹', ], kùn: ['困', '涃', '睏'], 'wéi tōng': ['囲'], qūn: ['囷', '夋', '逡'], rì: ['囸', '日', '衵', '鈤', '馹', '驲'], tāi: ['囼', '孡', '胎'], pǔ: [ '圃', '圑', '擈', '普', '暜', '樸', '檏', '氆', '浦', '溥', '烳', '諩', '譜', '谱', '蹼', '鐠', '镨', ], 'quān juàn juān': ['圈', '圏'], 'chuí chuán': ['圌'], tuǎn: ['圕', '畽', '疃'], lüè: ['圙', '掠', '略', '畧', '稤', '鋝', '鋢', '锊', '䂮'], 'huán yuán': ['圜'], luán: [ '圝', '圞', '奱', '娈', '孌', '孪', '孿', '峦', '巒', '挛', '攣', '曫', '栾', '欒', '滦', '灤', '癴', '癵', '羉', '脔', '臠', '虊', '銮', '鑾', '鵉', '鸞', '鸾', ], tǔ: ['土', '圡', '釷', '钍'], 'xū wéi': ['圩'], 'dì de': ['地', '嶳'], 'qiān sú': ['圱'], zhèn: [ '圳', '塦', '挋', '振', '朕', '栚', '甽', '眹', '紖', '絼', '纼', '誫', '賑', '赈', '鋴', '鎭', '鎮', '镇', '阵', '陣', '震', '鴆', '鸩', ], 'chǎng cháng': ['场', '場', '塲'], 'qí yín': ['圻'], jiá: [ '圿', '忦', '恝', '戞', '扴', '脥', '荚', '莢', '蛱', '蛺', '裌', '跲', '郏', '郟', '鋏', '铗', '頬', '頰', '颊', '鴶', '鵊', ], 'zhǐ zhì': ['坁'], bǎn: [ '坂', '岅', '昄', '板', '版', '瓪', '粄', '舨', '蝂', '鈑', '钣', '阪', '魬', ], qǐn: ['坅', '寑', '寝', '寢', '昑', '梫', '笉', '螼', '赾', '鋟', '锓'], 'méi fén': ['坆'], 'rǒng kēng': ['坈'], 'fāng fáng': ['坊'], 'fèn bèn': ['坋'], tān: ['坍', '怹', '摊', '擹', '攤', '滩', '灘', '瘫', '癱', '舑', '貪', '贪'], 'huài pēi pī péi': ['坏'], 'dì làn': ['坔'], tán: [ '坛', '墰', '墵', '壇', '壜', '婒', '憛', '昙', '曇', '榃', '檀', '潭', '燂', '痰', '磹', '罈', '罎', '藫', '談', '譚', '譠', '谈', '谭', '貚', '郯', '醰', '錟', '顃', ], bà: ['坝', '垻', '壩', '弝', '欛', '灞', '爸', '矲', '覇', '霸', '鮁', '鲅'], fén: [ '坟', '墳', '妢', '岎', '幩', '枌', '棼', '汾', '焚', '燌', '燓', '羒', '羵', '蒶', '蕡', '蚠', '蚡', '豮', '豶', '轒', '鐼', '隫', '馩', '魵', '黂', '鼖', '鼢', '𣸣', ], zhuì: [ '坠', '墜', '惴', '甀', '畷', '礈', '綴', '縋', '缀', '缒', '腏', '膇', '諈', '贅', '赘', '醊', '錣', '鑆', ], pō: ['坡', '岥', '泼', '溌', '潑', '釙', '鏺', '钋', '頗', '颇', '䥽'], 'pǎn bàn': ['坢'], kūn: [ '坤', '堃', '堒', '崐', '崑', '昆', '晜', '潉', '焜', '熴', '猑', '琨', '瑻', '菎', '蜫', '裈', '裩', '褌', '醌', '錕', '锟', '騉', '髠', '髡', '髨', '鯤', '鲲', '鵾', '鶤', '鹍', ], diàn: [ '坫', '垫', '墊', '壂', '奠', '婝', '店', '惦', '扂', '橂', '殿', '淀', '澱', '玷', '琔', '电', '癜', '簟', '蜔', '鈿', '電', '靛', '驔', ], 'mù mǔ': ['坶'], 'kē kě': ['坷', '軻'], xuè: ['坹', '岤', '桖', '瀥', '狘', '瞲', '謔', '谑', '趐'], 'dǐ chí': ['坻', '柢'], lā: ['垃', '柆', '菈', '邋'], lǒng: ['垄', '垅', '壟', '壠', '拢', '攏', '竉', '陇', '隴', '𬕂'], mín: [ '垊', '姄', '岷', '崏', '捪', '旻', '旼', '民', '珉', '琘', '琝', '瑉', '痻', '盿', '砇', '緍', '緡', '缗', '罠', '苠', '鈱', '錉', '鍲', '鴖', ], 'dòng tóng': ['垌', '峒', '洞'], cí: [ '垐', '嬨', '慈', '柌', '濨', '珁', '瓷', '甆', '磁', '礠', '祠', '糍', '茨', '詞', '词', '辝', '辞', '辤', '辭', '雌', '飺', '餈', '鴜', '鶿', '鷀', '鹚', ], duī: ['垖', '堆', '塠', '痽', '磓', '鐓', '鐜', '鴭'], 'duò duǒ': ['垛'], 'duǒ duò': ['垜', '挆'], chá: ['垞', '察', '嵖', '搽', '槎', '檫', '猹', '茬', '茶', '詧', '靫', '𥻗'], shǎng: ['垧', '晌', '樉', '賞', '贘', '赏', '鋿', '鏛', '鑜'], shǒu: ['垨', '守', '手', '扌', '艏', '首'], da: ['垯', '繨', '跶'], háng: [ '垳', '斻', '杭', '筕', '絎', '绗', '航', '苀', '蚢', '裄', '貥', '迒', '頏', '颃', '魧', ], 'ān ǎn': ['垵'], xīng: [ '垶', '惺', '星', '曐', '煋', '猩', '瑆', '皨', '篂', '腥', '興', '觪', '觲', '謃', '騂', '骍', '鮏', '鯹', ], 'yuàn huán': ['垸'], bāng: [ '垹', '帮', '幇', '幚', '幫', '捠', '梆', '浜', '邦', '邫', '鞤', '𠳐', ], 'póu fú': ['垺'], cén: ['埁', '岑', '涔'], 'běng fēng': ['埄'], 'dì fáng': ['埅'], 'xiá jiā': ['埉'], 'mái mán': ['埋'], làng: ['埌', '崀', '浪', '蒗', '閬', '㫰'], 'shān yán': ['埏'], 'qín jīn': ['埐'], 'pǔ bù': ['埔'], huā: ['埖', '婲', '椛', '硴', '糀', '花', '蒊', '蘤', '誮', '錵'], 'suì sù': ['埣'], 'pí pì': ['埤'], 'qīng zhēng': ['埥', '鲭'], 'wǎn wān': ['埦'], lǔn: ['埨', '稐', '𫭢'], 'zhēng chéng': ['埩'], kōng: ['埪', '崆', '箜', '躻', '錓', '鵼'], 'cǎi cài': ['埰', '寀', '采'], 'chù tòu': ['埱'], běng: ['埲', '琫', '菶', '鞛'], 'kǎn xiàn': ['埳'], 'yì shì': ['埶', '醳'], péi: ['培', '毰', '裴', '裵', '賠', '赔', '錇', '锫', '阫', '陪'], 'sào sǎo': ['埽'], 'jǐn qīn jìn': ['堇'], 'péng bèng': ['堋'], 'qiàn zàn jiàn': ['堑'], àn: [ '堓', '屵', '岸', '按', '暗', '案', '胺', '荌', '豻', '貋', '錌', '闇', '隌', '黯', ], 'duò huī': ['堕', '墮'], huán: [ '堚', '寏', '寰', '峘', '桓', '洹', '澴', '獂', '环', '環', '糫', '繯', '缳', '羦', '荁', '萈', '萑', '豲', '鍰', '鐶', '锾', '镮', '闤', '阛', '雈', '鬟', '鹮', '𬘫', '𤩽', ], 'bǎo bǔ pù': ['堡'], 'máo móu wǔ': ['堥'], ruán: ['堧', '壖', '撋'], 'ài è yè': ['堨'], gèng: ['堩', '暅'], méi: [ '堳', '塺', '媒', '嵋', '徾', '攗', '枚', '栂', '梅', '楣', '楳', '槑', '湄', '湈', '煤', '猸', '玫', '珻', '瑂', '眉', '睂', '禖', '脄', '脢', '腜', '苺', '莓', '葿', '郿', '酶', '鎇', '镅', '霉', '鶥', '鹛', '黴', ], dǔ: ['堵', '琽', '睹', '笃', '篤', '覩', '賭', '赌'], féng: ['堸', '綘', '艂', '逢'], hèng: ['堼'], chūn: [ '堾', '媋', '旾', '春', '暙', '杶', '椿', '槆', '橁', '櫄', '瑃', '箺', '萅', '蝽', '輴', '鰆', '鶞', '䲠', ], jiǎng: [ '塂', '奖', '奨', '奬', '桨', '槳', '獎', '耩', '膙', '蒋', '蔣', '講', '讲', '顜', ], huāng: ['塃', '巟', '慌', '肓', '荒', '衁'], duàn: [ '塅', '断', '斷', '椴', '段', '毈', '煅', '瑖', '碫', '簖', '籪', '緞', '缎', '腶', '葮', '躖', '鍛', '锻', ], tǎ: ['塔', '墖', '獭', '獺', '鮙', '鰨', '鳎'], wěng: ['塕', '奣', '嵡', '攚', '暡', '瞈', '蓊'], 'sāi sài sè': ['塞'], zàng: ['塟', '弉', '臓', '臟', '葬', '蔵', '銺'], tián: [ '塡', '屇', '恬', '沺', '湉', '璳', '甛', '甜', '田', '畋', '畑', '碵', '磌', '胋', '闐', '阗', '鴫', '鷆', '鷏', ], zhèng: [ '塣', '幁', '政', '証', '諍', '證', '证', '诤', '郑', '鄭', '靕', '鴊', ], 'tián zhèn': ['填'], wēn: [ '塭', '昷', '榲', '殟', '温', '溫', '瑥', '瘟', '蕰', '豱', '輼', '轀', '辒', '鎾', '饂', '鰛', '鰮', '鳁', ], liù: ['塯', '廇', '磟', '翏', '雡', '霤', '餾', '鬸', '鷚', '鹨'], hǎi: ['塰', '海', '烸', '酼', '醢'], lǎng: ['塱', '朖', '朗', '朤', '烺', '蓢', '㮾'], bèng: ['塴', '揼', '泵', '甏', '綳', '蹦', '迸', '逬', '鏰', '镚'], chén: [ '塵', '宸', '尘', '忱', '敐', '敶', '晨', '曟', '栕', '樄', '沉', '煁', '瘎', '臣', '茞', '莀', '莐', '蔯', '薼', '螴', '訦', '諶', '軙', '辰', '迧', '鈂', '陈', '陳', '霃', '鷐', '麎', ], 'ōu qiū': ['塸'], 'qiàn jiàn': ['塹'], 'zhuān tuán': ['塼'], shuǎng: ['塽', '慡', '漺', '爽', '縔', '鏯'], shú: ['塾', '婌', '孰', '璹', '秫', '贖', '赎'], lǒu: ['塿', '嵝', '嶁', '甊', '篓', '簍'], chí: [ '墀', '弛', '持', '池', '漦', '竾', '筂', '箎', '篪', '茌', '荎', '蚳', '謘', '貾', '赿', '踟', '迟', '迡', '遅', '遟', '遲', '鍉', '馳', '驰', ], shù: [ '墅', '庶', '庻', '怷', '恕', '戍', '束', '树', '樹', '沭', '漱', '潄', '濖', '竖', '竪', '絉', '腧', '荗', '蒁', '虪', '術', '裋', '豎', '述', '鉥', '錰', '鏣', '霔', '鶐', '𬬸', ], 'dì zhì': ['墆', '疐'], kàn: ['墈', '崁', '瞰', '矙', '磡', '衎', '鬫'], chěn: ['墋', '夦', '硶', '碜', '磣', '贂', '趻', '踸', '鍖'], 'zhǐ zhuó': ['墌'], qiǎng: ['墏', '繈', '繦', '羥', '襁'], zēng: ['増', '增', '憎', '璔', '矰', '磳', '罾', '譄', '鄫', '鱛', '䎖'], qiáng: [ '墙', '墻', '嫱', '嬙', '樯', '檣', '漒', '牆', '艢', '蔃', '蔷', '蘠', ], 'kuài tuí': ['墤'], 'tuǎn dǒng': ['墥'], 'qiáo què': ['墧'], 'zūn dūn': ['墫'], 'qiāo áo': ['墽'], 'yì tú': ['墿'], 'xué bó jué': ['壆'], lǎn: [ '壈', '嬾', '孄', '孏', '懒', '懶', '揽', '擥', '攬', '榄', '欖', '浨', '漤', '灠', '纜', '缆', '罱', '覧', '覽', '览', '醂', '顲', ], huài: ['壊', '壞', '蘾'], rǎng: ['壌', '壤', '攘', '爙'], 'làn xiàn': ['壏'], dǎo: [ '壔', '导', '導', '岛', '島', '嶋', '嶌', '嶹', '捣', '搗', '擣', '槝', '祷', '禂', '禱', '蹈', '陦', '隝', '隯', ], ruǐ: ['壡', '桵', '橤', '繠', '蕊', '蕋', '蘂', '蘃'], san: ['壭'], zhuàng: ['壮', '壯', '壵', '撞', '焋', '状', '狀'], 'ké qiào': ['壳', '殼'], kǔn: [ '壸', '壼', '悃', '捆', '梱', '硱', '祵', '稇', '稛', '綑', '裍', '閫', '閸', '阃', ], mǎng: ['壾', '漭', '茻', '莽', '莾', '蠎'], cún: ['壿', '存'], 'zhǐ zhōng': ['夂'], 'gǔ yíng': ['夃'], 'jiàng xiáng': ['夅', '降'], 'páng féng fēng': ['夆'], zhāi: ['夈', '捚', '摘', '斋', '斎', '榸', '粂', '齋'], 'xuàn xiòng': ['夐'], wài: ['外', '顡'], 'wǎn yuàn wān yuān': ['夗'], 'mǎo wǎn': ['夘'], mèng: ['夢', '夣', '孟', '梦', '癦', '霥'], 'dà dài': ['大'], 'fū fú': ['夫', '姇', '枎', '粰'], guài: ['夬', '怪', '恠'], yāng: [ '央', '姎', '抰', '殃', '泱', '秧', '胦', '鉠', '鍈', '雵', '鴦', '鸯', ], 'hāng bèn': ['夯'], gǎo: [ '夰', '搞', '杲', '槀', '槁', '檺', '稁', '稾', '稿', '縞', '缟', '菒', '藁', '藳', ], 'tāo běn': ['夲'], 'tóu tou': ['头'], 'yǎn tāo': ['夵'], 'kuā kuà': ['夸', '誇'], 'jiá jiā gā xiá': ['夹'], huà: [ '夻', '婳', '嫿', '嬅', '崋', '摦', '杹', '枠', '桦', '槬', '樺', '澅', '画', '畫', '畵', '繣', '舙', '話', '諙', '譮', '话', '黊', ], 'jiā jiá gā xiá': ['夾'], ēn: ['奀', '恩', '蒽'], 'dī tì': ['奃'], 'yǎn yān': ['奄', '渰'], pào: ['奅', '疱', '皰', '砲', '礟', '礮', '靤', '麭'], nài: ['奈', '柰', '渿', '耐', '萘', '褦', '錼', '鼐'], 'quān juàn': ['奍', '弮', '棬'], zòu: ['奏', '揍'], 'qì qiè xiè': ['契'], kāi: ['奒', '开', '揩', '鐦', '锎', '開'], 'bēn bèn': ['奔', '泍'], tào: ['套'], 'zàng zhuǎng': ['奘'], běn: ['奙', '本', '楍', '畚', '翉', '苯'], 'xùn zhuì': ['奞'], shē: ['奢', '檨', '猞', '畭', '畲', '賒', '賖', '赊', '輋', '𪨶'], 'hǎ pò tǎi': ['奤'], 'ào yù': ['奥', '奧', '澚'], yūn: ['奫', '氲', '氳', '蒀', '蒕', '蝹', '贇', '赟', '𫖳'], 'duǒ chě': ['奲'], 'nǚ rǔ': ['女'], nú: ['奴', '孥', '笯', '駑', '驽'], 'dīng dǐng tiǎn': ['奵'], 'tā jiě': ['她'], nuán: ['奻'], 'hǎo hào': ['好'], fàn: [ '奿', '嬎', '梵', '汎', '泛', '滼', '瀪', '犯', '畈', '盕', '笵', '範', '范', '訉', '販', '贩', '軬', '輽', '飯', '飰', '饭', ], shuò: ['妁', '搠', '朔', '槊', '烁', '爍', '矟', '蒴', '鎙', '鑠', '铄'], 'fēi pèi': ['妃'], wàng: ['妄', '忘', '旺', '望', '朢'], zhuāng: [ '妆', '妝', '娤', '庄', '庒', '桩', '梉', '樁', '粧', '糚', '荘', '莊', '装', '裝', ], mā: ['妈', '媽'], 'fū yōu': ['妋'], 'hài jiè': ['妎'], dù: [ '妒', '妬', '杜', '殬', '渡', '秺', '芏', '荰', '螙', '蠧', '蠹', '鍍', '镀', '靯', '𬭊', ], miào: ['妙', '庙', '庿', '廟', '玅', '竗'], 'fǒu pēi pī': ['妚'], 'yuè jué': ['妜'], niū: ['妞'], 'nà nàn': ['妠'], tuǒ: ['妥', '嫷', '庹', '椭', '楕', '橢', '鬌', '鰖', '鵎'], 'wàn yuán': ['妧'], fáng: ['妨', '房', '肪', '防', '魴', '鲂'], nī: ['妮'], zhóu: ['妯', '碡'], zhāo: ['妱', '巶', '招', '昭', '釗', '鉊', '鍣', '钊', '駋', '𬬿'], 'nǎi nǐ': ['妳'], tǒu: ['妵', '敨', '紏', '蘣', '黈'], 'xián xuán xù': ['妶'], 'zhí yì': ['妷', '秇'], ē: ['妸', '妿', '婀', '屙'], mèi: [ '妹', '媚', '寐', '抺', '旀', '昧', '沬', '煝', '痗', '眛', '睸', '祙', '篃', '蝞', '袂', '跊', '鬽', '魅', ], 'qī qì': ['妻'], 'xū xǔ': ['姁', '稰'], 'shān shàn': ['姍', '姗', '苫', '釤', '钐'], mán: ['姏', '慲', '樠', '蛮', '蠻', '謾', '饅', '馒', '鬗', '鬘', '鰻', '鳗'], jiě: ['姐', '媎', '檞', '毑', '飷'], 'wěi wēi': ['委'], pīn: ['姘', '拼', '礗', '穦', '馪', '驞'], 'huá huó': ['姡'], 'jiāo xiáo': ['姣'], 'gòu dù': ['姤'], 'lǎo mǔ': ['姥'], 'nián niàn': ['姩'], zhěn: [ '姫', '屒', '弫', '抮', '昣', '枕', '畛', '疹', '眕', '稹', '縝', '縥', '缜', '聄', '萙', '袗', '裖', '覙', '診', '诊', '軫', '轸', '辴', '駗', '鬒', ], héng: [ '姮', '恆', '恒', '烆', '珩', '胻', '蘅', '衡', '鑅', '鴴', '鵆', '鸻', ], 'jūn xún': ['姰'], 'kuā hù': ['姱'], 'è yà': ['姶'], 'xiān shēn': ['姺'], wá: ['娃'], 'ráo rǎo': ['娆', '嬈'], 'shào shāo': ['娋'], xiē: ['娎', '揳', '楔', '歇', '蝎', '蠍'], 'wǔ méi mǔ': ['娒'], 'chuò lài': ['娕'], niáng: ['娘', '嬢', '孃'], 'nà nuó': ['娜', '𦰡'], 'pōu bǐ': ['娝'], 'něi suī': ['娞'], tuì: ['娧', '煺', '蛻', '蜕', '退', '駾'], mǎn: ['娨', '屘', '満', '满', '滿', '螨', '蟎', '襔', '鏋'], 'wú wù yú': ['娪'], 'xī āi': ['娭'], 'zhuì shuì': ['娷'], 'dōng dòng': ['娻'], 'ǎi ái è': ['娾'], 'ē ě': ['娿'], mián: [ '婂', '嬵', '宀', '杣', '棉', '檰', '櫋', '眠', '矈', '矊', '矏', '綿', '緜', '绵', '芇', '蝒', ], 'pǒu péi bù': ['婄'], biǎo: ['婊', '脿', '表', '裱', '褾', '諘', '錶'], 'fù fàn': ['婏'], wǒ: ['婐', '婑', '我'], 'ní nǐ': ['婗', '棿'], 'quán juàn': ['婘', '惓'], hūn: [ '婚', '昏', '昬', '棔', '涽', '睧', '睯', '碈', '荤', '葷', '蔒', '轋', '閽', '阍', ], 'qiān jǐn': ['婜'], 'wān wà': ['婠'], 'lái lài': ['婡', '徕', '徠'], 'zhōu chōu': ['婤'], 'chuò nào': ['婥'], 'nüè àn': ['婩'], 'hùn kūn': ['婫'], 'dàng yáng': ['婸'], nàn: ['婻'], 'ruò chuò': ['婼'], jiǎ: ['婽', '岬', '斚', '斝', '榎', '槚', '檟', '玾', '甲', '胛', '鉀', '钾'], 'tōu yú': ['婾', '媮'], 'yù yú': ['媀'], 'wéi wěi': ['媁'], 'dì tí': ['媂', '珶', '苐'], róu: [ '媃', '揉', '柔', '渘', '煣', '瑈', '瓇', '禸', '粈', '糅', '脜', '腬', '葇', '蝚', '蹂', '輮', '鍒', '鞣', '騥', '鰇', '鶔', '𫐓', ], 'ruǎn nèn': ['媆'], miáo: ['媌', '嫹', '描', '瞄', '苗', '鶓', '鹋'], 'yí pèi': ['媐'], 'mián miǎn': ['媔'], 'tí shì': ['媞', '惿'], 'duò tuó': ['媠', '沲'], ǎo: ['媪', '媼', '艹', '芺', '袄', '襖', '镺'], 'chú zòu': ['媰'], yìng: ['媵', '映', '暎', '硬', '膡', '鱦'], 'qín shēn': ['嫀'], jià: ['嫁', '幏', '架', '榢', '稼', '駕', '驾'], sǎo: ['嫂'], 'zhēn zhěn': ['嫃'], 'jiē suǒ': ['嫅'], 'míng mǐng': ['嫇'], niǎo: ['嫋', '嬝', '嬲', '茑', '蔦', '袅', '裊', '褭', '鸟'], tāo: [ '嫍', '幍', '弢', '慆', '掏', '搯', '槄', '涛', '滔', '濤', '瑫', '絛', '縚', '縧', '绦', '詜', '謟', '轁', '鞱', '韜', '韬', '飸', '饕', ], biáo: ['嫑'], 'piáo piāo': ['嫖', '薸'], xuán: [ '嫙', '悬', '懸', '暶', '檈', '漩', '玄', '璇', '璿', '痃', '蜁', '𫠊', ], 'màn mān': ['嫚'], kāng: [ '嫝', '嵻', '康', '慷', '槺', '漮', '砊', '穅', '糠', '躿', '鏮', '鱇', '𡐓', '𩾌', ], 'hān nǎn': ['嫨'], nèn: ['嫩', '嫰'], zhē: ['嫬', '遮'], 'mā má': ['嫲'], piè: ['嫳'], zhǎn: [ '嫸', '展', '搌', '斩', '斬', '琖', '盏', '盞', '輾', '醆', '颭', '飐', ], 'xiān yǎn jìn': ['嬐'], liǎn: [ '嬚', '敛', '斂', '琏', '璉', '羷', '脸', '臉', '蔹', '蘝', '蘞', '裣', '襝', '鄻', ], 'qióng huán xuān': ['嬛'], dǒng: ['嬞', '懂', '箽', '董', '蕫', '諌'], cān: ['嬠', '湌', '爘', '飡', '餐', '驂', '骖'], tiǎo: ['嬥', '宨', '晀', '朓', '窱', '脁'], bí: ['嬶', '荸', '鼻'], liǔ: [ '嬼', '柳', '栁', '桞', '桺', '橮', '熮', '珋', '綹', '绺', '罶', '羀', '鋶', '锍', ], 'qiān xiān': ['孅', '欦'], 'xié huī': ['孈'], 'huān quán': ['孉'], 'lí lì': ['孋', '麗'], 'zhú chuò': ['孎'], kǒng: ['孔', '恐'], 'mā zī': ['孖'], 'sūn xùn': ['孙', '孫'], 'bèi bó': ['孛', '誖'], 'yòu niū': ['孧'], zhuǎn: ['孨', '竱', '轉'], hái: ['孩', '骸'], nāo: ['孬'], 'chán càn': ['孱'], bò: ['孹', '檗', '蘗', '譒'], nái: ['孻', '腉'], 'níng nìng': ['宁', '寍', '寗', '寜', '寧', '甯'], zhái: ['宅'], 'tū jiā': ['宊'], sòng: ['宋', '訟', '誦', '讼', '诵', '送', '鎹', '頌', '颂', '餸'], ròu: ['宍', '肉', '譳'], zhūn: ['宒', '窀', '衠', '諄', '谆', '迍'], 'mì fú': ['宓'], 'dàng tàn': ['宕'], 'wǎn yuān': ['宛'], chǒng: ['宠', '寵'], qún: ['宭', '峮', '帬', '羣', '群', '裙', '裠'], zǎi: ['宰', '崽'], 'bǎo shí': ['宲'], 'jiā jia jie': ['家'], 'huāng huǎng': ['宺'], kuān: ['宽', '寛', '寬', '臗', '鑧', '髋', '髖'], 'sù xiǔ xiù': ['宿'], 'jié zǎn': ['寁'], 'bìng bǐng': ['寎'], 'jìn qǐn': ['寖'], 'lóu jù': ['寠'], 'xiě xiè': ['寫'], 'qīn qìn': ['寴'], cùn: ['寸', '籿'], duì: [ '对', '対', '對', '怼', '憝', '懟', '濧', '瀩', '碓', '祋', '綐', '薱', '譈', '譵', '轛', '队', '陮', ], 'lüè luó': ['寽'], 'shè yè yì': ['射'], 'jiāng jiàng qiāng': ['将'], 'jiāng jiàng': ['將', '浆', '漿', '畺'], zūn: ['尊', '嶟', '樽', '罇', '遵', '鐏', '鱒', '鳟', '鶎', '鷷', '𨱔'], 'shù zhù': ['尌', '澍'], xiǎo: ['小', '晓', '暁', '曉', '皛', '皢', '筱', '筿', '篠', '謏', '𫍲'], 'jié jí': ['尐', '诘', '鞊'], 'shǎo shào': ['少'], ěr: [ '尒', '尓', '尔', '栮', '毦', '洱', '爾', '珥', '耳', '薾', '衈', '趰', '迩', '邇', '鉺', '铒', '餌', '饵', '駬', ], 'wāng yóu': ['尢'], wāng: ['尣', '尩', '尪', '尫', '汪'], liào: ['尥', '尦', '廖', '撂', '料', '炓', '窷', '鐐', '镣', '𪤗'], 'méng máng lóng páng': ['尨'], gà: ['尬', '魀'], 'kuì kuǐ': ['尯'], tuí: ['尵', '弚', '穨', '蘈', '蹪', '隤', '頹', '頺', '頽', '颓', '魋', '𬯎'], yǐn: [ '尹', '嶾', '引', '朄', '檃', '檼', '櫽', '淾', '濥', '瘾', '癮', '粌', '蘟', '蚓', '螾', '讔', '赺', '趛', '輑', '鈏', '靷', ], 'chǐ chě': ['尺'], kāo: ['尻', '髛'], 'jìn jǐn': ['尽'], 'wěi yǐ': ['尾'], 'niào suī': ['尿'], céng: ['层', '層', '嶒', '驓'], diǎo: ['屌'], 'píng bǐng bīng': ['屏'], lòu: ['屚', '漏', '瘘', '瘺', '瘻', '鏤', '镂', '陋'], 'shǔ zhǔ': ['属', '屬'], 'xiè tì': ['屟'], 'chè cǎo': ['屮'], 'tún zhūn': ['屯'], 'nì jǐ': ['屰'], 'hóng lóng': ['屸'], 'qǐ kǎi': ['岂', '豈'], áng: ['岇', '昂', '昻'], 'gǎng gāng': ['岗', '崗'], kě: ['岢', '敤', '渇', '渴', '炣'], gǒu: ['岣', '狗', '玽', '笱', '耇', '耈', '耉', '苟', '豿'], tiáo: [ '岧', '岹', '樤', '祒', '笤', '芀', '萔', '蓚', '蓨', '蜩', '迢', '鋚', '鎥', '鞗', '髫', '鯈', '鰷', '鲦', '齠', '龆', ], 'qū jū': ['岨'], lǐng: ['岭', '嶺', '領', '领'], pò: ['岶', '敀', '洦', '湐', '烞', '珀', '破', '砶', '粕', '蒪', '魄'], 'bā kè': ['峇'], luò: [ '峈', '摞', '洛', '洜', '犖', '珞', '笿', '纙', '荦', '詻', '雒', '駱', '骆', '鵅', ], 'fù niè': ['峊'], ěn: ['峎'], 'zhì shì': ['峙', '崻'], qiǎ: ['峠', '跒', '酠', '鞐'], 'qiáo jiào': ['峤', '癄'], 'xié yé': ['峫'], bū: ['峬', '庯', '晡', '誧', '逋', '鈽', '錻', '钸', '餔', '鵏'], chóng: ['崇', '崈', '爞', '虫', '蝩', '蟲', '褈', '隀'], 'zú cuì': ['崒', '椊'], 'líng léng': ['崚'], 'dòng dōng': ['崠'], xiáo: ['崤', '洨', '淆', '訤', '誵'], 'pí bǐ': ['崥', '芘'], 'zhǎn chán': ['崭', '嶃', '嶄'], 'wǎi wēi': ['崴'], 'yáng dàng': ['崵'], 'shì dié': ['崼'], yào: [ '崾', '曜', '熎', '燿', '矅', '穾', '窔', '筄', '耀', '艞', '药', '葯', '薬', '藥', '袎', '覞', '詏', '讑', '靿', '鷂', '鹞', '鼼', ], 'kān zhàn': ['嵁'], 'hán dǎng': ['嵅'], 'qiàn kàn': ['嵌'], 'wù máo': ['嵍'], 'kě jié': ['嵑', '嶱'], 'wēi wěi': ['嵔'], kē: [ '嵙', '柯', '棵', '榼', '樖', '牁', '牱', '犐', '珂', '疴', '瞌', '磕', '礚', '科', '稞', '窠', '萪', '薖', '蚵', '蝌', '趷', '轲', '醘', '鈳', '钶', '頦', '顆', '颗', '髁', ], 'dàng táng': ['嵣'], 'róng yíng': ['嵤', '爃'], 'ái kǎi': ['嵦'], 'kāo qiāo': ['嵪'], cuó: ['嵯', '嵳', '痤', '矬', '蒫', '蔖', '虘', '鹺', '鹾'], 'qiǎn qīn': ['嵰'], 'dì dié': ['嵽'], cēn: ['嵾'], dǐng: ['嵿', '艼', '薡', '鐤', '頂', '顶', '鼎', '鼑'], 'áo ào': ['嶅'], 'pǐ pèi': ['嶏'], 'jiào qiáo': ['嶠', '潐'], 'jué guì': ['嶡', '鳜'], 'zhān shàn': ['嶦', '鳣'], 'xiè jiè': ['嶰'], 'guī xī juàn': ['嶲'], rū: ['嶿'], 'lì liè': ['巁', '棙', '爄', '綟'], 'xī guī juàn': ['巂'], 'yíng hōng': ['巆'], yǐng: [ '巊', '廮', '影', '摬', '梬', '潁', '瘿', '癭', '矨', '穎', '郢', '鐛', '頴', '颍', '颕', '颖', ], chǎo: ['巐', '炒', '煼', '眧', '麨'], cuán: ['巑', '櫕', '欑'], chuān: ['巛', '川', '氚', '瑏', '穿'], 'jīng xíng': ['巠'], cháo: [ '巢', '巣', '晁', '漅', '潮', '牊', '窲', '罺', '謿', '轈', '鄛', '鼌', ], qiǎo: ['巧', '愀', '髜'], gǒng: ['巩', '廾', '拱', '拲', '栱', '汞', '珙', '輁', '鞏'], 'chà chā chāi cī': ['差'], 'xiàng hàng': ['巷'], shuài: ['帅', '帥', '蟀'], pà: ['帊', '帕', '怕', '袙'], 'tǎng nú': ['帑'], 'mò wà': ['帓'], 'tiē tiě tiè': ['帖'], zhǒu: ['帚', '晭', '疛', '睭', '箒', '肘', '菷', '鯞'], 'juǎn juàn': ['帣'], shuì: ['帨', '涗', '涚', '睡', '稅', '税', '裞'], 'chóu dào': ['帱', '幬'], 'jiǎn jiān sàn': ['帴'], 'shà qiè': ['帹'], 'qí jì': ['帺', '荠'], 'shān qiāo shēn': ['幓'], 'zhuàng chuáng': ['幢'], 'chān chàn': ['幨'], miè: [ '幭', '懱', '搣', '滅', '灭', '烕', '礣', '篾', '蔑', '薎', '蠛', '衊', '鑖', '鱴', '鴓', ], 'gān gàn': ['干'], 'bìng bīng': ['并', '幷'], 'jī jǐ': ['幾'], 'guǎng ān': ['广'], guǎng: ['広', '廣', '犷', '獷'], me: ['庅'], 'dùn tún': ['庉'], 'bài tīng': ['庍'], 'yìng yīng': ['应'], 'dǐ de': ['底'], 'dù duó': ['度'], 'máng méng páng': ['庬'], 'bìng píng': ['庰'], chěng: ['庱', '悜', '睈', '逞', '騁', '骋'], 'jī cuò': ['庴'], qǐng: ['庼', '廎', '檾', '漀', '苘', '請', '謦', '请', '頃', '顷'], 'guī wěi huì': ['廆'], 'jǐn qín': ['廑'], kuò: [ '廓', '扩', '拡', '擴', '濶', '筈', '萿', '葀', '蛞', '闊', '阔', '霩', '鞟', '鞹', '韕', '頢', '鬠', ], 'qiáng sè': ['廧', '薔'], 'yǐn yìn': ['廴', '隐', '隠', '隱', '飮', '飲', '饮'], 'pò pǎi': ['廹', '迫'], 'nòng lòng': ['弄'], 'dì tì tuí': ['弟'], 'jué zhāng': ['弡'], 'mí mǐ': ['弥', '彌', '靡'], chāo: ['弨', '怊', '抄', '欩', '訬', '超', '鈔', '钞'], yi: ['弬'], shāo: [ '弰', '旓', '烧', '焼', '燒', '筲', '艄', '萷', '蕱', '輎', '髾', '鮹', ], 'xuān yuān': ['弲'], 'qiáng qiǎng jiàng': ['強', '强'], 'tán dàn': ['弹', '醈'], biè: ['彆'], 'qiáng jiàng qiǎng': ['彊'], 'jì xuě': ['彐'], tuàn: ['彖', '褖'], yuē: ['彟', '曰', '曱', '矱'], 'shān xiǎn': ['彡'], wén: [ '彣', '文', '炆', '珳', '瘒', '繧', '聞', '芠', '蚉', '蚊', '螡', '蟁', '閺', '閿', '闅', '闦', '闻', '阌', '雯', '馼', '駇', '魰', '鳼', '鴍', '鼤', '𫘜', ], 'péng bāng': ['彭'], 'piāo piào': ['彯'], 'zhuó bó': ['彴'], 'tuǒ yí': ['彵'], 'páng fǎng': ['彷'], wǎng: [ '彺', '往', '徃', '惘', '枉', '棢', '網', '网', '罒', '罓', '罔', '罖', '菵', '蛧', '蝄', '誷', '輞', '辋', '魍', ], cú: ['徂', '殂'], 'dài dāi': ['待'], huái: ['徊', '怀', '懐', '懷', '槐', '淮', '耲', '蘹', '褢', '褱', '踝'], 'wā wàng jiā': ['徍'], 'chěng zhèng': ['徎'], 'dé děi de': ['得'], 'cóng zòng': ['從'], 'shì tǐ': ['徥'], 'tí chí': ['徲', '鶗', '鶙'], dé: ['徳', '德', '恴', '悳', '惪', '淂', '鍀', '锝'], 'zhǐ zhēng': ['徴', '徵'], bié: ['徶', '癿', '莂', '蛂', '襒', '蹩'], 'chōng zhǒng': ['徸'], 'jiǎo jiào': ['徼', '笅', '筊'], 'lòng lǒng': ['徿'], 'qú jù': ['忂', '渠', '瞿', '螶'], 'dìng tìng': ['忊'], gǎi: ['忋', '改'], rěn: ['忍', '栠', '栣', '秹', '稔', '綛', '荏', '荵', '躵'], chàn: ['忏', '懴', '懺', '硟', '羼', '韂', '顫'], tè: ['忑', '慝', '特', '蟘', '鋱', '铽'], 'tè tēi tuī': ['忒'], 'gān hàn': ['忓', '攼'], 'yì qì': ['忔'], 'tài shì': ['忕'], 'xī liě': ['忚'], 'yīng yìng': ['応', '應', '譍'], 'mǐn wěn mín': ['忞', '忟'], 'sōng zhōng': ['忪'], 'yù shū': ['忬', '悆'], 'qí shì': ['忯', '耆'], 'tún zhūn dùn': ['忳'], 'qián qín': ['忴', '扲'], hún: ['忶', '浑', '渾', '餛', '馄', '魂', '鼲'], niǔ: ['忸', '扭', '炄', '狃', '紐', '纽', '莥', '鈕', '钮', '靵'], 'kuáng wǎng': ['忹'], 'kāng hàng': ['忼'], 'kài xì': ['忾', '愾'], òu: ['怄', '慪'], 'bǎo bào': ['怉'], 'mín mén': ['怋'], 'zuò zhà': ['怍'], zěn: ['怎'], yàng: ['怏', '恙', '样', '様', '樣', '漾', '羕', '詇'], 'kòu jù': ['怐'], 'náo niú': ['怓'], 'zhēng zhèng': ['怔', '掙', '钲', '铮'], 'tiē zhān': ['怗'], 'hù gù': ['怘'], 'cū jù zū': ['怚'], 'sī sāi': ['思'], 'yóu chóu': ['怞'], 'tū dié': ['怢'], 'yōu yào': ['怮'], xuàn: [ '怰', '昡', '楦', '泫', '渲', '炫', '琄', '眩', '碹', '絢', '縼', '繏', '绚', '蔙', '衒', '袨', '贙', '鉉', '鏇', '铉', '镟', '颴', ], 'xù xuè': ['怴'], 'bì pī': ['怶'], 'xī shù': ['怸'], 'nèn nín': ['恁'], 'tiāo yáo': ['恌'], 'xī qī xù': ['恓'], 'xiào jiǎo': ['恔'], 'hū kuā': ['恗'], nǜ: ['恧', '朒', '衂', '衄'], hèn: ['恨'], 'dòng tōng': ['恫'], 'quán zhuān': ['恮'], 'è wù ě wū': ['恶', '惡'], tòng: ['恸', '慟', '憅', '痛', '衕'], 'yuān juàn': ['悁'], 'qiāo qiǎo': ['悄'], 'jiè kè': ['悈'], 'hào jiào': ['悎'], huǐ: ['悔', '檓', '毀', '毁', '毇', '燬', '譭'], 'mán mèn': ['悗', '鞔'], 'yī yì': ['悘', '衣'], quān: ['悛', '箞', '鐉', '𨟠'], 'kuī lǐ': ['悝'], 'yì niàn': ['悥'], 'mèn mēn': ['悶'], guàn: [ '悹', '悺', '惯', '慣', '掼', '摜', '樌', '欟', '泴', '涫', '潅', '灌', '爟', '瓘', '盥', '礶', '祼', '罆', '罐', '貫', '贯', '躀', '遦', '鏆', '鑵', '鱹', '鸛', '鹳', ], 'kōng kǒng': ['悾'], 'lǔn lùn': ['惀'], guǒ: [ '惈', '果', '椁', '槨', '粿', '綶', '菓', '蜾', '裹', '褁', '輠', '餜', '馃', ], 'yuān wǎn': ['惌', '箢'], 'lán lín': ['惏'], 'yù xù': ['惐', '淢'], 'chuò chuì': ['惙'], 'hūn mèn': ['惛'], 'chǎng tǎng': ['惝'], 'suǒ ruǐ': ['惢'], cǎn: ['惨', '慘', '憯', '黪', '黲', '䅟'], cán: ['惭', '慙', '慚', '残', '殘', '蚕', '蝅', '蠶', '蠺'], 'dàn dá': ['惮', '憚'], rě: ['惹'], 'yú tōu': ['愉'], 'kài qì': ['愒'], 'dàng táng shāng yáng': ['愓'], 'chén xìn dān': ['愖'], 'kè qià': ['愘'], nuò: [ '愞', '懦', '懧', '掿', '搦', '榒', '稬', '穤', '糑', '糥', '糯', '諾', '诺', '蹃', '逽', '鍩', '锘', ], gǎn: [ '感', '擀', '敢', '桿', '橄', '澉', '澸', '皯', '秆', '稈', '笴', '芉', '衦', '赶', '趕', '鱤', '鳡', ], 'còng sōng': ['愡'], 'sāi sī sǐ': ['愢'], 'gōng gòng hǒng': ['愩', '慐'], 'shuò sù': ['愬', '洬'], 'yáo yào': ['愮'], huàng: ['愰', '曂', '榥', '滉', '皝', '皩', '鎤', '㿠'], zhěng: ['愸', '抍', '拯', '整', '晸'], cǎo: ['愺', '艸', '草', '騲'], 'xì xié': ['慀'], 'cǎo sāo': ['慅'], 'xù chù': ['慉'], 'qiè qiàn': ['慊'], 'cáo cóng': ['慒'], 'ào áo': ['慠'], 'lián liǎn': ['慩', '梿', '槤', '櫣'], 'jìn qín jǐn': ['慬'], 'dì chì': ['慸'], 'zhí zhé': ['慹'], 'lóu lǚ': ['慺', '鷜'], còng: ['憁', '謥'], 'zhī zhì': ['憄', '知', '織', '织'], chēng: [ '憆', '摚', '撐', '撑', '晿', '柽', '棦', '橕', '檉', '泟', '浾', '琤', '瞠', '碀', '緽', '罉', '蛏', '蟶', '赪', '赬', '鏿', '鐣', '阷', '靗', '頳', '饓', ], biē: ['憋', '虌', '鱉', '鳖', '鼈', '龞'], 'chéng dèng zhèng': ['憕'], 'xǐ xī': ['憘'], 'duì dùn tūn': ['憞'], 'xiāo jiāo': ['憢'], 'xián xiàn': ['憪'], 'liáo liǎo': ['憭', '燎', '爎', '爒'], shéng: ['憴', '縄', '繉', '繩', '绳', '譝'], 'náo nǎo náng': ['憹'], 'jǐng jìng': ['憼'], 'jǐ jiǎo': ['憿'], 'xuān huān': ['懁'], 'cǎo sāo sào': ['懆'], mèn: ['懑', '懣', '暪', '焖', '燜'], 'mèng méng měng': ['懜'], 'ài yì nǐ': ['懝'], 'méng měng': ['懞', '瞢', '矒'], 'qí jī jì': ['懠'], mǒ: ['懡'], 'lán xiàn': ['懢'], 'yōu yǒu': ['懮'], 'liú liǔ': ['懰', '藰'], ràng: ['懹', '譲', '讓', '让'], huān: ['懽', '欢', '歓', '歡', '獾', '讙', '貛', '酄', '驩', '鴅', '鵍'], nǎn: ['戁', '揇', '湳', '煵', '腩', '蝻', '赧'], 'mí mó': ['戂'], 'gàng zhuàng': ['戅', '戆'], 'zhuàng gàng': ['戇'], 'xū qu': ['戌'], 'xì hū': ['戏', '戯', '戲'], 'jiá gā': ['戛'], zéi: ['戝', '蠈', '賊', '贼', '鰂', '鱡', '鲗'], děng: ['戥', '等'], 'hū xì': ['戱'], chuō: ['戳', '踔', '逴'], 'biǎn piān': ['扁'], 'shǎng jiōng': ['扄'], 'shàn shān': ['扇'], cái: ['才', '材', '纔', '裁', '財', '财'], 'zhā zā zhá': ['扎'], 'lè lì cái': ['扐'], 'bā pá': ['扒'], 'dǎ dá': ['打'], rēng: ['扔'], 'fǎn fú': ['払'], 'diǎo dí yuē lì': ['扚'], 'káng gāng': ['扛'], 'yū wū': ['扜'], 'yū wū kū': ['扝'], 'tuō chǐ yǐ': ['扡'], 'gǔ jié xì gē': ['扢'], dèn: ['扥', '扽'], 'sǎo sào': ['扫', '掃'], rǎo: ['扰', '擾', '隢'], 'xī chā qì': ['扱'], 'bān pān': ['扳'], 'bā ào': ['扷'], 'xī zhé': ['扸'], 'zhì sǔn kǎn': ['扻'], zhǎo: ['找', '沼', '瑵'], 'kuáng wǎng zài': ['抂'], 'hú gǔ': ['抇', '鹄', '鹘'], 'bǎ bà': ['把'], 'dǎn shěn': ['抌'], 'nè nì ruì nà': ['抐'], zhuā: ['抓', '檛', '簻', '膼', '髽'], póu: ['抔', '裒'], 'zhé shé zhē': ['折'], 'póu pōu fū': ['抙', '捊'], pāo: ['抛', '拋', '脬', '萢'], 'ǎo ào niù': ['抝'], 'lūn lún': ['抡', '掄'], 'qiǎng qiāng chēng': ['抢'], 'zhǐ zhǎi': ['抧'], 'bù pū': ['抪', '柨'], 'yǎo tāo': ['抭'], 'hē hè qiā': ['抲'], 'nǐ ní': ['抳'], 'pī pēi': ['抷'], 'mǒ mò mā': ['抹'], chōu: ['抽', '犨', '犫', '瘳', '篘'], 'jiā yá': ['拁'], 'fú bì': ['拂', '畐', '鶝'], zhǎ: ['拃', '眨', '砟', '鮺', '鲝'], 'dān dàn dǎn': ['担'], 'chāi cā': ['拆'], niān: ['拈', '蔫'], 'lā lá lǎ là': ['拉'], 'bàn pàn': ['拌'], pāi: ['拍'], līn: ['拎'], guǎi: ['拐', '枴', '柺'], 'tuò tà zhí': ['拓'], 'ào ǎo niù': ['拗'], 'jū gōu': ['拘'], 'pīn pàn fān': ['拚'], 'bài bái': ['拜'], bài: ['拝', '敗', '稗', '粺', '薭', '贁', '败', '韛'], qiá: ['拤'], 'nǐng níng nìng': ['拧'], 'zé zhái': ['择', '擇'], hén: ['拫', '痕', '鞎'], 'kuò guā': ['括'], 'jié jiá': ['拮'], nǐn: ['拰'], shuān: ['拴', '栓', '閂', '闩'], 'cún zùn': ['拵'], 'zā zǎn': ['拶', '桚'], kǎo: ['拷', '攷', '栲', '烤', '考'], 'yí chǐ hài': ['拸'], 'cè sè chuò': ['拺'], 'zhuài zhuāi yè': ['拽'], 'shí shè': ['拾'], bāi: ['挀', '掰'], 'kuò guāng': ['挄'], nòng: ['挊', '挵', '齈'], 'jiào jiāo': ['挍', '敎', '教'], 'kuà kū': ['挎'], 'ná rú': ['挐'], 'tiāo tiǎo': ['挑'], 'dié shè': ['挕'], liě: ['挘', '毟'], 'yà yǎ': ['挜', '掗'], 'wō zhuā': ['挝'], 'xié jiā': ['挟', '挾'], 'dǎng dàng': ['挡', '擋'], 'zhèng zhēng': ['挣', '正', '症'], 'āi ái': ['挨'], 'tuō shuì': ['挩', '捝'], 'tǐ tì': ['挮'], 'suō shā': ['挱'], 'sā shā suō': ['挲'], 'kēng qiān': ['挳', '摼'], 'bàng péng': ['挷'], 'ruó ruá': ['挼'], 'jiǎo kù': ['捁'], 'wǔ wú': ['捂'], tǒng: ['捅', '桶', '筒', '筩', '統', '綂', '统', '㛚'], 'huò chì': ['捇'], 'tú shū chá': ['捈'], 'lǚ luō': ['捋'], 'shāo shào': ['捎', '稍'], niē: ['捏', '揑'], 'shù sǒng sōu': ['捒'], 'yé yú': ['捓'], 'jué zhuó': ['捔'], 'bù pú zhì': ['捗'], zùn: ['捘', '銌'], lāo: ['捞', '撈', '粩'], sǔn: ['损', '損', '榫', '笋', '筍', '箰', '鎨', '隼'], 'wàn wǎn wān yù': ['捥'], pěng: ['捧', '淎', '皏'], shě: ['捨'], 'fǔ fù bǔ': ['捬'], dáo: ['捯'], 'luò luǒ wǒ': ['捰'], 'juǎn quán': ['捲'], 'chēn tiǎn': ['捵'], 'niǎn niē': ['捻'], 'ruó wěi ré': ['捼'], zuó: ['捽', '昨', '秨', '稓', '筰', '莋', '鈼'], 'wò xiá': ['捾'], 'qìng qiàn': ['掅'], 'póu pǒu': ['掊'], qiā: ['掐', '葜'], 'pái pǎi': ['排'], 'qiān wàn': ['掔'], 'yè yē': ['掖'], 'niè nǐ yì': ['掜'], 'huò xù': ['掝'], 'yàn shàn yǎn': ['掞'], 'zhěng dìng': ['掟'], kòng: ['控', '鞚'], tuī: ['推', '蓷', '藬'], 'zōu zhōu chōu': ['掫'], tiàn: ['掭', '舚'], kèn: ['掯', '裉', '褃'], pá: ['掱', '杷', '潖', '爬', '琶', '筢'], 'guó guāi': ['掴'], 'dǎn shàn': ['掸', '撣'], 'chān xiān càn shǎn': ['掺'], sāo: ['掻', '搔', '溞', '繅', '缫', '螦', '騒', '騷', '鰠', '鱢', '鳋'], pèng: ['掽', '椪', '槰', '碰', '踫'], 'zhēng kēng': ['揁'], 'jiū yóu': ['揂'], 'jiān jiǎn': ['揃', '籛'], 'pì chè': ['揊'], 'sāi zǒng cāi': ['揌'], 'tí dī dǐ': ['提'], 'zǒng sōng': ['揔'], 'huáng yóng': ['揘'], 'zǎn zuàn': ['揝'], 'xū jū': ['揟'], 'ké qiā': ['揢'], 'chuāi chuǎi chuài tuán zhuī': ['揣'], 'dì tì': ['揥'], 'lá là': ['揦'], là: [ '揧', '楋', '溂', '瓎', '瘌', '翋', '臘', '蝋', '蝲', '蠟', '辢', '辣', '鑞', '镴', '鬎', '鯻', '𬶟', ], 'jiē qì': ['揭'], 'chòng dǒng': ['揰'], 'dié shé yè': ['揲'], 'jiàn qián jiǎn': ['揵'], yé: ['揶', '爷', '爺', '瑘', '鋣', '鎁', '铘'], chān: ['搀', '摻', '攙', '裧', '襜', '覘', '觇', '辿', '鋓'], 'gē gé': ['搁', '擱'], 'lǒu lōu': ['搂', '摟'], 'chōu zǒu': ['搊'], chuāi: ['搋'], sūn: ['搎', '槂', '狲', '猻', '荪', '蓀', '蕵', '薞', '飧', '飱'], 'róng náng nǎng': ['搑'], 'péng bàng': ['搒'], cuō: ['搓', '瑳', '磋', '蹉', '遳', '醝'], 'kē è': ['搕'], 'nù nuò nòu': ['搙'], 'lā xié xiàn': ['搚'], qiǔ: ['搝', '糗'], 'xiǎn xiān': ['搟'], 'jié zhé': ['搩'], 'pán bān pó': ['搫'], bān: [ '搬', '攽', '斑', '斒', '班', '瘢', '癍', '肦', '螁', '螌', '褩', '辬', '頒', '颁', '𨭉', ], 'zhì nái': ['搱'], 'wā wǎ wà': ['搲'], huá: ['搳', '撶', '滑', '猾', '蕐', '螖', '譁', '鏵', '铧', '驊', '骅', '鷨'], 'qiāng qiǎng chēng': ['搶'], 'tián shēn': ['搷'], 'ná nuò': ['搻'], èn: ['摁'], 'shè niè': ['摄', '攝'], bìn: ['摈', '擯', '殡', '殯', '膑', '臏', '髌', '髕', '髩', '鬂', '鬓', '鬢'], 'shā sà shǎi': ['摋'], 'chǎn sùn': ['摌'], 'jiū liú liáo jiǎo náo': ['摎'], 'féng pěng': ['摓'], shuāi: ['摔'], 'dì tú zhí': ['摕'], 'qì jì chá': ['摖'], 'sōu sǒng': ['摗'], 'liǎn liàn': ['摙'], 'gài xì': ['摡'], 'hù chū': ['摢'], tàng: ['摥', '烫', '燙', '鐋'], 'nái zhì': ['摨'], 'mó mā': ['摩'], 'jiāng qiàng': ['摪'], 'áo qiáo': ['摮'], 'niè chè': ['摰'], 'mán màn': ['摱'], 'chàn cán': ['摲'], 'sè mí sù': ['摵'], 'biāo biào': ['摽'], 'juē jué': ['撅'], piē: ['撆', '暼', '氕', '瞥'], 'piě piē': ['撇'], 'zǎn zān zēn qián': ['撍'], 'sā sǎ': ['撒'], hòng: ['撔', '訌', '讧', '闀', '鬨'], 'héng guàng': ['撗'], niǎn: [ '撚', '撵', '攆', '涊', '焾', '碾', '簐', '蹍', '蹨', '躎', '輦', '辇', ], 'chéng zhěng': ['撜'], 'huī wéi': ['撝'], cāo: ['撡', '操', '糙'], 'xiāo sōu': ['撨'], 'liáo liāo': ['撩'], 'cuō zuǒ': ['撮'], 'wěi tuǒ': ['撱'], cuān: ['撺', '攛', '汆', '蹿', '躥', '鑹', '镩'], 'qiào yāo jī': ['撽'], 'zhuā wō': ['撾'], 'lèi léi': ['擂'], nǎng: ['擃', '攮', '曩', '灢'], 'qíng jǐng': ['擏'], kuǎi: ['擓', '蒯', '㧟'], 'pǐ bò': ['擗'], 'bò bāi': ['擘'], 'jù jǐ': ['據'], mēng: ['擝'], 'sǒu sòu': ['擞'], xǐng: ['擤', '箵', '醒'], cā: ['擦'], 'níng nǐng nìng': ['擰'], 'zhì jié': ['擳'], 'là liè': ['擸', '爉'], 'sòu sǒu': ['擻'], 'lì luò yuè': ['擽'], 'tī zhāi zhì': ['擿'], pān: ['攀', '潘', '眅', '萠'], lèi: [ '攂', '泪', '涙', '淚', '禷', '类', '纇', '蘱', '酹', '銇', '錑', '頛', '頪', '類', '颣', ], 'cā sǎ': ['攃'], 'jùn pèi': ['攈'], 'lì luò': ['攊', '躒'], 'là lài': ['攋', '櫴'], 'lú luó': ['攎'], 'zǎn cuán': ['攒'], 'xiān jiān': ['攕'], 'mí mǐ mó': ['攠'], 'zǎn cuán zàn zuān': ['攢'], zuàn: ['攥'], 'lì shài': ['攦'], 'lì luǒ': ['攭'], 'guǐ guì': ['攱'], 'jī qī yǐ': ['攲'], fàng: ['放'], 'wù móu': ['敄'], 'chù shōu': ['敊'], 'gé guó è': ['敋'], 'duó duì': ['敓', '敚'], 'duō què': ['敠', '敪'], 'sàn sǎn': ['散'], 'dūn duì': ['敦', '镦'], 'qī yǐ jī': ['敧'], 'xiào xué': ['敩'], 'shù shǔ shuò': ['数', '數'], 'ái zhú': ['敱', '敳'], 'xiòng xuàn': ['敻'], 'zhuó zhú': ['斀'], 'yì dù': ['斁'], 'lí tái': ['斄'], 'fěi fēi': ['斐'], 'yǔ zhōng': ['斔'], 'dòu dǒu': ['斗'], 'wò guǎn': ['斡'], 'tǒu tiǎo': ['斢'], dòu: [ '斣', '梪', '浢', '痘', '窦', '竇', '脰', '荳', '豆', '逗', '郖', '酘', '閗', '闘', '餖', '饾', '鬥', '鬦', '鬪', '鬬', '鬭', ], 'yín zhì': ['斦'], 'chǎn jiè': ['斺'], 'wū yū yú': ['於'], 'yóu liú': ['斿'], 'páng bàng': ['旁'], 'máo mào': ['旄'], 'pī bì': ['旇'], 'xuán xuàn': ['旋'], 'wú mó': ['无'], zǎo: ['早', '枣', '栆', '棗', '澡', '璪', '薻', '藻', '蚤'], gā: ['旮'], 'gàn hàn': ['旰'], 'tái yīng': ['旲'], 'xū xù': ['旴'], 'tūn zhùn': ['旽'], 'wù wǔ': ['旿'], 'pò pèi': ['昢'], zòng: ['昮', '猔', '疭', '瘲', '粽', '糉', '糭', '縦'], ǎi: ['昹', '毐', '矮', '蔼', '藹', '譪', '躷', '霭', '靄'], 'huàng huǎng': ['晃'], xuǎn: ['晅', '癣', '癬', '选', '選'], 'xù kuā': ['晇'], hǒng: ['晎'], shài: ['晒', '曬'], 'yūn yùn': ['晕', '煴'], 'shèng chéng': ['晟', '椉', '盛'], 'jǐng yǐng': ['景'], shǎn: ['晱', '熌', '睒', '覢', '閃', '闪', '陕', '陝'], 'qǐ dù': ['晵'], 'ǎn àn yǎn': ['晻'], 'wǎng wàng': ['暀'], zàn: [ '暂', '暫', '瓉', '瓒', '瓚', '禶', '襸', '讃', '讚', '賛', '贊', '赞', '蹔', '鄼', '錾', '鏨', '饡', ], 'yùn yūn': ['暈'], 'mín mǐn': ['暋'], 'dǔ shǔ': ['暏'], shǔ: [ '暑', '曙', '潻', '癙', '糬', '署', '薥', '薯', '藷', '蜀', '蠴', '襡', '襩', '鱪', '鱰', '黍', '鼠', '鼡', ], 'jiǎn lán': ['暕'], nuǎn: ['暖', '煗', '餪'], 'bào pù': ['暴'], 'xī xǐ': ['暿'], 'pù bào': ['曝', '瀑'], 'qū qǔ': ['紶'], 'qǔ qū': ['曲'], 'gèng gēng': ['更'], 'hū hù': ['曶', '雽'], 'zēng céng': ['曽', '橧'], 'céng zēng': ['曾', '竲'], 'cǎn qián jiàn': ['朁'], 'qiè hé': ['朅'], 'bì pí': ['朇', '禆', '笓', '裨'], 'yǒu yòu': ['有'], 'bān fén': ['朌', '鳻'], 'fú fù': ['服', '洑'], 'fěi kū': ['朏', '胐'], 'qú xù chǔn': ['朐'], 'juān zuī': ['朘'], 'huāng máng wáng': ['朚'], 'qī jī': ['期'], 'tóng chuáng': ['朣', '橦'], zhá: ['札', '牐', '箚', '蚻', '譗', '鍘', '铡', '閘', '闸'], 'zhú shù shú': ['朮'], 'shù shú zhú': ['术'], 'zhū shú': ['朱'], 'pǔ pò pō piáo': ['朴'], 'dāo tiáo mù': ['朷'], 'guǐ qiú': ['朹'], xiǔ: ['朽', '滫', '潃', '糔'], 'chéng chēng': ['朾'], zá: ['杂', '沯', '砸', '襍', '雑', '雜', '雥', '韴'], 'yú wū': ['杅'], 'gān gǎn': ['杆'], 'chā chà': ['杈'], 'shān shā': ['杉'], cūn: ['村', '皴', '竴', '膥', '踆', '邨'], 'rèn ér': ['杒', '梕'], 'sháo biāo': ['杓'], 'dì duò': ['杕', '枤'], 'gū gài': ['杚'], 'yí zhì lí duò': ['杝'], 'gàng gāng': ['杠'], 'tiáo tiāo': ['条', '條'], 'mà mǎ': ['杩'], 'sì zhǐ xǐ': ['杫'], 'yuán wán': ['杬', '蚖'], 'bèi fèi': ['杮'], 'shū duì': ['杸'], 'niǔ chǒu': ['杻'], 'wò yuè': ['枂', '臒'], máo: [ '枆', '毛', '氂', '渵', '牦', '矛', '罞', '茅', '茆', '蝥', '蟊', '軞', '酕', '鉾', '錨', '锚', '髦', '鶜', ], 'pī mì': ['枈'], àng: ['枊', '盎', '醠'], 'fāng bìng': ['枋'], 'hù dǐ': ['枑'], xín: ['枔', '襑', '鐔', '鬵'], 'yāo yǎo': ['枖'], 'ě è': ['枙'], 'zhī qí': ['枝'], 'cōng zōng': ['枞', '樅'], 'xiān zhēn': ['枮'], 'tái sì': ['枱'], 'gǒu jǔ gōu': ['枸'], 'bāo fú': ['枹'], 'yì xiè': ['枻', '栧'], 'tuó duò': ['柁', '馱', '駄', '驮'], 'yí duò lí': ['柂'], 'nǐ chì': ['柅'], 'pán bàn': ['柈', '跘'], 'yǎng yàng yāng yīng': ['柍'], 'fù fū fǔ': ['柎'], 'bǎi bó bò': ['柏'], mǒu: ['某'], 'sháo shào': ['柖'], zhè: ['柘', '樜', '浙', '淛', '蔗', '蟅', '這', '鷓', '鹧', '䗪'], 'yòu yóu': ['柚', '櫾'], 'guì jǔ': ['柜'], 'zhà zuò': ['柞'], 'dié zhì': ['柣', '眰'], 'zhā zǔ zū': ['柤'], 'chá zhā': ['查', '査'], 'āo ào': ['柪', '軪'], 'bā fú pèi bó biē': ['柭'], 'duò zuó wù': ['柮'], 'bì bié': ['柲'], 'zhù chù': ['柷'], 'bēi pēi': ['柸'], 'shì fèi': ['柹'], 'shān zhà shi cè': ['栅'], 'lì yuè': ['栎', '櫟'], 'qì qiè': ['栔', '砌'], 'qī xī': ['栖', '蹊'], 'guā kuò': ['栝'], 'bīng bēn': ['栟'], 'xiào jiào': ['校'], 'jiàn zùn': ['栫', '袸'], 'yǒu yù': ['栯'], 'hé hú': ['核'], gēn: ['根', '跟'], 'zhī yì': ['栺'], 'gé gē': ['格'], 'héng háng': ['桁'], 'guàng guāng': ['桄'], 'yí tí': ['桋', '荑'], sāng: ['桑', '桒', '槡'], 'jú jié': ['桔'], 'yú móu': ['桙'], 'ráo náo': ['桡', '橈'], 'guì huì': ['桧', '檜'], 'chén zhèn': ['桭'], 'tīng yíng': ['桯'], 'bó po': ['桲'], 'bèn fàn': ['桳'], 'fēng fèng': ['桻', '葑'], 'sù yìn': ['梀'], 'tǐng tìng': ['梃'], 'xuān juān xié': ['梋'], 'tú chá': ['梌'], 'āo yòu': ['梎'], kuǎn: ['梡', '欵', '款', '歀'], 'shāo sào': ['梢'], 'qín chén cén': ['梣'], 'lí sì qǐ': ['梩'], 'chān yán': ['梴'], 'bīn bīng': ['梹', '槟', '檳'], 'táo chóu dào': ['梼'], 'cōng sōng': ['棇'], 'gùn hùn': ['棍'], 'dé zhé': ['棏'], 'pái bèi pèi': ['棑'], 'bàng pǒu bèi bēi': ['棓'], 'dì dài tì': ['棣'], sēn: ['森', '椮', '槮', '襂'], 'rěn shěn': ['棯'], 'léng lēng líng': ['棱'], 'fú sù': ['棴'], 'zōu sǒu': ['棷'], zōu: [ '棸', '箃', '緅', '諏', '诹', '邹', '郰', '鄒', '鄹', '陬', '騶', '驺', '鯫', '鲰', '黀', '齱', '齺', ], 'zhào zhuō': ['棹'], 'chēn shēn': ['棽'], 'jiē qiè': ['椄'], 'yǐ yī': ['椅'], 'chóu zhòu diāo': ['椆'], 'qiāng kōng': ['椌'], 'zhuī chuí': ['椎'], 'bēi pí': ['椑'], mēn: ['椚'], 'quān juàn quán': ['椦'], 'duǒ chuán': ['椯'], 'wěi huī': ['椲'], 'jiǎ jiā': ['椵'], 'hán jiān': ['椷'], 'shèn zhēn': ['椹'], 'yàn yà': ['椻'], 'zhā chá': ['楂'], 'guō kuǎ': ['楇'], 'jí zhì': ['楖'], 'kǔ hù': ['楛'], 'yóu yǒu': ['楢'], 'sǒng cōng': ['楤'], 'yuán xuàn': ['楥'], 'yǎng yàng yīng': ['楧'], pián: ['楩', '胼', '腁', '賆', '蹁', '駢', '騈', '骈', '骿', '㛹'], 'dié yè': ['楪'], 'dùn shǔn': ['楯'], 'còu zòu': ['楱'], 'dì dǐ shì': ['楴'], 'kǎi jiē': ['楷'], 'róu ròu': ['楺'], 'lè yuè': ['楽'], 'wēn yùn': ['榅', '鞰'], lǘ: ['榈', '櫚', '氀', '膢', '藘', '閭', '闾', '驢', '驴'], shén: ['榊', '神', '鉮', '鰰', '𬬹'], 'bī pi': ['榌'], 'zhǎn niǎn zhèn': ['榐'], 'fú fù bó': ['榑'], 'jiàn jìn': ['榗'], 'bǎng bàng': ['榜'], 'shā xiè': ['榝', '樧'], nòu: ['槈', '耨', '鎒', '鐞'], 'qiǎn lián xiàn': ['槏'], gàng: ['槓', '焵', '焹', '筻', '鿍'], gāo: [ '槔', '槹', '橰', '櫜', '睾', '篙', '糕', '羔', '臯', '韟', '餻', '高', '髙', '鷎', '鷱', '鼛', ], 'diān zhěn zhēn': ['槙'], 'kǎn jiàn': ['槛'], 'xí dié': ['槢'], 'jī guī': ['槣'], 'róng yōng': ['槦'], 'tuán shuàn quán': ['槫'], 'qì sè': ['槭'], 'cuī zhǐ': ['槯'], 'yǒu chǎo': ['槱'], 'màn wàn': ['槾'], 'lí chī': ['樆'], 'léi lěi': ['樏', '櫑', '礌'], 'cháo jiǎo chāo': ['樔'], 'chēng táng': ['樘'], 'jiū liáo': ['樛'], 'mó mú': ['模'], 'niǎo mù': ['樢'], 'héng hèng': ['横', '橫'], xuě: ['樰', '膤', '艝', '轌', '雪', '鱈', '鳕'], 'fá fèi': ['橃'], rùn: ['橍', '润', '潤', '膶', '閏', '閠', '闰'], 'zhǎn jiǎn': ['橏'], shùn: ['橓', '瞚', '瞬', '舜', '蕣', '順', '顺', '鬊'], 'tuí dūn': ['橔'], 'táng chēng': ['橖'], 'sù qiū': ['橚'], 'tán diàn': ['橝'], 'fén fèn fèi': ['橨'], 'rǎn yān': ['橪'], 'cū chu': ['橻'], 'shū qiāo': ['橾'], 'píng bò': ['檘'], 'zhái shì tú': ['檡'], 'biǎo biāo': ['檦'], 'qiān lián': ['檶'], 'nǐ mí': ['檷'], 'jiàn kǎn': ['檻'], 'nòu ruǎn rú': ['檽'], 'jī jì': ['櫅', '禨'], 'huǎng guǒ gǔ': ['櫎'], 'lǜ chū': ['櫖'], 'miè mèi': ['櫗'], ōu: [ '櫙', '欧', '歐', '殴', '毆', '瓯', '甌', '膒', '藲', '謳', '讴', '鏂', '鴎', '鷗', '鸥', ], 'zhù zhuó': ['櫡'], 'jué jì': ['櫭'], 'huái guī': ['櫰'], 'chán zhàn': ['欃'], 'wéi zuì': ['欈'], cáng: ['欌', '鑶'], 'yù yì': ['欥'], 'chù qù xì': ['欪'], 'kài ài': ['欬'], 'yì yīn': ['欭'], 'xì kài': ['欯'], 'shuò sòu': ['欶'], 'ǎi ēi éi ěi èi ê̄ ế ê̌ ề': ['欸'], 'qī yī': ['欹'], 'chuā xū': ['欻'], 'chǐ chuài': ['欼'], 'kǎn qiàn': ['欿'], 'kǎn kè': ['歁'], 'chuǎn chuán': ['歂'], 'yīn yān': ['歅'], 'jìn qūn': ['歏'], pēn: ['歕'], 'xū chuā': ['歘'], 'xī shè': ['歙'], 'liǎn hān': ['歛'], 'zhì chí': ['歭'], 'sè shà': ['歰'], sǐ: ['死'], 'wěn mò': ['歾'], piǎo: ['殍', '皫', '瞟', '醥', '顠'], 'qíng jìng': ['殑'], 'fǒu bó': ['殕'], 'zhí shi': ['殖'], 'yè yān yàn': ['殗'], 'hūn mèi': ['殙'], chòu: ['殠', '臰', '遚'], 'kuì huì': ['殨', '溃', '潰'], cuàn: ['殩', '熶', '爨', '窜', '竄', '篡', '簒'], 'yīn yān yǐn': ['殷'], 'qìng kēng shēng': ['殸'], 'yáo xiáo xiào': ['殽'], 'gū gǔ': ['毂', '蛄'], 'guàn wān': ['毌'], 'dú dài': ['毒'], 'xún xùn': ['毥'], mú: ['毪', '氁'], 'dòu nuò': ['毭'], 'sāi suī': ['毸'], lu: ['氇'], sào: ['氉', '瘙', '矂', '髞'], 'shì zhī': ['氏'], 'dī dǐ': ['氐'], 'máng méng': ['氓'], 'yáng rì': ['氜'], shuǐ: ['水', '氵', '氺', '閖'], 'zhěng chéng zhèng': ['氶'], tǔn: ['氽'], 'fán fàn': ['氾'], 'guǐ jiǔ': ['氿'], 'bīn pà pā': ['汃'], 'zhuó què': ['汋'], 'dà tài': ['汏'], pìn: ['汖', '牝', '聘'], 'hàn hán': ['汗', '馯'], tu: ['汢'], 'tāng shāng': ['汤', '湯'], 'zhī jì': ['汥'], 'gàn hán cén': ['汵'], 'wèn mén': ['汶'], 'fāng pāng': ['汸'], 'hǔ huǎng': ['汻'], 'niú yóu': ['汼'], hàng: ['沆'], 'shěn chén': ['沈'], 'dùn zhuàn': ['沌'], 'nǜ niǔ': ['沑'], 'méi mò': ['沒', '没'], 'tà dá': ['沓'], 'mì wù': ['沕'], 'hóng pāng': ['沗'], 'shā shà': ['沙'], 'zhuǐ zǐ': ['沝'], 'ōu òu': ['沤', '漚'], 'jǔ jù': ['沮'], 'tuō duó': ['沰'], 'mǐ lì': ['沵'], 'yí chí': ['沶'], 'xiè yì': ['泄'], 'bó pō': ['泊'], 'mì bì': ['泌', '秘'], 'chù shè': ['泏'], 'yōu yòu āo': ['泑'], 'pēng píng': ['泙', '硑'], 'pào pāo': ['泡'], 'ní nì': ['泥', '秜'], 'yuè sà': ['泧'], 'jué xuè': ['泬', '疦'], 'lóng shuāng': ['泷', '瀧'], 'luò pō': ['泺', '濼'], 'zé shì': ['泽', '澤'], 'sǎ xǐ': ['洒'], 'sè qì zì': ['洓'], 'xǐ xiǎn': ['洗'], 'kǎo kào': ['洘'], 'àn yàn è': ['洝'], 'lěi lèi': ['洡'], 'qiè jié': ['洯'], 'qiǎn jiān': ['浅'], 'jì jǐ': ['济', '済', '濟', '纪'], 'hǔ xǔ': ['浒', '滸'], 'jùn xùn': ['浚', '濬'], 'yǐng chéng yíng': ['浧'], 'liàn lì': ['浰'], 'féng hóng': ['浲', '溄'], 'jiǒng jiōng': ['浻'], 'suī něi': ['浽'], 'yǒng chōng': ['涌'], 'tūn yūn': ['涒'], 'wō guō': ['涡', '渦'], hēng: ['涥', '脝'], 'zhǎng zhàng': ['涨', '漲'], 'shòu tāo': ['涭'], shuàn: ['涮', '腨'], 'kōng náng': ['涳'], 'wò wǎn yuān': ['涴'], 'tuō tuò': ['涶'], wō: ['涹', '猧', '窝', '窩', '莴', '萵', '蜗', '蝸', '踒'], 'qiè jí': ['淁'], 'guǒ guàn': ['淉'], 'lín lìn': ['淋', '獜', '疄'], 'tǎng chǎng': ['淌'], 'nào chuò zhuō': ['淖'], 'péng píng': ['淜'], féi: ['淝', '肥', '腓', '蜰'], 'pì pèi': ['淠'], 'niǎn shěn': ['淰'], 'biāo hǔ': ['淲'], 'chún zhūn': ['淳'], 'hùn hún': ['混'], qiǎn: ['淺', '繾', '缱', '肷', '膁', '蜸', '譴', '谴', '遣', '鑓'], 'wèn mín': ['渂'], 'rè ruò luò': ['渃'], 'dú dòu': ['渎', '瀆', '读'], 'jiàn jiān': ['渐', '溅', '漸', '濺'], 'miǎn shéng': ['渑', '澠'], 'nuǎn nuán': ['渜'], 'qiú wù': ['渞'], 'tíng tīng': ['渟'], 'dì tí dī': ['渧'], 'gǎng jiǎng': ['港'], 'hōng qìng': ['渹'], tuān: ['湍', '煓'], 'huì mǐn xū': ['湏'], 'xǔ xù': ['湑'], pén: ['湓', '瓫', '盆', '葐'], 'mǐn hūn': ['湣'], 'tuàn nuǎn': ['湪'], 'qiū jiǎo': ['湫', '湬'], 'yān yīn': ['湮'], 'bàn pán': ['湴'], 'zhuāng hún': ['湷'], 'yàn guì': ['溎'], 'lián liǎn nián xián xiàn': ['溓'], 'dá tǎ': ['溚', '鿎'], 'liū liù': ['溜', '澑', '蹓'], lùn: ['溣'], mǎ: [ '溤', '犸', '獁', '玛', '瑪', '码', '碼', '遤', '鎷', '馬', '马', '鰢', '鷌', ], 'zhēn qín': ['溱'], 'nì niào': ['溺'], 'chù xù': ['滀', '畜'], 'wěng wēng': ['滃'], 'hào xuè': ['滈'], 'qì xì xiē': ['滊'], 'xíng yíng': ['滎'], 'zé hào': ['滜'], 'piāo piào piǎo': ['漂'], 'cóng sǒng': ['漎'], 'féng péng': ['漨'], 'luò tà': ['漯'], 'pēng bēn': ['漰'], 'chóng shuāng': ['漴'], 'huǒ kuò huò': ['漷'], 'liáo liú': ['漻'], 'cuǐ cuī': ['漼'], 'cóng zǒng': ['潀'], 'cóng zōng': ['潈'], 'pì piē': ['潎'], 'dàng xiàng': ['潒'], 'huáng guāng': ['潢'], 'liáo lào lǎo': ['潦'], 'cōng zòng': ['潨'], 'zhí zhì': ['潪'], 'tān shàn': ['潬'], 'tú zhā': ['潳'], 'sàn sǎ': ['潵'], hēi: ['潶', '黑', '黒', '𬭶'], 'chéng dèng': ['澄', '瀓'], 'cūn cún': ['澊'], 'péng pēng': ['澎'], 'hòng gǒng': ['澒', '銾'], 'wàn màn': ['澫'], 'kuài huì': ['澮'], 'guō wō': ['濄'], 'pēn fén': ['濆'], 'jí shà': ['濈'], 'huì huò': ['濊'], 'dǐng tìng': ['濎'], 'mǐ nǐ': ['濔'], 'bì pì': ['濞'], 'cuì zuǐ': ['濢'], 'hù huò': ['濩'], 'ǎi kài kè': ['濭'], 'wěi duì': ['濻', '瀢'], 'zàn cuán': ['濽', '灒'], 'yǎng yàng': ['瀁'], 'wǎng wāng': ['瀇'], 'mò miè': ['瀎', '眜'], suǐ: ['瀡', '膸', '髓'], 'huái wāi': ['瀤'], 'zùn jiàn': ['瀳'], 'yīng yǐng yìng': ['瀴'], 'ráng ràng': ['瀼'], shuàng: ['灀'], 'zhuó jiào zé': ['灂'], sǎ: ['灑', '訯', '靸'], 'luán luàn': ['灓'], 'dǎng tǎng': ['灙'], 'xún quán quàn': ['灥'], 'huǒ biāo': ['灬'], 'zhà yù': ['灹'], 'fén bèn': ['炃'], 'jiǒng guì': ['炅'], 'pàng fēng': ['炐'], quē: ['炔', '缺', '缼', '蒛'], biān: [ '炞', '煸', '甂', '砭', '笾', '箯', '籩', '編', '编', '蝙', '邉', '邊', '鍽', '鞭', '鯾', '鯿', '鳊', ], 'zhāo zhào': ['炤'], 'zhuō chù': ['炪'], 'pào páo bāo': ['炮'], 'páo fǒu': ['炰'], 'shǎn qián shān': ['炶'], 'zhà zhá': ['炸'], 'jiǎo yào': ['烄'], quǎn: ['烇', '犬', '犭', '畎', '綣', '绻', '虇'], 'yàng yáng': ['烊'], 'lào luò': ['烙'], 'huí huǐ': ['烠'], rè: ['热', '熱'], 'fú páo': ['烰'], 'xiè chè': ['烲', '焎'], 'yàn shān': ['烻'], 'hūn xūn': ['焄'], kào: ['焅', '犒', '銬', '铐', '靠', '鮳', '鯌', '鲓', '㸆'], 'juān yè': ['焆'], 'jùn qū': ['焌'], 'tāo dào': ['焘'], 'chǎo jù': ['焣'], 'wò ài': ['焥'], 'zǒng cōng': ['焧'], 'xī yì': ['焬'], 'xìn xīn': ['焮'], 'chāo zhuō': ['焯'], 'xiǒng yīng': ['焸', '焽'], kuǐ: ['煃', '跬', '蹞', '頍', '𫠆'], 'huī yùn xūn': ['煇'], 'jiǎo qiāo': ['煍'], 'qián shǎn shān': ['煔'], 'xī yí': ['煕'], 'shà shā': ['煞'], 'yè zhá': ['煠'], 'yáng yàng': ['煬'], 'ēn yūn': ['煾'], 'yūn yǔn': ['熅'], 'hè xiāo': ['熇'], xióng: ['熊', '熋', '雄'], 'xūn xùn': ['熏', '爋'], gòng: ['熕', '貢', '贡'], liū: ['熘'], 'cōng zǒng': ['熜'], 'lù āo': ['熝'], 'shú shóu': ['熟'], 'fēng péng': ['熢'], 'cuǐ suī': ['熣'], tēng: ['熥', '膯', '鼟'], 'yùn yù': ['熨'], 'áo āo': ['熬'], 'hàn rǎn': ['熯'], 'ōu ǒu': ['熰'], 'huáng huǎng': ['熿'], 'chǎn dǎn chàn': ['燀'], 'jiāo zhuó qiáo jué': ['燋'], 'yàn yān': ['燕'], 'tài liè': ['燤'], āo: ['爊'], 'yàn xún': ['爓'], 'jué jiào': ['爝', '覐', '覚', '覺', '觉'], 'lǎn làn': ['爦'], 'zhuǎ zhǎo': ['爪'], 'zhǎo zhuǎ': ['爫'], 'fù fǔ': ['父'], diē: ['爹', '褺', '跌'], zāng: ['牂', '羘', '臧', '賍', '賘', '贓', '贜', '赃', '髒'], 'piàn piān': ['片'], 'biān miàn': ['牑'], bǎng: ['牓', '綁', '绑'], 'yǒu yōng': ['牗'], 'chēng chèng': ['牚', '竀'], niú: ['牛', '牜'], 'jiū lè': ['牞'], 'mù móu': ['牟'], māng: ['牤'], 'gē qiú': ['牫'], 'yòu chōu': ['牰'], 'tè zhí': ['犆'], bēn: ['犇', '錛', '锛'], 'jiān qián': ['犍', '玪'], má: ['犘', '痲', '蔴', '蟇', '麻'], 'máo lí': ['犛'], 'bá quǎn': ['犮'], 'zhuó bào': ['犳'], 'àn hān': ['犴'], 'kàng gǎng': ['犺'], 'pèi fèi': ['犻'], 'fān huān': ['犿'], kuáng: ['狂', '狅', '誑', '诳', '軖', '軠', '鵟', '𫛭'], 'yí quán chí': ['狋'], 'xīng shēng': ['狌'], 'tuó yí': ['狏'], kǔ: ['狜', '苦'], 'huán huān': ['狟'], 'hé mò': ['狢'], 'tà shì': ['狧'], 'máng dòu': ['狵'], 'xī shǐ': ['狶'], suān: ['狻', '痠', '酸'], 'bài pí': ['猈'], 'jiān yàn': ['猏', '豣'], 'yī yǐ': ['猗'], 'yá wèi': ['猚'], cāi: ['猜'], 'māo máo': ['猫', '貓'], 'chuàn chuān': ['猭'], 'tuān tuàn': ['猯', '貒'], 'yà jiá qiè': ['猰'], 'hè xiē gé hài': ['猲'], 'biān piàn': ['猵', '獱'], 'bó pò': ['猼'], 'háo gāo': ['獋'], 'fén fèn': ['獖'], 'yào xiāo': ['獟'], 'shuò xī': ['獡'], 'gé liè xiē': ['獦'], 'nòu rú': ['獳'], 'náo nǎo yōu': ['獶'], ráng: ['獽', '瓤', '禳', '穣', '穰', '蘘', '躟', '鬤'], 'náo yōu': ['獿'], 'lǜ shuài': ['率'], 'wáng wàng': ['王'], 'yáng chàng': ['玚'], 'mín wén': ['玟'], 'bīn fēn': ['玢'], 'mén yǔn': ['玧'], 'qiāng cāng': ['玱', '瑲', '篬'], 'án gān': ['玵'], 'xuán xián': ['玹'], 'cī cǐ': ['玼', '跐'], 'yí tāi': ['珆'], 'zǔ jù': ['珇'], fà: ['珐', '琺', '蕟', '髪', '髮'], 'yín kèn': ['珢'], 'huī hún': ['珲'], 'xuán qióng': ['琁'], 'fú fū': ['琈'], 'bǐng pín': ['琕'], 'cuì sè': ['琗'], 'yù wéi': ['琟'], 'tiǎn tiàn': ['琠'], 'zhuó zuó': ['琢'], 'běng pěi': ['琣'], guǎn: ['琯', '璭', '痯', '筦', '管', '舘', '輨', '錧', '館', '馆', '鳤'], 'hún huī': ['琿'], 'xié jiē': ['瑎'], 'chàng dàng yáng': ['瑒'], 'tiàn zhèn': ['瑱'], 'bīn pián': ['瑸', '璸'], 'tú shū': ['瑹'], cuǐ: ['璀', '皠', '趡'], 'zǎo suǒ': ['璅'], 'jué qióng': ['璚'], 'lú fū': ['璷'], 'jì zī': ['璾'], suí: ['瓍', '綏', '绥', '遀', '随', '隨', '髄'], 'mí xǐ': ['瓕'], 'qióng wěi wèi': ['瓗'], 'huán yè yà': ['瓛'], 'bó páo': ['瓟'], 'zhí hú': ['瓡'], piáo: ['瓢', '闝'], 'wǎ wà': ['瓦'], 'xiáng hóng': ['瓨'], wèng: ['瓮', '甕', '罋', '蕹', '齆'], 'shèn shén': ['甚'], ruí: ['甤', '緌', '蕤'], yòng: ['用', '砽', '苚', '蒏', '醟', '㶲'], shuǎi: ['甩'], béng: ['甭', '甮'], 'yóu zhá': ['甴'], 'diàn tián shèng': ['甸'], 'tǐng dīng': ['町', '甼'], 'zāi zī': ['甾'], 'bì qí': ['畁'], 'dá fú': ['畗'], 'cè jì': ['畟'], 'zāi zī tián': ['畠'], 'zhì chóu shì': ['畤'], 'fān pān': ['畨', '番'], 'shē yú': ['畬'], 'dāng dàng dǎng': ['當'], 'jiāng qiáng': ['疆'], 'pǐ yǎ shū': ['疋'], 'jié qiè': ['疌'], 'yí nǐ': ['疑'], nè: ['疒', '眲', '訥', '讷'], 'gē yì': ['疙'], 'nüè yào': ['疟', '瘧'], 'lì lài': ['疠', '癘'], 'yǎ xiā': ['疨'], xuē: ['疶', '蒆', '薛', '辥', '辪', '靴', '鞾'], 'dǎn da': ['疸'], 'fá biǎn': ['疺'], 'fèi féi': ['疿', '痱'], 'shān diàn': ['痁'], 'téng chóng': ['痋'], 'tōng tóng': ['痌'], 'wěi yòu yù': ['痏'], 'tān shǐ': ['痑'], 'pū pù': ['痡', '鋪'], 'bēng péng': ['痭'], 'má lìn': ['痳'], 'tiǎn diàn': ['痶'], 'ān yè è': ['痷'], 'kē ē': ['痾'], 'zhì chì': ['瘈'], 'jiǎ xiá xiā': ['瘕'], 'lěi huì': ['瘣'], 'chài cuó': ['瘥'], 'diān chēn': ['瘨'], 'da dá': ['瘩'], 'biě biē': ['瘪'], qué: ['瘸'], 'dàn dān': ['癉'], 'guì wēi': ['癐'], 'nòng nóng': ['癑'], 'biē biě': ['癟'], 'bō bǒ': ['癷'], bái: ['白'], 'jí bī': ['皀'], 'de dì dí dī': ['的'], 'pā bà': ['皅'], 'gāo háo': ['皋'], 'gāo yáo': ['皐'], 'lì luò bō': ['皪'], 'zhā cǔ': ['皻'], 'zhāo zhǎn dǎn': ['皽'], 'jiān jiàn': ['监', '監', '鋻', '间', '鞬'], 'gài gě hé': ['盖'], 'máng wàng': ['盳'], yuǎn: ['盶', '逺', '遠'], 'tián xián': ['盷'], 'xiāng xiàng': ['相'], dǔn: ['盹', '趸', '躉'], 'xì pǎn': ['盻'], 'shěng xǐng': ['省'], 'yún hùn': ['眃'], 'miǎn miàn': ['眄'], 'kàn kān': ['看'], 'yìng yāng yǎng': ['眏'], 'yǎo āo ǎo': ['眑'], 'jū xū kōu': ['眗'], 'yí chì': ['眙'], 'dié tì': ['眣'], 'bǐng fǎng': ['眪'], 'pàng pán': ['眫'], 'mī mí': ['眯', '瞇'], 'xuàn shùn xún': ['眴'], tiào: ['眺', '粜', '糶', '覜', '趒'], 'zhe zhuó zháo zhāo': ['着'], 'qiáo shào xiāo': ['睄'], 'cuó zhuài': ['睉'], gùn: ['睔', '謴'], 'suì zuì': ['睟'], 'pì bì': ['睥', '稫', '辟'], 'yì zé gāo': ['睪'], 'xǐng xìng': ['睲'], 'guì wèi kuì': ['瞆'], 'kòu jì': ['瞉'], 'qióng huán': ['瞏'], 'mán mén': ['瞒', '瞞'], 'diāo dōu': ['瞗'], 'lou lóu lǘ': ['瞜'], 'shùn rún': ['瞤'], 'liào liǎo': ['瞭', '钌'], 'jiàn xián': ['瞯'], 'wǔ mí': ['瞴'], 'guì kuì': ['瞶'], 'nǐng chēng': ['矃'], 'huò yuè': ['矆'], 'mēng méng': ['矇'], 'kuàng guō': ['矌'], 'guàn quán': ['矔'], 'mǎn mán': ['矕'], 'jīn guān qín': ['矜'], 'jīn qín guān': ['矝'], 'yù xù jué': ['矞'], 'jiǎo jiáo': ['矫', '矯'], duǎn: ['短'], 'shí dàn': ['石'], 'gāng qiāng kòng': ['矼'], 'huā xū': ['砉'], 'pīn bīn fēn': ['砏'], 'yán yàn': ['研', '硏'], 'luǒ kē': ['砢'], 'fú fèi': ['砩', '笰'], 'zhǔ zhù': ['砫'], 'lá lì lā': ['砬'], 'kuāng guāng': ['硄'], 'gè luò': ['硌'], 'shuò shí': ['硕', '碩'], 'wèi wéi ái': ['硙'], 'què kè kù': ['硞'], 'mǎng bàng': ['硥'], 'luò lòng': ['硦'], 'yǒng tóng': ['硧'], nüè: ['硸', '虐'], 'kēng kěng': ['硻'], 'yān yǎn': ['硽'], 'zhuì chuí duǒ': ['硾'], 'kōng kòng': ['硿'], 'zòng cóng': ['碂'], 'jiān zhàn': ['碊'], 'lù liù': ['碌', '陆'], 'què xī': ['碏'], 'lún lǔn lùn': ['碖'], 'náo gāng': ['碙'], 'jié yà': ['碣'], 'wèi wěi': ['碨'], 'tí dī': ['碮'], 'chá chā': ['碴'], 'qiāo què': ['碻'], 'sù xiè': ['碿'], 'liú liù': ['磂', '遛', '鎦', '馏'], 'sī tí': ['磃'], 'bàng páng': ['磅'], 'huá kě gū': ['磆'], 'wěi kuǐ': ['磈'], 'xiá qià yà': ['磍'], 'lián qiān': ['磏'], 'wèi ái gài': ['磑'], 'lá lā': ['磖'], 'áo qiāo': ['磝'], 'pēng pèng': ['磞', '閛'], 'yīn yǐn': ['磤'], 'lěi léi': ['磥'], 'mó mò': ['磨'], 'qì zhú': ['磩'], 'láo luò': ['磱'], 'pán bō': ['磻'], 'jí shé': ['磼'], 'hé qiāo qiào': ['礉'], 'kè huò': ['礊'], 'què hú': ['礐'], 'è qì': ['礘'], cǎ: ['礤', '礸'], 'xián xín': ['礥'], 'léi lěi lèi': ['礧'], 'yán yǎn': ['礹'], 'qí zhǐ': ['祇', '蚔'], 'bēng fāng': ['祊'], 'bì mì': ['祕'], suàn: ['祘', '笇', '筭', '算', '蒜'], 'piào piāo': ['票'], 'jì zhài': ['祭'], 'shuì lèi': ['祱'], 'jìn jīn': ['禁'], 'chán shàn': ['禅'], 'yáng shāng': ['禓'], 'zhī zhǐ tí': ['禔'], 'shàn chán': ['禪'], 'yú yù ǒu': ['禺'], 'zǐ zì': ['秄'], 'chá ná': ['秅'], 'zhǒng zhòng chóng': ['种'], 'hào mào': ['秏'], 'kù kū': ['秙'], zū: ['租', '葅'], chèng: ['秤', '穪'], 'huó kuò': ['秮', '秳'], 'chēng chèn chèng': ['称', '稱'], 'shì zhì': ['秲', '銴'], 'fù pū': ['秿'], 'xùn zè': ['稄'], 'tú shǔ': ['稌'], 'zhùn zhǔn': ['稕'], 'jī qí': ['稘', '綨', '觭'], 'léng líng': ['稜'], 'zuì zú sū': ['稡'], 'xì qiè': ['稧', '郄'], 'zhǒng zhòng': ['種'], 'zōng zǒng': ['稯'], 'xián jiān liàn': ['稴'], 'zī jiū': ['稵'], 'jī qǐ': ['稽'], ròng: ['穃'], 'shān cǎn cēn': ['穇'], 'mén méi': ['穈'], 'jǐ jì': ['穖'], 'xiāo rào': ['穘'], 'zhuō bó': ['穛'], 'tóng zhǒng zhòng': ['穜'], zuō: ['穝'], 'biāo pāo': ['穮', '藨'], 'zhuō jué': ['穱'], 'cuán zàn': ['穳'], 'kōng kòng kǒng': ['空'], 'yū yǔ': ['穻'], zhǎi: ['窄', '鉙'], báo: ['窇', '雹'], 'kū zhú': ['窋'], 'jiào liáo liù': ['窌'], 'wā guī': ['窐'], 'tiǎo yáo': ['窕'], 'xūn yìn': ['窨'], 'yà yē': ['窫'], 'tián diān yǎn': ['窴'], 'chāo kē': ['窼'], 'kuǎn cuàn': ['窽', '窾'], 'chù qì': ['竐'], 'qǔ kǒu': ['竘'], 'jìng zhěn': ['竧'], 'kǎn kàn': ['竷'], 'zhú dǔ': ['竺'], 'lè jīn': ['竻'], 'zhuì ruì': ['笍'], 'háng hàng': ['笐'], 'cén jìn hán': ['笒'], 'dā xiá nà': ['笚'], 'zé zuó': ['笮'], 'lóng lǒng': ['笼', '篭', '籠', '躘', '龓'], 'zhù zhú': ['筑', '築'], 'dá dā': ['答', '荅'], shāi: ['筛', '篩', '簁', '籭'], 'yún jūn': ['筠'], 'láng làng': ['筤', '郎', '阆'], 'zhì zhǐ': ['筫'], o: ['筽'], 'póu bù fú pú': ['箁'], 'pái bēi': ['箄'], gè: ['箇', '虼', '鉻', '铬'], 'tái chí': ['箈'], 'guǎi dài': ['箉'], 'zhào dào': ['箌'], 'jīng qìng': ['箐'], 'lín lǐn': ['箖'], 'jùn qūn': ['箘'], 'shī yí': ['箷', '釶'], 'yuē yào chuò': ['箹'], 'xiāo shuò qiào': ['箾'], 'gōng gǎn lǒng': ['篢'], 'páng péng': ['篣'], 'zhuó huò': ['篧'], 'jiǎn jiān': ['篯'], 'dí zhú': ['篴'], 'zān cēn cǎn': ['篸'], 'zhuàn suǎn zuàn': ['篹'], 'piǎo biāo': ['篻'], 'guó guì': ['簂'], 'cè jí': ['簎'], 'mì miè': ['簚'], 'shāi sī': ['簛'], 'sǔn zhuàn': ['簨'], 'gàn gǎn': ['簳'], 'bò bǒ': ['簸'], 'bó bù': ['簿'], shi: ['籂'], 'zhēn jiān': ['籈'], 'zhuàn zuǎn': ['籑'], 'fān pān biān': ['籓'], 'sǒu shǔ': ['籔'], zuǎn: ['籫', '繤', '纂', '纉', '纘', '缵'], nǚ: ['籹', '釹', '钕'], 'shā chǎo': ['粆'], 'kāng jīng': ['粇'], fěn: ['粉', '黺'], cū: ['粗', '觕', '麁', '麄', '麤'], 'nián zhān': ['粘'], 'cè sè': ['粣'], 'zhōu yù': ['粥'], 'shēn sǎn': ['糁'], 'biān biǎn': ['糄', '萹'], miàn: ['糆', '面', '靣', '麪', '麫', '麵', '麺'], 'hú hū hù': ['糊'], 'gǔ gòu': ['糓'], 'mí méi': ['糜'], 'sǎn shēn': ['糝', '糣'], zāo: ['糟', '蹧', '遭', '醩'], 'mì sī': ['糸'], 'jiū jiǔ': ['糺'], 'xì jì': ['系', '繫'], 'zhēng zhěng': ['糽'], 'chà chǎ': ['紁', '衩'], 'yuē yāo': ['約', '约'], 'hóng gōng': ['紅', '红'], 'hé gē': ['紇', '纥'], 'wén wèn': ['紋', '纹'], fóu: ['紑'], 'jì jié jiè': ['紒'], 'pī pí bǐ': ['紕', '纰'], 'jīn jìn': ['紟'], 'zhā zā': ['紥', '紮'], hā: ['紦'], 'fū fù': ['紨'], 'chōu chóu': ['紬'], 'lèi léi lěi': ['累'], 'bō bì': ['紴'], 'tiǎn zhěn': ['紾'], 'jiōng jiǒng': ['絅'], 'jié jiē': ['結', '结', '节'], 'guà kuā': ['絓'], 'bǎi mò': ['絔'], 'gēng huán': ['絙'], 'jié xié': ['絜'], 'quán shuān': ['絟'], 'gǎi ǎi': ['絠'], 'luò lào': ['絡', '络'], 'bīng bēng pēng': ['絣'], 'gěi jǐ': ['給', '给'], 'tóng tōng dòng': ['絧'], 'tiào diào dào': ['絩'], 'lěi lèi léi': ['絫'], 'gāi hài': ['絯'], 'chī zhǐ': ['絺'], 'wèn miǎn mán wàn': ['絻'], 'huán huàn wàn': ['綄'], 'qīn xiān': ['綅'], 'tì tí': ['綈'], 'yán xiàn': ['綖'], 'zōng zèng zòng': ['綜'], 'chēn lín': ['綝'], 'zhǔn zhùn': ['綧'], 'qiàn qīng zhēng': ['綪'], 'qìng qǐ': ['綮'], 'lún guān': ['綸', '纶'], 'chuò chāo': ['綽', '绰'], 'tián tǎn chān': ['緂'], 'lǜ lù': ['緑', '绿'], 'ruǎn ruàn': ['緛'], 'jí qī': ['緝'], 'zhòng chóng': ['緟', '重'], 'miáo máo': ['緢'], 'xiè yè': ['緤'], huǎn: ['緩', '缓', '㬊'], 'gēng gèng': ['緪', '縆'], 'tōu xū shū': ['緰'], 'zōng zòng': ['緵', '繌'], 'yùn gǔn': ['緷'], 'guā wō': ['緺'], 'yùn yūn wēn': ['緼', '縕'], 'bāng bàng': ['縍'], 'gǔ hú': ['縎', '鶻'], 'cī cuò suǒ': ['縒'], 'cuī shuāi': ['縗'], 'róng rǒng ròng': ['縙'], 'zài zēng': ['縡'], cài: ['縩', '菜', '蔡'], 'féng fèng': ['縫'], 'suō sù': ['縮', '缩'], 'yǎn yǐn': ['縯', '酓'], 'zòng zǒng': ['縱', '纵'], 'zhuàn juàn': ['縳'], 'mò mù': ['縸', '莫'], 'piǎo piāo': ['縹', '缥'], 'fán pó': ['繁'], 'bēng bèng': ['繃'], 'móu miù miào liǎo': ['繆'], 'yáo yóu zhòu': ['繇'], 'zēng zèng': ['繒', '缯'], 'jú jué': ['繘'], 'chuō chuò': ['繛'], 'zūn zǔn': ['繜'], rào: ['繞', '绕', '遶'], 'chǎn chán': ['繟'], 'huì huí': ['繢', '缋', '藱'], 'qiāo sāo zǎo': ['繰'], 'jiǎo zhuó': ['繳', '缴'], 'dàn tán chán': ['繵'], nǒng: ['繷'], 'pú fú': ['纀'], 'yào lì': ['纅'], 'rǎng xiāng': ['纕'], 'lí sǎ xǐ lǐ': ['纚'], 'xiān qiàn': ['纤'], 'jīng jìng': ['经'], 'tí tì': ['绨'], 'bēng běng bèng': ['绷'], 'zōng zèng': ['综'], 'jī qī': ['缉'], 'wēn yùn yūn': ['缊'], 'fèng féng': ['缝'], 'shuāi cuī suī': ['缞'], 'miù móu liáo miào mù': ['缪'], 'qiāo sāo': ['缲'], fǒu: ['缶', '缹', '缻', '雬', '鴀'], 'bà ba pí': ['罢', '罷'], 'guà guǎi': ['罫'], 'yáng xiáng': ['羊', '羏'], 'měi gāo': ['羙'], 'yì xī': ['羛'], 'qiǎng qiān': ['羟'], 'qiāng kòng': ['羫'], 'qián xián yán': ['羬'], nóu: ['羺'], 'hóng gòng': ['羾'], 'pī bì pō': ['翍'], 'qú yù': ['翑'], ké: ['翗'], 'qiào qiáo': ['翘'], 'zhái dí': ['翟'], 'dào zhōu': ['翢'], 'hóu qú': ['翵'], shuǎ: ['耍'], 'ruǎn nuò': ['耎'], 'ér nài': ['耏'], 'zhuān duān': ['耑'], 'pá bà': ['耙'], 'chí sì': ['耛'], 'qù chú': ['耝'], 'lún lǔn': ['耣'], 'jí jiè': ['耤'], 'tāng tǎng': ['耥'], pǎng: ['耪', '覫'], 'zhá zé': ['耫'], 'yē yé': ['耶'], 'yún yíng': ['耺'], 'wà tuǐ zhuó': ['聉'], 'ér nǜ': ['聏'], 'tiē zhé': ['聑'], 'dǐ zhì': ['聜'], qié: ['聺'], 'nǐ jiàn': ['聻'], 'lèi lē': ['肋'], cào: ['肏', '襙', '鄵', '鼜'], 'bó dí': ['肑'], 'xiào xiāo': ['肖'], 'dù dǔ': ['肚'], chāi: ['肞', '釵', '钗'], 'hán qín hàn': ['肣'], 'pàng pán pàn': ['肨', '胖'], 'zhūn chún': ['肫'], āng: ['肮', '骯'], 'yù yō': ['育'], 'pí bǐ bì': ['肶'], 'fèi bì': ['胇'], 'bèi bēi': ['背'], 'fèi zǐ': ['胏'], 'píng pēng': ['胓', '苹'], 'fū fú zhǒu': ['胕'], 'shèng shēng': ['胜'], kuà: ['胯', '跨', '骻'], 'gǎi hǎi': ['胲'], 'gē gé gā': ['胳'], 'néng nài': ['能'], 'guī kuì': ['胿'], 'mài mò': ['脉'], 'zāng zàng': ['脏'], 'jiǎo jué': ['脚', '角'], cuǒ: ['脞'], 'de te': ['脦'], 'zuī juān': ['脧'], něi: ['脮', '腇', '餒', '馁', '鮾', '鯘'], 'pú fǔ': ['脯'], niào: ['脲'], shuí: ['脽'], guò: ['腂', '過', '鐹'], 'là xī': ['腊'], 'yān ā': ['腌'], 'gāo gào': ['膏'], 'lù biāo': ['膔'], chuái: ['膗'], 'zhuān chuán chún zhuǎn': ['膞'], chuài: ['膪', '踹'], 'fán pán': ['膰'], 'wǔ hū': ['膴'], 'shān dàn': ['膻'], tún: ['臀', '臋', '蛌', '豘', '豚', '軘', '霕', '飩', '饨', '魨', '鲀', '黗'], 'bì bei': ['臂'], 'là gé': ['臈'], 'sào sāo': ['臊'], nào: ['臑', '閙', '闹', '鬧'], 'ní luán': ['臡'], 'qiān xián': ['臤'], 'guàng jiǒng': ['臦'], 'guǎng jiǒng': ['臩'], 'chòu xiù': ['臭'], 'mián biān': ['臱'], 'dié zhí': ['臷'], 'zhī jìn': ['臸'], 'shè shě': ['舍'], pù: ['舖', '舗'], 'bān bō pán': ['般'], kuā: ['舿'], 'gèn gěn': ['艮'], 'sè shǎi': ['色'], 'fú bó': ['艴'], 'jiāo qiú': ['艽'], 'chāi chā': ['芆'], 'sháo què': ['芍'], 'hù xià': ['芐'], 'zì zǐ': ['芓'], 'huì hū': ['芔'], 'tún chūn': ['芚'], 'jiè gài': ['芥'], 'xù zhù': ['芧'], 'yuán yán': ['芫'], 'xīn xìn': ['芯'], 'lún huā': ['芲'], 'wù hū': ['芴'], 'gōu gǒu': ['芶'], 'mào máo': ['芼'], 'fèi fú': ['芾'], 'chán yín': ['苂'], qiē: ['苆'], 'sū sù': ['苏'], 'tiáo sháo': ['苕'], 'lì jī': ['苙'], 'kē hē': ['苛'], 'jù qǔ': ['苣'], 'ruò rě': ['若'], 'zhù níng': ['苧'], 'pā bó': ['苩'], xiú: ['苬'], 'zhǎ zuó': ['苲'], 'jū chá': ['苴'], nié: ['苶'], 'shēng ruí': ['苼'], 'qié jiā': ['茄'], 'zǐ cí': ['茈'], 'qiàn xī': ['茜'], chǎi: ['茝'], 'fá pèi': ['茷'], ráo: ['荛', '蕘', '襓', '饒', '饶'], 'yíng xíng': ['荥'], 'qián xún': ['荨', '蕁'], 'yìn yīn': ['荫'], 'hé hè': ['荷'], 'shā suō': ['莎'], 'péng fēng': ['莑'], 'shēn xīn': ['莘'], 'wǎn guān guǎn': ['莞'], 'yóu sù': ['莤'], 'shāo xiāo': ['莦', '蛸'], 'làng liáng': ['莨'], 'piǎo fú': ['莩'], 'wèn wǎn miǎn': ['莬'], 'shì shí': ['莳', '蒔'], 'tù tú': ['莵'], 'xiān liǎn': ['莶', '薟'], 'wǎn yù': ['菀'], 'zōu chù': ['菆'], 'lù lǜ': ['菉'], 'jūn jùn': ['菌'], 'niè rěn': ['菍'], 'zī zì zāi': ['菑'], 'tú tù': ['菟'], 'jiē shà': ['菨'], 'qiáo zhǎo': ['菬'], 'tái zhī chí': ['菭'], 'fēi fěi': ['菲', '蜚'], 'qín qīn jīn': ['菳'], 'zū jù': ['菹', '蒩'], 'lǐn má': ['菻'], 'tián tiàn': ['菾'], tiē: ['萜', '貼', '贴'], 'luò là lào luō': ['落'], 'zhù zhuó zhe': ['著'], 'shèn rèn': ['葚'], 'gě gé': ['葛'], 'jùn suǒ': ['葰'], 'kuì kuài': ['蒉'], 'rú ná': ['蒘'], 'méng mēng měng': ['蒙'], 'yuán huán': ['蒝'], 'xú shú': ['蒣'], 'xí xì': ['蒵'], 'mì míng': ['蓂'], 'sōu sǒu': ['蓃'], 'gài gě hé hài': ['蓋'], 'yǎo zhuó': ['蓔'], 'diào tiáo dí': ['蓧'], 'xū qiū fū': ['蓲'], 'zí jú': ['蓻'], 'liǎo lù': ['蓼'], xu: ['蓿'], 'hàn hǎn': ['蔊'], 'màn wàn mán': ['蔓'], 'pó bò': ['蔢'], 'fān fán bō': ['蕃'], 'hóng hòng': ['蕻'], 'yù ào': ['薁', '隩'], 'xí xiào': ['薂'], 'báo bó bò': ['薄'], 'cí zī': ['薋'], 'wàn luàn': ['薍'], 'kǎo hāo': ['薧'], 'yuǎn wěi': ['薳'], 'zhòu chóu': ['薵'], 'wō mái': ['薶'], 'xiāo hào': ['藃'], 'yù xù xū': ['藇'], 'jiè jí': ['藉'], 'diào zhuó': ['藋'], 'cáng zàng': ['藏'], lǎ: ['藞'], 'chú zhū': ['藸'], 'pín píng': ['蘋'], 'gān hán': ['虷'], 'hóng jiàng': ['虹'], 'huī huǐ': ['虺'], 'xiā há': ['虾'], 'mǎ mà mā': ['蚂'], 'fāng bàng': ['蚄'], 'bàng bèng': ['蚌'], 'jué quē': ['蚗'], 'qín qián': ['蚙'], 'gōng zhōng': ['蚣'], 'fǔ fù': ['蚥'], 'dài dé': ['蚮'], 'gǒu qú xù': ['蚼'], 'bǒ pí': ['蚾'], 'shé yí': ['蛇'], tiě: ['蛈', '鉄', '銕', '鐡', '鐵', '铁', '驖'], 'gé luò': ['蛒'], 'máng bàng': ['蛖'], 'yì xǔ': ['蛡'], 'há gé': ['蛤'], 'qiè ní': ['蛪'], 'é yǐ': ['蛾'], 'zhē zhé': ['蜇'], 'là zhà': ['蜡'], suò: ['蜶', '逤'], 'yóu qiú': ['蝤'], 'xiā hā': ['蝦'], 'xī qī': ['螇'], 'bī pí': ['螕'], 'nài něng': ['螚'], 'hé xiá': ['螛'], 'guì huǐ': ['螝'], 'mǎ mā mà': ['螞'], 'shì zhē': ['螫'], 'zhì dié': ['螲'], 'jiàn chán': ['螹'], 'ma má mò': ['蟆'], 'mǎng měng': ['蟒'], 'biē bié': ['蟞'], 'bēn fèi': ['蟦'], 'láo liáo': ['蟧'], 'yín xún': ['蟫'], 'lí lǐ': ['蠡'], 'xuè xiě': ['血'], 'xíng háng hàng héng': ['行'], 'shuāi cuī': ['衰'], 'tuó tuō': ['袉'], 'lǐng líng': ['袊'], 'bào páo pào': ['袌'], 'jù jiē': ['袓'], 'hè kè': ['袔'], 'yí yì': ['袘', '貤'], 'nà jué': ['袦'], 'bèi pī': ['被'], 'chǐ nuǒ': ['袲'], 'chǐ qǐ duǒ nuǒ': ['袳'], 'jiá qiā jié': ['袷'], 'bó mò': ['袹'], 'guī guà': ['袿'], 'liè liě': ['裂'], 'chéng chěng': ['裎'], 'jiē gé': ['裓'], 'dāo chóu': ['裯'], 'shang cháng': ['裳'], 'yuān gǔn': ['裷'], 'yǎn ān': ['裺'], 'tì xī': ['裼'], 'fù fú': ['褔'], 'chǔ zhǔ': ['褚'], 'tuì tùn': ['褪'], lǎi: ['襰'], 'yào yāo': ['要'], 'qín tán': ['覃'], 'jiàn xiàn': ['見', '见'], piǎn: ['覑', '諞', '谝', '貵', '𡎚'], 'piē miè': ['覕'], 'yíng yǐng': ['覮'], 'qù qū': ['覰', '覷', '觑'], 'jiàn biǎn': ['覵'], 'luó luǎn': ['覶'], 'zī zuǐ': ['觜'], 'huà xiè': ['觟'], 'jiě jiè xiè': ['解', '觧'], 'xué hù': ['觷'], 'lì lù': ['觻'], tǎo: ['討', '讨'], zhùn: ['訰'], 'zī zǐ': ['訾'], 'yí dài': ['詒', '诒'], xiòng: ['詗', '诇'], 'diào tiǎo': ['誂'], 'yí chǐ chì': ['誃'], 'lǎng làng': ['誏'], 'ēi éi ěi èi xī': ['誒', '诶'], shuà: ['誜'], 'yǔ yù': ['語', '语', '雨'], 'shuō shuì yuè': ['說', '说'], 'shuí shéi': ['誰', '谁'], 'qū juè': ['誳'], 'chī lài': ['誺'], 'nì ná': ['誽'], 'diào tiáo': ['調'], 'pǐ bēi': ['諀'], 'jì jī': ['諅'], 'zé zuò zhǎ cuò': ['諎'], 'chù jí': ['諔'], 'háo xià': ['諕'], 'lùn lún': ['論', '论'], 'shì dì': ['諟'], 'huà guā': ['諣'], 'xǐ shāi āi': ['諰'], 'nán nàn': ['諵', '難'], miù: ['謬', '谬'], zèn: ['譖', '谮'], 'shí zhì': ['識', '识'], 'juàn xuān': ['讂'], 'yí tuī': ['讉'], zhán: ['讝'], 'xǔ hǔ': ['许'], 'xiáng yáng': ['详'], 'tiáo diào zhōu': ['调'], 'chén shèn': ['谌'], 'mí mèi': ['谜'], 'màn mán': ['谩'], 'gǔ yù': ['谷'], 'huō huò huá': ['豁'], 'zhì zhài': ['豸'], 'huān huán': ['貆'], 'kěn kūn': ['貇'], 'mò hé': ['貈'], 'mò hé háo': ['貉'], 'jù lóu': ['貗'], 'zé zhài': ['責', '责'], 'dài tè': ['貸'], 'bì bēn': ['賁'], 'jiǎ gǔ jià': ['賈'], 'xiōng mín': ['賯'], càng: ['賶'], 'zhuàn zuàn': ['賺', '赚'], 'wàn zhuàn': ['贃'], 'gàn gòng zhuàng': ['贛'], 'yuán yùn': ['贠'], 'bēn bì': ['贲'], 'jiǎ gǔ': ['贾'], zǒu: ['走', '赱', '鯐'], 'dié tú': ['趃'], 'jū qiè': ['趄'], 'qū cù': ['趋', '趨'], 'jí jié': ['趌'], 'guā huó': ['趏'], 'què qì jí': ['趞'], 'tàng tāng': ['趟'], 'chuō zhuó': ['趠'], 'qù cù': ['趣'], 'yuè tì': ['趯'], 'bō bào': ['趵'], 'kuà wù': ['趶'], 'guì jué': ['趹'], 'fāng fàng páng': ['趽'], 'páo bà': ['跁'], 'qí qǐ': ['跂'], 'jiàn chén': ['跈'], 'pǎo páo': ['跑'], 'diǎn diē tiē': ['跕'], 'jū jù qiè': ['跙'], bǒ: ['跛'], 'luò lì': ['跞'], 'dài duò duō chí': ['跢'], zhuǎi: ['跩'], 'bèng pián': ['跰'], 'tiào táo': ['跳'], 'shū chōu': ['跾'], 'liàng liáng': ['踉'], 'tà tā': ['踏'], chǎ: ['蹅', '鑔', '镲'], 'dí zhí': ['蹢'], 'dēng dèng': ['蹬', '鐙', '镫'], cèng: ['蹭'], 'dūn cún': ['蹲'], 'juě jué': ['蹶'], liāo: ['蹽'], 'xiè sǎ': ['躠'], tǐ: ['躰', '軆', '骵'], 'yà zhá gá': ['轧', '軋'], 'xìn xiàn': ['軐'], 'fàn guǐ': ['軓'], 'zhuàn zhuǎn': ['転'], 'zhóu zhòu': ['軸', '轴'], bú: ['轐', '醭', '鳪'], 'zhuǎn zhuàn zhuǎi': ['转'], 'zǎi zài': ['载'], 'niǎn zhǎn': ['辗'], 'biān bian': ['边'], 'dào biān': ['辺'], 'yǐ yí': ['迆', '迤', '迱'], 'guò guo guō': ['过'], 'wàng kuāng': ['迋'], 'hái huán': ['还'], 'zhè zhèi': ['这'], 'yuǎn yuàn': ['远'], 'zhì lì': ['迣'], 'zhù wǎng': ['迬'], 'zhuī duī': ['追'], 'shì kuò': ['适'], tòu: ['透'], 'tōng tòng': ['通'], guàng: ['逛'], 'dǎi dài': ['逮'], 'suì suí': ['遂'], 'tí dì': ['遆'], 'yí wèi': ['遗'], 'shì dí zhé': ['適'], cà: ['遪'], 'huán hái': ['還'], 'lí chí': ['邌'], 'kàng háng': ['邟'], 'nà nèi nā': ['那'], 'xié yá yé yú xú': ['邪'], 'gāi hái': ['郂'], 'huán xún': ['郇'], 'chī xī': ['郗'], hǎo: ['郝'], 'lì zhí': ['郦'], 'xiáo ǎo': ['郩'], 'dōu dū': ['都'], liǎo: ['曢', '鄝', '镽'], 'zàn cuán cuó': ['酂', '酇'], 'dīng dǐng': ['酊'], 'cù zuò': ['酢'], 'fā pō': ['酦'], 'shāi shī': ['酾'], niàng: ['酿', '醸'], 'qiú chōu': ['醔'], 'pō fā': ['醗', '醱'], 'chǎn chěn': ['醦'], 'yàn liǎn xiān': ['醶'], 'niàng niáng': ['釀'], 'lǐ li': ['里'], 'lí xǐ xī': ['釐'], 'liǎo liào': ['釕'], 'dīng dìng': ['釘', '钉'], 'qiǎo jiǎo': ['釥'], 'yú huá': ['釪'], 'huá wū': ['釫'], 'rì rèn jiàn': ['釰', '釼'], 'dì dài': ['釱'], 'pī zhāo': ['釽'], 'yá yé': ['釾'], 'bǎ pá': ['鈀', '钯'], 'tā tuó': ['鉈', '铊'], běi: ['鉳'], 'bǐng píng': ['鉼'], 'hā kē': ['鉿', '铪'], chòng: ['銃', '铳'], 'xiǎng jiōng': ['銄'], 'yù sì': ['銉'], 'xù huì': ['銊'], 'rén rěn': ['銋'], 'shàn shuò': ['銏'], 'chì lì': ['銐'], 'xiǎn xǐ': ['銑', '铣'], 'hóu xiàng': ['銗'], 'diào tiáo yáo': ['銚'], 'xiān kuò tiǎn guā': ['銛', '銽', '铦'], 'zhé niè': ['銸'], 'zhōng yōng': ['銿'], 'tōu tù dòu': ['鋀'], 'méi méng': ['鋂'], 'wàn jiǎn': ['鋄', '鎫'], 'tǐng dìng': ['鋌', '铤'], 'juān jiān cuān': ['鋑'], 'sī tuó': ['鋖'], 'juān xuān juàn': ['鋗'], 'wú huá wū': ['鋘'], 'zhuó chuò': ['鋜'], 'xíng xìng jīng': ['鋞'], 'jū jú': ['鋦', '锔'], 'zuì niè': ['鋷'], 'yuān yuǎn wǎn wān': ['鋺'], 'gāng gàng': ['鋼', '钢'], zhuī: ['錐', '锥', '騅', '骓', '鵻'], ā: ['錒', '锕'], 'cuō chā': ['鎈'], 'suǒ sè': ['鎍'], 'yáo zú': ['鎐'], 'yè tà gé': ['鎑'], 'qiāng chēng': ['鎗'], 'gé lì': ['鎘', '镉', '鬲'], 'bī pī bì': ['鎞'], 'gǎo hào': ['鎬'], 'zú chuò': ['鏃'], 'xiū xiù': ['鏅'], 'shòu sōu': ['鏉'], 'dí dī': ['鏑', '镝'], 'qiāo sǎn càn': ['鏒'], 'lù áo': ['鏕'], 'tāng táng': ['鏜'], 'jiàn zàn': ['鏩'], 'huì suì ruì': ['鏸'], 'qiǎng qiāng': ['鏹', '镪'], 'sǎn xiàn sà': ['鏾'], 'jiǎn jiàn': ['鐧', '锏'], 'dāng chēng': ['鐺', '铛'], 'zuān zuàn': ['鑽'], 'sà xì': ['钑'], 'yào yuè': ['钥'], 'tǒu dǒu': ['钭'], 'zuàn zuān': ['钻'], 'qiān yán': ['铅'], 'pí pī': ['铍'], 'yáo diào tiáo': ['铫'], 'tāng tàng': ['铴'], 'pù pū': ['铺'], 'tán xiān': ['锬'], 'liù liú': ['镏'], 'hào gǎo': ['镐'], 'táng tāng': ['镗'], 'tán chán xín': ['镡'], 'huò shǎn': ['閄'], 'hàn bì': ['閈', '闬'], 'kāng kàng': ['閌', '闶'], 'xián jiàn jiān jiǎn': ['閒'], 'xiā xiǎ': ['閕'], 'xiǎ kě': ['閜'], 'biàn guān': ['閞'], 'hé gé': ['閤', '颌'], 'hòng xiàng': ['閧'], 'sē xī': ['閪'], 'tíng tǐng': ['閮'], 'è yān': ['閼', '阏'], 'hòng juǎn xiàng': ['闂'], 'bǎn pàn': ['闆'], 'dū shé': ['闍', '阇'], 'què quē': ['闕'], 'tāng táng chāng': ['闛'], 'kàn hǎn': ['闞', '阚'], 'xì sè tà': ['闟'], 'mēn mèn': ['闷'], 'quē què': ['阙'], 'yán diàn': ['阽'], 'ā ē': ['阿'], 'bēi pō pí': ['陂'], 'yàn yǎn': ['隁'], 'yú yáo shù': ['隃'], 'lóng lōng': ['隆'], 'duì zhuì': ['隊'], 'suí duò': ['隋'], 'gāi qí ái': ['隑'], 'huī duò': ['隓', '隳'], 'wěi kuí': ['隗'], 'lì dài': ['隸'], 'zhuī cuī wéi': ['隹'], 'hè hú': ['隺', '鶮'], 'jùn juàn': ['隽', '雋'], 'nán nàn nuó': ['难'], 'què qiāo qiǎo': ['雀'], 'guàn huán': ['雚'], 'guī xī': ['雟'], 'sè xí': ['雭'], án: ['雸'], 'wù méng': ['雺'], tèng: ['霯'], 'lù lòu': ['露'], mái: ['霾'], 'jìng liàng': ['靚'], 'gé jí': ['革'], bǎ: ['靶'], 'yāng yàng': ['鞅'], 'gé tà sǎ': ['鞈'], 'biān yìng': ['鞕'], 'qiào shāo': ['鞘'], 'juān xuān': ['鞙'], 'shàng zhǎng': ['鞝'], 'pí bǐng bì bēi': ['鞞'], la: ['鞡'], 'xiè dié': ['鞢'], ēng: ['鞥'], 'móu mù': ['鞪'], 'bì bǐng': ['鞸'], 'mèi wà': ['韎'], rǒu: ['韖'], 'shè xiè': ['韘'], 'yùn wēn': ['韫'], 'dùn dú': ['頓', '顿'], duǐ: ['頧'], luō: ['頱'], 'bīn pín': ['頻'], yóng: ['顒', '颙', '鰫'], mān: ['顢', '颟'], 'jǐng gěng': ['颈'], 'jié xié jiá': ['颉'], 'kē ké': ['颏'], 'pín bīn': ['频'], 'chàn zhàn': ['颤'], 'fēng fěng': ['風', '风'], 'biāo diū': ['颩'], 'bá fú': ['颰'], 'sāo sōu': ['颾'], 'liù liáo': ['飂'], 'shí sì yì': ['食'], 'yǎng juàn': ['飬'], 'zhù tǒu': ['飳'], 'yí sì': ['飴'], 'zuò zé zhā': ['飵'], tiè: ['飻', '餮'], 'xiǎng náng': ['饟'], 'táng xíng': ['饧'], 'gē le': ['饹'], 'chā zha': ['馇'], 'náng nǎng': ['馕'], 'yūn wò': ['馧'], 'zhī shì': ['馶'], 'xìn jìn': ['馸'], 'kuài jué': ['駃'], zǎng: ['駔', '驵'], 'tái dài': ['駘'], 'xún xuān': ['駨'], 'liáng láng': ['駺'], piàn: ['騗', '騙', '骗', '魸'], 'dài tái': ['骀'], 'sāo sǎo': ['骚'], 'gǔ gū': ['骨'], 'bèi mó': ['骳'], 'xiāo qiāo': ['骹'], 'bǎng pǎng': ['髈'], 'bó jué': ['髉'], 'bì pǒ': ['髲'], 'máo méng': ['髳'], 'kuò yuè': ['髺'], 'bā bà': ['魞', '鲃'], 'jì cǐ': ['鮆'], 'bó bà': ['鮊'], 'zhǎ zhà': ['鮓', '鲊'], 'chóu dài': ['鮘'], 'luò gé': ['鮥'], 'guī xié wā kuí': ['鮭'], 'xiān xiǎn': ['鮮', '鲜'], 'pū bū': ['鯆'], 'yì sī': ['鯣'], 'bà bó': ['鲌'], 'guī xié': ['鲑'], 'sāi xǐ': ['鳃'], 'niǎo diǎo': ['鳥'], 'diāo zhāo': ['鳭'], 'gān hàn yàn': ['鳱'], 'fū guī': ['鳺'], 'jiān qiān zhān': ['鳽'], 'hé jiè': ['鶡'], 'piān biǎn': ['鶣'], 'chuàn zhì': ['鶨'], 'cāng qiāng': ['鶬'], 'sǔn xùn': ['鶽'], 'biāo páo': ['麃'], 'zhù cū': ['麆'], 'jūn qún': ['麇', '麕'], chi: ['麶'], 'mó me': ['麼'], 'mó me ma': ['麽'], 'mí mǒ': ['麿'], 'dàn shèn': ['黮'], 'zhěn yān': ['黰'], 'dǎn zhǎn': ['黵'], 'miǎn mǐn měng': ['黾'], hōu: ['齁'], nàng: ['齉'], 'qí jì zī zhāi': ['齐'], 'yín kěn yǎn': ['龂'], 'yín kěn': ['龈'], 'gōng wò': ['龏'], 'guī jūn qiū': ['龜', '龟'], 'kuí wā': ['䖯'], lōu: ['䁖'], 'ōu qū': ['𫭟'], 'lóu lǘ': ['𦝼'], 'gǎ gā gá': ['嘎'], 'wā guà': ['坬'], 'zhǐ dǐ': ['茋'], 'gǒng hóng': ['硔'], 'yáo xiào': ['滧'], }; const DICT1 = new _common_utils_mjs__WEBPACK_IMPORTED_MODULE_0__.FastDictFactory(); Object.keys(map).forEach((key) => { const chars = map[key]; for (let char of chars) { DICT1.set(char, key); } }); /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/data/dict2.mjs": /*!*********************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/data/dict2.mjs ***! \*********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Pattern2: function() { return /* binding */ Pattern2; }, /* harmony export */ "default": function() { return /* binding */ DICT2; } /* harmony export */ }); /* harmony import */ var _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common/constant.mjs */ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs"); const DICT2 = { 这个: 'zhè ge', 成为: 'chéng wéi', 认为: 'rèn wéi', 作为: 'zuò wéi', 部分: 'bù fen', 要求: 'yāo qiú', 应该: 'yīng gāi', 增长: 'zēng zhǎng', 提供: 'tí gōng', 觉得: 'jué de', 任务: 'rèn wu', 那个: 'nà ge', 称为: 'chēng wéi', 为主: 'wéi zhǔ', 了解: 'liǎo jiě', 处理: 'chǔ lǐ', 皇上: 'huáng shang', 只要: 'zhǐ yào', 大量: 'dà liàng', 力量: 'lì liàng', 几乎: 'jī hū', 干部: 'gàn bù', 目的: 'mù dì', 行为: 'xíng wéi', 只见: 'zhǐ jiàn', 认识: 'rèn shi', 市长: 'shì zhǎng', 师父: 'shī fu', 调查: 'diào chá', 重新: 'chóng xīn', 分为: 'fēn wéi', 知识: 'zhī shi', 导弹: 'dǎo dàn', 质量: 'zhì liàng', 行款: 'háng kuǎn', 行列: 'háng liè', 行话: 'háng huà', 行业: 'háng yè', 隔行: 'gé háng', 在行: 'zài háng', 行家: 'háng jia', 内行: 'nèi háng', 外行: 'wài háng', 同行: 'tóng háng', 本行: 'běn háng', 行伍: 'háng wǔ', 洋行: 'yáng háng', 银行: 'yín háng', 商行: 'shāng háng', 支行: 'zhī háng', 总行: 'zǒng háng', 行情: 'háng qíng', 懂行: 'dǒng háng', 行规: 'háng guī', 行当: 'háng dang', 行货: 'háng huò', 太行: 'tài háng', 入行: 'rù háng', 中行: 'zhōng háng', 农行: 'nóng háng', 工行: 'gōng háng', 建行: 'jiàn háng', 各行: "gè háng", 行号: 'háng hào', 行高: 'háng gāo', 行首: 'háng shǒu', 行尾: 'háng wěi', 行末: 'háng mò', 行长: 'háng zhǎng', 行距: 'háng jù', 换行: 'huàn háng', 行会: 'háng huì', 行辈: 'háng bèi', 行道: 'háng dào', 道行: 'dào heng', 参与: 'cān yù', 充分: 'chōng fèn', 尽管: 'jǐn guǎn', 生长: 'shēng zhǎng', 数量: 'shù liàng', 应当: 'yīng dāng', 院长: 'yuàn zhǎng', 强调: 'qiáng diào', 只能: 'zhǐ néng', 音乐: 'yīn yuè', 以为: 'yǐ wéi', 处于: 'chǔ yú', 部长: 'bù zhǎng', 蒙古: 'měng gǔ', 只有: 'zhǐ yǒu', 适当: 'shì dàng', 只好: 'zhǐ hǎo', 成长: 'chéng zhǎng', 高兴: 'gāo xìng', 不了: 'bù liǎo', 产量: 'chǎn liàng', 胖子: 'pàng zi', 显得: 'xiǎn de', 只是: 'zhǐ shì', 似的: 'shì de', 率领: 'shuài lǐng', 改为: 'gǎi wéi', 不禁: 'bù jīn', 成分: 'chéng fèn', 答应: 'dā ying', 少年: 'shào nián', 兴趣: 'xìng qù', 太监: 'tài jian', 休息: 'xiū xi', 校长: 'xiào zhǎng', 更新: 'gēng xīn', 合同: 'hé tong', 喝道: 'hè dào', 重庆: 'chóng qìng', 重建: 'chóng jiàn', 使得: 'shǐ de', 审查: 'shěn chá', 累计: 'lěi jì', 给予: 'jǐ yǔ', 极为: 'jí wéi', 冠军: 'guàn jūn', 仿佛: 'fǎng fú', 头发: 'tóu fa', 投降: 'tóu xiáng', 家长: 'jiā zhǎng', 仔细: 'zǐ xì', 要是: 'yào shi', 将领: 'jiàng lǐng', 含量: 'hán liàng', 更为: 'gèng wéi', 积累: 'jī lěi', 地处: 'dì chǔ', 县长: 'xiàn zhǎng', 少女: 'shào nǚ', 路上: 'lù shang', 只怕: 'zhǐ pà', 能量: 'néng liàng', 储量: 'chǔ liàng', 供应: 'gōng yìng', 挑战: 'tiǎo zhàn', 西藏: 'xī zàng', 记得: 'jì de', 总量: 'zǒng liàng', 当真: 'dàng zhēn', 将士: 'jiàng shì', 差别: 'chā bié', 较为: 'jiào wéi', 长老: 'zhǎng lǎo', 大夫: 'dài fu', 差异: 'chā yì', 懂得: 'dǒng de', 尽量: 'jǐn liàng', 模样: 'mú yàng', 的确: 'dí què', 为首: 'wéi shǒu', 便宜: 'pián yi', 更名: 'gēng míng', 石头: 'shí tou', 州长: 'zhōu zhǎng', 为止: 'wéi zhǐ', 漂亮: 'piào liang', 炮弹: 'pào dàn', 藏族: 'zàng zú', 角色: 'jué sè', 当作: 'dàng zuò', 尽快: 'jǐn kuài', 人为: 'rén wéi', 重复: 'chóng fù', 胡同: 'hú tòng', 差距: 'chā jù', 弟兄: 'dì xiong', 大将: 'dà jiàng', 睡觉: 'shuì jiào', 一觉: 'yí jiào', 团长: 'tuán zhǎng', 队长: 'duì zhǎng', 区长: 'qū zhǎng', 难得: 'nán dé', 丫头: 'yā tou', 会长: 'huì zhǎng', 弟弟: 'dì di', 王爷: 'wáng ye', 重量: 'zhòng liàng', 誉为: 'yù wéi', 家伙: 'jiā huo', 华山: 'huà shān', 椅子: 'yǐ zi', 流量: 'liú liàng', 长大: 'zhǎng dà', 勉强: 'miǎn qiǎng', 会计: 'kuài jì', 过分: 'guò fèn', 济南: 'jǐ nán', 调动: 'diào dòng', 燕京: 'yān jīng', 少将: 'shào jiàng', 中毒: 'zhòng dú', 晓得: 'xiǎo de', 变更: 'biàn gēng', 打更: 'dǎ gēng', 认得: 'rèn de', 苹果: 'píng guǒ', 念头: 'niàn tou', 挣扎: 'zhēng zhá', 三藏: 'sān zàng', 剥削: 'bō xuē', 丞相: 'chéng xiàng', 少量: 'shǎo liàng', 寻思: 'xún si', 夺得: 'duó dé', 干线: 'gàn xiàn', 呼吁: 'hū yù', 处罚: 'chǔ fá', 长官: 'zhǎng guān', 柏林: 'bó lín', 亲戚: 'qīn qi', 身分: 'shēn fèn', 胳膊: 'gē bo', 着手: 'zhuó shǒu', 炸弹: 'zhà dàn', 咳嗽: 'ké sou', 叶子: 'yè zi', 外长: 'wài zhǎng', 供给: 'gōng jǐ', 师长: 'shī zhǎng', 变量: 'biàn liàng', 应有: 'yīng yǒu', 下载: 'xià zài', 乐器: 'yuè qì', 间接: 'jiàn jiē', 底下: 'dǐ xià', 打扮: 'dǎ bàn', 子弹: 'zǐ dàn', 弹药: 'dàn yào', 热量: 'rè liàng', 削弱: 'xuē ruò', 骨干: 'gǔ gàn', 容量: 'róng liàng', 模糊: 'mó hu', 转动: 'zhuàn dòng', 称呼: 'chēng hu', 科长: 'kē zhǎng', 处置: 'chǔ zhì', 着重: 'zhuó zhòng', 着急: 'zháo jí', 强迫: 'qiǎng pò', 庭长: 'tíng zhǎng', 首相: 'shǒu xiàng', 喇嘛: 'lǎ ma', 镇长: 'zhèn zhǎng', 只管: 'zhǐ guǎn', 重重: 'chóng chóng', 免得: 'miǎn de', 着实: 'zhuó shí', 度假: 'dù jià', 真相: 'zhēn xiàng', 相貌: 'xiàng mào', 处分: 'chǔ fèn', 委屈: 'wěi qu', 为期: 'wéi qī', 伯伯: 'bó bo', 伯子: 'bǎi zi', 圈子: 'quān zi', 见识: 'jiàn shi', 笼罩: 'lǒng zhào', 与会: 'yù huì', 都督: 'dū du', 都市: 'dū shì', 成都: 'chéng dū', 首都: 'shǒu dū', 帝都: 'dì dū', 王都: 'wáng dū', 东都: 'dōng dū', 都护: 'dū hù', 都城: 'dū chéng', 建都: 'jiàn dū', 迁都: 'qiān dū', 故都: 'gù dū', 定都: 'dìng dū', 中都: 'zhōng dū', 六安: 'lù ān', 宰相: 'zǎi xiàng', 较量: 'jiào liàng', 对称: 'duì chèn', 总长: 'zǒng zhǎng', 相公: 'xiàng gong', 空白: 'kòng bái', 打量: 'dǎ liang', 水分: 'shuǐ fèn', 舌头: 'shé tou', 没收: 'mò shōu', 行李: 'xíng li', 判处: 'pàn chǔ', 散文: 'sǎn wén', 处境: 'chǔ jìng', 孙子: 'sūn zi', 拳头: 'quán tou', 打发: 'dǎ fā', 组长: 'zǔ zhǎng', 骨头: 'gǔ tou', 宁可: 'nìng kě', 更换: 'gēng huàn', 薄弱: 'bó ruò', 还原: 'huán yuán', 重修: 'chóng xiū', 重来: 'chóng lái', 只顾: 'zhǐ gù', 爱好: 'ài hào', 馒头: 'mán tou', 军长: 'jūn zhǎng', 首长: 'shǒu zhǎng', 厂长: 'chǎng zhǎng', 司长: 'sī zhǎng', 长子: 'zhǎng zǐ', 强劲: 'qiáng jìng', 恰当: 'qià dàng', 头儿: 'tóu er', 站长: 'zhàn zhǎng', 折腾: 'zhē teng', 相处: 'xiāng chǔ', 统率: 'tǒng shuài', 中将: 'zhōng jiàng', 命中: 'mìng zhòng', 名将: 'míng jiàng', 木头: 'mù tou', 动弹: 'dòng tan', 地壳: 'dì qiào', 干活: 'gàn huó', 少爷: 'shào ye', 水量: 'shuǐ liàng', 补给: 'bǔ jǐ', 尾巴: 'wěi ba', 来得: 'lái de', 好奇: 'hào qí', 钥匙: 'yào shi', 当做: 'dàng zuò', 沉着: 'chén zhuó', 哑巴: 'yǎ ba', 车子: 'chē zi', 上将: 'shàng jiàng', 恶心: 'ě xīn', 担子: 'dàn zi', 应届: 'yīng jiè', 主角: 'zhǔ jué', 运转: 'yùn zhuǎn', 兄长: 'xiōng zhǎng', 格式: 'gé shì', 正月: 'zhēng yuè', 营长: 'yíng zhǎng', 当成: 'dàng chéng', 女婿: 'nǚ xu', 咽喉: 'yān hóu', 重阳: 'chóng yáng', 化为: 'huà wéi', 吐蕃: 'tǔ bō', 钻进: 'zuān jìn', 乐队: 'yuè duì', 亮相: 'liàng xiàng', 被子: 'bèi zi', 舍得: 'shě de', 杉木: 'shā mù', 击中: 'jī zhòng', 排长: 'pái zhǎng', 假期: 'jià qī', 分量: 'fèn liàng', 数次: 'shù cì', 提防: 'dī fáng', 吆喝: 'yāo he', 查处: 'chá chǔ', 量子: 'liàng zǐ', 里头: 'lǐ tou', 调研: 'diào yán', 伺候: 'cì hou', 重申: 'chóng shēn', 枕头: 'zhěn tou', 拚命: 'pīn mìng', 社长: 'shè zhǎng', 归还: 'guī huán', 批量: 'pī liàng', 畜牧: 'xù mù', 点着: 'diǎn zháo', 甚为: 'shèn wéi', 小将: 'xiǎo jiàng', 着眼: 'zhuó yǎn', 处死: 'chǔ sǐ', 厌恶: 'yàn wù', 鼓乐: 'gǔ yuè', 树干: 'shù gàn', 秘鲁: 'bì lǔ', 大方: 'dà fāng', 外头: 'wài tou', 班长: 'bān zhǎng', 星宿: 'xīng xiù', 宁愿: 'nìng yuàn', 钦差: 'qīn chāi', 为数: 'wéi shù', 勾当: 'gòu dàng', 削减: 'xuē jiǎn', 间谍: 'jiàn dié', 埋怨: 'mán yuàn', 结实: 'jiē shi', 计量: 'jì liáng', 淹没: 'yān mò', 村长: 'cūn zhǎng', 连长: 'lián zhǎng', 自给: 'zì jǐ', 武将: 'wǔ jiàng', 温差: 'wēn chā', 直奔: 'zhí bèn', 供求: 'gōng qiú', 剂量: 'jì liàng', 道长: 'dào zhǎng', 泄露: 'xiè lòu', 王八: 'wáng ba', 切割: 'qiē gē', 间隔: 'jiàn gé', 一晃: 'yì huǎng', 长假: 'cháng jià', 令狐: 'líng hú', 为害: 'wéi hài', 句子: 'jù zi', 偿还: 'cháng huán', 疙瘩: 'gē da', 燕山: 'yān shān', 堵塞: 'dǔ sè', 夺冠: 'duó guàn', 扎实: 'zhā shi', 电荷: 'diàn hè', 看守: 'kān shǒu', 复辟: 'fù bì', 郁闷: 'yù mèn', 尽早: 'jǐn zǎo', 切断: 'qiē duàn', 指头: 'zhǐ tou', 为生: 'wéi shēng', 畜生: 'chù sheng', 切除: 'qiē chú', 着力: 'zhuó lì', 着想: 'zhuó xiǎng', 级差: 'jí chā', 投奔: 'tóu bèn', 棍子: 'gùn zi', 含糊: 'hán hu', 少妇: 'shào fù', 兴致: 'xìng zhì', 纳闷: 'nà mèn', 干流: 'gàn liú', 卷起: 'juǎn qǐ', 扇子: 'shàn zi', 更改: 'gēng gǎi', 笼络: 'lǒng luò', 喇叭: 'lǎ ba', 载荷: 'zài hè', 妥当: 'tuǒ dàng', 为难: 'wéi nán', 着陆: 'zhuó lù', 燕子: 'yàn zi', 干吗: 'gàn má', 白发: 'bái fà', 总得: 'zǒng děi', 夹击: 'jiā jī', 曝光: 'bào guāng', 曲调: 'qǔ diào', 相机: 'xiàng jī', 叫化: 'jiào huà', 角逐: 'jué zhú', 啊哟: 'ā yō', 载重: 'zài zhòng', 长辈: 'zhǎng bèi', 出差: 'chū chāi', 垛口: 'duǒ kǒu', 撇开: 'piē kāi', 厅长: 'tīng zhǎng', 组分: 'zǔ fèn', 误差: 'wù chā', 家当: 'jiā dàng', 传记: 'zhuàn jì', 个子: 'gè zi', 铺设: 'pū shè', 干事: 'gàn shì', 杆菌: 'gǎn jūn', 定量: 'dìng liàng', 运载: 'yùn zài', 会儿: 'huì er', 酋长: 'qiú zhǎng', 重返: 'chóng fǎn', 差额: 'chā é', 露面: 'lòu miàn', 钻研: 'zuān yán', 大城: 'dài chéng', 上当: 'shàng dàng', 销量: 'xiāo liàng', 作坊: 'zuō fang', 照相: 'zhào xiàng', 哎呀: 'āi yā', 调集: 'diào jí', 看中: 'kàn zhòng', 议长: 'yì zhǎng', 风筝: 'fēng zheng', 辟邪: 'bì xié', 空隙: 'kòng xì', 更迭: 'gēng dié', 偏差: 'piān chā', 声调: 'shēng diào', 适量: 'shì liàng', 屯子: 'tún zi', 无量: 'wú liàng', 空地: 'kòng dì', 调度: 'diào dù', 散射: 'sǎn shè', 创伤: 'chuāng shāng', 海参: 'hǎi shēn', 满载: 'mǎn zài', 重叠: 'chóng dié', 落差: 'luò chā', 单调: 'dān diào', 老将: 'lǎo jiàng', 人参: 'rén shēn', 间断: 'jiàn duàn', 重现: 'chóng xiàn', 夹杂: 'jiā zá', 调用: 'diào yòng', 萝卜: 'luó bo', 附着: 'fù zhuó', 应声: 'yìng shēng', 主将: 'zhǔ jiàng', 罪过: 'zuì guo', 咀嚼: 'jǔ jué', 为政: 'wéi zhèng', 过量: 'guò liàng', 乐曲: 'yuè qǔ', 负荷: 'fù hè', 枪弹: 'qiāng dàn', 悄然: 'qiǎo rán', 处方: 'chǔ fāng', 悄声: 'qiǎo shēng', 曲子: 'qǔ zi', 情调: 'qíng diào', 挑衅: 'tiǎo xìn', 代为: 'dài wéi', 了结: 'liǎo jié', 打中: 'dǎ zhòng', 酒吧: 'jiǔ bā', 懒得: 'lǎn de', 增量: 'zēng liàng', 衣着: 'yī zhuó', 部将: 'bù jiàng', 要塞: 'yào sài', 茶几: 'chá jī', 杠杆: 'gàng gǎn', 出没: 'chū mò', 鲜有: 'xiǎn yǒu', 间隙: 'jiàn xì', 重担: 'zhòng dàn', 重演: 'chóng yǎn', 重试: 'chóng shì', 应酬: 'yìng chou', 只当: 'zhǐ dāng', 毋宁: 'wú nìng', 包扎: 'bāo zā', 前头: 'qián tou', 卷烟: 'juǎn yān', 非得: 'fēi děi', 弹道: 'dàn dào', 杆子: 'gān zi', 门将: 'mén jiàng', 后头: 'hòu tou', 喝彩: 'hè cǎi', 暖和: 'nuǎn huo', 累积: 'lěi jī', 调遣: 'diào qiǎn', 倔强: 'jué jiàng', 宝藏: 'bǎo zàng', 丧事: 'sāng shì', 约莫: 'yuē mo', 纤夫: 'qiàn fū', 更替: 'gēng tì', 装载: 'zhuāng zài', 背包: 'bēi bāo', 帖子: 'tiě zi', 松散: 'sōng sǎn', 呼喝: 'hū hè', 可恶: 'kě wù', 自转: 'zì zhuàn', 供电: 'gōng diàn', 反省: 'fǎn xǐng', 坦率: 'tǎn shuài', 苏打: 'sū dá', 本分: 'běn fèn', 落得: 'luò de', 鄙薄: 'bǐ bó', 相间: 'xiāng jiàn', 单薄: 'dān bó', 混蛋: 'hún dàn', 贞观: 'zhēn guān', 附和: 'fù hè', 能耐: 'néng nài', 吓唬: 'xià hu', 未了: 'wèi liǎo', 引着: 'yǐn zháo', 抽调: 'chōu diào', 沙子: 'shā zi', 席卷: 'xí juǎn', 标的: 'biāo dì', 别扭: 'biè niu', 思量: 'sī liang', 喝采: 'hè cǎi', 论语: 'lún yǔ', 盖子: 'gài zi', 分外: 'fèn wài', 弄堂: 'lòng táng', 乐舞: 'yuè wǔ', 雨量: 'yǔ liàng', 毛发: 'máo fà', 差遣: 'chāi qiǎn', 背负: 'bēi fù', 转速: 'zhuàn sù', 声乐: 'shēng yuè', 夹攻: 'jiā gōng', 供水: 'gōng shuǐ', 主干: 'zhǔ gàn', 惩处: 'chéng chǔ', 长相: 'zhǎng xiàng', 公差: 'gōng chāi', 榴弹: 'liú dàn', 省得: 'shěng de', 条子: 'tiáo zi', 重围: 'chóng wéi', 阻塞: 'zǔ sè', 劲风: 'jìng fēng', 纠葛: 'jiū gé', 颠簸: 'diān bǒ', 点中: 'diǎn zhòng', 重创: 'zhòng chuāng', 姥姥: 'lǎo lao', 迷糊: 'mí hu', 公家: 'gōng jia', 几率: 'jī lǜ', 苦闷: 'kǔ mèn', 度量: 'dù liàng', 差错: 'chā cuò', 暑假: 'shǔ jià', 参差: 'cēn cī', 搭载: 'dā zài', 助长: 'zhù zhǎng', 相称: 'xiāng chèn', 红晕: 'hóng yùn', 舍命: 'shě mìng', 喜好: 'xǐ hào', 列传: 'liè zhuàn', 劲敌: 'jìng dí', 蛤蟆: 'há ma', 请假: 'qǐng jià', 钉子: 'dīng zi', 沉没: 'chén mò', 高丽: 'gāo lí', 休假: 'xiū jià', 无为: 'wú wéi', 巴结: 'bā jie', 了得: 'liǎo dé', 变相: 'biàn xiàng', 核弹: 'hé dàn', 亲家: 'qìng jia', 承载: 'chéng zài', 喝问: 'hè wèn', 还击: 'huán jī', 交还: 'jiāo huán', 将令: 'jiàng lìng', 单于: 'chán yú', 空缺: 'kòng quē', 绿林: 'lù lín', 胆量: 'dǎn liàng', 执着: 'zhí zhuó', 低调: 'dī diào', 闭塞: 'bì sè', 轻薄: 'qīng bó', 得当: 'dé dàng', 占卜: 'zhān bǔ', 扫帚: 'sào zhou', 龟兹: 'qiū cí', 年长: 'nián zhǎng', 外传: 'wài zhuàn', 头子: 'tóu zi', 裁缝: 'cái feng', 礼乐: 'lǐ yuè', 血泊: 'xuè pō', 散乱: 'sǎn luàn', 动量: 'dòng liàng', 倒腾: 'dǎo teng', 取舍: 'qǔ shě', 咱家: 'zán jiā', 长发: 'cháng fà', 爪哇: 'zhǎo wā', 弹壳: 'dàn ké', 省悟: 'xǐng wù', 嚷嚷: 'rāng rang', 连累: 'lián lèi', 应得: 'yīng dé', 族长: 'zú zhǎng', 柜子: 'guì zi', 擂鼓: 'léi gǔ', 眩晕: 'xuàn yùn', 调配: 'tiáo pèi', 躯干: 'qū gàn', 差役: 'chāi yì', 坎坷: 'kǎn kě', 少儿: 'shào ér', 乐团: 'yuè tuán', 养分: 'yǎng fèn', 退还: 'tuì huán', 格调: 'gé diào', 语调: 'yǔ diào', 音调: 'yīn diào', 乐府: 'yuè fǔ', 古朴: 'gǔ pǔ', 打点: 'dǎ diǎn', 差使: 'chāi shǐ', 匀称: 'yún chèn', 瘦削: 'shòu xuē', 膏药: 'gāo yao', 吞没: 'tūn mò', 调任: 'diào rèn', 散居: 'sǎn jū', 上头: 'shàng tóu', 风靡: 'fēng mǐ', 放假: 'fàng jià', 估量: 'gū liang', 失当: 'shī dàng', 中弹: 'zhòng dàn', 妄为: 'wàng wéi', 长者: 'zhǎng zhě', 起哄: 'qǐ hòng', 末了: 'mò liǎo', 相声: 'xiàng sheng', 校正: 'jiào zhèng', 劝降: 'quàn xiáng', 矢量: 'shǐ liàng', 沉闷: 'chén mèn', 给与: 'jǐ yǔ', 解法: 'jiě fǎ', 塞外: 'sài wài', 将校: 'jiàng xiào', 嗜好: 'shì hào', 没落: 'mò luò', 朴刀: 'pō dāo', 片子: 'piān zi', 切削: 'qiē xiāo', 弹丸: 'dàn wán', 稀薄: 'xī bó', 亏得: 'kuī dé', 间歇: 'jiàn xiē', 翘首: 'qiáo shǒu', 色调: 'sè diào', 处决: 'chǔ jué', 表率: 'biǎo shuài', 尺子: 'chǐ zi', 招降: 'zhāo xiáng', 称职: 'chèn zhí', 斗篷: 'dǒu peng', 铺子: 'pù zi', 底子: 'dǐ zi', 负载: 'fù zài', 干警: 'gàn jǐng', 倒数: 'dào shǔ', 将官: 'jiàng guān', 锄头: 'chú tou', 归降: 'guī xiáng', 疟疾: 'nüè ji', 唠叨: 'láo dao', 限量: 'xiàn liàng', 屏息: 'bǐng xī', 重逢: 'chóng féng', 器乐: 'qì yuè', 氢弹: 'qīng dàn', 脖颈: 'bó gěng', 妃子: 'fēi zi', 处事: 'chǔ shì', 参量: 'cān liàng', 轻率: 'qīng shuài', 缥缈: 'piāo miǎo', 中奖: 'zhòng jiǎng', 才干: 'cái gàn', 施舍: 'shī shě', 卷子: 'juàn zi', 游说: 'yóu shuì', 巷子: 'xiàng zi', 膀胱: 'páng guāng', 切勿: 'qiè wù', 看管: 'kān guǎn', 风头: 'fēng tou', 精干: 'jīng gàn', 高差: 'gāo chā', 恐吓: 'kǒng hè', 扁担: 'biǎn dàn', 给养: 'jǐ yǎng', 格子: 'gé zi', 供需: 'gōng xū', 反差: 'fǎn chā', 飞弹: 'fēi dàn', 微薄: 'wēi bó', 发型: 'fà xíng', 即兴: 'jí xìng', 攒动: 'cuán dòng', 间或: 'jiàn huò', 浅薄: 'qiǎn bó', 乐章: 'yuè zhāng', 顺差: 'shùn chā', 调子: 'diào zi', 相位: 'xiàng wèi', 转子: 'zhuàn zǐ', 劲旅: 'jìng lǚ', 咔嚓: 'kā chā', 了事: 'liǎo shì', 转悠: 'zhuàn you', 当铺: 'dàng pù', 爪子: 'zhuǎ zi', 单子: 'dān zi', 好战: 'hào zhàn', 燕麦: 'yàn mài', 只许: 'zhǐ xǔ', 干练: 'gàn liàn', 女将: 'nǚ jiàng', 酒量: 'jiǔ liàng', 划船: 'huá chuán', 伎俩: 'jì liǎng', 挑拨: 'tiǎo bō', 少校: 'shào xiào', 着落: 'zhuó luò', 憎恶: 'zēng wù', 刻薄: 'kè bó', 要挟: 'yāo xié', 用处: 'yòng chu', 还手: 'huán shǒu', 模具: 'mú jù', 执著: 'zhí zhuó', 喝令: 'hè lìng', 保长: 'bǎo zhǎng', 吸着: 'xī zhe', 症结: 'zhēng jié', 公转: 'gōng zhuàn', 校勘: 'jiào kān', 重提: 'chóng tí', 扫兴: 'sǎo xìng', 铺盖: 'pū gài', 长史: 'zhǎng shǐ', 差价: 'chā jià', 压根: 'yà gēn', 怔住: 'zhèng zhù', 应允: 'yīng yǔn', 切入: 'qiē rù', 战将: 'zhàn jiàng', 年少: 'nián shào', 舍身: 'shě shēn', 执拗: 'zhí niù', 处世: 'chǔ shì', 中风: 'zhòng fēng', 等量: 'děng liàng', 放量: 'fàng liàng', 腔调: 'qiāng diào', 老少: 'lǎo shào', 没入: 'mò rù', 瓜葛: 'guā gé', 将帅: 'jiàng shuài', 车载: 'chē zài', 窝囊: 'wō nang', 长进: 'zhǎng jìn', 可汗: 'kè hán', 并州: 'bīng zhōu', 供销: 'gōng xiāo', 切片: 'qiē piàn', 差事: 'chāi shì', 知会: 'zhī hui', 鹰爪: 'yīng zhǎo', 处女: 'chǔ nǚ', 切磋: 'qiē cuō', 日头: 'rì tou', 押解: 'yā jiè', 滋长: 'zī zhǎng', 道观: 'dào guàn', 脚色: 'jué sè', 当量: 'dāng liàng', 婆家: 'pó jia', 缘分: 'yuán fèn', 空闲: 'kòng xián', 好色: 'hào sè', 怒喝: 'nù hè', 笼统: 'lǒng tǒng', 边塞: 'biān sài', 何曾: 'hé céng', 重合: 'chóng hé', 零散: 'líng sǎn', 轰隆: 'hōng lōng', 化子: 'huà zi', 内蒙: 'nèi měng', 数落: 'shǔ luò', 逆差: 'nì chā', 牟利: 'móu lì', 栅栏: 'zhà lan', 中标: 'zhòng biāo', 调档: 'diào dàng', 佝偻: 'gōu lóu', 场子: 'chǎng zi', 甲壳: 'jiǎ qiào', 重温: 'chóng wēn', 炮制: 'páo zhì', 返还: 'fǎn huán', 自传: 'zì zhuàn', 高调: 'gāo diào', 殷红: 'yān hóng', 固着: 'gù zhuó', 强求: 'qiǎng qiú', 本相: 'běn xiàng', 骄横: 'jiāo hèng', 草率: 'cǎo shuài', 气闷: 'qì mèn', 着色: 'zhuó sè', 宁肯: 'nìng kěn', 兴头: 'xìng tou', 拘泥: 'jū nì', 夹角: 'jiā jiǎo', 发髻: 'fà jì', 猛将: 'měng jiàng', 约摸: 'yuē mo', 拖累: 'tuō lěi', 呢绒: 'ní róng', 钻探: 'zuān tàn', 夹层: 'jiā céng', 落魄: 'luò pò', 巷道: 'hàng dào', 运量: 'yùn liàng', 解闷: 'jiě mèn', 空儿: 'kòng er', 估摸: 'gū mo', 好客: 'hào kè', 钻孔: 'zuān kǒng', 糊弄: 'hù nòng', 荥阳: 'xíng yáng', 烦闷: 'fán mèn', 仓卒: 'cāng cù', 分叉: 'fēn chà', 厂子: 'chǎng zi', 小调: 'xiǎo diào', 少阳: 'shào yáng', 受降: 'shòu xiáng', 染坊: 'rǎn fáng', 胳臂: 'gē bei', 将门: 'jiàng mén', 模板: 'mú bǎn', 配给: 'pèi jǐ', 为伍: 'wéi wǔ', 跟头: 'gēn tou', 划算: 'huá suàn', 累赘: 'léi zhui', 哄笑: 'hōng xiào', 晕眩: 'yūn xuàn', 干掉: 'gàn diào', 缝制: 'féng zhì', 难处: 'nán chù', 着意: 'zhuó yì', 蛮横: 'mán hèng', 奇数: 'jī shù', 短发: 'duǎn fà', 生还: 'shēng huán', 还清: 'huán qīng', 看护: 'kān hù', 直率: 'zhí shuài', 奏乐: 'zòu yuè', 载客: 'zài kè', 专横: 'zhuān hèng', 湮没: 'yān mò', 空格: 'kòng gé', 铺垫: 'pū diàn', 良将: 'liáng jiàng', 哗啦: 'huā lā', 散漫: 'sǎn màn', 脱发: 'tuō fà', 送还: 'sòng huán', 埋没: 'mái mò', 累及: 'lěi jí', 薄雾: 'bó wù', 调离: 'diào lí', 舌苔: 'shé tāi', 机长: 'jī zhǎng', 栓塞: 'shuān sè', 配角: 'pèi jué', 切口: 'qiē kǒu', 创口: 'chuāng kǒu', 哈欠: 'hā qian', 实弹: 'shí dàn', 铺平: 'pū píng', 哈达: 'hǎ dá', 懒散: 'lǎn sǎn', 实干: 'shí gàn', 填空: 'tián kòng', 刁钻: 'diāo zuān', 乐师: 'yuè shī', 量变: 'liàng biàn', 诱降: 'yòu xiáng', 搪塞: 'táng sè', 征调: 'zhēng diào', 夹道: 'jiā dào', 干咳: 'gān ké', 止咳: 'zhǐ ké', 乐工: 'yuè gōng', 划过: 'huá guò', 着火: 'zháo huǒ', 更正: 'gēng zhèng', 给付: 'jǐ fù', 空子: 'kòng zi', 哪吒: 'né zhā', 正着: 'zhèng zháo', 刷子: 'shuā zi', 丧葬: 'sāng zàng', 夹带: 'jiā dài', 安分: 'ān fèn', 中意: 'zhòng yì', 长孙: 'zhǎng sūn', 校订: 'jiào dìng', 卷曲: 'juǎn qū', 载运: 'zài yùn', 投弹: 'tóu dàn', 柞蚕: 'zuò cán', 份量: 'fèn liàng', 调换: 'diào huàn', 了然: 'liǎo rán', 咧嘴: 'liě zuǐ', 典当: 'diǎn dàng', 寒假: 'hán jià', 长兄: 'zhǎng xiōng', 给水: 'jǐ shuǐ', 须发: 'xū fà', 枝干: 'zhī gàn', 属相: 'shǔ xiàng', 哄抢: 'hōng qiǎng', 刻划: 'kè huà', 塞子: 'sāi zi', 单干: 'dān gàn', 还乡: 'huán xiāng', 兆头: 'zhào tou', 寺观: 'sì guàn', 督率: 'dū shuài', 啊哈: 'ā ha', 割舍: 'gē shě', 抹布: 'mā bù', 好恶: 'hào wù', 下处: 'xià chǔ', 消长: 'xiāo zhǎng', 离间: 'lí jiàn', 准头: 'zhǔn tou', 校对: 'jiào duì', 什物: 'shí wù', 番禺: 'pān yú', 佛爷: 'fó ye', 吗啡: 'mǎ fēi', 盐分: 'yán fèn', 虎将: 'hǔ jiàng', 薄荷: 'bò he', 独处: 'dú chǔ', 空位: 'kòng wèi', 铺路: 'pū lù', 乌拉: 'wū lā', 调回: 'diào huí', 来头: 'lái tou', 闲散: 'xián sǎn', 胶卷: 'jiāo juǎn', 冒失: 'mào shi', 干劲: 'gàn jìn', 弦乐: 'xián yuè', 相国: 'xiàng guó', 丹参: 'dān shēn', 助兴: 'zhù xìng', 铺开: 'pū kāi', 次长: 'cì zhǎng', 发卡: 'fà qiǎ', 拮据: 'jié jū', 刹车: 'shā chē', 生发: 'shēng fà', 重播: 'chóng bō', 缝合: 'féng hé', 音量: 'yīn liàng', 少尉: 'shào wèi', 冲压: 'chòng yā', 苍劲: 'cāng jìng', 厚薄: 'hòu báo', 威吓: 'wēi hè', 外相: 'wài xiàng', 呼号: 'hū háo', 着迷: 'zháo mí', 挑担: 'tiāo dàn', 纹路: 'wén lù', 还俗: 'huán sú', 强横: 'qiáng hèng', 着数: 'zhāo shù', 降顺: 'xiáng shùn', 挑明: 'tiǎo míng', 眯缝: 'mī feng', 分内: 'fèn nèi', 更衣: 'gēng yī', 软和: 'ruǎn huo', 尽兴: 'jìn xìng', 号子: 'hào zi', 爪牙: 'zhǎo yá', 败将: 'bài jiàng', 猜中: 'cāi zhòng', 结扎: 'jié zā', 没空: 'méi kòng', 夹缝: 'jiā fèng', 拾掇: 'shí duo', 掺和: 'chān huo', 簸箕: 'bò ji', 电量: 'diàn liàng', 荷载: 'hè zǎi', 调式: 'diào shì', 处身: 'chǔ shēn', 打手: 'dǎ shǒu', 弹弓: 'dàn gōng', 横蛮: 'hèng mán', 能干: 'néng gàn', 校点: 'jiào diǎn', 加载: 'jiā zài', 干校: 'gàn xiào', 哄传: 'hōng chuán', 校注: 'jiào zhù', 淤塞: 'yū sè', 马扎: 'mǎ zhá', 月氏: 'yuè zhī', 高干: 'gāo gàn', 经传: 'jīng zhuàn', 曾孙: 'zēng sūn', 好斗: 'hào dòu', 关卡: 'guān qiǎ', 逃奔: 'táo bèn', 磨蹭: 'mó ceng', 牟取: 'móu qǔ', 颤栗: 'zhàn lì', 蚂蚱: 'mà zha', 撮合: 'cuō he', 趔趄: 'liè qie', 摔打: 'shuāi dǎ', 台子: 'tái zi', 分得: 'fēn de', 粘着: 'nián zhuó', 采邑: 'cài yì', 散装: 'sǎn zhuāng', 婀娜: 'ē nuó', 兴味: 'xìng wèi', 行头: 'xíng tou', 气量: 'qì liàng', 调运: 'diào yùn', 处治: 'chǔ zhì', 乐音: 'yuè yīn', 充塞: 'chōng sè', 恫吓: 'dòng hè', 论调: 'lùn diào', 相中: 'xiāng zhòng', 民乐: 'mín yuè', 炮仗: 'pào zhang', 丧服: 'sāng fú', 骁将: 'xiāo jiàng', 量刑: 'liàng xíng', 缝补: 'féng bǔ', 财会: 'cái kuài', 大干: 'dà gàn', 历数: 'lì shǔ', 校场: 'jiào chǎng', 塞北: 'sài běi', 识相: 'shí xiàng', 辱没: 'rǔ mò', 鲜亮: 'xiān liàng', 语塞: 'yǔ sè', 露脸: 'lòu liǎn', 凉快: 'liáng kuai', 腰杆: 'yāo gǎn', 溜达: 'liū da', 嘎嘎: 'gā gā', 公干: 'gōng gàn', 桔梗: 'jié gěng', 挑逗: 'tiǎo dòu', 看门: 'kān mén', 乐歌: 'yuè gē', 拓片: 'tà piàn', 挑动: 'tiǎo dòng', 准将: 'zhǔn jiàng', 遒劲: 'qiú jìng', 磨坊: 'mò fáng', 逶迤: 'wēi yí', 搅和: 'jiǎo huo', 摩挲: 'mó suō', 作弄: 'zuò nòng', 苗头: 'miáo tou', 打颤: 'dǎ zhàn', 大藏: 'dà zàng', 畜牲: 'chù shēng', 勾搭: 'gōu da', 树荫: 'shù yīn', 树杈: 'shù chà', 铁杆: 'tiě gǎn', 将相: 'jiàng xiàng', 份子: 'fèn zi', 视差: 'shì chā', 绿荫: 'lǜ yīn', 枪杆: 'qiāng gǎn', 缝纫: 'féng rèn', 愁闷: 'chóu mèn', 点将: 'diǎn jiàng', 华佗: 'huà tuó', 劲射: 'jìng shè', 箱笼: 'xiāng lǒng', 终了: 'zhōng liǎo', 鬓发: 'bìn fà', 结巴: 'jiē ba', 苦干: 'kǔ gàn', 看家: 'kān jiā', 正旦: 'zhēng dàn', 中肯: 'zhòng kěn', 厦门: 'xià mén', 东莞: 'dōng guǎn', 食量: 'shí liàng', 宫调: 'gōng diào', 间作: 'jiàn zuò', 弹片: 'dàn piàn', 差池: 'chā chí', 漂白: 'piǎo bái', 杠子: 'gàng zi', 调处: 'tiáo chǔ', 好动: 'hào dòng', 转炉: 'zhuàn lú', 屏气: 'bǐng qì', 夹板: 'jiā bǎn', 哀乐: 'āi yuè', 干道: 'gàn dào', 苦处: 'kǔ chù', 劈柴: 'pǐ chái', 长势: 'zhǎng shì', 天华: 'tiān huá', 共处: 'gòng chǔ', 校验: 'jiào yàn', 出塞: 'chū sài', 磨盘: 'mò pán', 萎靡: 'wěi mǐ', 奔丧: 'bēn sāng', 唱和: 'chàng hè', 大调: 'dà diào', 非分: 'fēi fèn', 钻营: 'zuān yíng', 夹子: 'jiā zi', 超载: 'chāo zài', 更始: 'gēng shǐ', 铃铛: 'líng dang', 披散: 'pī sàn', 发还: 'fā huán', 转轮: 'zhuàn lún', 横财: 'hèng cái', 泡桐: 'pāo tóng', 抛撒: 'pāo sǎ', 天呀: 'tiān yā', 糊糊: 'hū hu', 躯壳: 'qū qiào', 通量: 'tōng liàng', 奉还: 'fèng huán', 午觉: 'wǔ jiào', 闷棍: 'mèn gùn', 浪头: 'làng tou', 砚台: 'yàn tái', 油坊: 'yóu fáng', 学长: 'xué zhǎng', 过载: 'guò zài', 笔调: 'bǐ diào', 衣被: 'yī bèi', 畜产: 'xù chǎn', 调阅: 'diào yuè', 蛮干: 'mán gàn', 曾祖: 'zēng zǔ', 提干: 'tí gàn', 变调: 'biàn diào', 覆没: 'fù mò', 模子: 'mú zi', 乐律: 'yuè lǜ', 称心: 'chèn xīn', 木杆: 'mù gān', 重印: 'chóng yìn', 自省: 'zì xǐng', 提调: 'tí diào', 看相: 'kàn xiàng', 芋头: 'yù tou', 下切: 'xià qiē', 塞上: 'sài shàng', 铺张: 'pū zhāng', 藤蔓: 'téng wàn', 薄幸: 'bó xìng', 解数: 'xiè shù', 褪去: 'tuì qù', 霰弹: 'xiàn dàn', 柚木: 'yóu mù', 痕量: 'hén liàng', 雅乐: 'yǎ yuè', 号哭: 'háo kū', 诈降: 'zhà xiáng', 猪圈: 'zhū juàn', 咋舌: 'zé shé', 铣床: 'xǐ chuáng', 防弹: 'fáng dàn', 健将: 'jiàn jiàng', 丽水: 'lí shuǐ', 削发: 'xuē fà', 空当: 'kòng dāng', 多相: 'duō xiàng', 鲜见: 'xiǎn jiàn', 划桨: 'huá jiǎng', 载波: 'zài bō', 跳蚤: 'tiào zao', 俏皮: 'qiào pí', 吧嗒: 'bā dā', 结发: 'jié fà', 了断: 'liǎo duàn', 同调: 'tóng diào', 石磨: 'shí mò', 时差: 'shí chā', 鼻塞: 'bí sè', 挑子: 'tiāo zi', 推磨: 'tuī mò', 武侯: 'wǔ hóu', 抹煞: 'mǒ shā', 调转: 'diào zhuǎn', 籍没: 'jí mò', 还债: 'huán zhài', 调演: 'diào yǎn', 分划: 'fēn huá', 奇偶: 'jī ǒu', 断喝: 'duàn hè', 闷雷: 'mèn léi', 狼藉: 'láng jí', 饭量: 'fàn liàng', 还礼: 'huán lǐ', 转调: 'zhuǎn diào', 星相: 'xīng xiàng', 手相: 'shǒu xiàng', 配乐: 'pèi yuè', 盖头: 'gài tou', 连杆: 'lián gǎn', 簿记: 'bù jì', 刀把: 'dāo bà', 量词: 'liàng cí', 名角: 'míng jué', 步调: 'bù diào', 校本: 'jiào běn', 账簿: 'zhàng bù', 隽永: 'juàn yǒng', 稍为: 'shāo wéi', 易传: 'yì zhuàn', 乐谱: 'yuè pǔ', 牵累: 'qiān lěi', 答理: 'dā li', 喝斥: 'hè chì', 吟哦: 'yín é', 干渠: 'gàn qú', 海量: 'hǎi liàng', 精当: 'jīng dàng', 着床: 'zhuó chuáng', 月相: 'yuè xiàng', 庶几: 'shù jī', 宫观: 'gōng guàn', 论处: 'lùn chǔ', 征辟: 'zhēng bì', 厚朴: 'hòu pò', 介壳: 'jiè qiào', 吭哧: 'kēng chī', 咯血: 'kǎ xiě', 铺陈: 'pū chén', 重生: 'chóng shēng', 乐理: 'yuè lǐ', 哀号: 'āi háo', 藏历: 'zàng lì', 刚劲: 'gāng jìng', 削平: 'xuē píng', 浓荫: 'nóng yīn', 城垛: 'chéng duǒ', 当差: 'dāng chāi', 正传: 'zhèng zhuàn', 并处: 'bìng chǔ', 创面: 'chuāng miàn', 旦角: 'dàn jué', 薄礼: 'bó lǐ', 晃荡: 'huàng dang', 臊子: 'sào zi', 家什: 'jiā shí', 闷头: 'mēn tóu', 美发: 'měi fà', 度数: 'dù shu', 着凉: 'zháo liáng', 闯将: 'chuǎng jiàng', 几案: 'jī àn', 姘头: 'pīn tou', 差数: 'chā shù', 散碎: 'sǎn suì', 壅塞: 'yōng sè', 寒颤: 'hán zhàn', 牵强: 'qiān qiǎng', 无间: 'wú jiàn', 轮转: 'lún zhuàn', 号叫: 'háo jiào', 铺排: 'pū pái', 降伏: 'xiáng fú', 轧钢: 'zhá gāng', 东阿: 'dōng ē', 病假: 'bìng jià', 累加: 'lěi jiā', 梗塞: 'gěng sè', 弹夹: 'dàn jiā', 钻心: 'zuān xīn', 晃眼: 'huǎng yǎn', 魔爪: 'mó zhǎo', 标量: 'biāo liàng', 憋闷: 'biē mèn', 猜度: 'cāi duó', 处士: 'chǔ shì', 官差: 'guān chāi', 讨还: 'tǎo huán', 长门: 'cháng mén', 馏分: 'liú fēn', 里弄: 'lǐ lòng', 色相: 'sè xiàng', 雅兴: 'yǎ xìng', 角力: 'jué lì', 弹坑: 'dàn kēng', 枝杈: 'zhī chà', 夹具: 'jiā jù', 处刑: 'chǔ xíng', 悍将: 'hàn jiàng', 好学: 'hào xué', 好好: 'hǎo hǎo', 银发: 'yín fà', 扫把: 'sào bǎ', 法相: 'fǎ xiàng', 贵干: 'guì gàn', 供气: 'gōng qì', 空余: 'kòng yú', 捆扎: 'kǔn zā', 瘠薄: 'jí bó', 浆糊: 'jiàng hu', 嘎吱: 'gā zhī', 调令: 'diào lìng', 法帖: 'fǎ tiè', 淋病: 'lìn bìng', 调派: 'diào pài', 转盘: 'zhuàn pán', 供稿: 'gōng gǎo', 差官: 'chāi guān', 忧闷: 'yōu mèn', 教长: 'jiào zhǎng', 重唱: 'chóng chàng', 酒兴: 'jiǔ xìng', 乐坛: 'yuè tán', 花呢: 'huā ní', 叱喝: 'chì hè', 膀臂: 'bǎng bì', 得空: 'dé kòng', 转圈: 'zhuàn quān', 横暴: 'hèng bào', 哄抬: 'hōng tái', 引吭: 'yǐn háng', 载货: 'zài huò', 中计: 'zhòng jì', 官长: 'guān zhǎng', 相面: 'xiàng miàn', 看头: 'kàn tou', 盼头: 'pàn tou', 意兴: 'yì xìng', 军乐: 'jūn yuè', 累次: 'lěi cì', 骨嘟: 'gǔ dū', 燕赵: 'yān zhào', 报丧: 'bào sāng', 弥撒: 'mí sa', 挨斗: 'ái dòu', 扁舟: 'piān zhōu', 丑角: 'chǒu jué', 吊丧: 'diào sāng', 强将: 'qiáng jiàng', 重奏: 'chóng zòu', 发辫: 'fà biàn', 着魔: 'zháo mó', 着法: 'zhāo fǎ', 盛放: 'shèng fàng', 填塞: 'tián sè', 凶横: 'xiōng hèng', 稽首: 'qǐ shǒu', 碑帖: 'bēi tiè', 冲量: 'chōng liàng', 发菜: 'fà cài', 假发: 'jiǎ fà', 翻卷: 'fān juǎn', 小量: 'xiǎo liàng', 胶着: 'jiāo zhuó', 里子: 'lǐ zi', 调调: 'diào diao', 散兵: 'sǎn bīng', 高挑: 'gāo tiǎo', 播撒: 'bō sǎ', 夹心: 'jiā xīn', 扇动: 'shān dòng', 叨扰: 'tāo rǎo', 霓裳: 'ní cháng', 捻子: 'niǎn zi', 弥缝: 'mí féng', 撒布: 'sǎ bù', 场院: 'cháng yuàn', 省亲: 'xǐng qīn', 提拉: 'tí lā', 惯量: 'guàn liàng', 强逼: 'qiáng bī', 强征: 'qiáng zhēng', 晕车: 'yùn chē', 数道: 'shù dào', 带累: 'dài lèi', 拓本: 'tà běn', 嫌恶: 'xián wù', 宿将: 'sù jiàng', 龟裂: 'jūn liè', 缠夹: 'chán jiā', 发式: 'fà shì', 隔扇: 'gé shàn', 天分: 'tiān fèn', 癖好: 'pǐ hào', 四通: 'sì tōng', 白术: 'bái zhú', 划伤: 'huá shāng', 角斗: 'jué dòu', 听差: 'tīng chāi', 岁差: 'suì chā', 丧礼: 'sāng lǐ', 脉脉: 'mò mò', 削瘦: 'xuē shòu', 撒播: 'sǎ bō', 莎草: 'suō cǎo', 犍为: 'qián wéi', 调头: 'diào tóu', 龙卷: 'lóng juǎn', 外调: 'wài diào', 字帖: 'zì tiè', 卷发: 'juǎn fà', 揣度: 'chuǎi duó', 洋相: 'yáng xiàng', 散光: 'sǎn guāng', 骨碌: 'gū lu', 薄命: 'bó mìng', 笼头: 'lóng tóu', 咽炎: 'yān yán', 碌碡: 'liù zhou', 片儿: 'piàn er', 纤手: 'qiàn shǒu', 散体: 'sǎn tǐ', 内省: 'nèi xǐng', 强留: 'qiáng liú', 解送: 'jiè sòng', 反间: 'fǎn jiàn', 少壮: 'shào zhuàng', 留空: 'liú kōng', 告假: 'gào jià', 咳血: 'ké xuè', 薄暮: 'bó mù', 铺轨: 'pū guǐ', 磨削: 'mó xuē', 治丧: 'zhì sāng', 叉子: 'chā zi', 哄动: 'hōng dòng', 蛾子: 'é zi', 出落: 'chū luò', 股长: 'gǔ zhǎng', 贵处: 'guì chù', 还魂: 'huán hún', 例假: 'lì jià', 刹住: 'shā zhù', 身量: 'shēn liàng', 同好: 'tóng hào', 模量: 'mó liàng', 更生: 'gēng shēng', 服丧: 'fú sāng', 率直: 'shuài zhí', 字模: 'zì mú', 散架: 'sǎn jià', 答腔: 'dā qiāng', 交恶: 'jiāo wù', 薄情: 'bó qíng', 眼泡: 'yǎn pāo', 袅娜: 'niǎo nuó', 草垛: 'cǎo duò', 冲劲: 'chòng jìn', 呢喃: 'ní nán', 切中: 'qiè zhòng', 挑灯: 'tiǎo dēng', 还愿: 'huán yuàn', 激将: 'jī jiàng', 更鼓: 'gēng gǔ', 没药: 'mò yào', 败兴: 'bài xìng', 切面: 'qiē miàn', 散户: 'sǎn hù', 累进: 'lěi jìn', 背带: 'bēi dài', 秤杆: 'chèng gǎn', 碾坊: 'niǎn fáng', 簿子: 'bù zi', 扳手: 'bān shǒu', 铅山: 'yán shān', 儒将: 'rú jiàng', 重光: 'chóng guāng', 剪发: 'jiǎn fà', 长上: 'zhǎng shàng', 小传: 'xiǎo zhuàn', 压轴: 'yā zhòu', 弱冠: 'ruò guàn', 花卷: 'huā juǎn', 横祸: 'hèng huò', 夹克: 'jiā kè', 光晕: 'guāng yùn', 披靡: 'pī mǐ', 对调: 'duì diào', 夹持: 'jiā chí', 空额: 'kòng é', 平调: 'píng diào', 铺床: 'pū chuáng', 丧钟: 'sāng zhōng', 作乐: 'zuò lè', 少府: 'shào fǔ', 数数: 'shuò shuò', 奔头: 'bèn tou', 进给: 'jìn jǐ', 率性: 'shuài xìng', 乐子: 'lè zi', 绑扎: 'bǎng zā', 挑唆: 'tiǎo suō', 漂洗: 'piǎo xǐ', 夹墙: 'jiā qiáng', 咳喘: 'ké chuǎn', 乜斜: 'miē xie', 错处: 'cuò chù', 闷酒: 'mèn jiǔ', 时调: 'shí diào', 重孙: 'chóng sūn', 经幢: 'jīng chuáng', 圩场: 'xū chǎng', 调门: 'diào mén', 花头: 'huā tóu', 划拉: 'huá la', 套色: 'tào shǎi', 粗率: 'cū shuài', 相率: 'xiāng shuài', 款识: 'kuǎn zhì', 吁请: 'yù qǐng', 荫蔽: 'yīn bì', 文蛤: 'wén gé', 嘀嗒: 'dī dā', 调取: 'diào qǔ', 交差: 'jiāo chāi', 落子: 'luò zǐ', 相册: 'xiàng cè', 絮叨: 'xù dao', 落发: 'luò fà', 异相: 'yì xiàng', 浸没: 'jìn mò', 角抵: 'jué dǐ', 卸载: 'xiè zài', 春卷: 'chūn juǎn', 扎挣: 'zhá zheng', 畜养: 'xù yǎng', 吡咯: 'bǐ luò', 垛子: 'duò zi', 恶少: 'è shào', 发际: 'fà jì', 红苕: 'hóng sháo', 糨糊: 'jiàng hu', 哭丧: 'kū sāng', 稍息: 'shào xī', 晕船: 'yùn chuán', 校样: 'jiào yàng', 外差: 'wài chā', 脚爪: 'jiǎo zhǎo', 铺展: 'pū zhǎn', 芫荽: 'yán sui', 夹紧: 'jiā jǐn', 尿泡: 'suī pào', 丧乱: 'sāng luàn', 凶相: 'xiōng xiàng', 华发: 'huá fà', 打场: 'dǎ cháng', 云量: 'yún liàng', 正切: 'zhèng qiē', 划拳: 'huá quán', 划艇: 'huá tǐng', 评传: 'píng zhuàn', 拉纤: 'lā qiàn', 句读: 'jù dòu', 散剂: 'sǎn jì', 骨殖: 'gǔ shi', 塞音: 'sè yīn', 铺叙: 'pū xù', 阏氏: 'yān zhī', 冷颤: 'lěng zhàn', 煞住: 'shā zhù', 少男: 'shào nán', 管乐: 'guǎn yuè', 号啕: 'háo táo', 纳降: 'nà xiáng', 拥塞: 'yōng sè', 万乘: 'wàn shèng', 杆儿: 'gǎn ér', 葛藤: 'gé téng', 簿籍: 'bù jí', 皮夹: 'pí jiā', 校准: 'jiào zhǔn', 允当: 'yǔn dàng', 器量: 'qì liàng', 选调: 'xuǎn diào', 扮相: 'bàn xiàng', 干才: 'gàn cái', 基干: 'jī gàn', 割切: 'gē qiē', 国乐: 'guó yuè', 卡壳: 'qiǎ ké', 辟谷: 'bì gǔ', 磨房: 'mò fáng', 咿呀: 'yī yā', 芥末: 'jiè mo', 薄技: 'bó jì', 产假: 'chǎn jià', 诗兴: 'shī xìng', 重出: 'chóng chū', 转椅: 'zhuàn yǐ', 酌量: 'zhuó liang', 簿册: 'bù cè', 藏青: 'zàng qīng', 的士: 'dī shì', 调人: 'diào rén', 解元: 'jiè yuán', 茎干: 'jīng gàn', 巨量: 'jù liàng', 榔头: 'láng tou', 率真: 'shuài zhēn', 喷香: 'pèn xiāng', 锁钥: 'suǒ yuè', 虾蟆: 'há má', 相图: 'xiàng tú', 兴会: 'xìng huì', 灶头: 'zào tóu', 重婚: 'chóng hūn', 钻洞: 'zuān dòng', 忖度: 'cǔn duó', 党参: 'dǎng shēn', 调温: 'diào wēn', 杆塔: 'gān tǎ', 葛布: 'gé bù', 拱券: 'gǒng xuàn', 夹生: 'jiā shēng', 露馅: 'lòu xiàn', 恰切: 'qià qiè', 散见: 'sǎn jiàn', 哨卡: 'shào qiǎ', 烫发: 'tàng fà', 体量: 'tǐ liàng', 挺括: 'tǐng kuò', 系带: 'jì dài', 相士: 'xiàng shì', 羊圈: 'yáng juàn', 转矩: 'zhuàn jǔ', 吧台: 'bā tái', 苍术: 'cāng zhú', 菲薄: 'fěi bó', 蛤蚧: 'gé jiè', 蛤蜊: 'gé lí', 瓜蔓: 'guā wàn', 怪相: 'guài xiàng', 临帖: 'lín tiè', 女红: 'nǚ gōng', 刨床: 'bào chuáng', 翘楚: 'qiáo chǔ', 数九: 'shǔ jiǔ', 谈兴: 'tán xìng', 雄劲: 'xióng jìng', 扎染: 'zā rǎn', 遮荫: 'zhē yīn', 周正: 'zhōu zhèng', 赚头: 'zhuàn tou', 扒手: 'pá shǒu', 搀和: 'chān huo', 诚朴: 'chéng pǔ', 肚量: 'dù liàng', 干结: 'gān jié', 工尺: 'gōng chě', 家累: 'jiā lěi', 曲水: 'qū shuǐ', 沙参: 'shā shēn', 挑花: 'tiǎo huā', 阿门: 'ā mén', 背篓: 'bēi lǒu', 瘪三: 'biē sān', 裁处: 'cái chǔ', 创痛: 'chuāng tòng', 福相: 'fú xiàng', 更动: 'gēng dòng', 豪兴: 'háo xìng', 还阳: 'huán yáng', 还嘴: 'huán zuǐ', 借调: 'jiè diào', 卷云: 'juǎn yún', 流弹: 'liú dàn', 想头: 'xiǎng tou', 削价: 'xuē jià', 校阅: 'jiào yuè', 雅量: 'yǎ liàng', 别传: 'bié zhuàn', 薄酒: 'bó jiǔ', 春假: 'chūn jià', 发妻: 'fà qī', 哗哗: 'huā huā', 宽绰: 'kuān chuo', 了悟: 'liǎo wù', 切花: 'qiē huā', 审度: 'shěn duó', 应许: 'yīng xǔ', 转台: 'zhuàn tái', 仔猪: 'zǐ zhū', 裁量: 'cái liáng', 藏戏: 'zàng xì', 乘兴: 'chéng xìng', 绸缪: 'chóu móu', 摧折: 'cuī zhé', 调经: 'tiáo jīng', 调职: 'diào zhí', 缝缀: 'féng zhuì', 骨朵: 'gū duǒ', 核儿: 'hú er', 恒量: 'héng liàng', 还价: 'huán jià', 浑朴: 'hún pǔ', 苦差: 'kǔ chāi', 面糊: 'miàn hù', 煞车: 'shā chē', 省视: 'xǐng shì', 什锦: 'shí jǐn', 信差: 'xìn chāi', 余切: 'yú qiē', 攒眉: 'cuán méi', 炸糕: 'zhá gāo', 钻杆: 'zuàn gǎn', 扒灰: 'pá huī', 拌和: 'bàn huò', 长调: 'cháng diào', 大溜: 'dà liù', 抖搂: 'dǒu lōu', 飞转: 'fēi zhuàn', 干仗: 'gàn zhàng', 好胜: 'hào shèng', 画片: 'huà piàn', 搅混: 'jiǎo hún', 螺杆: 'luó gǎn', 木模: 'mù mú', 怒号: 'nù háo', 频数: 'pín shù', 无宁: 'wú níng', 遗少: 'yí shào', 邮差: 'yóu chāi', 占卦: 'zhān guà', 占星: 'zhān xīng', 重审: 'chóng shěn', 自量: 'zì liàng', 调防: 'diào fáng', 发廊: 'fà láng', 反调: 'fǎn diào', 缝子: 'fèng zi', 更夫: 'gēng fū', 骨子: 'gǔ zi', 光杆: 'guāng gǎn', 夹棍: 'jiā gùn', 居丧: 'jū sāng', 巨贾: 'jù gǔ', 看押: 'kān yā', 空转: 'kōng zhuàn', 量力: 'liàng lì', 炮烙: 'páo luò', 赔还: 'péi huán', 扑扇: 'pū shān', 散记: 'sǎn jì', 散件: 'sǎn jiàn', 删削: 'shān xuē', 射干: 'shè gàn', 条几: 'tiáo jī', 偷空: 'tōu kòng', 削壁: 'xuē bì', 校核: 'jiào hé', 阴干: 'yīn gān', 择菜: 'zhái cài', 重九: 'chóng jiǔ', 主调: 'zhǔ diào', 自禁: 'zì jīn', 吧唧: 'bā jī', 便溺: 'biàn niào', 词调: 'cí diào', 叨咕: 'dáo gu', 落枕: 'lào zhěn', 铺砌: 'pū qì', 刷白: 'shuà bái', 委靡: 'wěi mǐ', 系泊: 'xì bó', 相马: 'xiàng mǎ', 熨帖: 'yù tiē', 转筋: 'zhuàn jīn', 棒喝: 'bàng hè', 傧相: 'bīn xiàng', 镐头: 'gǎo tóu', 间苗: 'jiàn miáo', 乐池: 'yuè chí', 卖相: 'mài xiàng', 屏弃: 'bǐng qì', 铅弹: 'qiān dàn', 切变: 'qiē biàn', 请调: 'qǐng diào', 群氓: 'qún méng', 散板: 'sǎn bǎn', 省察: 'xǐng chá', 事假: 'shì jià', 纤绳: 'qiàn shéng', 重影: 'chóng yǐng', 耕种: 'gēng zhòng', 种地: 'zhòng dì', 种菜: 'zhòng cài', 栽种: 'zāi zhòng', 接种: 'jiē zhòng', 垦种: 'kěn zhòng', 种殖: 'zhòng zhí', 种瓜: 'zhòng guā', 种豆: 'zhòng dòu', 种树: 'zhòng shù', 睡着: 'shuì zháo', 笼子: 'lóng zi', 重启: 'chóng qǐ', 重整: 'chóng zhěng', 重弹: 'chóng tán', 重足: 'chóng zú', 重山: 'chóng shān', 重游: 'chóng yóu', 重峦: 'chóng luán', 爷爷: 'yé ye', 奶奶: 'nǎi nai', 姥爷: 'lǎo ye', 爸爸: 'bà ba', 妈妈: 'mā ma', 婶婶: 'shěn shen', 舅舅: 'jiù jiu', 姑姑: 'gū gu', 叔叔: 'shū shu', 姨夫: 'yí fu', 舅母: 'jiù mu', 姑父: 'gū fu', 姐夫: 'jiě fu', 婆婆: 'pó po', 公公: 'gōng gong', 舅子: 'jiù zi', 姐姐: 'jiě jie', 哥哥: 'gē ge', 妹妹: 'mèi mei', 妹夫: 'mèi fu', 姨子: 'yí zi', 宝宝: 'bǎo bao', 娃娃: 'wá wa', 孩子: 'hái zi', 日子: 'rì zi', 样子: 'yàng zi', 狮子: 'shī zi', 身子: 'shēn zi', 架子: 'jià zi', 嫂子: 'sǎo zi', 鼻子: 'bí zi', 亭子: 'tíng zi', 折子: 'zhé zi', 面子: 'miàn zi', 脖子: 'bó zi', 辈子: 'bèi zi', 帽子: 'mào zi', 拍子: 'pāi zi', 柱子: 'zhù zi', 辫子: 'biàn zi', 鸽子: 'gē zi', 房子: 'fáng zi', 丸子: 'wán zi', 摊子: 'tān zi', 牌子: 'pái zi', 胡子: 'hú zi', 鬼子: 'guǐ zi', 矮子: 'ǎi zi', 鸭子: 'yā zi', 小子: 'xiǎo zi', 影子: 'yǐng zi', 屋子: 'wū zi', 对子: 'duì zi', 点子: 'diǎn zi', 本子: 'běn zi', 种子: 'zhǒng zi', 儿子: 'ér zi', 兔子: 'tù zi', 骗子: 'piàn zi', 院子: 'yuàn zi', 猴子: 'hóu zi', 嗓子: 'sǎng zi', 侄子: 'zhí zi', 柿子: 'shì zi', 钳子: 'qián zi', 虱子: 'shī zi', 瓶子: 'píng zi', 豹子: 'bào zi', 筷子: 'kuài zi', 篮子: 'lán zi', 绳子: 'shéng zi', 嘴巴: 'zuǐ ba', 耳朵: 'ěr duo', 茄子: 'qié zi', 蚌埠: 'bèng bù', 崆峒: 'kōng tóng', 琵琶: 'pí pa', 蘑菇: 'mó gu', 葫芦: 'hú lu', 狐狸: 'hú li', 桔子: 'jú zi', 盒子: 'hé zi', 桌子: 'zhuō zi', 竹子: 'zhú zi', 师傅: 'shī fu', 衣服: 'yī fu', 袜子: 'wà zi', 杯子: 'bēi zi', 刺猬: 'cì wei', 麦子: 'mài zi', 队伍: 'duì wu', 知了: 'zhī liǎo', 鱼儿: 'yú er', 馄饨: 'hún tun', 灯笼: 'dēng long', 庄稼: 'zhuāng jia', 聪明: 'cōng ming', 镜子: 'jìng zi', 银子: 'yín zi', 盘子: 'pán zi', 了却: 'liǎo què', 力气: 'lì qi', 席子: 'xí zi', 林子: 'lín zi', 朝霞: 'zhāo xiá', 朝夕: 'zhāo xī', 朝气: 'zhāo qì', 翅膀: 'chì bǎng', 省长: 'shěng zhǎng', 臧否: 'zāng pǐ', 否泰: 'pǐ tài', 变得: 'biàn de', 丈夫: 'zhàng fu', 豆腐: 'dòu fu', 笔杆: 'bǐ gǎn', 枞阳: 'zōng yáng', 行人: 'xíng rén', 打着: 'dǎ zhe', // 一字不变调的词语(需要增补更多) // 有歧义的词:一楼、一栋、一层、一排、一连 // “一楼”这个词,上下文语意是“一整栋楼”时,需要变调成四声;我住一楼时,则是一声 第一: 'dì yī', 万一: 'wàn yī', 之一: 'zhī yī', 得之: 'dé zhī', 统一: 'tǒng yī', 唯一: 'wéi yī', 专一: 'zhuān yī', 单一: 'dān yī', 如一: 'rú yī', 其一: 'qí yī', 合一: 'hé yī', 逐一: 'zhú yī', 周一: 'zhōu yī', 初一: 'chū yī', 研一: 'yán yī', 归一: 'guī yī', 假一: 'jiǎ yī', 闻一: 'wén yī', 了了: 'liǎo liǎo', 公了: 'gōng liǎo', 私了: 'sī liǎo', // 一 发音 一月: 'yī yuè', 一号: 'yī hào', 一级: 'yī jí', 一等: 'yī děng', 一哥: 'yī gē', 月一: 'yuè yī', 一一: 'yī yī', 二一: 'èr yī', 三一: 'sān yī', 四一: 'sì yī', 五一: 'wǔ yī', 六一: 'liù yī', 七一: 'qī yī', 八一: 'bā yī', 九一: 'jiǔ yī', 一〇: 'yī líng', 一零: 'yī líng', 一二: 'yī èr', 一三: 'yī sān', 一四: 'yī sì', 一五: 'yī wǔ', 一六: 'yī liù', 一七: 'yī qī', 一八: 'yī bā', 一九: 'yī jiǔ', 一又: 'yī yòu', 一饼: 'yī bǐng', 一楼: 'yī lóu', 为例: 'wéi lì', 为准: 'wéi zhǔn', 沧海: 'cāng hǎi', 难为: 'nán wéi', 责难: 'zé nàn', 患难: 'huàn nàn', 磨难: 'mó nàn', 大难: 'dà nàn', 刁难: 'diāo nàn', 殉难: 'xùn nàn', 落难: 'luò nàn', 罹难: 'lí nàn', 灾难: 'zāi nàn', 难民: 'nàn mín', 苦难: 'kǔ nàn', 危难: 'wēi nàn', 发难: 'fā nàn', 逃难: 'táo nàn', 避难: 'bì nàn', 遇难: 'yù nàn', 阻难: 'zǔ nàn', 厄难: 'è nàn', 徇难: 'xùn nàn', 空难: 'kōng nàn', 喜欢: 'xǐ huan', 朝朝: 'zhāo zhāo', 不行: 'bù xíng', 轧轧: 'yà yà', 弯曲: 'wān qū', 扭曲: 'niǔ qū', 曲直: 'qū zhí', 委曲: 'wěi qū', 酒曲: 'jiǔ qū', 曲径: 'qū jìng', 曲解: 'qū jiě', 歪曲: 'wāi qū', 曲线: 'qū xiàn', 曲阜: 'qū fù', 九曲: 'jiǔ qū', 曲折: 'qū zhé', 曲肱: 'qū gōng', 曲意: 'qū yì', 仡佬: 'gē lǎo', }; const Pattern2 = Object.keys(DICT2).map((key) => ({ zh: key, pinyin: DICT2[key], probability: 2e-8 /* Probability.DICT */, length: 2, priority: _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__.Priority.Normal, dict: Symbol('dict2'), })); /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/data/dict3.mjs": /*!*********************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/data/dict3.mjs ***! \*********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Pattern3: function() { return /* binding */ Pattern3; }, /* harmony export */ "default": function() { return /* binding */ DICT3; } /* harmony export */ }); /* harmony import */ var _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common/constant.mjs */ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs"); const DICT3 = { 为什么: 'wèi shén me', 实际上: 'shí jì shang', 检察长: 'jiǎn chá zhǎng', 干什么: 'gàn shén me', 这会儿: 'zhè huì er', 尽可能: 'jǐn kě néng', 董事长: 'dǒng shì zhǎng', 了不起: 'liǎo bù qǐ', 参谋长: 'cān móu zhǎng', 朝鲜族: 'cháo xiǎn zú', 海内外: 'hǎi nèi wài', 禁不住: 'jīn bú zhù', 柏拉图: 'bó lā tú', 不在乎: 'bú zài hu', 洛杉矶: 'luò shān jī', 有点儿: 'yǒu diǎn er', 迫击炮: 'pǎi jī pào', 不得了: 'bù dé liǎo', 马尾松: 'mǎ wěi sōng', 运输量: 'yùn shū liàng', 发脾气: 'fā pí qi', 士大夫: 'shì dà fū', 鸭绿江: 'yā lù jiāng', 压根儿: 'yà gēn er', 对得起: 'duì de qǐ', 那会儿: 'nà huì er', 自个儿: 'zì gě er', 物理量: 'wù lǐ liàng', 怎么着: 'zěn me zhāo', 明晃晃: 'míng huǎng huǎng', 节假日: 'jié jià rì', 心里话: 'xīn lǐ huà', 发行量: 'fā xíng liàng', 兴冲冲: 'xìng chōng chōng', 分子量: 'fēn zǐ liàng', 国子监: 'guó zǐ jiàn', 老大难: 'lǎo dà nán', 党内外: 'dǎng nèi wài', 这么着: 'zhè me zhāo', 少奶奶: 'shào nǎi nai', 暗地里: 'àn dì lǐ', 更年期: 'gēng nián qī', 工作量: 'gōng zuò liàng', 背地里: 'bèi dì lǐ', 山里红: 'shān li hóng', 好好儿: 'hǎo hāo er', 交响乐: 'jiāo xiǎng yuè', 好意思: 'hǎo yì si', 吐谷浑: 'tǔ yù hún', 没意思: 'méi yì si', 理发师: 'lǐ fà shī', 塔什干: 'tǎ shí gān', 充其量: 'chōng qí liàng', 靠得住: 'kào de zhù', 车行道: 'chē xíng dào', 人行道: 'rén xíng dào', 中郎将: 'zhōng láng jiàng', 照明弹: 'zhào míng dàn', 烟幕弹: 'yān mù dàn', 没奈何: 'mò nài hé', 乱哄哄: 'luàn hōng hōng', 惠更斯: 'huì gēng sī', 载重量: 'zài zhòng liàng', 瞧得起: 'qiáo de qǐ', 纪传体: 'jì zhuàn tǐ', 阿房宫: 'ē páng gōng', 卷心菜: 'juǎn xīn cài', 戏班子: 'xì bān zi', 过得去: 'guò de qù', 花岗石: 'huā gāng shí', 外甥女: 'wài sheng nǚ', 团团转: 'tuán tuán zhuàn', 大堡礁: 'dà bǎo jiāo', 燃烧弹: 'rán shāo dàn', 劳什子: 'láo shí zi', 摇滚乐: 'yáo gǔn yuè', 夹竹桃: 'jiā zhú táo', 闹哄哄: 'nào hōng hōng', 三连冠: 'sān lián guàn', 重头戏: 'zhòng tóu xì', 二人转: 'èr rén zhuàn', 节骨眼: 'jiē gǔ yǎn', 知识面: 'zhī shi miàn', 护士长: 'hù shi zhǎng', 信号弹: 'xìn hào dàn', 干电池: 'gān diàn chí', 枪杆子: 'qiāng gǎn zi', 哭丧棒: 'kū sāng bàng', 鼻咽癌: 'bí yān ái', 瓦岗军: 'wǎ gāng jūn', 买得起: 'mǎi de qǐ', 癞蛤蟆: 'lài há ma', 脊梁骨: 'jǐ liang gǔ', 子母弹: 'zǐ mǔ dàn', 开小差: 'kāi xiǎo chāi', 女强人: 'nǚ qiáng rén', 英雄传: 'yīng xióng zhuàn', 爵士乐: 'jué shì yuè', 说笑话: 'shuō xiào hua', 碰头会: 'pèng tóu huì', 玻璃钢: 'bō li gāng', 曳光弹: 'yè guāng dàn', 少林拳: 'shào lín quán', 咏叹调: 'yǒng tàn diào', 少先队: 'shào xiān duì', 灵长目: 'líng zhǎng mù', 对着干: 'duì zhe gàn', 蒙蒙亮: 'méng méng liàng', 软骨头: 'ruǎn gǔ tou', 铺盖卷: 'pū gài juǎn', 和稀泥: 'huò xī ní', 背黑锅: 'bēi hēi guō', 红彤彤: 'hóng tōng tōng', 武侯祠: 'wǔ hóu cí', 打哆嗦: 'dǎ duō suo', 户口簿: 'hù kǒu bù', 马尾藻: 'mǎ wěi zǎo', 夜猫子: 'yè māo zi', 打手势: 'dǎ shǒu shì', 龙王爷: 'lóng wáng yé', 气头上: 'qì tóu shang', 糊涂虫: 'hú tu chóng', 笔杆子: 'bǐ gǎn zi', 占便宜: 'zhàn pián yi', 打主意: 'dǎ zhǔ yì', 多弹头: 'duō dàn tóu', 露一手: 'lòu yì shǒu', 堰塞湖: 'yàn sè hú', 保得住: 'bǎo de zhù', 趵突泉: 'bào tū quán', 奥得河: 'ào de hé', 司务长: 'sī wù zhǎng', 禁不起: 'jīn bù qǐ', 什刹海: 'shí chà hǎi', 莲花落: 'lián huā lào', 见世面: 'jiàn shì miàn', 豁出去: 'huō chū qù', 电位差: 'diàn wèi chā', 挨个儿: 'āi gè er', 那阵儿: 'nà zhèn er', 肺活量: 'fèi huó liàng', 大师傅: 'dà shī fu', 掷弹筒: 'zhì dàn tǒng', 打呼噜: 'dǎ hū lu', 广渠门: 'ān qú mén', 未见得: 'wèi jiàn dé', 大婶儿: 'dà shěn er', 谈得来: 'tán de lái', 脚丫子: 'jiǎo yā zi', 空包弹: 'kōng bāo dàn', 窝里斗: 'wō li dòu', 弹着点: 'dàn zhuó diǎn', 个头儿: 'gè tóu er', 看得起: 'kàn de qǐ', 糊涂账: 'hú tu zhàng', 大猩猩: 'dà xīng xing', 禁得起: 'jīn de qǐ', 法相宗: 'fǎ xiàng zōng', 可怜相: 'kě lián xiàng', 吃得下: 'chī de xià', 汉堡包: 'hàn bǎo bāo', 闹嚷嚷: 'nào rāng rāng', 数来宝: 'shǔ lái bǎo', 合得来: 'hé de lái', 干性油: 'gān xìng yóu', 闷葫芦: 'mèn hú lu', 呱呱叫: 'guā guā jiào', 西洋参: 'xī yáng shēn', 林荫道: 'lín yīn dào', 拉家常: 'lā jiā cháng', 卷铺盖: 'juǎn pū gài', 过得硬: 'guò de yìng', 飞将军: 'fēi jiāng jūn', 挑大梁: 'tiǎo dà liáng', 哈巴狗: 'hǎ ba gǒu', 过家家: 'guò jiā jiā', 催泪弹: 'cuī lèi dàn', 雨夹雪: 'yǔ jiā xuě', 敲竹杠: 'qiāo zhú gàng', 列车长: 'liè chē zhǎng', 华达呢: 'huá dá ní', 犯得着: 'fàn de zháo', 土疙瘩: 'tǔ gē da', 煞风景: 'shā fēng jǐng', 轻量级: 'qīng liàng jí', 羞答答: 'xiū dā dā', 石子儿: 'shí zǐ er', 达姆弹: 'dá mǔ dàn', 科教片: 'kē jiào piān', 侃大山: 'kǎn dà shān', 丁点儿: 'dīng diǎn er', 吃得消: 'chī de xiāo', 捋虎须: 'luō hǔ xū', 高丽参: 'gāo lí shēn', 众生相: 'zhòng shēng xiàng', 咽峡炎: 'yān xiá yán', 禁得住: 'jīn de zhù', 吃得开: 'chī de kāi', 柞丝绸: 'zuò sī chóu', 应声虫: 'yìng shēng chóng', 数得着: 'shǔ de zháo', 傻劲儿: 'shǎ jìn er', 铅玻璃: 'qiān bō li', 可的松: 'kě dì sōng', 划得来: 'huá de lái', 晕乎乎: 'yūn hū hū', 屎壳郎: 'shǐ ke làng', 尥蹶子: 'liào juě zi', 藏红花: 'zàng hóng huā', 闷罐车: 'mèn guàn chē', 卡脖子: 'qiǎ bó zi', 红澄澄: 'hóng deng deng', 赶得及: 'gǎn de jí', 当间儿: 'dāng jiàn er', 露马脚: 'lòu mǎ jiǎo', 鸡内金: 'jī nèi jīn', 犯得上: 'fàn de shàng', 钉齿耙: 'dīng chǐ bà', 饱和点: 'bǎo hé diǎn', 龙爪槐: 'lóng zhǎo huái', 喝倒彩: 'hè dào cǎi', 定冠词: 'dìng guàn cí', 担担面: 'dàn dan miàn', 吃得住: 'chī de zhù', 爪尖儿: 'zhuǎ jiān er', 支着儿: 'zhī zhāo er', 折跟头: 'zhē gēn tou', 阴着儿: 'yīn zhāo er', 烟卷儿: 'yān juǎn er', 宣传弹: 'xuān chuán dàn', 信皮儿: 'xìn pí er', 弦切角: 'xián qiē jiǎo', 缩砂密: 'sù shā mì', 说得来: 'shuō de lái', 水漂儿: 'shuǐ piāo er', 耍笔杆: 'shuǎ bǐ gǎn', 数得上: 'shǔ de shàng', 数不着: 'shǔ bù zháo', 数不清: 'shǔ bù qīng', 什件儿: 'shí jiàn er', 生死簿: 'shēng sǐ bù', 扇风机: 'shān fēng jī', 撒呓挣: 'sā yì zheng', 日记簿: 'rì jì bù', 热得快: 'rè de kuài', 亲家公: 'qìng jia gōng', 奇函数: 'jī hán shù', 拍纸簿: 'pāi zhǐ bù', 努劲儿: 'nǔ jìn er', 泥娃娃: 'ní wá wa', 内切圆: 'nèi qiē yuán', 哪会儿: 'nǎ huì er', 闷头儿: 'mēn tóu er', 没谱儿: 'méi pǔ er', 铆劲儿: 'mǎo jìn er', 溜肩膀: 'liū jiān bǎng', 了望台: 'liào wàng tái', 老来少: 'lǎo lái shào', 坤角儿: 'kūn jué er', 考勤簿: 'kǎo qín bù', 卷笔刀: 'juǎn bǐ dāo', 进给量: 'jìn jǐ liàng', 划不来: 'huá bù lái', 汗褂儿: 'hàn guà er', 鼓囊囊: 'gǔ nāng nāng', 够劲儿: 'gòu jìn er', 公切线: 'gōng qiē xiàn', 搁得住: 'gé de zhù', 赶浪头: 'gǎn làng tóu', 赶得上: 'gǎn de shàng', 干酵母: 'gān jiào mǔ', 嘎渣儿: 'gā zhā er', 嘎嘣脆: 'gā bēng cuì', 对得住: 'duì de zhù', 逗闷子: 'dòu mèn zi', 顶呱呱: 'dǐng guā guā', 滴溜儿: 'dī liù er', 大轴子: 'dà zhòu zi', 打板子: 'dǎ bǎn zi', 寸劲儿: 'cùn jìn er', 醋劲儿: 'cù jìn er', 揣手儿: 'chuāi shǒu er', 冲劲儿: 'chòng jìn er', 吃得来: 'chī de lái', 不更事: 'bù gēng shì', 奔头儿: 'bèn tou er', 百夫长: 'bǎi fū zhǎng', 娃娃亲: 'wá wa qīn', 死劲儿: 'sǐ jìn er', 骨朵儿: 'gū duǒ er', 功劳簿: 'gōng láo bù', 都江堰: 'dū jiāng yàn', 一担水: 'yí dàn shuǐ', 否极泰: 'pǐ jí tài', 泰来否: 'tài lái pǐ', 咳特灵: 'ké tè líng', 开户行: 'kāi hù háng', 郦食其: 'lì yì jī', 花事了: 'huā shì liǎo', // 一字变调的词语(与两个字的字典冲突,故需要重新定义) 一更更: 'yì gēng gēng', 一重山: 'yì chóng shān', 风一更: 'fēng yì gēng', 雪一更: 'xuě yì gēng', 归一码: 'guī yì mǎ', // 一字不变调的词语(需要增补更多) 星期一: 'xīng qī yī', 礼拜一: 'lǐ bài yī', 一季度: 'yī jì dù', 一月一: 'yī yuè yī', 一字马: 'yī zì mǎ', 一是一: 'yī shì yī', 一次方: 'yī cì fāng', 一阳指: 'yī yáng zhǐ', 一字决: 'yī zì jué', 一年级: 'yī nián jí', 一不做: 'yī bú zuò', 屈戌儿: 'qū qu ér', 难为水: 'nán wéi shuǐ', 难为情: 'nán wéi qíng', 行一行: 'xíng yì háng', 别别的: 'biè bié de', 干哪行: 'gàn nǎ háng', 干一行: 'gàn yì háng', 曲别针: 'qū bié zhēn', }; const Pattern3 = Object.keys(DICT3).map((key) => ({ zh: key, pinyin: DICT3[key], probability: 2e-8 /* Probability.DICT */, length: 3, priority: _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__.Priority.Normal, dict: Symbol('dict3'), })); /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/data/dict4.mjs": /*!*********************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/data/dict4.mjs ***! \*********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Pattern4: function() { return /* binding */ Pattern4; }, /* harmony export */ "default": function() { return /* binding */ DICT4; } /* harmony export */ }); /* harmony import */ var _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common/constant.mjs */ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs"); const DICT4 = { 成吉思汗: "chéng jí sī hán", 四通八达: "sì tōng bā dá", 一模一样: "yì mú yí yàng", 青藏高原: "qīng zàng gāo yuán", 阿弥陀佛: "ē mí tuó fó", 解放思想: "jiè fàng sī xiǎng", 所作所为: "suǒ zuò suǒ wéi", 迷迷糊糊: "mí mí hu hū", 荷枪实弹: "hè qiāng shí dàn", 兴高采烈: "xìng gāo cǎi liè", 无能为力: "wú néng wéi lì", 布鲁塞尔: "bù lǔ sài ěr", 为所欲为: "wéi suǒ yù wéi", 克什米尔: "kè shí mǐ ěr", 没完没了: "méi wán méi liǎo", 不为人知: "bù wéi rén zhī", 结结巴巴: "jiē jiē bā bā", 前仆后继: "qián pū hòu jì", 铺天盖地: "pū tiān gài dì", 直截了当: "zhí jié liǎo dàng", 供不应求: "gōng bú yìng qiú", 御史大夫: "yù shǐ dà fū", 不为瓦全: "bù wéi wǎ quán", 不可收拾: "bù kě shōu shi", 胡作非为: "hú zuò fēi wéi", 分毫不差: "fēn háo bú chà", 模模糊糊: "mó mó hu hū", 不足为奇: "bù zú wéi qí", 悄无声息: "qiǎo wú shēng xī", 了如指掌: "liǎo rú zhǐ zhǎng", 深恶痛绝: "shēn wù tòng jué", 高高兴兴: "gāo gāo xìng xìng", 唉声叹气: "āi shēng tàn qì", 汉藏语系: "hàn zàng yǔ xì", 处心积虑: "chǔ xīn jī lǜ", 泣不成声: "qì bù chéng shēng", 半夜三更: "bàn yè sān gēng", 失魂落魄: "shī hún luò pò", 二十八宿: "èr shí bā xiù", 转来转去: "zhuàn lái zhuàn qù", 数以万计: "shǔ yǐ wàn jì", 相依为命: "xiāng yī wéi mìng", 恋恋不舍: "liàn liàn bù shě", 屈指可数: "qū zhǐ kě shǔ", 神出鬼没: "shén chū guǐ mò", 结结实实: "jiē jiē shí shí", 有的放矢: "yǒu dì fàng shǐ", 叽哩咕噜: "jī lǐ gū lū", 调兵遣将: "diào bīng qiǎn jiàng", 载歌载舞: "zài gē zài wǔ", 转危为安: "zhuǎn wēi wéi ān", 踏踏实实: "tā tā shi shí", 桑给巴尔: "sāng jǐ bā ěr", 装模作样: "zhuāng mú zuò yàng", 见义勇为: "jiàn yì yǒng wéi", 相差无几: "xiāng chā wú jǐ", 叹为观止: "tàn wéi guān zhǐ", 闷闷不乐: "mèn mèn bú lè", 喜怒哀乐: "xǐ nù āi lè", 鲜为人知: "xiǎn wéi rén zhī", 张牙舞爪: "zhāng yá wǔ zhǎo", 为非作歹: "wéi fēi zuò dǎi", 含糊其辞: "hán hú qí cí", 疲于奔命: "pí yú bēn mìng", 勉为其难: "miǎn wéi qí nán", 依依不舍: "yī yī bù shě", 顶头上司: "dǐng tóu shàng si", 不着边际: "bù zhuó biān jì", 大模大样: "dà mú dà yàng", 寻欢作乐: "xún huān zuò lè", 一走了之: "yì zǒu liǎo zhī", 字里行间: "zì lǐ háng jiān", 含含糊糊: "hán hán hu hū", 恰如其分: "qià rú qí fèn", 破涕为笑: "pò tì wéi xiào", 深更半夜: "shēn gēng bàn yè", 千差万别: "qiān chā wàn bié", 数不胜数: "shǔ bú shèng shǔ", 据为己有: "jù wéi jǐ yǒu", 天旋地转: "tiān xuán dì zhuàn", 养尊处优: "yǎng zūn chǔ yōu", 玻璃纤维: "bō li xiān wéi", 吵吵闹闹: "chāo chao nào nào", 晕头转向: "yūn tóu zhuàn xiàng", 土生土长: "tǔ shēng tǔ zhǎng", 宁死不屈: "nìng sǐ bù qū", 不省人事: "bù xǐng rén shì", 尽力而为: "jìn lì ér wéi", 精明强干: "jīng míng qiáng gàn", 唠唠叨叨: "láo lao dāo dāo", 叽叽喳喳: "jī ji zhā zhā", 功不可没: "gōng bù kě mò", 锲而不舍: "qiè ér bù shě", 排忧解难: "pái yōu jiě nàn", 稀里糊涂: "xī li hú tú", 各有所长: "gè yǒu suǒ cháng", 的的确确: "dí dí què què", 哄堂大笑: "hōng táng dà xiào", 听而不闻: "tīng ér bù wén", 刀耕火种: "dāo gēng huǒ zhòng", 内分泌腺: "nèi fèn mì xiàn", 化险为夷: "huà xiǎn wéi yí", 百发百中: "bǎi fā bǎi zhòng", 重见天日: "chóng jiàn tiān rì", 反败为胜: "fǎn bài wéi shèng", 一了百了: "yì liǎo bǎi liǎo", 大大咧咧: "dà da liē liē", 心急火燎: "xīn jí huǒ liǎo", 粗心大意: "cū xīn dà yi", 鸡皮疙瘩: "jī pí gē da", 夷为平地: "yí wéi píng dì", 日积月累: "rì jī yuè lěi", 设身处地: "shè shēn chǔ dì", 投其所好: "tóu qí suǒ hào", 间不容发: "jiān bù róng fà", 人满为患: "rén mǎn wéi huàn", 穷追不舍: "qióng zhuī bù shě", 为时已晚: "wéi shí yǐ wǎn", 如数家珍: "rú shǔ jiā zhēn", 心里有数: "xīn lǐ yǒu shù", 以牙还牙: "yǐ yá huán yá", 神不守舍: "shén bù shǒu shě", 孟什维克: "mèng shí wéi kè", 各自为战: "gè zì wéi zhàn", 怨声载道: "yuàn shēng zài dào", 救苦救难: "jiù kǔ jiù nàn", 好好先生: "hǎo hǎo xiān sheng", 怪模怪样: "guài mú guài yàng", 抛头露面: "pāo tóu lù miàn", 游手好闲: "yóu shǒu hào xián", 无所不为: "wú suǒ bù wéi", 调虎离山: "diào hǔ lí shān", 步步为营: "bù bù wéi yíng", 好大喜功: "hào dà xǐ gōng", 众矢之的: "zhòng shǐ zhī dì", 长生不死: "cháng shēng bù sǐ", 蔚为壮观: "wèi wéi zhuàng guān", 不可胜数: "bù kě shèng shǔ", 鬼使神差: "guǐ shǐ shén chāi", 洁身自好: "jié shēn zì hào", 敢作敢为: "gǎn zuò gǎn wéi", 茅塞顿开: "máo sè dùn kāi", 走马换将: "zǒu mǎ huàn jiàng", 为时过早: "wéi shí guò zǎo", 为人师表: "wéi rén shī biǎo", 阴差阳错: "yīn chā yáng cuò", 油腔滑调: "yóu qiāng huá diào", 重蹈覆辙: "chóng dǎo fù zhé", 骂骂咧咧: "mà ma liē liē", 絮絮叨叨: "xù xù dāo dāo", 如履薄冰: "rú lǚ bó bīng", 损兵折将: "sǔn bīng zhé jiàng", 拐弯抹角: "guǎi wān mò jiǎo", 像模像样: "xiàng mú xiàng yàng", 供过于求: "gōng guò yú qiú", 开花结果: "kāi huā jiē guǒ", 仔仔细细: "zǐ zǐ xì xì", 川藏公路: "chuān zàng gōng lù", 河北梆子: "hé běi bāng zi", 长年累月: "cháng nián lěi yuè", 正儿八经: "zhèng er bā jīng", 不识抬举: "bù shí tái ju", 重振旗鼓: "chóng zhèn qí gǔ", 气息奄奄: "qì xī yān yān", 紧追不舍: "jǐn zhuī bù shě", 服服帖帖: "fú fu tiē tiē", 强词夺理: "qiǎng cí duó lǐ", 噼里啪啦: "pī li pā lā", 人才济济: "rén cái jǐ jǐ", 发人深省: "fā rén shēn xǐng", 不足为凭: "bù zú wéi píng", 为富不仁: "wéi fù bù rén", 连篇累牍: "lián piān lěi dú", 呼天抢地: "hū tiān qiāng dì", 落落大方: "luò luò dà fāng", 自吹自擂: "zì chuī zì léi", 乐善好施: "lè shàn hào shī", 以攻为守: "yǐ gōng wéi shǒu", 磨磨蹭蹭: "mó mó cèng cèng", 削铁如泥: "xuē tiě rú ní", 助纣为虐: "zhù zhòu wéi nüè", 以退为进: "yǐ tuì wéi jìn", 嘁嘁喳喳: "qī qī chā chā", 枪林弹雨: "qiāng lín dàn yǔ", 令人发指: "lìng rén fà zhǐ", 转败为胜: "zhuǎn bài wéi shèng", 转弯抹角: "zhuǎn wān mò jiǎo", 在劫难逃: "zài jié nán táo", 正当防卫: "zhèng dàng fáng wèi", 不足为怪: "bù zú wéi guài", 难兄难弟: "nàn xiōng nàn dì", 咿咿呀呀: "yī yī yā yā", 弹尽粮绝: "dàn jìn liáng jué", 阿谀奉承: "ē yú fèng chéng", 稀里哗啦: "xī li huā lā", 返老还童: "fǎn lǎo huán tóng", 好高骛远: "hào gāo wù yuǎn", 鹿死谁手: "lù sǐ shéi shǒu", 差强人意: "chā qiáng rén yì", 大吹大擂: "dà chuī dà léi", 成家立业: "chéng jiā lì yè", 自怨自艾: "zì yuàn zì yì", 负债累累: "fù zhài lěi lěi", 古为今用: "gǔ wéi jīn yòng", 入土为安: "rù tǔ wéi ān", 下不为例: "xià bù wéi lì", 一哄而上: "yì hōng ér shàng", 没头苍蝇: "méi tóu cāng ying", 天差地远: "tiān chā dì yuǎn", 风卷残云: "fēng juǎn cán yún", 多灾多难: "duō zāi duō nàn", 乳臭未干: "rǔ xiù wèi gān", 行家里手: "háng jiā lǐ shǒu", 狼狈为奸: "láng bèi wéi jiān", 处变不惊: "chǔ biàn bù jīng", 一唱一和: "yí chàng yí hè", 一念之差: "yí niàn zhī chā", 金蝉脱壳: "jīn chán tuō qiào", 滴滴答答: "dī dī dā dā", 硕果累累: "shuò guǒ léi léi", 好整以暇: "hào zhěng yǐ xiá", 红得发紫: "hóng de fā zǐ", 传为美谈: "chuán wéi měi tán", 富商大贾: "fù shāng dà gǔ", 四海为家: "sì hǎi wéi jiā", 了若指掌: "liǎo ruò zhǐ zhǎng", 大有可为: "dà yǒu kě wéi", 出头露面: "chū tóu lù miàn", 鼓鼓囊囊: "gǔ gu nāng nāng", 窗明几净: "chuāng míng jī jìng", 泰然处之: "tài rán chǔ zhī", 怒发冲冠: "nù fà chōng guān", 有机玻璃: "yǒu jī bō li", 骨头架子: "gǔ tou jià zi", 义薄云天: "yì bó yún tiān", 一丁点儿: "yī dīng diǎn er", 时来运转: "shí lái yùn zhuǎn", 陈词滥调: "chén cí làn diào", 化整为零: "huà zhěng wéi líng", 火烧火燎: "huǒ shāo huǒ liǎo", 干脆利索: "gàn cuì lì suǒ", 吊儿郎当: "diào er láng dāng", 广种薄收: "guǎng zhòng bó shōu", 种瓜得瓜: "zhòng guā dé guā", 种豆得豆: "zhòng dòu dé dòu", 难舍难分: "nán shě nán fēn", 歃血为盟: "shà xuè wéi méng", 奋发有为: "fèn fā yǒu wéi", 阴错阳差: "yīn cuò yáng chā", 东躲西藏: "dōng duǒ xī cáng", 烟熏火燎: "yān xūn huǒ liǎo", 钻牛角尖: "zuān niú jiǎo jiān", 乔装打扮: "qiáo zhuāng dǎ bàn", 改弦更张: "gǎi xián gēng zhāng", 河南梆子: "hé nán bāng zi", 好吃懒做: "hào chī lǎn zuò", 何乐不为: "hé lè bù wéi", 大出风头: "dà chū fēng tóu", 攻城掠地: "gōng chéng lüè dì", 漂漂亮亮: "piào piào liang liang", 折衷主义: "zhé zhōng zhǔ yì", 大马哈鱼: "dà mǎ hǎ yú", 绿树成荫: "lǜ shù chéng yīn", 率先垂范: "shuài xiān chuí fàn", 家长里短: "jiā cháng lǐ duǎn", 宽大为怀: "kuān dà wéi huái", 左膀右臂: "zuǒ bǎng yòu bì", 一笑了之: "yí xiào liǎo zhī", 天下为公: "tiān xià wéi gōng", 还我河山: "huán wǒ hé shān", 何足为奇: "hé zú wéi qí", 好自为之: "hǎo zì wéi zhī", 风姿绰约: "fēng zī chuò yuē", 大雨滂沱: "dà yǔ pāng tuó", 传为佳话: "chuán wéi jiā huà", 吃里扒外: "chī lǐ pá wài", 重操旧业: "chóng cāo jiù yè", 小家子气: "xiǎo jiā zi qì", 少不更事: "shào bù gēng shì", 难分难舍: "nán fēn nán shě", 添砖加瓦: "tiān zhuān jiā wǎ", 是非分明: "shì fēi fēn míng", 舍我其谁: "shě wǒ qí shuí", 偏听偏信: "piān tīng piān xìn", 量入为出: "liàng rù wéi chū", 降龙伏虎: "xiáng lóng fú hǔ", 钢化玻璃: "gāng huà bō li", 正中下怀: "zhèng zhòng xià huái", 以身许国: "yǐ shēn xǔ guó", 一语中的: "yì yǔ zhòng dì", 丧魂落魄: "sàng hún luò pò", 三座大山: "sān zuò dà shān", 济济一堂: "jǐ jǐ yì táng", 好事之徒: "hào shì zhī tú", 干净利索: "gàn jìng lì suǒ", 出将入相: "chū jiàng rù xiàng", 袅袅娜娜: "niǎo niǎo nuó nuó", 狐狸尾巴: "hú li wěi ba", 好逸恶劳: "hào yì wù láo", 大而无当: "dà ér wú dàng", 打马虎眼: "dǎ mǎ hu yǎn", 板上钉钉: "bǎn shàng dìng dīng", 吆五喝六: "yāo wǔ hè liù", 虾兵蟹将: "xiā bīng xiè jiàng", 水调歌头: "shuǐ diào gē tóu", 数典忘祖: "shǔ diǎn wàng zǔ", 人事不省: "rén shì bù xǐng", 曲高和寡: "qǔ gāo hè guǎ", 屡教不改: "lǚ jiào bù gǎi", 互为因果: "hù wéi yīn guǒ", 互为表里: "hù wéi biǎo lǐ", 厚此薄彼: "hòu cǐ bó bǐ", 过关斩将: "guò guān zhǎn jiàng", 疙疙瘩瘩: "gē ge dā dā", 大腹便便: "dà fù pián pián", 走为上策: "zǒu wéi shàng cè", 冤家对头: "yuān jia duì tóu", 有隙可乘: "yǒu xì kě chèng", 一鳞半爪: "yì lín bàn zhǎo", 片言只语: "piàn yán zhǐ yǔ", 开花结实: "kāi huā jié shí", 经年累月: "jīng nián lěi yuè", 含糊其词: "hán hú qí cí", 寡廉鲜耻: "guǎ lián xiǎn chǐ", 成年累月: "chéng nián lěi yuè", 不徇私情: "bú xùn sī qíng", 不当人子: "bù dāng rén zǐ", 膀大腰圆: "bǎng dà yāo yuán", 指腹为婚: "zhǐ fù wéi hūn", 这么点儿: "zhè me diǎn er", 意兴索然: "yì xīng suǒ rán", 绣花枕头: "xiù huā zhěn tou", 无的放矢: "wú dì fàng shǐ", 望闻问切: "wàng wén wèn qiè", 舍己为人: "shě jǐ wèi rén", 穷年累月: "qióng nián lěi yuè", 排难解纷: "pái nàn jiě fēn", 处之泰然: "chǔ zhī tài rán", 指鹿为马: "zhǐ lù wéi mǎ", 危如累卵: "wēi rú lěi luǎn", 天兵天将: "tiān bīng tiān jiàng", 舍近求远: "shě jìn qiú yuǎn", 南腔北调: "nán qiāng běi diào", 苦中作乐: "kǔ zhōng zuò lè", 厚积薄发: "hòu jī bó fā", 臭味相投: "xiù wèi xiāng tóu", 长幼有序: "zhǎng yòu yǒu xù", 逼良为娼: "bī liáng wéi chāng", 悲悲切切: "bēi bēi qiè qiē", 败军之将: "bài jūn zhī jiàng", 欺行霸市: "qī háng bà shì", 削足适履: "xuē zú shì lǚ", 先睹为快: "xiān dǔ wéi kuài", 啼饥号寒: "tí jī háo hán", 疏不间亲: "shū bú jiàn qīn", 神差鬼使: "shén chāi guǐ shǐ", 敲敲打打: "qiāo qiāo dǎ dǎ", 平铺直叙: "píng pū zhí xù", 没头没尾: "méi tóu mò wěi", 寥寥可数: "liáo liáo kě shǔ", 哼哈二将: "hēng hā èr jiàng", 鹤发童颜: "hè fà tóng yán", 各奔前程: "gè bèn qián chéng", 弹无虚发: "dàn wú xū fā", 大人先生: "dà rén xiān sheng", 与民更始: "yǔ mín gēng shǐ", 树碑立传: "shù bēi lì zhuàn", 是非得失: "shì fēi dé shī", 实逼处此: "shí bī chǔ cǐ", 塞翁失马: "sài wēng shī mǎ", 日薄西山: "rì bó xī shān", 切身体会: "qiè shēn tǐ huì", 片言只字: "piàn yán zhǐ zì", 跑马卖解: "pǎo mǎ mài xiè", 宁折不弯: "nìng zhé bù wān", 零零散散: "líng líng sǎn sǎn", 量体裁衣: "liàng tǐ cái yī", 连中三元: "lián zhòng sān yuán", 礼崩乐坏: "lǐ bēng yuè huài", 不为已甚: "bù wéi yǐ shèn", 转悲为喜: "zhuǎn bēi wéi xǐ", 以眼还眼: "yǐ yǎn huán yǎn", 蔚为大观: "wèi wéi dà guān", 未为不可: "wèi wéi bù kě", 童颜鹤发: "tóng yán hè fà", 朋比为奸: "péng bǐ wéi jiān", 莫此为甚: "mò cǐ wéi shèn", 夹枪带棒: "jiā qiāng dài bàng", 富商巨贾: "fù shāng jù jiǎ", 淡然处之: "dàn rán chǔ zhī", 箪食壶浆: "dān shí hú jiāng", 创巨痛深: "chuāng jù tòng shēn", 草长莺飞: "cǎo zhǎng yīng fēi", 坐视不救: "zuò shī bú jiù", 以己度人: "yǐ jǐ duó rén", 随行就市: "suí háng jiù shì", 文以载道: "wén yǐ zài dào", 文不对题: "wén bú duì tí", 铁板钉钉: "tiě bǎn dìng dīng", 身体发肤: "shēn tǐ fà fū", 缺吃少穿: "quē chī shǎo chuān", 目无尊长: "mù wú zūn zhǎng", 吉人天相: "jí rén tiān xiàng", 毁家纾难: "huǐ jiā shū nàn", 钢筋铁骨: "gāng jīn tiě gǔ", 丢卒保车: "diū zú bǎo jū", 丢三落四: "diū sān là sì", 闭目塞听: "bì mù sè tīng", 削尖脑袋: "xuē jiān nǎo dài", 为非作恶: "wéi fēi zuò è", 人才难得: "rén cái nán dé", 情非得已: "qíng fēi dé yǐ", 切中要害: "qiè zhòng yào hài", 火急火燎: "huǒ jí huǒ liǎo", 画地为牢: "huà dì wéi láo", 好酒贪杯: "hào jiǔ tān bēi", 长歌当哭: "cháng gē dàng kū", 载沉载浮: "zài chén zài fú", 遇难呈祥: "yù nàn chéng xiáng", 榆木疙瘩: "yú mù gē da", 以邻为壑: "yǐ lín wéi hè", 洋为中用: "yáng wéi zhōng yòng", 言为心声: "yán wéi xīn shēng", 言必有中: "yán bì yǒu zhòng", 图穷匕见: "tú qióng bǐ xiàn", 滂沱大雨: "páng tuó dà yǔ", 目不暇给: "mù bù xiá jǐ", 量才录用: "liàng cái lù yòng", 教学相长: "jiào xué xiāng zhǎng", 悔不当初: "huǐ bù dāng chū", 呼幺喝六: "hū yāo hè liù", 不足为训: "bù zú wéi xùn", 不拘形迹: "bù jū xíng jī", 傍若无人: "páng ruò wú rén", 罪责难逃: "zuì zé nán táo", 自我吹嘘: "zì wǒ chuī xū", 转祸为福: "zhuǎn huò wéi fú", 勇冠三军: "yǒng guàn sān jūn", 易地而处: "yì dì ér chǔ", 卸磨杀驴: "xiè mò shā lǘ", 玩儿不转: "wán ér bú zhuàn", 天道好还: "tiān dào hǎo huán", 身单力薄: "shēn dān lì bó", 撒豆成兵: "sǎ dòu chéng bīng", 片纸只字: "piàn zhǐ zhī zì", 宁缺毋滥: "nìng quē wú làn", 没没无闻: "mò mò wú wén", 量力而为: "liàng lì ér wéi", 历历可数: "lì lì kě shǔ", 口碑载道: "kǒu bēi zài dào", 君子好逑: "jūn zǐ hǎo qiú", 好为人师: "hào wéi rén shī", 豪商巨贾: "háo shāng jù jiǎ", 各有所好: "gè yǒu suǒ hào", 度德量力: "duó dé liàng lì", 指天为誓: "zhǐ tiān wéi shì", 逸兴遄飞: "yì xìng chuán fēi", 心宽体胖: "xīn kuān tǐ pán", 为德不卒: "wéi dé bù zú", 天下为家: "tiān xià wéi jiā", 视为畏途: "shì wéi wèi tú", 三灾八难: "sān zāi bā nàn", 沐猴而冠: "mù hóu ér guàn", 哩哩啦啦: "lī li lā lā", 见缝就钻: "jiàn fèng jiù zuān", 夹层玻璃: "jiā céng bō li", 急公好义: "jí gōng hào yì", 积年累月: "jī nián lěi yuè", 划地为牢: "huá dì wéi láo", 更名改姓: "gēng míng gǎi xìng", 奉为圭臬: "fèng wéi guī niè", 多难兴邦: "duō nàn xīng bāng", 不破不立: "bú pò bú lì", 坐地自划: "zuò dì zì huá", 坐不重席: "zuò bù chóng xí", 坐不窥堂: "zuò bù kuī táng", 作嫁衣裳: "zuò jià yī shang", 左枝右梧: "zuǒ zhī yòu wú", 左宜右有: "zuǒ yí yòu yǒu", 钻头觅缝: "zuān tóu mì fèng", 钻天打洞: "zuān tiān dǎ dòng", 钻皮出羽: "zuān pí chū yǔ", 钻火得冰: "zuān huǒ dé bīng", 钻洞觅缝: "zuàn dòng mì féng", 钻冰求火: "zuān bīng qiú huǒ", 子为父隐: "zǐ wéi fù yǐn", 擢发难数: "zhuó fà nán shǔ", 着人先鞭: "zhuó rén xiān biān", 斫雕为朴: "zhuó diāo wéi pǔ", 锥处囊中: "zhuī chǔ náng zhōng", 椎心饮泣: "chuí xīn yǐn qì", 椎心泣血: "chuí xīn qì xuè", 椎牛飨士: "chuí niú xiǎng shì", 椎牛歃血: "chuí niú shà xuè", 椎牛发冢: "chuí niú fà zhǒng", 椎埋屠狗: "chuí mái tú gǒu", 椎埋狗窃: "chuí mái gǒu qiè", 壮发冲冠: "zhuàng fā chōng guàn", 庄严宝相: "zhuāng yán bǎo xiàng", 转愁为喜: "zhuǎn chóu wéi xǐ", 转嗔为喜: "zhuǎn chēn wéi xǐ", 拽巷啰街: "zhuài xiàng luó jiē", 拽耙扶犁: "zhuāi pá fú lí", 拽布拖麻: "zhuài bù tuō má", 箸长碗短: "zhù cháng wǎn duǎn", 铸剑为犁: "zhù jiàn wéi lí", 杼柚其空: "zhù yòu qí kōng", 杼柚空虚: "zhù yòu kōng xū", 助天为虐: "zhù tiān wéi nüè", 属垣有耳: "zhǔ yuán yǒu ěr", 属毛离里: "zhǔ máo lí lǐ", 属辞比事: "zhǔ cí bǐ shì", 逐物不还: "zhú wù bù huán", 铢量寸度: "zhū liáng cùn duó", 铢两悉称: "zhū liǎng xī chèn", 侏儒观戏: "zhū rú guān xì", 朱轓皁盖: "zhū fān zào gài", 昼度夜思: "zhòu duó yè sī", 诪张为幻: "zhōu zhāng wéi huàn", 重明继焰: "chóng míng jì yàn", 众啄同音: "zhòng zhuó tóng yīn", 众毛攒裘: "zhòng máo cuán qiú", 众好众恶: "zhòng hào zhòng wù", 擿埴索涂: "zhāi zhí suǒ tú", 稚齿婑媠: "zhì chǐ wǒ tuó", 至当不易: "zhì dàng bú yì", 指皂为白: "zhǐ zào wéi bái", 指雁为羹: "zhǐ yàn wéi gēng", 指树为姓: "zhǐ shù wéi xìng", 指山说磨: "zhǐ shān shuō mò", 止戈为武: "zhǐ gē wéi wǔ", 枝干相持: "zhī gàn xiāng chí", 枝大于本: "zh dà yú běn", 支吾其词: "zhī wú qí cí", 正身率下: "zhèng shēn shuài xià", 正冠李下: "zhèng guàn lǐ xià", 整冠纳履: "zhěng guān nà lǚ", 整躬率物: "zhěng gōng shuài wù", 整顿干坤: "zhěng dùn gàn kūn", 针头削铁: "zhēn tóu xuē tiě", 贞松劲柏: "zhēn sōng jìng bǎi", 赭衣塞路: "zhě yī sè lù", 折箭为誓: "shé jiàn wéi shì", 折而族之: "zhé ér zú zhī", 昭德塞违: "zhāo dé sè wéi", 章句小儒: "zhāng jù xiǎo rú", 湛恩汪濊: "zhàn ēn wāng huì", 占风望气: "zhān fēng wàng qì", 斩将搴旗: "zhǎn jiàng qiān qí", 曾母投杼: "zēng mǔ tóu zhù", 曾参杀人: "zēng shēn shā rén", 造谣中伤: "zào yáo zhòng shāng", 早占勿药: "zǎo zhān wù yào", 凿龟数策: "záo guī shǔ cè", 攒三聚五: "cuán sān jù wǔ", 攒眉蹙额: "cuán mei cù é", 攒零合整: "cuán líng hé zhěng", 攒锋聚镝: "cuán fēng jù dí", 载笑载言: "zài xiào zài yán", 载酒问字: "zài jiǔ wèn zì", 殒身不恤: "yǔn shēn bú xù", 云舒霞卷: "yún shū xiá juǎn", 月中折桂: "yuè zhōng shé guì", 月落参横: "yuè luò shēn héng", 鬻驽窃价: "yù nú qiè jià", 鬻鸡为凤: "yù jī wéi fèng", 遇难成祥: "yù nàn chéng xiáng", 郁郁累累: "yù yù lěi lěi", 玉卮无当: "yù zhī wú dàng", 语笑喧阗: "yǔ xiào xuān tián", 与世沉浮: "yǔ shì chén fú", 与时消息: "yǔ shí xiāo xi", 逾墙钻隙: "yú qiáng zuān xì", 渔夺侵牟: "yú duó qīn móu", 杅穿皮蠹: "yú chuān pí dù", 余勇可贾: "yú yǒng kě gǔ", 予智予雄: "yú zhì yú xióng", 予取予求: "yú qǔ yú qiú", 于家为国: "yú jiā wéi guó", 有借无还: "yǒu jiè wú huán", 有加无已: "yǒu jiā wú yǐ", 有国难投: "yǒu guó nán tóu", 游必有方: "yóu bì yǒu fāng", 油干灯尽: "yóu gàn dēng jìn", 尤云殢雨: "yóu yún tì yǔ", 庸中皦皦: "yōng zhōng jiǎo jiǎo", 郢书燕说: "yǐng shū yān shuō", 营蝇斐锦: "yíng yíng fēi jǐn", 鹰心雁爪: "yīng xīn yàn zhǎo", 莺吟燕儛: "yīng yín yàn wǔ", 应天顺时: "yīng tiān shùn shí", 印累绶若: "yìn léi shòu ruò", 隐占身体: "yǐn zhàn shēn tǐ", 饮犊上流: "yìn dú shàng liú", 引绳切墨: "yǐn shéng qiē mò", 龈齿弹舌: "yín chǐ dàn shé", 因缘为市: "yīn yuán wéi shì", 因树为屋: "yīn shù wéi wū", 溢美溢恶: "yì měi yì wù", 抑塞磊落: "yì sè lěi luò", 倚闾望切: "yǐ lǘ wàng qiē", 以意为之: "yǐ yì wéi zhī", 以言为讳: "yǐ yán wéi huì", 以疏间亲: "yǐ shū jiàn qīn", 以水济水: "yǐ shuǐ jǐ shuǐ", 以书为御: "yǐ shū wéi yù", 以守为攻: "yǐ shǒu wéi gōng", 以升量石: "yǐ shēng liáng dàn", 以慎为键: "yǐ shèn wéi jiàn", 以筌为鱼: "yǐ quán wéi yú", 以利累形: "yǐ lì lěi xíng", 以毁为罚: "yǐ huǐ wéi fá", 以黑为白: "yǐ hēi wéi bái", 以规为瑱: "yǐ guī wéi tiàn", 以古为鉴: "yǐ gǔ wéi jiàn", 以宫笑角: "yǐ gōng xiào jué", 以法为教: "yǐ fǎ wéi jiào", 以大恶细: "yǐ dà wù xì", 遗世忘累: "yí shì wàng lěi", 遗寝载怀: "yí qǐn zài huái", 移的就箭: "yí dì jiù jiàn", 依头缕当: "yī tóu lǚ dàng", 衣租食税: "yì zū shí shuì", 衣轻乘肥: "yì qīng chéng féi", 衣裳之会: "yī shang zhī huì", 衣单食薄: "yī dān shí bó", 一还一报: "yì huán yí bào", 叶公好龙: "yè gōng hào lóng", 野调无腔: "yě diào wú qiāng", 瑶池女使: "yáo chí nǚ shǐ", 幺麽小丑: "yāo mó xiǎo chǒu", 养精畜锐: "yǎng jīng xù ruì", 卬首信眉: "áng shǒu shēn méi", 洋洋纚纚: "yáng yáng sǎ sǎ", 羊羔美酒: "yáng gāo měi jiǔ", 扬风扢雅: "yáng fēng jié yǎ", 燕昭市骏: "yān zhāo shì jùn", 燕昭好马: "yān zhāo hǎo mǎ", 燕石妄珍: "yān shí wàng zhēn", 燕骏千金: "yān jùn qiān jīn", 燕金募秀: "yān jīn mù xiù", 燕驾越毂: "yān jià yuè gǔ", 燕歌赵舞: "yān gē zhào wǔ", 燕岱之石: "yān dài zhī shí", 燕处危巢: "yàn chǔ wēi cháo", 掞藻飞声: "shàn zǎo fēi shēng", 偃革为轩: "yǎn gé wéi xuān", 妍蚩好恶: "yán chī hǎo è", 压良为贱: "yā liáng wéi jiàn", 搀行夺市: "chān háng duó shì", 泣数行下: "qì shù háng xià", 当行出色: "dāng háng chū sè", 秀出班行: "xiù chū bān háng", 儿女成行: "ér nǚ chéng háng", 大行大市: "dà háng dà shì", 寻行数墨: "xún háng shǔ mò", 埙篪相和: "xūn chí xiāng hè", 血债累累: "xuè zhài lěi lěi", 炫玉贾石: "xuàn yù gǔ shí", 炫石为玉: "xuàn shí wéi yù", 悬石程书: "xuán dàn chéng shū", 悬狟素飡: "xuán huán sù cān", 悬龟系鱼: "xuán guī xì yú", 揎拳捋袖: "xuān quán luō xiù", 轩鹤冠猴: "xuān hè guàn hóu", 畜妻养子: "xù qī yǎng zǐ", 羞人答答: "xiū rén dā dā", 修鳞养爪: "xiū lín yǎng zhǎo", 熊据虎跱: "xióng jù hǔ zhì", 兄死弟及: "xiōng sǐ dì jí", 腥闻在上: "xīng wén zài shàng", 兴文匽武: "xīng wén yǎn wǔ", 兴观群怨: "xìng guān qún yuàn", 兴高彩烈: "xìng gāo cǎi liè", 心手相应: "xīn shǒu xiāng yìng", 心口相应: "xīn kǒu xiāng yīng", 挟势弄权: "xié shì nòng quán", 胁肩累足: "xié jiān lěi zú", 校短量长: "jiào duǎn liáng cháng", 小眼薄皮: "xiǎo yǎn bó pí", 硝云弹雨: "xiāo yún dàn yǔ", 鸮鸣鼠暴: "xiāo míng shǔ bào", 削株掘根: "xuē zhū jué gēn", 削铁无声: "xuē tiě wú shēng", 削职为民: "xuē zhí wéi mín", 削木为吏: "xuē mù wéi lì", 想望风褱: "xiǎng wàng fēng huái", 香培玉琢: "xiang pei yu zhuó", 相鼠有皮: "xiàng shǔ yǒu pí", 相时而动: "xiàng shí ér dòng", 相切相磋: "xiāng qiē xiāng cuō", 相女配夫: "xiàng nǚ pèi fū", 相门有相: "xiàng mén yǒu xiàng", 挦章撦句: "xián zhāng chě jù", 先我着鞭: "xiān wǒ zhuó biān", 习焉不察: "xí yān bù chá", 歙漆阿胶: "shè qī ē jiāo", 晰毛辨发: "xī máo biàn fà", 悉索薄赋: "xī suǒ bó fù", 雾鳞云爪: "wù lín yún zhǎo", 物稀为贵: "wù xī wéi guì", 碔砆混玉: "wǔ fū hùn yù", 武断专横: "wǔ duàn zhuān héng", 五石六鹢: "wǔ shí liù yì", 五色相宣: "wǔ sè xiāng xuān", 五侯七贵: "wǔ hóu qī guì", 五侯蜡烛: "wǔ hòu là zhú", 五羖大夫: "wǔ gǔ dà fū", 吾自有处: "wú zì yǒu chǔ", 无下箸处: "wú xià zhù chǔ", 无伤无臭: "wú shāng wú xiù", 无能为役: "wú néng wéi yì", 无寇暴死: "wú kòu bào sǐ", 无孔不钻: "wú kǒng bú zuàn", 无间可乘: "wú jiān kě chéng", 无间冬夏: "wú jiān dōng xià", 无恶不为: "wú è bù wéi", 无动为大: "wú dòng wéi dà", 诬良为盗: "wū liáng wéi dào", 握拳透爪: "wò quán tòu zhǎo", 文武差事: "wén wǔ chāi shì", 委委佗佗: "wēi wēi tuó tuó", 惟日为岁: "wéi rì wéi suì", 帷薄不修: "wéi bó bù xiū", 为善最乐: "wéi shàn zuì lè", 为山止篑: "wéi shān zhǐ kuì", 为仁不富: "wéi rén bú fù", 为裘为箕: "wéi qiú wéi jī", 为民父母: "wéi mín fù mǔ", 为虺弗摧: "wéi huǐ fú cuī", 为好成歉: "wéi hǎo chéng qiàn", 为鬼为蜮: "wéi guǐ wéi yù", 望风响应: "wàng fēng xiǎng yīng", 望尘僄声: "wàng chén piào shēng", 往渚还汀: "wǎng zhǔ huán tīng", 王贡弹冠: "wáng gòng dàn guàn", 亡国大夫: "wáng guó dà fū", 万贯家私: "wàn guàn jiā sī", 晚食当肉: "wǎn shí dàng ròu", 晚节不保: "wǎn jié bù bǎo", 玩岁愒时: "wán suì kài shí", 蛙蟆胜负: "wā má shèng fù", 吞言咽理: "tūn yán yàn lǐ", 颓垣断堑: "tuí yuán duàn qiàn", 推干就湿: "tuī gàn jiù shī", 剸繁决剧: "tuán fán jué jù", 团头聚面: "tuán tóu jù miàn", 兔丝燕麦: "tù sī yàn mài", 兔头麞脑: "tù tóu zhāng nǎo", 兔葵燕麦: "tù kuí yàn mài", 吐哺握发: "tǔ bǔ wò fà", 投传而去: "tóu zhuàn ér qù", 头没杯案: "tóu mò bēi àn", 头昏脑闷: "tóu hūn nǎo mèn", 头会箕敛: "tóu kuài jī liǎn", 头出头没: "tóu chū tóu mò", 痛自创艾: "tòng zì chuāng yì", 同恶相助: "tóng wù xiāng zhù", 同恶相恤: "tóng wù xiāng xù", 痌瘝在抱: "tōng guān zài bào", 通文调武: "tōng wén diào wǔ", 停留长智: "tíng liú zhǎng zhì", 铁树开华: "tiě shù kāi huā", 条贯部分: "tiáo guàn bù fēn", 挑牙料唇: "tiǎo yá liào chún", 挑么挑六: "tiāo yāo tiāo liù", 挑唇料嘴: "tiǎo chún liào zuǐ", 恬不为意: "tián bù wéi yì", 恬不为怪: "tián bù wéi guài", 天下为笼: "tiān xià wéi lóng", 天台路迷: "tiān tái lù mí", 天年不遂: "tiān nián bú suì", 探囊胠箧: "tàn náng qū qiè", 谭言微中: "tán yán wēi zhòng", 谈言微中: "tán yán wēi zhòng", 狧穅及米: "shì kāng jí mǐ", 随物应机: "suí wù yīng jī", 搜岩采干: "sōu yán cǎi gàn", 宋斤鲁削: "sòng jīn lǔ xuē", 松筠之节: "sōng yún zhī jié", 四亭八当: "sì tíng bā dàng", 四马攒蹄: "sì mǎ cuán tí", 四不拗六: "sì bú niù liù", 思所逐之: "sī suǒ zhú zhī", 丝恩发怨: "sī ēn fà yuàn", 硕望宿德: "shuò wàng xiǔ dé", 铄古切今: "shuò gǔ qiē jīn", 顺风而呼: "shùn fēng ér hū", 顺风吹火: "shùn fēng chuī huǒ", 水中著盐: "shuǐ zhōng zhuó yán", 双柑斗酒: "shuāng gān dǒu jiǔ", 数米而炊: "shǔ mǐ ér chuī", 数米量柴: "shǔ mǐ liáng chái", 数理逻辑: "shù lǐ luó ji", 数黑论黄: "shǔ hēi lùn huáng", 数白论黄: "shǔ bái lùn huáng", 束缊还妇: "shù yūn huán fù", 束蒲为脯: "shù pú wéi pú", 束椽为柱: "shù chuán wéi zhù", 书缺有间: "shū quē yǒu jiàn", 手足重茧: "shǒu zú chóng jiǎn", 手足异处: "shǒu zú yì chǔ", 手脚干净: "shǒu jiǎo gàn jìng", 手不应心: "shǒu bù yīng xīn", 螫手解腕: "shì shǒu jiě wàn", 释知遗形: "shì zhī yí xíng", 适时应务: "shì shí yīng wù", 适情率意: "shì qíng shuài yì", 适当其冲: "shì dāng qí chōng", 视为知己: "shì wéi zhī jǐ", 使羊将狼: "shǐ yáng jiàng láng", 食为民天: "shí wéi mín tiān", 拾掇无遗: "shí duō wú yí", 实与有力: "shí yù yǒu lì", 石英玻璃: "shí yīng bō li", 石室金匮: "shí shì jīn guì", 什袭珍藏: "shí xí zhēn cáng", 什伍东西: "shí wǔ dōng xī", 什围伍攻: "shí wéi wǔ gōng", 十魔九难: "shí mó jiǔ nàn", 诗书发冢: "shī shū fà zhǒng", 虱处裈中: "shī chǔ kūn zhōng", 师直为壮: "shī zhí wéi zhuàng", 尸居龙见: "shī jū lóng xiàn", 圣经贤传: "shèng jīng xián zhuàn", 圣君贤相: "shèng jūn xián xiàng", 生拖死拽: "shēng tuō sǐ zhuài", 审己度人: "shěn jǐ duó rén", 神武挂冠: "shén wǔ guà guàn", 神龙失埶: "shén lóng shī shì", 深文曲折: "shēn wén qǔ shé", 深厉浅揭: "shēn lì qiǎn qì", 深谷为陵: "shēn gǔ wéi líng", 深恶痛疾: "shēn wù tòng jí", 深仇宿怨: "shēn chóu xiǔ yuàn", 舍己为公: "shě jǐ wèi gōng", 舍短取长: "shě duǎn qǔ cháng", 舍策追羊: "shě cè zhuī yáng", 蛇蝎为心: "shé xiē wéi xīn", 少成若性: "shào chéng ruò xìng", 上当学乖: "shàng dàng xué guāi", 赏不当功: "shǎng bù dāng gōng", 善自为谋: "shàn zì wéi móu", 善为说辞: "shàn wéi shuō cí", 善善恶恶: "shàn shàn wù è", 善财难舍: "shàn cái nán shě", 苫眼铺眉: "shān yǎn pū méi", 讪牙闲嗑: "shàn yá xián kē", 山阴乘兴: "shān yīn chéng xīng", 山殽野湋: "shān yáo yě wéi", 山溜穿石: "shān liù chuān shí", 山节藻棁: "shān jié zǎo zhuō", 杀鸡为黍: "shā jī wéi shǔ", 色厉胆薄: "sè lì dǎn bó", 桑荫未移: "sāng yīn wèi yí", 桑荫不徙: "sāng yīn bù xǐ", 桑土绸缪: "sāng tǔ chóu miù", 桑户棬枢: "sāng hù juàn shū", 三战三北: "sān zhàn sān běi", 三瓦两舍: "sān wǎ liǎng shě", 三人为众: "sān rén wèi zhòng", 三差两错: "sān chā liǎng cuò", 塞井焚舍: "sāi jǐng fén shě", 洒心更始: "sǎ xīn gèng shǐ", 洒扫应对: "sǎ sǎo yìng duì", 软红香土: "ruǎn hóng xiāng tǔ", 入吾彀中: "rù wú gòu zhōng", 入铁主簿: "rù tiě zhǔ bù", 入理切情: "rù lǐ qiē qíng", 汝成人耶: "rǔ chéng rén yé", 如水投石: "rú shuǐ tóu shí", 如切如磋: "rú qiē rú cuō", 如登春台: "rú dēng chūn tái", 肉薄骨并: "ròu bó gǔ bìng", 柔情绰态: "róu qíng chuò tài", 戎马劻勷: "róng mǎ kuāng ráng", 日中为市: "rì zhōng wéi shì", 日月参辰: "rì yuè shēn chén", 日省月修: "rì xǐng yuè xiū", 日削月割: "rì xuē yuè gē", 日省月试: "rì xǐng yuè shì", 任达不拘: "rèn dá bù jū", 人言藉藉: "rén yán jí jí", 人模狗样: "rén mú gǒu yàng", 人莫予毒: "rén mò yú dú", 热熬翻饼: "rè áo fān bǐng", 圈牢养物: "juàn láo yǎng wù", 取予有节: "qǔ yǔ yǒu jié", 诎要桡腘: "qū yāo ráo guó", 穷形尽相: "qióng xíng jìn xiàng", 情凄意切: "qíng qī yì qiè", 情见势屈: "qíng xiàn shì qū", 情见乎辞: "qíng xiàn hū cí", 清都绛阙: "qīng dōu jiàng què", 倾肠倒肚: "qīng cháng dào dǔ", 青紫被体: "qīng zǐ pī tǐ", 青林黑塞: "qīng lín hēi sài", 螓首蛾眉: "qín shǒu é méi", 琴瑟之好: "qín sè zhī hào", 且住为佳: "qiě zhù wéi jiā", 切树倒根: "qiē shù dǎo gēn", 切理餍心: "qiē lǐ yàn xīn", 切近的当: "qiē jìn de dāng", 翘足引领: "qiáo zú yǐn lǐng", 巧发奇中: "qiǎo fā qí zhòng", 强嘴拗舌: "jiàng zuǐ niù shé", 强直自遂: "qiáng zhí zì suí", 强死强活: "qiǎng sǐ qiǎng huó", 强食自爱: "qiǎng shí zì ài", 强食靡角: "qiǎng shí mí jiǎo", 强弓劲弩: "qiáng gōng jìng nǔ", 强聒不舍: "qiǎng guō bù shě", 强凫变鹤: "qiáng fú biàn hè", 强而后可: "qiǎng ér hòu kě", 强得易贫: "qiǎng dé yì pín", 遣兴陶情: "qiǎn xìng táo qíng", 牵羊担酒: "qiān yáng dān jiǔ", 千了百当: "qiān liǎo bǎi dàng", 泣下如雨: "qì xià rú yǔ", 起偃为竖: "qǐ yǎn wéi shù", 岂弟君子: "kǎi tì jūn zǐ", 綦溪利跂: "qí xī lì qí", 棋输先著: "qí shū xiān zhuó", 齐王舍牛: "qí wáng shě niú", 欺天诳地: "qī tiān kuáng dì", 普天率土: "pǔ tiān shuài tǔ", 铺胸纳地: "pū xiōng nà dì", 铺锦列绣: "pū jǐn liè xiù", 破家为国: "pò jiā wèi guó", 破觚为圜: "pò gū wéi yuán", 萍飘蓬转: "píng piāo péng zhuàn", 帡天极地: "píng tiān jí dì", 屏声息气: "bǐng shēng xī qì", 凭几据杖: "píng jī jù zhàng", 贫嘴薄舌: "pín zuǐ bó shé", 片语只辞: "piàn yǔ zhī cí", 披发文身: "pī fà wén shēn", 烹龙炮凤: "pēng lóng páo fèng", 炰鳖脍鲤: "fǒu biē kuài lǐ", 庞眉皓发: "páng méi hào fà", 攀花折柳: "pān huā zhé liǔ", 攀蟾折桂: "pān chán shé guì", 女大难留: "nǚ dà nán liú", 弄玉吹箫: "nòng yù chuī xiāo", 弄管调弦: "nòng guǎn tiáo xián", 弄粉调朱: "nòng fěn diào zhū", 浓抹淡妆: "nóng mò dàn zhuāng", 捻土为香: "niǎn tǔ wéi xiāng", 年谊世好: "nián yì shì hǎo", 年华垂暮: "nián huá chuí mù", 儗不于伦: "nǐ bù yú lún", 泥而不滓: "ní ér bù zǐ", 能者为师: "néng zhě wéi shī", 能不称官: "néng bú chèn guān", 挠直为曲: "náo zhí wéi qū", 难进易退: "nán jìn yì tuì", 难得糊涂: "nán dé hú tú", 南蛮鴂舌: "nán mán jué shé", 南贩北贾: "nán fàn běi gǔ", 牧猪奴戏: "mù zhū nú xì", 目眢心忳: "mù yuān xīn tún", 目挑心招: "mù tiǎo xīn zhāo", 目量意营: "mù liàng yì yíng", 木头木脑: "mù tóu mù nǎo", 木干鸟栖: "mù gàn niǎo qī", 侔色揣称: "móu sè chuǎi chèn", 莫予毒也: "mò yú dú yě", 抹粉施脂: "mò fěn shī zhī", 磨砻镌切: "mó lóng juān qiē", 磨棱刓角: "mó léng wán jiǎo", 摸门不着: "mō mén bù zháo", 摸不着边: "mō bù zhuó biān", 命中注定: "mìng zhōng zhù dìng", 鸣鹤之应: "míng hè zhī yìng", 明效大验: "míng xiào dà yàn", 名我固当: "míng wǒ gù dāng", 邈处欿视: "miǎo chǔ kǎn shì", 黾穴鸲巢: "měng xué qú cháo", 绵里薄材: "mián lǐ bó cái", 靡有孑遗: "mǐ yǒu jié yí", 靡衣偷食: "mǐ yī tōu shí", 迷恋骸骨: "mí liàn hái gǔ", 扪参历井: "mén shēn lì jǐng", 门单户薄: "mén dān hù bó", 昧旦晨兴: "mèi dàn chén xīng", 冒名接脚: "mào míng jiē jiǎo", 毛遂堕井: "máo suí duò jǐng", 毛发倒竖: "máo fā dǎo shù", 卖文为生: "mài wén wéi shēng", 卖李钻核: "mài lǐ zuān hé", 买椟还珠: "mǎi dú huán zhū", 埋三怨四: "mán sān yuàn sì", 马入华山: "mǎ rù huá shān", 落魄江湖: "luò pò jiāng hú", 落落难合: "luò luò nán hé", 落草为寇: "luò cǎo wéi kòu", 罗织构陷: "luó zhī gòu xiàn", 鸾凤和鸣: "luán fèng hè míng", 率由旧章: "shuài yóu jiù zhāng", 率土同庆: "shuài tǔ tóng qìng", 率兽食人: "shuài shòu shí rén", 率土归心: "shuài tǔ guī xīn", 率马以骥: "shuài mǎ yǐ jì", 率尔成章: "shuài ěr chéng zhāng", 鲁斤燕削: "lǔ jīn yàn xuē", 漏尽更阑: "lòu jìn gēng lán", 笼鸟槛猿: "lóng niǎo jiàn yuán", 笼鸟池鱼: "lóng niǎo chí yú", 龙游曲沼: "lóng yóu qū zhǎo", 龙血玄黄: "lóng xuè xuán huáng", 龙雕凤咀: "lóng diāo fèng jǔ", 六尺之讬: "liù chǐ zhī tuō", 令原之戚: "líng yuán zhī qī", 令人捧腹: "lìng rén pěng fù", 陵劲淬砺: "líng jìng cuì lì", 临敌易将: "lín dí yì jiàng", 裂裳衣疮: "liè shang yī chuāng", 裂冠毁冕: "liè guàn huǐ miǎn", 了无惧色: "liǎo wú jù sè", 了身达命: "liǎo shēn dá mìng", 了然无闻: "liǎo rán wú wén", 了不可见: "liǎo bù kě jiàn", 了不长进: "liǎo bù zhǎng jìn", 燎发摧枯: "liǎo fà cuī kū", 审时度势: "shěn shí duó shì", 量小力微: "liàng xiǎo lì wēi", 相时度力: "xiāng shí duó lì", 量枘制凿: "liàng ruì zhì záo", 量如江海: "liàng rú jiāng hǎi", 量金买赋: "liàng jīn mǎi fù", 量己审分: "liàng jǐ shěn fēn", 敛骨吹魂: "liǎn gǔ chuī hún", 詈夷为跖: "lì yí wéi zhí", 利令志惛: "lì lìng zhì hūn", 李广不侯: "lǐ guǎng bú hòu", 礼为情貌: "lǐ wéi qíng mào", 礼让为国: "lǐ ràng wéi guó", 犁生骍角: "lí shēng xīng jiǎo", 离本徼末: "lí běn jiǎo mò", 楞眉横眼: "léng méi hèng yǎn", 擂天倒地: "léi tiān dǎo dì", 累足成步: "lěi zú chéng bù", 累瓦结绳: "lěi wǎ jié shéng", 累土至山: "lěi tǔ zhì shān", 累土聚沙: "lěi tǔ jù shā", 累卵之危: "lěi luǎn zhī wēi", 累累如珠: "lěi lěi rú zhū", 累块积苏: "lěi kuài jī sū", 乐山乐水: "lè shān lè shuǐ", 潦原浸天: "lǎo yuán jìn tiān", 老师宿儒: "lǎo shī xiǔ rú", 牢什古子: "láo shí gǔ zi", 琅嬛福地: "láng huán fú dì", 揆情度理: "kuí qíng duó lǐ", 旷日累时: "kuàng rì lěi shí", 匡救弥缝: "kuāng jiù mí fèng", 枯树生华: "kū shù shēng huā", 口轻舌薄: "kǒu qīng shé bó", 口角生风: "kǒu jiǎo shēng fēng", 口角春风: "kǒu jiǎo chūn fēng", 口角风情: "kǒu jiǎo fēng qíng", 口干舌焦: "kǒu gān shé jiāo", 口腹之累: "kǒu fù zhī lěi", 空腹便便: "kōng fù pián pián", 嗑牙料嘴: "kē yá liào zuǐ", 刻木为鹄: "kè mù wéi hú", 咳珠唾玉: "ké zhū tuò yù", 咳唾成珠: "ké tuò chéng zhū", 抗颜为师: "kàng yán wéi shī", 开华结果: "kāi huā jié guǒ", 峻阪盐车: "jùn bǎn yán chē", 嚼铁咀金: "jiáo tiě jǔ jīn", 嚼墨喷纸: "jué mò pēn zhǐ", 倔头强脑: "juè tóu jiàng nǎo", 倔头倔脑: "juè tóu juè nǎo", 倦鸟知还: "juàn niǎo zhī huán", 卷席而葬: "juǎn xí ér zàng", 卷甲倍道: "juǎn jiǎ bèi dào", 聚米为山: "jù mǐ wéi shān", 举手相庆: "jǔ shǒu xiāng qìng", 举世混浊: "jǔ shì hún zhuó", 鞠为茂草: "jū wéi mào cǎo", 拘神遣将: "jū shén qiǎn jiàng", 居下讪上: "jū xià shàn shàng", 久要不忘: "jiǔ yāo bú wàng", 九转功成: "jiǔ zhuǎn gōng chéng", 九蒸三熯: "jiǔ zhēng sān hàn", 敬业乐群: "jìng yè lè qún", 井底虾蟆: "jǐng dǐ xiā má", 旌旗卷舒: "jīng qí juǎn shū", 荆棘载途: "jīng jí zài tú", 禁舍开塞: "jìn shě kāi sāi", 祲威盛容: "jìn wēi shèng róng", 进退消长: "jìn tuì xiāo cháng", 进退应矩: "jìn tuì yīng jǔ", 进退触籓: "jìn tuì chù fān", 进退跋疐: "jìn tuì bá zhì", 尽多尽少: "jǐn duō jǐn shǎo", 锦囊还矢: "jǐn náng huán shǐ", 矜己自饰: "jīn jǐ zì shì", 矜功负气: "jīn gōng fù qì", 津关险塞: "jīn guān xiǎn sài", 金吾不禁: "jīn wú bú jìn", 金翅擘海: "jīn chì bāi hǎi", 解衣衣人: "jiě yī yī rén", 解人难得: "jiě rén nán dé", 解铃系铃: "jiě líng xì líng", 解发佯狂: "jiě fà yáng kuáng", 诘屈磝碻: "jié qū áo qiāo", 教猱升木: "jiāo náo shēng mù", 较瘦量肥: "jiào shòu liàng féi", 角立杰出: "jiǎo lì jié chū", 焦沙烂石: "jiāo shā làn shí", 骄儿騃女: "jiāo ér sì nǚ", 浇风薄俗: "jiāo fēng bó sú", 降妖捉怪: "xiáng yāo zhuō guài", 将取固予: "jiāng qǔ gù yǔ", 将门有将: "jiàng mén yǒu jiàng", 将夺固与: "jiāng duó gù yǔ", 槛花笼鹤: "jiàn huā lóng hè", 鉴影度形: "jiàn yǐng duó xíng", 渐不可长: "jiàn bù kě zhǎng", 见素抱朴: "xiàn sù bào pǔ", 见弃于人: "jiàn qì yú rén", 简丝数米: "jiǎn sī shǔ mǐ", 俭不中礼: "jiǎn bú zhòng lǐ", 间见层出: "jiàn xiàn céng chū", 尖嘴薄舌: "jiān zuǐ bó shé", 甲冠天下: "jiǎ guàn tiān xià", 葭莩之亲: "jiā fú zhī qīn", 家累千金: "jiā lèi qiān jīn", 家给人足: "jiā jǐ rén zú", 家道从容: "jiā dào cóng róng", 夹袋人物: "jiā dài rén wù", 霁风朗月: "jì fēng lǎng yuè", 寄兴寓情: "jì xìng yù qíng", 计深虑远: "jì shēn lǜ yuǎn", 计功量罪: "jì gōng liàng zuì", 掎裳连襼: "jǐ shang lián yì", 虮虱相吊: "jǐ shī xiāng diào", 疾不可为: "jí bù kě wéi", 极深研几: "jí shēn yán jī", 及宾有鱼: "jí bīn yǒu yú", 激薄停浇: "jī bó tíng jiāo", 积素累旧: "jī sù lěi jiù", 积时累日: "jī shí lěi rì", 积露为波: "jī lù wéi bō", 积德累功: "jī dé lěi gōng", 积谗糜骨: "jī chán méi gǔ", 击排冒没: "jī pái mào mò", 祸为福先: "huò wéi fú xiān", 祸福相依: "huò fú xiāng yī", 获隽公车: "huò jùn gōng chē", 混应滥应: "hùn yīng làn yīng", 毁舟为杕: "huǐ zhōu wéi duò", 毁钟为铎: "huǐ zhōng wéi duó", 毁冠裂裳: "huǐ guān liè cháng", 晦盲否塞: "huì máng pǐ sè", 回船转舵: "huí chuán zhuàn duò", 潢池盗弄: "huáng chí dào nòng", 黄冠草履: "huáng guàn cǎo lǚ", 黄发儿齿: "huáng fà ér chǐ", 黄发垂髫: "huáng fà chuí tiáo", 还珠返璧: "huán zhū fǎn bì", 还年驻色: "huán nián zhù sè", 还年却老: "huán nián què lǎo", 坏裳为裤: "huài shang wéi kù", 画荻和丸: "huà dí huò wán", 化枭为鸠: "huà xiāo wéi jiū", 化腐为奇: "huà fǔ wéi qí", 化鸱为凤: "huà chī wéi fèng", 花不棱登: "huā bu lēng dēng", 户限为穿: "hù xiàn wéi chuān", 呼卢喝雉: "hū lú hè zhì", 呼来喝去: "hū lái hè qù", 呼不给吸: "hū bù jǐ xī", 厚味腊毒: "hòu wèi xī dú", 厚德载物: "hòu dé zài wù", 鸿渐于干: "hóng jiàn yú gàn", 洪炉燎发: "hóng lú liáo fà", 红绳系足: "hóng shéng jì zú", 红不棱登: "hóng bu lēng dēng", 横抢硬夺: "hèng qiǎng yìng duó", 横恩滥赏: "hèng ēn làn shǎng", 恨海难填: "hèn hǎi nán tián", 鹤发鸡皮: "hè fà jī pí", 涸思干虑: "hé sī gān lǜ", 河涸海干: "hé hé hǎi gān", 和颜说色: "hé yán yuè sè", 合从连衡: "hé zòng lián héng", 浩浩汤汤: "hào hào shāng shāng", 好勇斗狠: "hào yǒng dòu hěn", 好问则裕: "hào wèn zé yù", 好为事端: "hào wéi shì duān", 好问决疑: "hào wèn jué yí", 好生之德: "hào shēng zhī dé", 好奇尚异: "hǎo qí shàng yì", 好恶不同: "hǎo è bù tóng", 好丹非素: "hào dān fēi sù", 豪干暴取: "háo gàn bào qǔ", 毫发不爽: "háo fà bù shuǎng", 寒酸落魄: "hán suān luò pò", 含英咀华: "hán yīng jǔ huá", 含糊不明: "hán hú bù míng", 过为已甚: "guò wéi yǐ shèn", 桂折兰摧: "guì shé lán cuī", 规旋矩折: "guī xuán jǔ shé", 广文先生: "guǎng wén xiān sheng", 广陵散绝: "guǎng líng sǎn jué", 冠山戴粒: "guàn shān dài lì", 冠屦倒施: "guàn jù dǎo shī", 挂席为门: "guà xí wéi mén", 寡见鲜闻: "guǎ jiàn xiǎn wén", 瓜葛相连: "guā gé xiāng lián", 鼓吻奋爪: "gǔ wěn fèn zhǎo", 古调单弹: "gǔ diào dān tán", 古调不弹: "gǔ diào bù tán", 姑射神人: "gū yè shén rén", 苟合取容: "gǒu hé qǔ róng", 狗续侯冠: "gǒu xù hòu guàn", 钩爪锯牙: "gōu zhǎo jù yá", 共枝别干: "gòng zhī bié gàn", 共为唇齿: "gòng wéi chún chǐ", 拱手而降: "gǒng shǒu ér xiáng", 拱肩缩背: "gǒng jiān suō bèi", 功薄蝉翼: "gōng bó chán yì", 弓调马服: "gōng diào mǎ fú", 更姓改物: "gēng xìng gǎi wù", 更仆难数: "gēng pú nán shǔ", 更令明号: "gēng lìng míng hào", 更待干罢: "gèng dài gàn bà", 更唱迭和: "gēng chàng dié hé", 更长梦短: "gēng cháng mèng duǎn", 各色名样: "gè sè míng yàng", 格格不纳: "gé gé bú nà", 格格不吐: "gé gé bù tǔ", 告朔饩羊: "gù shuò xì yáng", 膏车秣马: "gào chē mò mǎ", 高义薄云: "gāo yì bó yún", 岗头泽底: "gāng tóu zé dǐ", 敢为敢做: "gǎn wéi gǎn zuò", 甘分随时: "gān fèn suí shí", 甘处下流: "gān chǔ xià liú", 干啼湿哭: "gàn tí shī kū", 干名犯义: "gàn míng fàn yì", 干将莫邪: "gān jiāng mò yé", 干城之将: "gān chéng zhī jiàng", 腹载五车: "fù zài wǔ chē", 父债子还: "fù zhài zǐ huán", 父为子隐: "fù wéi zǐ yǐn", 辅世长民: "fǔ shì zhǎng mín", 福为祸始: "fú wéi huò shǐ", 符号逻辑: "fú hào luó jí", 浮收勒折: "fú shōu lè shé", 肤受之愬: "fū shòu zhī sù", 否终则泰: "pǐ zhōng zé tài", 佛头著粪: "fó tóu zhuó fèn", 奉为楷模: "fèng wéi kǎi mó", 凤靡鸾吪: "fèng mǐ luán é", 封豨修蛇: "fēng xī xiū shé", 风影敷衍: "fēng yǐng fū yǎn", 丰屋蔀家: "fēng wū bù jiā", 粪土不如: "fèn tǔ bù rú", 分风劈流: "fēn fēng pǐ liú", 沸沸汤汤: "fèi fèi shāng shāng", 菲食薄衣: "fěi shí bó yī", 飞将数奇: "fēi jiàng shù qí", 放辟邪侈: "fàng pì xié chǐ", 方领圆冠: "fāng lǐng yuán guàn", 犯而不校: "fàn ér bú jiào", 返本还源: "fǎn běn huán yuán", 反劳为逸: "fǎn láo wéi yì", 法轮常转: "fǎ lún cháng zhuàn", 罚不当罪: "fá bù dāng zuì", 发引千钧: "fà yǐn qiān jūn", 发奸擿伏: "fā jiān tī fú", 发短心长: "fà duǎn xīn cháng", 二竖为虐: "èr shù wéi nüè", 儿女心肠: "ér nǚ xīn cháng", 儿女亲家: "ér nǚ qìng jiā", 遏恶扬善: "è wù yáng shàn", 饿殍枕藉: "è piǎo zhěn jí", 饿殍载道: "è piǎo zài dào", 恶醉强酒: "wù zuì qiǎng jiǔ", 恶意中伤: "è yì zhòng shāng", 恶湿居下: "wù shī jū xià", 恶居下流: "wù jū xià liú", 恶不去善: "wù bú qù shàn", 扼吭夺食: "è háng duó shí", 扼襟控咽: "è jīn kòng yān", 峨峨汤汤: "é é shāng shāng", 屙金溺银: "ē jīn niào yín", 朵颐大嚼: "duǒ yí dà jiáo", 夺人所好: "duó rén suǒ hào", 多言数穷: "duō yán shuò qióng", 多文为富: "duō wén wéi fù", 多端寡要: "duō duān guǎ yào", 多财善贾: "duō cái shàn gǔ", 遁世无闷: "dùn shì wú mèn", 遁迹黄冠: "dùn jì huáng guàn", 堆案盈几: "duī àn yíng jī", 断还归宗: "duàn huán guī zōng", 短见薄识: "duǎn jiàn bó shí", 蠹居棊处: "dù jū qí chǔ", 度己以绳: "duó jǐ yǐ shéng", 杜默为诗: "dù mò wéi shī", 杜鹃啼血: "dù juān tí xuè", 笃近举远: "dǔ jìn jǔ yuǎn", 独有千秋: "dú yǒu qiān qiū", 读书得间: "dú shū dé jiàn", 斗转参横: "dǒu zhuǎn shēn héng", 兜肚连肠: "dōu dǔ lián cháng", 洞见症结: "dòng jiàn zhèng jié", 恫疑虚喝: "dòng yí xū hè", 动中窾要: "dòng zhōng kuǎn yào", 东鸣西应: "dōng míng xī yīng", 东鳞西爪: "dōng lín xī zhǎo", 东量西折: "dōng liàng xī shé", 东家西舍: "dōng jiā xī shè", 东扯西拽: "dōng chě xī zhuāi", 鼎铛有耳: "dǐng chēng yǒu ěr", 鼎铛玉石: "dǐng chēng yù shí", 钉头磷磷: "dīng tóu lín lín", 跌宕不羁: "diē dàng bù jī", 跌弹斑鸠: "diē dàn bān jiū", 雕心雁爪: "diāo xīn yàn zhǎo", 颠倒衣裳: "diān dǎo yī cháng", 德薄能鲜: "dé bó néng xiǎn", 得马折足: "dé mǎ shé zú", 蹈其覆辙: "dǎo qí fù zhé", 捣虚撇抗: "dǎo xū piē kàng", 倒载干戈: "dào zài gān gē", 倒裳索领: "dào cháng suǒ lǐng", 倒果为因: "dào guǒ wéi yīn", 叨在知己: "tāo zài zhī jǐ", 叨陪末座: "tāo péi mò zuò", 党豺为虐: "dǎng chái wéi nüè", 当轴处中: "dāng zhóu chǔ zhōng", 当着不着: "dāng zhuó bù zhuó", 当务始终: "dāng wù shǐ zhōng", 淡汝浓抹: "dàn rǔ nóng mǒ", 弹丸脱手: "tán wán tuō shǒu", 弹铗无鱼: "dàn jiá wú yú", 箪食瓢饮: "dān sì piáo yǐn", 大璞不完: "dà pú bù wán", 大明法度: "dà míng fǎ dù", 大车以载: "dà chē yǐ zài", 打闷葫芦: "dǎ mèn hú lu", 沓来踵至: "tà lái zhǒng zhì", 厝火燎原: "cuò huǒ liǎo yuán", 撮科打哄: "cuō kē dǎ hòng", 寸积铢累: "cùn jī zhū lěi", 啛啛喳喳: "cuì cuì chā chā", 摧折豪强: "cuī zhé háo qiáng", 摧刚为柔: "cuī gāng wéi róu", 从俗就简: "cóng sú jiù jiǎn", 此发彼应: "cǐ fā bǐ yīng", 此唱彼和: "cǐ chàng bǐ hè", 慈悲为本: "cí bēi wéi běn", 纯属骗局: "chún shǔ piàn jú", 春笋怒发: "chūn sǔn nù fā", 垂头搨翼: "chuí tóu tà yì", 传为笑谈: "chuán wéi xiào tán", 传风扇火: "chuán fēng shān huǒ", 穿红着绿: "chuān hóng zhuó lǜ", 触处机来: "chù chǔ jī lái", 处尊居显: "chǔ zūn jū xiǎn", 处堂燕雀: "chǔ táng yàn què", 处实效功: "chǔ shí xiào gōng", 处高临深: "chǔ gāo lín shēn", 出入无间: "chū rù wú jiān", 出门应辙: "chū mén yīng zhé", 出处语默: "chū chǔ yǔ mò", 出处殊途: "chū chǔ shū tú", 出处进退: "chū chǔ jìn tuì", 愁山闷海: "chóu shān mèn hǎi", 冲冠眦裂: "chōng guàn zì liè", 齿牙为祸: "chǐ yá wéi huò", 尺二冤家: "chǐ èr yuān jia", 尺短寸长: "chǐ duǎn cùn cháng", 尺寸之功: "chǐ cùn zhī gōng", 城北徐公: "chéng běi xú gōng", 成败兴废: "chéng bài xīng fèi", 趁水和泥: "chèn shuǐ huò ní", 称雨道晴: "chēng yǔ dào qíng", 称体载衣: "chēng tǐ zài yī", 称体裁衣: "chèn tǐ cái yī", 称家有无: "chèn jiā yǒu wú", 称德度功: "chēng dé duó gōng", 沉吟章句: "chén yín zhāng jù", 沉吟不决: "chén yín bù jué", 沉疴宿疾: "chén kē sù jí", 扯纤拉烟: "chě qiàn lā yān", 扯顺风旗: "chě shùn fēng qí", 车载船装: "chē zǎi chuán zhuāng", 朝升暮合: "zhāo shēng mù gě", 朝攀暮折: "zhāo pān mù shé", 超今冠古: "chāo jīn guàn gǔ", 倡而不和: "chàng ér bú hè", 畅所欲为: "chàng suǒ yù wéi", 苌弘碧血: "cháng hóng bì xiě", 长幼尊卑: "zhǎng yòu zūn bēi", 长绳系日: "cháng shéng jì rì", 长年三老: "zhǎng nián sān lǎo", 长春不老: "cháng chūn bù lǎo", 长傲饰非: "zhǎng ào shì fēi", 昌亭旅食: "chāng tíng lǚ shí", 禅絮沾泥: "chán xù zhān ní", 差三错四: "chā sān cuò sì", 层台累榭: "céng tái lěi xiè", 层见迭出: "céng xiàn dié chū", 藏踪蹑迹: "cáng zōng niè jì", 苍蝇见血: "cāng yíng jiàn xiě", 餐松啖柏: "cān sōng dàn bó", 骖风驷霞: "cān fēng sì xiá", 参伍错综: "cēn wǔ cuò zōng", 参辰卯酉: "shēn chén mǎo yǒu", 材优干济: "cái yōu gān jǐ", 材薄质衰: "cái bó zhì shuāi", 才大难用: "cái dà nán yòng", 才薄智浅: "cái bó zhì qiǎn", 不足为意: "bù zú wéi yì", 不足为据: "bù zú wéi jù", 不足为法: "bù zú wéi fǎ", 不足齿数: "bù zú chǐ shǔ", 不着疼热: "bù zhuó téng rè", 不知薡蕫: "bù zhī dǐng dǒng", 不越雷池: "bú yuè léi chí", 不相为谋: "bù xiāng wéi móu", 不贪为宝: "bù tān wéi bǎo", 不了而了: "bù liǎo ér liǎo", 不可揆度: "bù kě kuí duó", 不遑启处: "bù huáng qǐ chǔ", 不当不正: "bù dāng bú zhèng", 不差什么: "bú chà shén me", 不差累黍: "bù chā lěi shǔ", 擘两分星: "bò liǎng fēn xīng", 簸土扬沙: "bǒ tǔ yáng shā", 薄物细故: "bó wù xì gù", 薄寒中人: "bó hán zhòng rén", 博文约礼: "bó wén yuē lǐ", 播糠眯目: "bō kāng mí mù", 剥皮抽筋: "bō pí chōu jīn", 剥肤椎髓: "bō fū chuí suǐ", 波属云委: "bō zhǔ yún wěi", 波骇云属: "bō hài yún zhǔ", 兵微将寡: "bīng wēi jiàng guǎ", 兵强将勇: "bīng qiáng jiàng yǒng", 兵多将广: "bīng duō jiàng guǎng", 兵不由将: "bīng bù yóu jiàng", 冰解的破: "bīng jiě dì pò", 彬彬济济: "bīn bīn jǐ jǐ", 摽梅之年: "biào méi zhī nián", 表里为奸: "biǎo lǐ wéi jiān", 飙发电举: "biāo fā diàn jǔ", 变贪厉薄: "biàn tān lì bó", 敝盖不弃: "bì gài bú qì", 秕言谬说: "bǐ yán miù shuō", 比物属事: "bǐ wù zhǔ shì", 被山带河: "pī shān dài hé", 被甲枕戈: "pī jiǎ zhěn gē", 被甲据鞍: "pī jiǎ jù ān", 被褐怀玉: "pī hè huái yù", 被发缨冠: "pī fà yīng guàn", 背曲腰躬: "bèi qǔ yāo gōng", 北窗高卧: "běi chuāng gāo wò", 北辰星拱: "běi chén xīng gǒng", 北鄙之音: "běi bǐ zhī yīn", 卑宫菲食: "bēi gōng fěi shí", 暴衣露冠: "pù yī lù guàn", 暴腮龙门: "pù sāi lóng mén", 暴露文学: "bào lù wén xué", 暴虎冯河: "bào hǔ píng hé", 抱蔓摘瓜: "bào wàn zhāi guā", 抱法处势: "bào fǎ chǔ shì", 褒贬与夺: "bāo biǎn yǔ duó", 帮闲钻懒: "bāng xián zuān lǎn", 拜将封侯: "bài jiàng fēng hóu", 百兽率舞: "bǎi shòu shuài wǔ", 百孔千创: "bǎi kǒng qiān chuāng", 白衣卿相: "bái yī qīng xiàng", 白首为郎: "bái shǒu wéi láng", 白首相知: "bái shǒu xiāng zhī", 把玩无厌: "bǎ wán wú yàn", 拔锅卷席: "bá guō juǎn xí", 拔本塞源: "bá běn sè yuán", 傲不可长: "ào bù kě zhǎng", 熬更守夜: "áo gēng shǒu yè", 安时处顺: "ān shí chǔ shùn", 安身为乐: "ān shēn wéi lè", 安老怀少: "ān lǎo huái shào", 安步当车: "ān bù dàng chē", 爱人好士: "ài rén hào shì", 矮人观场: "ǎi rén guān chǎng", 捱风缉缝: "ái fēng jī fèng", 挨山塞海: "āi shān sè hǎi", 阿家阿翁: "ā jiā ā wēng", 阿党相为: "ē dǎng xiāng wéi", 追亡逐北: "zhuī wáng zhú běi", 竹篮打水: "zhú lán dá shuǐ", 知疼着热: "zhī téng zháo rè", 语不惊人: "yǔ bù jīng rén", 于今为烈: "yú jīn wéi liè", 一日三省: "yí rì sān xǐng", 穴居野处: "xué jū yě chǔ", 五脊六兽: "wǔ jǐ liù shòu", 无声无臭: "wú shēng wú xiù", 谓予不信: "wèi yú bú xìn", 舍身为国: "shě shēn wéi guó", 杀妻求将: "shā qī qiú jiàng", 强作解人: "qiǎng zuò jiě rén", 气冲斗牛: "qì chōng dǒu niú", 临深履薄: "lín shēn lǚ bó", 钧天广乐: "jūn tiān guǎng yuè", 艰难竭蹶: "jiān nán jié jué", 夹七夹八: "jiā qī jiā bā", 混混噩噩: "hún hún è è", 厚古薄今: "hòu gǔ bó jīn", 鬼怕恶人: "guǐ pà è rén", 伽马射线: "gā mǎ shè xiàn", 佛头着粪: "fó tóu zhuó fèn", 奉为至宝: "fèng wéi zhì bǎo", 登坛拜将: "dēng tán bài jiàng", 晨昏定省: "chén hūn dìng xǐng", 察察为明: "chá chá wéi míng", 博闻强识: "bó wén qiáng zhì", 避难就易: "bì nán jiù yì", 了无生机: 'liǎo wú shēng jī', // 一字不变调的词语,如果词语仅有单个一且一字在结尾的无需添加(需要增补更多) 有一说一: 'yǒu yī shuō yī', 独一无二: 'dú yī wú èr', 说一不二: 'shuō yī bù èr', 举一反三: 'jǔ yī fǎn sān', 数一数二: 'shǔ yī shǔ èr', 杀一儆百: 'shā yī jǐng bǎi', 丁一卯二: 'dīng yī mǎo èr', 丁一确二: 'dīng yī què èr', 不一而止: 'bù yī ér zhǐ', 无一幸免: 'wú yī xìng miǎn', // 来源:https://m.gushici.com/cyxy_4e00_4 表里不一: 'biǎo lǐ bù yī', 良莠不一: 'liáng yǒu bù yī', 心口不一: 'xīn kǒu bù yī', 言行不一: 'yán xíng bù yī', 政令不一: 'zhèng lìng bù yī', 参差不一: 'cēn cī bù yī', 纷纷不一: 'fēn fēn bù yī', 毁誉不一: 'huǐ yù bù yī', 不一而三: 'bù yī ér sān', 百不一遇: 'bǎi bù yī yù', 言行抱一: 'yán xíng bào yī', 瑜百瑕一: 'yú bǎi xiá yī', 背城借一: 'bèi chéng jiè yī', 凭城借一: 'píng chéng jiè yī', 劝百讽一: 'quàn bǎi fěng yī', 群居和一: 'qún jū hé yī', 百不获一: 'bǎi bù huò yī', 百不失一: 'bǎi bù shī yī', 百无失一: 'bǎi wú shī yī', 万不失一: 'wàn bù shī yī', 万无失一: 'wàn wú shī yī', 合而为一: 'hé ér wéi yī', 合两为一: 'hé liǎng wéi yī', 合二为一: 'hé èr wéi yī', 天下为一: 'tiān xià wéi yī', 相与为一: 'xiāng yǔ wéi yī', 较若画一: 'jiào ruò huà yī', 较如画一: 'jiào rú huà yī', 斠若画一: 'jiào ruò huà yī', 言行若一: 'yán xíng ruò yī', 始终若一: 'shǐ zhōng ruò yī', 终始若一: 'zhōng shǐ ruò yī', 惟精惟一: 'wéi jīng wéi yī', 众多非一: 'zhòng duō fēi yī', 不能赞一: 'bù néng zàn yī', 问一答十: 'wèn yī dá shí', 一不扭众: 'yī bù niǔ zhòng', 一以贯之: 'yī yǐ guàn zhī', 一以当百: 'yī yǐ dāng bǎi', 百不当一: 'bǎi bù dāng yī', 十不当一: 'shí bù dāng yī', 以一警百: 'yǐ yī jǐng bǎi', 以一奉百: 'yǐ yī fèng bǎi', 以一持万: 'yǐ yī chí wàn', 以一知万: 'yǐ yī zhī wàn', 百里挑一: 'bǎi lǐ tiāo yī', 整齐划一: 'zhěng qí huà yī', 一来二去: 'yī lái èr qù', 一路公交: 'yī lù gōng jiāo', 一路汽车: 'yī lù qì chē', 一路巴士: 'yī lù bā shì', 朝朝朝落: 'zhāo cháo zhāo luò', 曲意逢迎: 'qū yì féng yíng', 一行不行: 'yì háng bù xíng', 行行不行: 'háng háng bù xíng' }; const Pattern4 = Object.keys(DICT4).map((key) => ({ zh: key, pinyin: DICT4[key], probability: 2e-8 /* Probability.DICT */, length: 4, priority: _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__.Priority.Normal, dict: Symbol('dict4'), })); /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/data/dict5.mjs": /*!*********************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/data/dict5.mjs ***! \*********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Pattern5: function() { return /* binding */ Pattern5; }, /* harmony export */ "default": function() { return /* binding */ DICT5; } /* harmony export */ }); /* harmony import */ var _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common/constant.mjs */ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs"); const DICT5 = { 巴尔干半岛: 'bā ěr gàn bàn dǎo', 巴尔喀什湖: 'bā ěr kā shí hú', 不幸而言中: 'bú xìng ér yán zhòng', 布尔什维克: 'bù ěr shí wéi kè', 何乐而不为: 'hé lè ér bù wéi', 苛政猛于虎: 'kē zhèng měng yú hǔ', 蒙得维的亚: 'méng dé wéi dì yà', 民以食为天: 'mín yǐ shí wéi tiān', 事后诸葛亮: 'shì hòu zhū gě liàng', 物以稀为贵: 'wù yǐ xī wéi guì', 先下手为强: 'xiān xià shǒu wéi qiáng', 行行出状元: 'háng háng chū zhuàng yuan', 亚得里亚海: 'yà dé lǐ yà hǎi', 眼不见为净: 'yǎn bú jiàn wéi jìng', 竹筒倒豆子: 'zhú tǒng dào dòu zi', }; const Pattern5 = Object.keys(DICT5).map((key) => ({ zh: key, pinyin: DICT5[key], probability: 2e-8 /* Probability.DICT */, length: 5, priority: _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__.Priority.Normal, dict: Symbol('dict5'), })); /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/data/patterns.mjs": /*!************************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/data/patterns.mjs ***! \************************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PatternsNormal: function() { return /* binding */ PatternsNormal; } /* harmony export */ }); /* harmony import */ var _special_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./special.mjs */ "./node_modules/pinyin-pro/dist/esm/data/special.mjs"); /* harmony import */ var _dict2_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./dict2.mjs */ "./node_modules/pinyin-pro/dist/esm/data/dict2.mjs"); /* harmony import */ var _dict3_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./dict3.mjs */ "./node_modules/pinyin-pro/dist/esm/data/dict3.mjs"); /* harmony import */ var _dict4_mjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./dict4.mjs */ "./node_modules/pinyin-pro/dist/esm/data/dict4.mjs"); /* harmony import */ var _dict5_mjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./dict5.mjs */ "./node_modules/pinyin-pro/dist/esm/data/dict5.mjs"); /* harmony import */ var _surname_mjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./surname.mjs */ "./node_modules/pinyin-pro/dist/esm/data/surname.mjs"); const PatternsNormal = [ ..._dict5_mjs__WEBPACK_IMPORTED_MODULE_4__.Pattern5, ..._dict4_mjs__WEBPACK_IMPORTED_MODULE_3__.Pattern4, ..._dict3_mjs__WEBPACK_IMPORTED_MODULE_2__.Pattern3, ..._dict2_mjs__WEBPACK_IMPORTED_MODULE_1__.Pattern2, ..._special_mjs__WEBPACK_IMPORTED_MODULE_0__.PatternNumberDict, ..._surname_mjs__WEBPACK_IMPORTED_MODULE_5__.PatternSurname, ]; /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/data/special.mjs": /*!***********************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/data/special.mjs ***! \***********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ InitialList: function() { return /* binding */ InitialList; }, /* harmony export */ PatternNumberDict: function() { return /* binding */ PatternNumberDict; }, /* harmony export */ SpecialFinalList: function() { return /* binding */ SpecialFinalList; }, /* harmony export */ SpecialFinalMap: function() { return /* binding */ SpecialFinalMap; }, /* harmony export */ SpecialInitialList: function() { return /* binding */ SpecialInitialList; }, /* harmony export */ doubleFinalList: function() { return /* binding */ doubleFinalList; }, /* harmony export */ toneSandhiIgnoreSuffix: function() { return /* binding */ toneSandhiIgnoreSuffix; }, /* harmony export */ toneSandhiList: function() { return /* binding */ toneSandhiList; }, /* harmony export */ toneSandhiMap: function() { return /* binding */ toneSandhiMap; } /* harmony export */ }); /* harmony import */ var _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common/constant.mjs */ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs"); /* harmony import */ var _common_utils_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../common/utils.mjs */ "./node_modules/pinyin-pro/dist/esm/common/utils.mjs"); const InitialList = [ "zh", "ch", "sh", "z", "c", "s", "b", "p", "m", "f", "d", "t", "n", "l", "g", "k", "h", "j", "q", "x", "r", "y", "w", "", ]; const SpecialInitialList = ["j", "q", "x"]; const SpecialFinalList = [ "uān", "uán", "uǎn", "uàn", "uan", "uē", "ué", "uě", "uè", "ue", "ūn", "ún", "ǔn", "ùn", "un", "ū", "ú", "ǔ", "ù", "u", ]; const SpecialFinalMap = { uān: "üān", uán: "üán", uǎn: "üǎn", uàn: "üàn", uan: "üan", uē: "üē", ué: "üé", uě: "üě", uè: "üè", ue: "üe", ūn: "ǖn", ún: "ǘn", ǔn: "ǚn", ùn: "ǜn", un: "ün", ū: "ǖ", ú: "ǘ", ǔ: "ǚ", ù: "ǜ", u: "ü", }; const doubleFinalList = [ "ia", "ian", "iang", "iao", "ie", "iu", "iong", "ua", "uai", "uan", "uang", "ue", "ui", "uo", "üan", "üe", "van", "ve", ]; /** * @description: 数量词 + 特殊词 音调处理 */ const Numbers = { 一: "yì", 二: "èr", 三: "sān", 四: "sì", 五: "wǔ", 六: "liù", 七: "qī", 八: "bā", 九: "jiǔ", 十: "shí", 百: "bǎi", 千: "qiān", 万: "wàn", 亿: "yì", 单: "dān", 两: "liǎng", 双: "shuāng", 多: "duō", 几: "jǐ", 十一: "shí yī", 零一: "líng yī", 第一: "dì yī", 一十: "yī shí", 一十一: "yī shí yī", }; const NumberWordMap = { 重: "chóng", 行: "háng", 斗: "dǒu", 更: "gēng", }; // 与以下词组合时,不变调 function genNumberDict() { const dict = { 零一: "líng yī", 〇一: "líng yī", 十一: "shí yī", 一十: "yī shí", 第一: "dì yī", 一十一: "yī shí yī", }; for (let number in Numbers) { for (let key in NumberWordMap) { const word = `${number}${key}`; const pinyin = `${Numbers[number]} ${NumberWordMap[key]}`; dict[word] = pinyin; } } return dict; } const NumberDict = genNumberDict(); const PatternNumberDict = Object.keys(NumberDict).map((key) => ({ zh: key, pinyin: NumberDict[key], probability: 1e-12 /* Probability.Rule */, length: (0,_common_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.stringLength)(key), priority: _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__.Priority.Normal, dict: Symbol("rule"), })); /** * @description: 连续变调处理:https://zh.wiktionary.org/wiki/Appendix:%E2%80%9C%E4%B8%80%E2%80%9D%E5%8F%8A%E2%80%9C%E4%B8%8D%E2%80%9D%E7%9A%84%E5%8F%98%E8%B0%83 */ const toneSandhiMap = { // 说不说,说一说,叠词之间发音为轻声 不: { bú: [4], // "不" 后面跟 4 声时,变调为 2 声 }, 一: { yí: [4], yì: [1, 2, 3], }, }; const toneSandhiIgnoreSuffix = { 不: ["的", "而", "之", "后", "也", "还", "地"], 一: ["的", "而", "之", "后", "也", "还", "是"], }; const toneSandhiList = Object.keys(toneSandhiMap); /***/ }), /***/ "./node_modules/pinyin-pro/dist/esm/data/surname.mjs": /*!***********************************************************!*\ !*** ./node_modules/pinyin-pro/dist/esm/data/surname.mjs ***! \***********************************************************/ /***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PatternSurname: function() { return /* binding */ PatternSurname; }, /* harmony export */ "default": function() { return /* binding */ Surnames; } /* harmony export */ }); /* harmony import */ var _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common/constant.mjs */ "./node_modules/pinyin-pro/dist/esm/common/constant.mjs"); /* harmony import */ var _common_utils_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../common/utils.mjs */ "./node_modules/pinyin-pro/dist/esm/common/utils.mjs"); const Surnames = { 南宫: 'nán gōng', 第五: 'dì wǔ', 万俟: 'mò qí', 司马: 'sī mǎ', 上官: 'shàng guān', 欧阳: 'ōu yáng', 夏侯: 'xià hóu', 诸葛: 'zhū gě', 闻人: 'wén rén', 东方: 'dōng fāng', 赫连: 'hè lián', 皇甫: 'huáng fǔ', 尉迟: 'yù chí', 公羊: 'gōng yáng', 澹台: 'tán tái', 公冶: 'gōng yě', 宗政: 'zōng zhèng', 濮阳: 'pú yáng', 淳于: 'chún yú', 太叔: 'tài shū', 申屠: 'shēn tú', 公孙: 'gōng sūn', 仲孙: 'zhòng sūn', 轩辕: 'xuān yuán', 令狐: 'líng hú', 钟离: 'zhōng lí', 宇文: 'yǔ wén', 长孙: 'zhǎng sūn', 慕容: 'mù róng', 鲜于: 'xiān yú', 闾丘: 'lǘ qiū', 司徒: 'sī tú', 司空: 'sī kōng', 亓官: 'qí guān', 司寇: 'sī kòu', 仉督: 'zhǎng dū', 子车: 'zǐ jū', 颛孙: 'zhuān sūn', 端木: 'duān mù', 巫马: 'wū mǎ', 公西: 'gōng xī', 漆雕: 'qī diāo', 乐正: 'yuè zhèng', 壤驷: 'rǎng sì', 公良: 'gōng liáng', 拓跋: 'tuò bá', 夹谷: 'jiá gǔ', 宰父: 'zǎi fǔ', 榖梁: 'gǔ liáng', 段干: 'duàn gān', 百里: 'bǎi lǐ', 东郭: 'dōng guō', 南门: 'nán mén', 呼延: 'hū yán', 羊舌: 'yáng shé', 梁丘: 'liáng qiū', 左丘: 'zuǒ qiū', 东门: 'dōng mén', 西门: 'xī mén', 句龙: 'gōu lóng', 毌丘: 'guàn qiū', 赵: 'zhào', 钱: 'qián', 孙: 'sūn', 李: 'lǐ', 周: 'zhōu', 吴: 'wú', 郑: 'zhèng', 王: 'wáng', 冯: 'féng', 陈: 'chén', 褚: 'chǔ', 卫: 'wèi', 蒋: 'jiǎng', 沈: 'shěn', 韩: 'hán', 杨: 'yáng', 朱: 'zhū', 秦: 'qín', 尤: 'yóu', 许: 'xǔ', 何: 'hé', 吕: 'lǚ', 施: 'shī', 张: 'zhāng', 孔: 'kǒng', 曹: 'cáo', 严: 'yán', 华: 'huà', 金: 'jīn', 魏: 'wèi', 陶: 'táo', 姜: 'jiāng', 戚: 'qī', 谢: 'xiè', 邹: 'zōu', 喻: 'yù', 柏: 'bǎi', 水: 'shuǐ', 窦: 'dòu', 章: 'zhāng', 云: 'yún', 苏: 'sū', 潘: 'pān', 葛: 'gě', 奚: 'xī', 范: 'fàn', 彭: 'péng', 郎: 'láng', 鲁: 'lǔ', 韦: 'wéi', 昌: 'chāng', 马: 'mǎ', 苗: 'miáo', 凤: 'fèng', 花: 'huā', 方: 'fāng', 俞: 'yú', 任: 'rén', 袁: 'yuán', 柳: 'liǔ', 酆: 'fēng', 鲍: 'bào', 史: 'shǐ', 唐: 'táng', 费: 'fèi', 廉: 'lián', 岑: 'cén', 薛: 'xuē', 雷: 'léi', 贺: 'hè', 倪: 'ní', 汤: 'tāng', 滕: 'téng', 殷: 'yīn', 罗: 'luó', 毕: 'bì', 郝: 'hǎo', 邬: 'wū', 安: 'ān', 常: 'cháng', 乐: 'yuè', 于: 'yú', 时: 'shí', 傅: 'fù', 皮: 'pí', 卞: 'biàn', 齐: 'qí', 康: 'kāng', 伍: 'wǔ', 余: 'yú', 元: 'yuán', 卜: 'bǔ', 顾: 'gù', 孟: 'mèng', 平: 'píng', 黄: 'huáng', 和: 'hé', 穆: 'mù', 萧: 'xiāo', 尹: 'yǐn', 姚: 'yáo', 邵: 'shào', 湛: 'zhàn', 汪: 'wāng', 祁: 'qí', 毛: 'máo', 禹: 'yǔ', 狄: 'dí', 米: 'mǐ', 贝: 'bèi', 明: 'míng', 臧: 'zāng', 计: 'jì', 伏: 'fú', 成: 'chéng', 戴: 'dài', 谈: 'tán', 宋: 'sòng', 茅: 'máo', 庞: 'páng', 熊: 'xióng', 纪: 'jǐ', 舒: 'shū', 屈: 'qū', 项: 'xiàng', 祝: 'zhù', 董: 'dǒng', 梁: 'liáng', 杜: 'dù', 阮: 'ruǎn', 蓝: 'lán', 闵: 'mǐn', 席: 'xí', 季: 'jì', 麻: 'má', 强: 'qiáng', 贾: 'jiǎ', 路: 'lù', 娄: 'lóu', 危: 'wēi', 江: 'jiāng', 童: 'tóng', 颜: 'yán', 郭: 'guō', 梅: 'méi', 盛: 'shèng', 林: 'lín', 刁: 'diāo', 钟: 'zhōng', 徐: 'xú', 邱: 'qiū', 骆: 'luò', 高: 'gāo', 夏: 'xià', 蔡: 'cài', 田: 'tián', 樊: 'fán', 胡: 'hú', 凌: 'líng', 霍: 'huò', 虞: 'yú', 万: 'wàn', 支: 'zhī', 柯: 'kē', 昝: 'zǎn', 管: 'guǎn', 卢: 'lú', 莫: 'mò', 经: 'jīng', 房: 'fáng', 裘: 'qiú', 缪: 'miào', 干: 'gān', 解: 'xiè', 应: 'yīng', 宗: 'zōng', 丁: 'dīng', 宣: 'xuān', 贲: 'bēn', 邓: 'dèng', 郁: 'yù', 单: 'shàn', 杭: 'háng', 洪: 'hóng', 包: 'bāo', 诸: 'zhū', 左: 'zuǒ', 石: 'shí', 崔: 'cuī', 吉: 'jí', 钮: 'niǔ', 龚: 'gōng', 程: 'chéng', 嵇: 'jī', 邢: 'xíng', 滑: 'huá', 裴: 'péi', 陆: 'lù', 荣: 'róng', 翁: 'wēng', 荀: 'xún', 羊: 'yáng', 於: 'yū', 惠: 'huì', 甄: 'zhēn', 曲: 'qū', 家: 'jiā', 封: 'fēng', 芮: 'ruì', 羿: 'yì', 储: 'chǔ', 靳: 'jìn', 汲: 'jí', 邴: 'bǐng', 糜: 'mí', 松: 'sōng', 井: 'jǐng', 段: 'duàn', 富: 'fù', 巫: 'wū', 乌: 'wū', 焦: 'jiāo', 巴: 'bā', 弓: 'gōng', 牧: 'mù', 隗: 'wěi', 山: 'shān', 谷: 'gǔ', 车: 'chē', 侯: 'hóu', 宓: 'mì', 蓬: 'péng', 全: 'quán', 郗: 'xī', 班: 'bān', 仰: 'yǎng', 秋: 'qiū', 仲: 'zhòng', 伊: 'yī', 宫: 'gōng', 宁: 'nìng', 仇: 'qiú', 栾: 'luán', 暴: 'bào', 甘: 'gān', 钭: 'tǒu', 厉: 'lì', 戎: 'róng', 祖: 'zǔ', 武: 'wǔ', 符: 'fú', 刘: 'liú', 景: 'jǐng', 詹: 'zhān', 束: 'shù', 龙: 'lóng', 叶: 'yè', 幸: 'xìng', 司: 'sī', 韶: 'sháo', 郜: 'gào', 黎: 'lí', 蓟: 'jì', 薄: 'bó', 印: 'yìn', 宿: 'sù', 白: 'bái', 怀: 'huái', 蒲: 'pú', 邰: 'tái', 从: 'cóng', 鄂: 'è', 索: 'suǒ', 咸: 'xián', 籍: 'jí', 赖: 'lài', 卓: 'zhuó', 蔺: 'lìn', 屠: 'tú', 蒙: 'méng', 池: 'chí', 乔: 'qiáo', 阴: 'yīn', 鬱: 'yù', 胥: 'xū', 能: 'nài', 苍: 'cāng', 双: 'shuāng', 闻: 'wén', 莘: 'shēn', 党: 'dǎng', 翟: 'zhái', 谭: 'tán', 贡: 'gòng', 劳: 'láo', 逄: 'páng', 姬: 'jī', 申: 'shēn', 扶: 'fú', 堵: 'dǔ', 冉: 'rǎn', 宰: 'zǎi', 郦: 'lì', 雍: 'yōng', 郤: 'xì', 璩: 'qú', 桑: 'sāng', 桂: 'guì', 濮: 'pú', 牛: 'niú', 寿: 'shòu', 通: 'tōng', 边: 'biān', 扈: 'hù', 燕: 'yān', 冀: 'jì', 郏: 'jiá', 浦: 'pǔ', 尚: 'shàng', 农: 'nóng', 温: 'wēn', 别: 'bié', 庄: 'zhuāng', 晏: 'yàn', 柴: 'chái', 瞿: 'qú', 阎: 'yán', 充: 'chōng', 慕: 'mù', 连: 'lián', 茹: 'rú', 习: 'xí', 宦: 'huàn', 艾: 'ài', 鱼: 'yú', 容: 'róng', 向: 'xiàng', 古: 'gǔ', 易: 'yì', 慎: 'shèn', 戈: 'gē', 廖: 'liào', 庾: 'yǔ', 终: 'zhōng', 暨: 'jì', 居: 'jū', 衡: 'héng', 步: 'bù', 都: 'dū', 耿: 'gěng', 满: 'mǎn', 弘: 'hóng', 匡: 'kuāng', 国: 'guó', 文: 'wén', 寇: 'kòu', 广: 'guǎng', 禄: 'lù', 阙: 'quē', 东: 'dōng', 欧: 'ōu', 殳: 'shū', 沃: 'wò', 利: 'lì', 蔚: 'wèi', 越: 'yuè', 夔: 'kuí', 隆: 'lóng', 师: 'shī', 巩: 'gǒng', 厍: 'shè', 聂: 'niè', 晁: 'cháo', 勾: 'gōu', 敖: 'áo', 融: 'róng', 冷: 'lěng', 訾: 'zī', 辛: 'xīn', 阚: 'kàn', 那: 'nā', 简: 'jiǎn', 饶: 'ráo', 空: 'kōng', 曾: 'zēng', 母: 'mǔ', 沙: 'shā', 乜: 'niè', 养: 'yǎng', 鞠: 'jū', 须: 'xū', 丰: 'fēng', 巢: 'cháo', 关: 'guān', 蒯: 'kuǎi', 相: 'xiàng', 查: 'zhā', 后: 'hòu', 荆: 'jīng', 红: 'hóng', 游: 'yóu', 竺: 'zhú', 权: 'quán', 逯: 'lù', 盖: 'gě', 益: 'yì', 桓: 'huán', 公: 'gōng', 牟: 'móu', 哈: 'hǎ', 言: 'yán', 福: 'fú', 肖: 'xiāo', 区: 'ōu', 覃: 'qín', 朴: 'piáo', 繁: 'pó', 员: 'yùn', 句: 'gōu', 要: 'yāo', 过: 'guō', 钻: 'zuān', 谌: 'chén', 折: 'shé', 召: 'shào', 郄: 'qiè', 撒: 'sǎ', 甯: 'nìng', 六: 'lù', 啜: 'chuài', 行: 'xíng', }; const PatternSurname = Object.keys(Surnames).map((key) => ({ zh: key, pinyin: Surnames[key], probability: 1 /* Probability.Surname */ + (0,_common_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.stringLength)(key), length: (0,_common_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.stringLength)(key), priority: _common_constant_mjs__WEBPACK_IMPORTED_MODULE_0__.Priority.Surname, dict: Symbol('surname'), })); /***/ }), /***/ "./img/bkg/index.json": /*!****************************!*\ !*** ./img/bkg/index.json ***! \****************************/ /***/ (function(module) { "use strict"; module.exports = /*#__PURE__*/JSON.parse('{"patt":[{"name":"a00.png","size":200},{"name":"a01.jpg","size":384},{"name":"a02.jpg","size":384},{"name":"a03.jpg","size":384},{"name":"a04.png","size":400},{"name":"a05.jpg","size":400},{"name":"a06.jpg","size":256},{"name":"a07.jpg","size":384},{"name":"a08.jpg","size":384},{"name":"a09.jpg","size":400},{"name":"a10.jpg","size":256},{"name":"a11.png","size":200}],"img":[{"name":"w01.jpg","pr":"p01.jpg"},{"name":"w02.jpg","pr":"p02.jpg"},{"name":"w03.jpg","pr":"p03.jpg"},{"name":"w04.jpg","pr":"p04.jpg"},{"name":"w05.jpg","pr":"p05.jpg"},{"name":"w06.jpg","pr":"p06.jpg"},{"name":"w07.jpg","pr":"p07.jpg"},{"name":"w08.jpg","pr":"p08.jpg"},{"name":"w09.jpg","pr":"p09.jpg"},{"name":"w10.jpg","pr":"p10.jpg"},{"name":"w11.jpg","pr":"p11.jpg"},{"name":"w12.jpg","pr":"p12.jpg"},{"name":"w13.jpg","pr":"p13.jpg"},{"name":"w14.jpg","pr":"p14.jpg"},{"name":"w15.jpg","pr":"p15.jpg"},{"name":"w16.jpg","pr":"p16.jpg"},{"name":"w17.jpg","pr":"p17.jpg"},{"name":"w18.jpg","pr":"p18.jpg"},{"name":"w19.jpg","pr":"p19.jpg"},{"name":"w20.jpg","pr":"p20.jpg"},{"name":"w21.jpg","pr":"p21.jpg"},{"name":"w22.jpg","pr":"p22.jpg"},{"name":"w23.jpg","pr":"p23.jpg"},{"name":"w24.jpg","pr":"p24.jpg"}]}'); /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ if (!(moduleId in __webpack_modules__)) { /******/ delete __webpack_module_cache__[moduleId]; /******/ var e = new Error("Cannot find module '" + moduleId + "'"); /******/ e.code = 'MODULE_NOT_FOUND'; /******/ throw e; /******/ } /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = __webpack_modules__; /******/ /************************************************************************/ /******/ /* webpack/runtime/compat get default export */ /******/ !function() { /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function() { return module['default']; } : /******/ function() { return module; }; /******/ __webpack_require__.d(getter, { a: getter }); /******/ return getter; /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/create fake namespace object */ /******/ !function() { /******/ var getProto = Object.getPrototypeOf ? function(obj) { return Object.getPrototypeOf(obj); } : function(obj) { return obj.__proto__; }; /******/ var leafPrototypes; /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 16: return value when it's Promise-like /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = this(value); /******/ if(mode & 8) return value; /******/ if(typeof value === 'object' && value) { /******/ if((mode & 4) && value.__esModule) return value; /******/ if((mode & 16) && typeof value.then === 'function') return value; /******/ } /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ var def = {}; /******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; /******/ for(var current = mode & 2 && value; (typeof current == 'object' || typeof current == 'function') && !~leafPrototypes.indexOf(current); current = getProto(current)) { /******/ Object.getOwnPropertyNames(current).forEach(function(key) { def[key] = function() { return value[key]; }; }); /******/ } /******/ def['default'] = function() { return value; }; /******/ __webpack_require__.d(ns, def); /******/ return ns; /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/define property getters */ /******/ !function() { /******/ // define getter/value functions for harmony exports /******/ __webpack_require__.d = function(exports, definition) { /******/ if(Array.isArray(definition)) { /******/ var i = 0; /******/ while(i < definition.length) { /******/ var key = definition[i++]; /******/ var binding = definition[i++]; /******/ if(!__webpack_require__.o(exports, key)) { /******/ if(binding === 0) { /******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] }); /******/ } else { /******/ Object.defineProperty(exports, key, { enumerable: true, get: binding }); /******/ } /******/ } else if(binding === 0) { i++; } /******/ } /******/ } else { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ } /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/ensure chunk */ /******/ !function() { /******/ __webpack_require__.f = {}; /******/ // This file contains only the entry chunk. /******/ // The chunk loading function for additional chunks /******/ __webpack_require__.e = function(chunkId) { /******/ return Promise.all(Object.keys(__webpack_require__.f).reduce(function(promises, key) { /******/ __webpack_require__.f[key](chunkId, promises); /******/ return promises; /******/ }, [])); /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/get javascript chunk filename */ /******/ !function() { /******/ // This function allow to reference async chunks /******/ __webpack_require__.u = function(chunkId) { /******/ // return url for filenames based on template /******/ return "" + chunkId + ".dev.js"; /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/global */ /******/ !function() { /******/ __webpack_require__.g = (function() { /******/ if (typeof globalThis === 'object') return globalThis; /******/ try { /******/ return this || new Function('return this')(); /******/ } catch (e) { /******/ if (typeof window === 'object') return window; /******/ } /******/ })(); /******/ }(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ !function() { /******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } /******/ }(); /******/ /******/ /* webpack/runtime/load script */ /******/ !function() { /******/ var inProgress = {}; /******/ var dataWebpackPrefix = "tinode-webapp:"; /******/ // loadScript function to load a script via script tag /******/ __webpack_require__.l = function(url, done, key, chunkId) { /******/ if(inProgress[url]) { inProgress[url].push(done); return; } /******/ var script, needAttach; /******/ if(key !== undefined) { /******/ var scripts = document.getElementsByTagName("script"); /******/ for(var i = 0; i < scripts.length; i++) { /******/ var s = scripts[i]; /******/ if(s.getAttribute("src") == url || s.getAttribute("data-webpack") == dataWebpackPrefix + key) { script = s; break; } /******/ } /******/ } /******/ if(!script) { /******/ needAttach = true; /******/ script = document.createElement('script'); /******/ /******/ script.charset = 'utf-8'; /******/ if (__webpack_require__.nc) { /******/ script.setAttribute("nonce", __webpack_require__.nc); /******/ } /******/ script.setAttribute("data-webpack", dataWebpackPrefix + key); /******/ /******/ script.src = url; /******/ } /******/ inProgress[url] = [done]; /******/ var onScriptComplete = function(prev, event) { /******/ // avoid mem leaks in IE. /******/ script.onerror = script.onload = null; /******/ clearTimeout(timeout); /******/ var doneFns = inProgress[url]; /******/ delete inProgress[url]; /******/ script.parentNode && script.parentNode.removeChild(script); /******/ doneFns && doneFns.forEach(function(fn) { return fn(event); }); /******/ if(prev) return prev(event); /******/ } /******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); /******/ script.onerror = onScriptComplete.bind(null, script.onerror); /******/ script.onload = onScriptComplete.bind(null, script.onload); /******/ needAttach && document.head.appendChild(script); /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/ !function() { /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/set anonymous default export name */ /******/ !function() { /******/ // set .name for anonymous default exports per ES spec /******/ __webpack_require__.dn = function(x) { /******/ (Object.getOwnPropertyDescriptor(x, "name") || {}).writable || Object.defineProperty(x, "name", { value: "default", configurable: true }); /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/publicPath */ /******/ !function() { /******/ __webpack_require__.p = "/umd/"; /******/ }(); /******/ /******/ /* webpack/runtime/jsonp chunk loading */ /******/ !function() { /******/ // no baseURI /******/ /******/ // object to store loaded and loading chunks /******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched /******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded /******/ var installedChunks = { /******/ "index": 0 /******/ }; /******/ /******/ __webpack_require__.f.j = function(chunkId, promises) { /******/ // JSONP chunk loading for javascript /******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; /******/ if(installedChunkData !== 0) { // 0 means "already installed". /******/ /******/ // a Promise means "currently loading". /******/ if(installedChunkData) { /******/ promises.push(installedChunkData[2]); /******/ } else { /******/ if(true) { // all chunks have JS /******/ // setup Promise in chunk cache /******/ var promise = new Promise(function(resolve, reject) { installedChunkData = installedChunks[chunkId] = [resolve, reject]; }); /******/ promises.push(installedChunkData[2] = promise); /******/ /******/ // start chunk loading /******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); /******/ // create error before stack unwound to get useful stacktrace later /******/ var error = new Error(); /******/ var loadingEnded = function(event) { /******/ if(__webpack_require__.o(installedChunks, chunkId)) { /******/ installedChunkData = installedChunks[chunkId]; /******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; /******/ if(installedChunkData) { /******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); /******/ var realSrc = event && event.target && event.target.src; /******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')'; /******/ error.name = 'ChunkLoadError'; /******/ error.type = errorType; /******/ error.request = realSrc; /******/ installedChunkData[1](error); /******/ } /******/ } /******/ }; /******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId); /******/ } /******/ } /******/ } /******/ }; /******/ /******/ // no prefetching /******/ /******/ // no preloaded /******/ /******/ // no HMR /******/ /******/ // no HMR manifest /******/ /******/ // no on chunks loaded /******/ /******/ // install a JSONP callback for chunk loading /******/ var webpackJsonpCallback = function(parentChunkLoadingFunction, data) { /******/ var chunkIds = data[0]; /******/ var moreModules = data[1]; /******/ var runtime = data[2]; /******/ // add "moreModules" to the modules object, /******/ // then flag all "chunkIds" as loaded and fire callback /******/ var moduleId, chunkId, i = 0; /******/ if(chunkIds.some(function(id) { return installedChunks[id] !== 0; })) { /******/ for(moduleId in moreModules) { /******/ if(__webpack_require__.o(moreModules, moduleId)) { /******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; /******/ } /******/ } /******/ if(runtime) var result = runtime(__webpack_require__); /******/ } /******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); /******/ for(;i < chunkIds.length; i++) { /******/ chunkId = chunkIds[i]; /******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { /******/ installedChunks[chunkId][0](); /******/ } /******/ installedChunks[chunkId] = 0; /******/ } /******/ /******/ } /******/ /******/ var chunkLoadingGlobal = self["webpackChunktinode_webapp"] = self["webpackChunktinode_webapp"] || []; /******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); /******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); /******/ }(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry needs to be wrapped in an IIFE because it needs to be in strict mode. !function() { "use strict"; /*!**********************!*\ !*** ./src/index.js ***! \**********************/ __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_dom_client__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-dom/client */ "./node_modules/react-dom/client.js"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _views_tinode_web_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./views/tinode-web.jsx */ "./src/views/tinode-web.jsx"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./lib/navigation.js */ "./src/lib/navigation.js"); if (typeof FIREBASE_INIT != 'undefined' && FIREBASE_INIT && FIREBASE_INIT.measurementId) { const head = document.getElementsByTagName('head')[0]; let script = document.createElement('script'); script.src = 'https://www.googletagmanager.com/gtag/js?id=' + FIREBASE_INIT.measurementId; script.async = true; head.prepend(script); window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments); } gtag('js', new Date()); gtag('config', FIREBASE_INIT.measurementId); } const messageLoader = { 'ar': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_ar_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/ar.json */ "./src/i18n.min/ar.json", 19)), 'de': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_de_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/de.json */ "./src/i18n.min/de.json", 19)), 'en': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_en_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/en.json */ "./src/i18n.min/en.json", 19)), 'es': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_es_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/es.json */ "./src/i18n.min/es.json", 19)), 'fr': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_fr_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/fr.json */ "./src/i18n.min/fr.json", 19)), 'it': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_it_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/it.json */ "./src/i18n.min/it.json", 19)), 'ko': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_ko_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/ko.json */ "./src/i18n.min/ko.json", 19)), 'ro': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_ro_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/ro.json */ "./src/i18n.min/ro.json", 19)), 'ru': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_ru_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/ru.json */ "./src/i18n.min/ru.json", 19)), 'th': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_th_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/th.json */ "./src/i18n.min/th.json", 19)), 'uk': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_uk_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/uk.json */ "./src/i18n.min/uk.json", 19)), 'vi': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_vi_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/vi.json */ "./src/i18n.min/vi.json", 19)), 'zh': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_zh_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/zh.json */ "./src/i18n.min/zh.json", 19)), 'zh-TW': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_zh-TW_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/zh-TW.json */ "./src/i18n.min/zh-TW.json", 19)) }; const rtl = ['ar', 'fa', 'he', 'ur']; const { params } = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_4__["default"].parseUrlHash(window.location.hash); const language = params && params.hl || navigator.languages && navigator.languages[0] || navigator.language || navigator.userLanguage || 'en'; const normalized = language.replace('_', '-'); const baseLanguage = normalized.split('-')[0].toLowerCase(); const htmlLang = messageLoader[normalized] ? language : messageLoader[baseLanguage] ? baseLanguage : 'en'; const html = document.getElementsByTagName('html')[0]; html.setAttribute('lang', htmlLang); if (rtl.includes(baseLanguage)) { html.setAttribute('dir', 'rtl'); } const root = (0,react_dom_client__WEBPACK_IMPORTED_MODULE_1__.createRoot)(document.getElementById('mountPoint')); messageLoader[htmlLang]().then(messages => root.render(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__.IntlProvider, { locale: language, messages: messages, textComponent: (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_views_tinode_web_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], null)))); }(); /******/ })() ; //# sourceMappingURL=index.dev.js.map