UNPKG

logbeacon

Version:

浏览器端日志采集与上报工具,支持多种日志服务后端,包括阿里云日志服务(SLS)和Grafana Loki

1 lines 34.8 kB
{"version":3,"file":"logs.cjs","sources":["../../../node_modules/.pnpm/loglevel@1.9.2/node_modules/loglevel/lib/loglevel.js","../../common/serializeLogContent.js","../../common/utils.js","../../core/logs.js"],"sourcesContent":["/*\n* loglevel - https://github.com/pimterry/loglevel\n*\n* Copyright (c) 2013 Tim Perry\n* Licensed under the MIT license.\n*/\n(function (root, definition) {\n \"use strict\";\n if (typeof define === 'function' && define.amd) {\n define(definition);\n } else if (typeof module === 'object' && module.exports) {\n module.exports = definition();\n } else {\n root.log = definition();\n }\n}(this, function () {\n \"use strict\";\n\n // Slightly dubious tricks to cut down minimized file size\n var noop = function() {};\n var undefinedType = \"undefined\";\n var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && (\n /Trident\\/|MSIE /.test(window.navigator.userAgent)\n );\n\n var logMethods = [\n \"trace\",\n \"debug\",\n \"info\",\n \"warn\",\n \"error\"\n ];\n\n var _loggersByName = {};\n var defaultLogger = null;\n\n // Cross-browser bind equivalent that works at least back to IE6\n function bindMethod(obj, methodName) {\n var method = obj[methodName];\n if (typeof method.bind === 'function') {\n return method.bind(obj);\n } else {\n try {\n return Function.prototype.bind.call(method, obj);\n } catch (e) {\n // Missing bind shim or IE8 + Modernizr, fallback to wrapping\n return function() {\n return Function.prototype.apply.apply(method, [obj, arguments]);\n };\n }\n }\n }\n\n // Trace() doesn't print the message in IE, so for that case we need to wrap it\n function traceForIE() {\n if (console.log) {\n if (console.log.apply) {\n console.log.apply(console, arguments);\n } else {\n // In old IE, native console methods themselves don't have apply().\n Function.prototype.apply.apply(console.log, [console, arguments]);\n }\n }\n if (console.trace) console.trace();\n }\n\n // Build the best logging method possible for this env\n // Wherever possible we want to bind, not wrap, to preserve stack traces\n function realMethod(methodName) {\n if (methodName === 'debug') {\n methodName = 'log';\n }\n\n if (typeof console === undefinedType) {\n return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives\n } else if (methodName === 'trace' && isIE) {\n return traceForIE;\n } else if (console[methodName] !== undefined) {\n return bindMethod(console, methodName);\n } else if (console.log !== undefined) {\n return bindMethod(console, 'log');\n } else {\n return noop;\n }\n }\n\n // These private functions always need `this` to be set properly\n\n function replaceLoggingMethods() {\n /*jshint validthis:true */\n var level = this.getLevel();\n\n // Replace the actual methods.\n for (var i = 0; i < logMethods.length; i++) {\n var methodName = logMethods[i];\n this[methodName] = (i < level) ?\n noop :\n this.methodFactory(methodName, level, this.name);\n }\n\n // Define log.log as an alias for log.debug\n this.log = this.debug;\n\n // Return any important warnings.\n if (typeof console === undefinedType && level < this.levels.SILENT) {\n return \"No console available for logging\";\n }\n }\n\n // In old IE versions, the console isn't present until you first open it.\n // We build realMethod() replacements here that regenerate logging methods\n function enableLoggingWhenConsoleArrives(methodName) {\n return function () {\n if (typeof console !== undefinedType) {\n replaceLoggingMethods.call(this);\n this[methodName].apply(this, arguments);\n }\n };\n }\n\n // By default, we use closely bound real methods wherever possible, and\n // otherwise we wait for a console to appear, and then try again.\n function defaultMethodFactory(methodName, _level, _loggerName) {\n /*jshint validthis:true */\n return realMethod(methodName) ||\n enableLoggingWhenConsoleArrives.apply(this, arguments);\n }\n\n function Logger(name, factory) {\n // Private instance variables.\n var self = this;\n /**\n * The level inherited from a parent logger (or a global default). We\n * cache this here rather than delegating to the parent so that it stays\n * in sync with the actual logging methods that we have installed (the\n * parent could change levels but we might not have rebuilt the loggers\n * in this child yet).\n * @type {number}\n */\n var inheritedLevel;\n /**\n * The default level for this logger, if any. If set, this overrides\n * `inheritedLevel`.\n * @type {number|null}\n */\n var defaultLevel;\n /**\n * A user-specific level for this logger. If set, this overrides\n * `defaultLevel`.\n * @type {number|null}\n */\n var userLevel;\n\n var storageKey = \"loglevel\";\n if (typeof name === \"string\") {\n storageKey += \":\" + name;\n } else if (typeof name === \"symbol\") {\n storageKey = undefined;\n }\n\n function persistLevelIfPossible(levelNum) {\n var levelName = (logMethods[levelNum] || 'silent').toUpperCase();\n\n if (typeof window === undefinedType || !storageKey) return;\n\n // Use localStorage if available\n try {\n window.localStorage[storageKey] = levelName;\n return;\n } catch (ignore) {}\n\n // Use session cookie as fallback\n try {\n window.document.cookie =\n encodeURIComponent(storageKey) + \"=\" + levelName + \";\";\n } catch (ignore) {}\n }\n\n function getPersistedLevel() {\n var storedLevel;\n\n if (typeof window === undefinedType || !storageKey) return;\n\n try {\n storedLevel = window.localStorage[storageKey];\n } catch (ignore) {}\n\n // Fallback to cookies if local storage gives us nothing\n if (typeof storedLevel === undefinedType) {\n try {\n var cookie = window.document.cookie;\n var cookieName = encodeURIComponent(storageKey);\n var location = cookie.indexOf(cookieName + \"=\");\n if (location !== -1) {\n storedLevel = /^([^;]+)/.exec(\n cookie.slice(location + cookieName.length + 1)\n )[1];\n }\n } catch (ignore) {}\n }\n\n // If the stored level is not valid, treat it as if nothing was stored.\n if (self.levels[storedLevel] === undefined) {\n storedLevel = undefined;\n }\n\n return storedLevel;\n }\n\n function clearPersistedLevel() {\n if (typeof window === undefinedType || !storageKey) return;\n\n // Use localStorage if available\n try {\n window.localStorage.removeItem(storageKey);\n } catch (ignore) {}\n\n // Use session cookie as fallback\n try {\n window.document.cookie =\n encodeURIComponent(storageKey) + \"=; expires=Thu, 01 Jan 1970 00:00:00 UTC\";\n } catch (ignore) {}\n }\n\n function normalizeLevel(input) {\n var level = input;\n if (typeof level === \"string\" && self.levels[level.toUpperCase()] !== undefined) {\n level = self.levels[level.toUpperCase()];\n }\n if (typeof level === \"number\" && level >= 0 && level <= self.levels.SILENT) {\n return level;\n } else {\n throw new TypeError(\"log.setLevel() called with invalid level: \" + input);\n }\n }\n\n /*\n *\n * Public logger API - see https://github.com/pimterry/loglevel for details\n *\n */\n\n self.name = name;\n\n self.levels = { \"TRACE\": 0, \"DEBUG\": 1, \"INFO\": 2, \"WARN\": 3,\n \"ERROR\": 4, \"SILENT\": 5};\n\n self.methodFactory = factory || defaultMethodFactory;\n\n self.getLevel = function () {\n if (userLevel != null) {\n return userLevel;\n } else if (defaultLevel != null) {\n return defaultLevel;\n } else {\n return inheritedLevel;\n }\n };\n\n self.setLevel = function (level, persist) {\n userLevel = normalizeLevel(level);\n if (persist !== false) { // defaults to true\n persistLevelIfPossible(userLevel);\n }\n\n // NOTE: in v2, this should call rebuild(), which updates children.\n return replaceLoggingMethods.call(self);\n };\n\n self.setDefaultLevel = function (level) {\n defaultLevel = normalizeLevel(level);\n if (!getPersistedLevel()) {\n self.setLevel(level, false);\n }\n };\n\n self.resetLevel = function () {\n userLevel = null;\n clearPersistedLevel();\n replaceLoggingMethods.call(self);\n };\n\n self.enableAll = function(persist) {\n self.setLevel(self.levels.TRACE, persist);\n };\n\n self.disableAll = function(persist) {\n self.setLevel(self.levels.SILENT, persist);\n };\n\n self.rebuild = function () {\n if (defaultLogger !== self) {\n inheritedLevel = normalizeLevel(defaultLogger.getLevel());\n }\n replaceLoggingMethods.call(self);\n\n if (defaultLogger === self) {\n for (var childName in _loggersByName) {\n _loggersByName[childName].rebuild();\n }\n }\n };\n\n // Initialize all the internal levels.\n inheritedLevel = normalizeLevel(\n defaultLogger ? defaultLogger.getLevel() : \"WARN\"\n );\n var initialLevel = getPersistedLevel();\n if (initialLevel != null) {\n userLevel = normalizeLevel(initialLevel);\n }\n replaceLoggingMethods.call(self);\n }\n\n /*\n *\n * Top-level API\n *\n */\n\n defaultLogger = new Logger();\n\n defaultLogger.getLogger = function getLogger(name) {\n if ((typeof name !== \"symbol\" && typeof name !== \"string\") || name === \"\") {\n throw new TypeError(\"You must supply a name when creating a logger.\");\n }\n\n var logger = _loggersByName[name];\n if (!logger) {\n logger = _loggersByName[name] = new Logger(\n name,\n defaultLogger.methodFactory\n );\n }\n return logger;\n };\n\n // Grab the current global log variable in case of overwrite\n var _log = (typeof window !== undefinedType) ? window.log : undefined;\n defaultLogger.noConflict = function() {\n if (typeof window !== undefinedType &&\n window.log === defaultLogger) {\n window.log = _log;\n }\n\n return defaultLogger;\n };\n\n defaultLogger.getLoggers = function getLoggers() {\n return _loggersByName;\n };\n\n // ES6 default export, for compatibility\n defaultLogger['default'] = defaultLogger;\n\n return defaultLogger;\n}));\n","/**\n * 日志内容序列化\n * @param {any[]} args - 需要序列化的参数数组\n * @returns {string} 序列化后的字符串\n */\nfunction serializeLogContent(args) {\n return args.map(arg => serializeSingleValue(arg)).join(\" \");\n}\n\n/**\n * 序列化单个值\n * @param {any} value - 需要序列化的值\n * @param {Object} options - 序列化选项\n * @param {number} options.maxDepth - 最大序列化深度,默认为 10\n * @param {number} options.maxLength - 序列化结果最大长度,默认为 10000\n * @param {string[]} options.sensitiveKeys - 敏感信息的键名,默认为 ['password', 'token', 'secret']\n * @param {number} [currentDepth=0] - 当前序列化深度\n * @returns {string} 序列化后的字符串\n */\nfunction serializeSingleValue(value, options = {}, currentDepth = 0) {\n const {\n maxDepth = 10,\n maxLength = 10000,\n sensitiveKeys = ['password', 'token', 'secret', 'auth']\n } = options;\n \n // 处理 undefined 和 null\n if (value === undefined) return 'undefined';\n if (value === null) return 'null';\n \n // 处理原始类型\n const type = typeof value;\n if (\n type === 'string' || \n type === 'number' || \n type === 'boolean'\n ) {\n return String(value);\n }\n \n // 处理 BigInt\n if (type === 'bigint') {\n return `${value.toString()}n`;\n }\n \n // 处理 Symbol\n if (type === 'symbol') {\n return value.toString();\n }\n \n // 如果已达到最大深度,返回类型信息\n if (currentDepth >= maxDepth) {\n return `[${Object.prototype.toString.call(value)}]`;\n }\n \n // 处理 Error 对象\n if (value instanceof Error) {\n return `${value.name}: ${value.message}\\nStack: ${value.stack || ''}`;\n }\n \n // 处理日期对象\n if (value instanceof Date) {\n return value.toISOString();\n }\n \n // 处理正则表达式\n if (value instanceof RegExp) {\n return value.toString();\n }\n \n // 处理函数\n if (type === 'function') {\n const fnStr = value.toString();\n return `Function: ${value.name || 'anonymous'} ${fnStr.slice(0, 100)}${fnStr.length > 100 ? '...' : ''}`;\n }\n \n // 处理特殊集合类型\n if (typeof Map !== 'undefined' && value instanceof Map) {\n const obj = {};\n value.forEach((v, k) => {\n // 将 Map 的键转换为字符串\n const keyStr = typeof k === 'object' && k !== null ? '[object]' : String(k);\n obj[keyStr] = v;\n });\n return serializeSingleValue(obj, options, currentDepth + 1);\n }\n \n if (typeof Set !== 'undefined' && value instanceof Set) {\n return serializeSingleValue(Array.from(value.values()), options, currentDepth + 1);\n }\n \n // 处理数组\n if (Array.isArray(value)) {\n const items = value.map(item => serializeSingleValue(item, options, currentDepth + 1));\n const result = `[${items.join(', ')}]`;\n return result.length > maxLength ? result.slice(0, maxLength) + '...' : result;\n }\n \n // 处理 DOM 元素 (浏览器环境)\n if (typeof window !== 'undefined' && typeof Element !== 'undefined' && value instanceof Element) {\n return `<${value.tagName.toLowerCase()}${value.id ? ` id=\"${value.id}\"` : ''}${value.className ? ` class=\"${value.className}\"` : ''}>`;\n }\n \n // 处理对象\n try {\n // 检查是否有自定义的 toJSON 方法\n if (value !== null && typeof value.toJSON === 'function') {\n return serializeSingleValue(value.toJSON(), options, currentDepth + 1);\n }\n \n // 使用 JSON.stringify 但处理循环引用和敏感信息\n const seen = new WeakSet();\n const result = JSON.stringify(value, function(key, val) {\n // 过滤敏感信息\n if (sensitiveKeys.includes(key.toLowerCase())) {\n return '[敏感信息已过滤]';\n }\n \n // 处理循环引用\n if (typeof val === 'object' && val !== null) {\n if (seen.has(val)) {\n return '[循环引用]';\n }\n seen.add(val);\n }\n \n return val;\n }, 2);\n \n // 截断过长的结果\n return result.length > maxLength ? result.slice(0, maxLength) + '...' : result;\n } catch (e) {\n // JSON.stringify 失败,尝试 toString\n try {\n if (value !== null && typeof value.toString === 'function' && value.toString !== Object.prototype.toString) {\n return value.toString();\n }\n } catch (e2) {\n // 如果 toString 也失败,使用 Object.prototype.toString\n return Object.prototype.toString.call(value);\n }\n \n // 最后的备选方案\n return String(value);\n }\n}\n\nexport {\n serializeLogContent,\n serializeSingleValue\n}","import { serializeLogContent, serializeSingleValue } from \"./serializeLogContent.js\";\n\n/**\n * 判断两个时间戳是否为同一天\n * @param {number} ts1 毫秒级时间戳\n * @param {number} ts2 毫秒级时间戳\n * @returns {boolean}\n */\nexport function isSameDay(ts1, ts2) {\n const d1 = new Date(ts1);\n const d2 = new Date(ts2);\n return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate();\n}\n\n/**\n * 请求公网IP和地区(使用 geojs)\n * @returns {Promise<{ip?: string, region?: string}>}\n */\nexport async function fetchPublicIPAndRegion() {\n try {\n const res = await fetch('https://get.geojs.io/v1/ip/geo.json');\n if (!res.ok) return {};\n const data = await res.json();\n const ip = data.ip;\n const region = data.country;\n return { ip, region };\n } catch (e) {\n return {};\n }\n}\n\n/**\n * 浏览器端获取/生成uuid 如果 window 不存在则返回空字符串\n * @returns {string}\n */\nexport function getOrCreateUUID() {\n if (typeof window === \"undefined\") return \"\";\n const key = \"_client_uuid\";\n let uuid = window.localStorage.getItem(key);\n if (!uuid) {\n if (window.crypto && window.crypto.randomUUID) {\n uuid = window.crypto.randomUUID();\n window.localStorage.setItem(key, uuid);\n } else {\n // fallback简单uuid\n uuid = Math.random().toString(36).substring(2) + Date.now().toString(36);\n window.localStorage.setItem(key, uuid);\n }\n }\n return uuid;\n}\n\n/**\n * 获取日志的附加信息\n * @typedef {Object} LogExtraInfo\n * @property {number} time - 日志生成的时间戳(毫秒级)\n * @property {string} clientUuid - 客户端唯一标识\n * @property {string} userAgent - 用户代理字符串\n * @property {Object} screen - 屏幕信息\n * @property {number} screen.width - 屏幕宽度\n * @property {number} screen.height - 屏幕高度\n * @property {Object} window - 窗口信息\n * @property {number} window.width - 窗口宽度\n * @property {number} window.height - 窗口高度\n * @property {string} url - 当前页面URL\n */\n\n/**\n * @returns {LogExtraInfo|Object} 如果 window 不存在则返回空对象,否则返回日志附加信息\n * @description 获取浏览器环境下的日志附加信息,如果非浏览器环境则返回空对象\n */\nexport function getLogExtraInfo() {\n if (typeof window === \"undefined\" || typeof window.document === \"undefined\") {\n return {};\n }\n const base = {\n time: Date.now(),\n clientUuid: getOrCreateUUID(),\n userAgent: window.navigator.userAgent,\n screen: serializeSingleValue({ width: window.screen.width, height: window.screen.height }),\n window: serializeSingleValue({ width: window.innerWidth, height: window.innerHeight }),\n url: window.location.href\n };\n return base;\n}\n\n/**\n * 获取指定作用域的 Service Worker\n * @param {string} scope - Service Worker 的作用域\n * @returns {Promise<ServiceWorker|null>} 激活的 Service Worker 或 null\n */\nexport async function getServiceWorker(scope = '/beacon/') {\n if (!navigator.serviceWorker) return null;\n \n try {\n const registrations = await navigator.serviceWorker.getRegistrations();\n // 查找匹配作用域的注册\n const swRegistration = registrations.find(reg => \n reg.scope.includes(scope)\n );\n \n if (!swRegistration) return null;\n \n // Service Worker 已经激活,直接返回\n if (swRegistration.active) return swRegistration.active;\n \n // 如果同时存在 installing 和 waiting,返回 null\n if (swRegistration.installing && swRegistration.waiting) return null;\n \n // Service Worker is installing or waiting for activation\n const worker = swRegistration.installing || swRegistration.waiting;\n if (!worker) return null;\n \n // Create a Promise to wait for Service Worker activation\n const waitForActivation = new Promise((resolve, reject) => {\n // Listen for state changes\n worker.addEventListener('statechange', function() {\n if (this.state === 'activated') {\n resolve(swRegistration.active);\n } else if (this.state === 'redundant') {\n // Service Worker 变为冗余状态(安装失败)\n reject(new Error('Service Worker installation failed'));\n }\n });\n });\n \n // 等待激活,最多等待 60 秒\n const timeout = new Promise((_, reject) => {\n setTimeout(() => reject(new Error('Service Worker activation timeout')), 60 * 1000);\n });\n \n return await Promise.race([waitForActivation, timeout]);\n } catch (e) {\n console.error('Failed to get Service Worker:', e);\n return null;\n }\n}\n\n/**\n * 发送日志到service worker\n * @param {\"trace\"|\"debug\"|\"info\"|\"warn\"|\"error\"} level - 日志等级\n * @param {any[]} logs - 需要发送的日志数组\n */\nexport async function sendLog(level, logs) {\n if (typeof window === \"undefined\") return;\n \n const extraInfo = getLogExtraInfo();\n const base = {\n level,\n content: serializeLogContent(logs),\n ...extraInfo\n };\n \n // 发送到 service worker,消息结构带 type\n const msg = {\n type: 'log',\n payload: base\n };\n\n try {\n // 获取指定作用域的 Service Worker\n const serviceWorker = await getServiceWorker('/beacon/');\n if (!serviceWorker) {\n const event = new CustomEvent('sendLog', {\n detail: msg\n });\n window.dispatchEvent(event)\n } else {\n serviceWorker.postMessage(msg);\n }\n } catch (e) {\n console.error('Failed to send logs to Service Worker:', e);\n }\n}\n\nexport const logFilter = {\n setKeyWords(keyWords) {\n if (typeof window === \"undefined\") return;\n if (typeof keyWords !== \"string\") return;\n window.localStorage.setItem(\"_logFilterKeyWords\", keyWords);\n },\n getKeyWords() {\n if (typeof window === \"undefined\") return \"\";\n return window.localStorage.getItem(\"_logFilterKeyWords\");\n },\n}\n\n","import loglevel from \"loglevel\";\nimport { sendLog, logFilter } from \"../common/utils.js\";\n\nconst LOG_METHODS = [\"trace\", \"debug\", \"info\", \"warn\", \"error\"];\n\n// 定义一个方法,这个方法返回使用一个proxy,proxy拦截函数执行\nconst proxyLoglevelFn = (fn, fnName) => {\n return new Proxy(fn, {\n apply: (target, thisArg, argumentsList) => {\n if (!LOG_METHODS.includes(fnName)) {\n return target.apply(thisArg, argumentsList);\n }\n if (fnName === 'setKeyWords') {\n return logFilter.setKeyWords(argumentsList[0]);\n }\n if (typeof window !== \"undefined\") {\n sendLog(fnName, argumentsList);\n }\n if (typeof argumentsList[0] !== \"string\") {\n return target.apply(thisArg, argumentsList);\n }\n const keyWords = logFilter.getKeyWords();\n if (!keyWords) {\n return target.apply(thisArg, argumentsList);\n }\n if (!argumentsList[0].startsWith(keyWords)) {\n return;\n }\n return target.apply(thisArg, argumentsList);\n }\n })\n}\n\nconst log = new Proxy(loglevel, {\n get(target, prop) {\n const orig = target[prop];\n if (typeof orig === 'function') {\n return proxyLoglevelFn(orig, prop);\n }\n return orig;\n }\n});\n\n\n\n\nif (typeof window === 'undefined') {\n let logLevel = typeof process !== 'undefined' && process.env && process.env.LOGS_LEVEL;\n logLevel = logLevel || loglevel.levels.TRACE;\n loglevel.setLevel(logLevel);\n}\n\nexport default log;\n"],"names":["root","definition","this","noop","isIE","window","navigator","test","userAgent","logMethods","_loggersByName","defaultLogger","bindMethod","obj","methodName","method","bind","Function","prototype","call","e","apply","arguments","traceForIE","console","log","trace","replaceLoggingMethods","level","getLevel","i","length","methodFactory","name","debug","levels","SILENT","enableLoggingWhenConsoleArrives","defaultMethodFactory","_level","_loggerName","undefined","realMethod","Logger","factory","inheritedLevel","defaultLevel","userLevel","self","storageKey","getPersistedLevel","storedLevel","localStorage","ignore","cookie","document","cookieName","encodeURIComponent","location","indexOf","exec","slice","normalizeLevel","input","toUpperCase","TypeError","TRACE","DEBUG","INFO","WARN","ERROR","setLevel","persist","levelNum","levelName","persistLevelIfPossible","setDefaultLevel","resetLevel","removeItem","clearPersistedLevel","enableAll","disableAll","rebuild","childName","initialLevel","getLogger","logger","_log","noConflict","getLoggers","module","exports","serializeSingleValue","value","options","currentDepth","maxDepth","maxLength","sensitiveKeys","type","String","toString","Object","Error","message","stack","Date","toISOString","RegExp","fnStr","Map","forEach","v","k","keyStr","Set","Array","from","values","isArray","result","map","item","join","Element","tagName","toLowerCase","id","className","toJSON","seen","WeakSet","JSON","stringify","key","val","includes","has","add","e2","getOrCreateUUID","uuid","getItem","crypto","randomUUID","setItem","Math","random","substring","now","async","sendLog","logs","extraInfo","time","clientUuid","screen","width","height","innerWidth","innerHeight","url","href","args","msg","payload","content","arg","serviceWorker","scope","swRegistration","getRegistrations","find","reg","active","installing","waiting","worker","waitForActivation","Promise","resolve","reject","addEventListener","state","timeout","_","setTimeout","race","getServiceWorker","postMessage","event","CustomEvent","detail","dispatchEvent","logFilter","setKeyWords","keyWords","getKeyWords","LOG_METHODS","Proxy","loglevel","get","target","prop","orig","fnName","thisArg","argumentsList","startsWith","logLevel","process","env","LOGS_LEVEL"],"mappings":"uVAMC,IAAUA,KAAMC,WAAND,KASTE,eATeD,WAST,WAIJ,IAAIE,KAAO,aAEPC,KADgB,oBACDC,aADC,IACoCA,OAAOC,WAC3D,kBAAkBC,KAAKF,OAAOC,UAAUE,WAGxCC,WAAa,CACb,QACA,QACA,OACA,OACA,SAGAC,eAAiB,CAAA,EACjBC,cAAgB,KAGpB,SAASC,WAAWC,IAAKC,YACrB,IAAIC,OAASF,IAAIC,YACjB,GAA2B,mBAAhBC,OAAOC,KACd,OAAOD,OAAOC,KAAKH,KAEnB,IACI,OAAOI,SAASC,UAAUF,KAAKG,KAAKJ,OAAQF,IAC/C,CAAC,MAAOO,GAEL,OAAO,WACH,OAAOH,SAASC,UAAUG,MAAMA,MAAMN,OAAQ,CAACF,IAAKS,WACxE,CACa,CAER,CAGD,SAASC,aACDC,QAAQC,MACJD,QAAQC,IAAIJ,OAIZJ,SAASC,UAAUG,MAAMA,MAAMG,QAAQC,IAAK,CAACD,QAASF,aAG1DE,QAAQE,KACf,CAwBD,SAASC,wBAKL,IAHA,IAAIC,MAAQ1B,KAAK2B,WAGRC,EAAI,EAAGA,EAAIrB,WAAWsB,OAAQD,IAAK,CACxC,IAAIhB,WAAaL,WAAWqB,GAC5B5B,KAAKY,YAAegB,EAAIF,MACpBzB,KACAD,KAAK8B,cAAclB,WAAYc,MAAO1B,KAAK+B,KAClD,CAMD,GAHA/B,KAAKuB,IAAMvB,KAAKgC,MAjFA,oBAoFLV,SAA6BI,MAAQ1B,KAAKiC,OAAOC,OACxD,MAAO,kCAEd,CAID,SAASC,gCAAgCvB,YACrC,OAAO,WA5FS,oBA6FDU,UACPG,sBAAsBR,KAAKjB,MAC3BA,KAAKY,YAAYO,MAAMnB,KAAMoB,WAE7C,CACK,CAID,SAASgB,qBAAqBxB,WAAYyB,OAAQC,aAE9C,OAxDJ,SAAoB1B,YAKhB,MAJmB,UAAfA,aACAA,WAAa,OAlDD,oBAqDLU,UAEe,UAAfV,YAA0BV,KAC1BmB,gBACwBkB,IAAxBjB,QAAQV,YACRF,WAAWY,QAASV,iBACJ2B,IAAhBjB,QAAQC,IACRb,WAAWY,QAAS,OAEpBrB,KAEd,CAwCUuC,CAAW5B,aACXuB,gCAAgChB,MAAMnB,KAAMoB,UACtD,CAED,SAASqB,OAAOV,KAAMW,SAEpB,IASIC,eAMAC,aAMAC,UArBAC,KAAO9C,KAuBP+C,WAAa,WAyBjB,SAASC,oBACL,IAAIC,YAEJ,GAjKc,oBAiKH9C,QAA6B4C,WAAxC,CAEA,IACIE,YAAc9C,OAAO+C,aAAaH,WAChD,CAAY,MAAOI,QAAU,CAGnB,QAxKc,IAwKHF,YACP,IACI,IAAIG,OAASjD,OAAOkD,SAASD,OACzBE,WAAaC,mBAAmBR,YAChCS,SAAWJ,OAAOK,QAAQH,WAAa,MACzB,IAAdE,WACAP,YAAc,WAAWS,KACrBN,OAAOO,MAAMH,SAAWF,WAAWzB,OAAS,IAC9C,GAExB,CAAgB,MAAOsB,QAAU,CAQvB,YAJiCZ,IAA7BO,KAAKb,OAAOgB,eACZA,iBAAcV,GAGXU,WAzBoD,CA0B9D,CAiBD,SAASW,eAAeC,OACpB,IAAInC,MAAQmC,MAIZ,GAHqB,iBAAVnC,YAA2Da,IAArCO,KAAKb,OAAOP,MAAMoC,iBAC/CpC,MAAQoB,KAAKb,OAAOP,MAAMoC,gBAET,iBAAVpC,OAAsBA,OAAS,GAAKA,OAASoB,KAAKb,OAAOC,OAChE,OAAOR,MAEP,MAAM,IAAIqC,UAAU,6CAA+CF,MAE1E,CAhFmB,iBAAT9B,KACTgB,YAAc,IAAMhB,KACK,iBAATA,OAChBgB,gBAAaR,GAqFfO,KAAKf,KAAOA,KAEZe,KAAKb,OAAS,CAAE+B,MAAS,EAAGC,MAAS,EAAGC,KAAQ,EAAGC,KAAQ,EACvDC,MAAS,EAAGlC,OAAU,GAE1BY,KAAKhB,cAAgBY,SAAWN,qBAEhCU,KAAKnB,SAAW,WACZ,OAAiB,MAAbkB,UACKA,UACkB,MAAhBD,aACFA,aAEAD,cAEnB,EAEMG,KAAKuB,SAAW,SAAU3C,MAAO4C,SAO7B,OANAzB,UAAYe,eAAelC,QACX,IAAZ4C,SArGR,SAAgCC,UAC5B,IAAIC,WAAajE,WAAWgE,WAAa,UAAUT,cAEnD,GA/Ic,oBA+IH3D,QAA6B4C,WAAxC,CAGA,IAEI,YADA5C,OAAO+C,aAAaH,YAAcyB,UAEhD,CAAY,MAAOrB,QAAU,CAGnB,IACIhD,OAAOkD,SAASD,OACdG,mBAAmBR,YAAc,IAAMyB,UAAY,GACnE,CAAY,MAAOrB,QAAU,CAZwC,CAa9D,CAsFOsB,CAAuB5B,WAIpBpB,sBAAsBR,KAAK6B,KAC5C,EAEMA,KAAK4B,gBAAkB,SAAUhD,OAC7BkB,aAAegB,eAAelC,OACzBsB,qBACDF,KAAKuB,SAAS3C,OAAO,EAEnC,EAEMoB,KAAK6B,WAAa,WACd9B,UAAY,KApEhB,WACI,GA9Lc,oBA8LH1C,QAA6B4C,WAAxC,CAGA,IACI5C,OAAO+C,aAAa0B,WAAW7B,WAC7C,CAAY,MAAOI,QAAU,CAGnB,IACIhD,OAAOkD,SAASD,OACdG,mBAAmBR,YAAc,0CACjD,CAAY,MAAOI,QAAU,CAXwC,CAY9D,CAwDG0B,GACApD,sBAAsBR,KAAK6B,KACrC,EAEMA,KAAKgC,UAAY,SAASR,SACtBxB,KAAKuB,SAASvB,KAAKb,OAAO+B,MAAOM,QAC3C,EAEMxB,KAAKiC,WAAa,SAAST,SACvBxB,KAAKuB,SAASvB,KAAKb,OAAOC,OAAQoC,QAC5C,EAEMxB,KAAKkC,QAAU,WAMX,GALIvE,gBAAkBqC,OAClBH,eAAiBiB,eAAenD,cAAckB,aAElDF,sBAAsBR,KAAK6B,MAEvBrC,gBAAkBqC,KAClB,IAAK,IAAImC,aAAazE,eACpBA,eAAeyE,WAAWD,SAG1C,EAGMrC,eAAiBiB,eACbnD,cAAgBA,cAAckB,WAAa,QAE/C,IAAIuD,aAAelC,oBACC,MAAhBkC,eACArC,UAAYe,eAAesB,eAE/BzD,sBAAsBR,KAAK6B,KAC5B,EAQDrC,cAAgB,IAAIgC,QAEN0C,UAAY,SAAmBpD,MACzC,GAAqB,iBAATA,MAAqC,iBAATA,MAA+B,KAATA,KAC1D,MAAM,IAAIgC,UAAU,kDAGxB,IAAIqB,OAAS5E,eAAeuB,MAO5B,OANKqD,SACDA,OAAS5E,eAAeuB,MAAQ,IAAIU,OAChCV,KACAtB,cAAcqB,gBAGfsD,MACf,EAGI,IAAIC,KA9TgB,oBA8TDlF,OAA4BA,OAAOoB,SAAMgB,EAiB5D,OAhBA9B,cAAc6E,WAAa,WAMvB,MArUgB,oBAgULnF,QACJA,OAAOoB,MAAQd,gBAClBN,OAAOoB,IAAM8D,MAGV5E,aACf,EAEIA,cAAc8E,WAAa,WACvB,OAAO/E,cACf,EAGIC,cAAuB,QAAIA,cAEpBA,aACX,EA1V6C+E,OAAOC,QAC5CD,OAAAC,QAAiB1F,aAEjBD,KAAKyB,IAAMxB,mFCMnB,SAAS2F,qBAAqBC,MAAOC,QAAU,CAAA,EAAIC,aAAe,GAChE,MAAMC,SACJA,SAAW,GAAEC,UACbA,UAAY,IAAKC,cACjBA,cAAgB,CAAC,WAAY,QAAS,SAAU,SAC9CJ,QAGJ,QAAcrD,IAAVoD,MAAqB,MAAO,YAChC,GAAc,OAAVA,MAAgB,MAAO,OAG3B,MAAMM,YAAcN,MACpB,GACW,WAATM,MACS,WAATA,MACS,YAATA,KAEA,OAAOC,OAAOP,OAIhB,GAAa,WAATM,KACF,MAAO,GAAGN,MAAMQ,cAIlB,GAAa,WAATF,KACF,OAAON,MAAMQ,WAIf,GAAIN,cAAgBC,SAClB,MAAO,IAAIM,OAAOpF,UAAUmF,SAASlF,KAAK0E,UAI5C,GAAIA,iBAAiBU,MACnB,MAAO,GAAGV,MAAM5D,SAAS4D,MAAMW,mBAAmBX,MAAMY,OAAS,KAInE,GAAIZ,iBAAiBa,KACnB,OAAOb,MAAMc,cAIf,GAAId,iBAAiBe,OACnB,OAAOf,MAAMQ,WAIf,GAAa,aAATF,KAAqB,CACvB,MAAMU,MAAQhB,MAAMQ,WACpB,MAAO,aAAaR,MAAM5D,MAAQ,eAAe4E,MAAMhD,MAAM,EAAG,OAAOgD,MAAM9E,OAAS,IAAM,MAAQ,IACrG,CAGD,GAAmB,oBAAR+E,KAAuBjB,iBAAiBiB,IAAK,CACtD,MAAMjG,IAAM,CAAA,EAMZ,OALAgF,MAAMkB,SAAQ,CAACC,EAAGC,KAEhB,MAAMC,OAAsB,iBAAND,GAAwB,OAANA,EAAa,WAAab,OAAOa,GACzEpG,IAAIqG,QAAUF,CAAC,IAEVpB,qBAAqB/E,IAAKiF,QAASC,aAAe,EAC1D,CAED,GAAmB,oBAARoB,KAAuBtB,iBAAiBsB,IACjD,OAAOvB,qBAAqBwB,MAAMC,KAAKxB,MAAMyB,UAAWxB,QAASC,aAAe,GAIlF,GAAIqB,MAAMG,QAAQ1B,OAAQ,CACxB,MACM2B,OAAS,IADD3B,MAAM4B,KAAIC,MAAQ9B,qBAAqB8B,KAAM5B,QAASC,aAAe,KAC1D4B,KAAK,SAC9B,OAAOH,OAAOzF,OAASkE,UAAYuB,OAAO3D,MAAM,EAAGoC,WAAa,MAAQuB,MACzE,CAGD,GAAsB,oBAAXnH,QAA6C,oBAAZuH,SAA2B/B,iBAAiB+B,QACtF,MAAO,IAAI/B,MAAMgC,QAAQC,gBAAgBjC,MAAMkC,GAAK,QAAQlC,MAAMkC,MAAQ,KAAKlC,MAAMmC,UAAY,WAAWnC,MAAMmC,aAAe,MAInI,IAEE,GAAc,OAAVnC,OAA0C,mBAAjBA,MAAMoC,OACjC,OAAOrC,qBAAqBC,MAAMoC,SAAUnC,QAASC,aAAe,GAItE,MAAMmC,KAAO,IAAIC,QACXX,OAASY,KAAKC,UAAUxC,OAAO,SAASyC,IAAKC,KAEjD,GAAIrC,cAAcsC,SAASF,IAAIR,eAC7B,MAAO,YAIT,GAAmB,iBAARS,KAA4B,OAARA,IAAc,CAC3C,GAAIL,KAAKO,IAAIF,KACX,MAAO,SAETL,KAAKQ,IAAIH,IACV,CAED,OAAOA,GACR,GAAE,GAGH,OAAOf,OAAOzF,OAASkE,UAAYuB,OAAO3D,MAAM,EAAGoC,WAAa,MAAQuB,MACzE,CAAC,MAAOpG,GAEP,IACE,GAAc,OAAVyE,OAA4C,mBAAnBA,MAAMQ,UAA2BR,MAAMQ,WAAaC,OAAOpF,UAAUmF,SAChG,OAAOR,MAAMQ,UAEhB,CAAC,MAAOsC,IAEP,OAAOrC,OAAOpF,UAAUmF,SAASlF,KAAK0E,MACvC,CAGD,OAAOO,OAAOP,MACf,CACH,CC9GO,SAAS+C,kBACd,GAAsB,oBAAXvI,OAAwB,MAAO,GAC1C,MAAMiI,IAAM,eACZ,IAAIO,KAAOxI,OAAO+C,aAAa0F,QAAQR,KAWvC,OAVKO,OACCxI,OAAO0I,QAAU1I,OAAO0I,OAAOC,YACjCH,KAAOxI,OAAO0I,OAAOC,aACrB3I,OAAO+C,aAAa6F,QAAQX,IAAKO,QAGjCA,KAAOK,KAAKC,SAAS9C,SAAS,IAAI+C,UAAU,GAAK1C,KAAK2C,MAAMhD,SAAS,IACrEhG,OAAO+C,aAAa6F,QAAQX,IAAKO,QAG9BA,IACT,CA6FOS,eAAeC,QAAQ3H,MAAO4H,MACnC,GAAsB,oBAAXnJ,OAAwB,OAEnC,MAAMoJ,UA1EgB,oBAAXpJ,aAAqD,IAApBA,OAAOkD,SAC1C,GAEI,CACXmG,KAAMhD,KAAK2C,MACXM,WAAYf,kBACZpI,UAAWH,OAAOC,UAAUE,UAC5BoJ,OAAQhE,qBAAqB,CAAEiE,MAAOxJ,OAAOuJ,OAAOC,MAAOC,OAAQzJ,OAAOuJ,OAAOE,SACjFzJ,OAAQuF,qBAAqB,CAAEiE,MAAOxJ,OAAO0J,WAAYD,OAAQzJ,OAAO2J,cACxEC,IAAK5J,OAAOqD,SAASwG,MD5EzB,IAA6BC,KCqJ3B,MAAMC,IAAM,CACVjE,KAAM,MACNkE,QATW,CACXzI,YACA0I,SDhJyBH,KCgJIX,KD/IxBW,KAAK1C,KAAI8C,KAAO3E,qBAAqB2E,OAAM5C,KAAK,SCgJlD8B,YASL,IAEE,MAAMe,oBAtEHlB,eAAgCmB,MAAQ,YAC7C,IAAKnK,UAAUkK,cAAe,OAAO,KAErC,IACE,MAEME,sBAFsBpK,UAAUkK,cAAcG,oBAEfC,MAAKC,KACxCA,IAAIJ,MAAMjC,SAASiC,SAGrB,IAAKC,eAAgB,OAAO,KAG5B,GAAIA,eAAeI,OAAQ,OAAOJ,eAAeI,OAGjD,GAAIJ,eAAeK,YAAcL,eAAeM,QAAS,OAAO,KAGhE,MAAMC,OAASP,eAAeK,YAAcL,eAAeM,QAC3D,IAAKC,OAAQ,OAAO,KAGpB,MAAMC,kBAAoB,IAAIC,SAAQ,CAACC,QAASC,UAE9CJ,OAAOK,iBAAiB,eAAe,WAClB,cAAfpL,KAAKqL,MACPH,QAAQV,eAAeI,QACC,cAAf5K,KAAKqL,OAEdF,OAAO,IAAI9E,MAAM,sCAE3B,GAAQ,IAIEiF,QAAU,IAAIL,SAAQ,CAACM,EAAGJ,UAC9BK,YAAW,IAAML,OAAO,IAAI9E,MAAM,uCAAuC,IAAU,IAGrF,aAAa4E,QAAQQ,KAAK,CAACT,kBAAmBM,SAC/C,CAAC,MAAOpK,GAEP,OAAO,IACR,CACH,CAyBgCwK,CAAiB,YAC7C,GAAKpB,cAMHA,cAAcqB,YAAYzB,SANR,CAClB,MAAM0B,MAAQ,IAAIC,YAAY,UAAW,CACvCC,OAAQ5B,MAEV/J,OAAO4L,cAAcH,MAC3B,CAGG,CAAC,MAAO1K,GAER,CACH,CAEO,MAAM8K,UAAY,CACvB,WAAAC,CAAYC,UACY,oBAAX/L,QACa,iBAAb+L,UACX/L,OAAO+C,aAAa6F,QAAQ,qBAAsBmD,SACnD,EACDC,YAAW,IACa,oBAAXhM,OAA+B,GACnCA,OAAO+C,aAAa0F,QAAQ,uBCpLjCwD,YAAc,CAAC,QAAS,QAAS,OAAQ,OAAQ,SA8BjD7K,IAAM,IAAI8K,MAAMC,SAAU,CAC9B,GAAAC,CAAIC,OAAQC,MACV,MAAMC,KAAOF,OAAOC,MACpB,MAAoB,mBAATC,MA9BcC,OA+BMF,KA9B1B,IAAIJ,MA8BgBK,KA9BN,CACnBvL,MAAO,CAACqL,OAAQI,QAASC,iBACvB,IAAKT,YAAY9D,SAASqE,QACxB,OAAOH,OAAOrL,MAAMyL,QAASC,eAE/B,GAAe,gBAAXF,OACF,OAAOX,UAAUC,YAAYY,cAAc,IAK7C,GAHsB,oBAAX1M,QACTkJ,QAAQsD,OAAQE,eAEc,iBAArBA,cAAc,GACvB,OAAOL,OAAOrL,MAAMyL,QAASC,eAE/B,MAAMX,SAAWF,UAAUG,cAC3B,OAAKD,SAGAW,cAAc,GAAGC,WAAWZ,UAG1BM,OAAOrL,MAAMyL,QAASC,oBAH7B,EAFSL,OAAOrL,MAAMyL,QAASC,cAKY,KAWtCH,KAjCa,IAAKC,MAkC1B,IAMH,GAAsB,oBAAXxM,OAAwB,CACjC,IAAI4M,SAA8B,oBAAZC,SAA2BA,QAAQC,KAAOD,QAAQC,IAAIC,WAC5EH,SAAWA,UAAYT,SAASrK,OAAO+B,MACvCsI,SAASjI,SAAS0I,SACpB","x_google_ignoreList":[0]}