UNPKG

logbeacon

Version:

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

1 lines 68.7 kB
const ARRAY_SAMPLING_CONFIG={primitive:{threshold:20,head:10,tail:4,middle:3},complex:{threshold:10,head:5,tail:3,middle:2}},browserTypeHandlers=new Map;function serializeLogContent(content){const serializableObject=serializeSingleValue(content);try{const result=JSON.stringify(serializableObject);return result.length>1e5?result.slice(0,1e5)+"...":result}catch(e){return`[序列化失败: ${e.message}]`}}function serializeSingleValue(value,options={maxDepth:10,sensitiveKeys:["password","token","secret","auth"]},currentDepth=0,seen=new WeakSet){const{maxDepth:maxDepth,sensitiveKeys:sensitiveKeys}=options,type=typeof value;if(null===value||["string","number","boolean","undefined"].includes(type))return value;if("bigint"===type)return`${value.toString()}n`;if("symbol"===type)return value.toString();if("function"===type)return`[Function: ${value.name||"anonymous"}]`;if("object"==typeof value){if(seen.has(value))return"[循环引用]";seen.add(value)}if(currentDepth>=maxDepth)return`[达到最大深度: ${Object.prototype.toString.call(value)}]`;for(const[typeConstructor,handler]of browserTypeHandlers.entries())if(value instanceof typeConstructor)return handler(value,options,currentDepth,seen);if(value instanceof Error)return`${value.name}: ${value.message}\nStack: ${value.stack||""}`;if(value instanceof Date)return value.toISOString();if(value instanceof RegExp)return value.toString();if("undefined"!=typeof Map&&value instanceof Map){const obj={};for(const[k,v]of value.entries()){obj["object"==typeof k&&null!==k?"[object]":String(k)]=serializeSingleValue(v,options,currentDepth+1,seen)}return obj}if("undefined"!=typeof Set&&value instanceof Set){const arr=[];for(const v of value.values())arr.push(serializeSingleValue(v,options,currentDepth+1,seen));return arr}if(Array.isArray(value)){const rules=value.length>0&&"object"==typeof value[0]&&null!==value[0]?ARRAY_SAMPLING_CONFIG.complex:ARRAY_SAMPLING_CONFIG.primitive;if(value.length<=rules.threshold)return value.map((item=>serializeSingleValue(item,options,currentDepth+1,seen)));const sampledResult={_t:"arr",_l:value.length,_e:{}},indices=new Set;for(let i=0;i<rules.head&&i<value.length;i++)indices.add(i);for(let i=0;i<rules.tail&&value.length-1-i>=0;i++)indices.add(value.length-1-i);const midStart=Math.floor(value.length/2-rules.middle/2);for(let i=0;i<rules.middle&&midStart+i<value.length;i++)indices.add(midStart+i);const sortedIndices=Array.from(indices).sort(((a,b)=>a-b));for(const index of sortedIndices)sampledResult._e[index]=serializeSingleValue(value[index],options,currentDepth+1,seen);return sampledResult}if("undefined"!=typeof window&&value instanceof window.Element)return`<${value.tagName.toLowerCase()} class="${value.className}" id="${value.id}">`;if("object"==typeof value&&null!==value){if("function"==typeof value.toJSON)return serializeSingleValue(value.toJSON(),options,currentDepth+1,seen);const result={};for(const key of Object.keys(value))sensitiveKeys.includes(key.toLowerCase())?result[key]="[敏感信息已过滤]":result[key]=serializeSingleValue(value[key],options,currentDepth+1,seen);return result}return String(value)}function getOrCreateUUID(){if("undefined"==typeof window)return"";const key="_client_uuid";let uuid=window.localStorage.getItem(key);return uuid||(window.crypto&&window.crypto.randomUUID?(uuid=window.crypto.randomUUID(),window.localStorage.setItem(key,uuid)):(uuid=function(){let uuid="";for(let i=0;i<32;i++)uuid+=12===i?"4":16===i?"0123456789abcdef"[8+Math.floor(4*Math.random())]:"0123456789abcdef"[Math.floor(16*Math.random())];return[uuid.substring(0,8),uuid.substring(8,12),uuid.substring(12,16),uuid.substring(16,20),uuid.substring(20,32)].join("-")}(),window.localStorage.setItem(key,uuid))),uuid}function getOrCreateSessionId(){if("undefined"==typeof window)return"";const key="_session_id";let sessionId=window.sessionStorage.getItem(key);return sessionId||(sessionId=function(){let uuid;if("undefined"!=typeof crypto&&crypto.randomUUID)uuid=crypto.randomUUID();else{const hexChars="0123456789ABCDEF";uuid="";for(let i=0;i<32;i++)uuid+=hexChars[Math.floor(16*Math.random())]}return uuid.replace(/-/g,"").toUpperCase().substring(0,16)}(),window.sessionStorage.setItem(key,sessionId)),sessionId}function getLogExtraInfo(){if("undefined"==typeof window||void 0===window.document)return{};const extendedAttributes={};if(window.LOGS_CONTEXT&&"object"==typeof window.LOGS_CONTEXT)for(const[key,value]of Object.entries(window.LOGS_CONTEXT))"string"==typeof value&&value.trim().length>0&&(extendedAttributes[key]=value);return{time:Date.now(),clientUuid:getOrCreateUUID(),userAgent:window.navigator.userAgent,screen:JSON.stringify(serializeSingleValue({width:window.screen.width,height:window.screen.height})),window:JSON.stringify(serializeSingleValue({width:window.innerWidth,height:window.innerHeight})),url:window.location.href,referrer:document.referrer,sessionId:getOrCreateSessionId(),extendedAttributes:extendedAttributes}}"undefined"!=typeof window&&(browserTypeHandlers.set(window.ErrorEvent,((value,options,currentDepth,seen)=>({_t:"ErrorEvent",message:value.message,filename:value.filename,lineno:value.lineno,colno:value.colno,error:serializeSingleValue(value.error,options,currentDepth+1,seen)}))),browserTypeHandlers.set(window.PromiseRejectionEvent,((value,options,currentDepth,seen)=>({_t:"PromiseRejectionEvent",reason:serializeSingleValue(value.reason,options,currentDepth+1,seen)}))),browserTypeHandlers.set(window.MessageEvent,((value,options,currentDepth,seen)=>({_t:"MessageEvent",data:serializeSingleValue(value.data,options,currentDepth+1,seen),origin:value.origin,lastEventId:value.lastEventId,source:"[WindowProxy]"}))),browserTypeHandlers.set(window.CloseEvent,((value,options,currentDepth,seen)=>({_t:"CloseEvent",code:value.code,reason:value.reason,wasClean:value.wasClean}))),browserTypeHandlers.set(window.CustomEvent,((value,options,currentDepth,seen)=>({_t:"CustomEvent",type:value.type,detail:serializeSingleValue(value.detail,options,currentDepth+1,seen),bubbles:value.bubbles,cancelable:value.cancelable,composed:value.composed}))),browserTypeHandlers.set(window.KeyboardEvent,((value,options,currentDepth,seen)=>({_t:"KeyboardEvent",type:value.type,key:value.key,code:value.code,ctrlKey:value.ctrlKey,shiftKey:value.shiftKey,altKey:value.altKey,metaKey:value.metaKey,repeat:value.repeat,bubbles:value.bubbles,cancelable:value.cancelable}))),browserTypeHandlers.set(window.InputEvent,((value,options,currentDepth,seen)=>({_t:"InputEvent",type:value.type,inputType:value.inputType,data:value.data,isComposing:value.isComposing,bubbles:value.bubbles,cancelable:value.cancelable}))),browserTypeHandlers.set(window.StorageEvent,((value,options,currentDepth,seen)=>({_t:"StorageEvent",type:value.type,key:value.key,newValue:value.newValue,oldValue:value.oldValue,url:value.url,storageArea:"[Storage]",bubbles:value.bubbles,cancelable:value.cancelable}))));const instanceOfAny=(object,constructors)=>constructors.some((c=>object instanceof c));let idbProxyableTypes,cursorAdvanceMethods;const transactionDoneMap=new WeakMap,transformCache=new WeakMap,reverseTransformCache=new WeakMap;let idbProxyTraps={get(target,prop,receiver){if(target instanceof IDBTransaction){if("done"===prop)return transactionDoneMap.get(target);if("store"===prop)return receiver.objectStoreNames[1]?void 0:receiver.objectStore(receiver.objectStoreNames[0])}return wrap(target[prop])},set:(target,prop,value)=>(target[prop]=value,!0),has:(target,prop)=>target instanceof IDBTransaction&&("done"===prop||"store"===prop)||prop in target};function replaceTraps(callback){idbProxyTraps=callback(idbProxyTraps)}function wrapFunction(func){return(cursorAdvanceMethods||(cursorAdvanceMethods=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])).includes(func)?function(...args){return func.apply(unwrap(this),args),wrap(this.request)}:function(...args){return wrap(func.apply(unwrap(this),args))}}function transformCachableValue(value){return"function"==typeof value?wrapFunction(value):(value instanceof IDBTransaction&&function(tx){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)},complete=()=>{resolve(),unlisten()},error=()=>{reject(tx.error||new DOMException("AbortError","AbortError")),unlisten()};tx.addEventListener("complete",complete),tx.addEventListener("error",error),tx.addEventListener("abort",error)}));transactionDoneMap.set(tx,done)}(value),instanceOfAny(value,idbProxyableTypes||(idbProxyableTypes=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction]))?new Proxy(value,idbProxyTraps):value)}function wrap(value){if(value instanceof IDBRequest)return function(request){const promise=new Promise(((resolve,reject)=>{const unlisten=()=>{request.removeEventListener("success",success),request.removeEventListener("error",error)},success=()=>{resolve(wrap(request.result)),unlisten()},error=()=>{reject(request.error),unlisten()};request.addEventListener("success",success),request.addEventListener("error",error)}));return reverseTransformCache.set(promise,request),promise}(value);if(transformCache.has(value))return transformCache.get(value);const newValue=transformCachableValue(value);return newValue!==value&&(transformCache.set(value,newValue),reverseTransformCache.set(newValue,value)),newValue}const unwrap=value=>reverseTransformCache.get(value);const readMethods=["get","getKey","getAll","getAllKeys","count"],writeMethods=["put","add","delete","clear"],cachedMethods=new Map;function getMethod(target,prop){if(!(target instanceof IDBDatabase)||prop in target||"string"!=typeof prop)return;if(cachedMethods.get(prop))return cachedMethods.get(prop);const targetFuncName=prop.replace(/FromIndex$/,""),useIndex=prop!==targetFuncName,isWrite=writeMethods.includes(targetFuncName);if(!(targetFuncName in(useIndex?IDBIndex:IDBObjectStore).prototype)||!isWrite&&!readMethods.includes(targetFuncName))return;const method=async function(storeName,...args){const tx=this.transaction(storeName,isWrite?"readwrite":"readonly");let target=tx.store;return useIndex&&(target=target.index(args.shift())),(await Promise.all([target[targetFuncName](...args),isWrite&&tx.done]))[0]};return cachedMethods.set(prop,method),method}replaceTraps((oldTraps=>({...oldTraps,get:(target,prop,receiver)=>getMethod(target,prop)||oldTraps.get(target,prop,receiver),has:(target,prop)=>!!getMethod(target,prop)||oldTraps.has(target,prop)})));const advanceMethodProps=["continue","continuePrimaryKey","advance"],methodMap={},advanceResults=new WeakMap,ittrProxiedCursorToOriginalProxy=new WeakMap,cursorIteratorTraps={get(target,prop){if(!advanceMethodProps.includes(prop))return target[prop];let cachedFunc=methodMap[prop];return cachedFunc||(cachedFunc=methodMap[prop]=function(...args){advanceResults.set(this,ittrProxiedCursorToOriginalProxy.get(this)[prop](...args))}),cachedFunc}};async function*iterate(...args){let cursor=this;if(cursor instanceof IDBCursor||(cursor=await cursor.openCursor(...args)),!cursor)return;const proxiedCursor=new Proxy(cursor,cursorIteratorTraps);for(ittrProxiedCursorToOriginalProxy.set(proxiedCursor,cursor),reverseTransformCache.set(proxiedCursor,unwrap(cursor));cursor;)yield proxiedCursor,cursor=await(advanceResults.get(proxiedCursor)||cursor.continue()),advanceResults.delete(proxiedCursor)}function isIteratorProp(target,prop){return prop===Symbol.asyncIterator&&instanceOfAny(target,[IDBIndex,IDBObjectStore,IDBCursor])||"iterate"===prop&&instanceOfAny(target,[IDBIndex,IDBObjectStore])}replaceTraps((oldTraps=>({...oldTraps,get:(target,prop,receiver)=>isIteratorProp(target,prop)?iterate:oldTraps.get(target,prop,receiver),has:(target,prop)=>isIteratorProp(target,prop)||oldTraps.has(target,prop)})));class LogStore{_dbPromise=null;constructor(){this._initDB()}_initDB(){this._dbPromise=function(name,version,{blocked:blocked,upgrade:upgrade,blocking:blocking,terminated:terminated}={}){const request=indexedDB.open(name,version),openPromise=wrap(request);return upgrade&&request.addEventListener("upgradeneeded",(event=>{upgrade(wrap(request.result),event.oldVersion,event.newVersion,wrap(request.transaction),event)})),blocked&&request.addEventListener("blocked",(event=>blocked(event.oldVersion,event.newVersion,event))),openPromise.then((db=>{terminated&&db.addEventListener("close",(()=>terminated())),blocking&&db.addEventListener("versionchange",(event=>blocking(event.oldVersion,event.newVersion,event)))})).catch((()=>{})),openPromise}("beacon-db",1,{upgrade(db){if(db.objectStoreNames.contains("b_dat")||db.createObjectStore("b_dat",{keyPath:"id",autoIncrement:!0}),!db.objectStoreNames.contains("digestCache")){db.createObjectStore("digestCache",{keyPath:"digest"}).createIndex("by_timestamp","timestamp")}db.objectStoreNames.contains("meta")||db.createObjectStore("meta")}})}async _getDB(){return this._dbPromise||this._initDB(),this._dbPromise}_encode(data){return(new TextEncoder).encode(data)}_decode(buffer){return buffer?(new TextDecoder).decode(buffer):null}async insertLog(logData){return(await this._getDB()).add("b_dat",logData)}async getAllLogs(){return(await this._getDB()).getAll("b_dat")}async clearLogs(){const db=await this._getDB();await db.clear("b_dat")}async setDigest(digest,timestamp){return(await this._getDB()).put("digestCache",{digest:digest,timestamp:timestamp})}async getAllDigests(){return(await this._getDB()).getAll("digestCache")}async clearOldDigests(maxAgeTimestamp){const tx=(await this._getDB()).transaction("digestCache","readwrite"),index=tx.store.index("by_timestamp");let cursor=await index.openCursor(IDBKeyRange.upperBound(maxAgeTimestamp));for(;cursor;)await cursor.delete(),cursor=await cursor.continue();await tx.done}async setMeta(key,value){const db=await this._getDB(),encodedValue=this._encode(value);return db.put("meta",encodedValue,key)}async getMeta(key){const db=await this._getDB(),encodedValue=await db.get("meta",key);return this._decode(encodedValue)}async getAllMeta(){const tx=(await this._getDB()).transaction("meta","readonly"),store=tx.store,allMeta={};let cursor=await store.openCursor();for(;cursor;)allMeta[cursor.key]=this._decode(cursor.value),cursor=await cursor.continue();return await tx.done,allMeta}async hydrateState(){const[logs,digests,deviceInfo,logContext]=await Promise.all([this.getAllLogs(),this.getAllDigests(),this.getMeta("deviceInfo"),this.getMeta("logContext")]);return{logs:logs,digests:digests,deviceInfo:deviceInfo,logContext:logContext}}}var props,TYPEOF_FUNCTION="function",TYPEOF_OBJECT="object",TYPEOF_STRING="string",TYPEOF_UNDEFINED="undefined",BROWSER="browser",CPU="cpu",DEVICE="device",ENGINE="engine",OS="os",NAME="name",TYPE="type",VENDOR="vendor",VERSION="version",ARCHITECTURE="architecture",MODEL="model",MOBILE="mobile",TABLET="tablet",SMARTTV="smarttv",CH="sec-ch-ua",CH_FULL_VER_LIST=CH+"-full-version-list",CH_ARCH=CH+"-arch",CH_BITNESS=CH+"-bitness",CH_FORM_FACTORS=CH+"-form-factors",CH_MOBILE=CH+"-"+MOBILE,CH_MODEL=CH+"-"+MODEL,CH_PLATFORM=CH+"-platform",CH_PLATFORM_VER=CH_PLATFORM+"-version",CH_ALL_VALUES=["brands","fullVersionList",MOBILE,MODEL,"platform","platformVersion",ARCHITECTURE,"formFactors","bitness"],NAVIGATOR=typeof window!==TYPEOF_UNDEFINED&&window.navigator?window.navigator:void 0,NAVIGATOR_UADATA=NAVIGATOR&&NAVIGATOR.userAgentData?NAVIGATOR.userAgentData:void 0,enumerize=function(arr){for(var enums={},i=0;i<arr.length;i++)enums[arr[i].toUpperCase()]=arr[i];return enums},has=function(str1,str2){if(typeof str1===TYPEOF_OBJECT&&str1.length>0){for(var i in str1)if(lowerize(str2)==lowerize(str1[i]))return!0;return!1}return!!isString(str1)&&lowerize(str2)==lowerize(str1)},isExtensions=function(obj,deep){for(var prop in obj)return/^(browser|cpu|device|engine|os)$/.test(prop)||!!deep&&isExtensions(obj[prop])},isString=function(val){return typeof val===TYPEOF_STRING},itemListToArray=function(header){if(header){for(var arr=[],tokens=strip(/\\?\"/g,header).split(","),i=0;i<tokens.length;i++)if(tokens[i].indexOf(";")>-1){var token=trim(tokens[i]).split(";v=");arr[i]={brand:token[0],version:token[1]}}else arr[i]=trim(tokens[i]);return arr}},lowerize=function(str){return isString(str)?str.toLowerCase():str},majorize=function(version){return isString(version)?strip(/[^\d\.]/g,version).split(".")[0]:void 0},setProps=function(arr){for(var i in arr)if(arr.hasOwnProperty(i)){var propName=arr[i];typeof propName==TYPEOF_OBJECT&&2==propName.length?this[propName[0]]=propName[1]:this[propName]=void 0}return this},strip=function(pattern,str){return isString(str)?str.replace(pattern,""):str},stripQuotes=function(str){return strip(/\\?\"/g,str)},trim=function(str,len){return str=strip(/^\s\s*/,String(str)),typeof len===TYPEOF_UNDEFINED?str:str.substring(0,len)},rgxMapper=function(ua,arrays){if(ua&&arrays)for(var j,k,p,q,matches,match,i=0;i<arrays.length&&!matches;){var regex=arrays[i],props=arrays[i+1];for(j=k=0;j<regex.length&&!matches&&regex[j];)if(matches=regex[j++].exec(ua))for(p=0;p<props.length;p++)match=matches[++k],typeof(q=props[p])===TYPEOF_OBJECT&&q.length>0?2===q.length?typeof q[1]==TYPEOF_FUNCTION?this[q[0]]=q[1].call(this,match):this[q[0]]=q[1]:q.length>=3&&(typeof q[1]!==TYPEOF_FUNCTION||q[1].exec&&q[1].test?3==q.length?this[q[0]]=match?match.replace(q[1],q[2]):void 0:4==q.length?this[q[0]]=match?q[3].call(this,match.replace(q[1],q[2])):void 0:q.length>4&&(this[q[0]]=match?q[3].apply(this,[match.replace(q[1],q[2])].concat(q.slice(4))):void 0):q.length>3?this[q[0]]=match?q[1].apply(this,q.slice(2)):void 0:this[q[0]]=match?q[1].call(this,match,q[2]):void 0):this[q]=match||void 0;i+=2}},strMapper=function(str,map){for(var i in map)if(typeof map[i]===TYPEOF_OBJECT&&map[i].length>0){for(var j=0;j<map[i].length;j++)if(has(map[i][j],str))return"?"===i?void 0:i}else if(has(map[i],str))return"?"===i?void 0:i;return map.hasOwnProperty("*")?map["*"]:str},windowsVersionMap={ME:"4.90","NT 3.51":"3.51","NT 4.0":"4.0",2e3:["5.0","5.01"],XP:["5.1","5.2"],Vista:"6.0",7:"6.1",8:"6.2",8.1:"6.3",10:["6.4","10.0"],NT:""},formFactorsMap={embedded:"Automotive",mobile:"Mobile",tablet:["Tablet","EInk"],smarttv:"TV",wearable:"Watch",xr:["VR","XR"],"?":["Desktop","Unknown"],"*":void 0},browserHintsMap={Chrome:"Google Chrome",Edge:"Microsoft Edge","Edge WebView2":"Microsoft Edge WebView2","Chrome WebView":"Android WebView","Chrome Headless":"HeadlessChrome","Huawei Browser":"HuaweiBrowser","MIUI Browser":"Miui Browser","Opera Mobi":"OperaMobile",Yandex:"YaBrowser"},defaultRegexes={browser:[[/\b(?:crmo|crios)\/([\w\.]+)/i],[VERSION,[NAME,"Mobile Chrome"]],[/webview.+edge\/([\w\.]+)/i],[VERSION,[NAME,"Edge WebView"]],[/edg(?:e|ios|a)?\/([\w\.]+)/i],[VERSION,[NAME,"Edge"]],[/(opera mini)\/([-\w\.]+)/i,/(opera [mobiletab]{3,6})\b.+version\/([-\w\.]+)/i,/(opera)(?:.+version\/|[\/ ]+)([\w\.]+)/i],[NAME,VERSION],[/opios[\/ ]+([\w\.]+)/i],[VERSION,[NAME,"Opera Mini"]],[/\bop(?:rg)?x\/([\w\.]+)/i],[VERSION,[NAME,"Opera GX"]],[/\bopr\/([\w\.]+)/i],[VERSION,[NAME,"Opera"]],[/\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\/ ]?([\w\.]+)/i],[VERSION,[NAME,"Baidu"]],[/\b(?:mxbrowser|mxios|myie2)\/?([-\w\.]*)\b/i],[VERSION,[NAME,"Maxthon"]],[/(kindle)\/([\w\.]+)/i,/(lunascape|maxthon|netfront|jasmine|blazer|sleipnir)[\/ ]?([\w\.]*)/i,/(avant|iemobile|slim(?:browser|boat|jet))[\/ ]?([\d\.]*)/i,/(?:ms|\()(ie) ([\w\.]+)/i,/(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:lg |qute)browser|palemoon)\/([-\w\.]+)/i,/(heytap|ovi|115|surf|qwant)browser\/([\d\.]+)/i,/(qwant)(?:ios|mobile)\/([\d\.]+)/i,/(ecosia|weibo)(?:__| \w+@)([\d\.]+)/i],[NAME,VERSION],[/quark(?:pc)?\/([-\w\.]+)/i],[VERSION,[NAME,"Quark"]],[/\bddg\/([\w\.]+)/i],[VERSION,[NAME,"DuckDuckGo"]],[/(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i],[VERSION,[NAME,"UCBrowser"]],[/microm.+\bqbcore\/([\w\.]+)/i,/\bqbcore\/([\w\.]+).+microm/i,/micromessenger\/([\w\.]+)/i],[VERSION,[NAME,"WeChat"]],[/konqueror\/([\w\.]+)/i],[VERSION,[NAME,"Konqueror"]],[/trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i],[VERSION,[NAME,"IE"]],[/ya(?:search)?browser\/([\w\.]+)/i],[VERSION,[NAME,"Yandex"]],[/slbrowser\/([\w\.]+)/i],[VERSION,[NAME,"Smart Lenovo Browser"]],[/(avast|avg)\/([\w\.]+)/i],[[NAME,/(.+)/,"$1 Secure Browser"],VERSION],[/\bfocus\/([\w\.]+)/i],[VERSION,[NAME,"Firefox Focus"]],[/\bopt\/([\w\.]+)/i],[VERSION,[NAME,"Opera Touch"]],[/coc_coc\w+\/([\w\.]+)/i],[VERSION,[NAME,"Coc Coc"]],[/dolfin\/([\w\.]+)/i],[VERSION,[NAME,"Dolphin"]],[/coast\/([\w\.]+)/i],[VERSION,[NAME,"Opera Coast"]],[/miuibrowser\/([\w\.]+)/i],[VERSION,[NAME,"MIUI Browser"]],[/fxios\/([\w\.-]+)/i],[VERSION,[NAME,"Mobile Firefox"]],[/\bqihoobrowser\/?([\w\.]*)/i],[VERSION,[NAME,"360"]],[/\b(qq)\/([\w\.]+)/i],[[NAME,/(.+)/,"$1Browser"],VERSION],[/(oculus|sailfish|huawei|vivo|pico)browser\/([\w\.]+)/i],[[NAME,/(.+)/,"$1 Browser"],VERSION],[/samsungbrowser\/([\w\.]+)/i],[VERSION,[NAME,"Samsung Internet"]],[/metasr[\/ ]?([\d\.]+)/i],[VERSION,[NAME,"Sogou Explorer"]],[/(sogou)mo\w+\/([\d\.]+)/i],[[NAME,"Sogou Mobile"],VERSION],[/(electron)\/([\w\.]+) safari/i,/(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i,/m?(qqbrowser|2345(?=browser|chrome|explorer))\w*[\/ ]?v?([\w\.]+)/i],[NAME,VERSION],[/(lbbrowser|rekonq)/i],[NAME],[/ome\/([\w\.]+) \w* ?(iron) saf/i,/ome\/([\w\.]+).+qihu (360)[es]e/i],[VERSION,NAME],[/((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i],[[NAME,"Facebook"],VERSION,[TYPE,"inapp"]],[/(kakao(?:talk|story))[\/ ]([\w\.]+)/i,/(naver)\(.*?(\d+\.[\w\.]+).*\)/i,/(daum)apps[\/ ]([\w\.]+)/i,/safari (line)\/([\w\.]+)/i,/\b(line)\/([\w\.]+)\/iab/i,/(alipay)client\/([\w\.]+)/i,/(twitter)(?:and| f.+e\/([\w\.]+))/i,/(bing)(?:web|sapphire)\/([\w\.]+)/i,/(instagram|snapchat|klarna)[\/ ]([-\w\.]+)/i],[NAME,VERSION,[TYPE,"inapp"]],[/\bgsa\/([\w\.]+) .*safari\//i],[VERSION,[NAME,"GSA"],[TYPE,"inapp"]],[/musical_ly(?:.+app_?version\/|_)([\w\.]+)/i],[VERSION,[NAME,"TikTok"],[TYPE,"inapp"]],[/\[(linkedin)app\]/i],[NAME,[TYPE,"inapp"]],[/(zalo(?:app)?)[\/\sa-z]*([\w\.-]+)/i],[[NAME,/(.+)/,"Zalo"],VERSION,[TYPE,"inapp"]],[/(chromium)[\/ ]([-\w\.]+)/i],[NAME,VERSION],[/headlesschrome(?:\/([\w\.]+)| )/i],[VERSION,[NAME,"Chrome Headless"]],[/wv\).+chrome\/([\w\.]+).+edgw\//i],[VERSION,[NAME,"Edge WebView2"]],[/ wv\).+(chrome)\/([\w\.]+)/i],[[NAME,"Chrome WebView"],VERSION],[/droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i],[VERSION,[NAME,"Android Browser"]],[/chrome\/([\w\.]+) mobile/i],[VERSION,[NAME,"Mobile Chrome"]],[/(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i],[NAME,VERSION],[/version\/([\w\.\,]+) .*mobile(?:\/\w+ | ?)safari/i],[VERSION,[NAME,"Mobile Safari"]],[/iphone .*mobile(?:\/\w+ | ?)safari/i],[[NAME,"Mobile Safari"]],[/version\/([\w\.\,]+) .*(safari)/i],[VERSION,NAME],[/webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i],[NAME,[VERSION,"1"]],[/(webkit|khtml)\/([\w\.]+)/i],[NAME,VERSION],[/(?:mobile|tablet);.*(firefox)\/([\w\.-]+)/i],[[NAME,"Mobile Firefox"],VERSION],[/(navigator|netscape\d?)\/([-\w\.]+)/i],[[NAME,"Netscape"],VERSION],[/(wolvic|librewolf)\/([\w\.]+)/i],[NAME,VERSION],[/mobile vr; rv:([\w\.]+)\).+firefox/i],[VERSION,[NAME,"Firefox Reality"]],[/ekiohf.+(flow)\/([\w\.]+)/i,/(swiftfox)/i,/(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror)[\/ ]?([\w\.\+]+)/i,/(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|basilisk|waterfox)\/([-\w\.]+)$/i,/(firefox)\/([\w\.]+)/i,/(mozilla)\/([\w\.]+(?= .+rv\:.+gecko\/\d+)|[0-4][\w\.]+(?!.+compatible))/i,/(amaya|dillo|doris|icab|ladybird|lynx|mosaic|netsurf|obigo|polaris|w3m|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i,/\b(links) \(([\w\.]+)/i],[NAME,[VERSION,/_/g,"."]],[/(cobalt)\/([\w\.]+)/i],[NAME,[VERSION,/[^\d\.]+./,""]]],cpu:[[/\b((amd|x|x86[-_]?|wow|win)64)\b/i],[[ARCHITECTURE,"amd64"]],[/(ia32(?=;))/i,/\b((i[346]|x)86)(pc)?\b/i],[[ARCHITECTURE,"ia32"]],[/\b(aarch64|arm(v?[89]e?l?|_?64))\b/i],[[ARCHITECTURE,"arm64"]],[/\b(arm(v[67])?ht?n?[fl]p?)\b/i],[[ARCHITECTURE,"armhf"]],[/( (ce|mobile); ppc;|\/[\w\.]+arm\b)/i],[[ARCHITECTURE,"arm"]],[/ sun4\w[;\)]/i],[[ARCHITECTURE,"sparc"]],[/\b(avr32|ia64(?=;)|68k(?=\))|\barm(?=v([1-7]|[5-7]1)l?|;|eabi)|(irix|mips|sparc)(64)?\b|pa-risc)/i,/((ppc|powerpc)(64)?)( mac|;|\))/i,/(?:osf1|[freopnt]{3,4}bsd) (alpha)/i],[[ARCHITECTURE,/ower/,"",lowerize]],[/mc680.0/i],[[ARCHITECTURE,"68k"]],[/winnt.+\[axp/i],[[ARCHITECTURE,"alpha"]]],device:[[/\b(sch-i[89]0\d|shw-m380s|sm-[ptx]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus 10)/i],[MODEL,[VENDOR,"Samsung"],[TYPE,TABLET]],[/\b((?:s[cgp]h|gt|sm)-(?![lr])\w+|sc[g-]?[\d]+a?|galaxy nexus)/i,/samsung[- ]((?!sm-[lr]|browser)[-\w]+)/i,/sec-(sgh\w+)/i],[MODEL,[VENDOR,"Samsung"],[TYPE,MOBILE]],[/(?:\/|\()(ip(?:hone|od)[\w, ]*)[\/\);]/i],[MODEL,[VENDOR,"Apple"],[TYPE,MOBILE]],[/\b(?:ios|apple\w+)\/.+[\(\/](ipad)/i,/\b(ipad)[\d,]*[;\] ].+(mac |i(pad)?)os/i],[MODEL,[VENDOR,"Apple"],[TYPE,TABLET]],[/(macintosh);/i],[MODEL,[VENDOR,"Apple"]],[/\b(sh-?[altvz]?\d\d[a-ekm]?)/i],[MODEL,[VENDOR,"Sharp"],[TYPE,MOBILE]],[/\b((?:brt|eln|hey2?|gdi|jdn)-a?[lnw]09|(?:ag[rm]3?|jdn2|kob2)-a?[lw]0[09]hn)(?: bui|\)|;)/i],[MODEL,[VENDOR,"Honor"],[TYPE,TABLET]],[/honor([-\w ]+)[;\)]/i],[MODEL,[VENDOR,"Honor"],[TYPE,MOBILE]],[/\b((?:ag[rs][2356]?k?|bah[234]?|bg[2o]|bt[kv]|cmr|cpn|db[ry]2?|jdn2|got|kob2?k?|mon|pce|scm|sht?|[tw]gr|vrd)-[ad]?[lw][0125][09]b?|605hw|bg2-u03|(?:gem|fdr|m2|ple|t1)-[7a]0[1-4][lu]|t1-a2[13][lw]|mediapad[\w\. ]*(?= bui|\)))\b(?!.+d\/s)/i],[MODEL,[VENDOR,"Huawei"],[TYPE,TABLET]],[/(?:huawei) ?([-\w ]+)[;\)]/i,/\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][\dc][adnt]?)\b(?!.+d\/s)/i],[MODEL,[VENDOR,"Huawei"],[TYPE,MOBILE]],[/oid[^\)]+; (2[\dbc]{4}(182|283|rp\w{2})[cgl]|m2105k81a?c)(?: bui|\))/i,/\b(?:xiao)?((?:red)?mi[-_ ]?pad[\w- ]*)(?: bui|\))/i],[[MODEL,/_/g," "],[VENDOR,"Xiaomi"],[TYPE,TABLET]],[/\b(poco[\w ]+|m2\d{3}j\d\d[a-z]{2})(?: bui|\))/i,/\b; (\w+) build\/hm\1/i,/\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i,/\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i,/oid[^\)]+; (m?[12][0-389][01]\w{3,6}[c-y])( bui|; wv|\))/i,/\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note|max|cc)?[_ ]?(?:\d{0,2}\w?)[_ ]?(?:plus|se|lite|pro)?( 5g|lte)?)(?: bui|\))/i,/ ([\w ]+) miui\/v?\d/i],[[MODEL,/_/g," "],[VENDOR,"Xiaomi"],[TYPE,MOBILE]],[/droid.+; (cph2[3-6]\d[13579]|((gm|hd)19|(ac|be|in|kb)20|(d[en]|eb|le|mt)21|ne22)[0-2]\d|p[g-k]\w[1m]10)\b/i,/(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i],[MODEL,[VENDOR,"OnePlus"],[TYPE,MOBILE]],[/; (\w+) bui.+ oppo/i,/\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i],[MODEL,[VENDOR,"OPPO"],[TYPE,MOBILE]],[/\b(opd2(\d{3}a?))(?: bui|\))/i],[MODEL,[VENDOR,strMapper,{OnePlus:["203","304","403","404","413","415"],"*":"OPPO"}],[TYPE,TABLET]],[/(vivo (5r?|6|8l?|go|one|s|x[il]?[2-4]?)[\w\+ ]*)(?: bui|\))/i],[MODEL,[VENDOR,"BLU"],[TYPE,MOBILE]],[/; vivo (\w+)(?: bui|\))/i,/\b(v[12]\d{3}\w?[at])(?: bui|;)/i],[MODEL,[VENDOR,"Vivo"],[TYPE,MOBILE]],[/\b(rmx[1-3]\d{3})(?: bui|;|\))/i],[MODEL,[VENDOR,"Realme"],[TYPE,MOBILE]],[/(ideatab[-\w ]+|602lv|d-42a|a101lv|a2109a|a3500-hv|s[56]000|pb-6505[my]|tb-?x?\d{3,4}(?:f[cu]|xu|[av])|yt\d?-[jx]?\d+[lfmx])( bui|;|\)|\/)/i,/lenovo ?(b[68]0[08]0-?[hf]?|tab(?:[\w- ]+?)|tb[\w-]{6,7})( bui|;|\)|\/)/i],[MODEL,[VENDOR,"Lenovo"],[TYPE,TABLET]],[/lenovo[-_ ]?([-\w ]+?)(?: bui|\)|\/)/i],[MODEL,[VENDOR,"Lenovo"],[TYPE,MOBILE]],[/\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i,/\bmot(?:orola)?[- ]([\w\s]+)(\)| bui)/i,/((?:moto(?! 360)[-\w\(\) ]+|xt\d{3,4}[cgkosw\+]?[-\d]*|nexus 6)(?= bui|\)))/i],[MODEL,[VENDOR,"Motorola"],[TYPE,MOBILE]],[/\b(mz60\d|xoom[2 ]{0,2}) build\//i],[MODEL,[VENDOR,"Motorola"],[TYPE,TABLET]],[/((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i],[MODEL,[VENDOR,"LG"],[TYPE,TABLET]],[/(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i,/\blg[-e;\/ ]+(?!.*(?:browser|netcast|android tv|watch|webos))(\w+)/i,/\blg-?([\d\w]+) bui/i],[MODEL,[VENDOR,"LG"],[TYPE,MOBILE]],[/(nokia) (t[12][01])/i],[VENDOR,MODEL,[TYPE,TABLET]],[/(?:maemo|nokia).*(n900|lumia \d+|rm-\d+)/i,/nokia[-_ ]?(([-\w\. ]*?))( bui|\)|;|\/)/i],[[MODEL,/_/g," "],[TYPE,MOBILE],[VENDOR,"Nokia"]],[/(pixel (c|tablet))\b/i],[MODEL,[VENDOR,"Google"],[TYPE,TABLET]],[/droid.+;(?: google)? (g(01[13]a|020[aem]|025[jn]|1b60|1f8f|2ybb|4s1m|576d|5nz6|8hhn|8vou|a02099|c15s|d1yq|e2ae|ec77|gh2x|kv4x|p4bc|pj41|r83y|tt9q|ur25|wvk6)|pixel[\d ]*a?( pro)?( xl)?( fold)?( \(5g\))?)( bui|\))/i],[MODEL,[VENDOR,"Google"],[TYPE,MOBILE]],[/(google) (pixelbook( go)?)/i],[VENDOR,MODEL],[/droid.+; (a?\d[0-2]{2}so|[c-g]\d{4}|so[-gl]\w+|xq-\w\w\d\d)(?= bui|\).+chrome\/(?![1-6]{0,1}\d\.))/i],[MODEL,[VENDOR,"Sony"],[TYPE,MOBILE]],[/sony tablet [ps]/i,/\b(?:sony)?sgp\w+(?: bui|\))/i],[[MODEL,"Xperia Tablet"],[VENDOR,"Sony"],[TYPE,TABLET]],[/(alexa)webm/i,/(kf[a-z]{2}wi|aeo(?!bc)\w\w)( bui|\))/i,/(kf[a-z]+)( bui|\)).+silk\//i],[MODEL,[VENDOR,"Amazon"],[TYPE,TABLET]],[/((?:sd|kf)[0349hijorstuw]+)( bui|\)).+silk\//i],[[MODEL,/(.+)/g,"Fire Phone $1"],[VENDOR,"Amazon"],[TYPE,MOBILE]],[/(playbook);[-\w\),; ]+(rim)/i],[MODEL,VENDOR,[TYPE,TABLET]],[/\b((?:bb[a-f]|st[hv])100-\d)/i,/(?:blackberry|\(bb10;) (\w+)/i],[MODEL,[VENDOR,"BlackBerry"],[TYPE,MOBILE]],[/(?:\b|asus_)(transfo[prime ]{4,10} \w+|eeepc|slider \w+|nexus 7|padfone|p00[cj])/i],[MODEL,[VENDOR,"ASUS"],[TYPE,TABLET]],[/ (z[bes]6[027][012][km][ls]|zenfone \d\w?)\b/i],[MODEL,[VENDOR,"ASUS"],[TYPE,MOBILE]],[/(nexus 9)/i],[MODEL,[VENDOR,"HTC"],[TYPE,TABLET]],[/(htc)[-;_ ]{1,2}([\w ]+(?=\)| bui)|\w+)/i,/(zte)[- ]([\w ]+?)(?: bui|\/|\))/i,/(alcatel|geeksphone|nexian|panasonic(?!(?:;|\.))|sony(?!-bra))[-_ ]?([-\w]*)/i],[VENDOR,[MODEL,/_/g," "],[TYPE,MOBILE]],[/tcl (xess p17aa)/i,/droid [\w\.]+; ((?:8[14]9[16]|9(?:0(?:48|60|8[01])|1(?:3[27]|66)|2(?:6[69]|9[56])|466))[gqswx])(_\w(\w|\w\w))?(\)| bui)/i],[MODEL,[VENDOR,"TCL"],[TYPE,TABLET]],[/droid [\w\.]+; (418(?:7d|8v)|5087z|5102l|61(?:02[dh]|25[adfh]|27[ai]|56[dh]|59k|65[ah])|a509dl|t(?:43(?:0w|1[adepqu])|50(?:6d|7[adju])|6(?:09dl|10k|12b|71[efho]|76[hjk])|7(?:66[ahju]|67[hw]|7[045][bh]|71[hk]|73o|76[ho]|79w|81[hks]?|82h|90[bhsy]|99b)|810[hs]))(_\w(\w|\w\w))?(\)| bui)/i],[MODEL,[VENDOR,"TCL"],[TYPE,MOBILE]],[/(itel) ((\w+))/i],[[VENDOR,lowerize],MODEL,[TYPE,strMapper,{tablet:["p10001l","w7001"],"*":"mobile"}]],[/droid.+; ([ab][1-7]-?[0178a]\d\d?)/i],[MODEL,[VENDOR,"Acer"],[TYPE,TABLET]],[/droid.+; (m[1-5] note) bui/i,/\bmz-([-\w]{2,})/i],[MODEL,[VENDOR,"Meizu"],[TYPE,MOBILE]],[/; ((?:power )?armor(?:[\w ]{0,8}))(?: bui|\))/i],[MODEL,[VENDOR,"Ulefone"],[TYPE,MOBILE]],[/; (energy ?\w+)(?: bui|\))/i,/; energizer ([\w ]+)(?: bui|\))/i],[MODEL,[VENDOR,"Energizer"],[TYPE,MOBILE]],[/; cat (b35);/i,/; (b15q?|s22 flip|s48c|s62 pro)(?: bui|\))/i],[MODEL,[VENDOR,"Cat"],[TYPE,MOBILE]],[/((?:new )?andromax[\w- ]+)(?: bui|\))/i],[MODEL,[VENDOR,"Smartfren"],[TYPE,MOBILE]],[/droid.+; (a(in)?(0(15|59|6[35])|142)p?)/i],[MODEL,[VENDOR,"Nothing"],[TYPE,MOBILE]],[/; (x67 5g|tikeasy \w+|ac[1789]\d\w+)( b|\))/i,/archos ?(5|gamepad2?|([\w ]*[t1789]|hello) ?\d+[\w ]*)( b|\))/i],[MODEL,[VENDOR,"Archos"],[TYPE,TABLET]],[/archos ([\w ]+)( b|\))/i,/; (ac[3-6]\d\w{2,8})( b|\))/i],[MODEL,[VENDOR,"Archos"],[TYPE,MOBILE]],[/; (n159v)/i],[MODEL,[VENDOR,"HMD"],[TYPE,MOBILE]],[/(imo) (tab \w+)/i,/(infinix|tecno) (x1101b?|p904|dp(7c|8d|10a)( pro)?|p70[1-3]a?|p904|t1101)/i],[VENDOR,MODEL,[TYPE,TABLET]],[/(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus(?! zenw)|dell|jolla|meizu|motorola|polytron|tecno|micromax|advan)[-_ ]?([-\w]*)/i,/; (blu|hmd|imo|infinix|lava|oneplus|tcl|wiko)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i,/(hp) ([\w ]+\w)/i,/(microsoft); (lumia[\w ]+)/i,/(oppo) ?([\w ]+) bui/i,/(hisense) ([ehv][\w ]+)\)/i,/droid[^;]+; (philips)[_ ]([sv-x][\d]{3,4}[xz]?)/i],[VENDOR,MODEL,[TYPE,MOBILE]],[/(kobo)\s(ereader|touch)/i,/(hp).+(touchpad(?!.+tablet)|tablet)/i,/(kindle)\/([\w\.]+)/i],[VENDOR,MODEL,[TYPE,TABLET]],[/(surface duo)/i],[MODEL,[VENDOR,"Microsoft"],[TYPE,TABLET]],[/droid [\d\.]+; (fp\du?)(?: b|\))/i],[MODEL,[VENDOR,"Fairphone"],[TYPE,MOBILE]],[/((?:tegranote|shield t(?!.+d tv))[\w- ]*?)(?: b|\))/i],[MODEL,[VENDOR,"Nvidia"],[TYPE,TABLET]],[/(sprint) (\w+)/i],[VENDOR,MODEL,[TYPE,MOBILE]],[/(kin\.[onetw]{3})/i],[[MODEL,/\./g," "],[VENDOR,"Microsoft"],[TYPE,MOBILE]],[/droid.+; ([c6]+|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i],[MODEL,[VENDOR,"Zebra"],[TYPE,TABLET]],[/droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i],[MODEL,[VENDOR,"Zebra"],[TYPE,MOBILE]],[/(philips)[\w ]+tv/i,/smart-tv.+(samsung)/i],[VENDOR,[TYPE,SMARTTV]],[/hbbtv.+maple;(\d+)/i],[[MODEL,/^/,"SmartTV"],[VENDOR,"Samsung"],[TYPE,SMARTTV]],[/(vizio)(?: |.+model\/)(\w+-\w+)/i,/tcast.+(lg)e?. ([-\w]+)/i],[VENDOR,MODEL,[TYPE,SMARTTV]],[/(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i],[[VENDOR,"LG"],[TYPE,SMARTTV]],[/(apple) ?tv/i],[VENDOR,[MODEL,"Apple TV"],[TYPE,SMARTTV]],[/crkey.*devicetype\/chromecast/i],[[MODEL,"Chromecast Third Generation"],[VENDOR,"Google"],[TYPE,SMARTTV]],[/crkey.*devicetype\/([^/]*)/i],[[MODEL,/^/,"Chromecast "],[VENDOR,"Google"],[TYPE,SMARTTV]],[/fuchsia.*crkey/i],[[MODEL,"Chromecast Nest Hub"],[VENDOR,"Google"],[TYPE,SMARTTV]],[/crkey/i],[[MODEL,"Chromecast"],[VENDOR,"Google"],[TYPE,SMARTTV]],[/(portaltv)/i],[MODEL,[VENDOR,"Facebook"],[TYPE,SMARTTV]],[/droid.+aft(\w+)( bui|\))/i],[MODEL,[VENDOR,"Amazon"],[TYPE,SMARTTV]],[/(shield \w+ tv)/i],[MODEL,[VENDOR,"Nvidia"],[TYPE,SMARTTV]],[/\(dtv[\);].+(aquos)/i,/(aquos-tv[\w ]+)\)/i],[MODEL,[VENDOR,"Sharp"],[TYPE,SMARTTV]],[/(bravia[\w ]+)( bui|\))/i],[MODEL,[VENDOR,"Sony"],[TYPE,SMARTTV]],[/(mi(tv|box)-?\w+) bui/i],[MODEL,[VENDOR,"Xiaomi"],[TYPE,SMARTTV]],[/Hbbtv.*(technisat) (.*);/i],[VENDOR,MODEL,[TYPE,SMARTTV]],[/\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i,/hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i],[[VENDOR,/.+\/(\w+)/,"$1",strMapper,{LG:"lge"}],[MODEL,trim],[TYPE,SMARTTV]],[/(playstation \w+)/i],[MODEL,[VENDOR,"Sony"],[TYPE,"console"]],[/\b(xbox(?: one)?(?!; xbox))[\); ]/i],[MODEL,[VENDOR,"Microsoft"],[TYPE,"console"]],[/(ouya)/i,/(nintendo) (\w+)/i,/(retroid) (pocket ([^\)]+))/i],[VENDOR,MODEL,[TYPE,"console"]],[/droid.+; (shield)( bui|\))/i],[MODEL,[VENDOR,"Nvidia"],[TYPE,"console"]],[/\b(sm-[lr]\d\d[0156][fnuw]?s?|gear live)\b/i],[MODEL,[VENDOR,"Samsung"],[TYPE,"wearable"]],[/((pebble))app/i,/(asus|google|lg|oppo) ((pixel |zen)?watch[\w ]*)( bui|\))/i],[VENDOR,MODEL,[TYPE,"wearable"]],[/(ow(?:19|20)?we?[1-3]{1,3})/i],[MODEL,[VENDOR,"OPPO"],[TYPE,"wearable"]],[/(watch)(?: ?os[,\/]|\d,\d\/)[\d\.]+/i],[MODEL,[VENDOR,"Apple"],[TYPE,"wearable"]],[/(opwwe\d{3})/i],[MODEL,[VENDOR,"OnePlus"],[TYPE,"wearable"]],[/(moto 360)/i],[MODEL,[VENDOR,"Motorola"],[TYPE,"wearable"]],[/(smartwatch 3)/i],[MODEL,[VENDOR,"Sony"],[TYPE,"wearable"]],[/(g watch r)/i],[MODEL,[VENDOR,"LG"],[TYPE,"wearable"]],[/droid.+; (wt63?0{2,3})\)/i],[MODEL,[VENDOR,"Zebra"],[TYPE,"wearable"]],[/droid.+; (glass) \d/i],[MODEL,[VENDOR,"Google"],[TYPE,"xr"]],[/(pico) ([\w ]+) os\d/i],[VENDOR,MODEL,[TYPE,"xr"]],[/(quest( \d| pro)?s?).+vr/i],[MODEL,[VENDOR,"Facebook"],[TYPE,"xr"]],[/mobile vr; rv.+firefox/i],[[TYPE,"xr"]],[/(tesla)(?: qtcarbrowser|\/[-\w\.]+)/i],[VENDOR,[TYPE,"embedded"]],[/(aeobc)\b/i],[MODEL,[VENDOR,"Amazon"],[TYPE,"embedded"]],[/(homepod).+mac os/i],[MODEL,[VENDOR,"Apple"],[TYPE,"embedded"]],[/windows iot/i],[[TYPE,"embedded"]],[/droid.+; ([\w- ]+) (4k|android|smart|google)[- ]?tv/i],[MODEL,[TYPE,SMARTTV]],[/\b((4k|android|smart|opera)[- ]?tv|tv; rv:|large screen[\w ]+safari)\b/i],[[TYPE,SMARTTV]],[/droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew|; hmsc).+?(mobile|vr|\d) safari/i],[MODEL,[TYPE,strMapper,{mobile:"Mobile",xr:"VR","*":TABLET}]],[/\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i],[[TYPE,TABLET]],[/(phone|mobile(?:[;\/]| [ \w\/\.]*safari)|pda(?=.+windows ce))/i],[[TYPE,MOBILE]],[/droid .+?; ([\w\. -]+)( bui|\))/i],[MODEL,[VENDOR,"Generic"]]],engine:[[/windows.+ edge\/([\w\.]+)/i],[VERSION,[NAME,"EdgeHTML"]],[/(arkweb)\/([\w\.]+)/i],[NAME,VERSION],[/webkit\/537\.36.+chrome\/(?!27)([\w\.]+)/i],[VERSION,[NAME,"Blink"]],[/(presto)\/([\w\.]+)/i,/(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna|servo)\/([\w\.]+)/i,/ekioh(flow)\/([\w\.]+)/i,/(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i,/(icab)[\/ ]([23]\.[\d\.]+)/i,/\b(libweb)/i],[NAME,VERSION],[/ladybird\//i],[[NAME,"LibWeb"]],[/rv\:([\w\.]{1,9})\b.+(gecko)/i],[VERSION,NAME]],os:[[/(windows nt) (6\.[23]); arm/i],[[NAME,/N/,"R"],[VERSION,strMapper,windowsVersionMap]],[/(windows (?:phone|mobile|iot))(?: os)?[\/ ]?([\d\.]*( se)?)/i,/(windows)[\/ ](1[01]|2000|3\.1|7|8(\.1)?|9[58]|me|server 20\d\d( r2)?|vista|xp)/i],[NAME,VERSION],[/windows nt ?([\d\.\)]*)(?!.+xbox)/i,/\bwin(?=3| ?9|n)(?:nt| 9x )?([\d\.;]*)/i],[[VERSION,/(;|\))/g,"",strMapper,windowsVersionMap],[NAME,"Windows"]],[/(windows ce)\/?([\d\.]*)/i],[NAME,VERSION],[/[adehimnop]{4,7}\b(?:.*os ([\w]+) like mac|; opera)/i,/(?:ios;fbsv|ios(?=.+ip(?:ad|hone))|ip(?:ad|hone)(?: |.+i(?:pad)?)os)[\/ ]([\w\.]+)/i,/cfnetwork\/.+darwin/i],[[VERSION,/_/g,"."],[NAME,"iOS"]],[/(mac os x) ?([\w\. ]*)/i,/(macintosh|mac_powerpc\b)(?!.+(haiku|morphos))/i],[[NAME,"macOS"],[VERSION,/_/g,"."]],[/android ([\d\.]+).*crkey/i],[VERSION,[NAME,"Chromecast Android"]],[/fuchsia.*crkey\/([\d\.]+)/i],[VERSION,[NAME,"Chromecast Fuchsia"]],[/crkey\/([\d\.]+).*devicetype\/smartspeaker/i],[VERSION,[NAME,"Chromecast SmartSpeaker"]],[/linux.*crkey\/([\d\.]+)/i],[VERSION,[NAME,"Chromecast Linux"]],[/crkey\/([\d\.]+)/i],[VERSION,[NAME,"Chromecast"]],[/droid ([\w\.]+)\b.+(android[- ]x86)/i],[VERSION,NAME],[/(ubuntu) ([\w\.]+) like android/i],[[NAME,/(.+)/,"$1 Touch"],VERSION],[/(harmonyos)[\/ ]?([\d\.]*)/i,/(android|bada|blackberry|kaios|maemo|meego|openharmony|qnx|rim tablet os|sailfish|series40|symbian|tizen)\w*[-\/\.; ]?([\d\.]*)/i],[NAME,VERSION],[/\(bb(10);/i],[VERSION,[NAME,"BlackBerry"]],[/(?:symbian ?os|symbos|s60(?=;)|series ?60)[-\/ ]?([\w\.]*)/i],[VERSION,[NAME,"Symbian"]],[/mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i],[VERSION,[NAME,"Firefox OS"]],[/\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i,/webos(?:[ \/]?|\.tv-20(?=2[2-9]))(\d[\d\.]*)/i],[VERSION,[NAME,"webOS"]],[/web0s;.+?(?:chr[o0]me|safari)\/(\d+)/i],[[VERSION,strMapper,{25:"120",24:"108",23:"94",22:"87",6:"79",5:"68",4:"53",3:"38",2:"538",1:"537","*":"TV"}],[NAME,"webOS"]],[/watch(?: ?os[,\/]|\d,\d\/)([\d\.]+)/i],[VERSION,[NAME,"watchOS"]],[/(cros) [\w]+(?:\)| ([\w\.]+)\b)/i],[[NAME,"Chrome OS"],VERSION],[/panasonic;(viera)/i,/(netrange)mmh/i,/(nettv)\/(\d+\.[\w\.]+)/i,/(nintendo|playstation) (\w+)/i,/(xbox); +xbox ([^\);]+)/i,/(pico) .+os([\w\.]+)/i,/\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i,/linux.+(mint)[\/\(\) ]?([\w\.]*)/i,/(mageia|vectorlinux|fuchsia|arcaos|arch(?= ?linux))[;l ]([\d\.]*)/i,/([kxln]?ubuntu|debian|suse|opensuse|gentoo|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire|knoppix)(?: gnu[\/ ]linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i,/((?:open)?solaris)[-\/ ]?([\w\.]*)/i,/\b(aix)[; ]([1-9\.]{0,4})/i,/(hurd|linux|morphos)(?: (?:arm|x86|ppc)\w*| ?)([\w\.]*)/i,/(gnu) ?([\w\.]*)/i,/\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i,/(haiku) ?(r\d)?/i],[NAME,VERSION],[/(sunos) ?([\d\.]*)/i],[[NAME,"Solaris"],VERSION],[/\b(beos|os\/2|amigaos|openvms|hp-ux|serenityos)/i,/(unix) ?([\w\.]*)/i],[NAME,VERSION]]},defaultProps=(setProps.call((props={init:{},isIgnore:{},isIgnoreRgx:{},toString:{}}).init,[[BROWSER,[NAME,VERSION,"major",TYPE]],[CPU,[ARCHITECTURE]],[DEVICE,[TYPE,MODEL,VENDOR]],[ENGINE,[NAME,VERSION]],[OS,[NAME,VERSION]]]),setProps.call(props.isIgnore,[[BROWSER,[VERSION,"major"]],[ENGINE,[VERSION]],[OS,[VERSION]]]),setProps.call(props.isIgnoreRgx,[[BROWSER,/ ?browser$/i],[OS,/ ?os$/i]]),setProps.call(props.toString,[[BROWSER,[NAME,VERSION]],[CPU,[ARCHITECTURE]],[DEVICE,[VENDOR,MODEL]],[ENGINE,[NAME,VERSION]],[OS,[NAME,VERSION]]]),props),createIData=function(item,itemType){var init_props=defaultProps.init[itemType],is_ignoreProps=defaultProps.isIgnore[itemType]||0,is_ignoreRgx=defaultProps.isIgnoreRgx[itemType]||0,toString_props=defaultProps.toString[itemType]||0;function IData(){setProps.call(this,init_props)}return IData.prototype.getItem=function(){return item},IData.prototype.withClientHints=function(){return NAVIGATOR_UADATA?NAVIGATOR_UADATA.getHighEntropyValues(CH_ALL_VALUES).then((function(res){return item.setCH(new UACHData(res,!1)).parseCH().get()})):item.parseCH().get()},IData.prototype.withFeatureCheck=function(){return item.detectFeature().get()},"result"!=itemType&&(IData.prototype.is=function(strToCheck){var is=!1;for(var i in this)if(this.hasOwnProperty(i)&&!has(is_ignoreProps,i)&&lowerize(is_ignoreRgx?strip(is_ignoreRgx,this[i]):this[i])==lowerize(is_ignoreRgx?strip(is_ignoreRgx,strToCheck):strToCheck)){if(is=!0,strToCheck!=TYPEOF_UNDEFINED)break}else if(strToCheck==TYPEOF_UNDEFINED&&is){is=!is;break}return is},IData.prototype.toString=function(){var str="";for(var i in toString_props)typeof this[toString_props[i]]!==TYPEOF_UNDEFINED&&(str+=(str?" ":"")+this[toString_props[i]]);return str||TYPEOF_UNDEFINED}),NAVIGATOR_UADATA||(IData.prototype.then=function(cb){var that=this,IDataResolve=function(){for(var prop in that)that.hasOwnProperty(prop)&&(this[prop]=that[prop])};IDataResolve.prototype={is:IData.prototype.is,toString:IData.prototype.toString};var resolveData=new IDataResolve;return cb(resolveData),resolveData}),new IData};function UACHData(uach,isHttpUACH){if(uach=uach||{},setProps.call(this,CH_ALL_VALUES),isHttpUACH)setProps.call(this,[["brands",itemListToArray(uach[CH])],["fullVersionList",itemListToArray(uach[CH_FULL_VER_LIST])],[MOBILE,/\?1/.test(uach[CH_MOBILE])],[MODEL,stripQuotes(uach[CH_MODEL])],["platform",stripQuotes(uach[CH_PLATFORM])],["platformVersion",stripQuotes(uach[CH_PLATFORM_VER])],[ARCHITECTURE,stripQuotes(uach[CH_ARCH])],["formFactors",itemListToArray(uach[CH_FORM_FACTORS])],["bitness",stripQuotes(uach[CH_BITNESS])]]);else for(var prop in uach)this.hasOwnProperty(prop)&&typeof uach[prop]!==TYPEOF_UNDEFINED&&(this[prop]=uach[prop])}function UAItem(itemType,ua,rgxMap,uaCH){return this.get=function(prop){return prop?this.data.hasOwnProperty(prop)?this.data[prop]:void 0:this.data},this.set=function(prop,val){return this.data[prop]=val,this},this.setCH=function(ch){return this.uaCH=ch,this},this.detectFeature=function(){if(NAVIGATOR&&NAVIGATOR.userAgent==this.ua)switch(this.itemType){case BROWSER:NAVIGATOR.brave&&typeof NAVIGATOR.brave.isBrave==TYPEOF_FUNCTION&&this.set(NAME,"Brave");break;case DEVICE:!this.get(TYPE)&&NAVIGATOR_UADATA&&NAVIGATOR_UADATA[MOBILE]&&this.set(TYPE,MOBILE),"Macintosh"==this.get(MODEL)&&NAVIGATOR&&typeof NAVIGATOR.standalone!==TYPEOF_UNDEFINED&&NAVIGATOR.maxTouchPoints&&NAVIGATOR.maxTouchPoints>2&&this.set(MODEL,"iPad").set(TYPE,TABLET);break;case OS:!this.get(NAME)&&NAVIGATOR_UADATA&&NAVIGATOR_UADATA.platform&&this.set(NAME,NAVIGATOR_UADATA.platform);break;case"result":var data=this.data,detect=function(itemType){return data[itemType].getItem().detectFeature().get()};this.set(BROWSER,detect(BROWSER)).set(CPU,detect(CPU)).set(DEVICE,detect(DEVICE)).set(ENGINE,detect(ENGINE)).set(OS,detect(OS))}return this},this.parseUA=function(){switch("result"!=this.itemType&&rgxMapper.call(this.data,this.ua,this.rgxMap),this.itemType){case BROWSER:this.set("major",majorize(this.get(VERSION)));break;case OS:if("iOS"==this.get(NAME)&&"18.6"==this.get(VERSION)){var realVersion=/\) Version\/([\d\.]+)/.exec(this.ua);realVersion&&parseInt(realVersion[1].substring(0,2),10)>=26&&this.set(VERSION,realVersion[1])}}return this},this.parseCH=function(){var uaCH=this.uaCH,rgxMap=this.rgxMap;switch(this.itemType){case BROWSER:case ENGINE:var prevName,brands=uaCH.fullVersionList||uaCH.brands;if(brands)for(var i=0;i<brands.length;i++){var brandName=brands[i].brand||brands[i],brandVersion=brands[i].version;this.itemType==BROWSER&&!/not.a.brand/i.test(brandName)&&(!prevName||/Chrom/.test(prevName)&&"Chromium"!=brandName||"Edge"==prevName&&/WebView2/.test(brandName))&&(brandName=strMapper(brandName,browserHintsMap),(prevName=this.get(NAME))&&!/Chrom/.test(prevName)&&/Chrom/.test(brandName)||this.set(NAME,brandName).set(VERSION,brandVersion).set("major",majorize(brandVersion)),prevName=brandName),this.itemType==ENGINE&&"Chromium"==brandName&&this.set(VERSION,brandVersion)}break;case CPU:var archName=uaCH[ARCHITECTURE];archName&&(archName&&"64"==uaCH.bitness&&(archName+="64"),rgxMapper.call(this.data,archName+";",rgxMap));break;case DEVICE:if(uaCH[MOBILE]&&this.set(TYPE,MOBILE),uaCH[MODEL]&&(this.set(MODEL,uaCH[MODEL]),!this.get(TYPE)||!this.get(VENDOR))){var reParse={};rgxMapper.call(reParse,"droid 9; "+uaCH[MODEL]+")",rgxMap),!this.get(TYPE)&&reParse.type&&this.set(TYPE,reParse.type),!this.get(VENDOR)&&reParse.vendor&&this.set(VENDOR,reParse.vendor)}if(uaCH.formFactors){var ff;if("string"!=typeof uaCH.formFactors)for(var idx=0;!ff&&idx<uaCH.formFactors.length;)ff=strMapper(uaCH.formFactors[idx++],formFactorsMap);else ff=strMapper(uaCH.formFactors,formFactorsMap);this.set(TYPE,ff)}break;case OS:var osName=uaCH.platform;if(osName){var osVersion=uaCH.platformVersion;"Windows"==osName&&(osVersion=parseInt(majorize(osVersion),10)>=13?"11":"10"),this.set(NAME,osName).set(VERSION,osVersion)}"Windows"==this.get(NAME)&&"Xbox"==uaCH[MODEL]&&this.set(NAME,"Xbox").set(VERSION,void 0);break;case"result":var data=this.data,parse=function(itemType){return data[itemType].getItem().setCH(uaCH).parseCH().get()};this.set(BROWSER,parse(BROWSER)).set(CPU,parse(CPU)).set(DEVICE,parse(DEVICE)).set(ENGINE,parse(ENGINE)).set(OS,parse(OS))}return this},setProps.call(this,[["itemType",itemType],["ua",ua],["uaCH",uaCH],["rgxMap",rgxMap],["data",createIData(this,itemType)]]),this}function UAParser(ua,extensions,headers){if(typeof ua===TYPEOF_OBJECT?(isExtensions(ua,!0)?(typeof extensions===TYPEOF_OBJECT&&(headers=extensions),extensions=ua):(headers=ua,extensions=void 0),ua=void 0):typeof ua!==TYPEOF_STRING||isExtensions(extensions,!0)||(headers=extensions,extensions=void 0),headers)if(typeof headers.append===TYPEOF_FUNCTION){var kv={};headers.forEach((function(v,k){kv[String(k).toLowerCase()]=v})),headers=kv}else{var normalized={};for(var header in headers)headers.hasOwnProperty(header)&&(normalized[String(header).toLowerCase()]=headers[header]);headers=normalized}if(!(this instanceof UAParser))return new UAParser(ua,extensions,headers).getResult();var userAgent=typeof ua===TYPEOF_STRING?ua:headers&&headers["user-agent"]?headers["user-agent"]:NAVIGATOR&&NAVIGATOR.userAgent?NAVIGATOR.userAgent:"",httpUACH=new UACHData(headers,!0),regexMap=extensions?function(defaultRgx,extensions){var mergedRgx={},extraRgx=extensions;if(!isExtensions(extensions))for(var i in extraRgx={},extensions)for(var j in extensions[i])extraRgx[j]=extensions[i][j].concat(extraRgx[j]?extraRgx[j]:[]);for(var k in defaultRgx)mergedRgx[k]=extraRgx[k]&&extraRgx[k].length%2==0?extraRgx[k].concat(defaultRgx[k]):defaultRgx[k];return mergedRgx}(defaultRegexes,extensions):defaultRegexes,createItemFunc=function(itemType){return"result"==itemType?function(){return new UAItem(itemType,userAgent,regexMap,httpUACH).set("ua",userAgent).set(BROWSER,this.getBrowser()).set(CPU,this.getCPU()).set(DEVICE,this.getDevice()).set(ENGINE,this.getEngine()).set(OS,this.getOS()).get()}:function(){return new UAItem(itemType,userAgent,regexMap[itemType],httpUACH).parseUA().get()}};return setProps.call(this,[["getBrowser",createItemFunc(BROWSER)],["getCPU",createItemFunc(CPU)],["getDevice",createItemFunc(DEVICE)],["getEngine",createItemFunc(ENGINE)],["getOS",createItemFunc(OS)],["getResult",createItemFunc("result")],["getUA",function(){return userAgent}],["setUA",function(ua){return isString(ua)&&(userAgent=trim(ua,500)),this}]]).setUA(userAgent),this}UAParser.VERSION="2.0.6",UAParser.BROWSER=enumerize([NAME,VERSION,"major",TYPE]),UAParser.CPU=enumerize([ARCHITECTURE]),UAParser.DEVICE=enumerize([MODEL,VENDOR,TYPE,"console",MOBILE,SMARTTV,TABLET,"wearable","embedded"]),UAParser.ENGINE=UAParser.OS=enumerize([NAME,VERSION]);const utf8TextDecoder="undefined"==typeof TextDecoder?null:new TextDecoder("utf-8");class Pbf{constructor(buf=new Uint8Array(16)){this.buf=ArrayBuffer.isView(buf)?buf:new Uint8Array(buf),this.dataView=new DataView(this.buf.buffer),this.pos=0,this.type=0,this.length=this.buf.length}readFields(readField,result,end=this.length){for(;this.pos<end;){const val=this.readVarint(),tag=val>>3,startPos=this.pos;this.type=7&val,readField(tag,result,this),this.pos===startPos&&this.skip(val)}return result}readMessage(readField,result){return this.readFields(readField,result,this.readVarint()+this.pos)}readFixed32(){const val=this.dataView.getUint32(this.pos,!0);return this.pos+=4,val}readSFixed32(){const val=this.dataView.getInt32(this.pos,!0);return this.pos+=4,val}readFixed64(){const val=this.dataView.getUint32(this.pos,!0)+4294967296*this.dataView.getUint32(this.pos+4,!0);return this.pos+=8,val}readSFixed64(){const val=this.dataView.getUint32(this.pos,!0)+4294967296*this.dataView.getInt32(this.pos+4,!0);return this.pos+=8,val}readFloat(){const val=this.dataView.getFloat32(this.pos,!0);return this.pos+=4,val}readDouble(){const val=this.dataView.getFloat64(this.pos,!0);return this.pos+=8,val}readVarint(isSigned){const buf=this.buf;let val,b;return b=buf[this.pos++],val=127&b,b<128?val:(b=buf[this.pos++],val|=(127&b)<<7,b<128?val:(b=buf[this.pos++],val|=(127&b)<<14,b<128?val:(b=buf[this.pos++],val|=(127&b)<<21,b<128?val:(b=buf[this.pos],val|=(15&b)<<28,function(l,s,p){const buf=p.buf;let h,b;if(b=buf[p.pos++],h=(112&b)>>4,b<128)return toNum(l,h,s);if(b=buf[p.pos++],h|=(127&b)<<3,b<128)return toNum(l,h,s);if(b=buf[p.pos++],h|=(127&b)<<10,b<128)return toNum(l,h,s);if(b=buf[p.pos++],h|=(127&b)<<17,b<128)return toNum(l,h,s);if(b=buf[p.pos++],h|=(127&b)